static int gs_chars_in_buffer(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; int chars = 0; if (!port) return 0; spin_lock_irqsave(&port->port_lock, flags); chars = gs_buf_data_avail(&port->port_write_buf); spin_unlock_irqrestore(&port->port_lock, flags); pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n", port->port_num, tty, chars); return chars; }
static int gs_put_char(struct tty_struct *tty, unsigned char ch) { struct gs_port *port = tty->driver_data; unsigned long flags; int status; if (!port) return 0; pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n", port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); status = gs_buf_put(&port->port_write_buf, &ch, 1); spin_unlock_irqrestore(&port->port_lock, flags); return status; }
static int gs_write_room(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; int room = 0; if(port == NULL) return room; spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) room = gs_buf_space_avail(&port->port_write_buf); spin_unlock_irqrestore(&port->port_lock, flags); pr_vdebug("gs_write_room: (%d,%p) room=%d\n", port->port_num, tty, room); return room; }
static void gs_flush_chars(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; #ifdef CONFIG_USB_G_LGE_ANDROID if (!port) return; #endif pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); }
static int gs_break_ctl(struct tty_struct *tty, int duration) { struct gs_port *port = tty->driver_data; int status = 0; struct gserial *gser; pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n", port->port_num, duration); spin_lock_irq(&port->port_lock); gser = port->port_usb; if (gser && gser->send_break) status = gser->send_break(gser, duration); spin_unlock_irq(&port->port_lock); return status; }
/** * Gets a character from the usb endpoint under the * interrupt context * * Returns 0 or a negative error number */ static int __gs_poll_get_char(struct gs_port *port, char *ch) { struct gserial *gs = port->port_usb; struct usb_ep *ept = gs->out; struct usb_request *usb_req; int rv; int read_ch = -EINVAL; BUG_ON(!ept); for (;;) { read_ch = gs_poll_pop_buffer(); if (read_ch >= 0) { break; /* got a character, done */ } /** * There is nothing in buffer, start the USB endpoint to * receive something */ /* Replace complete function to intercept usb read */ usb_req = gs_alloc_req(ept, ept->maxpacket, GFP_ATOMIC); if (!usb_req) { pr_err("%s: OOM for read req\n", __func__); return -ENOMEM; } /* Queue request */ usb_req->length = ept->maxpacket; usb_req->complete = gs_poll_read_complete; if ((rv = usb_ep_queue(ept, usb_req, GFP_ATOMIC))) { pr_err("%s: usb_ep_queue err %d\n", __func__, rv); return rv; } /* Read and free request */ pr_vdebug("%s: polling for read\n", __func__); while ( usb_loop_poll_hw(ept, 1 /*rx*/) ); gs_free_req(ept, usb_req); } *ch = read_ch; return 0; }
static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); spin_lock_irqsave(&port->port_lock, flags); if (count) count = kfifo_in(&port->port_write_buf, buf, count); /* treat count == 0 as flush_chars() */ if (port->port_usb) gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); return count; }
/* undo side effects of setting TTY_THROTTLED */ static void gs_unthrottle(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; if(port == NULL) return; spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) { /* Kickstart read queue processing. We don't do xon/xoff, * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ tasklet_schedule(&port->push); pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); } spin_unlock_irqrestore(&port->port_lock, flags); }
/** * gs_poll_read_complete */ static void gs_poll_read_complete(struct usb_ep *ep, struct usb_request *req) { switch (req->status) { case 0: /* get data */ console_buf_len = req->actual; console_buf_read = 0; memcpy(console_buf, req->buf, req->actual); console_buf[req->actual] = '\0'; pr_vdebug("[%s] len = %d\n", console_buf, console_buf_len); break; default: pr_err("%s: unexpected status error, status=%d\n", __func__, req->status); break; } }
static int gs_write_room(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; /* if usb not connect, return room available; to avoid thread in sleep */ int room = WRITE_BUF_SIZE - 1; spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) room = gs_buf_space_avail(&port->port_write_buf); spin_unlock_irqrestore(&port->port_lock, flags); pr_vdebug("gs_write_room: (%d,%p) room=%d\n", port->port_num, tty, room); return room; }
/** * 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_write_complete(struct usb_ep *ep, struct usb_request *req) { struct gs_port *port = ep->driver_data; unsigned long flags; pr_vdebug("%s: %d bytes\n", __func__, req->actual); spin_lock_irqsave(&port->port_lock, flags); list_add(&req->list, &port->write_pool); switch (req->status) { default: /* presumably a transient fault */ pr_warning("%s: unexpected %s status %d\n", __func__, ep->name, req->status); /* FALL THROUGH */ case 0: /* normal completion */ if (port->port_usb) gs_start_tx(port); break; case -ESHUTDOWN: /* disconnect */ printk("%s: ESHUTDOWN\n", __func__); break; case -ENODEV: spin_lock(&port->port_lock); printk("%s: ENODEV\n", __func__); list_add_tail(&req->list, &port->read_pool); /* Implemented handling in future if needed */ spin_unlock(&port->port_lock); break; spin_lock(&port->port_lock); list_add_tail(&req->list, &port->read_pool); printk(KERN_ERR "gs_read_complete: unexpected status error, status=%d\n", req->status); spin_unlock(&port->port_lock); /* goto requeue; */ break; } }
static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; int status; pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); spin_lock_irqsave(&port->port_lock, flags); if (count) count = gs_buf_put(&port->port_write_buf, buf, count); if (port->port_usb) status = gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); return count; }
static void gs_flush_chars(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; //ALPS00423739 if(!port) { printk("ERROR!!! port is closed!! %s, line %d: port = %p\n", __func__, __LINE__, port); /*abort immediately after disconnect */ return; } //ALPS00423739 pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); }
/** * 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; /* don't need to free console tty - port0 */ if (gs_console_tty_driver) tty_unregister_device(gs_console_tty_driver, 0); if (!gs_tty_driver) return; /* start sysfs and /dev/ttyGS* node removal */ for (i = 1; i < n_ports; i++) tty_unregister_device(gs_tty_driver, i-1); for (i = 1; 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); put_tty_driver(gs_tty_driver); gs_tty_driver = NULL; pr_vdebug("%s: cleaned up ttyGS* support\n", __func__); }
static int at_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gdata_port *port = tty->driver_data; int avail; struct sk_buff *skb; int status; pr_vdebug("at_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); avail = test_bit(CH_OPENED, &port->bridge_sts); /* if no space, we'll have to setup a notification later to wake up the * tty framework when space becomes avaliable */ if (!avail) { pr_debug("at_write: avail(0)\n"); return 0; } #ifdef VERBOSE_DEBUG print_hex_dump(KERN_DEBUG, "fromatd:", DUMP_PREFIX_OFFSET, 16, 1, buf, count, 1); #endif skb = alloc_skb(count, GFP_ATOMIC); if (!skb) { pr_debug("at_write: ENOMEM\n"); return -ENOMEM; } memcpy(skb->data, buf, count); skb->len = count; status = ghsic_data_receive(port, skb, count); if (status) { pr_debug("at_write: status(%d)\n", status); return status; } pr_debug("at_write: return(%d)\n", count); return count; }
static void gs_flush_chars(struct tty_struct *tty) { struct gs_port *port = NULL; unsigned long flags; if(!tty ){ pr_err("%s error: wrong parameter! *tty=0x%x", __func__, (unsigned int) tty); return; } port = tty->driver_data; if(!port){ pr_err("%s error: port = NULL! already closed??\n", __func__); return; } pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); }
static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; int status; pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); spin_lock_irqsave(&port->port_lock, flags); if (unlikely(!port->open_count)) { spin_unlock_irqrestore(&port->port_lock, flags); return -EINVAL; } if (unlikely(!port->port_usb || port->is_suspend)) { port->stat_write_not_conn++; spin_unlock_irqrestore(&port->port_lock, flags); return -ESHUTDOWN; } /* * we don't have enough room for some data * may be the host don't start read, so drop the data. * otherwise the printed thread may pending forever. */ if (!port->line_state_on && list_empty(&port->write_pool)) { port->stat_write_no_mem++; spin_unlock_irqrestore(&port->port_lock, flags); return -ENOMEM; } if (count) count = gs_buf_put(&port->port_write_buf, buf, count); /* treat count == 0 as flush_chars() */ if (port->port_usb) status = gs_start_tx(port);/* [false alarm]:fortify disable */ spin_unlock_irqrestore(&port->port_lock, flags); return count; }
/* undo side effects of setting TTY_THROTTLED */ static void gs_unthrottle(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; /* * tty's driver data is set to NULL during port close. Nothing * to do here. */ if (!port) return; spin_lock_irqsave(&port->port_lock, flags); if (port->port_usb) { /* Kickstart read queue processing. We don't do xon/xoff, * rts/cts, or other handshaking with the host, but if the * read queue backs up enough we'll be NAKing OUT packets. */ queue_work(gserial_wq, &port->push); pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); } spin_unlock_irqrestore(&port->port_lock, flags); }
static void gs_complete_out(struct usb_ep *ep, struct usb_request *req) { struct gscons_info *info = &gscons_info; switch (req->status) { default: pr_warn("%s: unexpected %s status %d\n", __func__, ep->name, req->status); /* fall through */ case 0: /* normal completion */ spin_lock(&info->con_lock); info->req_busy = 0; spin_unlock(&info->con_lock); wake_up_process(info->console_thread); break; case -ESHUTDOWN: /* disconnect */ pr_vdebug("%s: %s shutdown\n", __func__, ep->name); break; } }
static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; int status; #ifdef CONFIG_USB_G_LGE_ANDROID if (!port) return 0; #endif pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); spin_lock_irqsave(&port->port_lock, flags); if (count) count = gs_buf_put(&port->port_write_buf, buf, count); /* treat count == 0 as flush_chars() */ if (port->port_usb) status = gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); return count; }
static int gs_chars_in_buffer(struct tty_struct *tty) { struct gs_port *port = tty->driver_data; unsigned long flags; int chars = 0; //ALPS00423739 if(!port) { printk("ERROR!!! port is closed!! %s, line %d: port = %p\n", __func__, __LINE__, port); /*abort immediately after disconnect */ return -EINVAL; } //ALPS00423739 spin_lock_irqsave(&port->port_lock, flags); chars = gs_buf_data_avail(&port->port_write_buf); spin_unlock_irqrestore(&port->port_lock, flags); pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n", port->port_num, tty, chars); return chars; }
static int gs_put_char(struct tty_struct *tty, unsigned char ch) { struct gs_port *port = tty->driver_data; unsigned long flags; int status; //ALPS00423739 if(!port) { printk("ERROR!!! port is closed!! %s, line %d: port = %p\n", __func__, __LINE__, port); /*abort immediately after disconnect */ return -EINVAL; } //ALPS00423739 pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n", port->port_num, tty, ch, __builtin_return_address(0)); spin_lock_irqsave(&port->port_lock, flags); status = gs_buf_put(&port->port_write_buf, &ch, 1); spin_unlock_irqrestore(&port->port_lock, flags); return status; }
/* * RX tasklet takes data out of the RX queue and hands it up to the TTY * layer until it refuses to take any more data (or is throttled back). * Then it issues reads for any further data. * * If the RX queue becomes full enough that no usb_request is queued, * the OUT endpoint may begin NAKing as soon as its FIFO fills up. * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ static void gs_rx_push(struct work_struct *w) { struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; bool do_push = false; /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); tty = port->port_tty; while (!list_empty(queue)) { struct usb_request *req; req = list_first_entry(queue, struct usb_request, list); /* discard data if tty was closed */ if (!tty) goto recycle; /* leave data queued if tty was rx throttled */ if (test_bit(TTY_THROTTLED, &tty->flags)) break; switch (req->status) { case -ESHUTDOWN: disconnect = true; pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); break; default: /* presumably a transient fault */ pr_warning(PREFIX "%d: unexpected RX status %d\n", port->port_num, req->status); /* FALLTHROUGH */ case 0: /* normal completion */ break; } /* push data to (open) tty */ if (req->actual) { char *packet = req->buf; unsigned size = req->actual; unsigned n; int count; /* we may have pushed part of this packet already... */ n = port->n_read; if (n) { packet += n; size -= n; } count = tty_insert_flip_string(tty, packet, size); port->nbytes_to_tty += count; if (count) do_push = true; if (count != size) { /* stop pushing; TTY layer can't handle more */ port->n_read += count; pr_vdebug(PREFIX "%d: rx block %d/%d\n", port->port_num, count, req->actual); break; } port->n_read = 0; } recycle: list_move(&req->list, &port->read_pool); port->read_started--; } /* Push from tty to ldisc; without low_latency set this is handled by * a workqueue, so we won't get callbacks and can hold port_lock */ if (tty && do_push) tty_flip_buffer_push(tty); /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any * this time around, there may be trouble unless there's an * implicit tty_unthrottle() call on its way... * * REVISIT we should probably add a timer to keep the work queue * from starving ... but it's not clear that case ever happens. */ if (!list_empty(queue) && tty) { if (!test_bit(TTY_THROTTLED, &tty->flags)) { if (do_push) queue_work(gserial_wq, &port->push); else pr_warning(PREFIX "%d: RX not scheduled?\n", port->port_num); } } /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) gs_start_rx(port); 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 = port->port_usb->in; int status = 0; static long prev_len; bool do_tty_wake = false; 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 explicitly to make it * work with UDCs which don't support req->zero flag */ 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); 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; port->write_started++; } 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; int status = 0; bool do_tty_wake = false; while (!list_empty(pool)) { struct usb_request *req; int len; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, in->maxpacket); #if ACM_ZLP if (len == 0) { //printk("[%s] len == 0 ;\n", __func__); if (s3c_need_zlp == 0) { req->zero = 0; wake_up_interruptible(&port->drain_wait); break; } else { //printk("[%s] zlp: => req.zero = true ;\n", __func__); req->zero = 1; s3c_need_zlp = 0; s3c_multiple = 0; } } #else if (len == 0) { wake_up_interruptible(&port->drain_wait); break; } #endif do_tty_wake = true; req->length = len; list_del(&req->list); 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; } /* 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_rx_push(struct work_struct *w) { struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; bool do_push = false; spin_lock_irq(&port->port_lock); tty = port->port_tty; while (!list_empty(queue)) { struct usb_request *req; req = list_first_entry(queue, struct usb_request, list); if (!tty) goto recycle; if (test_bit(TTY_THROTTLED, &tty->flags)) break; switch (req->status) { case -ESHUTDOWN: disconnect = true; pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); break; default: pr_warning(PREFIX "%d: unexpected RX status %d\n", port->port_num, req->status); case 0: break; } if (req->actual) { char *packet = req->buf; unsigned size = req->actual; unsigned n; int count; n = port->n_read; if (n) { packet += n; size -= n; } count = tty_insert_flip_string(tty, packet, size); if (count) do_push = true; if (count != size) { port->n_read += count; pr_vdebug(PREFIX "%d: rx block %d/%d\n", port->port_num, count, req->actual); break; } port->n_read = 0; } recycle: list_move(&req->list, &port->read_pool); } if (tty && do_push) { spin_unlock_irq(&port->port_lock); tty_flip_buffer_push(tty); wake_up_interruptible(&tty->read_wait); spin_lock_irq(&port->port_lock); tty = port->port_tty; } if (!list_empty(queue) && tty) { if (!test_bit(TTY_THROTTLED, &tty->flags)) { if (do_push) queue_work(gserial_wq, &port->push); else pr_warning(PREFIX "%d: RX not scheduled?\n", port->port_num); } } if (!disconnect && port->port_usb) gs_start_rx(port); spin_unlock_irq(&port->port_lock); }
static int gs_start_tx(struct gs_port *port) { struct list_head *pool = &port->write_pool; struct usb_ep *in = port->port_usb->in; int status = 0; static long prev_len; bool do_tty_wake = false; while (!list_empty(pool)) { struct usb_request *req; int len; req = list_entry(pool->next, struct usb_request, list); len = gs_send_packet(port, req->buf, TX_BUF_SIZE); if (len == 0) { 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 (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); 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)); 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; } prev_len = req->length; if (!port->port_usb) break; } if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }
/* * RX tasklet takes data out of the RX queue and hands it up to the TTY * layer until it refuses to take any more data (or is throttled back). * Then it issues reads for any further data. * * If the RX queue becomes full enough that no usb_request is queued, * the OUT endpoint may begin NAKing as soon as its FIFO fills up. * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) * can be buffered before the TTY layer's buffers (currently 64 KB). */ static void gs_rx_push(struct work_struct *w) { struct gs_port *port = container_of(w, struct gs_port, push); struct tty_struct *tty; struct list_head *queue = &port->read_queue; bool disconnect = false; bool do_push = false; /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); tty = port->port_tty; while (!list_empty(queue)) { struct usb_request *req; req = list_first_entry(queue, struct usb_request, list); /* discard data if tty was closed */ if (!tty) goto recycle; /* push data to (open) tty */ if (req->actual) { char *packet = req->buf; unsigned size = req->actual; unsigned n; int count; /* we may have pushed part of this packet already... */ n = port->n_read; if (n) { packet += n; size -= n; } count = tty_insert_flip_string(tty, packet, size); port->nbytes_to_tty += count; if (count) do_push = true; if (count != size) { /* stop pushing; TTY layer can't handle more */ port->n_read += count; pr_vdebug(PREFIX "%d: rx block %d/%d\n", port->port_num, count, req->actual); break; } port->n_read = 0; } recycle: list_move(&req->list, &port->read_pool); port->read_started--; port->rx_qcnt--; } /* Push from tty to ldisc; this is immediate with low_latency, and * may trigger callbacks to this driver ... so drop the spinlock. */ if (tty && do_push) { spin_unlock_irq(&port->port_lock); tty_flip_buffer_push(tty); wake_up_interruptible(&tty->read_wait); spin_lock_irq(&port->port_lock); /* tty may have been closed */ tty = port->port_tty; } /* We want our data queue to become empty ASAP, keeping data * in the tty and ldisc (not here). If we couldn't push any * this time around, there may be trouble unless there's an * implicit tty_unthrottle() call on its way... * * REVISIT we should probably add a timer to keep the work queue * from starving ... but it's not clear that case ever happens. */ if (!list_empty(queue) && tty) { if (!test_bit(TTY_THROTTLED, &tty->flags)) { if (do_push) queue_work(gserial_wq, &port->push); else pr_warning(PREFIX "%d: RX not scheduled?\n", port->port_num); } } /* If we're still connected, refill the USB RX queue. */ if (!disconnect && port->port_usb) gs_start_rx(port); 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 pxa910_gs_start_tx(struct pxa910_gs_port *port) /* __releases(&port->port_lock) __acquires(&port->port_lock) */ { struct list_head *pool; struct usb_ep *in; int status = 0; bool do_tty_wake = false; if (NULL == port) return 0; pool = &port->write_pool; 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 = pxa910_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 = (pxa910_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_usb) wake_up_interruptible(&port->port_usb->port_send); if (do_tty_wake && port->port_tty) tty_wakeup(port->port_tty); return status; }