static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; struct gserial *gser; spin_lock_irq(&port->port_lock); if (port->open_count != 1) { if (port->open_count == 0) WARN_ON(1); else --port->open_count; goto exit; } pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file); /* mark port as closing but in use; we can drop port lock * and sleep if necessary */ port->openclose = true; port->open_count = 0; gser = port->port_usb; if (gser && gser->disconnect) gser->disconnect(gser); /* wait for circular write buffer to drain, disconnect, or at * most GS_CLOSE_TIMEOUT seconds; then discard the rest */ if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { spin_unlock_irq(&port->port_lock); wait_event_interruptible_timeout(port->drain_wait, gs_writes_finished(port), GS_CLOSE_TIMEOUT * HZ); spin_lock_irq(&port->port_lock); gser = port->port_usb; } /* Iff we're disconnected, there can be no I/O in flight so it's * ok to free the circular buffer; else just scrub it. And don't * let the push work queue fire again until we're re-opened. */ if (gser == NULL) gs_buf_free(&port->port_write_buf); else gs_buf_clear(&port->port_write_buf); tty->driver_data = NULL; port->port_tty = NULL; port->openclose = false; pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); wake_up_interruptible(&port->close_wait); exit: spin_unlock_irq(&port->port_lock); }
static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; struct gserial *gser; spin_lock_irq(&port->port_lock); if (port->open_count != 1) { if (port->open_count == 0) WARN_ON(1); else --port->open_count; goto exit; } pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file); port->openclose = true; port->open_count = 0; gser = port->port_usb; if (gser && gser->disconnect) gser->disconnect(gser); if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { spin_unlock_irq(&port->port_lock); wait_event_interruptible_timeout(port->drain_wait, gs_writes_finished(port), GS_CLOSE_TIMEOUT * HZ); spin_lock_irq(&port->port_lock); gser = port->port_usb; } if (gser == NULL) gs_buf_free(&port->port_write_buf); else gs_buf_clear(&port->port_write_buf); tty->driver_data = NULL; port->port_tty = NULL; port->openclose = false; pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); wake_up(&port->close_wait); exit: spin_unlock_irq(&port->port_lock); }
/** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called * Context: any (usually from irq) * * This is called to deactivate endpoints and let the TTY layer know * that the connection went inactive ... not unlike "hangup". * * On return, the state is as if gserial_connect() had never been called; * there is no active USB I/O on these endpoints. */ void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; if (!port) return; /* tell the TTY glue not to do I/O here any more */ spin_lock_irqsave(&port->port_lock, flags); /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); /* * don't need to hangup tty, it may stop the tty working, * when remove usb device. */ /* if (port->port_tty) tty_hangup(port->port_tty); */ } spin_unlock_irqrestore(&port->port_lock, flags); /* disable endpoints, aborting down any active I/O */ usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; spin_unlock_irqrestore(&port->port_lock, flags); port->stat_port_is_connect = 0; port->is_suspend = 0; }
/** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called * Context: any (usually from irq) * * This is called to deactivate endpoints and let the TTY layer know * that the connection went inactive ... not unlike "hangup". * * On return, the state is as if gserial_connect() had never been called; * there is no active USB I/O on these endpoints. */ void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; if (!port) return; /* tell the TTY glue not to do I/O here any more */ #ifdef CONFIG_USB_G_SERIAL_CONSOLE // unregister_console(&port->port_console); schedule_work(&port->work_unregister); #endif spin_lock_irqsave(&port->port_lock, flags); /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) tty_hangup(port->port_tty); } spin_unlock_irqrestore(&port->port_lock, flags); /* disable endpoints, aborting down any active I/O */ usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; port->nbytes_from_host = port->nbytes_to_tty = port->nbytes_from_tty = port->nbytes_to_host = 0; spin_unlock_irqrestore(&port->port_lock, flags); }
/** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called * Context: any (usually from irq) * * This is called to deactivate endpoints and let the TTY layer know * that the connection went inactive ... not unlike "hangup". * * On return, the state is as if gserial_connect() had never been called; * there is no active USB I/O on these endpoints. */ void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; if (!port) return; if (port->port_num == ACM_LOGGING_PORT) if (acm_logging_cb->stop) acm_logging_cb->stop(); /* tell the TTY glue not to do I/O here any more */ spin_lock_irqsave(&port->port_lock, flags); /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) tty_hangup(port->port_tty); } spin_unlock_irqrestore(&port->port_lock, flags); /* disable endpoints, aborting down any active I/O */ usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; spin_unlock_irqrestore(&port->port_lock, flags); }
void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; if (!port) return; spin_lock_irqsave(&port->port_lock, flags); port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) tty_hangup(port->port_tty); } spin_unlock_irqrestore(&port->port_lock, flags); usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; port->nbytes_from_host = port->nbytes_to_tty = port->nbytes_from_tty = port->nbytes_to_host = 0; spin_unlock_irqrestore(&port->port_lock, flags); }
/** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called * Context: any (usually from irq) * * This is called to deactivate endpoints and let the TTY layer know * that the connection went inactive ... not unlike "hangup". * * On return, the state is as if gserial_connect() had never been called; * there is no active USB I/O on these endpoints. */ void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; pr_info("Davis: enter gserial_disconnect port_num %d\n", port->port_num); if (!port) return; /* tell the TTY glue not to do I/O here any more */ spin_lock_irqsave(&port->port_lock, flags); /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) tty_hangup(port->port_tty); } spin_unlock_irqrestore(&port->port_lock, flags); /* disable endpoints, aborting down any active I/O */ usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool); gs_free_requests(gser->out, &port->read_queue); gs_free_requests(gser->in, &port->write_pool); spin_unlock_irqrestore(&port->port_lock, flags); // Davis: close the gserial port #ifdef CONFIG_USB_SERIAL_RELAY if(port->port_num == GS_PORT_NUM) gs_deinit_port(port->port_num); #endif }
/** * gserial_disconnect - notify TTY I/O glue that USB link is inactive * @gser: the function, on which gserial_connect() was called * Context: any (usually from irq) * * This is called to deactivate endpoints and let the TTY layer know * that the connection went inactive ... not unlike "hangup". * * On return, the state is as if gserial_connect() had never been called; * there is no active USB I/O on these endpoints. */ void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; unsigned long flags; pr_vdebug("%s\n", __func__); if (!port) return; /* tell the TTY glue not to do I/O here any more */ spin_lock_irqsave(&port->port_lock, flags); /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; port->port_usb = NULL; gser->ioport = NULL; #if 0 if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) tty_hangup(port->port_tty); } #endif spin_unlock_irqrestore(&port->port_lock, flags); /* disable endpoints, aborting down any active I/O */ usb_ep_fifo_flush(gser->out); usb_ep_fifo_flush(gser->in); usb_ep_disable(gser->out); gser->out->driver_data = NULL; usb_ep_disable(gser->in); gser->in->driver_data = NULL; /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->open_count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool); gs_free_requests(gser->out, &port->read_queue); gs_free_requests(gser->in, &port->write_pool); spin_unlock_irqrestore(&port->port_lock, flags); }
static void gs_deinit_port(int port_num) { struct gs_port *port; struct gserial *gser; pr_info("Davis: enter gs_deinit_port port_num %d\n", port_num); if (!gs_tty_driver || port_num >= n_ports) return; tty_port_relay_unregister_gs(gs_tty_driver); /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; spin_lock_irq(&port->port_lock); if (port->open_count != 1) { if (port->open_count == 0) WARN_ON(1); else --port->open_count; goto exit; } pr_info("gs_deinit_port: ttyGS%d ...\n", port->port_num); /* mark port as closing but in use; we can drop port lock * and sleep if necessary */ port->openclose = true; port->open_count = 0; gser = port->port_usb; //if (gser && gser->disconnect) Davis: temp // gser->disconnect(gser); Davis: temp /* wait for circular write buffer to drain, disconnect, or at * most GS_CLOSE_TIMEOUT seconds; then discard the rest */ if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { spin_unlock_irq(&port->port_lock); wait_event_interruptible_timeout(port->drain_wait, gs_writes_finished(port), GS_CLOSE_TIMEOUT * HZ); spin_lock_irq(&port->port_lock); gser = port->port_usb; } /* Iff we're disconnected, there can be no I/O in flight so it's * ok to free the circular buffer; else just scrub it. And don't * let the push tasklet fire again until we're re-opened. */ if (gser == NULL) gs_buf_free(&port->port_write_buf); else gs_buf_clear(&port->port_write_buf); //tty->driver_data = NULL;Davis: temp port->port_tty = NULL; port->openclose = false; pr_debug("gs_deinit_port: ttyGS%d done!\n", port->port_num); wake_up_interruptible(&port->close_wait); exit: spin_unlock_irq(&port->port_lock); }