diff options
author | Robert Jarzmik <robert.jarzmik@atosorigin.com> | 2011-11-24 04:01:30 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-12-05 17:59:02 +0100 |
commit | 699a4a1eca1ba836159f1ce4dec440bc22b7f3e8 (patch) | |
tree | 0b6bb0977fbacb414b3bdef34f3f46a84e1b5879 /drivers/usb/gadget/u_serial.c | |
parent | 8173427d8d95a021963a7d0b63d5399334392eb0 (diff) | |
download | barebox-699a4a1eca1ba836159f1ce4dec440bc22b7f3e8.tar.gz barebox-699a4a1eca1ba836159f1ce4dec440bc22b7f3e8.tar.xz |
usb/gadget: make serial gadget resistant to cable unplug
As USB can have its cable plugged out anytime, make the
serial gadget reliable in case of unplugging :
- unregister the gadget_serial provided console
- don't stay forever in the read loop if connection was cut
This behaviour relies on correct implementation of
usb_gadget_poll(), which should return an error if the USB
cable was removed.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/usb/gadget/u_serial.c')
-rw-r--r-- | drivers/usb/gadget/u_serial.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 8c2c8fa132..49aedc23ef 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -367,12 +367,13 @@ 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 = port->port_usb->in; + struct usb_ep *in; struct usb_request *req; int status; if (list_empty(pool)) return; + in = port->port_usb->in; req = list_entry(pool->next, struct usb_request, list); req->length = 1; @@ -381,8 +382,8 @@ static void serial_putc(struct console_device *cdev, char c) *(unsigned char *)req->buf = c; status = usb_ep_queue(in, req); - while (list_empty(pool)) - usb_gadget_poll(); + while (status >= 0 && list_empty(pool)) + status = usb_gadget_poll(); } static int serial_tstc(struct console_device *cdev) @@ -399,7 +400,10 @@ static int serial_getc(struct console_device *cdev) struct gs_port, cdev); unsigned char ch; - while (kfifo_getc(port->recv_fifo, &ch)); + if (!port->port_usb) + return -EIO; + while (kfifo_getc(port->recv_fifo, &ch)) + usb_gadget_poll(); return ch; } @@ -421,6 +425,10 @@ int gserial_connect(struct gserial *gser, u8 port_num) /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; + /* In case of multiple activation (ie. multiple SET_INTERFACE) */ + if (port->port_usb) + return 0; + /* activate the endpoints */ status = usb_ep_enable(gser->in, gser->in_desc); if (status < 0) @@ -498,7 +506,9 @@ BAREBOX_CMD_END void gserial_disconnect(struct gserial *gser) { struct gs_port *port = gser->ioport; -printf("%s\n", __func__); + struct console_device *cdev; + + printf("%s\n", __func__); if (!port) return; @@ -518,7 +528,9 @@ printf("%s\n", __func__); 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); + + cdev = &port->cdev; + console_unregister(cdev); } |