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