From 5f848137744106ee737f559454ce5adfceb38347 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 16 Dec 2006 15:34:53 -0800 Subject: USB: becomes This moves to to reduce some of the clutter of usb header files. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 812c733ba8ce..5a72743606fd 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 83b4866df9af..d18901b92cda 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 53d584589c26..f28af06905a5 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d15bf22b9a03..ca8e0ebc79e8 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 72f2ae96fbf3..027b31505265 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -253,7 +253,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index f1a679656c96..d08a8d0e6427 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index d0ef1d6b3fac..e873cf488246 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index e3bb78524c88..b3fe197e1eeb 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -49,7 +49,7 @@ #include #include -#include +#include #include /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 569eb8ccf232..7617ff7bd5ac 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index cdcfd42843d4..140104341db4 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index b78de9694665..0d225369847d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -56,7 +56,7 @@ #include #endif -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f8a3ec64635d..6c742a909225 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index b1735767660b..3459ea6c6c0b 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 40710ea1b490..ebe04e0d2879 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -84,7 +84,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" -- cgit v1.2.2 From 11d5489873facd395653a4ee14669751bfe9bab5 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 11 Dec 2006 15:59:04 -0800 Subject: USB: ethernet gadget interop with MCCI Windows driver It turns out that minor tweaks to the "CDC Subset" support in the Ethernet gadget driver, just updating a config descriptor, let it be automagically recognized by a Windows driver supported by MCCI. This patch adds those descriptors, so systems using PXA 255 processors (like Gumstix etc) can interop with those commercial MS-Windows drivers. This is a Good Thing since Microsoft's RNDIS code has bugginess issues, which are unfortunately compounded by "won't fix" issues as well as "the published specs are incomplete and wrong" issues. Being able to talk to the MCCI driver gives Windows users another connectivity option. (MCCI also has CDC Ethernet drivers, which can help most non-PXA processors.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 142 ++++++++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 39 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index ca8e0ebc79e8..72e2b65293c8 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -72,9 +72,18 @@ * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. - * Linux supports it, but other host operating systems may not. - * (This is a subset of CDC Ethernet.) + * link-level setup only requires activating the configuration. Only the + * endpoint descriptors, and product/vendor IDs, are relevant; no control + * operations are available. Linux supports it, but other host operating + * systems may not. (This is a subset of CDC Ethernet.) + * + * It turns out that if you add a few descriptors to that "CDC Subset", + * (Windows) host side drivers from MCCI can treat it as one submode of + * a proprietary scheme called "SAFE" ... without needing to know about + * specific product/vendor IDs. So we do that, making it easier to use + * those MS-Windows drivers. Those added descriptors make it resemble a + * CDC MDLM device, but they don't change device behavior at all. (See + * MCCI Engineering report 950198 "SAFE Networking Functions".) * * A third option is also in use. Rather than CDC Ethernet, or something * simpler, Microsoft pushes their own approach: RNDIS. The published @@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_S3C2410 +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_AT91 #define DEV_CONFIG_CDC #endif @@ -283,9 +296,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_S3C2410 -#define DEV_CONFIG_CDC -#endif /*-------------------------------------------------------------------------*/ @@ -487,8 +497,17 @@ rndis_config = { * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. * - * RNDIS shares a lot with CDC-Ethernet, since it's a variant of - * the CDC-ACM (modem) spec. + * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the + * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it + * may hang or oops. Since bugfixes (or accurate specs, letting Linux + * work around those bugs) are unlikely to ever come from MSFT, you may + * wish to avoid using RNDIS. + * + * MCCI offers an alternative to RNDIS if you need to connect to Windows + * but have hardware that can't support CDC Ethernet. We add descriptors + * to present the CDC Subset as a (nonconformant) CDC MDLM variant called + * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can + * get those drivers from MCCI, or bundled with various products. */ #ifdef DEV_CONFIG_CDC @@ -522,8 +541,6 @@ rndis_control_intf = { }; #endif -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - static const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -532,6 +549,8 @@ static const struct usb_cdc_header_desc header_desc = { .bcdCDC = __constant_cpu_to_le16 (0x0110), }; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -564,7 +583,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = { #endif -#ifdef DEV_CONFIG_CDC +#ifndef DEV_CONFIG_CDC + +/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various + * ways: data endpoints live in the control interface, there's no data + * interface, and it's not used to talk to a cell phone radio. + */ + +static const struct usb_cdc_mdlm_desc mdlm_desc = { + .bLength = sizeof mdlm_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_MDLM_TYPE, + + .bcdVersion = __constant_cpu_to_le16(0x0100), + .bGUID = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, + }, +}; + +/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we + * can't really use its struct. All we do here is say that we're using + * the submode of "SAFE" which directly matches the CDC Subset. + */ +static const u8 mdlm_detail_desc[] = { + 6, + USB_DT_CS_INTERFACE, + USB_CDC_MDLM_DETAIL_TYPE, + + 0, /* "SAFE" */ + 0, /* network control capabilities (none) */ + 0, /* network data capabilities ("raw" encapsulation) */ +}; + +#endif static const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, @@ -579,7 +631,6 @@ static const struct usb_cdc_ether_desc ether_desc = { .bNumberPowerFilters = 0, }; -#endif #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -672,6 +723,9 @@ rndis_data_intf = { /* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. + * + * To assist host side drivers, we fancy it up a bit, and add descriptors + * so some host side drivers will understand it as a "SAFE" variant. */ static const struct usb_interface_descriptor @@ -682,8 +736,8 @@ subset_data_intf = { .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; @@ -731,10 +785,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = { static inline void __init fs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[4] = NULL; + fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[8] = NULL; #else fs_eth_function[1] = NULL; #endif @@ -828,10 +887,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = { static inline void __init hs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[4] = NULL; + hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; + hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; + hs_eth_function[8] = NULL; #else hs_eth_function[1] = NULL; #endif @@ -878,10 +942,8 @@ static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; static char serial_number [20]; -#ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; -#endif /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -889,9 +951,9 @@ static struct usb_string strings [] = { { STRING_PRODUCT, product_desc, }, { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, + { STRING_ETHADDR, ethaddr, }, #ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, - { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", }, #endif #ifdef DEV_CONFIG_SUBSET @@ -986,10 +1048,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) } #endif - dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; - dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data @@ -2278,10 +2340,10 @@ eth_bind (struct usb_gadget *gadget) "RNDIS/%s", driver_desc); /* CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. + * drivers aren't widely available. (That may be improved by + * supporting one submode of the "SAFE" variant of MDLM.) */ } else if (!cdc) { - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; device_desc.idVendor = __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); device_desc.idProduct = @@ -2352,6 +2414,10 @@ autoconf_fail: if (!cdc) { eth_config.bNumInterfaces = 1; eth_config.iConfiguration = STRING_SUBSET; + + /* use functions to set these up, in case we're built to work + * with multiple controllers and must override CDC Ethernet. + */ fs_subset_descriptors(); hs_subset_descriptors(); } @@ -2415,22 +2481,20 @@ autoconf_fail: /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * ends up in a persistent config database. + * ends up in a persistent config database. It's not clear if + * host side code for the SAFE thing cares -- its original BLAN + * thing didn't, Sharp never assigned those addresses on Zaurii. */ if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); - if (cdc || rndis) { - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&gadget->dev, - "using random %s ethernet address\n", "host"); -#ifdef DEV_CONFIG_CDC - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - dev->host_mac [0], dev->host_mac [1], - dev->host_mac [2], dev->host_mac [3], - dev->host_mac [4], dev->host_mac [5]); -#endif - } + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "host"); + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); if (rndis) { status = rndis_init(); -- cgit v1.2.2 From 7ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5 Mon Sep 17 00:00:00 2001 From: John Daiker Date: Fri, 29 Dec 2006 19:02:06 -0800 Subject: USB Gadget file_storage.c: remove unnecessary casts Went looking through some usb stuff and found some unnecessary casts in file_storage.c This is part of the KernelJanitors TODO list. Signed-off-by: John Daiker Acked-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/file_storage.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 027b31505265..f04a29a46646 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg) static void ep0_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; if (req->actual > 0) dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); @@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) @@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) #ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg) } if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; + struct bulk_cs_wrap *csw = bh->buf; /* Store and send the Bulk-only CSW */ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); @@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg) return 0; } else { // USB_PR_CBI - struct interrupt_data *buf = (struct interrupt_data *) - bh->buf; + struct interrupt_data *buf = bh->buf; /* Store and send the Interrupt data. UFI sends the ASC * and ASCQ bytes. Everything else sends a Type (which @@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg) static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; + struct bulk_cb_wrap *cbw = req->buf; /* Was this a real packet? */ if (req->status) @@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg) static int fsg_main_thread(void *fsg_) { - struct fsg_dev *fsg = (struct fsg_dev *) fsg_; + struct fsg_dev *fsg = fsg_; /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ @@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); char *p; ssize_t rc; @@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int i; if (sscanf(buf, "%d", &i) != 1) @@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int rc = 0; if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { @@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref) static void lun_release(struct device *dev) { - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); kref_put(&fsg->ref, fsg_release); } -- cgit v1.2.2 From 2505107def8b300576223367e3b603620d825e52 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 15 Jan 2007 11:30:28 -0800 Subject: usb: gadgetfs whitespace cleanup Remove some whitespace bugs in gadgetfs (mostly from someone's patch updating the AIO support). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3fb1044a4db0..10a5f7a164de 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,7 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ +// #define DEBUG /* data to help fault diagnosis */ // #define VERBOSE /* extra debug messages (success too) */ #include @@ -565,29 +565,29 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) ssize_t len, total; int i; - /* we "retry" to get the right mm context for this: */ - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - if (total == 0) - break; - } - kfree(priv->buf); - kfree(priv); - aio_put_req(iocb); - return len; + /* we "retry" to get the right mm context for this: */ + + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } + + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + aio_put_req(iocb); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -636,7 +636,7 @@ ep_aio_rwtail( size_t len, struct ep_data *epdata, const struct iovec *iv, - unsigned long nr_segs + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -1808,7 +1808,7 @@ static struct usb_gadget_driver gadgetfs_driver = { .disconnect = gadgetfs_disconnect, .suspend = gadgetfs_suspend, - .driver = { + .driver = { .name = (char *) shortname, }, }; @@ -1829,7 +1829,7 @@ static struct usb_gadget_driver probe_driver = { .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, - .driver = { + .driver = { .name = "nop", }, }; @@ -1849,7 +1849,7 @@ static struct usb_gadget_driver probe_driver = { * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; - * this one's optional except for high-speed hardware + * this one's optional except for high-speed hardware * . device descriptor * * Endpoints are not yet enabled. Drivers may want to immediately -- cgit v1.2.2 From 511779fd9eb7ed67116e4a1cad802363d2d58b20 Mon Sep 17 00:00:00 2001 From: Phil Endecott Date: Mon, 15 Jan 2007 11:35:01 -0800 Subject: usb: gadgetfs remove delayed init mode Gadgetfs had a mode in which endpoint descriptors were written by the user program before connection. This mode had some bugs, and hasn't seen much (if any) use. This patch removes that mode, leaving the mode of operation where the user program waits for endpoint 0 to report a SET_CONFIGURATION, and only then configures the endpoints. From: "Phil Endecott" Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 60 ++++++++++------------------------------------ 1 file changed, 12 insertions(+), 48 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 10a5f7a164de..0f00249720b3 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -59,11 +59,11 @@ * may serve as a source of device events, used to handle all control * requests other than basic enumeration. * - * - Then either immediately, or after a SET_CONFIGURATION control request, - * ep_config() is called when each /dev/gadget/ep* file is configured - * (by writing endpoint descriptors). Afterwards these files are used - * to write() IN data or to read() OUT data. To halt the endpoint, a - * "wrong direction" request is issued (like reading an IN endpoint). + * - Then, after a SET_CONFIGURATION control request, ep_config() is + * called when each /dev/gadget/ep* file is configured (by writing + * endpoint descriptors). Afterwards these files are used to write() + * IN data or to read() OUT data. To halt the endpoint, a "wrong + * direction" request is issued (like reading an IN endpoint). * * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe * not possible on all hardware. For example, precise fault handling with @@ -188,7 +188,6 @@ static struct dev_data *dev_new (void) enum ep_state { STATE_EP_DISABLED = 0, STATE_EP_READY, - STATE_EP_DEFER_ENABLE, STATE_EP_ENABLED, STATE_EP_UNBOUND, }; @@ -313,18 +312,10 @@ nonblock: if ((val = down_interruptible (&epdata->lock)) < 0) return val; -newstate: + switch (epdata->state) { case STATE_EP_ENABLED: break; - case STATE_EP_DEFER_ENABLE: - DBG (epdata->dev, "%s wait for host\n", epdata->name); - if ((val = wait_event_interruptible (epdata->wait, - epdata->state != STATE_EP_DEFER_ENABLE - || epdata->dev->state == STATE_DEV_UNBOUND - )) < 0) - goto fail; - goto newstate; // case STATE_EP_DISABLED: /* "can't happen" */ // case STATE_EP_READY: /* "can't happen" */ default: /* error! */ @@ -333,7 +324,6 @@ newstate: // FALLTHROUGH case STATE_EP_UNBOUND: /* clean disconnect */ val = -ENODEV; -fail: up (&epdata->lock); } return val; @@ -852,9 +842,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) break; #endif default: - DBG (data->dev, "unconnected, %s init deferred\n", + DBG(data->dev, "unconnected, %s init abandoned\n", data->name); - data->state = STATE_EP_DEFER_ENABLE; + value = -EINVAL; } if (value == 0) { fd->f_op = &ep_io_operations; @@ -1393,8 +1383,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_UNCONNECTED) { - struct usb_ep *ep; - struct ep_data *data; dev->state = STATE_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; @@ -1411,27 +1399,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) event->u.speed = gadget->speed; ep0_readable (dev); - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - data = ep->driver_data; - /* ... down_trylock (&data->lock) ... */ - if (data->state != STATE_EP_DEFER_ENABLE) - continue; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) - value = usb_ep_enable (ep, &data->hs_desc); - else -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - value = usb_ep_enable (ep, &data->desc); - if (value) { - ERROR (dev, "deferred %s enable --> %d\n", - data->name, value); - continue; - } - data->state = STATE_EP_ENABLED; - wake_up (&data->wait); - DBG (dev, "woke up %s waiters\n", data->name); - } - /* host may have given up waiting for response. we can miss control * requests handled lower down (device/endpoint status and features); * then ep0_{read,write} will report the wrong status. controller @@ -1852,16 +1819,13 @@ static struct usb_gadget_driver probe_driver = { * this one's optional except for high-speed hardware * . device descriptor * - * Endpoints are not yet enabled. Drivers may want to immediately - * initialize them, using the /dev/gadget/ep* files that are available - * as soon as the kernel sees the configuration, or they can wait - * until device configuration and interface altsetting changes create + * Endpoints are not yet enabled. Drivers must wait until device + * configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that - * $CHIP file is open. Events may then be read from that descriptor, - * such as configuration notifications. More complex drivers will handle - * some control requests in user space. + * $CHIP file is open. Events must then be read from that descriptor, + * such as configuration notifications. */ static int is_valid_config (struct usb_config_descriptor *config) -- cgit v1.2.2 From 66e56ce75e39210415fb12ceacd5f3580ad72d50 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 12:46:39 -0800 Subject: USB: at91_udc wakeup event updates This updates the AT91 UDC driver's handling of wakeup events: - Fix a bug in the original scheme, which was never updated after the {enable,disable}_irq_wake() semantics were updated to address refcounting issues (i.e. behave for shared irqs). - Couple handling of both type of wakeup events, to be more direct. The controller can be source of wakeup events for cases like bus reset and USB resume. On some boards, VBUS sensing is also IRQ driven. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/at91_udc.c | 19 +++++++++++-------- drivers/usb/gadget/at91_udc.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 5a72743606fd..f39050145f1f 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) || !wake || at91_suspend_entering_slow_clock()) { pullup(udc, 0); - disable_irq_wake(udc->udp_irq); + wake = 0; } else enable_irq_wake(udc->udp_irq); - if (udc->board.vbus_pin > 0) { - if (wake) - enable_irq_wake(udc->board.vbus_pin); - else - disable_irq_wake(udc->board.vbus_pin); - } + udc->active_suspend = wake; + if (udc->board.vbus_pin > 0 && wake) + enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + if (udc->board.vbus_pin > 0 && udc->active_suspend) + disable_irq_wake(udc->board.vbus_pin); + /* maybe reconnect to host; if so, clocks on */ - pullup(udc, 1); + if (udc->active_suspend) + disable_irq_wake(udc->udp_irq); + else + pullup(udc, 1); return 0; } #else diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 677089baa59d..7e34e2f864f9 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -136,6 +136,7 @@ struct at91_udc { unsigned wait_for_addr_ack:1; unsigned wait_for_config_ack:1; unsigned selfpowered:1; + unsigned active_suspend:1; u8 addr; struct at91_udc_data board; struct clk *iclk, *fclk; -- cgit v1.2.2 From 7489d14943181731ef8694e2ea2d5a919b93b956 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:51:04 -0800 Subject: USB: gadgetfs cleanups Minor gadgetfs cleanups: - EP0 state constants become consistently STATE_DEV_* rather than sometimes omitting the "DEV_"; STATE_EP_* were already consistent. - Comment that ep0 state is protected by the spinlock, and update code that was neglecting that rule. None of this is expected to change behavior. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 75 +++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 34 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 0f00249720b3..cbdcb3c10c5e 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -98,16 +98,16 @@ enum ep0_state { * must always write descriptors to initialize the device, then * the device becomes UNCONNECTED until enumeration. */ - STATE_OPENED, + STATE_DEV_OPENED, /* From then on, ep0 fd is in either of two basic modes: * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it * - SETUP: read/write will transfer control data and succeed; * or if "wrong direction", performs protocol stall */ - STATE_UNCONNECTED, - STATE_CONNECTED, - STATE_SETUP, + STATE_DEV_UNCONNECTED, + STATE_DEV_CONNECTED, + STATE_DEV_SETUP, /* UNBOUND means the driver closed ep0, so the device won't be * accessible again (DEV_DISABLED) until all fds are closed. @@ -121,7 +121,7 @@ enum ep0_state { struct dev_data { spinlock_t lock; atomic_t count; - enum ep0_state state; + enum ep0_state state; /* P: lock */ struct usb_gadgetfs_event event [N_EVENT]; unsigned ev_next; struct fasync_struct *fasync; @@ -942,8 +942,14 @@ static void ep0_complete (struct usb_ep *ep, struct usb_request *req) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else if (dev->state == STATE_SETUP) - dev->state = STATE_CONNECTED; + } else { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state == STATE_DEV_SETUP) + dev->state = STATE_DEV_CONNECTED; + spin_unlock_irqrestore(&dev->lock, flags); + } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) @@ -988,13 +994,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) } /* control DATA stage */ - if ((state = dev->state) == STATE_SETUP) { + if ((state = dev->state) == STATE_DEV_SETUP) { if (dev->setup_in) { /* stall IN */ VDEBUG(dev, "ep0in stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else if (len == 0) { /* ack SET_CONFIGURATION etc */ struct usb_ep *ep = dev->gadget->ep0; @@ -1002,7 +1008,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) if ((retval = setup_req (ep, req, 0)) == 0) retval = usb_ep_queue (ep, req, GFP_ATOMIC); - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; /* assume that was SET_CONFIGURATION */ if (dev->current_config) { @@ -1061,7 +1067,7 @@ scan: len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); - /* ep0 can't deliver events when STATE_SETUP */ + /* ep0 can't deliver events when STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { len = i + 1; @@ -1088,7 +1094,7 @@ scan: sizeof (struct usb_gadgetfs_event) * (tmp - len)); if (n == 0) - dev->state = STATE_SETUP; + dev->state = STATE_DEV_SETUP; spin_unlock_irq (&dev->lock); } return retval; @@ -1103,8 +1109,8 @@ scan: DBG (dev, "fail %s, state %d\n", __FUNCTION__, state); retval = -ESRCH; break; - case STATE_UNCONNECTED: - case STATE_CONNECTED: + case STATE_DEV_UNCONNECTED: + case STATE_DEV_CONNECTED: spin_unlock_irq (&dev->lock); DBG (dev, "%s wait\n", __FUNCTION__); @@ -1131,7 +1137,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) switch (type) { /* these events purge the queue */ case GADGETFS_DISCONNECT: - if (dev->state == STATE_SETUP) + if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; // FALL THROUGH case GADGETFS_CONNECT: @@ -1178,7 +1184,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) retval = -EIDRM; /* data and/or status stage for control request */ - } else if (dev->state == STATE_SETUP) { + } else if (dev->state == STATE_DEV_SETUP) { /* IN DATA+STATUS caller makes len <= wLength */ if (dev->setup_in) { @@ -1209,7 +1215,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) VDEBUG(dev, "ep0out stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else { DBG(dev, "bogus ep0out stall!\n"); } @@ -1251,7 +1257,9 @@ dev_release (struct inode *inode, struct file *fd) put_dev (dev); /* other endpoints were all decoupled from this device */ + spin_lock_irq(&dev->lock); dev->state = STATE_DEV_DISABLED; + spin_unlock_irq(&dev->lock); return 0; } @@ -1272,7 +1280,7 @@ ep0_poll (struct file *fd, poll_table *wait) goto out; } - if (dev->state == STATE_SETUP) { + if (dev->state == STATE_DEV_SETUP) { if (dev->setup_in || dev->setup_can_stall) mask = POLLOUT; } else { @@ -1382,9 +1390,9 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; - if (dev->state == STATE_UNCONNECTED) { + if (dev->state == STATE_DEV_UNCONNECTED) { - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1404,7 +1412,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * then ep0_{read,write} will report the wrong status. controller * driver will have aborted pending i/o. */ - } else if (dev->state == STATE_SETUP) + } else if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; req->buf = dev->rbuf; @@ -1550,7 +1558,7 @@ delegate: } /* proceed with data transfer and status phases? */ - if (value >= 0 && dev->state != STATE_SETUP) { + if (value >= 0 && dev->state != STATE_DEV_SETUP) { req->length = value; req->zero = value < w_length; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); @@ -1714,7 +1722,9 @@ gadgetfs_bind (struct usb_gadget *gadget) goto enomem; INFO (dev, "bound to %s driver\n", gadget->name); - dev->state = STATE_UNCONNECTED; + spin_lock_irq(&dev->lock); + dev->state = STATE_DEV_UNCONNECTED; + spin_unlock_irq(&dev->lock); get_dev (dev); return 0; @@ -1729,11 +1739,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget) struct dev_data *dev = get_gadget_data (gadget); spin_lock (&dev->lock); - if (dev->state == STATE_UNCONNECTED) { - DBG (dev, "already unconnected\n"); + if (dev->state == STATE_DEV_UNCONNECTED) goto exit; - } - dev->state = STATE_UNCONNECTED; + dev->state = STATE_DEV_UNCONNECTED; INFO (dev, "disconnected\n"); next_event (dev, GADGETFS_DISCONNECT); @@ -1750,9 +1758,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) INFO (dev, "suspended from state %d\n", dev->state); spin_lock (&dev->lock); switch (dev->state) { - case STATE_SETUP: // VERY odd... host died?? - case STATE_CONNECTED: - case STATE_UNCONNECTED: + case STATE_DEV_SETUP: // VERY odd... host died?? + case STATE_DEV_CONNECTED: + case STATE_DEV_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); /* FALLTHROUGH */ @@ -1848,9 +1856,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) u32 tag; char *kbuf; - if (dev->state != STATE_OPENED) - return -EEXIST; - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; @@ -1942,13 +1947,15 @@ dev_open (struct inode *inode, struct file *fd) struct dev_data *dev = inode->i_private; int value = -EBUSY; + spin_lock_irq(&dev->lock); if (dev->state == STATE_DEV_DISABLED) { dev->ev_next = 0; - dev->state = STATE_OPENED; + dev->state = STATE_DEV_OPENED; fd->private_data = dev; get_dev (dev); value = 0; } + spin_unlock_irq(&dev->lock); return value; } -- cgit v1.2.2 From 0864c7a9286b02319d3db2103bada1c2269c1e1e Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:53:58 -0800 Subject: USB: gadgetfs simplifications This simplifies event reading by eliminating arithmetic and being more direct/obvious, and tweaks some debug messages slightly. The math elimination will change timings, sometimes enough to allow a race to appear. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index cbdcb3c10c5e..ea8e3160d05e 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1062,39 +1062,36 @@ scan: /* return queued events right away */ if (dev->ev_next != 0) { unsigned i, n; - int tmp = dev->ev_next; - len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); + if (dev->ev_next < n) + n = dev->ev_next; - /* ep0 can't deliver events when STATE_DEV_SETUP */ + /* ep0 i/o has special semantics during STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { - len = i + 1; - len *= sizeof (struct usb_gadgetfs_event); - n = 0; + dev->state = STATE_DEV_SETUP; + n = i + 1; break; } } spin_unlock_irq (&dev->lock); + len = n * sizeof (struct usb_gadgetfs_event); if (copy_to_user (buf, &dev->event, len)) retval = -EFAULT; else retval = len; if (len > 0) { - len /= sizeof (struct usb_gadgetfs_event); - /* NOTE this doesn't guard against broken drivers; * concurrent ep0 readers may lose events. */ spin_lock_irq (&dev->lock); - dev->ev_next -= len; - if (dev->ev_next != 0) - memmove (&dev->event, &dev->event [len], + if (dev->ev_next > n) { + memmove(&dev->event[0], &dev->event[n], sizeof (struct usb_gadgetfs_event) - * (tmp - len)); - if (n == 0) - dev->state = STATE_DEV_SETUP; + * (dev->ev_next - n)); + } + dev->ev_next -= n; spin_unlock_irq (&dev->lock); } return retval; @@ -1149,7 +1146,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) for (i = 0; i != dev->ev_next; i++) { if (dev->event [i].type != type) continue; - DBG (dev, "discard old event %d\n", type); + DBG(dev, "discard old event[%d] %d\n", i, type); dev->ev_next--; if (i == dev->ev_next) break; @@ -1162,9 +1159,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) default: BUG (); } + VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); event = &dev->event [dev->ev_next++]; BUG_ON (dev->ev_next > N_EVENT); - VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next); memset (event, 0, sizeof *event); event->type = type; return event; -- cgit v1.2.2 From 5b89db02a5a7c8bad3c6fb7888778082a441b385 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 22:56:26 -0800 Subject: USB: gadgetfs race fix This resolves a race in gadgetfs associated with changing device/ep0 when processing control requests. The fix is to change that state earlier, when the control response is issued, so there's no window in which userspace could see the wrong state; and enlarge the scope of the spinlock during the ep0 request completion handler. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ea8e3160d05e..e5ce4f0bb7cc 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -933,28 +933,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) static void ep0_complete (struct usb_ep *ep, struct usb_request *req) { struct dev_data *dev = ep->driver_data; + unsigned long flags; int free = 1; /* for control OUT, data must still get to userspace */ + spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) { dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->state == STATE_DEV_SETUP) - dev->state = STATE_DEV_CONNECTED; - spin_unlock_irqrestore(&dev->lock, flags); } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) clean_req (ep, req); req->complete = epio_complete; + spin_unlock_irqrestore(&dev->lock, flags); } static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) @@ -1036,6 +1032,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); if (retval) goto done; + + if (dev->state != STATE_DEV_SETUP) { + retval = -ECANCELED; + goto done; + } + dev->state = STATE_DEV_CONNECTED; + if (dev->setup_out_error) retval = -EIO; else { @@ -1187,6 +1190,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { + dev->state = STATE_DEV_CONNECTED; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; -- cgit v1.2.2 From ce46794f77f698eaf3b80922fafac5a9379085e0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 16 Jan 2007 23:06:07 -0800 Subject: USB: gadgetfs behaves better on userspace init bug Resolve an initizlization issue that could come up if the userspace driver wrote invalid descriptors to a dual-speed device. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index e5ce4f0bb7cc..1c5e1ee7e36b 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1392,17 +1392,17 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; if (dev->state == STATE_DEV_UNCONNECTED) { - - dev->state = STATE_DEV_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; - #ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { + spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } #endif /* CONFIG_USB_GADGET_DUALSPEED */ + dev->state = STATE_DEV_CONNECTED; + dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; + INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); event->u.speed = gadget->speed; -- cgit v1.2.2 From 49631ca7f3e2fd05186028b453fa27f75b830de7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 23:28:48 -0800 Subject: USB: gadgetfs AIO tweaks This patch (as837) fixes several mistakes in the AIO interface of the gadgetfs driver: The ki_retry method is not supposed to do a put on the kiocb. The extra call to aio_put_req() causes memory corruption. (Note: This call was removed before, by patch as691, and then mysteriously re-introduced later.) Even if a read transfer is cancelled, we can and should send to the user all the data that did manage to get transferred. Testing for AIO cancellation in the I/O completion handler is both racy and (now) unnecessary. aio_complete() does its own checking, in a safe manner. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 1c5e1ee7e36b..34296e79edcf 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -576,7 +576,6 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) } kfree(priv->buf); kfree(priv); - aio_put_req(iocb); return len; } @@ -590,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->iv == NULL - || unlikely(req->actual == 0) - || unlikely(kiocbIsCancelled(iocb))) { + + /* if this was a write or a read returning no data then we + * don't need to copy anything to userspace, so we can + * complete the aio request immediately. + */ + if (priv->iv == NULL || unlikely(req->actual == 0)) { kfree(req->buf); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - if (unlikely(kiocbIsCancelled(iocb))) - aio_put_req(iocb); - else - aio_complete(iocb, - req->actual ? req->actual : req->status, + aio_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { /* retry() won't report both; so we hide some faults */ -- cgit v1.2.2 From 1f5b9cc9e4cf5847e7550c4079cebb80170e71dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=E5vard=20Skinnemoen?= Date: Wed, 17 Jan 2007 11:03:29 -0800 Subject: USB: list atmel husb2_udc gadget controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This identifies the driver for the Atmel HUSB2 Device Controller, as integrated into the first AVR32 chip, the AT32AP700. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/gadget_chips.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index aa80f0910720..2e3d6620d216 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -75,6 +75,12 @@ #define gadget_is_pxa27x(g) 0 #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#else +#define gadget_is_husb2dev(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_S3C2410 #define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) #else @@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; + else if (gadget_is_husb2dev(gadget)) + return 0x18; return -ENOENT; } -- cgit v1.2.2 From ef3ff462a31987629c4d0488550fbbb66fbfcc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=E5vard=20Skinnemoen?= Date: Mon, 27 Feb 2006 18:15:04 +0100 Subject: USB: usb ethernet gadget recognizes HUSB2DEV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define DEV_CONFIG_CDC when compiling for HUSB2DEV. From: Håvard Skinnemoen Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb/gadget') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 72e2b65293c8..22e3c9443641 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -279,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. -- cgit v1.2.2