/* * gs_start_tx * * This function finds available write requests, calls * gs_send_packet to fill these packets with data, and * continues until either there are no more write requests * available or no more data to send. This function is * run whenever data arrives or write requests are available. * * Context: caller owns port_lock; port_usb is non-null. */ static int gs_start_tx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; struct usb_ep *in = port->port_usb->in; int status = 0; bool do_tty_wake = false; while (!list_empty(pool)) { struct usb_request *req; int len; if (port->write_started >= QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, in->maxpacket); if (len == 0) { wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may * happen too; maybe immediately before we queue this! * * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } port->write_started++; /* abort immediately after disconnect */ if (!port->port_usb) break; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; struct gserial *gser; if (WARN_ON(!port)) return; 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 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; 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 ssize_t debug_read_status(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct gs_port *ui_dev = file->private_data; struct tty_struct *tty; struct gserial *gser; char *buf; unsigned long flags; int i = 0; int ret; int result = 0; tty = ui_dev->port_tty; gser = ui_dev->port_usb; buf = kzalloc(sizeof(char) * BUF_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; spin_lock_irqsave(&ui_dev->port_lock, flags); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_from_host: %lu\n", ui_dev->nbytes_from_host); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_to_tty: %lu\n", ui_dev->nbytes_to_tty); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_with_usb_OUT_txr: %lu\n", (ui_dev->nbytes_from_host - ui_dev->nbytes_to_tty)); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_from_tty: %lu\n", ui_dev->nbytes_from_tty); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_to_host: %lu\n", ui_dev->nbytes_to_host); i += scnprintf(buf + i, BUF_SIZE - i, "nbytes_with_usb_IN_txr: %lu\n", (ui_dev->nbytes_from_tty - ui_dev->nbytes_to_host)); if (tty) i += scnprintf(buf + i, BUF_SIZE - i, "tty_flags: %lu\n", tty->flags); if (gser->get_dtr) { result |= (gser->get_dtr(gser) ? TIOCM_DTR : 0); i += scnprintf(buf + i, BUF_SIZE - i, "DTR_status: %d\n", result); } i += scnprintf(buf + i, BUF_SIZE - i, "port_write_buf: %d\n", gs_buf_data_avail(&ui_dev->port_write_buf)); i += scnprintf(buf + i, BUF_SIZE - i, "write_started: %d\n", ui_dev->write_started); spin_unlock_irqrestore(&ui_dev->port_lock, flags); ret = simple_read_from_buffer(ubuf, count, ppos, buf, i); kfree(buf); return ret; }
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); }
/* * gs_start_tx * * This function finds available write requests, calls * gs_send_packet to fill these packets with data, and * continues until either there are no more write requests * available or no more data to send. This function is * run whenever data arrives or write requests are available. * * Context: caller owns port_lock; port_usb is non-null. */ static int gs_start_tx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; struct usb_ep *in; int status = 0; static long prev_len; bool do_tty_wake = false; if (port->port_usb) in = port->port_usb->in; else return 0; while (!list_empty(pool)) { struct usb_request *req; int len; if (port->write_started >= TX_QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, TX_BUF_SIZE); if (len == 0) { /* Queue zero length packet */ if (prev_len && (prev_len % in->maxpacket == 0)) { req->length = 0; list_del(&req->list); spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (!port->port_usb) { gs_free_req(in, req); break; } if (status) { printk(KERN_ERR "%s: %s err %d\n", __func__, "queue", status); list_add(&req->list, pool); } prev_len = 0; } wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may * happen too; maybe immediately before we queue this! * * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); /* * If port_usb is NULL, gserial disconnect is called * while the spinlock is dropped and all requests are * freed. Free the current request here. */ if (!port->port_usb) { do_tty_wake = false; gs_free_req(in, req); break; } if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } prev_len = req->length; port->nbytes_from_tty += req->length; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
/* * gs_start_tx * * This function finds available write requests, calls * gs_send_packet to fill these packets with data, and * continues until either there are no more write requests * available or no more data to send. This function is * run whenever data arrives or write requests are available. * * Context: caller owns port_lock; port_usb is non-null. */ static int gs_start_tx(struct gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; //struct usb_ep *in = port->port_usb->in; struct usb_ep *in; int status = 0; bool do_tty_wake = false; if (!port->port_usb) /* abort immediately after disconnect */ return -EINVAL; in = port->port_usb->in; while (!list_empty(pool)) { struct usb_request *req; int len; if (port->write_started >= QUEUE_SIZE) break; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, in->maxpacket); if (len == 0) { wake_up_interruptible(&port->drain_wait); break; } do_tty_wake = true; req->length = len; list_del(&req->list); req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0); pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n", port->port_num, len, *((u8 *)req->buf), *((u8 *)req->buf+1), *((u8 *)req->buf+2)); USB_LOGGER(GS_START_TX, GS_START_TX, port->port_num, len); #define OUTPUT_BTYE_NUM 5 { int i,j = 0; char* prefix[] = {"p1","p2","p3","p4","p5"}; char* suffix[] = {"s1","s2","s3","s4","s5"}; for (i = 0; i < req->actual && i < OUTPUT_BTYE_NUM; i++) USB_LOGGER(HEX_NUM, GS_START_TX, prefix[i], *((u8 *)req->buf+i)); if (req->actual >= OUTPUT_BTYE_NUM*2) { for(i = req->actual-1, j = 1; i >= (req->actual - OUTPUT_BTYE_NUM) \ && i >= OUTPUT_BTYE_NUM; i--,j++) { USB_LOGGER(HEX_NUM, GS_START_TX, suffix[OUTPUT_BTYE_NUM-j], \ *((u8 *)req->buf+i)); } } } /* Drop lock while we call out of driver; completions * could be issued while we do so. Disconnection may * happen too; maybe immediately before we queue this! * * NOTE that we may keep sending data for a while after * the TTY closed (dev->ioport->port_tty is NULL). */ spin_unlock(&port->port_lock); status = usb_ep_queue(in, req, GFP_ATOMIC); spin_lock(&port->port_lock); if (status) { pr_debug("%s: %s %s err %d\n", __func__, "queue", in->name, status); list_add(&req->list, pool); break; } port->write_started++; /* abort immediately after disconnect */ if (!port->port_usb) break; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
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); }