diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c index d617e8a..ef93cff 100644 --- a/drivers/usb/storage/libusual.c +++ b/drivers/usb/storage/libusual.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -15,6 +16,7 @@ */ #define USU_MOD_FL_THREAD 1 /* Thread is running */ #define USU_MOD_FL_PRESENT 2 /* The module is loaded */ +#define USU_MOD_FL_FAILED 4 /* The module failed to load */ struct mod_status { unsigned long fls; @@ -35,8 +37,12 @@ static DEFINE_MUTEX(usu_probe_mutex); static DECLARE_COMPLETION(usu_end_notify); static atomic_t total_threads = ATOMIC_INIT(0); +static int usu_kick(unsigned long type); static int usu_probe_thread(void *arg); +static struct class *usu_class; +static struct device *usu_class_device; + /* * The table. */ @@ -115,17 +121,42 @@ EXPORT_SYMBOL_GPL(usb_usual_check_type); /* */ +static int usu_uevent(struct device *class_dev, struct kobj_uevent_env *env) +{ + unsigned long flags; + int i; + + for (i = 1; i < 3; i++) { + spin_lock_irqsave(&usu_lock, flags); + if (stat[i].fls & USU_MOD_FL_FAILED) { + stat[i].fls &= ~USU_MOD_FL_FAILED; + spin_unlock_irqrestore(&usu_lock, flags); + usu_kick(i); + } else { + spin_unlock_irqrestore(&usu_lock, flags); + } + } + return 0; +} + +/* + */ static int usu_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int rc; unsigned long type; - struct task_struct* task; - unsigned long flags; type = USB_US_TYPE(id->driver_info); if (type == 0) type = atomic_read(&usu_bias); + return usu_kick(type); +} + +static int usu_kick(unsigned long type) +{ + int rc; + unsigned long flags; + struct task_struct* task; spin_lock_irqsave(&usu_lock, flags); if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) { @@ -182,13 +213,24 @@ static int usu_probe_thread(void *arg) mutex_lock(&usu_probe_mutex); rc = request_module(bias_names[type]); spin_lock_irqsave(&usu_lock, flags); - if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) { + if ((st->fls & USU_MOD_FL_PRESENT) == 0) { /* * This should not happen, but let us keep tabs on it. + * One common source of this a user who builds USB + * statically, then uses initrd, and has a USB device. + * When static devices are probed, request_module() + * calls a fake modprobe and fails. */ - printk(KERN_NOTICE "libusual: " - "modprobe for %s succeeded, but module is not present\n", - bias_names[type]); + if (rc == 0) { + printk(KERN_NOTICE "libusual: request for %s succeeded," + "but module is not present\n", + bias_names[type]); + } else { + printk(KERN_DEBUG "libusual: " + "request for %s failed (%d)\n", + bias_names[type], rc); + } + st->fls |= USU_MOD_FL_FAILED; } st->fls &= ~USU_MOD_FL_THREAD; spin_unlock_irqrestore(&usu_lock, flags); @@ -203,9 +245,31 @@ static int __init usb_usual_init(void) { int rc; + usu_class = class_create(THIS_MODULE, "libusual"); + if (IS_ERR(usu_class)) { + rc = PTR_ERR(usu_class_device); + goto err_class; + } + usu_class->dev_uevent = usu_uevent; + usu_class_device = device_create(usu_class, NULL, 0, NULL, "0"); + if (IS_ERR(usu_class_device)) { + rc = PTR_ERR(usu_class_device); + goto err_classdev; + } + mutex_lock(&usu_probe_mutex); rc = usb_register(&usu_driver); mutex_unlock(&usu_probe_mutex); + if (rc != 0) + goto err_reg; + return 0; + +err_reg: + put_device(usu_class_device); + device_unregister(usu_class_device); +err_classdev: + class_destroy(usu_class); +err_class: return rc; } @@ -222,6 +286,12 @@ static void __exit usb_usual_exit(void) wait_for_completion(&usu_end_notify); atomic_dec(&total_threads); } + + // Why bother with device_destroy(usu_class, 0) if we have a pointer? + put_device(usu_class_device); + device_unregister(usu_class_device); + + class_destroy(usu_class); } /*