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 size_t ttyport_receive_buf(struct tty_port *port, const u8 *cp, 26 const u8 *fp, size_t count) 27 { 28 struct serdev_controller *ctrl = port->client_data; 29 struct serport *serport = serdev_controller_get_drvdata(ctrl); 30 size_t 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 > count, 38 "receive_buf returns %zu (count = %zu)\n", 39 ret, count); 40 if (ret > count) 41 return count; 42 43 return ret; 44 } 45 46 static void ttyport_write_wakeup(struct tty_port *port) 47 { 48 struct serdev_controller *ctrl = port->client_data; 49 struct serport *serport = serdev_controller_get_drvdata(ctrl); 50 struct tty_struct *tty; 51 52 tty = tty_port_tty_get(port); 53 if (!tty) 54 return; 55 56 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && 57 test_bit(SERPORT_ACTIVE, &serport->flags)) 58 serdev_controller_write_wakeup(ctrl); 59 60 /* Wake up any tty_wait_until_sent() */ 61 wake_up_interruptible(&tty->write_wait); 62 63 tty_kref_put(tty); 64 } 65 66 static const struct tty_port_client_operations client_ops = { 67 .receive_buf = ttyport_receive_buf, 68 .write_wakeup = ttyport_write_wakeup, 69 }; 70 71 /* 72 * Callback functions from the serdev core. 73 */ 74 75 static ssize_t ttyport_write_buf(struct serdev_controller *ctrl, const u8 *data, size_t len) 76 { 77 struct serport *serport = serdev_controller_get_drvdata(ctrl); 78 struct tty_struct *tty = serport->tty; 79 80 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 81 return 0; 82 83 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 84 return tty->ops->write(serport->tty, data, len); 85 } 86 87 static void ttyport_write_flush(struct serdev_controller *ctrl) 88 { 89 struct serport *serport = serdev_controller_get_drvdata(ctrl); 90 struct tty_struct *tty = serport->tty; 91 92 tty_driver_flush_buffer(tty); 93 } 94 95 static int ttyport_open(struct serdev_controller *ctrl) 96 { 97 struct serport *serport = serdev_controller_get_drvdata(ctrl); 98 struct tty_struct *tty; 99 struct ktermios ktermios; 100 int ret; 101 102 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 103 if (IS_ERR(tty)) 104 return PTR_ERR(tty); 105 serport->tty = tty; 106 107 if (!tty->ops->open || !tty->ops->close) { 108 ret = -ENODEV; 109 goto err_unlock; 110 } 111 112 ret = tty->ops->open(serport->tty, NULL); 113 if (ret) 114 goto err_close; 115 116 tty_unlock(serport->tty); 117 118 /* Bring the UART into a known 8 bits no parity hw fc state */ 119 ktermios = tty->termios; 120 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 121 INLCR | IGNCR | ICRNL | IXON); 122 ktermios.c_oflag &= ~OPOST; 123 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 124 ktermios.c_cflag &= ~(CSIZE | PARENB); 125 ktermios.c_cflag |= CS8; 126 ktermios.c_cflag |= CRTSCTS; 127 /* Hangups are not supported so make sure to ignore carrier detect. */ 128 ktermios.c_cflag |= CLOCAL; 129 tty_set_termios(tty, &ktermios); 130 131 set_bit(SERPORT_ACTIVE, &serport->flags); 132 133 return 0; 134 135 err_close: 136 tty->ops->close(tty, NULL); 137 err_unlock: 138 tty_unlock(tty); 139 tty_release_struct(tty, serport->tty_idx); 140 141 return ret; 142 } 143 144 static void ttyport_close(struct serdev_controller *ctrl) 145 { 146 struct serport *serport = serdev_controller_get_drvdata(ctrl); 147 struct tty_struct *tty = serport->tty; 148 149 clear_bit(SERPORT_ACTIVE, &serport->flags); 150 151 tty_lock(tty); 152 if (tty->ops->close) 153 tty->ops->close(tty, NULL); 154 tty_unlock(tty); 155 156 tty_release_struct(tty, serport->tty_idx); 157 } 158 159 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 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 ktermios.c_cflag &= ~CBAUD; 166 tty_termios_encode_baud_rate(&ktermios, speed, speed); 167 168 /* tty_set_termios() return not checked as it is always 0 */ 169 tty_set_termios(tty, &ktermios); 170 return ktermios.c_ospeed; 171 } 172 173 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 174 { 175 struct serport *serport = serdev_controller_get_drvdata(ctrl); 176 struct tty_struct *tty = serport->tty; 177 struct ktermios ktermios = tty->termios; 178 179 if (enable) 180 ktermios.c_cflag |= CRTSCTS; 181 else 182 ktermios.c_cflag &= ~CRTSCTS; 183 184 tty_set_termios(tty, &ktermios); 185 } 186 187 static int ttyport_set_parity(struct serdev_controller *ctrl, 188 enum serdev_parity parity) 189 { 190 struct serport *serport = serdev_controller_get_drvdata(ctrl); 191 struct tty_struct *tty = serport->tty; 192 struct ktermios ktermios = tty->termios; 193 194 ktermios.c_cflag &= ~(PARENB | PARODD | CMSPAR); 195 if (parity != SERDEV_PARITY_NONE) { 196 ktermios.c_cflag |= PARENB; 197 if (parity == SERDEV_PARITY_ODD) 198 ktermios.c_cflag |= PARODD; 199 } 200 201 tty_set_termios(tty, &ktermios); 202 203 if ((tty->termios.c_cflag & (PARENB | PARODD | CMSPAR)) != 204 (ktermios.c_cflag & (PARENB | PARODD | CMSPAR))) 205 return -EINVAL; 206 207 return 0; 208 } 209 210 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout) 211 { 212 struct serport *serport = serdev_controller_get_drvdata(ctrl); 213 struct tty_struct *tty = serport->tty; 214 215 tty_wait_until_sent(tty, timeout); 216 } 217 218 static int ttyport_get_tiocm(struct serdev_controller *ctrl) 219 { 220 struct serport *serport = serdev_controller_get_drvdata(ctrl); 221 struct tty_struct *tty = serport->tty; 222 223 if (!tty->ops->tiocmget) 224 return -EOPNOTSUPP; 225 226 return tty->ops->tiocmget(tty); 227 } 228 229 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) 230 { 231 struct serport *serport = serdev_controller_get_drvdata(ctrl); 232 struct tty_struct *tty = serport->tty; 233 234 if (!tty->ops->tiocmset) 235 return -EOPNOTSUPP; 236 237 return tty->ops->tiocmset(tty, set, clear); 238 } 239 240 static int ttyport_break_ctl(struct serdev_controller *ctrl, unsigned int break_state) 241 { 242 struct serport *serport = serdev_controller_get_drvdata(ctrl); 243 struct tty_struct *tty = serport->tty; 244 245 if (!tty->ops->break_ctl) 246 return -EOPNOTSUPP; 247 248 return tty->ops->break_ctl(tty, break_state); 249 } 250 251 static const struct serdev_controller_ops ctrl_ops = { 252 .write_buf = ttyport_write_buf, 253 .write_flush = ttyport_write_flush, 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 .break_ctl = ttyport_break_ctl, 263 }; 264 265 struct device *serdev_tty_port_register(struct tty_port *port, 266 struct device *host, 267 struct device *parent, 268 struct tty_driver *drv, int idx) 269 { 270 struct serdev_controller *ctrl; 271 struct serport *serport; 272 int ret; 273 274 if (!port || !drv || !parent) 275 return ERR_PTR(-ENODEV); 276 277 ctrl = serdev_controller_alloc(host, parent, sizeof(struct serport)); 278 if (!ctrl) 279 return ERR_PTR(-ENOMEM); 280 serport = serdev_controller_get_drvdata(ctrl); 281 282 serport->port = port; 283 serport->tty_idx = idx; 284 serport->tty_drv = drv; 285 286 ctrl->ops = &ctrl_ops; 287 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 = &tty_port_default_client_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_data = NULL; 316 port->client_ops = &tty_port_default_client_ops; 317 serdev_controller_put(ctrl); 318 319 return 0; 320 } 321