static int gs_start_io(struct gs_port *port) { struct list_head *head = &port->read_pool; struct usb_ep *ep = port->port_usb->out; int status; unsigned started; status = gs_alloc_requests(ep, head, RX_QUEUE_SIZE, RX_BUF_SIZE, gs_read_complete); if (status) return status; status = gs_alloc_requests(port->port_usb->in, &port->write_pool, TX_QUEUE_SIZE, TX_BUF_SIZE, gs_write_complete); if (status) { gs_free_requests(ep, head); return status; } port->n_read = 0; started = gs_start_rx(port); if (started) { tty_wakeup(port->port_tty); } else { gs_free_requests(ep, head); gs_free_requests(port->port_usb->in, &port->write_pool); status = -EIO; } return status; }
/** * gs_start_io - start USB I/O streams * @dev: encapsulates endpoints to use * Context: holding port_lock; port_tty and port_usb are non-null * * We only start I/O when something is connected to both sides of * this port. If nothing is listening on the host side, we may * be pointlessly filling up our TX buffers and FIFO. */ static int gs_start_io(struct gs_port *port) { struct list_head *head; struct usb_ep *ep; int status; unsigned started; if (!port || !port->port_usb) { pr_err("Error - port or port->usb is NULL."); return -EIO; } head = &port->read_pool; ep = port->port_usb->out; /* Allocate RX and TX I/O buffers. We can't easily do this much * earlier (with GFP_KERNEL) because the requests are coupled to * endpoints, as are the packet sizes we'll be using. Different * configurations may use different endpoints with a given port; * and high speed vs full speed changes packet sizes too. */ status = gs_alloc_requests(ep, head, RX_QUEUE_SIZE, RX_BUF_SIZE, gs_read_complete, &port->read_allocated); if (status) return status; status = gs_alloc_requests(port->port_usb->in, &port->write_pool, TX_QUEUE_SIZE, TX_BUF_SIZE, gs_write_complete, &port->write_allocated); if (status) { gs_free_requests(ep, head, &port->read_allocated); return status; } /* queue read requests */ port->n_read = 0; started = gs_start_rx(port); if (!port->port.tty) { printk(KERN_ERR "usb:[%s] port_usb or port_tty is NULL!! started(%d)\n", __func__, started); return -EIO; } /* unblock any pending writes into our circular buffer */ if (started) { tty_wakeup(port->port.tty); } else { gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(port->port_usb->in, &port->write_pool, &port->write_allocated); status = -EIO; } return status; }
/** * gs_start_io - start USB I/O streams * @dev: encapsulates endpoints to use * Context: holding port_lock; port_tty and port_usb are non-null * * We only start I/O when something is connected to both sides of * this port. If nothing is listening on the host side, we may * be pointlessly filling up our TX buffers and FIFO. */ static int gs_start_io(struct gs_port *port) { struct list_head *head = &port->read_pool; struct usb_ep *ep = port->port_usb->out; int status; unsigned started; /* Allocate RX and TX I/O buffers. We can't easily do this much * earlier (with GFP_KERNEL) because the requests are coupled to * endpoints, as are the packet sizes we'll be using. Different * configurations may use different endpoints with a given port; * and high speed vs full speed changes packet sizes too. */ status = gs_alloc_requests(ep, head, RX_QUEUE_SIZE, RX_BUF_SIZE, gs_read_complete, &port->read_allocated); if (status) return status; status = gs_alloc_requests(port->port_usb->in, &port->write_pool, TX_QUEUE_SIZE, TX_BUF_SIZE, gs_write_complete, &port->write_allocated); if (status) { gs_free_requests(ep, head, &port->read_allocated); return status; } /* queue read requests */ port->n_read = 0; started = gs_start_rx(port); if (!port->port_usb) return -EIO; /* unblock any pending writes into our circular buffer */ #ifndef CONFIG_USB_G_SERIAL_CONSOLE if (started) { tty_wakeup(port->port_tty); } else { gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(port->port_usb->in, &port->write_pool, &port->write_allocated); status = -EIO; } #else if (!port->port_tty) return status; if(started){ tty_wakeup(port->port_tty); } else { gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(port->port_usb->in, &port->write_pool, &port->write_allocated); status = -EIO; } #endif return status; }
/** * 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); }
/* *alloc read and write request for usb io *and init this request with read and write complete funciton */ static int gs_start_io_mine(struct gs_port *port) { struct list_head *head = &port->read_pool; struct usb_ep *ep = port->port_usb->out; int status; unsigned started; /* Allocate RX and TX I/O buffers. We can't easily do this much * earlier (with GFP_KERNEL) because the requests are coupled to * endpoints, as are the packet sizes we'll be using. Different * configurations may use different endpoints with a given port; * and high speed vs full speed changes packet sizes too. */ status = gs_alloc_requests(ep, head, gs_read_complete, &port->read_allocated); if (status) return status; status = gs_alloc_requests(port->port_usb->in, &port->write_pool, gs_write_complete, &port->write_allocated); if (status) { gs_free_requests(ep, head, &port->read_allocated); return status; } }
/** * 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_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); /* * Freeing the previously queued requests as they are * allocated again as a part of gs_open() */ if (port->port_usb) { spin_unlock_irq(&port->port_lock); usb_ep_fifo_flush(gser->out); usb_ep_fifo_flush(gser->in); spin_lock_irq(&port->port_lock); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); } port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; 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_interruptible(&port->close_wait); if (port->port_usb) { spin_unlock_irq(&port->port_lock); usb_ep_fifo_flush(gser->out); usb_ep_fifo_flush(gser->in); spin_lock_irq(&port->port_lock); gs_free_requests(gser->out, &port->read_queue, NULL); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->in, &port->write_pool, NULL); } port->read_allocated = port->read_started = port->write_allocated = port->write_started = 0; exit: spin_unlock_irq(&port->port_lock); }