diff options
Diffstat (limited to 'drivers/usb/gadget/u_serial.c')
-rw-r--r-- | drivers/usb/gadget/u_serial.c | 608 |
1 files changed, 0 insertions, 608 deletions
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c deleted file mode 100644 index 140346e770..0000000000 --- a/drivers/usb/gadget/u_serial.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * u_serial.c - utilities for USB gadget "serial port"/TTY support - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This code also borrows from usbserial.c, which is - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2000 Peter Berger (pberger@brimson.com) - * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com) - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include <common.h> -#include <complete.h> -#include <usb/cdc.h> -#include <kfifo.h> -#include <clock.h> -#include <linux/err.h> -#include <dma.h> - -#include "u_serial.h" - - -/* - * This component encapsulates the TTY layer glue needed to provide basic - * "serial port" functionality through the USB gadget stack. Each such - * port is exposed through a /dev/ttyGS* node. - * - * After this module has been loaded, the individual TTY port can be requested - * (gserial_alloc_line()) and it will stay available until they are removed - * (gserial_free_line()). Each one may be connected to a USB function - * (gserial_connect), or disconnected (with gserial_disconnect) when the USB - * host issues a config change event. Data can only flow when the port is - * connected to the host. - * - * A given TTY port can be made available in multiple configurations. - * For example, each one might expose a ttyGS0 node which provides a - * login application. In one case that might use CDC ACM interface 0, - * while another configuration might use interface 3 for that. The - * work to handle that (including descriptor management) is not part - * of this component. - * - * Configurations may expose more than one TTY port. For example, if - * ttyGS0 provides login service, then ttyGS1 might provide dialer access - * for a telephone or fax link. And ttyGS2 might be something that just - * needs a simple byte stream interface for some messaging protocol that - * is managed in userspace ... OBEX, PTP, and MTP have been mentioned. - */ - -#define PREFIX "ttyGS" - -/* - * gserial is the lifecycle interface, used by USB functions - * gs_port is the I/O nexus, used by the tty driver - * tty_struct links to the tty/filesystem framework - * - * gserial <---> gs_port ... links will be null when the USB link is - * inactive; managed by gserial_{connect,disconnect}(). each gserial - * instance can wrap its own USB control protocol. - * gserial->ioport == usb_ep->driver_data ... gs_port - * gs_port->port_usb ... gserial - * - * gs_port <---> tty_struct ... links will be null when the TTY file - * isn't opened; managed by gs_open()/gs_close() - * gserial->port_tty ... tty_struct - * tty_struct->driver_data ... gserial - */ - -/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the - * next layer of buffering. For TX that's a circular buffer; for RX - * consider it a NOP. A third layer is provided by the TTY code. - */ -#define QUEUE_SIZE 16 -#define WRITE_BUF_SIZE 8192 /* TX only */ -#define RECV_FIFO_SIZE (1024 * 8) - -/* circular buffer */ -struct gs_buf { - unsigned buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - -/* - * The port structure holds info for each port, one for each minor number - * (and thus for each /dev/ node). - */ -struct gs_port { - struct gserial *port_usb; - struct console_device cdev; - struct kfifo *recv_fifo; - - u8 port_num; - - struct list_head read_pool; - unsigned read_nb_queued; - - struct list_head write_pool; - - /* REVISIT this state ... */ - struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ -}; - -static struct portmaster { - struct gs_port *port; -} ports[MAX_U_SERIAL_PORTS]; - -#define GS_CLOSE_TIMEOUT 15 /* seconds */ - -static unsigned gs_start_rx(struct gs_port *port) -{ - struct list_head *pool = &port->read_pool; - struct usb_ep *out = port->port_usb->out; - unsigned started = 0; - - while (!list_empty(pool) && - ((out->maxpacket * (port->read_nb_queued + 1) + - kfifo_len(port->recv_fifo)) < RECV_FIFO_SIZE)) { - struct usb_request *req; - int status; - - req = list_entry(pool->next, struct usb_request, list); - list_del(&req->list); - req->length = out->maxpacket; - - /* drop lock while we call out; the controller driver - * may need to call us back (e.g. for disconnect) - */ - port->read_nb_queued++; - status = usb_ep_queue(out, req); - - if (status) { - pr_debug("%s: %s %s err %d\n", - __func__, "queue", out->name, status); - list_add(&req->list, pool); - break; - } - started++; - - /* abort immediately after disconnect */ - if (!port->port_usb) - break; - } - return started; -} - -/*-------------------------------------------------------------------------*/ - -static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct gs_port *port = ep->driver_data; - - if (req->status == -ESHUTDOWN) - return; - - kfifo_put(port->recv_fifo, req->buf, req->actual); - list_add_tail(&req->list, &port->read_pool); - port->read_nb_queued--; - - gs_start_rx(port); -} - -/*-------------------------------------------------------------------------*/ - -/* I/O glue between TTY (upper) and USB function (lower) driver layers */ - -static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct gs_port *port = ep->driver_data; - - 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 */ - break; - - case -ESHUTDOWN: - /* disconnect */ - pr_vdebug("%s: %s shutdown\n", __func__, ep->name); - break; - } -} - -/* - * gs_alloc_req - * - * Allocate a usb_request and its buffer. Returns a pointer to the - * usb_request or NULL if there is an error. - */ -struct usb_request * -gs_alloc_req(struct usb_ep *ep, unsigned len) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep); - - if (req != NULL) { - req->length = len; - req->buf = dma_alloc(len); - } - - return req; -} -EXPORT_SYMBOL_GPL(gs_alloc_req); - -/* - * gs_free_req - * - * Free a usb_request and its buffer. - */ -void gs_free_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} -EXPORT_SYMBOL_GPL(gs_free_req); - -static void gs_free_requests(struct usb_ep *ep, struct list_head *head) -{ - struct usb_request *req; - - while (!list_empty(head)) { - req = list_entry(head->next, struct usb_request, list); - list_del(&req->list); - gs_free_req(ep, req); - } -} - -static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, - void (*fn)(struct usb_ep *, struct usb_request *)) -{ - int i; - struct usb_request *req; - - /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't - * do quite that many this time, don't fail ... we just won't - * be as speedy as we might otherwise be. - */ - for (i = 0; i < QUEUE_SIZE; i++) { - req = gs_alloc_req(ep, ep->maxpacket); - if (!req) - return list_empty(head) ? -ENOMEM : 0; - req->complete = fn; - list_add_tail(&req->list, head); - } - return 0; -} - -/** - * 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, gs_read_complete); - if (status) - return status; - - status = gs_alloc_requests(port->port_usb->in, &port->write_pool, - gs_write_complete); - if (status) { - gs_free_requests(ep, head); - return status; - } - - /* queue read requests */ - port->read_nb_queued = 0; - started = gs_start_rx(port); - - /* unblock any pending writes into our circular buffer */ - if (!started) { - gs_free_requests(ep, head); - gs_free_requests(port->port_usb->in, &port->write_pool); - status = -EIO; - } - - return status; -} - -/*-------------------------------------------------------------------------*/ - -static int -gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) -{ - struct gs_port *port; - int ret = 0; - - if (ports[port_num].port) { - ret = -EBUSY; - goto out; - } - - port = kzalloc(sizeof(struct gs_port), GFP_KERNEL); - if (port == NULL) { - ret = -ENOMEM; - goto out; - } - - INIT_LIST_HEAD(&port->read_pool); - INIT_LIST_HEAD(&port->write_pool); - - port->port_num = port_num; - port->port_line_coding = *coding; - - ports[port_num].port = port; -out: - return ret; -} - -static void gserial_free_port(struct gs_port *port) -{ - kfree(port); -} - -void gserial_free_line(unsigned char port_num) -{ - struct gs_port *port; - - if (WARN_ON(!ports[port_num].port)) - return; - - port = ports[port_num].port; - ports[port_num].port = NULL; - - gserial_free_port(port); -} -EXPORT_SYMBOL_GPL(gserial_free_line); - -int gserial_alloc_line(unsigned char *line_num) -{ - struct usb_cdc_line_coding coding; - int ret; - int port_num; - - coding.dwDTERate = cpu_to_le32(9600); - coding.bCharFormat = 8; - coding.bParityType = USB_CDC_NO_PARITY; - coding.bDataBits = USB_CDC_1_STOP_BITS; - - for (port_num = 0; port_num < MAX_U_SERIAL_PORTS; port_num++) { - ret = gs_port_alloc(port_num, &coding); - if (ret == -EBUSY) - continue; - if (ret) - return ret; - break; - } - if (ret) - return ret; - - /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ - - *line_num = port_num; - - return ret; -} -EXPORT_SYMBOL_GPL(gserial_alloc_line); - -static void serial_putc(struct console_device *cdev, char c) -{ - struct gs_port *port = container_of(cdev, - struct gs_port, cdev); - struct list_head *pool = &port->write_pool; - struct usb_ep *in; - struct usb_request *req; - int status; - uint64_t to; - - if (list_empty(pool)) - return; - in = port->port_usb->in; - req = list_entry(pool->next, struct usb_request, list); - - req->length = 1; - list_del(&req->list); - - *(unsigned char *)req->buf = c; - status = usb_ep_queue(in, req); - - to = get_time_ns(); - while (status >= 0 && list_empty(pool)) { - status = usb_gadget_poll(); - if (is_timeout(to, 300 * MSECOND)) - break; - } -} - -static int serial_tstc(struct console_device *cdev) -{ - struct gs_port *port = container_of(cdev, - struct gs_port, cdev); - - gs_start_rx(port); - return (kfifo_len(port->recv_fifo) == 0) ? 0 : 1; -} - -static int serial_getc(struct console_device *cdev) -{ - struct gs_port *port = container_of(cdev, - struct gs_port, cdev); - unsigned char ch; - uint64_t to; - - if (!port->port_usb) - return -EIO; - to = get_time_ns(); - while (kfifo_getc(port->recv_fifo, &ch)) { - usb_gadget_poll(); - if (is_timeout(to, 300 * MSECOND)) - goto timeout; - } - - gs_start_rx(port); - return ch; -timeout: - gs_start_rx(port); - return -ETIMEDOUT; -} - -static void serial_flush(struct console_device *cdev) -{ -} - -static int serial_setbaudrate(struct console_device *cdev, int baudrate) -{ - return 0; -} - -/** - * gserial_connect - notify TTY I/O glue that USB link is active - * @gser: the function, set up with endpoints and descriptors - * @port_num: which port is active - * Context: any (usually from irq) - * - * This is called activate endpoints and let the TTY layer know that - * the connection is active ... not unlike "carrier detect". It won't - * necessarily start I/O queues; unless the TTY is held open by any - * task, there would be no point. However, the endpoints will be - * activated so the USB host can perform I/O, subject to basic USB - * hardware flow control. - * - * Caller needs to have set up the endpoints and USB function in @dev - * before calling this, as well as the appropriate (speed-specific) - * endpoint descriptors, and also have allocate @port_num by calling - * @gserial_alloc_line(). - * - * Returns negative errno or zero. - * On success, ep->driver_data will be overwritten. - */ -int gserial_connect(struct gserial *gser, u8 port_num) -{ - struct gs_port *port; - int status; - struct console_device *cdev; - - if (port_num >= MAX_U_SERIAL_PORTS) - return -ENXIO; - - port = ports[port_num].port; - if (!port) { - pr_err("serial line %d not allocated.\n", port_num); - return -EINVAL; - } - if (port->port_usb) { - pr_err("serial line %d is in use.\n", port_num); - return -EBUSY; - } - - /* activate the endpoints */ - status = usb_ep_enable(gser->in); - if (status < 0) - return status; - gser->in->driver_data = port; - - status = usb_ep_enable(gser->out); - if (status < 0) - goto fail_out; - gser->out->driver_data = port; - - /* then tell the tty glue that I/O can work */ - gser->ioport = port; - port->port_usb = gser; - - /* REVISIT unclear how best to handle this state... - * we don't really couple it with the Linux TTY. - */ - gser->port_line_coding = port->port_line_coding; - - port->recv_fifo = kfifo_alloc(RECV_FIFO_SIZE); - - /*printf("gserial_connect: start ttyGS%d\n", port->port_num);*/ - gs_start_io(port); - if (gser->connect) - gser->connect(gser); - - cdev = &port->cdev; - cdev->tstc = serial_tstc; - cdev->putc = serial_putc; - cdev->getc = serial_getc; - cdev->flush = serial_flush; - cdev->setbrg = serial_setbaudrate; - cdev->devname = "usbserial"; - cdev->devid = DEVICE_ID_SINGLE; - - status = console_register(cdev); - if (status) - goto fail_out; - - if (IS_ENABLED(CONFIG_CONSOLE_FULL)) - console_set_active(cdev, CONSOLE_STDIN | CONSOLE_STDOUT | - CONSOLE_STDERR); - - /* REVISIT if waiting on "carrier detect", signal. */ - - /* if it's already open, start I/O ... and notify the serial - * protocol about open/close status (connect/disconnect). - */ - if (1) { - pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); - if (gser->connect) - gser->connect(gser); - } else { - if (gser->disconnect) - gser->disconnect(gser); - } - - return status; - -fail_out: - usb_ep_disable(gser->in); - gser->in->driver_data = NULL; - return status; -} -EXPORT_SYMBOL_GPL(gserial_connect); - -/** - * 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; - struct console_device *cdev; - - if (!port) - return; - - cdev = &port->cdev; - - /* tell the TTY glue not to do I/O here any more */ - console_unregister(cdev); - - /* REVISIT as above: how best to track this? */ - port->port_line_coding = gser->port_line_coding; - - port->port_usb = NULL; - gser->ioport = NULL; - - /* 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 */ - gs_free_requests(gser->out, &port->read_pool); - gs_free_requests(gser->in, &port->write_pool); - - kfifo_free(port->recv_fifo); -} |