serial gadget: enable/disable on request
- 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 <eric@eukrea.com> Tested-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
eb98425068
commit
f7aaa22493
|
@ -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
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* usbserial.c - usb serial gadget command
|
||||
*
|
||||
* Copyright (c) 2011 Eric Bénard <eric@eukrea.com>, Eukréa Electromatique
|
||||
* based on dfu.c which is :
|
||||
* Copyright (c) 2009 Sascha Hauer <s.hauer@pengutronix.de>, 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue