1 // SPDX-License-Identifier: GPL-2.0
3 * xhci-dbgtty.c - tty glue for xHCI debug capability
5 * Copyright (C) 2017 Intel Corporation
7 * Author: Lu Baolu <baolu.lu@linux.intel.com>
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
);