X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fstorage%2Flibusual.c;fp=drivers%2Fusb%2Fstorage%2Flibusual.c;h=d3fda92f92200684c418400effc577991db023b7;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=b1ec4a718547316c62cf39fa4872ffd7651424f9;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c index b1ec4a718..d3fda92f9 100644 --- a/drivers/usb/storage/libusual.c +++ b/drivers/usb/storage/libusual.c @@ -5,14 +5,17 @@ */ #include #include +#include #include #include #include +#include /* */ #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; @@ -33,8 +36,12 @@ static DECLARE_MUTEX_LOCKED(usu_init_notify); 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 class_device *usu_class_device; + /* * The table. */ @@ -111,18 +118,44 @@ int usb_usual_check_type(const struct usb_device_id *id, int caller_type) } EXPORT_SYMBOL_GPL(usb_usual_check_type); +/* + */ +static int usu_uevent(struct class_device *class_dev, + char **envp, int num_envp, char *buffer, int buffer_size) +{ + 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) { unsigned long type; - int rc; - 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) +{ + 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) { @@ -132,8 +165,9 @@ static int usu_probe(struct usb_interface *intf, stat[type].fls |= USU_MOD_FL_THREAD; spin_unlock_irqrestore(&usu_lock, flags); - rc = kernel_thread(usu_probe_thread, (void*)type, CLONE_VM); - if (rc < 0) { + task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type); + if (IS_ERR(task)) { + int rc = PTR_ERR(task); printk(KERN_WARNING "libusual: " "Unable to start the thread for %s: %d\n", bias_names[type], rc); @@ -175,8 +209,6 @@ static int usu_probe_thread(void *arg) int rc; unsigned long flags; - daemonize("libusual_%d", type); /* "usb-storage" is kinda too long */ - /* A completion does not work here because it's counted. */ down(&usu_init_notify); up(&usu_init_notify); @@ -186,10 +218,14 @@ static int usu_probe_thread(void *arg) if (rc == 0 && (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", + "request for %s succeeded, but module is not present\n", bias_names[type]); + st->fls |= USU_MOD_FL_FAILED; } st->fls &= ~USU_MOD_FL_THREAD; spin_unlock_irqrestore(&usu_lock, flags); @@ -203,9 +239,27 @@ 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_device = class_device_create(usu_class, NULL, 0, NULL, "0"); + if (IS_ERR(usu_class_device)) { + rc = PTR_ERR(usu_class_device); + goto err_classdev; + } + usu_class_device->uevent = usu_uevent; + rc = usb_register(&usu_driver); up(&usu_init_notify); return rc; + + // class_device_destroy(usu_class, 0); +err_classdev: + class_destroy(usu_class); +err_class: + return rc; } static void __exit usb_usual_exit(void) @@ -221,6 +275,9 @@ static void __exit usb_usual_exit(void) wait_for_completion(&usu_end_notify); atomic_dec(&total_threads); } + + class_device_destroy(usu_class, 0); + class_destroy(usu_class); } /*