1 /* 2 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 #include <linux/kernel.h> 14 #include <linux/serdev.h> 15 #include <linux/tty.h> 16 #include <linux/tty_driver.h> 17 #include <linux/poll.h> 18 19 #define SERPORT_ACTIVE 1 20 21 struct serport { 22 struct tty_port *port; 23 struct tty_struct *tty; 24 struct tty_driver *tty_drv; 25 int tty_idx; 26 unsigned long flags; 27 }; 28 29 /* 30 * Callback functions from the tty port. 31 */ 32 33 static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp, 34 const unsigned char *fp, size_t count) 35 { 36 struct serdev_controller *ctrl = port->client_data; 37 struct serport *serport = serdev_controller_get_drvdata(ctrl); 38 39 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 40 return 0; 41 42 return serdev_controller_receive_buf(ctrl, cp, count); 43 } 44 45 static void ttyport_write_wakeup(struct tty_port *port) 46 { 47 struct serdev_controller *ctrl = port->client_data; 48 struct serport *serport = serdev_controller_get_drvdata(ctrl); 49 50 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) && 51 test_bit(SERPORT_ACTIVE, &serport->flags)) 52 serdev_controller_write_wakeup(ctrl); 53 54 wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT); 55 } 56 57 static const struct tty_port_client_operations client_ops = { 58 .receive_buf = ttyport_receive_buf, 59 .write_wakeup = ttyport_write_wakeup, 60 }; 61 62 /* 63 * Callback functions from the serdev core. 64 */ 65 66 static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len) 67 { 68 struct serport *serport = serdev_controller_get_drvdata(ctrl); 69 struct tty_struct *tty = serport->tty; 70 71 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 72 return 0; 73 74 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 75 return tty->ops->write(serport->tty, data, len); 76 } 77 78 static void ttyport_write_flush(struct serdev_controller *ctrl) 79 { 80 struct serport *serport = serdev_controller_get_drvdata(ctrl); 81 struct tty_struct *tty = serport->tty; 82 83 tty_driver_flush_buffer(tty); 84 } 85 86 static int ttyport_write_room(struct serdev_controller *ctrl) 87 { 88 struct serport *serport = serdev_controller_get_drvdata(ctrl); 89 struct tty_struct *tty = serport->tty; 90 91 return tty_write_room(tty); 92 } 93 94 static int ttyport_open(struct serdev_controller *ctrl) 95 { 96 struct serport *serport = serdev_controller_get_drvdata(ctrl); 97 struct tty_struct *tty; 98 struct ktermios ktermios; 99 100 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 101 if (IS_ERR(tty)) 102 return PTR_ERR(tty); 103 serport->tty = tty; 104 105 if (tty->ops->open) 106 tty->ops->open(serport->tty, NULL); 107 else 108 tty_port_open(serport->port, tty, NULL); 109 110 /* Bring the UART into a known 8 bits no parity hw fc state */ 111 ktermios = tty->termios; 112 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 113 INLCR | IGNCR | ICRNL | IXON); 114 ktermios.c_oflag &= ~OPOST; 115 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 116 ktermios.c_cflag &= ~(CSIZE | PARENB); 117 ktermios.c_cflag |= CS8; 118 ktermios.c_cflag |= CRTSCTS; 119 tty_set_termios(tty, &ktermios); 120 121 set_bit(SERPORT_ACTIVE, &serport->flags); 122 123 tty_unlock(serport->tty); 124 return 0; 125 } 126 127 static void ttyport_close(struct serdev_controller *ctrl) 128 { 129 struct serport *serport = serdev_controller_get_drvdata(ctrl); 130 struct tty_struct *tty = serport->tty; 131 132 clear_bit(SERPORT_ACTIVE, &serport->flags); 133 134 if (tty->ops->close) 135 tty->ops->close(tty, NULL); 136 137 tty_release_struct(tty, serport->tty_idx); 138 } 139 140 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 141 { 142 struct serport *serport = serdev_controller_get_drvdata(ctrl); 143 struct tty_struct *tty = serport->tty; 144 struct ktermios ktermios = tty->termios; 145 146 ktermios.c_cflag &= ~CBAUD; 147 tty_termios_encode_baud_rate(&ktermios, speed, speed); 148 149 /* tty_set_termios() return not checked as it is always 0 */ 150 tty_set_termios(tty, &ktermios); 151 return ktermios.c_ospeed; 152 } 153 154 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 155 { 156 struct serport *serport = serdev_controller_get_drvdata(ctrl); 157 struct tty_struct *tty = serport->tty; 158 struct ktermios ktermios = tty->termios; 159 160 if (enable) 161 ktermios.c_cflag |= CRTSCTS; 162 else 163 ktermios.c_cflag &= ~CRTSCTS; 164 165 tty_set_termios(tty, &ktermios); 166 } 167 168 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout) 169 { 170 struct serport *serport = serdev_controller_get_drvdata(ctrl); 171 struct tty_struct *tty = serport->tty; 172 173 tty_wait_until_sent(tty, timeout); 174 } 175 176 static int ttyport_get_tiocm(struct serdev_controller *ctrl) 177 { 178 struct serport *serport = serdev_controller_get_drvdata(ctrl); 179 struct tty_struct *tty = serport->tty; 180 181 if (!tty->ops->tiocmget) 182 return -ENOTSUPP; 183 184 return tty->driver->ops->tiocmget(tty); 185 } 186 187 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) 188 { 189 struct serport *serport = serdev_controller_get_drvdata(ctrl); 190 struct tty_struct *tty = serport->tty; 191 192 if (!tty->ops->tiocmset) 193 return -ENOTSUPP; 194 195 return tty->driver->ops->tiocmset(tty, set, clear); 196 } 197 198 static const struct serdev_controller_ops ctrl_ops = { 199 .write_buf = ttyport_write_buf, 200 .write_flush = ttyport_write_flush, 201 .write_room = ttyport_write_room, 202 .open = ttyport_open, 203 .close = ttyport_close, 204 .set_flow_control = ttyport_set_flow_control, 205 .set_baudrate = ttyport_set_baudrate, 206 .wait_until_sent = ttyport_wait_until_sent, 207 .get_tiocm = ttyport_get_tiocm, 208 .set_tiocm = ttyport_set_tiocm, 209 }; 210 211 struct device *serdev_tty_port_register(struct tty_port *port, 212 struct device *parent, 213 struct tty_driver *drv, int idx) 214 { 215 const struct tty_port_client_operations *old_ops; 216 struct serdev_controller *ctrl; 217 struct serport *serport; 218 int ret; 219 220 if (!port || !drv || !parent) 221 return ERR_PTR(-ENODEV); 222 223 ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); 224 if (!ctrl) 225 return ERR_PTR(-ENOMEM); 226 serport = serdev_controller_get_drvdata(ctrl); 227 228 serport->port = port; 229 serport->tty_idx = idx; 230 serport->tty_drv = drv; 231 232 ctrl->ops = &ctrl_ops; 233 234 old_ops = port->client_ops; 235 port->client_ops = &client_ops; 236 port->client_data = ctrl; 237 238 ret = serdev_controller_add(ctrl); 239 if (ret) 240 goto err_reset_data; 241 242 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx); 243 return &ctrl->dev; 244 245 err_reset_data: 246 port->client_data = NULL; 247 port->client_ops = old_ops; 248 serdev_controller_put(ctrl); 249 250 return ERR_PTR(ret); 251 } 252 253 int serdev_tty_port_unregister(struct tty_port *port) 254 { 255 struct serdev_controller *ctrl = port->client_data; 256 struct serport *serport = serdev_controller_get_drvdata(ctrl); 257 258 if (!serport) 259 return -ENODEV; 260 261 serdev_controller_remove(ctrl); 262 port->client_ops = NULL; 263 port->client_data = NULL; 264 serdev_controller_put(ctrl); 265 266 return 0; 267 } 268