Commit 0601da86 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: usb gadget zero, basic OTG updates

This patch teaches "gadget zero" enough about OTG to pass simple USBCV
tests, mostly by including OTG descriptors in each configuration.  It
tests and reports OTG status, as reported by the USB controller driver.

It also adds an option to build gadget zero to act as the designated
OTG "HNP Test Device", which exists primarily to trigger HNP.  However,
it won't currently request HNP.

Includes other minor tweaks:  delete a timer on disconnect, reset
the req->zero flag, don't autoresume after disconnect.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 8ae7288e
...@@ -208,6 +208,16 @@ config USB_ZERO ...@@ -208,6 +208,16 @@ config USB_ZERO
Say "y" to link the driver statically, or "m" to build a Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_zero". dynamically linked module called "g_zero".
config USB_ZERO_HNPTEST
boolean "HNP Test Device"
depends on USB_ZERO && USB_OTG
help
You can configure this device to enumerate using the device
identifiers of the USB-OTG test device. That means that when
this gadget connects to another OTG device, with this one using
the "B-Peripheral" role, that device will use HNP to let this
one serve as the USB host instead (in the "B-Host" role).
config USB_ETH config USB_ETH
tristate "Ethernet Gadget" tristate "Ethernet Gadget"
depends on NET depends on NET
......
...@@ -194,8 +194,13 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR); ...@@ -194,8 +194,13 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures. * Instead: allocate your own, using normal USB-IF procedures.
*/ */
#ifndef CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
#else
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
#define DRIVER_PRODUCT_NUM 0xbadd
#endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -259,6 +264,14 @@ loopback_config = { ...@@ -259,6 +264,14 @@ loopback_config = {
.bMaxPower = 1, /* self-powered */ .bMaxPower = 1, /* self-powered */
}; };
static struct usb_otg_descriptor
otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
.bmAttributes = USB_OTG_SRP,
};
/* one interface in each configuration */ /* one interface in each configuration */
static const struct usb_interface_descriptor static const struct usb_interface_descriptor
...@@ -302,6 +315,7 @@ fs_sink_desc = { ...@@ -302,6 +315,7 @@ fs_sink_desc = {
}; };
static const struct usb_descriptor_header *fs_source_sink_function [] = { static const struct usb_descriptor_header *fs_source_sink_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_source_desc,
...@@ -309,6 +323,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = { ...@@ -309,6 +323,7 @@ static const struct usb_descriptor_header *fs_source_sink_function [] = {
}; };
static const struct usb_descriptor_header *fs_loopback_function [] = { static const struct usb_descriptor_header *fs_loopback_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_source_desc,
...@@ -356,6 +371,7 @@ dev_qualifier = { ...@@ -356,6 +371,7 @@ dev_qualifier = {
}; };
static const struct usb_descriptor_header *hs_source_sink_function [] = { static const struct usb_descriptor_header *hs_source_sink_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc, (struct usb_descriptor_header *) &hs_sink_desc,
...@@ -363,6 +379,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = { ...@@ -363,6 +379,7 @@ static const struct usb_descriptor_header *hs_source_sink_function [] = {
}; };
static const struct usb_descriptor_header *hs_loopback_function [] = { static const struct usb_descriptor_header *hs_loopback_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc, (struct usb_descriptor_header *) &hs_sink_desc,
...@@ -444,6 +461,10 @@ config_buf (struct usb_gadget *gadget, ...@@ -444,6 +461,10 @@ config_buf (struct usb_gadget *gadget,
? fs_source_sink_function ? fs_source_sink_function
: fs_loopback_function; : fs_loopback_function;
/* for now, don't advertise srp-only devices */
if (!gadget->is_otg)
function++;
len = usb_gadget_config_buf (is_source_sink len = usb_gadget_config_buf (is_source_sink
? &source_sink_config ? &source_sink_config
: &loopback_config, : &loopback_config,
...@@ -485,7 +506,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) ...@@ -485,7 +506,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/* optionally require specific source/sink data patterns */ /* optionally require specific source/sink data patterns */
static inline int static int
check_read_data ( check_read_data (
struct zero_dev *dev, struct zero_dev *dev,
struct usb_ep *ep, struct usb_ep *ep,
...@@ -519,7 +540,7 @@ check_read_data ( ...@@ -519,7 +540,7 @@ check_read_data (
return 0; return 0;
} }
static inline void static void
reinit_write_data ( reinit_write_data (
struct zero_dev *dev, struct zero_dev *dev,
struct usb_ep *ep, struct usb_ep *ep,
...@@ -811,6 +832,7 @@ static void zero_reset_config (struct zero_dev *dev) ...@@ -811,6 +832,7 @@ static void zero_reset_config (struct zero_dev *dev)
dev->out_ep = 0; dev->out_ep = 0;
} }
dev->config = 0; dev->config = 0;
del_timer (&dev->resume);
} }
/* change our operational config. this code must agree with the code /* change our operational config. this code must agree with the code
...@@ -902,6 +924,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -902,6 +924,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
/* usually this stores reply data in the pre-allocated ep0 buffer, /* usually this stores reply data in the pre-allocated ep0 buffer,
* but config change events will reconfigure hardware. * but config change events will reconfigure hardware.
*/ */
req->zero = 0;
switch (ctrl->bRequest) { switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR: case USB_REQ_GET_DESCRIPTOR:
...@@ -951,6 +974,12 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -951,6 +974,12 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_SET_CONFIGURATION: case USB_REQ_SET_CONFIGURATION:
if (ctrl->bRequestType != 0) if (ctrl->bRequestType != 0)
goto unknown; goto unknown;
if (gadget->a_hnp_support)
DBG (dev, "HNP available\n");
else if (gadget->a_alt_hnp_support)
DBG (dev, "HNP needs a different root port\n");
else
VDBG (dev, "HNP inactive\n");
spin_lock (&dev->lock); spin_lock (&dev->lock);
value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
spin_unlock (&dev->lock); spin_unlock (&dev->lock);
...@@ -1080,8 +1109,10 @@ zero_autoresume (unsigned long _dev) ...@@ -1080,8 +1109,10 @@ zero_autoresume (unsigned long _dev)
/* normally the host would be woken up for something /* normally the host would be woken up for something
* more significant than just a timer firing... * more significant than just a timer firing...
*/ */
status = usb_gadget_wakeup (dev->gadget); if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
DBG (dev, "wakeup --> %d\n", status); status = usb_gadget_wakeup (dev->gadget);
DBG (dev, "wakeup --> %d\n", status);
}
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1199,6 +1230,12 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1199,6 +1230,12 @@ zero_bind (struct usb_gadget *gadget)
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#endif #endif
if (gadget->is_otg) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
usb_gadget_set_selfpowered (gadget); usb_gadget_set_selfpowered (gadget);
init_timer (&dev->resume); init_timer (&dev->resume);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment