ChangeSet 1.1757.66.24, 2004/07/14 15:00:19-07:00, david-b@pacbell.net [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: David Brownell Signed-off-by: Greg Kroah-Hartman drivers/usb/gadget/Kconfig | 10 ++++++++++ drivers/usb/gadget/zero.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 4 deletions(-) diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2004-07-14 16:44:15 -07:00 +++ b/drivers/usb/gadget/Kconfig 2004-07-14 16:44:15 -07:00 @@ -208,6 +208,16 @@ Say "y" to link the driver statically, or "m" to build a 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 tristate "Ethernet Gadget" depends on NET diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c 2004-07-14 16:44:15 -07:00 +++ b/drivers/usb/gadget/zero.c 2004-07-14 16:44:15 -07:00 @@ -194,8 +194,13 @@ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ +#ifndef CONFIG_USB_ZERO_HNPTEST #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ #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 @@ .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 */ static const struct usb_interface_descriptor @@ -302,6 +315,7 @@ }; 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 *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, @@ -309,6 +323,7 @@ }; 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 *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, @@ -356,6 +371,7 @@ }; 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 *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, @@ -363,6 +379,7 @@ }; 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 *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, @@ -444,6 +461,10 @@ ? fs_source_sink_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 ? &source_sink_config : &loopback_config, @@ -485,7 +506,7 @@ /* optionally require specific source/sink data patterns */ -static inline int +static int check_read_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -519,7 +540,7 @@ return 0; } -static inline void +static void reinit_write_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -811,6 +832,7 @@ dev->out_ep = 0; } dev->config = 0; + del_timer (&dev->resume); } /* change our operational config. this code must agree with the code @@ -902,6 +924,7 @@ /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ + req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -951,6 +974,12 @@ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) 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); value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); @@ -1080,8 +1109,10 @@ /* normally the host would be woken up for something * more significant than just a timer firing... */ - status = usb_gadget_wakeup (dev->gadget); - DBG (dev, "wakeup --> %d\n", status); + if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + status = usb_gadget_wakeup (dev->gadget); + DBG (dev, "wakeup --> %d\n", status); + } } /*-------------------------------------------------------------------------*/ @@ -1198,6 +1229,12 @@ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #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);