From dda034bcb51a0a28318046d74d664e0fc5f7d1d4 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 27 May 2007 17:04:58 +0200 Subject: USB: set default y for CONFIG_USB_DEVICE_CLASS Signed-off-by: Kay Sievers Cc: bert hubert Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Kconfig | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f493fb1eaa2..346fc030c92 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -40,21 +40,25 @@ config USB_DEVICEFS config USB_DEVICE_CLASS bool "USB device class-devices (DEPRECATED)" depends on USB - default n + default y ---help--- Userspace access to USB devices is granted by device-nodes exported directly from the usbdev in sysfs. Old versions of the driver core and udev needed additional class devices to export device nodes. These additional devices are difficult to handle in userspace, if - information about USB interfaces must be available. One device contains - the device node, the other device contains the interface data. Both - devices are at the same level in sysfs (siblings) and one can't access - the other. The device node created directly by the usbdev is the parent - device of the interface and therefore easily accessible from the interface - event. - - This option provides backward compatibility if needed. + information about USB interfaces must be available. One device + contains the device node, the other device contains the interface + data. Both devices are at the same level in sysfs (siblings) and one + can't access the other. The device node created directly by the + usb device is the parent device of the interface and therefore + easily accessible from the interface event. + + This option provides backward compatibility for libusb device + nodes (lsusb) when usbfs is not used, and the following udev rule + doesn't exist: + SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ + NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation (EXPERIMENTAL)" -- cgit v1.2.3 From 97cb95d1c4b724bc3bedd16dd022fbd3c2d61283 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Thu, 24 May 2007 21:59:19 -0700 Subject: usblp: Don't let suspend to kill ->used Suspend destroys refcounting for open/release. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 7b1edfe46b2..6778f9af794 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -347,10 +347,8 @@ static int handle_bidir (struct usblp *usblp) if (usblp->bidir && usblp->used && !usblp->sleeping) { usblp->readcount = 0; usblp->readurb->dev = usblp->dev; - if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { - usblp->used = 0; + if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) return -EIO; - } } return 0; @@ -412,6 +410,7 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->readurb->status = 0; if (handle_bidir(usblp) < 0) { + usblp->used = 0; file->private_data = NULL; retval = -EIO; } -- cgit v1.2.3 From 01ee7d7032204b383b2fba73021e7acbc776184b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 25 May 2007 20:40:14 -0700 Subject: USB: usb gadgets avoid le{16,32}_to_cpup() It turns out that le16_to_cpup() and le32_to_cpup() aren't always safe to call with pointers into packed structures, since those are inlined functions and GCC may lose the "packed" attribute. So those references can become unaligned kernel accesses, which are evil on some hardware. This patch updates uses of those routines in the gadget stack. The references into packed structures can just use leXX_to_cpu(*x), which in most cases is more natural. Some other uses in RNDIS, mostly in debug code, were wrong in the first place; those use get_unaligned(). Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/inode.c | 8 ++++---- drivers/usb/gadget/net2280.c | 6 +++--- drivers/usb/gadget/omap_udc.c | 6 +++--- drivers/usb/gadget/rndis.c | 35 ++++++++++++++++++++++------------- 5 files changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index f28af06905a..6042364402b 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -132,7 +132,7 @@ ep_matches ( * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. */ - max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize); + max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize); switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high speed */ diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 188c74a9521..46d0e525274 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1369,12 +1369,12 @@ config_buf (struct dev_data *dev, u8 type, unsigned index) hs = !hs; if (hs) { dev->req->buf = dev->hs_config; - len = le16_to_cpup (&dev->hs_config->wTotalLength); + len = le16_to_cpu(dev->hs_config->wTotalLength); } else #endif { dev->req->buf = dev->config; - len = le16_to_cpup (&dev->config->wTotalLength); + len = le16_to_cpu(dev->config->wTotalLength); } ((u8 *)dev->req->buf) [1] = type; return len; @@ -1885,7 +1885,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* full or low speed config */ dev->config = (void *) kbuf; - total = le16_to_cpup (&dev->config->wTotalLength); + total = le16_to_cpu(dev->config->wTotalLength); if (!is_valid_config (dev->config) || total >= length) goto fail; kbuf += total; @@ -1894,7 +1894,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* optional high speed config */ if (kbuf [1] == USB_DT_CONFIG) { dev->hs_config = (void *) kbuf; - total = le16_to_cpup (&dev->hs_config->wTotalLength); + total = le16_to_cpu(dev->hs_config->wTotalLength); if (!is_valid_config (dev->hs_config) || total >= length) goto fail; kbuf += total; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 52779c52b56..d975ecf18e0 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2440,9 +2440,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) tmp = 0; -#define w_value le16_to_cpup (&u.r.wValue) -#define w_index le16_to_cpup (&u.r.wIndex) -#define w_length le16_to_cpup (&u.r.wLength) +#define w_value le16_to_cpu(u.r.wValue) +#define w_index le16_to_cpu(u.r.wIndex) +#define w_length le16_to_cpu(u.r.wLength) /* ack the irq */ writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index b394e63894d..c4975a6cf77 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -1651,9 +1651,9 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP); -#define w_value le16_to_cpup (&u.r.wValue) -#define w_index le16_to_cpup (&u.r.wIndex) -#define w_length le16_to_cpup (&u.r.wLength) +#define w_value le16_to_cpu(u.r.wValue) +#define w_index le16_to_cpu(u.r.wIndex) +#define w_length le16_to_cpu(u.r.wLength) /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 6ec8cf1a3cc..708657c8913 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -186,10 +186,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, DEBUG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DEBUG ("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpup((__le32 *)&buf[i]), - le32_to_cpup((__le32 *)&buf[i + 4]), - le32_to_cpup((__le32 *)&buf[i + 8]), - le32_to_cpup((__le32 *)&buf[i + 12])); + le32_to_cpu(get_unaligned((__le32 *) + &buf[i])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 4])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 8])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 12]))); } } @@ -665,7 +669,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_PNP_QUERY_POWER: DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__, - le32_to_cpup((__le32 *) buf) - 1); + le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... */ @@ -704,10 +708,14 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, DEBUG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DEBUG ("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpup((__le32 *)&buf[i]), - le32_to_cpup((__le32 *)&buf[i + 4]), - le32_to_cpup((__le32 *)&buf[i + 8]), - le32_to_cpup((__le32 *)&buf[i + 12])); + le32_to_cpu(get_unaligned((__le32 *) + &buf[i])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 4])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 8])), + le32_to_cpu(get_unaligned((__le32 *) + &buf[i + 12]))); } } @@ -721,7 +729,8 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - *params->filter = (u16) le32_to_cpup((__le32 *)buf); + *params->filter = (u16) le32_to_cpu(get_unaligned( + (__le32 *)buf)); DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __FUNCTION__, *params->filter); @@ -771,7 +780,7 @@ update_linkstate: * resuming, Windows forces a reset, and then SET_POWER D0. * FIXME ... then things go batty; Windows wedges itself. */ - i = le32_to_cpup((__force __le32 *)buf); + i = le32_to_cpu(get_unaligned((__le32 *)buf)); DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1); switch (i) { case NdisDeviceStateD0: @@ -1058,8 +1067,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOMEM; tmp = (__le32 *) buf; - MsgType = le32_to_cpup(tmp++); - MsgLength = le32_to_cpup(tmp++); + MsgType = le32_to_cpu(get_unaligned(tmp++)); + MsgLength = le32_to_cpu(get_unaligned(tmp++)); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; -- cgit v1.2.3 From 67fa10627ec0d8aa16f1cf38cf527e67d8097d3c Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Sat, 26 May 2007 03:06:32 -0700 Subject: USB: UNUSUAL_DEV: Sync up some reported devices from Ubuntu UNUSUAL_DEV: Sync up some reported devices from Ubuntu Various unusual dev entries accumulated from Ubuntu bug reports. Signed-off-by: Ben Collins Cc: Alan Stern Signed-off-by: Phil Dibowitz --- drivers/usb/storage/unusual_devs.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d230ee72f9c..54979c239c6 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1179,8 +1179,8 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* These are virtual windows driver CDs, which the zd1211rw driver automatically - * converts into a WLAN devices. */ +/* These are virtual windows driver CDs, which the zd1211rw driver + * automatically converts into WLAN devices. */ UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101, "ZyXEL", "G-220F USB-WLAN Install", @@ -1193,6 +1193,14 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_DEVICE ), +/* SanDisk that has a second LUN for a driver ISO, reported by + * Ben Collins */ +UNUSUAL_DEV( 0x0781, 0x5406, 0x0000, 0xffff, + "SanDisk", + "U3 Cruzer Micro driver ISO", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", @@ -1271,6 +1279,15 @@ UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Reported by Edward Chapman (taken from linux-usb mailing list) + Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive */ +UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999, + "Netac", + "USB Flash Disk", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + + /* Patch by Stephan Walter * I don't know why, but it works... */ UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012, -- cgit v1.2.3 From da1f82b5543738d4c127a449490bc0d55e121fe8 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 10 May 2007 23:04:12 -0700 Subject: USB: cxacru: create sysfs attributes in atm_start instead of bind Since usbatm doesn't set the usb_interface driver data until after calling bind and heavy_init, it would be NULL when the sysfs attributes are read. Reading the MAC address from atm_dev before atm_dev exists would have been be possible too. Calling create_device_file in atm_start will avoid this problem, and the data is useless until the first status poll runs. However, it must be ready before a status poll does a printk on line status change otherwise userspace could react before the files exist. For completeness I've moved remove_device_file to atm_stop so it's not called in unbind when it's not needed. There's no point starting ADSL if atm_start could still fail either. Signed-off-by: Simon Arlott Cc: Duncan Sands Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 30b7bfbc985..68cf582fd4f 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -629,10 +629,22 @@ static int cxacru_card_status(struct cxacru_data *instance) return 0; } +static void cxacru_remove_device_files(struct usbatm_data *usbatm_instance, + struct atm_dev *atm_dev) +{ + struct usb_interface *intf = usbatm_instance->usb_intf; + + #define CXACRU_DEVICE_REMOVE_FILE(_name) \ + device_remove_file(&intf->dev, &dev_attr_##_name); + CXACRU_ALL_FILES(REMOVE); + #undef CXACRU_DEVICE_REMOVE_FILE +} + static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev) { struct cxacru_data *instance = usbatm_instance->driver_data; + struct usb_interface *intf = usbatm_instance->usb_intf; /* struct atm_dev *atm_dev = usbatm_instance->atm_dev; */ @@ -649,6 +661,13 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, return ret; } + #define CXACRU_DEVICE_CREATE_FILE(_name) \ + ret = device_create_file(&intf->dev, &dev_attr_##_name); \ + if (unlikely(ret)) \ + goto fail_sysfs; + CXACRU_ALL_FILES(CREATE); + #undef CXACRU_DEVICE_CREATE_FILE + /* start ADSL */ mutex_lock(&instance->adsl_state_serialize); ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); @@ -680,6 +699,11 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, if (start_polling) cxacru_poll_status(&instance->poll_work.work); return 0; + +fail_sysfs: + usb_err(usbatm_instance, "cxacru_atm_start: device_create_file failed (%d)\n", ret); + cxacru_remove_device_files(usbatm_instance, atm_dev); + return ret; } static void cxacru_poll_status(struct work_struct *work) @@ -1065,13 +1089,6 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, goto fail; } - #define CXACRU_DEVICE_CREATE_FILE(_name) \ - ret = device_create_file(&intf->dev, &dev_attr_##_name); \ - if (unlikely(ret)) \ - goto fail_sysfs; - CXACRU_ALL_FILES(CREATE); - #undef CXACRU_DEVICE_CREATE_FILE - usb_fill_int_urb(instance->rcv_urb, usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), instance->rcv_buf, PAGE_SIZE, @@ -1092,14 +1109,6 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, return 0; - fail_sysfs: - dbg("cxacru_bind: device_create_file failed (%d)\n", ret); - - #define CXACRU_DEVICE_REMOVE_FILE(_name) \ - device_remove_file(&intf->dev, &dev_attr_##_name); - CXACRU_ALL_FILES(REMOVE); - #undef CXACRU_DEVICE_REVOVE_FILE - fail: free_page((unsigned long) instance->snd_buf); free_page((unsigned long) instance->rcv_buf); @@ -1146,11 +1155,6 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, free_page((unsigned long) instance->snd_buf); free_page((unsigned long) instance->rcv_buf); - #define CXACRU_DEVICE_REMOVE_FILE(_name) \ - device_remove_file(&intf->dev, &dev_attr_##_name); - CXACRU_ALL_FILES(REMOVE); - #undef CXACRU_DEVICE_REVOVE_FILE - kfree(instance); usbatm_instance->driver_data = NULL; @@ -1231,6 +1235,7 @@ static struct usbatm_driver cxacru_driver = { .heavy_init = cxacru_heavy_init, .unbind = cxacru_unbind, .atm_start = cxacru_atm_start, + .atm_stop = cxacru_remove_device_files, .bulk_in = CXACRU_EP_DATA, .bulk_out = CXACRU_EP_DATA, .rx_padding = 3, -- cgit v1.2.3 From fd209e35b74110ee1f3371838b0782b5b02eaaba Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Thu, 10 May 2007 23:04:13 -0700 Subject: USB: cxacru: ignore error trying to start ADSL in atm_start The sysfs adsl_status attribute ignores (aside from returning -EIO to the user) any error sending a START/STOP command to the device and there is at least one firmware which never sends a response but appears to work regardless. Therefore atm_start should also continue if an error is received so that such firmware is usable. The official Conexant driver doesn't expect a reply either but this is for another device (E2 router) and a commonly used firmware does respond. Also, there is no point in changing -ECONNRESET to -ETIMEDOUT since nothing ever checks for either of these values. Signed-off-by: Simon Arlott Cc: Duncan Sands Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 68cf582fd4f..8bcf7fe1dd8 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -476,8 +476,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done, add_timer(&timer); wait_for_completion(done); status = urb->status; - if (status == -ECONNRESET) - status = -ETIMEDOUT; del_timer_sync(&timer); if (actual_length) @@ -671,11 +669,8 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, /* start ADSL */ mutex_lock(&instance->adsl_state_serialize); ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); - if (ret < 0) { + if (ret < 0) atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret); - mutex_unlock(&instance->adsl_state_serialize); - return ret; - } /* Start status polling */ mutex_lock(&instance->poll_state_serialize); -- cgit v1.2.3 From 615ae11b3b4af7a5adb0819ff11b3b764eb92268 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 8 Jun 2007 15:23:27 -0400 Subject: USB: Fix up bogus bInterval values in endpoint descriptors This patch (as904) adds code to check for endpoint descriptor bInterval values outside the legal limits. Illegal values are set to 32 ms, which seems like a reasonable default. This fixes Bugzilla #8432. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 2d4fd530e5e..dd3482328ad 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -49,7 +50,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; struct usb_host_endpoint *endpoint; - int n, i; + int n, i, j; d = (struct usb_endpoint_descriptor *) buffer; buffer += d->bLength; @@ -84,6 +85,45 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, memcpy(&endpoint->desc, d, n); INIT_LIST_HEAD(&endpoint->urb_list); + /* If the bInterval value is outside the legal range, + * set it to a default value: 32 ms */ + i = 0; /* i = min, j = max, n = default */ + j = 255; + if (usb_endpoint_xfer_int(d)) { + i = 1; + switch (to_usb_device(ddev)->speed) { + case USB_SPEED_HIGH: + n = 9; /* 32 ms = 2^(9-1) uframes */ + j = 16; + break; + default: /* USB_SPEED_FULL or _LOW */ + /* For low-speed, 10 ms is the official minimum. + * But some "overclocked" devices might want faster + * polling so we'll allow it. */ + n = 32; + break; + } + } else if (usb_endpoint_xfer_isoc(d)) { + i = 1; + j = 16; + switch (to_usb_device(ddev)->speed) { + case USB_SPEED_HIGH: + n = 9; /* 32 ms = 2^(9-1) uframes */ + break; + default: /* USB_SPEED_FULL */ + n = 6; /* 32 ms = 2^(6-1) frames */ + break; + } + } + if (d->bInterval < i || d->bInterval > j) { + dev_warn(ddev, "config %d interface %d altsetting %d " + "endpoint 0x%X has an invalid bInterval %d, " + "changing to %d\n", + cfgno, inum, asnum, + d->bEndpointAddress, d->bInterval, n); + endpoint->desc.bInterval = n; + } + /* Skip over any Class Specific or Vendor Specific descriptors; * find the next endpoint or interface descriptor */ endpoint->extra = buffer; -- cgit v1.2.3 From 6fd75b19483b2f6e6619602a535b4939e46921c1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 4 May 2007 11:57:00 -0400 Subject: OHCI: Fix machine check in ohci_hub_status_data This patch (as901) fixes an oversight in ohci-hcd. The hub_status_data routine must not try to access the controller's memory-mapped registers if the controller is in a low-power state; such attempts will cause a crash on some architectures (such as PPC). Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 216c9c9d4d6..bb9cc595219 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -417,6 +417,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) + goto done; /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) -- cgit v1.2.3