diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:40:57 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:40:57 -0700 |
commit | 37b05b17985ecc43a33e2a8cbdaa220115de4703 (patch) | |
tree | 8213bf790182711677018ed322a9ccf61470242e /drivers/usb/core | |
parent | ce1d5b23a8d1e19866ab82bdec0dc41fde5273d8 (diff) | |
parent | 4953d141dc5db748475001cfbfdcc42e66cf900e (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (120 commits)
usb: don't update devnum for wusb devices
wusb: make ep0_reinit available for modules
wusb: devices dont use a set address
wusb: teach choose_address() about wireless devices
wusb: add link wusb-usb device
wusb: add authenticathed bit to usb_dev
USB: remove unnecessary type casting of urb->context
usb serial: more fixes and groundwork for tty changes
USB: replace remaining __FUNCTION__ occurrences
USB: usbfs: export the URB_NO_INTERRUPT flag to userspace
USB: fix compile problems in ehci-hcd
USB: ehci: qh_completions cleanup and bugfix
USB: cdc-acm: signedness fix
USB: add documentation about callbacks
USB: don't explicitly reenable root-hub status interrupts
USB: OHCI: turn off RD when remote wakeup is disabled
USB: HCDs use the do_remote_wakeup flag
USB: g_file_storage: ignore bulk-out data after invalid CBW
USB: serial: remove endpoints setting checks from core and header
USB: serial: remove unneeded number endpoints settings
...
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/Kconfig | 42 | ||||
-rw-r--r-- | drivers/usb/core/config.c | 17 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 73 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 52 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 25 | ||||
-rw-r--r-- | drivers/usb/core/hcd.h | 9 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 396 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 9 | ||||
-rw-r--r-- | drivers/usb/core/inode.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 17 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 14 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 22 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 26 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 2 |
15 files changed, 443 insertions, 280 deletions
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index a2b0aa48b8e..cc9f397e839 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -76,8 +76,8 @@ config USB_DEVICE_CLASS NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" config USB_DYNAMIC_MINORS - bool "Dynamic USB minor allocation (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL + bool "Dynamic USB minor allocation" + depends on USB help If you say Y here, the USB subsystem will use dynamic minor allocation for any device that uses the USB major number. @@ -102,31 +102,6 @@ config USB_SUSPEND If you are unsure about this, say N here. -config USB_PERSIST - bool "USB device persistence during system suspend (DANGEROUS)" - depends on USB && PM && EXPERIMENTAL - default n - help - - If you say Y here and enable the "power/persist" attribute - for a USB device, the device's data structures will remain - persistent across system suspend, even if the USB bus loses - power. (This includes hibernation, also known as swsusp or - suspend-to-disk.) The devices will reappear as if by magic - when the system wakes up, with no need to unmount USB - filesystems, rmmod host-controller drivers, or do anything - else. - - WARNING: This option can be dangerous! - - If a USB device is replaced by another of the same type while - the system is asleep, there's a good chance the kernel won't - detect the change. Likewise if the media in a USB storage - device is replaced. When this happens it's almost certain to - cause data corruption and maybe even crash your system. - - If you are unsure, say N here. - config USB_OTG bool depends on USB && EXPERIMENTAL @@ -136,14 +111,16 @@ config USB_OTG config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" - depends on USB_OTG - default y + depends on USB_OTG || EMBEDDED + default y if USB_OTG + default n if EMBEDDED help If you say Y here, the "otg_whitelist.h" file will be used as a product whitelist, so USB peripherals not listed there will be rejected during enumeration. This behavior is required by the USB OTG specification for all devices not on your product's - "Targeted Peripherals List". + "Targeted Peripherals List". "Embedded Hosts" are likewise + allowed to support only a limited number of peripherals. Otherwise, peripherals not listed there will only generate a warning and enumeration will continue. That's more like what @@ -152,9 +129,10 @@ config USB_OTG_WHITELIST config USB_OTG_BLACKLIST_HUB bool "Disable external hubs" - depends on USB_OTG + depends on USB_OTG || EMBEDDED help If you say Y here, then Linux will refuse to enumerate external hubs. OTG hosts are allowed to reduce hardware - and software costs by not supporting external hubs. + and software costs by not supporting external hubs. So + are "Emedded Hosts" that don't offer OTG support. diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index a92122a216b..568244c99bd 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -145,6 +145,23 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, endpoint->desc.wMaxPacketSize = cpu_to_le16(8); } + /* + * Some buggy high speed devices have bulk endpoints using + * maxpacket sizes other than 512. High speed HCDs may not + * be able to handle that particular bug, so let's warn... + */ + if (to_usb_device(ddev)->speed == USB_SPEED_HIGH + && usb_endpoint_xfer_bulk(d)) { + unsigned maxp; + + maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff; + if (maxp != 512) + dev_warn(ddev, "config %d interface %d altsetting %d " + "bulk endpoint 0x%X has invalid maxpacket %d\n", + cfgno, inum, asnum, d->bEndpointAddress, + maxp); + } + /* Skip over any Class Specific or Vendor Specific descriptors; * find the next endpoint or interface descriptor */ endpoint->extra = buffer; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ae94176c64e..de17738f3ac 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -647,6 +647,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) struct usbdevfs_ctrltransfer ctrl; unsigned int tmo; unsigned char *tbuf; + unsigned wLength; int i, j, ret; if (copy_from_user(&ctrl, arg, sizeof(ctrl))) @@ -654,7 +655,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); if (ret) return ret; - if (ctrl.wLength > PAGE_SIZE) + wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ + if (wLength > PAGE_SIZE) return -EINVAL; tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); if (!tbuf) @@ -946,8 +948,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, int ret, ifnum = -1; int is_in; - if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| - URB_NO_FSBR|URB_ZERO_PACKET)) + if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | + USBDEVFS_URB_SHORT_NOT_OK | + USBDEVFS_URB_NO_FSBR | + USBDEVFS_URB_ZERO_PACKET | + USBDEVFS_URB_NO_INTERRUPT)) return -EINVAL; if (!uurb->buffer) return -EINVAL; @@ -1102,8 +1107,24 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN); - as->urb->transfer_flags = uurb->flags | - (is_in ? URB_DIR_IN : URB_DIR_OUT); + + /* This tedious sequence is necessary because the URB_* flags + * are internal to the kernel and subject to change, whereas + * the USBDEVFS_URB_* flags are a user API and must not be changed. + */ + u = (is_in ? URB_DIR_IN : URB_DIR_OUT); + if (uurb->flags & USBDEVFS_URB_ISO_ASAP) + u |= URB_ISO_ASAP; + if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + u |= URB_SHORT_NOT_OK; + if (uurb->flags & USBDEVFS_URB_NO_FSBR) + u |= URB_NO_FSBR; + if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) + u |= URB_ZERO_PACKET; + if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) + u |= URB_NO_INTERRUPT; + as->urb->transfer_flags = u; + as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; as->urb->start_frame = uurb->start_frame; @@ -1509,60 +1530,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, switch (cmd) { case USBDEVFS_CONTROL: - snoop(&dev->dev, "%s: CONTROL\n", __FUNCTION__); + snoop(&dev->dev, "%s: CONTROL\n", __func__); ret = proc_control(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_BULK: - snoop(&dev->dev, "%s: BULK\n", __FUNCTION__); + snoop(&dev->dev, "%s: BULK\n", __func__); ret = proc_bulk(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESETEP: - snoop(&dev->dev, "%s: RESETEP\n", __FUNCTION__); + snoop(&dev->dev, "%s: RESETEP\n", __func__); ret = proc_resetep(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_RESET: - snoop(&dev->dev, "%s: RESET\n", __FUNCTION__); + snoop(&dev->dev, "%s: RESET\n", __func__); ret = proc_resetdevice(ps); break; case USBDEVFS_CLEAR_HALT: - snoop(&dev->dev, "%s: CLEAR_HALT\n", __FUNCTION__); + snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__); ret = proc_clearhalt(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_GETDRIVER: - snoop(&dev->dev, "%s: GETDRIVER\n", __FUNCTION__); + snoop(&dev->dev, "%s: GETDRIVER\n", __func__); ret = proc_getdriver(ps, p); break; case USBDEVFS_CONNECTINFO: - snoop(&dev->dev, "%s: CONNECTINFO\n", __FUNCTION__); + snoop(&dev->dev, "%s: CONNECTINFO\n", __func__); ret = proc_connectinfo(ps, p); break; case USBDEVFS_SETINTERFACE: - snoop(&dev->dev, "%s: SETINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: SETINTERFACE\n", __func__); ret = proc_setintf(ps, p); break; case USBDEVFS_SETCONFIGURATION: - snoop(&dev->dev, "%s: SETCONFIGURATION\n", __FUNCTION__); + snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__); ret = proc_setconfig(ps, p); break; case USBDEVFS_SUBMITURB: - snoop(&dev->dev, "%s: SUBMITURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: SUBMITURB\n", __func__); ret = proc_submiturb(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; @@ -1571,60 +1592,60 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, #ifdef CONFIG_COMPAT case USBDEVFS_SUBMITURB32: - snoop(&dev->dev, "%s: SUBMITURB32\n", __FUNCTION__); + snoop(&dev->dev, "%s: SUBMITURB32\n", __func__); ret = proc_submiturb_compat(ps, p); if (ret >= 0) inode->i_mtime = CURRENT_TIME; break; case USBDEVFS_REAPURB32: - snoop(&dev->dev, "%s: REAPURB32\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURB32\n", __func__); ret = proc_reapurb_compat(ps, p); break; case USBDEVFS_REAPURBNDELAY32: - snoop(&dev->dev, "%s: REAPURBDELAY32\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__); ret = proc_reapurbnonblock_compat(ps, p); break; case USBDEVFS_IOCTL32: - snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + snoop(&dev->dev, "%s: IOCTL\n", __func__); ret = proc_ioctl_compat(ps, ptr_to_compat(p)); break; #endif case USBDEVFS_DISCARDURB: - snoop(&dev->dev, "%s: DISCARDURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: DISCARDURB\n", __func__); ret = proc_unlinkurb(ps, p); break; case USBDEVFS_REAPURB: - snoop(&dev->dev, "%s: REAPURB\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURB\n", __func__); ret = proc_reapurb(ps, p); break; case USBDEVFS_REAPURBNDELAY: - snoop(&dev->dev, "%s: REAPURBDELAY\n", __FUNCTION__); + snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__); ret = proc_reapurbnonblock(ps, p); break; case USBDEVFS_DISCSIGNAL: - snoop(&dev->dev, "%s: DISCSIGNAL\n", __FUNCTION__); + snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__); ret = proc_disconnectsignal(ps, p); break; case USBDEVFS_CLAIMINTERFACE: - snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__); ret = proc_claiminterface(ps, p); break; case USBDEVFS_RELEASEINTERFACE: - snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __FUNCTION__); + snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__); ret = proc_releaseinterface(ps, p); break; case USBDEVFS_IOCTL: - snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__); + snoop(&dev->dev, "%s: IOCTL\n", __func__); ret = proc_ioctl_default(ps, p); break; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 801b6f142fa..1e56f1cfa6d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -157,7 +157,7 @@ static int usb_probe_device(struct device *dev) struct usb_device *udev; int error = -ENODEV; - dev_dbg(dev, "%s\n", __FUNCTION__); + dev_dbg(dev, "%s\n", __func__); if (!is_usb_device(dev)) /* Sanity check */ return error; @@ -194,7 +194,7 @@ static int usb_probe_interface(struct device *dev) const struct usb_device_id *id; int error = -ENODEV; - dev_dbg(dev, "%s\n", __FUNCTION__); + dev_dbg(dev, "%s\n", __func__); if (is_usb_device(dev)) /* Sanity check */ return error; @@ -211,7 +211,7 @@ static int usb_probe_interface(struct device *dev) if (!id) id = usb_match_dynamic_id(intf, driver); if (id) { - dev_dbg(dev, "%s - got id\n", __FUNCTION__); + dev_dbg(dev, "%s - got id\n", __func__); error = usb_autoresume_device(udev); if (error) @@ -793,9 +793,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) status = udriver->suspend(udev, msg); done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - if (status == 0) - udev->dev.power.power_state.event = msg.event; + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); return status; } @@ -823,11 +821,9 @@ static int usb_resume_device(struct usb_device *udev) status = udriver->resume(udev); done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - if (status == 0) { + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + if (status == 0) udev->autoresume_disabled = 0; - udev->dev.power.power_state.event = PM_EVENT_ON; - } return status; } @@ -864,7 +860,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) } done: - dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); return status; } @@ -914,7 +910,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume) } done: - dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); if (status == 0) mark_active(intf); @@ -936,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule) * is disabled. Also fail if any interfaces require remote wakeup * but it isn't available. */ - udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->pm_usage_cnt > 0) return -EBUSY; if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) @@ -1098,7 +1093,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); return status; } @@ -1180,8 +1175,7 @@ static int usb_resume_both(struct usb_device *udev) } } else { - /* Needed for setting udev->dev.power.power_state.event, - * for possible debugging message, and for reset_resume. */ + /* Needed for reset-resume */ status = usb_resume_device(udev); } @@ -1193,8 +1187,9 @@ static int usb_resume_both(struct usb_device *udev) } done: - dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); - udev->reset_resume = 0; + dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + if (!status) + udev->reset_resume = 0; return status; } @@ -1262,7 +1257,7 @@ void usb_autosuspend_device(struct usb_device *udev) status = usb_autopm_do_device(udev, -1); dev_vdbg(&udev->dev, "%s: cnt %d\n", - __FUNCTION__, udev->pm_usage_cnt); + __func__, udev->pm_usage_cnt); } /** @@ -1282,7 +1277,7 @@ void usb_try_autosuspend_device(struct usb_device *udev) { usb_autopm_do_device(udev, 0); dev_vdbg(&udev->dev, "%s: cnt %d\n", - __FUNCTION__, udev->pm_usage_cnt); + __func__, udev->pm_usage_cnt); } /** @@ -1310,7 +1305,7 @@ int usb_autoresume_device(struct usb_device *udev) status = usb_autopm_do_device(udev, 1); dev_vdbg(&udev->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, udev->pm_usage_cnt); + __func__, status, udev->pm_usage_cnt); return status; } @@ -1382,7 +1377,7 @@ void usb_autopm_put_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, -1); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); } EXPORT_SYMBOL_GPL(usb_autopm_put_interface); @@ -1426,7 +1421,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, 1); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); return status; } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); @@ -1448,7 +1443,7 @@ int usb_autopm_set_interface(struct usb_interface *intf) status = usb_autopm_do_interface(intf, 0); dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", - __FUNCTION__, status, intf->pm_usage_cnt); + __func__, status, intf->pm_usage_cnt); return status; } EXPORT_SYMBOL_GPL(usb_autopm_set_interface); @@ -1523,9 +1518,14 @@ static int usb_suspend(struct device *dev, pm_message_t message) udev = to_usb_device(dev); /* If udev is already suspended, we can skip this suspend and - * we should also skip the upcoming system resume. */ + * we should also skip the upcoming system resume. High-speed + * root hubs are an exception; they need to resume whenever the + * system wakes up in order for USB-PERSIST port handover to work + * properly. + */ if (udev->state == USB_STATE_SUSPENDED) { - udev->skip_sys_resume = 1; + if (udev->parent || udev->speed != USB_SPEED_HIGH) + udev->skip_sys_resume = 1; return 0; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 84760ddbc33..5b87ae7f0a6 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -73,7 +73,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (pci_enable_device(dev) < 0) return -ENODEV; dev->current_state = PCI_D0; - dev->dev.power.power_state = PMSG_ON; if (!dev->irq) { dev_err(&dev->dev, @@ -216,9 +215,9 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) hcd->state == HC_STATE_HALT)) return -EBUSY; - if (hcd->driver->suspend) { - retval = hcd->driver->suspend(hcd, message); - suspend_report_result(hcd->driver->suspend, retval); + if (hcd->driver->pci_suspend) { + retval = hcd->driver->pci_suspend(hcd, message); + suspend_report_result(hcd->driver->pci_suspend, retval); if (retval) goto done; } @@ -302,8 +301,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) done: if (retval == 0) { - dev->dev.power.power_state = PMSG_SUSPEND; - #ifdef CONFIG_PPC_PMAC /* Disable ASIC clocks for USB */ if (machine_is(powermac)) { @@ -406,12 +403,10 @@ int usb_hcd_pci_resume(struct pci_dev *dev) pci_set_master(dev); pci_restore_state(dev); - dev->dev.power.power_state = PMSG_ON; - clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); - if (hcd->driver->resume) { - retval = hcd->driver->resume(hcd); + if (hcd->driver->pci_resume) { + retval = hcd->driver->pci_resume(hcd); if (retval) { dev_err(hcd->self.controller, "PCI post-resume error %d!\n", retval); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e52ed1663b3..bf10e9c4195 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -129,7 +129,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ - 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ + 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ @@ -291,7 +291,6 @@ static int ascii2utf (char *s, u8 *utf, int utfmax) * rh_string - provides manufacturer, product and serial strings for root hub * @id: the string ID number (1: serial number, 2: product, 3: vendor) * @hcd: the host controller for this root hub - * @type: string describing our driver * @data: return packet in UTF-16 LE * @len: length of the return packet * @@ -355,9 +354,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) __attribute__((aligned(4))); const u8 *bufp = tbuf; int len = 0; - int patch_wakeup = 0; int status; int n; + u8 patch_wakeup = 0; + u8 patch_protocol = 0; might_sleep(); @@ -434,6 +434,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) else goto error; len = 18; + if (hcd->has_tt) + patch_protocol = 1; break; case USB_DT_CONFIG << 8: if (hcd->driver->flags & HCD_USB2) { @@ -528,6 +530,13 @@ error: bmAttributes)) ((struct usb_config_descriptor *)ubuf)->bmAttributes |= USB_CONFIG_ATT_WAKEUP; + + /* report whether RH hardware has an integrated TT */ + if (patch_protocol && + len > offsetof(struct usb_device_descriptor, + bDeviceProtocol)) + ((struct usb_device_descriptor *) ubuf)-> + bDeviceProtocol = 1; } /* any errors get returned through the urb completion */ @@ -915,15 +924,6 @@ static int register_root_hub(struct usb_hcd *hcd) return retval; } -void usb_enable_root_hub_irq (struct usb_bus *bus) -{ - struct usb_hcd *hcd; - - hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) - hcd->driver->hub_irq_enable (hcd); -} - /*-------------------------------------------------------------------------*/ @@ -1677,7 +1677,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); * usb_hcd_irq - hook IRQs to HCD framework (bus glue) * @irq: the IRQ being raised * @__hcd: pointer to the HCD whose IRQ is being signaled - * @r: saved hardware registers * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 2d1c3d5e47b..1e4b81e9eb5 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -28,7 +28,7 @@ /* * USB Packet IDs (PIDs) */ -#define USB_PID_UNDEF_0 0xf0 +#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */ #define USB_PID_OUT 0xe1 #define USB_PID_ACK 0xd2 #define USB_PID_DATA0 0xc3 @@ -99,6 +99,7 @@ struct usb_hcd { unsigned poll_pending:1; /* status has changed? */ unsigned wireless:1; /* Wireless USB HCD */ unsigned authorized_default:1; + unsigned has_tt:1; /* Integrated TT in root hub */ int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ @@ -177,10 +178,10 @@ struct hc_driver { * a whole, not just the root hub; they're for PCI bus glue. */ /* called after suspending the hub, before entering D3 etc */ - int (*suspend) (struct usb_hcd *hcd, pm_message_t message); + int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message); /* called after entering D0 (etc), before resuming the hub */ - int (*resume) (struct usb_hcd *hcd); + int (*pci_resume) (struct usb_hcd *hcd); /* cleanly make HCD stop writing memory and doing I/O */ void (*stop) (struct usb_hcd *hcd); @@ -209,8 +210,6 @@ struct hc_driver { int (*bus_suspend)(struct usb_hcd *); int (*bus_resume)(struct usb_hcd *); int (*start_port_reset)(struct usb_hcd *, unsigned port_num); - void (*hub_irq_enable)(struct usb_hcd *); - /* Needed only if port-change IRQs are level-triggered */ /* force handover of high-speed port to full-speed companion */ void (*relinquish_port)(struct usb_hcd *, int); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 57aeca160f3..eb57fcc701d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -30,12 +30,6 @@ #include "hcd.h" #include "hub.h" -#ifdef CONFIG_USB_PERSIST -#define USB_PERSIST 1 -#else -#define USB_PERSIST 0 -#endif - /* if we are in debug mode, always announce new devices */ #ifdef DEBUG #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES @@ -333,6 +327,27 @@ static int get_port_status(struct usb_device *hdev, int port1, return status; } +static int hub_port_status(struct usb_hub *hub, int port1, + u16 *status, u16 *change) +{ + int ret; + + mutex_lock(&hub->status_mutex); + ret = get_port_status(hub->hdev, port1, &hub->status->port); + if (ret < 4) { + dev_err(hub->intfdev, + "%s failed (err = %d)\n", __func__, ret); + if (ret >= 0) + ret = -EIO; + } else { + *status = le16_to_cpu(hub->status->port.wPortStatus); + *change = le16_to_cpu(hub->status->port.wPortChange); + ret = 0; + } + mutex_unlock(&hub->status_mutex); + return ret; +} + static void kick_khubd(struct usb_hub *hub) { unsigned long flags; @@ -560,7 +575,7 @@ static int hub_hub_status(struct usb_hub *hub, ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (hub->intfdev, - "%s failed (err = %d)\n", __FUNCTION__, ret); + "%s failed (err = %d)\n", __func__, ret); else { *status = le16_to_cpu(hub->status->hub.wHubStatus); *change = le16_to_cpu(hub->status->hub.wHubChange); @@ -610,9 +625,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) } /* caller has locked the hub device */ -static int hub_pre_reset(struct usb_interface *intf) +static void hub_stop(struct usb_hub *hub) { - struct usb_hub *hub = usb_get_intfdata(intf); struct usb_device *hdev = hub->hdev; int i; @@ -622,6 +636,89 @@ static int hub_pre_reset(struct usb_interface *intf) usb_disconnect(&hdev->children[i]); } hub_quiesce(hub); +} + +#define HUB_RESET 1 +#define HUB_RESUME 2 +#define HUB_RESET_RESUME 3 + +#ifdef CONFIG_PM + +static void hub_restart(struct usb_hub *hub, int type) +{ + struct usb_device *hdev = hub->hdev; + int port1; + + /* Check each of the children to see if they require + * USB-PERSIST handling or disconnection. Also check + * each unoccupied port to make sure it is still disabled. + */ + for (port1 = 1; port1 <= hdev->maxchild; ++port1) { + struct usb_device *udev = hdev->children[port1-1]; + int status = 0; + u16 portstatus, portchange; + + if (!udev || udev->state == USB_STATE_NOTATTACHED) { + if (type != HUB_RESET) { + status = hub_port_status(hub, port1, + &portstatus, &portchange); + if (status == 0 && (portstatus & + USB_PORT_STAT_ENABLE)) + clear_port_feature(hdev, port1, + USB_PORT_FEAT_ENABLE); + } + continue; + } + + /* Was the power session lost while we were suspended? */ + switch (type) { + case HUB_RESET_RESUME: + portstatus = 0; + portchange = USB_PORT_STAT_C_CONNECTION; + break; + + case HUB_RESET: + case HUB_RESUME: + status = hub_port_status(hub, port1, + &portstatus, &portchange); + break; + } + + /* For "USB_PERSIST"-enabled children we must + * mark the child device for reset-resume and + * turn off the various status changes to prevent + * khubd from disconnecting it later. + */ + if (udev->persist_enabled && status == 0 && + !(portstatus & USB_PORT_STAT_ENABLE)) { + if (portchange & USB_PORT_STAT_C_ENABLE) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_ENABLE); + if (portchange & USB_PORT_STAT_C_CONNECTION) + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_CONNECTION); + udev->reset_resume = 1; + } + + /* Otherwise for a reset_resume we must disconnect the child, + * but as we may not lock the child device here + * we have to do a "logical" disconnect. + */ + else if (type == HUB_RESET_RESUME) + hub_port_logical_disconnect(hub, port1); + } + + hub_activate(hub); +} + +#endif /* CONFIG_PM */ + +/* caller has locked the hub device */ +static int hub_pre_reset(struct usb_interface *intf) +{ + struct usb_hub *hub = usb_get_intfdata(intf); + + hub_stop(hub); return 0; } @@ -910,7 +1007,7 @@ static void hub_disconnect(struct usb_interface *intf) /* Disconnect all children and quiesce the hub */ hub->error = 0; - hub_pre_reset(intf); + hub_stop(hub); usb_set_intfdata (intf, NULL); @@ -1098,21 +1195,42 @@ void usb_set_device_state(struct usb_device *udev, spin_unlock_irqrestore(&device_state_lock, flags); } +/* + * WUSB devices are simple: they have no hubs behind, so the mapping + * device <-> virtual port number becomes 1:1. Why? to simplify the + * life of the device connection logic in + * drivers/usb/wusbcore/devconnect.c. When we do the initial secret + * handshake we need to assign a temporary address in the unauthorized + * space. For simplicity we use the first virtual port number found to + * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()] + * and that becomes it's address [X < 128] or its unauthorized address + * [X | 0x80]. + * + * We add 1 as an offset to the one-based USB-stack port number + * (zero-based wusb virtual port index) for two reasons: (a) dev addr + * 0 is reserved by USB for default address; (b) Linux's USB stack + * uses always #1 for the root hub of the controller. So USB stack's + * port #1, which is wusb virtual-port #0 has address #2. + */ static void choose_address(struct usb_device *udev) { int devnum; struct usb_bus *bus = udev->bus; /* If khubd ever becomes multithreaded, this will need a lock */ - - /* Try to allocate the next devnum beginning at bus->devnum_next. */ - devnum = find_next_zero_bit(bus->devmap.devicemap, 128, - bus->devnum_next); - if (devnum >= 128) - devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1); - - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); - + if (udev->wusb) { + devnum = udev->portnum + 1; + BUG_ON(test_bit(devnum, bus->devmap.devicemap)); + } else { + /* Try to allocate the next devnum beginning at + * bus->devnum_next. */ + devnum = find_next_zero_bit(bus->devmap.devicemap, 128, + bus->devnum_next); + if (devnum >= 128) + devnum = find_next_zero_bit(bus->devmap.devicemap, + 128, 1); + bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); + } if (devnum < 128) { set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; @@ -1127,6 +1245,13 @@ static void release_address(struct usb_device *udev) } } +static void update_address(struct usb_device *udev, int devnum) +{ + /* The address for a WUSB device is managed by wusbcore. */ + if (!udev->wusb) + udev->devnum = devnum; +} + #ifdef CONFIG_USB_SUSPEND static void usb_stop_pm(struct usb_device *udev) @@ -1173,7 +1298,7 @@ void usb_disconnect(struct usb_device **pdev) int i; |