]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/core/driver.c
Driver core: change add_uevent_var to use a struct
[linux-2.6-omap-h63xx.git] / drivers / usb / core / driver.c
index 02d6db61c940a03623f46add7b10ad4c1a406d93..6273a5197e6abbac86db575f531dd447463f87da 100644 (file)
@@ -29,6 +29,7 @@
 #include "hcd.h"
 #include "usb.h"
 
+
 #ifdef CONFIG_HOTPLUG
 
 /*
@@ -59,7 +60,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
        spin_lock(&dynids->lock);
-       list_add_tail(&dynids->list, &dynid->node);
+       list_add_tail(&dynid->node, &dynids->list);
        spin_unlock(&dynids->lock);
 
        if (get_driver(driver)) {
@@ -575,12 +576,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct usb_device *usb_dev;
-       int i = 0;
-       int length = 0;
 
        if (!dev)
                return -ENODEV;
@@ -609,51 +607,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
         * all the device descriptors we don't tell them about.  Or
         * act as usermode drivers.
         */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVICE=/proc/bus/usb/%03d/%03d",
+       if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
                           usb_dev->bus->busnum, usb_dev->devnum))
                return -ENOMEM;
 #endif
 
        /* per-device configurations are common */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PRODUCT=%x/%x/%x",
+       if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
                           le16_to_cpu(usb_dev->descriptor.idVendor),
                           le16_to_cpu(usb_dev->descriptor.idProduct),
                           le16_to_cpu(usb_dev->descriptor.bcdDevice)))
                return -ENOMEM;
 
        /* class-based driver binding models */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "TYPE=%d/%d/%d",
+       if (add_uevent_var(env, "TYPE=%d/%d/%d",
                           usb_dev->descriptor.bDeviceClass,
                           usb_dev->descriptor.bDeviceSubClass,
                           usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "BUSNUM=%03d",
+       if (add_uevent_var(env, "BUSNUM=%03d",
                           usb_dev->bus->busnum))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVNUM=%03d",
+       if (add_uevent_var(env, "DEVNUM=%03d",
                           usb_dev->devnum))
                return -ENOMEM;
 
-       envp[i] = NULL;
        return 0;
 }
 
 #else
 
-static int usb_uevent(struct device *dev, char **envp,
-                     int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
@@ -812,8 +798,8 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
        }
        status = udriver->suspend(udev, msg);
 
-done:
-       // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
        if (status == 0)
                udev->dev.power.power_state.event = msg.event;
        return status;
@@ -842,8 +828,8 @@ static int usb_resume_device(struct usb_device *udev)
        udriver = to_usb_device_driver(udev->dev.driver);
        status = udriver->resume(udev);
 
-done:
-       // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
        if (status == 0) {
                udev->autoresume_disabled = 0;
                udev->dev.power.power_state.event = PM_EVENT_ON;
@@ -881,8 +867,8 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
                mark_quiesced(intf);
        }
 
-done:
-       // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+       dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
        return status;
 }
 
@@ -907,21 +893,37 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
        }
        driver = to_usb_driver(intf->dev.driver);
 
-       if (reset_resume && driver->post_reset)
-               driver->post_reset(intf, reset_resume);
-       else if (driver->resume) {
-               status = driver->resume(intf);
-               if (status)
-                       dev_err(&intf->dev, "%s error %d\n",
-                                       "resume", status);
-       } else
-               dev_warn(&intf->dev, "no resume for driver %s?\n",
-                               driver->name);
+       if (reset_resume) {
+               if (driver->reset_resume) {
+                       status = driver->reset_resume(intf);
+                       if (status)
+                               dev_err(&intf->dev, "%s error %d\n",
+                                               "reset_resume", status);
+               } else {
+                       // status = -EOPNOTSUPP;
+                       dev_warn(&intf->dev, "no %s for driver %s?\n",
+                                       "reset_resume", driver->name);
+               }
+       } else {
+               if (driver->resume) {
+                       status = driver->resume(intf);
+                       if (status)
+                               dev_err(&intf->dev, "%s error %d\n",
+                                               "resume", status);
+               } else {
+                       // status = -EOPNOTSUPP;
+                       dev_warn(&intf->dev, "no %s for driver %s?\n",
+                                       "resume", driver->name);
+               }
+       }
 
 done:
-       // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
        if (status == 0)
                mark_active(intf);
+
+       /* FIXME: Unbind the driver and reprobe if the resume failed
+        * (not possible if auto_pm is set) */
        return status;
 }
 
@@ -958,6 +960,18 @@ static int autosuspend_check(struct usb_device *udev)
                                                "for autosuspend\n");
                                return -EOPNOTSUPP;
                        }
+
+                       /* Don't allow autosuspend if the device will need
+                        * a reset-resume and any of its interface drivers
+                        * doesn't include support.
+                        */
+                       if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+                               struct usb_driver *driver;
+
+                               driver = to_usb_driver(intf->dev.driver);
+                               if (!driver->reset_resume)
+                                       return -EOPNOTSUPP;
+                       }
                }
        }
 
@@ -974,7 +988,7 @@ static int autosuspend_check(struct usb_device *udev)
                         * or for the past.
                         */
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                                       suspend_time - jiffies);
+                               round_jiffies_relative(suspend_time - jiffies));
                        }
                return -EAGAIN;
        }
@@ -1083,7 +1097,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        }
 
  done:
-       // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
        return status;
 }
 
@@ -1138,7 +1152,8 @@ static int usb_resume_both(struct usb_device *udev)
                        status = usb_autoresume_device(parent);
                        if (status == 0) {
                                status = usb_resume_device(udev);
-                               if (status) {
+                               if (status || udev->state ==
+                                               USB_STATE_NOTATTACHED) {
                                        usb_autosuspend_device(parent);
 
                                        /* It's possible usb_resume_device()
@@ -1159,11 +1174,7 @@ static int usb_resume_both(struct usb_device *udev)
                        /* We can't progagate beyond the USB subsystem,
                         * so if a root hub's controller is suspended
                         * then we're stuck. */
-                       if (udev->dev.parent->power.power_state.event !=
-                                       PM_EVENT_ON)
-                               status = -EHOSTUNREACH;
-                       else
-                               status = usb_resume_device(udev);
+                       status = usb_resume_device(udev);
                }
        } else {
 
@@ -1180,7 +1191,7 @@ static int usb_resume_both(struct usb_device *udev)
        }
 
  done:
-       // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
        udev->reset_resume = 0;
        return status;
 }
@@ -1198,6 +1209,8 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
        udev->auto_pm = 1;
        udev->pm_usage_cnt += inc_usage_cnt;
        WARN_ON(udev->pm_usage_cnt < 0);
+       if (inc_usage_cnt)
+               udev->last_busy = jiffies;
        if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
                if (udev->state == USB_STATE_SUSPENDED)
                        status = usb_resume_both(udev);
@@ -1206,8 +1219,6 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
                else if (inc_usage_cnt)
                        udev->last_busy = jiffies;
        } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
-               if (inc_usage_cnt)
-                       udev->last_busy = jiffies;
                status = usb_suspend_both(udev, PMSG_SUSPEND);
        }
        usb_pm_unlock(udev);
@@ -1248,8 +1259,8 @@ void usb_autosuspend_device(struct usb_device *udev)
        int     status;
 
        status = usb_autopm_do_device(udev, -1);
-       // dev_dbg(&udev->dev, "%s: cnt %d\n",
-       //              __FUNCTION__, udev->pm_usage_cnt);
+       dev_vdbg(&udev->dev, "%s: cnt %d\n",
+                       __FUNCTION__, udev->pm_usage_cnt);
 }
 
 /**
@@ -1268,8 +1279,8 @@ void usb_autosuspend_device(struct usb_device *udev)
 void usb_try_autosuspend_device(struct usb_device *udev)
 {
        usb_autopm_do_device(udev, 0);
-       // dev_dbg(&udev->dev, "%s: cnt %d\n",
-       //              __FUNCTION__, udev->pm_usage_cnt);
+       dev_vdbg(&udev->dev, "%s: cnt %d\n",
+                       __FUNCTION__, udev->pm_usage_cnt);
 }
 
 /**
@@ -1296,8 +1307,8 @@ int usb_autoresume_device(struct usb_device *udev)
        int     status;
 
        status = usb_autopm_do_device(udev, 1);
-       // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
-       //              __FUNCTION__, status, udev->pm_usage_cnt);
+       dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
+                       __FUNCTION__, status, udev->pm_usage_cnt);
        return status;
 }
 
@@ -1316,16 +1327,15 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
        else {
                udev->auto_pm = 1;
                intf->pm_usage_cnt += inc_usage_cnt;
+               udev->last_busy = jiffies;
                if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
                        if (udev->state == USB_STATE_SUSPENDED)
                                status = usb_resume_both(udev);
                        if (status != 0)
                                intf->pm_usage_cnt -= inc_usage_cnt;
-                       else if (inc_usage_cnt)
+                       else
                                udev->last_busy = jiffies;
                } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
-                       if (inc_usage_cnt)
-                               udev->last_busy = jiffies;
                        status = usb_suspend_both(udev, PMSG_SUSPEND);
                }
        }
@@ -1369,8 +1379,8 @@ void usb_autopm_put_interface(struct usb_interface *intf)
        int     status;
 
        status = usb_autopm_do_interface(intf, -1);
-       // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-       //              __FUNCTION__, status, intf->pm_usage_cnt);
+       dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+                       __FUNCTION__, status, intf->pm_usage_cnt);
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
@@ -1413,8 +1423,8 @@ int usb_autopm_get_interface(struct usb_interface *intf)
        int     status;
 
        status = usb_autopm_do_interface(intf, 1);
-       // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-       //              __FUNCTION__, status, intf->pm_usage_cnt);
+       dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+                       __FUNCTION__, status, intf->pm_usage_cnt);
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1435,8 +1445,8 @@ int usb_autopm_set_interface(struct usb_interface *intf)
        int     status;
 
        status = usb_autopm_do_interface(intf, 0);
-       // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-       //              __FUNCTION__, status, intf->pm_usage_cnt);
+       dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+                       __FUNCTION__, status, intf->pm_usage_cnt);
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);