1
2
3
4
5
6
7
8
9
10#include <linux/slab.h>
11#include <linux/tty.h>
12#include <linux/tty_flip.h>
13
14#include "xhci.h"
15#include "xhci-dbgcap.h"
16
17static unsigned int
18dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size)
19{
20 unsigned int len;
21
22 len = kfifo_len(&port->write_fifo);
23 if (len < size)
24 size = len;
25 if (size != 0)
26 size = kfifo_out(&port->write_fifo, packet, size);
27 return size;
28}
29
30static int dbc_start_tx(struct dbc_port *port)
31 __releases(&port->port_lock)
32 __acquires(&port->port_lock)
33{
34 int len;
35 struct dbc_request *req;
36 int status = 0;
37 bool do_tty_wake = false;
38 struct list_head *pool = &port->write_pool;
39
40 while (!list_empty(pool)) {
41 req = list_entry(pool->next, struct dbc_request, list_pool);
42 len = dbc_send_packet(port, req->buf, DBC_MAX_PACKET);
43 if (len == 0)
44 break;
45 do_tty_wake = true;
46
47 req->length = len;
48 list_del(&req->list_pool);
49
50 spin_unlock(&port->port_lock);
51 status = dbc_ep_queue(port->out, req, GFP_ATOMIC);
52 spin_lock(&port->port_lock);
53
54 if (status) {
55 list_add(&req->list_pool, pool);
56 break;
57 }
58 }
59
60 if (do_tty_wake && port->port.tty)
61 tty_wakeup(port->port.tty);
62
63 return status;
64}
65
66static void dbc_start_rx(struct dbc_port *port)
67 __releases(&port->port_lock)
68 __acquires(&port->port_lock)
69{
70 struct dbc_request *req;
71 int status;
72 struct list_head *pool = &port->read_pool;
73
74 while (!list_empty(pool)) {
75 if (!port->port.tty)
76 break;
77
78 req = list_entry(pool->next, struct dbc_request, list_pool);
79 list_del(&req->list_pool);
80 req->length = DBC_MAX_PACKET;
81
82 spin_unlock(&port->port_lock);
83 status = dbc_ep_queue(port->in, req, GFP_ATOMIC);
84 spin_lock(&port->port_lock);
85
86 if (status) {
87 list_add(&req->list_pool, pool);
88 break;
89 }
90 }
91}
92
93static void
94dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
95{
96 unsigned long flags;
97 struct xhci_dbc *dbc = xhci->dbc;
98 struct dbc_port *port = &dbc->port;
99
100 spin_lock_irqsave(&port->port_lock, flags);
101 list_add_tail(&req->list_pool, &port->read_queue);
102 tasklet_schedule(&port->push);
103 spin_unlock_irqrestore(&port->port_lock, flags);
104}
105
106static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
107{
108 unsigned long flags;
109 struct xhci_dbc *dbc = xhci->dbc;
110 struct dbc_port *port = &dbc->port;
111
112 spin_lock_irqsave(&port->port_lock, flags);
113 list_add(&req->list_pool, &port->write_pool);
114 switch (req->status) {
115 case 0:
116 dbc_start_tx(port);
117 break;
118 case -ESHUTDOWN:
119 break;
120 default:
121 xhci_warn(xhci, "unexpected write complete status %d\n",
122 req->status);
123 break;
124 }
125 spin_unlock_irqrestore(&port->port_lock, flags);
126}
127
128static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
129{
130 kfree(req->buf);
131 dbc_free_request(dep, req);
132}
133
134static int
135xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head,
136 void (*fn)(struct xhci_hcd *, struct dbc_request *))
137{
138 int i;
139 struct dbc_request *req;
140
141 for (i = 0; i < DBC_QUEUE_SIZE; i++) {
142 req = dbc_alloc_request(dep, GFP_ATOMIC);
143 if (!req)
144 break;
145
146 req->length = DBC_MAX_PACKET;
147 req->buf = kmalloc(req->length, GFP_KERNEL);
148 if (!req->buf) {
149 xhci_dbc_free_req(dep, req);
150 break;
151 }
152
153 req->complete = fn;
154 list_add_tail(&req->list_pool, head);
155 }
156
157 return list_empty(head) ? -ENOMEM : 0;
158}
159
160static void
161xhci_dbc_free_requests(struct dbc_ep *dep, struct list_head *head)
162{
163 struct dbc_request *req;
164
165 while (!list_empty(head)) {
166 req = list_entry(head->next, struct dbc_request, list_pool);
167 list_del(&req->list_pool);
168 xhci_dbc_free_req(dep, req);
169 }
170}
171
172static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
173{
174 struct dbc_port *port = driver->driver_state;
175
176 tty->driver_data = port;
177
178 return tty_port_install(&port->port, driver, tty);
179}
180
181static int dbc_tty_open(struct tty_struct *tty, struct file *file)
182{
183 struct dbc_port *port = tty->driver_data;
184
185 return tty_port_open(&port->port, tty, file);
186}
187
188static void dbc_tty_close(struct tty_struct *tty, struct file *file)
189{
190 struct dbc_port *port = tty->driver_data;
191
192 tty_port_close(&port->port, tty, file);
193}
194
195static int dbc_tty_write(struct tty_struct *tty,
196 const unsigned char *buf,
197 int count)
198{
199 struct dbc_port *port = tty->driver_data;
200 unsigned long flags;
201
202 spin_lock_irqsave(&port->port_lock, flags);
203 if (count)
204 count = kfifo_in(&port->write_fifo, buf, count);
205 dbc_start_tx(port);
206 spin_unlock_irqrestore(&port->port_lock, flags);
207
208 return count;
209}
210
211static int dbc_tty_put_char(struct tty_struct *tty, unsigned char ch)
212{
213 struct dbc_port *port = tty->driver_data;
214 unsigned long flags;
215 int status;
216
217 spin_lock_irqsave(&port->port_lock, flags);
218 status = kfifo_put(&port->write_fifo, ch);
219 spin_unlock_irqrestore(&port->port_lock, flags);
220
221 return status;
222}
223
224static void dbc_tty_flush_chars(struct tty_struct *tty)
225{
226 struct dbc_port *port = tty->driver_data;
227 unsigned long flags;
228
229 spin_lock_irqsave(&port->port_lock, flags);
230 dbc_start_tx(port);
231 spin_unlock_irqrestore(&port->port_lock, flags);
232}
233
234static int dbc_tty_write_room(struct tty_struct *tty)
235{
236 struct dbc_port *port = tty->driver_data;
237 unsigned long flags;
238 int room = 0;
239
240 spin_lock_irqsave(&port->port_lock, flags);
241 room = kfifo_avail(&port->write_fifo);
242 spin_unlock_irqrestore(&port->port_lock, flags);
243
244 return room;
245}
246
247static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
248{
249 struct dbc_port *port = tty->driver_data;
250 unsigned long flags;
251 int chars = 0;
252
253 spin_lock_irqsave(&port->port_lock, flags);
254 chars = kfifo_len(&port->write_fifo);
255 spin_unlock_irqrestore(&port->port_lock, flags);
256
257 return chars;
258}
259
260static void dbc_tty_unthrottle(struct tty_struct *tty)
261{
262 struct dbc_port *port = tty->driver_data;
263 unsigned long flags;
264
265 spin_lock_irqsave(&port->port_lock, flags);
266 tasklet_schedule(&port->push);
267 spin_unlock_irqrestore(&port->port_lock, flags);
268}
269
270static const struct tty_operations dbc_tty_ops = {
271 .install = dbc_tty_install,
272 .open = dbc_tty_open,
273 .close = dbc_tty_close,
274 .write = dbc_tty_write,
275 .put_char = dbc_tty_put_char,
276 .flush_chars = dbc_tty_flush_chars,
277 .write_room = dbc_tty_write_room,
278 .chars_in_buffer = dbc_tty_chars_in_buffer,
279 .unthrottle = dbc_tty_unthrottle,
280};
281
282static struct tty_driver *dbc_tty_driver;
283
284int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci)
285{
286 int status;
287 struct xhci_dbc *dbc = xhci->dbc;
288
289 dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
290 TTY_DRIVER_DYNAMIC_DEV);
291 if (IS_ERR(dbc_tty_driver)) {
292 status = PTR_ERR(dbc_tty_driver);
293 dbc_tty_driver = NULL;
294 return status;
295 }
296
297 dbc_tty_driver->driver_name = "dbc_serial";
298 dbc_tty_driver->name = "ttyDBC";
299
300 dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
301 dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
302 dbc_tty_driver->init_termios = tty_std_termios;
303 dbc_tty_driver->init_termios.c_cflag =
304 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
305 dbc_tty_driver->init_termios.c_ispeed = 9600;
306 dbc_tty_driver->init_termios.c_ospeed = 9600;
307 dbc_tty_driver->driver_state = &dbc->port;
308
309 tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
310
311 status = tty_register_driver(dbc_tty_driver);
312 if (status) {
313 xhci_err(xhci,
314 "can't register dbc tty driver, err %d\n", status);
315 put_tty_driver(dbc_tty_driver);
316 dbc_tty_driver = NULL;
317 }
318
319 return status;
320}
321
322void xhci_dbc_tty_unregister_driver(void)
323{
324 if (dbc_tty_driver) {
325 tty_unregister_driver(dbc_tty_driver);
326 put_tty_driver(dbc_tty_driver);
327 dbc_tty_driver = NULL;
328 }
329}
330
331static void dbc_rx_push(unsigned long _port)
332{
333 struct dbc_request *req;
334 struct tty_struct *tty;
335 unsigned long flags;
336 bool do_push = false;
337 bool disconnect = false;
338 struct dbc_port *port = (void *)_port;
339 struct list_head *queue = &port->read_queue;
340
341 spin_lock_irqsave(&port->port_lock, flags);
342 tty = port->port.tty;
343 while (!list_empty(queue)) {
344 req = list_first_entry(queue, struct dbc_request, list_pool);
345
346 if (tty && tty_throttled(tty))
347 break;
348
349 switch (req->status) {
350 case 0:
351 break;
352 case -ESHUTDOWN:
353 disconnect = true;
354 break;
355 default:
356 pr_warn("ttyDBC0: unexpected RX status %d\n",
357 req->status);
358 break;
359 }
360
361 if (req->actual) {
362 char *packet = req->buf;
363 unsigned int n, size = req->actual;
364 int count;
365
366 n = port->n_read;
367 if (n) {
368 packet += n;
369 size -= n;
370 }
371
372 count = tty_insert_flip_string(&port->port, packet,
373 size);
374 if (count)
375 do_push = true;
376 if (count != size) {
377 port->n_read += count;
378 break;
379 }
380 port->n_read = 0;
381 }
382
383 list_move(&req->list_pool, &port->read_pool);
384 }
385
386 if (do_push)
387 tty_flip_buffer_push(&port->port);
388
389 if (!list_empty(queue) && tty) {
390 if (!tty_throttled(tty)) {
391 if (do_push)
392 tasklet_schedule(&port->push);
393 else
394 pr_warn("ttyDBC0: RX not scheduled?\n");
395 }
396 }
397
398 if (!disconnect)
399 dbc_start_rx(port);
400
401 spin_unlock_irqrestore(&port->port_lock, flags);
402}
403
404static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
405{
406 unsigned long flags;
407 struct dbc_port *port = container_of(_port, struct dbc_port, port);
408
409 spin_lock_irqsave(&port->port_lock, flags);
410 dbc_start_rx(port);
411 spin_unlock_irqrestore(&port->port_lock, flags);
412
413 return 0;
414}
415
416static const struct tty_port_operations dbc_port_ops = {
417 .activate = dbc_port_activate,
418};
419
420static void
421xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port)
422{
423 tty_port_init(&port->port);
424 spin_lock_init(&port->port_lock);
425 tasklet_init(&port->push, dbc_rx_push, (unsigned long)port);
426 INIT_LIST_HEAD(&port->read_pool);
427 INIT_LIST_HEAD(&port->read_queue);
428 INIT_LIST_HEAD(&port->write_pool);
429
430 port->in = get_in_ep(xhci);
431 port->out = get_out_ep(xhci);
432 port->port.ops = &dbc_port_ops;
433 port->n_read = 0;
434}
435
436static void
437xhci_dbc_tty_exit_port(struct dbc_port *port)
438{
439 tasklet_kill(&port->push);
440 tty_port_destroy(&port->port);
441}
442
443int xhci_dbc_tty_register_device(struct xhci_hcd *xhci)
444{
445 int ret;
446 struct device *tty_dev;
447 struct xhci_dbc *dbc = xhci->dbc;
448 struct dbc_port *port = &dbc->port;
449
450 xhci_dbc_tty_init_port(xhci, port);
451 tty_dev = tty_port_register_device(&port->port,
452 dbc_tty_driver, 0, NULL);
453 if (IS_ERR(tty_dev)) {
454 ret = PTR_ERR(tty_dev);
455 goto register_fail;
456 }
457
458 ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
459 if (ret)
460 goto buf_alloc_fail;
461
462 ret = xhci_dbc_alloc_requests(port->in, &port->read_pool,
463 dbc_read_complete);
464 if (ret)
465 goto request_fail;
466
467 ret = xhci_dbc_alloc_requests(port->out, &port->write_pool,
468 dbc_write_complete);
469 if (ret)
470 goto request_fail;
471
472 port->registered = true;
473
474 return 0;
475
476request_fail:
477 xhci_dbc_free_requests(port->in, &port->read_pool);
478 xhci_dbc_free_requests(port->out, &port->write_pool);
479 kfifo_free(&port->write_fifo);
480
481buf_alloc_fail:
482 tty_unregister_device(dbc_tty_driver, 0);
483
484register_fail:
485 xhci_dbc_tty_exit_port(port);
486
487 xhci_err(xhci, "can't register tty port, err %d\n", ret);
488
489 return ret;
490}
491
492void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci)
493{
494 struct xhci_dbc *dbc = xhci->dbc;
495 struct dbc_port *port = &dbc->port;
496
497 tty_unregister_device(dbc_tty_driver, 0);
498 xhci_dbc_tty_exit_port(port);
499 port->registered = false;
500
501 kfifo_free(&port->write_fifo);
502 xhci_dbc_free_requests(get_out_ep(xhci), &port->read_pool);
503 xhci_dbc_free_requests(get_out_ep(xhci), &port->read_queue);
504 xhci_dbc_free_requests(get_in_ep(xhci), &port->write_pool);
505}
506