diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/devio.c | 18 | ||||
-rw-r--r-- | drivers/usb/core/hcd-pci.c | 24 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 15 | ||||
-rw-r--r-- | drivers/usb/core/hub.h | 4 | ||||
-rw-r--r-- | drivers/usb/core/port.c | 32 |
5 files changed, 70 insertions, 23 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fcf68818e999..1a16a8bdea60 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -746,6 +746,7 @@ static int driver_resume(struct usb_interface *intf) return 0; } +#ifdef CONFIG_PM /* The following routines apply to the entire device, not interfaces */ void usbfs_notify_suspend(struct usb_device *udev) { @@ -764,6 +765,7 @@ void usbfs_notify_resume(struct usb_device *udev) } mutex_unlock(&usbfs_mutex); } +#endif struct usb_driver usbfs_driver = { .name = "usbfs", @@ -2640,21 +2642,21 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, snoop(&dev->dev, "%s: CONTROL\n", __func__); ret = proc_control(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_BULK: snoop(&dev->dev, "%s: BULK\n", __func__); ret = proc_bulk(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_RESETEP: snoop(&dev->dev, "%s: RESETEP\n", __func__); ret = proc_resetep(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_RESET: @@ -2666,7 +2668,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__); ret = proc_clearhalt(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_GETDRIVER: @@ -2693,7 +2695,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, snoop(&dev->dev, "%s: SUBMITURB\n", __func__); ret = proc_submiturb(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; #ifdef CONFIG_COMPAT @@ -2701,14 +2703,14 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, snoop(&dev->dev, "%s: CONTROL32\n", __func__); ret = proc_control_compat(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_BULK32: snoop(&dev->dev, "%s: BULK32\n", __func__); ret = proc_bulk_compat(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_DISCSIGNAL32: @@ -2720,7 +2722,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd, snoop(&dev->dev, "%s: SUBMITURB32\n", __func__); ret = proc_submiturb_compat(ps, p); if (ret >= 0) - inode->i_mtime = current_time(inode); + inode->i_mtime = inode->i_ctime = current_time(inode); break; case USBDEVFS_IOCTL32: diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ab2f3737764e..990280688b25 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -415,12 +415,15 @@ static int check_root_hub_suspended(struct device *dev) return 0; } -static int suspend_common(struct device *dev, bool do_wakeup) +static int suspend_common(struct device *dev, pm_message_t msg) { struct pci_dev *pci_dev = to_pci_dev(dev); struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + bool do_wakeup; int retval; + do_wakeup = PMSG_IS_AUTO(msg) ? true : device_may_wakeup(dev); + /* Root hub suspend should have stopped all downstream traffic, * and all bus master traffic. And done so for both the interface * and the stub usb_device (which we check here). But maybe it @@ -447,7 +450,7 @@ static int suspend_common(struct device *dev, bool do_wakeup) (retval == 0 && do_wakeup && hcd->shared_hcd && HCD_WAKEUP_PENDING(hcd->shared_hcd))) { if (hcd->driver->pci_resume) - hcd->driver->pci_resume(hcd, false); + hcd->driver->pci_resume(hcd, msg); retval = -EBUSY; } if (retval) @@ -470,7 +473,7 @@ static int suspend_common(struct device *dev, bool do_wakeup) return retval; } -static int resume_common(struct device *dev, int event) +static int resume_common(struct device *dev, pm_message_t msg) { struct pci_dev *pci_dev = to_pci_dev(dev); struct usb_hcd *hcd = pci_get_drvdata(pci_dev); @@ -498,12 +501,11 @@ static int resume_common(struct device *dev, int event) * No locking is needed because PCI controller drivers do not * get unbound during system resume. */ - if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) + if (pci_dev->class == CL_EHCI && msg.event != PM_EVENT_AUTO_RESUME) for_each_companion(pci_dev, hcd, ehci_wait_for_companions); - retval = hcd->driver->pci_resume(hcd, - event == PM_EVENT_RESTORE); + retval = hcd->driver->pci_resume(hcd, msg); if (retval) { dev_err(dev, "PCI post-resume error %d!\n", retval); usb_hc_died(hcd); @@ -516,7 +518,7 @@ static int resume_common(struct device *dev, int event) static int hcd_pci_suspend(struct device *dev) { - return suspend_common(dev, device_may_wakeup(dev)); + return suspend_common(dev, PMSG_SUSPEND); } static int hcd_pci_suspend_noirq(struct device *dev) @@ -577,12 +579,12 @@ static int hcd_pci_resume_noirq(struct device *dev) static int hcd_pci_resume(struct device *dev) { - return resume_common(dev, PM_EVENT_RESUME); + return resume_common(dev, PMSG_RESUME); } static int hcd_pci_restore(struct device *dev) { - return resume_common(dev, PM_EVENT_RESTORE); + return resume_common(dev, PMSG_RESTORE); } #else @@ -600,7 +602,7 @@ static int hcd_pci_runtime_suspend(struct device *dev) { int retval; - retval = suspend_common(dev, true); + retval = suspend_common(dev, PMSG_AUTO_SUSPEND); if (retval == 0) powermac_set_asic(to_pci_dev(dev), 0); dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval); @@ -612,7 +614,7 @@ static int hcd_pci_runtime_resume(struct device *dev) int retval; powermac_set_asic(to_pci_dev(dev), 1); - retval = resume_common(dev, PM_EVENT_AUTO_RESUME); + retval = resume_common(dev, PMSG_AUTO_RESUME); dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval); return retval; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 97a0f8faea6e..a739403a9e45 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2018,6 +2018,19 @@ bool usb_device_is_owned(struct usb_device *udev) return !!hub->ports[udev->portnum - 1]->port_owner; } +static void update_port_device_state(struct usb_device *udev) +{ + struct usb_hub *hub; + struct usb_port *port_dev; + + if (udev->parent) { + hub = usb_hub_to_struct_hub(udev->parent); + port_dev = hub->ports[udev->portnum - 1]; + WRITE_ONCE(port_dev->state, udev->state); + sysfs_notify_dirent(port_dev->state_kn); + } +} + static void recursively_mark_NOTATTACHED(struct usb_device *udev) { struct usb_hub *hub = usb_hub_to_struct_hub(udev); @@ -2030,6 +2043,7 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->state == USB_STATE_SUSPENDED) udev->active_duration -= jiffies; udev->state = USB_STATE_NOTATTACHED; + update_port_device_state(udev); } /** @@ -2086,6 +2100,7 @@ void usb_set_device_state(struct usb_device *udev, udev->state != USB_STATE_SUSPENDED) udev->active_duration += jiffies; udev->state = new_state; + update_port_device_state(udev); } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index e23833562e4f..37897afd1b64 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -84,6 +84,8 @@ struct usb_hub { * @peer: related usb2 and usb3 ports (share the same connector) * @req: default pm qos request for hubs without port power control * @connect_type: port's connect type + * @state: device state of the usb device attached to the port + * @state_kn: kernfs_node of the sysfs attribute that accesses @state * @location: opaque representation of platform connector location * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} * @portnum: port index num based one @@ -100,6 +102,8 @@ struct usb_port { struct usb_port *peer; struct dev_pm_qos_request *req; enum usb_port_connect_type connect_type; + enum usb_device_state state; + struct kernfs_node *state_kn; usb_port_location_t location; struct mutex status_lock; u32 over_current_count; diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 06a8f1f84f6f..77be0dc28da9 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -160,6 +160,16 @@ static ssize_t connect_type_show(struct device *dev, } static DEVICE_ATTR_RO(connect_type); +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *port_dev = to_usb_port(dev); + enum usb_device_state state = READ_ONCE(port_dev->state); + + return sysfs_emit(buf, "%s\n", usb_state_string(state)); +} +static DEVICE_ATTR_RO(state); + static ssize_t over_current_count_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -259,6 +269,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit); static struct attribute *port_dev_attrs[] = { &dev_attr_connect_type.attr, + &dev_attr_state.attr, &dev_attr_location.attr, &dev_attr_quirks.attr, &dev_attr_over_current_count.attr, @@ -705,19 +716,24 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) return retval; } + port_dev->state_kn = sysfs_get_dirent(port_dev->dev.kobj.sd, "state"); + if (!port_dev->state_kn) { + dev_err(&port_dev->dev, "failed to sysfs_get_dirent 'state'\n"); + retval = -ENODEV; + goto err_unregister; + } + /* Set default policy of port-poweroff disabled. */ retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req, DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF); if (retval < 0) { - device_unregister(&port_dev->dev); - return retval; + goto err_put_kn; } retval = component_add(&port_dev->dev, &connector_ops); if (retval) { dev_warn(&port_dev->dev, "failed to add component\n"); - device_unregister(&port_dev->dev); - return retval; + goto err_put_kn; } find_and_link_peer(hub, port1); @@ -754,6 +770,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) port_dev->req = NULL; } return 0; + +err_put_kn: + sysfs_put(port_dev->state_kn); +err_unregister: + device_unregister(&port_dev->dev); + + return retval; } void usb_hub_remove_port_device(struct usb_hub *hub, int port1) @@ -765,5 +788,6 @@ void usb_hub_remove_port_device(struct usb_hub *hub, int port1) if (peer) unlink_peers(port_dev, peer); component_del(&port_dev->dev, &connector_ops); + sysfs_put(port_dev->state_kn); device_unregister(&port_dev->dev); } |