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 serport->port->client_ops = &client_ops; 106 serport->port->client_data = ctrl; 107 108 if (tty->ops->open) 109 tty->ops->open(serport->tty, NULL); 110 else 111 tty_port_open(serport->port, tty, NULL); 112 113 /* Bring the UART into a known 8 bits no parity hw fc state */ 114 ktermios = tty->termios; 115 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 116 INLCR | IGNCR | ICRNL | IXON); 117 ktermios.c_oflag &= ~OPOST; 118 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 119 ktermios.c_cflag &= ~(CSIZE | PARENB); 120 ktermios.c_cflag |= CS8; 121 ktermios.c_cflag |= CRTSCTS; 122 tty_set_termios(tty, &ktermios); 123 124 set_bit(SERPORT_ACTIVE, &serport->flags); 125 126 tty_unlock(serport->tty); 127 return 0; 128 } 129 130 static void ttyport_close(struct serdev_controller *ctrl) 131 { 132 struct serport *serport = serdev_controller_get_drvdata(ctrl); 133 struct tty_struct *tty = serport->tty; 134 135 clear_bit(SERPORT_ACTIVE, &serport->flags); 136 137 if (tty->ops->close) 138 tty->ops->close(tty, NULL); 139 140 tty_release_struct(tty, serport->tty_idx); 141 } 142 143 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 144 { 145 struct serport *serport = serdev_controller_get_drvdata(ctrl); 146 struct tty_struct *tty = serport->tty; 147 struct ktermios ktermios = tty->termios; 148 149 ktermios.c_cflag &= ~CBAUD; 150 tty_termios_encode_baud_rate(&ktermios, speed, speed); 151 152 /* tty_set_termios() return not checked as it is always 0 */ 153 tty_set_termios(tty, &ktermios); 154 return speed; 155 } 156 157 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 158 { 159 struct serport *serport = serdev_controller_get_drvdata(ctrl); 160 struct tty_struct *tty = serport->tty; 161 struct ktermios ktermios = tty->termios; 162 163 if (enable) 164 ktermios.c_cflag |= CRTSCTS; 165 else 166 ktermios.c_cflag &= ~CRTSCTS; 167 168 tty_set_termios(tty, &ktermios); 169 } 170 171 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout) 172 { 173 struct serport *serport = serdev_controller_get_drvdata(ctrl); 174 struct tty_struct *tty = serport->tty; 175 176 tty_wait_until_sent(tty, timeout); 177 } 178 179 static int ttyport_get_tiocm(struct serdev_controller *ctrl) 180 { 181 struct serport *serport = serdev_controller_get_drvdata(ctrl); 182 struct tty_struct *tty = serport->tty; 183 184 if (!tty->ops->tiocmget) 185 return -ENOTSUPP; 186 187 return tty->driver->ops->tiocmget(tty); 188 } 189 190 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear) 191 { 192 struct serport *serport = serdev_controller_get_drvdata(ctrl); 193 struct tty_struct *tty = serport->tty; 194 195 if (!tty->ops->tiocmset) 196 return -ENOTSUPP; 197 198 return tty->driver->ops->tiocmset(tty, set, clear); 199 } 200 201 static const struct serdev_controller_ops ctrl_ops = { 202 .write_buf = ttyport_write_buf, 203 .write_flush = ttyport_write_flush, 204 .write_room = ttyport_write_room, 205 .open = ttyport_open, 206 .close = ttyport_close, 207 .set_flow_control = ttyport_set_flow_control, 208 .set_baudrate = ttyport_set_baudrate, 209 .wait_until_sent = ttyport_wait_until_sent, 210 .get_tiocm = ttyport_get_tiocm, 211 .set_tiocm = ttyport_set_tiocm, 212 }; 213 214 struct device *serdev_tty_port_register(struct tty_port *port, 215 struct device *parent, 216 struct tty_driver *drv, int idx) 217 { 218 struct serdev_controller *ctrl; 219 struct serport *serport; 220 int ret; 221 222 if (!port || !drv || !parent) 223 return ERR_PTR(-ENODEV); 224 225 ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); 226 if (!ctrl) 227 return ERR_PTR(-ENOMEM); 228 serport = serdev_controller_get_drvdata(ctrl); 229 230 serport->port = port; 231 serport->tty_idx = idx; 232 serport->tty_drv = drv; 233 234 ctrl->ops = &ctrl_ops; 235 236 ret = serdev_controller_add(ctrl); 237 if (ret) 238 goto err_controller_put; 239 240 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx); 241 return &ctrl->dev; 242 243 err_controller_put: 244 serdev_controller_put(ctrl); 245 return ERR_PTR(ret); 246 } 247 248 void serdev_tty_port_unregister(struct tty_port *port) 249 { 250 struct serdev_controller *ctrl = port->client_data; 251 struct serport *serport = serdev_controller_get_drvdata(ctrl); 252 253 if (!serport) 254 return; 255 256 serdev_controller_remove(ctrl); 257 port->client_ops = NULL; 258 port->client_data = NULL; 259 serdev_controller_put(ctrl); 260 } 261