/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; #ifdef CONFIG_USB_AUTO_INSTALL int ret; #endif if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ /* * port-bridge application will hold one file descriptor to gserial after usb mode switch sometimes * so wait_event will never get out ,further block kernel thread "suspend" and block console_early_suspend * which makes the whole system hang. */ #ifndef CONFIG_USB_AUTO_INSTALL wait_event(port->close_wait, gs_closed(port)); #else ret = wait_event_timeout(port->close_wait, gs_closed(port),HZ/10); pr_debug("%s timeout %d <\n",__func__,ret); #endif WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); tasklet_kill(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; tty_unregister_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ pr_info("gs_cleanup: unregister tty!\n"); for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); pr_info("gs_cleanup: wait port close!\n"); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); tasklet_kill(&port->push); pr_info("gs_cleanup: port%d++\n", i); /* wait for old opens to finish */ wait_event_timeout(port->close_wait, gs_closed(port), 2*HZ); if(!gs_closed(port)){ pr_info("%s: port %d still open, forcely close it!\n", __func__, i); gs_close_forcely(port); pr_info("%s: wait port %d close event again!\n", __func__, i); wait_event(port->close_wait, gs_closed(port)); pr_info("%s: wait port %d close event done!\n", __func__, i); } pr_info("gs_cleanup: port%d--\n", i); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; tty_unregister_driver(gs_tty_driver); gs_tty_driver = NULL; pr_info("%s: cleaned up ttyGS* support\n", __func__); }
static void gserial_free_port(struct gs_port *port) { tasklet_kill(&port->push); /* wait for old opens to finish */ wait_event(port->port.close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); tty_port_destroy(&port->port); kfree(port); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; int ret; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ #if 0 wait_event(port->close_wait, gs_closed(port)); #else ret = wait_event_timeout(port->close_wait, gs_closed(port),HZ/10); pr_debug("%s timeout %d <\n",__func__,ret); #endif WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
/** * gserial_cleanup - remove TTY-over-USB driver and devices * Context: may sleep * * This is called to free all resources allocated by @gserial_setup(). * Accordingly, it may need to wait until some open /dev/ files have * closed. * * The caller must have issued @gserial_disconnect() for any ports * that had previously been connected, so that there is never any * I/O pending when it's called. */ void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { /* prevent new opens */ mutex_lock(&ports[i].lock); port = ports[i].port; #ifdef CONFIG_USB_G_SERIAL_CONSOLE // unregister_console(&port->port_console); #endif ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); /* wait for old opens to finish */ wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }
void gserial_cleanup(void) { unsigned i; struct gs_port *port; if (!gs_tty_driver) return; for (i = 0; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i); for (i = 0; i < n_ports; i++) { mutex_lock(&ports[i].lock); port = ports[i].port; ports[i].port = NULL; mutex_unlock(&ports[i].lock); cancel_work_sync(&port->push); wait_event(port->close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); kfree(port); } n_ports = 0; usb_debugfs_remove(); destroy_workqueue(gserial_wq); tty_unregister_driver(gs_tty_driver); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_debug("%s: cleaned up ttyGS* support\n", __func__); }