[PATCH] USB: drivers/usb/storage/libusual
authorPete Zaitcev <zaitcev@redhat.com>
Sun, 23 Oct 2005 03:15:09 +0000 (20:15 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 4 Jan 2006 21:48:31 +0000 (13:48 -0800)
This patch adds a shim driver libusual, which routes devices between
usb-storage and ub according to the common table, based on unusual_devs.h.
The help and example syntax is in Kconfig.

Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
12 files changed:
drivers/block/Kconfig
drivers/block/ub.c
drivers/usb/Makefile
drivers/usb/storage/Kconfig
drivers/usb/storage/Makefile
drivers/usb/storage/libusual.c [new file with mode: 0644]
drivers/usb/storage/protocol.h
drivers/usb/storage/transport.h
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
include/linux/usb_usual.h [new file with mode: 0644]

index 7b1cd93892be4e271d5f94ef60982607020efa76..c4b9d2adfc08bce861a9078945c4e0acf63628a4 100644 (file)
@@ -358,7 +358,8 @@ config BLK_DEV_UB
          This driver supports certain USB attached storage devices
          such as flash keys.
 
-         Warning: Enabling this cripples the usb-storage driver.
+         If you enable this driver, it is recommended to avoid conflicts
+         with usb-storage by enabling USB_LIBUSUAL.
 
          If unsure, say N.
 
index bfb23d543ff7a71d1bba7b22de0ba5a5157cfaaf..06d741d58a688223b1c65823536ace32dfd1a99a 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/usb_usual.h>
 #include <linux/blkdev.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/timer.h>
  *                                                                   +--------+
  */
 
-/*
- * Definitions which have to be scattered once we understand the layout better.
- */
-
-/* Transport (despite PR in the name) */
-#define US_PR_BULK     0x50            /* bulk only */
-
-/* Protocol */
-#define US_SC_SCSI     0x06            /* Transparent */
-
 /*
  * This many LUNs per USB device.
  * Every one of them takes a host, see UB_MAX_HOSTS.
@@ -422,13 +413,18 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum);
 
 /*
  */
+#ifdef CONFIG_USB_LIBUSUAL
+
+#define ub_usb_ids  storage_usb_ids
+#else
+
 static struct usb_device_id ub_usb_ids[] = {
-       // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) },  /* SDDR-31 */
        { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
        { }
 };
 
 MODULE_DEVICE_TABLE(usb, ub_usb_ids);
+#endif /* CONFIG_USB_LIBUSUAL */
 
 /*
  * Find me a way to identify "next free minor" for add_disk(),
@@ -2172,6 +2168,9 @@ static int ub_probe(struct usb_interface *intf,
        int rc;
        int i;
 
+       if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
+               return -ENXIO;
+
        rc = -ENOMEM;
        if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
                goto err_core;
@@ -2479,6 +2478,7 @@ static int __init ub_init(void)
        if ((rc = usb_register(&ub_driver)) != 0)
                goto err_register;
 
+       usb_usual_set_present(USB_US_TYPE_UB);
        return 0;
 
 err_register:
@@ -2494,6 +2494,7 @@ static void __exit ub_exit(void)
 
        devfs_remove(DEVFS_NAME);
        unregister_blkdev(UB_MAJOR, DRV_NAME);
+       usb_usual_clear_present(USB_US_TYPE_UB);
 }
 
 module_init(ub_init);
index a50c2bc506f245d34bb0785d81cf3856151bd65e..3639c3f8d3578f0fdb9fa5841ed04a410f379b99 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_USB_MIDI)                += class/
 obj-$(CONFIG_USB_PRINTER)      += class/
 
 obj-$(CONFIG_USB_STORAGE)      += storage/
+obj-$(CONFIG_USB)              += storage/
 
 obj-$(CONFIG_USB_AIPTEK)       += input/
 obj-$(CONFIG_USB_ATI_REMOTE)   += input/
index c41d64dbb0f0ec39d50901ffe771715b31a62a48..bdfcb95d9c1281667e3f650e123002aeea14ae67 100644 (file)
@@ -124,3 +124,17 @@ config USB_STORAGE_ONETOUCH
          hard drive's as an input device. An action can be associated with
          this input in any keybinding software. (e.g. gnome's keyboard short-
          cuts)
+
+config USB_LIBUSUAL
+       bool "The shared table of common (or usual) storage devices"
+       depends on USB
+       help
+         This module contains a table of common (or usual) devices
+         for usb-storage and ub drivers, and allows to switch binding
+         of these devices without rebuilding modules.
+
+         Typical syntax of /etc/modprobe.conf is:
+
+               options libusual bias="ub"
+
+         If unsure, say N.
index 44ab8f9978fe9d3a44fd2675674f3395ac8949b0..2d416e9028bbad7eb7502f37ae091c342a4cbf20 100644 (file)
@@ -22,3 +22,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)        += onetouch.o
 
 usb-storage-objs :=    scsiglue.o protocol.o transport.o usb.o \
                        initializers.o $(usb-storage-obj-y)
+
+ifneq ($(CONFIG_USB_LIBUSUAL),)
+       obj-$(CONFIG_USB)       += libusual.o
+endif
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
new file mode 100644 (file)
index 0000000..61f73d8
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * libusual
+ *
+ * The libusual contains the table of devices common for ub and usb-storage.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+#include <linux/vmalloc.h>
+
+/*
+ */
+#define USU_MOD_FL_THREAD   1  /* Thread is running */
+#define USU_MOD_FL_PRESENT  2  /* The module is loaded */
+
+struct mod_status {
+       unsigned long fls;
+};
+
+static struct mod_status stat[3];
+static DEFINE_SPINLOCK(usu_lock);
+
+/*
+ */
+#define USB_US_DEFAULT_BIAS    USB_US_TYPE_STOR
+
+#define BIAS_NAME_SIZE  (sizeof("usb-storage"))
+static char bias[BIAS_NAME_SIZE];
+static int usb_usual_bias;
+static const char *bias_names[3] = { "none", "usb-storage", "ub" };
+
+static DECLARE_MUTEX_LOCKED(usu_init_notify);
+static DECLARE_COMPLETION(usu_end_notify);
+static atomic_t total_threads = ATOMIC_INIT(0);
+
+static int usu_probe_thread(void *arg);
+static int parse_bias(const char *bias_s);
+
+/*
+ * The table.
+ */
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+                   vendorName, productName,useProtocol, useTransport, \
+                   initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
+  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+
+#define USUAL_DEV(useProto, useTrans, useType) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
+  .driver_info = ((useType)<<24) }
+
+struct usb_device_id storage_usb_ids [] = {
+#      include "unusual_devs.h"
+       { } /* Terminating entry */
+};
+
+#undef USUAL_DEV
+#undef UNUSUAL_DEV
+
+MODULE_DEVICE_TABLE(usb, storage_usb_ids);
+EXPORT_SYMBOL_GPL(storage_usb_ids);
+
+/*
+ * @type: the module type as an integer
+ */
+void usb_usual_set_present(int type)
+{
+       struct mod_status *st;
+       unsigned long flags;
+
+       if (type <= 0 || type >= 3)
+               return;
+       st = &stat[type];
+       spin_lock_irqsave(&usu_lock, flags);
+       st->fls |= USU_MOD_FL_PRESENT;
+       spin_unlock_irqrestore(&usu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_usual_set_present);
+
+void usb_usual_clear_present(int type)
+{
+       struct mod_status *st;
+       unsigned long flags;
+
+       if (type <= 0 || type >= 3)
+               return;
+       st = &stat[type];
+       spin_lock_irqsave(&usu_lock, flags);
+       st->fls &= ~USU_MOD_FL_PRESENT;
+       spin_unlock_irqrestore(&usu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_usual_clear_present);
+
+/*
+ * Match the calling driver type against the table.
+ * Returns: 0 if the device matches.
+ */
+int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
+{
+       int id_type = USB_US_TYPE(id->driver_info);
+
+       if (caller_type <= 0 || caller_type >= 3)
+               return -EINVAL;
+
+       /* Drivers grab fixed assignment devices */
+       if (id_type == caller_type)
+               return 0;
+       /* Drivers grab devices biased to them */
+       if (id_type == USB_US_TYPE_NONE && caller_type == usb_usual_bias)
+               return 0;
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(usb_usual_check_type);
+
+/*
+ */
+static int usu_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       int type;
+       int rc;
+       unsigned long flags;
+
+       type = USB_US_TYPE(id->driver_info);
+       if (type == 0)
+               type = usb_usual_bias;
+
+       spin_lock_irqsave(&usu_lock, flags);
+       if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) {
+               spin_unlock_irqrestore(&usu_lock, flags);
+               return -ENXIO;
+       }
+       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) {
+               printk(KERN_WARNING "libusual: "
+                   "Unable to start the thread for %s: %d\n",
+                   bias_names[type], rc);
+               spin_lock_irqsave(&usu_lock, flags);
+               stat[type].fls &= ~USU_MOD_FL_THREAD;
+               spin_unlock_irqrestore(&usu_lock, flags);
+               return rc;      /* Not being -ENXIO causes a message printed */
+       }
+       atomic_inc(&total_threads);
+
+       return -ENXIO;
+}
+
+static void usu_disconnect(struct usb_interface *intf)
+{
+       ;       /* We should not be here. */
+}
+
+static struct usb_driver usu_driver = {
+       .owner =        THIS_MODULE,
+       .name =         "libusual",
+       .probe =        usu_probe,
+       .disconnect =   usu_disconnect,
+       .id_table =     storage_usb_ids,
+};
+
+/*
+ * A whole new thread for a purpose of request_module seems quite stupid.
+ * The request_module forks once inside again. However, if we attempt
+ * to load a storage module from our own modprobe thread, that module
+ * references our symbols, which cannot be resolved until our module is
+ * initialized. I wish there was a way to wait for the end of initialization.
+ * The module notifier reports MODULE_STATE_COMING only.
+ * So, we wait until module->init ends as the next best thing.
+ */
+static int usu_probe_thread(void *arg)
+{
+       int type = (unsigned long) arg;
+       struct mod_status *st = &stat[type];
+       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);
+
+       rc = request_module(bias_names[type]);
+       spin_lock_irqsave(&usu_lock, flags);
+       if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) {
+               /*
+                * This should not happen, but let us keep tabs on it.
+                */
+               printk(KERN_NOTICE "libusual: "
+                   "modprobe for %s succeeded, but module is not present\n",
+                   bias_names[type]);
+       }
+       st->fls &= ~USU_MOD_FL_THREAD;
+       spin_unlock_irqrestore(&usu_lock, flags);
+
+       complete_and_exit(&usu_end_notify, 0);
+}
+
+/*
+ */
+static int __init usb_usual_init(void)
+{
+       int rc;
+
+       bias[BIAS_NAME_SIZE-1] = 0;
+       usb_usual_bias = parse_bias(bias);
+
+       rc = usb_register(&usu_driver);
+       up(&usu_init_notify);
+       return rc;
+}
+
+static void __exit usb_usual_exit(void)
+{
+       /*
+        * We do not check for any drivers present, because
+        * they keep us pinned with symbol references.
+        */
+
+       usb_deregister(&usu_driver);
+
+       while (atomic_read(&total_threads) > 0) {
+               wait_for_completion(&usu_end_notify);
+               atomic_dec(&total_threads);
+       }
+}
+
+/*
+ * Validate and accept the bias parameter.
+ * Maybe make an sysfs method later. XXX
+ */
+static int parse_bias(const char *bias_s)
+{
+       int i;
+       int bias_n = 0;
+
+       if (bias_s[0] == 0 || bias_s[0] == ' ') {
+               bias_n = USB_US_DEFAULT_BIAS;
+       } else {
+               for (i = 1; i < 3; i++) {
+                       if (strcmp(bias_s, bias_names[i]) == 0) {
+                               bias_n = i;
+                               break;
+                       }
+               }
+               if (bias_n == 0) {
+                       bias_n = USB_US_DEFAULT_BIAS;
+                       printk(KERN_INFO
+                           "libusual: unknown bias \"%s\", using \"%s\"\n",
+                           bias_s, bias_names[bias_n]);
+               }
+       }
+       return bias_n;
+}
+
+module_init(usb_usual_init);
+module_exit(usb_usual_exit);
+
+module_param_string(bias, bias, BIAS_NAME_SIZE,  S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(bias, "Bias to usb-storage or ub");
+
+MODULE_LICENSE("GPL");
index 02bff01ab09c3721783242dec9dd9b279b808347..845bed4b80317fb336cbe14ca227f8fa41907a17 100644 (file)
 #ifndef _PROTOCOL_H_
 #define _PROTOCOL_H_
 
-/* Sub Classes */
-
-#define US_SC_RBC      0x01            /* Typically, flash devices */
-#define US_SC_8020     0x02            /* CD-ROM */
-#define US_SC_QIC      0x03            /* QIC-157 Tapes */
-#define US_SC_UFI      0x04            /* Floppy */
-#define US_SC_8070     0x05            /* Removable media */
-#define US_SC_SCSI     0x06            /* Transparent */
-#define US_SC_ISD200    0x07           /* ISD200 ATA */
-#define US_SC_MIN      US_SC_RBC
-#define US_SC_MAX      US_SC_ISD200
-
-#define US_SC_DEVICE   0xff            /* Use device's value */
-
 /* Protocol handling routines */
 extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*);
 extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*);
index 0a362cc781ad48676063d7b4b88dc0d2d90fc3bf..633a715850a43fe6f7654ee7cb659575b51c4acd 100644 (file)
 #ifndef _TRANSPORT_H_
 #define _TRANSPORT_H_
 
-#include <linux/config.h>
 #include <linux/blkdev.h>
 
-/* Protocols */
-
-#define US_PR_CBI      0x00            /* Control/Bulk/Interrupt */
-#define US_PR_CB       0x01            /* Control/Bulk w/o interrupt */
-#define US_PR_BULK     0x50            /* bulk only */
-#ifdef CONFIG_USB_STORAGE_USBAT
-#define US_PR_USBAT    0x80            /* SCM-ATAPI bridge */
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR09
-#define US_PR_EUSB_SDDR09      0x81    /* SCM-SCSI bridge for SDDR-09 */
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-#define US_PR_SDDR55   0x82            /* SDDR-55 (made up) */
-#endif
-#define US_PR_DPCM_USB  0xf0           /* Combination CB/SDDR09 */
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
-#define US_PR_FREECOM   0xf1           /* Freecom */
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-#define US_PR_DATAFAB   0xf2           /* Datafab chipsets */
-#endif
-
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-#define US_PR_JUMPSHOT  0xf3           /* Lexar Jumpshot */
-#endif
-
-#define US_PR_DEVICE   0xff            /* Use device's value */
-
 /*
  * Bulk only data structures
  */
index f5f47a34b1683980c1aba2076ef6a7b5bd4ed9c1..76904ad112415af403b5439346348e2541f461c0 100644 (file)
@@ -1134,3 +1134,27 @@ UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x9999,
                US_SC_SCSI, US_PR_SDDR55, NULL,
                US_FL_SINGLE_LUN),
 #endif
+
+/* Control/Bulk transport for all SubClass values */
+USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_QIC, US_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_UFI, US_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8070, US_PR_CB, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_SCSI, US_PR_CB, USB_US_TYPE_STOR),
+
+/* Control/Bulk/Interrupt transport for all SubClass values */
+USUAL_DEV(US_SC_RBC, US_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8020, US_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_QIC, US_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_UFI, US_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8070, US_PR_CBI, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_SCSI, US_PR_CBI, USB_US_TYPE_STOR),
+
+/* Bulk-only transport for all SubClass values */
+USUAL_DEV(US_SC_RBC, US_PR_BULK, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8020, US_PR_BULK, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_QIC, US_PR_BULK, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_UFI, US_PR_BULK, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_8070, US_PR_BULK, USB_US_TYPE_STOR),
+USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0),
index 3847ebed2aa439792bbcd7c69dacdf47654fe1ae..c8375aa627238a591a6968c40972db9e5bb8914c 100644 (file)
@@ -112,49 +112,33 @@ static atomic_t total_threads = ATOMIC_INIT(0);
 static DECLARE_COMPLETION(threads_gone);
 
 
-/* The entries in this table, except for final ones here
- * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
- * line for line with the entries of us_unsuaul_dev_list[].
+/*
+ * The entries in this table correspond, line for line,
+ * with the entries of us_unusual_dev_list[].
  */
+#ifndef CONFIG_USB_LIBUSUAL
 
 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
                    vendorName, productName,useProtocol, useTransport, \
                    initFunction, flags) \
-{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
+  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+
+#define USUAL_DEV(useProto, useTrans, useType) \
+{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
+  .driver_info = (USB_US_TYPE_STOR<<24) }
 
 static struct usb_device_id storage_usb_ids [] = {
 
 #      include "unusual_devs.h"
 #undef UNUSUAL_DEV
-       /* Control/Bulk transport for all SubClass values */
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
-
-       /* Control/Bulk/Interrupt transport for all SubClass values */
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
-
-       /* Bulk-only transport for all SubClass values */
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
-       { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
-
+#undef USUAL_DEV
        /* Terminating entry */
        { }
 };
 
 MODULE_DEVICE_TABLE (usb, storage_usb_ids);
+#endif /* CONFIG_USB_LIBUSUAL */
 
 /* This is the list of devices we recognize, along with their flag data */
 
@@ -167,7 +151,6 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
  * are free to use as many characters as you like.
  */
 
-#undef UNUSUAL_DEV
 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
                    vendor_name, product_name, use_protocol, use_transport, \
                    init_function, Flags) \
@@ -177,53 +160,18 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
        .useProtocol = use_protocol,    \
        .useTransport = use_transport,  \
        .initFunction = init_function,  \
-       .flags = Flags, \
+}
+
+#define USUAL_DEV(use_protocol, use_transport, use_type) \
+{ \
+       .useProtocol = use_protocol,    \
+       .useTransport = use_transport,  \
 }
 
 static struct us_unusual_dev us_unusual_dev_list[] = {
 #      include "unusual_devs.h" 
 #      undef UNUSUAL_DEV
-       /* Control/Bulk transport for all SubClass values */
-       { .useProtocol = US_SC_RBC,
-         .useTransport = US_PR_CB},
-       { .useProtocol = US_SC_8020,
-         .useTransport = US_PR_CB},
-       { .useProtocol = US_SC_QIC,
-         .useTransport = US_PR_CB},
-       { .useProtocol = US_SC_UFI,
-         .useTransport = US_PR_CB},
-       { .useProtocol = US_SC_8070,
-         .useTransport = US_PR_CB},
-       { .useProtocol = US_SC_SCSI,
-         .useTransport = US_PR_CB},
-
-       /* Control/Bulk/Interrupt transport for all SubClass values */
-       { .useProtocol = US_SC_RBC,
-         .useTransport = US_PR_CBI},
-       { .useProtocol = US_SC_8020,
-         .useTransport = US_PR_CBI},
-       { .useProtocol = US_SC_QIC,
-         .useTransport = US_PR_CBI},
-       { .useProtocol = US_SC_UFI,
-         .useTransport = US_PR_CBI},
-       { .useProtocol = US_SC_8070,
-         .useTransport = US_PR_CBI},
-       { .useProtocol = US_SC_SCSI,
-         .useTransport = US_PR_CBI},
-
-       /* Bulk-only transport for all SubClass values */
-       { .useProtocol = US_SC_RBC,
-         .useTransport = US_PR_BULK},
-       { .useProtocol = US_SC_8020,
-         .useTransport = US_PR_BULK},
-       { .useProtocol = US_SC_QIC,
-         .useTransport = US_PR_BULK},
-       { .useProtocol = US_SC_UFI,
-         .useTransport = US_PR_BULK},
-       { .useProtocol = US_SC_8070,
-         .useTransport = US_PR_BULK},
-       { .useProtocol = US_SC_SCSI,
-         .useTransport = US_PR_BULK},
+#      undef USUAL_DEV
 
        /* Terminating entry */
        { NULL }
@@ -484,14 +432,20 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
        return 0;
 }
 
+/* Find an unusual_dev descriptor (always succeeds in the current code) */
+static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
+{
+       const int id_index = id - storage_usb_ids;
+       return &us_unusual_dev_list[id_index];
+}
+
 /* Get the unusual_devs entries and the string descriptors */
-static void get_device_info(struct us_data *us, int id_index)
+static void get_device_info(struct us_data *us, const struct usb_device_id *id)
 {
        struct usb_device *dev = us->pusb_dev;
        struct usb_interface_descriptor *idesc =
                &us->pusb_intf->cur_altsetting->desc;
-       struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
-       struct usb_device_id *id = &storage_usb_ids[id_index];
+       struct us_unusual_dev *unusual_dev = find_unusual(id);
 
        /* Store the entries */
        us->unusual_dev = unusual_dev;
@@ -501,7 +455,7 @@ static void get_device_info(struct us_data *us, int id_index)
        us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
                        idesc->bInterfaceProtocol :
                        unusual_dev->useTransport;
-       us->flags = unusual_dev->flags;
+       us->flags = USB_US_ORIG_FLAGS(id->driver_info);
 
        /*
         * This flag is only needed when we're in high-speed, so let's
@@ -529,7 +483,7 @@ static void get_device_info(struct us_data *us, int id_index)
                if (unusual_dev->useTransport != US_PR_DEVICE &&
                        us->protocol == idesc->bInterfaceProtocol)
                        msg += 2;
-               if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE))
+               if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE))
                        printk(KERN_NOTICE USB_STORAGE "This device "
                                "(%04x,%04x,%04x S %02x P %02x)"
                                " has %s in unusual_devs.h\n"
@@ -921,10 +875,12 @@ static int storage_probe(struct usb_interface *intf,
 {
        struct Scsi_Host *host;
        struct us_data *us;
-       const int id_index = id - storage_usb_ids; 
        int result;
        struct task_struct *th;
 
+       if (usb_usual_check_type(id, USB_US_TYPE_STOR))
+               return -ENXIO;
+
        US_DEBUGP("USB Mass Storage device detected\n");
 
        /*
@@ -957,7 +913,7 @@ static int storage_probe(struct usb_interface *intf,
         * of the match from the usb_device_id table, so we can find the
         * corresponding entry in the private table.
         */
-       get_device_info(us, id_index);
+       get_device_info(us, id);
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
        if (us->protocol == US_PR_EUSB_SDDR09 ||
@@ -1062,9 +1018,10 @@ static int __init usb_stor_init(void)
 
        /* register the driver, return usb_register return code if error */
        retval = usb_register(&usb_storage_driver);
-       if (retval == 0)
+       if (retval == 0) {
                printk(KERN_INFO "USB Mass Storage support registered.\n");
-
+               usb_usual_set_present(USB_US_TYPE_STOR);
+       }
        return retval;
 }
 
@@ -1088,6 +1045,8 @@ static void __exit usb_stor_exit(void)
                wait_for_completion(&threads_gone);
                atomic_dec(&total_threads);
        }
+
+       usb_usual_clear_present(USB_US_TYPE_STOR);
 }
 
 module_init(usb_stor_init);
index 98b09711a73957a8b02a32dccaf6d1c13312825c..0cd1eebc4497730ba2a5f33743cbb5b9e71b5615 100644 (file)
@@ -45,6 +45,7 @@
 #define _USB_H_
 
 #include <linux/usb.h>
+#include <linux/usb_usual.h>
 #include <linux/blkdev.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
@@ -63,38 +64,8 @@ struct us_unusual_dev {
        __u8  useProtocol;
        __u8  useTransport;
        int (*initFunction)(struct us_data *);
-       unsigned int flags;
 };
 
-/*
- * Static flag definitions.  We use this roundabout technique so that the
- * proc_info() routine can automatically display a message for each flag.
- */
-#define US_DO_ALL_FLAGS                                                \
-       US_FLAG(SINGLE_LUN,     0x00000001)                     \
-               /* allow access to only LUN 0 */                \
-       US_FLAG(NEED_OVERRIDE,  0x00000002)                     \
-               /* unusual_devs entry is necessary */           \
-       US_FLAG(SCM_MULT_TARG,  0x00000004)                     \
-               /* supports multiple targets */                 \
-       US_FLAG(FIX_INQUIRY,    0x00000008)                     \
-               /* INQUIRY response needs faking */             \
-       US_FLAG(FIX_CAPACITY,   0x00000010)                     \
-               /* READ CAPACITY response too big */            \
-       US_FLAG(IGNORE_RESIDUE, 0x00000020)                     \
-               /* reported residue is wrong */                 \
-       US_FLAG(BULK32,         0x00000040)                     \
-               /* Uses 32-byte CBW length */                   \
-       US_FLAG(NOT_LOCKABLE,   0x00000080)                     \
-               /* PREVENT/ALLOW not supported */               \
-       US_FLAG(GO_SLOW,        0x00000100)                     \
-               /* Need delay after Command phase */            \
-       US_FLAG(NO_WP_DETECT,   0x00000200)                     \
-               /* Don't check for write-protect */             \
-
-#define US_FLAG(name, value)   US_FL_##name = value ,
-enum { US_DO_ALL_FLAGS };
-#undef US_FLAG
 
 /* Dynamic flag definitions: used in set_bit() etc. */
 #define US_FLIDX_URB_ACTIVE    18  /* 0x00040000  current_urb is in use  */
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
new file mode 100644 (file)
index 0000000..f9c058f
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Interface to the libusual.
+ *
+ * Copyright (c) 2005 Pete Zaitcev <zaitcev@redhat.com>
+ * Copyright (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ * Copyright (c) 1999 Michael Gee (michael@linuxspecific.com)
+ */
+
+#ifndef __LINUX_USB_USUAL_H
+#define __LINUX_USB_USUAL_H
+
+#include <linux/config.h>
+
+/* We should do this for cleanliness... But other usb_foo.h do not do this. */
+/* #include <linux/usb.h> */
+
+/*
+ * The flags field, which we store in usb_device_id.driver_info.
+ * It is compatible with the old usb-storage flags in lower 24 bits.
+ */
+
+/*
+ * Static flag definitions.  We use this roundabout technique so that the
+ * proc_info() routine can automatically display a message for each flag.
+ */
+#define US_DO_ALL_FLAGS                                                \
+       US_FLAG(SINGLE_LUN,     0x00000001)                     \
+               /* allow access to only LUN 0 */                \
+       US_FLAG(NEED_OVERRIDE,  0x00000002)                     \
+               /* unusual_devs entry is necessary */           \
+       US_FLAG(SCM_MULT_TARG,  0x00000004)                     \
+               /* supports multiple targets */                 \
+       US_FLAG(FIX_INQUIRY,    0x00000008)                     \
+               /* INQUIRY response needs faking */             \
+       US_FLAG(FIX_CAPACITY,   0x00000010)                     \
+               /* READ CAPACITY response too big */            \
+       US_FLAG(IGNORE_RESIDUE, 0x00000020)                     \
+               /* reported residue is wrong */                 \
+       US_FLAG(BULK32,         0x00000040)                     \
+               /* Uses 32-byte CBW length */                   \
+       US_FLAG(NOT_LOCKABLE,   0x00000080)                     \
+               /* PREVENT/ALLOW not supported */               \
+       US_FLAG(GO_SLOW,        0x00000100)                     \
+               /* Need delay after Command phase */            \
+       US_FLAG(NO_WP_DETECT,   0x00000200)                     \
+               /* Don't check for write-protect */             \
+
+#define US_FLAG(name, value)   US_FL_##name = value ,
+enum { US_DO_ALL_FLAGS };
+#undef US_FLAG
+
+/*
+ * The bias field for libusual and friends.
+ */
+#define USB_US_TYPE_NONE   0
+#define USB_US_TYPE_STOR   1           /* usb-storage */
+#define USB_US_TYPE_UB     2           /* ub */
+
+#define USB_US_TYPE(flags)             (((flags) >> 24) & 0xFF)
+#define USB_US_ORIG_FLAGS(flags)       ((flags) & 0x00FFFFFF)
+
+/*
+ * This is probably not the best place to keep these constants, conceptually.
+ * But it's the only header included into all places which need them.
+ */
+
+/* Sub Classes */
+
+#define US_SC_RBC      0x01            /* Typically, flash devices */
+#define US_SC_8020     0x02            /* CD-ROM */
+#define US_SC_QIC      0x03            /* QIC-157 Tapes */
+#define US_SC_UFI      0x04            /* Floppy */
+#define US_SC_8070     0x05            /* Removable media */
+#define US_SC_SCSI     0x06            /* Transparent */
+#define US_SC_ISD200    0x07           /* ISD200 ATA */
+#define US_SC_MIN      US_SC_RBC
+#define US_SC_MAX      US_SC_ISD200
+
+#define US_SC_DEVICE   0xff            /* Use device's value */
+
+/* Protocols */
+
+#define US_PR_CBI      0x00            /* Control/Bulk/Interrupt */
+#define US_PR_CB       0x01            /* Control/Bulk w/o interrupt */
+#define US_PR_BULK     0x50            /* bulk only */
+#ifdef CONFIG_USB_STORAGE_USBAT
+#define US_PR_USBAT    0x80            /* SCM-ATAPI bridge */
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR09
+#define US_PR_EUSB_SDDR09      0x81    /* SCM-SCSI bridge for SDDR-09 */
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+#define US_PR_SDDR55   0x82            /* SDDR-55 (made up) */
+#endif
+#define US_PR_DPCM_USB  0xf0           /* Combination CB/SDDR09 */
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#define US_PR_FREECOM   0xf1           /* Freecom */
+#endif
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+#define US_PR_DATAFAB   0xf2           /* Datafab chipsets */
+#endif
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+#define US_PR_JUMPSHOT  0xf3           /* Lexar Jumpshot */
+#endif
+
+#define US_PR_DEVICE   0xff            /* Use device's value */
+
+/*
+ */
+#ifdef CONFIG_USB_LIBUSUAL
+
+extern struct usb_device_id storage_usb_ids[];
+extern void usb_usual_set_present(int type);
+extern void usb_usual_clear_present(int type);
+extern int usb_usual_check_type(const struct usb_device_id *, int type);
+#else
+
+#define usb_usual_set_present(t)       do { } while(0)
+#define usb_usual_clear_present(t)     do { } while(0)
+#define usb_usual_check_type(id, t)    (0)
+#endif /* CONFIG_USB_LIBUSUAL */
+
+#endif /* __LINUX_USB_USUAL_H */