linux/drivers/usb/storage/libusual.c
<<
>>
Prefs
   1/*
   2 * libusual
   3 *
   4 * The libusual contains the table of devices common for ub and usb-storage.
   5 */
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/usb.h>
   9#include <linux/usb_usual.h>
  10#include <linux/vmalloc.h>
  11#include <linux/kthread.h>
  12#include <linux/mutex.h>
  13
  14/*
  15 */
  16#define USU_MOD_FL_THREAD   1   /* Thread is running */
  17#define USU_MOD_FL_PRESENT  2   /* The module is loaded */
  18
  19struct mod_status {
  20        unsigned long fls;
  21};
  22
  23static struct mod_status stat[3];
  24static DEFINE_SPINLOCK(usu_lock);
  25
  26/*
  27 */
  28#define USB_US_DEFAULT_BIAS     USB_US_TYPE_STOR
  29static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
  30
  31#define BIAS_NAME_SIZE  (sizeof("usb-storage"))
  32static const char *bias_names[3] = { "none", "usb-storage", "ub" };
  33
  34static DEFINE_MUTEX(usu_probe_mutex);
  35static DECLARE_COMPLETION(usu_end_notify);
  36static atomic_t total_threads = ATOMIC_INIT(0);
  37
  38static int usu_probe_thread(void *arg);
  39
  40/*
  41 * @type: the module type as an integer
  42 */
  43void usb_usual_set_present(int type)
  44{
  45        struct mod_status *st;
  46        unsigned long flags;
  47
  48        if (type <= 0 || type >= 3)
  49                return;
  50        st = &stat[type];
  51        spin_lock_irqsave(&usu_lock, flags);
  52        st->fls |= USU_MOD_FL_PRESENT;
  53        spin_unlock_irqrestore(&usu_lock, flags);
  54}
  55EXPORT_SYMBOL_GPL(usb_usual_set_present);
  56
  57void usb_usual_clear_present(int type)
  58{
  59        struct mod_status *st;
  60        unsigned long flags;
  61
  62        if (type <= 0 || type >= 3)
  63                return;
  64        st = &stat[type];
  65        spin_lock_irqsave(&usu_lock, flags);
  66        st->fls &= ~USU_MOD_FL_PRESENT;
  67        spin_unlock_irqrestore(&usu_lock, flags);
  68}
  69EXPORT_SYMBOL_GPL(usb_usual_clear_present);
  70
  71/*
  72 * Match the calling driver type against the table.
  73 * Returns: 0 if the device matches.
  74 */
  75int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
  76{
  77        int id_type = USB_US_TYPE(id->driver_info);
  78
  79        if (caller_type <= 0 || caller_type >= 3)
  80                return -EINVAL;
  81
  82        /* Drivers grab fixed assignment devices */
  83        if (id_type == caller_type)
  84                return 0;
  85        /* Drivers grab devices biased to them */
  86        if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias))
  87                return 0;
  88        return -ENODEV;
  89}
  90EXPORT_SYMBOL_GPL(usb_usual_check_type);
  91
  92/*
  93 */
  94static int usu_probe(struct usb_interface *intf,
  95                         const struct usb_device_id *id)
  96{
  97        int rc;
  98        unsigned long type;
  99        struct task_struct* task;
 100        unsigned long flags;
 101
 102        type = USB_US_TYPE(id->driver_info);
 103        if (type == 0)
 104                type = atomic_read(&usu_bias);
 105
 106        spin_lock_irqsave(&usu_lock, flags);
 107        if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) {
 108                spin_unlock_irqrestore(&usu_lock, flags);
 109                return -ENXIO;
 110        }
 111        stat[type].fls |= USU_MOD_FL_THREAD;
 112        spin_unlock_irqrestore(&usu_lock, flags);
 113
 114        task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
 115        if (IS_ERR(task)) {
 116                rc = PTR_ERR(task);
 117                printk(KERN_WARNING "libusual: "
 118                    "Unable to start the thread for %s: %d\n",
 119                    bias_names[type], rc);
 120                spin_lock_irqsave(&usu_lock, flags);
 121                stat[type].fls &= ~USU_MOD_FL_THREAD;
 122                spin_unlock_irqrestore(&usu_lock, flags);
 123                return rc;      /* Not being -ENXIO causes a message printed */
 124        }
 125        atomic_inc(&total_threads);
 126
 127        return -ENXIO;
 128}
 129
 130static void usu_disconnect(struct usb_interface *intf)
 131{
 132        ;       /* We should not be here. */
 133}
 134
 135static struct usb_driver usu_driver = {
 136        .name =         "libusual",
 137        .probe =        usu_probe,
 138        .disconnect =   usu_disconnect,
 139        .id_table =     usb_storage_usb_ids,
 140};
 141
 142/*
 143 * A whole new thread for a purpose of request_module seems quite stupid.
 144 * The request_module forks once inside again. However, if we attempt
 145 * to load a storage module from our own modprobe thread, that module
 146 * references our symbols, which cannot be resolved until our module is
 147 * initialized. I wish there was a way to wait for the end of initialization.
 148 * The module notifier reports MODULE_STATE_COMING only.
 149 * So, we wait until module->init ends as the next best thing.
 150 */
 151static int usu_probe_thread(void *arg)
 152{
 153        int type = (unsigned long) arg;
 154        struct mod_status *st = &stat[type];
 155        int rc;
 156        unsigned long flags;
 157
 158        mutex_lock(&usu_probe_mutex);
 159        rc = request_module(bias_names[type]);
 160        spin_lock_irqsave(&usu_lock, flags);
 161        if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
 162                /*
 163                 * This should not happen, but let us keep tabs on it.
 164                 */
 165                printk(KERN_NOTICE "libusual: "
 166                    "modprobe for %s succeeded, but module is not present\n",
 167                    bias_names[type]);
 168        }
 169        st->fls &= ~USU_MOD_FL_THREAD;
 170        spin_unlock_irqrestore(&usu_lock, flags);
 171        mutex_unlock(&usu_probe_mutex);
 172
 173        complete_and_exit(&usu_end_notify, 0);
 174}
 175
 176/*
 177 */
 178static int __init usb_usual_init(void)
 179{
 180        int rc;
 181
 182        mutex_lock(&usu_probe_mutex);
 183        rc = usb_register(&usu_driver);
 184        mutex_unlock(&usu_probe_mutex);
 185        return rc;
 186}
 187
 188static void __exit usb_usual_exit(void)
 189{
 190        /*
 191         * We do not check for any drivers present, because
 192         * they keep us pinned with symbol references.
 193         */
 194
 195        usb_deregister(&usu_driver);
 196
 197        while (atomic_read(&total_threads) > 0) {
 198                wait_for_completion(&usu_end_notify);
 199                atomic_dec(&total_threads);
 200        }
 201}
 202
 203/*
 204 * Validate and accept the bias parameter.
 205 */
 206static int usu_set_bias(const char *bias_s, struct kernel_param *kp)
 207{
 208        int i;
 209        int len;
 210        int bias_n = 0;
 211
 212        len = strlen(bias_s);
 213        if (len == 0)
 214                return -EDOM;
 215        if (bias_s[len-1] == '\n')
 216                --len;
 217
 218        for (i = 1; i < 3; i++) {
 219                if (strncmp(bias_s, bias_names[i], len) == 0) {
 220                        bias_n = i;
 221                        break;
 222                }
 223        }
 224        if (bias_n == 0)
 225                return -EINVAL;
 226
 227        atomic_set(&usu_bias, bias_n);
 228        return 0;
 229}
 230
 231static int usu_get_bias(char *buffer, struct kernel_param *kp)
 232{
 233        return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)]));
 234}
 235
 236module_init(usb_usual_init);
 237module_exit(usb_usual_exit);
 238
 239module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR);
 240__MODULE_PARM_TYPE(bias, "string");
 241MODULE_PARM_DESC(bias, "Bias to usb-storage or ub");
 242
 243MODULE_LICENSE("GPL");
 244