1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org> 4 */ 5 #include <linux/kernel.h> 6 #include <linux/serdev.h> 7 #include <linux/tty.h> 8 #include <linux/tty_driver.h> 9 #include <linux/poll.h> 10 11 #define SERPORT_ACTIVE 1 12 13 struct serport { 14 struct tty_port *port; 15 struct tty_struct *tty; 16 struct tty_driver *tty_drv; 17 int tty_idx; 18 unsigned long flags; 19 }; 20 21 /* 22 * Callback functions from the tty port. 23 */ 24 25 static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp, 26 const unsigned char *fp, size_t count) 27 { 28 struct serdev_controller *ctrl = port->client_data; 29 struct serport *serport = serdev_controller_get_drvdata(ctrl); 30 int ret; 31 32 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 33 return 0; 34 35 ret = serdev_controller_receive_buf(ctrl, cp, count); 36 37 dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count, 38 "receive_buf returns %d (count = %zu)\n", 39 ret, count); 40 if (ret < 0) 41 return 0; 42 else if (ret > count) 43 return count; 44 45 return ret; 46 } 47 48 static void ttyport_write_wakeup(struct tty_port *port) 49 { 50 struct serdev_controller *ctrl = port->client_data; 51 struct serport *serport = serdev_controller_get_drvdata(ctrl); 52 struct tty_struct *tty; 53 54 tty = tty_port_tty_get(port); 55 if (!tty) 56 return; 57 58 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && 59 test_bit(SERPORT_ACTIVE, &serport->flags)) 60 serdev_controller_write_wakeup(ctrl); 61 62 /* Wake up any tty_wait_until_sent() */ 63 wake_up_interruptible(&tty->write_wait); 64 65 tty_kref_put(tty); 66 } 67 68 static const struct tty_port_client_operations client_ops = { 69 .receive_buf = ttyport_receive_buf, 70 .write_wakeup = ttyport_write_wakeup, 71 }; 72 73 /* 74 * Callback functions from the serdev core. 75 */ 76 77 static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len) 78 { 79 struct serport *serport = serdev_controller_get_drvdata(ctrl); 80 struct tty_struct *tty = serport->tty; 81 82 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 83 return 0; 84 85 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 86 return tty->ops->write(serport->tty, data, len); 87 } 88 89 static void ttyport_write_flush(struct serdev_controller *ctrl) 90 { 91 struct serport *serport = serdev_controller_get_drvdata(ctrl); 92 struct tty_struct *tty = serport->tty; 93 94 tty_driver_flush_buffer(tty); 95 } 96 97 static int ttyport_write_room(struct serdev_controller *ctrl) 98 { 99 struct serport *serport = serdev_controller_get_drvdata(ctrl); 100 struct tty_struct *tty = serport->tty; 101 102 return tty_write_room(tty); 103 } 104 105 static int ttyport_open(struct serdev_controller *ctrl) 106 { 107 struct serport *serport = serdev_controller_get_drvdata(ctrl); 108 struct tty_struct *tty; 109 struct ktermios ktermios; 110 int ret; 111 112 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 113 if (IS_ERR(tty)) 114 return PTR_ERR(tty); 115 serport->tty = tty; 116 117 if (!tty->ops->open || !tty->ops->close) { 118 ret = -ENODEV; 119 goto err_unlock; 120 } 121 122 ret = tty->ops->open(serport->tty, NULL); 123 if (ret) 124 goto err_close; 125 126 tty_unlock(serport->tty); 127 128 /* Bring the UART into a known 8 bits no parity hw fc state */ 129 ktermios = tty->termios; 130 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 131 INLCR | IGNCR | ICRNL | IXON); 132 ktermios.c_oflag &= ~OPOST; 133 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 134 ktermios.c_cflag &= ~(CSIZE | PARENB); 135 ktermios.c_cflag |= CS8; 136 ktermios.c_cflag |= CRTSCTS; 137 /* Hangups are not supported so make sure to ignore carrier detect. */ 138 ktermios.c_cflag |= CLOCAL; 139 tty_set_termios(tty, &ktermios); 140 141 set_bit(SERPORT_ACTIVE, &serport->flags); 142 143 return 0; 144 145 err_close: 146 tty->ops->close(tty, NULL); 147 err_unlock: 148 tty_unlock(tty); 149 tty_release_struct(tty, serport->tty_idx); 150 151 return ret; 152 } 153 154 static void ttyport_close(struct serdev_controller *ctrl) 155 { 156 struct serport *serport = serdev_controller_get_drvdata(ctrl); 157 struct tty_struct *tty = serport->tty; 158 159 clear_bit(SERPORT_ACTIVE, &serport->flags); 160 161 tty_lock(tty); 162 if (tty->ops->close) 163 tty->ops->close(tty, NULL); 164 tty_unlock(tty); 165 166 tty_release_struct(tty, serport->tty_idx); 167 } 168 169 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 170 { 171 struct serport *serport = serdev_controller_get_drvdata(ctrl); 172 struct tty_struct *tty = serport->tty; 173 struct ktermios ktermios = tty->termios; 174 175 ktermios.c_cflag &= ~CBAUD; 176 tty_termios_encode_baud_rate(&ktermios, speed, speed); 177 178 /* tty_set_termios() return not checked as it is always 0 */ 179 tty_set_termios(tty, &ktermios); 180 return ktermios.c_ospeed; 181 } 182 183 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 184 { 185 struct serport *serport = serdev_controller_get_drvdata(ctrl); 186 struct tty_struct *tty = serport->tty; 187 struct ktermios ktermios = tty->termios; 188 189 if (enable) 190 ktermios.c_cflag |= CRTSCTS; 191 else 192 ktermios.c_cflag &= ~CRTSCTS; 193 194 tty_set_termios(tty, &ktermios); 195 } 196 197 static int ttyport_set_parity(struct serdev_controller *ctrl, 198 enum serdev_parity parity) 199 { 200 struct serport *serport = serdev_controller_get_drvdata(ctrl); 201 struct tty_struct *tty = serport->tty; 202 struct ktermios ktermios = tty->termios; 203 204 ktermios.c_cflag &= ~(PARENB | PARODD | CMSPAR); 205 if (parity != SERDEV_PARITY_NONE) { 206 ktermios.c_cflag |= PARENB; 207 if (parity == SERDEV_PARITY_ODD) 208 ktermios.c_cflag |= PARODD; 209 } 210 211 tty_set_termios(tty, &ktermios); 212 213 if ((tty->termios.c_cflag & (PARENB | PARODD | CMSPAR)) != 214 (ktermios.c_cflag & (PARENB | PARODD | CMSPAR))) 215 return -EINVAL; 216 217 return 0; 218 } 219 220 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout) 221 { 222 struct serport *serport = serdev_controller_get_drvdata(ctrl); 223 struct tty_struct *tty = serport->tty; 224 225 tty_wait_until_sent(tty, timeout); 226 } 227 228 static int ttyport_get_tiocm(struct serdev_controller *ctrl) 229 { 230 struct serport *serport = serdev_controller_get_drvdata(ctrl); 231 struct tty_struct *tty = serport->tty; 232 233 if (!tty->ops->tiocmget) 234 return -ENOTSUPP; 235 236 return tty->ops->tiocmget(tty); 237 } 238 239 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) 240 { 241 struct serport *serport = serdev_controller_get_drvdata(ctrl); 242 struct tty_struct *tty = serport->tty; 243 244 if (!tty->ops->tiocmset) 245 return -ENOTSUPP; 246 247 return tty->ops->tiocmset(tty, set, clear); 248 } 249 250 static const struct serdev_controller_ops ctrl_ops = { 251 .write_buf = ttyport_write_buf, 252 .write_flush = ttyport_write_flush, 253 .write_room = ttyport_write_room, 254 .open = ttyport_open, 255 .close = ttyport_close, 256 .set_flow_control = ttyport_set_flow_control, 257 .set_parity = ttyport_set_parity, 258 .set_baudrate = ttyport_set_baudrate, 259 .wait_until_sent = ttyport_wait_until_sent, 260 .get_tiocm = ttyport_get_tiocm, 261 .set_tiocm = ttyport_set_tiocm, 262 }; 263 264 struct device *serdev_tty_port_register(struct tty_port *port, 265 struct device *parent, 266 struct tty_driver *drv, int idx) 267 { 268 const struct tty_port_client_operations *old_ops; 269 struct serdev_controller *ctrl; 270 struct serport *serport; 271 int ret; 272 273 if (!port || !drv || !parent) 274 return ERR_PTR(-ENODEV); 275 276 ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); 277 if (!ctrl) 278 return ERR_PTR(-ENOMEM); 279 serport = serdev_controller_get_drvdata(ctrl); 280 281 serport->port = port; 282 serport->tty_idx = idx; 283 serport->tty_drv = drv; 284 285 ctrl->ops = &ctrl_ops; 286 287 old_ops = port->client_ops; 288 port->client_ops = &client_ops; 289 port->client_data = ctrl; 290 291 ret = serdev_controller_add(ctrl); 292 if (ret) 293 goto err_reset_data; 294 295 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx); 296 return &ctrl->dev; 297 298 err_reset_data: 299 port->client_data = NULL; 300 port->client_ops = old_ops; 301 serdev_controller_put(ctrl); 302 303 return ERR_PTR(ret); 304 } 305 306 int serdev_tty_port_unregister(struct tty_port *port) 307 { 308 struct serdev_controller *ctrl = port->client_data; 309 struct serport *serport = serdev_controller_get_drvdata(ctrl); 310 311 if (!serport) 312 return -ENODEV; 313 314 serdev_controller_remove(ctrl); 315 port->client_ops = NULL; 316 port->client_data = NULL; 317 serdev_controller_put(ctrl); 318 319 return 0; 320 } 321