#include <linux/device.h>
#include <linux/usb.h>
+#include <linux/workqueue.h>
#include "hcd.h"
#include "usb.h"
mutex_lock_nested(&udev->pm_mutex, udev->level);
udev->pm_usage_cnt -= dec_usage_cnt;
if (udev->pm_usage_cnt <= 0)
- schedule_delayed_work(&udev->autosuspend,
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
USB_AUTOSUSPEND_DELAY);
mutex_unlock(&udev->pm_mutex);
// dev_dbg(&udev->dev, "%s: cnt %d\n",
struct usb_device *udev = interface_to_usbdev(intf);
mutex_lock_nested(&udev->pm_mutex, udev->level);
- if (intf->condition != USB_INTERFACE_UNBOUND) {
- if (--intf->pm_usage_cnt <= 0)
- schedule_delayed_work(&udev->autosuspend,
- USB_AUTOSUSPEND_DELAY);
+ if (intf->condition != USB_INTERFACE_UNBOUND &&
+ --intf->pm_usage_cnt <= 0) {
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ USB_AUTOSUSPEND_DELAY);
}
mutex_unlock(&udev->pm_mutex);
// dev_dbg(&intf->dev, "%s: cnt %d\n",
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
static int nousb; /* Disable USB when built into kernel image */
+struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
+
/**
* usb_ifnum_to_if - get the interface object with a given interface number
udev = to_usb_device(dev);
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
cancel_delayed_work(&udev->autosuspend);
- flush_scheduled_work();
+ flush_workqueue(ksuspend_usb_wq);
#endif
usb_destroy_configuration(udev);
usb_put_hcd(bus_to_hcd(udev->bus));
#ifdef CONFIG_PM
+static int ksuspend_usb_init(void)
+{
+ ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
+ if (!ksuspend_usb_wq)
+ return -ENOMEM;
+ return 0;
+}
+
+static void ksuspend_usb_cleanup(void)
+{
+ destroy_workqueue(ksuspend_usb_wq);
+}
+
+#else
+
+#define ksuspend_usb_init() 0
+#define ksuspend_usb_cleanup() do {} while (0)
+
+#endif
+
+#ifdef CONFIG_USB_SUSPEND
+
/* usb_autosuspend_work - callback routine to autosuspend a USB device */
static void usb_autosuspend_work(void *_udev)
{
mutex_unlock(&udev->pm_mutex);
}
+#else
+
+static void usb_autosuspend_work(void *_udev)
+{}
+
#endif
/**
return 0;
}
+ retval = ksuspend_usb_init();
+ if (retval)
+ goto out;
retval = bus_register(&usb_bus_type);
if (retval)
- goto out;
+ goto bus_register_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
usb_host_cleanup();
host_init_failed:
bus_unregister(&usb_bus_type);
+bus_register_failed:
+ ksuspend_usb_cleanup();
out:
return retval;
}
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);
+ ksuspend_usb_cleanup();
}
subsys_initcall(usb_init);