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_interruptible_poll(&tty->write_wait, POLLOUT); 63 64 tty_kref_put(tty); 65 } 66 67 static const struct tty_port_client_operations client_ops = { 68 .receive_buf = ttyport_receive_buf, 69 .write_wakeup = ttyport_write_wakeup, 70 }; 71 72 /* 73 * Callback functions from the serdev core. 74 */ 75 76 static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len) 77 { 78 struct serport *serport = serdev_controller_get_drvdata(ctrl); 79 struct tty_struct *tty = serport->tty; 80 81 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 82 return 0; 83 84 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 85 return tty->ops->write(serport->tty, data, len); 86 } 87 88 static void ttyport_write_flush(struct serdev_controller *ctrl) 89 { 90 struct serport *serport = serdev_controller_get_drvdata(ctrl); 91 struct tty_struct *tty = serport->tty; 92 93 tty_driver_flush_buffer(tty); 94 } 95 96 static int ttyport_write_room(struct serdev_controller *ctrl) 97 { 98 struct serport *serport = serdev_controller_get_drvdata(ctrl); 99 struct tty_struct *tty = serport->tty; 100 101 return tty_write_room(tty); 102 } 103 104 static int ttyport_open(struct serdev_controller *ctrl) 105 { 106 struct serport *serport = serdev_controller_get_drvdata(ctrl); 107 struct tty_struct *tty; 108 struct ktermios ktermios; 109 int ret; 110 111 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 112 if (IS_ERR(tty)) 113 return PTR_ERR(tty); 114 serport->tty = tty; 115 116 if (!tty->ops->open || !tty->ops->close) { 117 ret = -ENODEV; 118 goto err_unlock; 119 } 120 121 ret = tty->ops->open(serport->tty, NULL); 122 if (ret) 123 goto err_close; 124 125 /* Bring the UART into a known 8 bits no parity hw fc state */ 126 ktermios = tty->termios; 127 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 128 INLCR | IGNCR | ICRNL | IXON); 129 ktermios.c_oflag &= ~OPOST; 130 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 131 ktermios.c_cflag &= ~(CSIZE | PARENB); 132 ktermios.c_cflag |= CS8; 133 ktermios.c_cflag |= CRTSCTS; 134 tty_set_termios(tty, &ktermios); 135 136 set_bit(SERPORT_ACTIVE, &serport->flags); 137 138 tty_unlock(serport->tty); 139 return 0; 140 141 err_close: 142 tty->ops->close(tty, NULL); 143 err_unlock: 144 tty_unlock(tty); 145 tty_release_struct(tty, serport->tty_idx); 146 147 return ret; 148 } 149 150 static void ttyport_close(struct serdev_controller *ctrl) 151 { 152 struct serport *serport = serdev_controller_get_drvdata(ctrl); 153 struct tty_struct *tty = serport->tty; 154 155 clear_bit(SERPORT_ACTIVE, &serport->flags); 156 157 tty_lock(tty); 158 if (tty->ops->close) 159 tty->ops->close(tty, NULL); 160 tty_unlock(tty); 161 162 tty_release_struct(tty, serport->tty_idx); 163 } 164 165 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 166 { 167 struct serport *serport = serdev_controller_get_drvdata(ctrl); 168 struct tty_struct *tty = serport->tty; 169 struct ktermios ktermios = tty->termios; 170 171 ktermios.c_cflag &= ~CBAUD; 172 tty_termios_encode_baud_rate(&ktermios, speed, speed); 173 174 /* tty_set_termios() return not checked as it is always 0 */ 175 tty_set_termios(tty, &ktermios); 176 return ktermios.c_ospeed; 177 } 178 179 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 180 { 181 struct serport *serport = serdev_controller_get_drvdata(ctrl); 182 struct tty_struct *tty = serport->tty; 183 struct ktermios ktermios = tty->termios; 184 185 if (enable) 186 ktermios.c_cflag |= CRTSCTS; 187 else 188 ktermios.c_cflag &= ~CRTSCTS; 189 190 tty_set_termios(tty, &ktermios); 191 } 192 193 static int ttyport_set_parity(struct serdev_controller *ctrl, 194 enum serdev_parity parity) 195 { 196 struct serport *serport = serdev_controller_get_drvdata(ctrl); 197 struct tty_struct *tty = serport->tty; 198 struct ktermios ktermios = tty->termios; 199 200 ktermios.c_cflag &= ~(PARENB | PARODD | CMSPAR); 201 if (parity != SERDEV_PARITY_NONE) { 202 ktermios.c_cflag |= PARENB; 203 if (parity == SERDEV_PARITY_ODD) 204 ktermios.c_cflag |= PARODD; 205 } 206 207 tty_set_termios(tty, &ktermios); 208 209 if ((tty->termios.c_cflag & (PARENB | PARODD | CMSPAR)) != 210 (ktermios.c_cflag & (PARENB | PARODD | CMSPAR))) 211 return -EINVAL; 212 213 return 0; 214 } 215 216 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout) 217 { 218 struct serport *serport = serdev_controller_get_drvdata(ctrl); 219 struct tty_struct *tty = serport->tty; 220 221 tty_wait_until_sent(tty, timeout); 222 } 223 224 static int ttyport_get_tiocm(struct serdev_controller *ctrl) 225 { 226 struct serport *serport = serdev_controller_get_drvdata(ctrl); 227 struct tty_struct *tty = serport->tty; 228 229 if (!tty->ops->tiocmget) 230 return -ENOTSUPP; 231 232 return tty->driver->ops->tiocmget(tty); 233 } 234 235 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) 236 { 237 struct serport *serport = serdev_controller_get_drvdata(ctrl); 238 struct tty_struct *tty = serport->tty; 239 240 if (!tty->ops->tiocmset) 241 return -ENOTSUPP; 242 243 return tty->driver->ops->tiocmset(tty, set, clear); 244 } 245 246 static const struct serdev_controller_ops ctrl_ops = { 247 .write_buf = ttyport_write_buf, 248 .write_flush = ttyport_write_flush, 249 .write_room = ttyport_write_room, 250 .open = ttyport_open, 251 .close = ttyport_close, 252 .set_flow_control = ttyport_set_flow_control, 253 .set_parity = ttyport_set_parity, 254 .set_baudrate = ttyport_set_baudrate, 255 .wait_until_sent = ttyport_wait_until_sent, 256 .get_tiocm = ttyport_get_tiocm, 257 .set_tiocm = ttyport_set_tiocm, 258 }; 259 260 struct device *serdev_tty_port_register(struct tty_port *port, 261 struct device *parent, 262 struct tty_driver *drv, int idx) 263 { 264 const struct tty_port_client_operations *old_ops; 265 struct serdev_controller *ctrl; 266 struct serport *serport; 267 int ret; 268 269 if (!port || !drv || !parent) 270 return ERR_PTR(-ENODEV); 271 272 ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); 273 if (!ctrl) 274 return ERR_PTR(-ENOMEM); 275 serport = serdev_controller_get_drvdata(ctrl); 276 277 serport->port = port; 278 serport->tty_idx = idx; 279 serport->tty_drv = drv; 280 281 ctrl->ops = &ctrl_ops; 282 283 old_ops = port->client_ops; 284 port->client_ops = &client_ops; 285 port->client_data = ctrl; 286 287 ret = serdev_controller_add(ctrl); 288 if (ret) 289 goto err_reset_data; 290 291 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx); 292 return &ctrl->dev; 293 294 err_reset_data: 295 port->client_data = NULL; 296 port->client_ops = old_ops; 297 serdev_controller_put(ctrl); 298 299 return ERR_PTR(ret); 300 } 301 302 int serdev_tty_port_unregister(struct tty_port *port) 303 { 304 struct serdev_controller *ctrl = port->client_data; 305 struct serport *serport = serdev_controller_get_drvdata(ctrl); 306 307 if (!serport) 308 return -ENODEV; 309 310 serdev_controller_remove(ctrl); 311 port->client_ops = NULL; 312 port->client_data = NULL; 313 serdev_controller_put(ctrl); 314 315 return 0; 316 } 317