- add a usbserial command to enable/disable the serial gadget
- allow dfu and usbserial to cohexist in the same barebox
- add a timeout in u_serial so that we don't get locked if the user
enable usbserial from a UART console but doesn't consume the data
on the usbserial port created on the PC
- remove debug or verbose printf
- tested on i.MX25 & i.MX35 & usb-a926x

Signed-off-by: Eric Bénard <[email protected]>
Tested-by: Jean-Christophe PLAGNIOL-VILLARD <[email protected]>
---
v4 : introduce HAVE_OBEX as suggested by Sascha
v3 : fix comment in usbserial.c and add usbserial.h
v2 : always recompile after fixing checkpatch notes ...
 commands/Makefile             |    1 +
 commands/usbserial.c          |  108 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/Kconfig    |    5 +--
 drivers/usb/gadget/f_acm.c    |    4 +-
 drivers/usb/gadget/serial.c   |   48 ++++++++++++++++--
 drivers/usb/gadget/u_serial.c |   22 +++++---
 include/usb/usbserial.h       |   19 +++++++
 7 files changed, 188 insertions(+), 19 deletions(-)
 create mode 100644 commands/usbserial.c
 create mode 100644 include/usb/usbserial.h

diff --git a/commands/Makefile b/commands/Makefile
index 24753be..43630e1 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_CMD_LSMOD)               += lsmod.o
 obj-$(CONFIG_CMD_INSMOD)       += insmod.o
 obj-$(CONFIG_CMD_BMP)          += bmp.o
 obj-$(CONFIG_USB_GADGET_DFU)   += dfu.o
+obj-$(CONFIG_USB_GADGET_SERIAL)        += usbserial.o
 obj-$(CONFIG_CMD_GPIO)         += gpio.o
 obj-$(CONFIG_CMD_UNCOMPRESS)   += uncompress.o
 obj-$(CONFIG_CMD_I2C)          += i2c.o
diff --git a/commands/usbserial.c b/commands/usbserial.c
new file mode 100644
index 0000000..eb31934
--- /dev/null
+++ b/commands/usbserial.c
@@ -0,0 +1,108 @@
+/*
+ * usbserial.c - usb serial gadget command
+ *
+ * Copyright (c) 2011 Eric Bénard <[email protected]>, Eukréa Electromatique
+ * based on dfu.c which is :
+ * Copyright (c) 2009 Sascha Hauer <[email protected]>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <fs.h>
+#include <xfuncs.h>
+#include <usb/usbserial.h>
+
+static int do_usbserial(struct command *cmdtp, int argc, char *argv[])
+{
+       int opt;
+       struct usb_serial_pdata pdata;
+       char *argstr;
+       char *manufacturer = "barebox";
+       char *productname = CONFIG_BOARDINFO;
+       u16 idVendor = 0, idProduct = 0;
+       int mode = 0;
+
+       while ((opt = getopt(argc, argv, "m:p:V:P:asd")) > 0) {
+               switch (opt) {
+               case 'm':
+                       manufacturer = optarg;
+                       break;
+               case 'p':
+                       productname = optarg;
+                       break;
+               case 'V':
+                       idVendor = simple_strtoul(optarg, NULL, 0);
+                       break;
+               case 'P':
+                       idProduct = simple_strtoul(optarg, NULL, 0);
+                       break;
+               case 'a':
+                       mode = 0;
+                       break;
+#ifdef HAVE_OBEX
+               case 'o':
+                       mode = 1;
+                       break;
+#endif
+               case 's':
+                       mode = 2;
+                       break;
+               case 'd':
+                       usb_serial_unregister();
+                       return 0;
+               }
+       }
+
+       argstr = argv[optind];
+
+       pdata.manufacturer = manufacturer;
+       pdata.productname = productname;
+       pdata.idVendor = idVendor;
+       pdata.idProduct = idProduct;
+       pdata.mode = mode;
+
+       return usb_serial_register(&pdata);
+}
+
+BAREBOX_CMD_HELP_START(usbserial)
+BAREBOX_CMD_HELP_USAGE("usbserial [OPTIONS] <description>\n")
+BAREBOX_CMD_HELP_SHORT("Enable/disable a serial gadget on the USB device 
interface.\n")
+BAREBOX_CMD_HELP_OPT  ("-m <str>",  "Manufacturer string (barebox)\n")
+BAREBOX_CMD_HELP_OPT  ("-p <str>",  "product string (" CONFIG_BOARDINFO ")\n")
+BAREBOX_CMD_HELP_OPT  ("-V <id>",   "vendor id\n")
+BAREBOX_CMD_HELP_OPT  ("-P <id>",   "product id\n")
+BAREBOX_CMD_HELP_OPT  ("-a",   "CDC ACM (default)\n")
+#ifdef HAVE_OBEX
+BAREBOX_CMD_HELP_OPT  ("-o",   "CDC OBEX\n")
+#endif
+BAREBOX_CMD_HELP_OPT  ("-s",   "Generic Serial\n")
+BAREBOX_CMD_HELP_OPT  ("-d",   "Disable the serial gadget\n")
+BAREBOX_CMD_HELP_END
+
+/**
+ * @page usbserial_command
+ */
+
+BAREBOX_CMD_START(usbserial)
+       .cmd            = do_usbserial,
+       .usage          = "Serial gadget enable/disable",
+       BAREBOX_CMD_HELP(cmd_usbserial_help)
+BAREBOX_CMD_END
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index fd471c0..797d19f 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -30,8 +30,7 @@ config USB_GADGET_DRIVER_PXA27X
        select POLLER
 endchoice
 
-choice
-       prompt "USB Gadget drivers"
+comment "USB Gadget drivers"
 
 config USB_GADGET_DFU
        bool
@@ -42,7 +41,5 @@ config USB_GADGET_SERIAL
        depends on EXPERIMENTAL
        prompt "Serial Gadget"
 
-endchoice
-
 endif
 
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 43b4992..218aed2 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -407,7 +407,7 @@ static void acm_disable(struct usb_function *f)
 {
        struct f_acm    *acm = func_to_acm(f);
 
-       printf("acm ttyGS%d deactivated\n", acm->port_num);
+       VDBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
        gserial_disconnect(&acm->port);
        usb_ep_disable(acm->notify);
        acm->notify->driver_data = NULL;
@@ -473,7 +473,7 @@ static int acm_notify_serial_state(struct f_acm *acm)
        int                     status;
 
        if (acm->notify_req) {
-               printf("acm ttyGS%d serial state %04x\n",
+               VDBG(cdev, "acm ttyGS%d serial state %04x\n",
                                acm->port_num, acm->serial_state);
                status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
                                0, &acm->serial_state, 
sizeof(acm->serial_state));
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 8ba9ab5..98a501b 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -4,6 +4,7 @@
 #include <usb/ch9.h>
 #include <usb/gadget.h>
 #include <usb/composite.h>
+#include <usb/usbserial.h>
 #include <asm/byteorder.h>
 
 #include "u_serial.h"
@@ -52,7 +53,9 @@ static struct usb_gadget_strings *dev_strings[] = {
 };
 
 static int use_acm = 1;
+#ifdef HAVE_OBEX
 static int use_obex = 0;
+#endif
 static unsigned n_ports = 1;
 
 static int serial_bind_config(struct usb_configuration *c)
@@ -63,8 +66,10 @@ static int serial_bind_config(struct usb_configuration *c)
        for (i = 0; i < n_ports && status == 0; i++) {
                if (use_acm)
                        status = acm_bind_config(c, i);
+#ifdef HAVE_OBEX
                else if (use_obex)
                        status = obex_bind_config(c, i);
+#endif
                else
                        status = gser_bind_config(c, i);
        }
@@ -100,7 +105,7 @@ static int gs_bind(struct usb_composite_dev *cdev)
        int                     gcnum;
        struct usb_gadget       *gadget = cdev->gadget;
        int                     status;
-printf("%s\n", __func__);
+
        status = gserial_setup(cdev->gadget, n_ports);
        if (status < 0)
                return status;
@@ -174,7 +179,7 @@ static struct usb_composite_driver gserial_driver = {
        .bind           = gs_bind,
 };
 
-static int __init gserial_init(void)
+int usb_serial_register(struct usb_serial_pdata *pdata)
 {
        /* We *could* export two configs; that'd be much cleaner...
         * but neither of these product IDs was defined that way.
@@ -187,19 +192,43 @@ static int __init gserial_init(void)
 #ifdef CONFIG_ARCH_PXA2XX
        use_acm = 0;
 #endif
+       switch (pdata->mode) {
+       case 1:
+#ifdef HAVE_OBEX
+               use_obex = 1;
+#endif
+               use_acm = 0;
+               break;
+       case 2:
+#ifdef HAVE_OBEX
+               use_obex = 1;
+#endif
+               use_acm = 0;
+               break;
+       default:
+#ifdef HAVE_OBEX
+               use_obex = 0;
+#endif
+               use_acm = 1;
+       }
+
        if (use_acm) {
                serial_config_driver.label = "CDC ACM config";
                serial_config_driver.bConfigurationValue = 2;
                device_desc.bDeviceClass = USB_CLASS_COMM;
                device_desc.idProduct =
                                cpu_to_le16(GS_CDC_PRODUCT_ID);
-       } else if (use_obex) {
+       }
+#ifdef HAVE_OBEX
+       else if (use_obex) {
                serial_config_driver.label = "CDC OBEX config";
                serial_config_driver.bConfigurationValue = 3;
                device_desc.bDeviceClass = USB_CLASS_COMM;
                device_desc.idProduct =
                        cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
-       } else {
+       }
+#endif
+       else {
                serial_config_driver.label = "Generic Serial config";
                serial_config_driver.bConfigurationValue = 1;
                device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
@@ -207,8 +236,17 @@ static int __init gserial_init(void)
                                cpu_to_le16(GS_PRODUCT_ID);
        }
        strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
+       if (pdata->idVendor)
+               device_desc.idVendor = pdata->idVendor;
+       if (pdata->idProduct)
+               device_desc.idProduct = pdata->idProduct;
+       strings_dev[STRING_MANUFACTURER_IDX].s = pdata->manufacturer;
+       strings_dev[STRING_PRODUCT_IDX].s = pdata->productname;
 
        return usb_composite_register(&gserial_driver);
 }
 
-late_initcall(gserial_init);
+void usb_serial_unregister(void)
+{
+       usb_composite_unregister(&gserial_driver);
+}
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 49aedc2..e310c3a 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -20,6 +20,7 @@
 #include <common.h>
 #include <usb/cdc.h>
 #include <kfifo.h>
+#include <clock.h>
 
 #include "u_serial.h"
 
@@ -107,8 +108,6 @@ static unsigned     n_ports;
 
 #define GS_CLOSE_TIMEOUT               15              /* seconds */
 
-
-
 #ifdef VERBOSE_DEBUG
 #define pr_vdebug(fmt, arg...) \
        pr_debug(fmt, ##arg)
@@ -370,6 +369,7 @@ static void serial_putc(struct console_device *cdev, char c)
        struct usb_ep           *in;
        struct usb_request      *req;
        int status;
+       uint64_t to;
 
        if (list_empty(pool))
                return;
@@ -382,8 +382,12 @@ static void serial_putc(struct console_device *cdev, char 
c)
        *(unsigned char *)req->buf = c;
        status = usb_ep_queue(in, req);
 
-       while (status >= 0 && list_empty(pool))
+       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)
@@ -399,11 +403,16 @@ 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;
-       while (kfifo_getc(port->recv_fifo, &ch))
+       to = get_time_ns();
+       while (kfifo_getc(port->recv_fifo, &ch)) {
                usb_gadget_poll();
+               if (is_timeout(to, 300 * MSECOND))
+                       break;
+       }
 
        return ch;
 }
@@ -420,8 +429,6 @@ int gserial_connect(struct gserial *gser, u8 port_num)
        int             status;
        struct console_device *cdev;
 
-       printf("%s %p %d\n", __func__, gser, port_num);
-
        /* we "know" gserial_cleanup() hasn't been called */
        port = ports[port_num].port;
 
@@ -451,7 +458,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 
        port->recv_fifo = kfifo_alloc(1024);
 
-       printf("gserial_connect: start ttyGS%d\n", port->port_num);
+       /*printf("gserial_connect: start ttyGS%d\n", port->port_num);*/
        gs_start_io(port);
        if (gser->connect)
                gser->connect(gser);
@@ -508,7 +515,6 @@ void gserial_disconnect(struct gserial *gser)
        struct gs_port  *port = gser->ioport;
        struct console_device *cdev;
 
-       printf("%s\n", __func__);
        if (!port)
                return;
 
diff --git a/include/usb/usbserial.h b/include/usb/usbserial.h
new file mode 100644
index 0000000..43c839c
--- /dev/null
+++ b/include/usb/usbserial.h
@@ -0,0 +1,19 @@
+#ifndef _USB_SERIAL_H
+#define _USB_SERIAL_H
+
+struct usb_serial_pdata {
+       char            *manufacturer;
+       char            *productname;
+       u16                     idVendor;
+       u16                     idProduct;
+       int                     mode;
+};
+
+int usb_serial_register(struct usb_serial_pdata *pdata);
+void usb_serial_unregister(void);
+
+/* OBEX support is missing in barebox */
+/* #define HAVE_OBEX */
+
+#endif /* _USB_SERIAL_H */
+
-- 
1.7.7.5


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to