1 // SPDX-License-Identifier: GPL-2.0
3 * xhci-dbgtty.c - tty glue for xHCI debug capability
5 * Copyright (C) 2017 Intel Corporation
10 #include <linux/slab.h>
11 #include <linux/tty.h>
12 #include <linux/tty_flip.h>
15 #include "xhci-dbgcap.h"
18 dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size)
22 len = kfifo_len(&port->write_fifo);
26 size = kfifo_out(&port->write_fifo, packet, size);
30 static int dbc_start_tx(struct dbc_port *port)
31 __releases(&port->port_lock)
32 __acquires(&port->port_lock)
35 struct dbc_request *req;
37 bool do_tty_wake = false;
38 struct list_head *pool = &port->write_pool;
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);
48 list_del(&req->list_pool);
50 spin_unlock(&port->port_lock);
51 status = dbc_ep_queue(port->out, req, GFP_ATOMIC);
52 spin_lock(&port->port_lock);
55 list_add(&req->list_pool, pool);
60 if (do_tty_wake && port->port.tty)
61 tty_wakeup(port->port.tty);
66 static void dbc_start_rx(struct dbc_port *port)
67 __releases(&port->port_lock)
68 __acquires(&port->port_lock)
70 struct dbc_request *req;
72 struct list_head *pool = &port->read_pool;
74 while (!list_empty(pool)) {
78 req = list_entry(pool->next, struct dbc_request, list_pool);
79 list_del(&req->list_pool);
80 req->length = DBC_MAX_PACKET;
82 spin_unlock(&port->port_lock);
83 status = dbc_ep_queue(port->in, req, GFP_ATOMIC);
84 spin_lock(&port->port_lock);
87 list_add(&req->list_pool, pool);
94 dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
97 struct xhci_dbc *dbc = xhci->dbc;
98 struct dbc_port *port = &dbc->port;
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);
106 static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
109 struct xhci_dbc *dbc = xhci->dbc;
110 struct dbc_port *port = &dbc->port;
112 spin_lock_irqsave(&port->port_lock, flags);
113 list_add(&req->list_pool, &port->write_pool);
114 switch (req->status) {
121 xhci_warn(xhci, "unexpected write complete status %d\n",
125 spin_unlock_irqrestore(&port->port_lock, flags);
128 static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
131 dbc_free_request(dep, req);
135 xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head,
136 void (*fn)(struct xhci_hcd *, struct dbc_request *))
139 struct dbc_request *req;
141 for (i = 0; i < DBC_QUEUE_SIZE; i++) {
142 req = dbc_alloc_request(dep, GFP_KERNEL);
146 req->length = DBC_MAX_PACKET;
147 req->buf = kmalloc(req->length, GFP_KERNEL);
149 dbc_free_request(dep, req);
154 list_add_tail(&req->list_pool, head);
157 return list_empty(head) ? -ENOMEM : 0;
161 xhci_dbc_free_requests(struct dbc_ep *dep, struct list_head *head)
163 struct dbc_request *req;
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);
172 static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
174 struct dbc_port *port = driver->driver_state;
176 tty->driver_data = port;
178 return tty_port_install(&port->port, driver, tty);
181 static int dbc_tty_open(struct tty_struct *tty, struct file *file)
183 struct dbc_port *port = tty->driver_data;
185 return tty_port_open(&port->port, tty, file);
188 static void dbc_tty_close(struct tty_struct *tty, struct file *file)
190 struct dbc_port *port = tty->driver_data;
192 tty_port_close(&port->port, tty, file);
195 static int dbc_tty_write(struct tty_struct *tty,
196 const unsigned char *buf,
199 struct dbc_port *port = tty->driver_data;
202 spin_lock_irqsave(&port->port_lock, flags);
204 count = kfifo_in(&port->write_fifo, buf, count);
206 spin_unlock_irqrestore(&port->port_lock, flags);
211 static int dbc_tty_put_char(struct tty_struct *tty, unsigned char ch)
213 struct dbc_port *port = tty->driver_data;
217 spin_lock_irqsave(&port->port_lock, flags);
218 status = kfifo_put(&port->write_fifo, ch);
219 spin_unlock_irqrestore(&port->port_lock, flags);
224 static void dbc_tty_flush_chars(struct tty_struct *tty)
226 struct dbc_port *port = tty->driver_data;
229 spin_lock_irqsave(&port->port_lock, flags);
231 spin_unlock_irqrestore(&port->port_lock, flags);
234 static int dbc_tty_write_room(struct tty_struct *tty)
236 struct dbc_port *port = tty->driver_data;
240 spin_lock_irqsave(&port->port_lock, flags);
241 room = kfifo_avail(&port->write_fifo);
242 spin_unlock_irqrestore(&port->port_lock, flags);
247 static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
249 struct dbc_port *port = tty->driver_data;
253 spin_lock_irqsave(&port->port_lock, flags);
254 chars = kfifo_len(&port->write_fifo);
255 spin_unlock_irqrestore(&port->port_lock, flags);
260 static void dbc_tty_unthrottle(struct tty_struct *tty)
262 struct dbc_port *port = tty->driver_data;
265 spin_lock_irqsave(&port->port_lock, flags);
266 tasklet_schedule(&port->push);
267 spin_unlock_irqrestore(&port->port_lock, flags);
270 static 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,
282 static struct tty_driver *dbc_tty_driver;
284 int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci)
287 struct xhci_dbc *dbc = xhci->dbc;
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;
297 dbc_tty_driver->driver_name = "dbc_serial";
298 dbc_tty_driver->name = "ttyDBC";
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;
309 tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
311 status = tty_register_driver(dbc_tty_driver);
314 "can't register dbc tty driver, err %d\n", status);
315 put_tty_driver(dbc_tty_driver);
316 dbc_tty_driver = NULL;
322 void xhci_dbc_tty_unregister_driver(void)
324 if (dbc_tty_driver) {
325 tty_unregister_driver(dbc_tty_driver);
326 put_tty_driver(dbc_tty_driver);
327 dbc_tty_driver = NULL;
331 static void dbc_rx_push(unsigned long _port)
333 struct dbc_request *req;
334 struct tty_struct *tty;
336 bool do_push = false;
337 bool disconnect = false;
338 struct dbc_port *port = (void *)_port;
339 struct list_head *queue = &port->read_queue;
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);
346 if (tty && tty_throttled(tty))
349 switch (req->status) {
356 pr_warn("ttyDBC0: unexpected RX status %d\n",
362 char *packet = req->buf;
363 unsigned int n, size = req->actual;
372 count = tty_insert_flip_string(&port->port, packet,
377 port->n_read += count;
383 list_move(&req->list_pool, &port->read_pool);
387 tty_flip_buffer_push(&port->port);
389 if (!list_empty(queue) && tty) {
390 if (!tty_throttled(tty)) {
392 tasklet_schedule(&port->push);
394 pr_warn("ttyDBC0: RX not scheduled?\n");
401 spin_unlock_irqrestore(&port->port_lock, flags);
404 static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
407 struct dbc_port *port = container_of(_port, struct dbc_port, port);
409 spin_lock_irqsave(&port->port_lock, flags);
411 spin_unlock_irqrestore(&port->port_lock, flags);
416 static const struct tty_port_operations dbc_port_ops = {
417 .activate = dbc_port_activate,
421 xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port)
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);
430 port->in = get_in_ep(xhci);
431 port->out = get_out_ep(xhci);
432 port->port.ops = &dbc_port_ops;
437 xhci_dbc_tty_exit_port(struct dbc_port *port)
439 tasklet_kill(&port->push);
440 tty_port_destroy(&port->port);
443 int xhci_dbc_tty_register_device(struct xhci_hcd *xhci)
446 struct device *tty_dev;
447 struct xhci_dbc *dbc = xhci->dbc;
448 struct dbc_port *port = &dbc->port;
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);
458 ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
462 ret = xhci_dbc_alloc_requests(port->in, &port->read_pool,
467 ret = xhci_dbc_alloc_requests(port->out, &port->write_pool,
472 port->registered = true;
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);
482 tty_unregister_device(dbc_tty_driver, 0);
485 xhci_dbc_tty_exit_port(port);
487 xhci_err(xhci, "can't register tty port, err %d\n", ret);
492 void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci)
494 struct xhci_dbc *dbc = xhci->dbc;
495 struct dbc_port *port = &dbc->port;
497 tty_unregister_device(dbc_tty_driver, 0);
498 xhci_dbc_tty_exit_port(port);
499 port->registered = false;
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);