/**
 * 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__);
}
Ejemplo n.º 2
0
/**
 * 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__);
}
Ejemplo n.º 3
0
/**
 * 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__);
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
/**
 * 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__);
}
Ejemplo n.º 6
0
/**
 * 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__);
}
Ejemplo n.º 7
0
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__);
}