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