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 #include <linux/platform_device.h>
11 #include <linux/module.h>
12
13 #define SERPORT_ACTIVE 1
14
15 static char *pdev_tty_port;
16 module_param(pdev_tty_port, charp, 0644);
17 MODULE_PARM_DESC(pdev_tty_port, "platform device tty port to claim");
18
19 struct serport {
20 struct tty_port *port;
21 struct tty_struct *tty;
22 struct tty_driver *tty_drv;
23 int tty_idx;
24 unsigned long flags;
25 };
26
27 /*
28 * Callback functions from the tty port.
29 */
30
ttyport_receive_buf(struct tty_port * port,const unsigned char * cp,const unsigned char * fp,size_t count)31 static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
32 const unsigned char *fp, size_t count)
33 {
34 struct serdev_controller *ctrl = port->client_data;
35 struct serport *serport = serdev_controller_get_drvdata(ctrl);
36 int ret;
37
38 if (!test_bit(SERPORT_ACTIVE, &serport->flags))
39 return 0;
40
41 ret = serdev_controller_receive_buf(ctrl, cp, count);
42
43 dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
44 "receive_buf returns %d (count = %zu)\n",
45 ret, count);
46 if (ret < 0)
47 return 0;
48 else if (ret > count)
49 return count;
50
51 return ret;
52 }
53
ttyport_write_wakeup(struct tty_port * port)54 static void ttyport_write_wakeup(struct tty_port *port)
55 {
56 struct serdev_controller *ctrl = port->client_data;
57 struct serport *serport = serdev_controller_get_drvdata(ctrl);
58 struct tty_struct *tty;
59
60 tty = tty_port_tty_get(port);
61 if (!tty)
62 return;
63
64 if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
65 test_bit(SERPORT_ACTIVE, &serport->flags))
66 serdev_controller_write_wakeup(ctrl);
67
68 /* Wake up any tty_wait_until_sent() */
69 wake_up_interruptible(&tty->write_wait);
70
71 tty_kref_put(tty);
72 }
73
74 static const struct tty_port_client_operations client_ops = {
75 .receive_buf = ttyport_receive_buf,
76 .write_wakeup = ttyport_write_wakeup,
77 };
78
79 /*
80 * Callback functions from the serdev core.
81 */
82
ttyport_write_buf(struct serdev_controller * ctrl,const unsigned char * data,size_t len)83 static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len)
84 {
85 struct serport *serport = serdev_controller_get_drvdata(ctrl);
86 struct tty_struct *tty = serport->tty;
87
88 if (!test_bit(SERPORT_ACTIVE, &serport->flags))
89 return 0;
90
91 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
92 return tty->ops->write(serport->tty, data, len);
93 }
94
ttyport_write_flush(struct serdev_controller * ctrl)95 static void ttyport_write_flush(struct serdev_controller *ctrl)
96 {
97 struct serport *serport = serdev_controller_get_drvdata(ctrl);
98 struct tty_struct *tty = serport->tty;
99
100 tty_driver_flush_buffer(tty);
101 }
102
ttyport_write_room(struct serdev_controller * ctrl)103 static int ttyport_write_room(struct serdev_controller *ctrl)
104 {
105 struct serport *serport = serdev_controller_get_drvdata(ctrl);
106 struct tty_struct *tty = serport->tty;
107
108 return tty_write_room(tty);
109 }
110
ttyport_open(struct serdev_controller * ctrl)111 static int ttyport_open(struct serdev_controller *ctrl)
112 {
113 struct serport *serport = serdev_controller_get_drvdata(ctrl);
114 struct tty_struct *tty;
115 struct ktermios ktermios;
116 int ret;
117
118 tty = tty_init_dev(serport->tty_drv, serport->tty_idx);
119 if (IS_ERR(tty))
120 return PTR_ERR(tty);
121 serport->tty = tty;
122
123 if (!tty->ops->open || !tty->ops->close) {
124 ret = -ENODEV;
125 goto err_unlock;
126 }
127
128 ret = tty->ops->open(serport->tty, NULL);
129 if (ret)
130 goto err_close;
131
132 tty_unlock(serport->tty);
133
134 /* Bring the UART into a known 8 bits no parity hw fc state */
135 ktermios = tty->termios;
136 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
137 INLCR | IGNCR | ICRNL | IXON);
138 ktermios.c_oflag &= ~OPOST;
139 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
140 ktermios.c_cflag &= ~(CSIZE | PARENB);
141 ktermios.c_cflag |= CS8;
142 ktermios.c_cflag |= CRTSCTS;
143 /* Hangups are not supported so make sure to ignore carrier detect. */
144 ktermios.c_cflag |= CLOCAL;
145 tty_set_termios(tty, &ktermios);
146
147 set_bit(SERPORT_ACTIVE, &serport->flags);
148
149 return 0;
150
151 err_close:
152 tty->ops->close(tty, NULL);
153 err_unlock:
154 tty_unlock(tty);
155 tty_release_struct(tty, serport->tty_idx);
156
157 return ret;
158 }
159
ttyport_close(struct serdev_controller * ctrl)160 static void ttyport_close(struct serdev_controller *ctrl)
161 {
162 struct serport *serport = serdev_controller_get_drvdata(ctrl);
163 struct tty_struct *tty = serport->tty;
164
165 clear_bit(SERPORT_ACTIVE, &serport->flags);
166
167 tty_lock(tty);
168 if (tty->ops->close)
169 tty->ops->close(tty, NULL);
170 tty_unlock(tty);
171
172 tty_release_struct(tty, serport->tty_idx);
173 }
174
ttyport_set_baudrate(struct serdev_controller * ctrl,unsigned int speed)175 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed)
176 {
177 struct serport *serport = serdev_controller_get_drvdata(ctrl);
178 struct tty_struct *tty = serport->tty;
179 struct ktermios ktermios = tty->termios;
180
181 ktermios.c_cflag &= ~CBAUD;
182 tty_termios_encode_baud_rate(&ktermios, speed, speed);
183
184 /* tty_set_termios() return not checked as it is always 0 */
185 tty_set_termios(tty, &ktermios);
186 return ktermios.c_ospeed;
187 }
188
ttyport_set_flow_control(struct serdev_controller * ctrl,bool enable)189 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
190 {
191 struct serport *serport = serdev_controller_get_drvdata(ctrl);
192 struct tty_struct *tty = serport->tty;
193 struct ktermios ktermios = tty->termios;
194
195 if (enable)
196 ktermios.c_cflag |= CRTSCTS;
197 else
198 ktermios.c_cflag &= ~CRTSCTS;
199
200 tty_set_termios(tty, &ktermios);
201 }
202
ttyport_set_parity(struct serdev_controller * ctrl,enum serdev_parity parity)203 static int ttyport_set_parity(struct serdev_controller *ctrl,
204 enum serdev_parity parity)
205 {
206 struct serport *serport = serdev_controller_get_drvdata(ctrl);
207 struct tty_struct *tty = serport->tty;
208 struct ktermios ktermios = tty->termios;
209
210 ktermios.c_cflag &= ~(PARENB | PARODD | CMSPAR);
211 if (parity != SERDEV_PARITY_NONE) {
212 ktermios.c_cflag |= PARENB;
213 if (parity == SERDEV_PARITY_ODD)
214 ktermios.c_cflag |= PARODD;
215 }
216
217 tty_set_termios(tty, &ktermios);
218
219 if ((tty->termios.c_cflag & (PARENB | PARODD | CMSPAR)) !=
220 (ktermios.c_cflag & (PARENB | PARODD | CMSPAR)))
221 return -EINVAL;
222
223 return 0;
224 }
225
ttyport_wait_until_sent(struct serdev_controller * ctrl,long timeout)226 static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout)
227 {
228 struct serport *serport = serdev_controller_get_drvdata(ctrl);
229 struct tty_struct *tty = serport->tty;
230
231 tty_wait_until_sent(tty, timeout);
232 }
233
ttyport_get_tiocm(struct serdev_controller * ctrl)234 static int ttyport_get_tiocm(struct serdev_controller *ctrl)
235 {
236 struct serport *serport = serdev_controller_get_drvdata(ctrl);
237 struct tty_struct *tty = serport->tty;
238
239 if (!tty->ops->tiocmget)
240 return -ENOTSUPP;
241
242 return tty->ops->tiocmget(tty);
243 }
244
ttyport_set_tiocm(struct serdev_controller * ctrl,unsigned int set,unsigned int clear)245 static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear)
246 {
247 struct serport *serport = serdev_controller_get_drvdata(ctrl);
248 struct tty_struct *tty = serport->tty;
249
250 if (!tty->ops->tiocmset)
251 return -ENOTSUPP;
252
253 return tty->ops->tiocmset(tty, set, clear);
254 }
255
256 static const struct serdev_controller_ops ctrl_ops = {
257 .write_buf = ttyport_write_buf,
258 .write_flush = ttyport_write_flush,
259 .write_room = ttyport_write_room,
260 .open = ttyport_open,
261 .close = ttyport_close,
262 .set_flow_control = ttyport_set_flow_control,
263 .set_parity = ttyport_set_parity,
264 .set_baudrate = ttyport_set_baudrate,
265 .wait_until_sent = ttyport_wait_until_sent,
266 .get_tiocm = ttyport_get_tiocm,
267 .set_tiocm = ttyport_set_tiocm,
268 };
269
serdev_tty_port_register(struct tty_port * port,struct device * parent,struct tty_driver * drv,int idx)270 struct device *serdev_tty_port_register(struct tty_port *port,
271 struct device *parent,
272 struct tty_driver *drv, int idx)
273 {
274 struct serdev_controller *ctrl;
275 struct serport *serport;
276 bool platform = false;
277 int ret;
278
279 if (!port || !drv || !parent)
280 return ERR_PTR(-ENODEV);
281
282 ctrl = serdev_controller_alloc(parent, sizeof(struct serport));
283 if (!ctrl)
284 return ERR_PTR(-ENOMEM);
285 serport = serdev_controller_get_drvdata(ctrl);
286
287 serport->port = port;
288 serport->tty_idx = idx;
289 serport->tty_drv = drv;
290
291 ctrl->ops = &ctrl_ops;
292
293 port->client_ops = &client_ops;
294 port->client_data = ctrl;
295
296 /* There is not always a way to bind specific platform devices because
297 * they may be defined on platforms without DT or ACPI. When dealing
298 * with a platform devices, do not allow direct binding unless it is
299 * whitelisted by module parameter. If a platform device is otherwise
300 * described by DT or ACPI it will still be bound and this check will
301 * be ignored.
302 */
303 if (parent->bus == &platform_bus_type) {
304 if (pdev_tty_port) {
305 unsigned long pdev_idx;
306 int tty_len = strlen(drv->name);
307
308 if (!strncmp(pdev_tty_port, drv->name, tty_len)) {
309 if (!kstrtoul(pdev_tty_port + tty_len, 10,
310 &pdev_idx) && pdev_idx == idx) {
311 platform = true;
312 }
313 }
314 }
315 }
316
317 ret = serdev_controller_add_platform(ctrl, platform);
318 if (ret)
319 goto err_reset_data;
320
321 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx);
322 return &ctrl->dev;
323
324 err_reset_data:
325 port->client_data = NULL;
326 port->client_ops = &tty_port_default_client_ops;
327 serdev_controller_put(ctrl);
328
329 return ERR_PTR(ret);
330 }
331
serdev_tty_port_unregister(struct tty_port * port)332 int serdev_tty_port_unregister(struct tty_port *port)
333 {
334 struct serdev_controller *ctrl = port->client_data;
335 struct serport *serport = serdev_controller_get_drvdata(ctrl);
336
337 if (!serport)
338 return -ENODEV;
339
340 serdev_controller_remove(ctrl);
341 port->client_data = NULL;
342 port->client_ops = &tty_port_default_client_ops;
343 serdev_controller_put(ctrl);
344
345 return 0;
346 }
347