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