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