Loading drivers/mmc/card/sdio_uart.c +119 −82 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ struct sdio_uart_port { struct kref kref; struct tty_struct *tty; unsigned int index; unsigned int opened; struct sdio_func *func; struct mutex func_lock; struct task_struct *in_sdio_uart_irq; Loading Loading @@ -150,6 +149,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port) static void sdio_uart_port_remove(struct sdio_uart_port *port) { struct sdio_func *func; struct tty_struct *tty; BUG_ON(sdio_uart_table[port->index] != port); Loading @@ -170,10 +170,9 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) sdio_claim_host(func); port->func = NULL; mutex_unlock(&port->func_lock); if (port->opened) { struct tty_struct *tty = tty_port_tty_get(&port->port); tty = tty_port_tty_get(&port->port); /* tty_hangup is async so is this safe as is ?? */ if (tty) if (tty) { tty_hangup(tty); tty_kref_put(tty); } Loading Loading @@ -560,13 +559,46 @@ static void sdio_uart_irq(struct sdio_func *func) port->in_sdio_uart_irq = NULL; } static int sdio_uart_startup(struct sdio_uart_port *port) /** * uart_dtr_rts - port helper to set uart signals * @tport: tty port to be updated * @onoff: set to turn on DTR/RTS * * Called by the tty port helpers when the modem signals need to be * adjusted during an open, close and hangup. */ static void uart_dtr_rts(struct tty_port *tport, int onoff) { unsigned long page; int ret = -ENOMEM; struct tty_struct *tty = tty_port_tty_get(&port->port); struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); if (onoff == 0) sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); else sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* FIXME: What if it is NULL ?? */ /** * sdio_uart_activate - start up hardware * @tport: tty port to activate * @tty: tty bound to this port * * Activate a tty port. The port locking guarantees us this will be * run exactly once per set of opens, and if successful will see the * shutdown method run exactly once to match. Start up and shutdown are * protected from each other by the internal locking and will not run * at the same time even during a hangup event. * * If we successfully start up the port we take an extra kref as we * will keep it around until shutdown when the kref is dropped. */ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); unsigned long page; int ret; /* * Set the TTY IO error marker - we will only clear this Loading @@ -577,7 +609,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) /* Initialise and allocate the transmit buffer. */ page = __get_free_page(GFP_KERNEL); if (!page) goto err0; return -ENOMEM; port->xmit.buf = (unsigned char *)page; circ_clear(&port->xmit); Loading Loading @@ -631,7 +663,6 @@ static int sdio_uart_startup(struct sdio_uart_port *port) sdio_uart_irq(port->func); sdio_uart_release_func(port); tty_kref_put(tty); return 0; err3: Loading @@ -640,15 +671,25 @@ static int sdio_uart_startup(struct sdio_uart_port *port) sdio_uart_release_func(port); err1: free_page((unsigned long)port->xmit.buf); err0: tty_kref_put(tty); return ret; } static void sdio_uart_shutdown(struct sdio_uart_port *port) /** * sdio_uart_shutdown - stop hardware * @tport: tty port to shut down * * Deactivate a tty port. The port locking guarantees us this will be * run only if a successful matching activate already ran. The two are * protected from each other by the internal locking and will not run * at the same time even during a hangup event. */ static void sdio_uart_shutdown(struct tty_port *tport) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); int ret; struct tty_struct *tty; ret = sdio_uart_claim_func(port); if (ret) Loading @@ -656,14 +697,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) sdio_uart_stop_rx(port); /* TODO: wait here for TX FIFO to drain */ tty = tty_port_tty_get(&port->port); /* Turn off DTR and RTS early. */ if (tty && (tty->termios->c_cflag & HUPCL)) sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); tty_kref_put(tty); /* Disable interrupts from this port */ sdio_release_irq(port->func); port->ier = 0; Loading @@ -688,74 +721,68 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) free_page((unsigned long)port->xmit.buf); } static int sdio_uart_open(struct tty_struct *tty, struct file *filp) { struct sdio_uart_port *port; int ret; port = sdio_uart_port_get(tty->index); if (!port) return -ENODEV; mutex_lock(&port->port.mutex); /* * Make sure not to mess up with a dead port * which has not been closed yet. /** * sdio_uart_install - install method * @driver: the driver in use (sdio_uart in our case) * @tty: the tty being bound * * Look up and bind the tty and the driver together. Initialize * any needed private data (in our case the termios) */ if (tty->driver_data && tty->driver_data != port) { mutex_unlock(&port->port.mutex); sdio_uart_port_put(port); return -EBUSY; } if (!port->opened) { static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct sdio_uart_port *port = sdio_uart_port_get(idx); int ret = tty_init_termios(tty); if (ret == 0) { tty_driver_kref_get(driver); tty->count++; /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; tty_port_tty_set(&port->port, tty); ret = sdio_uart_startup(port); if (ret) { tty->driver_data = NULL; tty_port_tty_set(&port->port, NULL); mutex_unlock(&port->port.mutex); driver->ttys[idx] = tty; } else sdio_uart_port_put(port); return ret; } } port->opened++; mutex_unlock(&port->port.mutex); return 0; } static void sdio_uart_close(struct tty_struct *tty, struct file * filp) /** * sdio_uart_cleanup - called on the last tty kref drop * @tty: the tty being destroyed * * Called asynchronously when the last reference to the tty is dropped. * We cannot destroy the tty->driver_data port kref until this point */ static void sdio_uart_cleanup(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; if (!port) return; mutex_lock(&port->port.mutex); BUG_ON(!port->opened); tty->driver_data = NULL; /* Bug trap */ sdio_uart_port_put(port); } /* * This is messy. The tty layer calls us even when open() * returned an error. Ignore this close request if tty->count * is larger than port->count. * Open/close/hangup is now entirely boilerplate */ if (tty->count > port->opened) { mutex_unlock(&port->port.mutex); return; static int sdio_uart_open(struct tty_struct *tty, struct file *filp) { struct sdio_uart_port *port = tty->driver_data; return tty_port_open(&port->port, tty, filp); } if (--port->opened == 0) { tty->closing = 1; sdio_uart_shutdown(port); tty_ldisc_flush(tty); tty_port_tty_set(&port->port, NULL); tty->driver_data = NULL; tty->closing = 0; static void sdio_uart_close(struct tty_struct *tty, struct file * filp) { struct sdio_uart_port *port = tty->driver_data; tty_port_close(&port->port, tty, filp); } mutex_unlock(&port->port.mutex); sdio_uart_port_put(port); static void sdio_uart_hangup(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; tty_port_hangup(&port->port); } static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, Loading Loading @@ -1021,6 +1048,12 @@ static const struct file_operations sdio_uart_proc_fops = { .release = single_release, }; static const struct tty_port_operations sdio_uart_port_ops = { .dtr_rts = uart_dtr_rts, .shutdown = sdio_uart_shutdown, .activate = sdio_uart_activate, }; static const struct tty_operations sdio_uart_ops = { .open = sdio_uart_open, .close = sdio_uart_close, Loading @@ -1031,9 +1064,12 @@ static const struct tty_operations sdio_uart_ops = { .throttle = sdio_uart_throttle, .unthrottle = sdio_uart_unthrottle, .set_termios = sdio_uart_set_termios, .hangup = sdio_uart_hangup, .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, .install = sdio_uart_install, .cleanup = sdio_uart_cleanup, .proc_fops = &sdio_uart_proc_fops, }; Loading Loading @@ -1096,6 +1132,7 @@ static int sdio_uart_probe(struct sdio_func *func, port->func = func; sdio_set_drvdata(func, port); tty_port_init(&port->port); port->port.ops = &sdio_uart_port_ops; ret = sdio_uart_add_port(port); if (ret) { Loading Loading
drivers/mmc/card/sdio_uart.c +119 −82 Original line number Diff line number Diff line Loading @@ -77,7 +77,6 @@ struct sdio_uart_port { struct kref kref; struct tty_struct *tty; unsigned int index; unsigned int opened; struct sdio_func *func; struct mutex func_lock; struct task_struct *in_sdio_uart_irq; Loading Loading @@ -150,6 +149,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port) static void sdio_uart_port_remove(struct sdio_uart_port *port) { struct sdio_func *func; struct tty_struct *tty; BUG_ON(sdio_uart_table[port->index] != port); Loading @@ -170,10 +170,9 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) sdio_claim_host(func); port->func = NULL; mutex_unlock(&port->func_lock); if (port->opened) { struct tty_struct *tty = tty_port_tty_get(&port->port); tty = tty_port_tty_get(&port->port); /* tty_hangup is async so is this safe as is ?? */ if (tty) if (tty) { tty_hangup(tty); tty_kref_put(tty); } Loading Loading @@ -560,13 +559,46 @@ static void sdio_uart_irq(struct sdio_func *func) port->in_sdio_uart_irq = NULL; } static int sdio_uart_startup(struct sdio_uart_port *port) /** * uart_dtr_rts - port helper to set uart signals * @tport: tty port to be updated * @onoff: set to turn on DTR/RTS * * Called by the tty port helpers when the modem signals need to be * adjusted during an open, close and hangup. */ static void uart_dtr_rts(struct tty_port *tport, int onoff) { unsigned long page; int ret = -ENOMEM; struct tty_struct *tty = tty_port_tty_get(&port->port); struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); if (onoff == 0) sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); else sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* FIXME: What if it is NULL ?? */ /** * sdio_uart_activate - start up hardware * @tport: tty port to activate * @tty: tty bound to this port * * Activate a tty port. The port locking guarantees us this will be * run exactly once per set of opens, and if successful will see the * shutdown method run exactly once to match. Start up and shutdown are * protected from each other by the internal locking and will not run * at the same time even during a hangup event. * * If we successfully start up the port we take an extra kref as we * will keep it around until shutdown when the kref is dropped. */ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); unsigned long page; int ret; /* * Set the TTY IO error marker - we will only clear this Loading @@ -577,7 +609,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) /* Initialise and allocate the transmit buffer. */ page = __get_free_page(GFP_KERNEL); if (!page) goto err0; return -ENOMEM; port->xmit.buf = (unsigned char *)page; circ_clear(&port->xmit); Loading Loading @@ -631,7 +663,6 @@ static int sdio_uart_startup(struct sdio_uart_port *port) sdio_uart_irq(port->func); sdio_uart_release_func(port); tty_kref_put(tty); return 0; err3: Loading @@ -640,15 +671,25 @@ static int sdio_uart_startup(struct sdio_uart_port *port) sdio_uart_release_func(port); err1: free_page((unsigned long)port->xmit.buf); err0: tty_kref_put(tty); return ret; } static void sdio_uart_shutdown(struct sdio_uart_port *port) /** * sdio_uart_shutdown - stop hardware * @tport: tty port to shut down * * Deactivate a tty port. The port locking guarantees us this will be * run only if a successful matching activate already ran. The two are * protected from each other by the internal locking and will not run * at the same time even during a hangup event. */ static void sdio_uart_shutdown(struct tty_port *tport) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); int ret; struct tty_struct *tty; ret = sdio_uart_claim_func(port); if (ret) Loading @@ -656,14 +697,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) sdio_uart_stop_rx(port); /* TODO: wait here for TX FIFO to drain */ tty = tty_port_tty_get(&port->port); /* Turn off DTR and RTS early. */ if (tty && (tty->termios->c_cflag & HUPCL)) sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); tty_kref_put(tty); /* Disable interrupts from this port */ sdio_release_irq(port->func); port->ier = 0; Loading @@ -688,74 +721,68 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) free_page((unsigned long)port->xmit.buf); } static int sdio_uart_open(struct tty_struct *tty, struct file *filp) { struct sdio_uart_port *port; int ret; port = sdio_uart_port_get(tty->index); if (!port) return -ENODEV; mutex_lock(&port->port.mutex); /* * Make sure not to mess up with a dead port * which has not been closed yet. /** * sdio_uart_install - install method * @driver: the driver in use (sdio_uart in our case) * @tty: the tty being bound * * Look up and bind the tty and the driver together. Initialize * any needed private data (in our case the termios) */ if (tty->driver_data && tty->driver_data != port) { mutex_unlock(&port->port.mutex); sdio_uart_port_put(port); return -EBUSY; } if (!port->opened) { static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct sdio_uart_port *port = sdio_uart_port_get(idx); int ret = tty_init_termios(tty); if (ret == 0) { tty_driver_kref_get(driver); tty->count++; /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; tty_port_tty_set(&port->port, tty); ret = sdio_uart_startup(port); if (ret) { tty->driver_data = NULL; tty_port_tty_set(&port->port, NULL); mutex_unlock(&port->port.mutex); driver->ttys[idx] = tty; } else sdio_uart_port_put(port); return ret; } } port->opened++; mutex_unlock(&port->port.mutex); return 0; } static void sdio_uart_close(struct tty_struct *tty, struct file * filp) /** * sdio_uart_cleanup - called on the last tty kref drop * @tty: the tty being destroyed * * Called asynchronously when the last reference to the tty is dropped. * We cannot destroy the tty->driver_data port kref until this point */ static void sdio_uart_cleanup(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; if (!port) return; mutex_lock(&port->port.mutex); BUG_ON(!port->opened); tty->driver_data = NULL; /* Bug trap */ sdio_uart_port_put(port); } /* * This is messy. The tty layer calls us even when open() * returned an error. Ignore this close request if tty->count * is larger than port->count. * Open/close/hangup is now entirely boilerplate */ if (tty->count > port->opened) { mutex_unlock(&port->port.mutex); return; static int sdio_uart_open(struct tty_struct *tty, struct file *filp) { struct sdio_uart_port *port = tty->driver_data; return tty_port_open(&port->port, tty, filp); } if (--port->opened == 0) { tty->closing = 1; sdio_uart_shutdown(port); tty_ldisc_flush(tty); tty_port_tty_set(&port->port, NULL); tty->driver_data = NULL; tty->closing = 0; static void sdio_uart_close(struct tty_struct *tty, struct file * filp) { struct sdio_uart_port *port = tty->driver_data; tty_port_close(&port->port, tty, filp); } mutex_unlock(&port->port.mutex); sdio_uart_port_put(port); static void sdio_uart_hangup(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; tty_port_hangup(&port->port); } static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, Loading Loading @@ -1021,6 +1048,12 @@ static const struct file_operations sdio_uart_proc_fops = { .release = single_release, }; static const struct tty_port_operations sdio_uart_port_ops = { .dtr_rts = uart_dtr_rts, .shutdown = sdio_uart_shutdown, .activate = sdio_uart_activate, }; static const struct tty_operations sdio_uart_ops = { .open = sdio_uart_open, .close = sdio_uart_close, Loading @@ -1031,9 +1064,12 @@ static const struct tty_operations sdio_uart_ops = { .throttle = sdio_uart_throttle, .unthrottle = sdio_uart_unthrottle, .set_termios = sdio_uart_set_termios, .hangup = sdio_uart_hangup, .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, .install = sdio_uart_install, .cleanup = sdio_uart_cleanup, .proc_fops = &sdio_uart_proc_fops, }; Loading Loading @@ -1096,6 +1132,7 @@ static int sdio_uart_probe(struct sdio_func *func, port->func = func; sdio_set_drvdata(func, port); tty_port_init(&port->port); port->port.ops = &sdio_uart_port_ops; ret = sdio_uart_add_port(port); if (ret) { Loading