commit b19dcd9341a81ff6e04fcec396f77eeb91570584
tree f2eebbf7142d5d36ffb44d365ad3eca539ff5127
parent 2e0a6b8cd27375089f8356e7f1ce2319059696eb
author Roman Kagan <[EMAIL PROTECTED]> 1114207621 -0700
committer Greg KH <[EMAIL PROTECTED]> 1114207621 -0700

    [PATCH] USB: scripts/mod/file2alias.c: handle numeric ranges for USB 
bcdDevice
    
    Another attempt at that...
    
    The attached patch fixes the longstanding problem with USB bcdDevice
    numeric ranges incorrectly converted into patterns for MODULE_ALIAS
    generation.  Previously it put both the lower and the upper limits into
    the pattern, dlXdhY, making it impossible to fnmatch against except for
    a few special cases, like dl*dh* or dlXdhX.
    
    The patch makes it generate multiple MODULE_ALIAS lines covering the
    whole range with fnmatch-able patterns.  E.g. for a range between 0x0001
    and 0x8345 it gives the following patterns:
    
    000[1-9]
    00[1-9]*
    0[1-9]*
    [1-7]*
    8[0-2]*
    83[0-3]*
    834[0-5]
    
    Since bcdDevice is 2 bytes wide = 4 digits in hex representation, the
    max no. of patters is 2 * 4 - 1 = 7.
    
    The values are BCD (binary-coded decimals) and not hex, so patterns
    using a dash seem to be safe regardless of locale collation order.
    
    The patch changes bcdDevice part of the alias from dlXdhY to dZ, but
    this shouldn't have big compatibility issues because fnmatch()-based
    modprobing hasn't yet been widely used.  Besides, the most common (and
    almost the only working) case of dl*dh* becomes d* and thus continues to
    work.
    
    The patch is against 2.6.12-rc2, applies to -mm3 with an offset.  The
    matching patch to fix the MODALIAS environment variable now generated by
    the usb hotplug function follows.
    
    Signed-off-by: Roman Kagan <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
    
    

Index: scripts/mod/file2alias.c
===================================================================
--- 958f2dd42626fd18ba5f85b7bab1eb4a7680ff75/scripts/mod/file2alias.c  
(mode:100644 sha1:d54b52d3bb6feca9d9af25bb9bbfcef183c71c1c)
+++ f2eebbf7142d5d36ffb44d365ad3eca539ff5127/scripts/mod/file2alias.c  
(mode:100644 sha1:32197efe67edbbd2e9619aca101c60370d4e14fd)
@@ -47,32 +47,31 @@
                 sprintf(str + strlen(str), "*");                \
 } while(0)
 
-/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */
-static int do_usb_entry(const char *filename,
-                       struct usb_device_id *id, char *alias)
+/* USB is special because the bcdDevice can be matched against a numeric range 
*/
+/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
+static void do_usb_entry(struct usb_device_id *id,
+                        unsigned int bcdDevice_initial, int 
bcdDevice_initial_digits,
+                        unsigned char range_lo, unsigned char range_hi,
+                        struct module *mod)
 {
-       id->match_flags = TO_NATIVE(id->match_flags);
-       id->idVendor = TO_NATIVE(id->idVendor);
-       id->idProduct = TO_NATIVE(id->idProduct);
-       id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
-       id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
-
-       /*
-        * Some modules (visor) have empty slots as placeholder for
-        * run-time specification that results in catch-all alias
-        */
-       if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
-               return 1;
-
+       char alias[500];
        strcpy(alias, "usb:");
        ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
            id->idVendor);
        ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
            id->idProduct);
-       ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
-           id->bcdDevice_lo);
-       ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
-           id->bcdDevice_hi);
+
+       strcat(alias, "d");
+       if (bcdDevice_initial_digits)
+               sprintf(alias + strlen(alias), "%0*X",
+                       bcdDevice_initial_digits, bcdDevice_initial);
+       if (range_lo == range_hi)
+               sprintf(alias + strlen(alias), "%u", range_lo);
+       else if (range_lo > 0 || range_hi < 9)
+               sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi);
+       if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1))
+               strcat(alias, "*");
+
        ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
            id->bDeviceClass);
        ADD(alias, "dsc",
@@ -90,7 +89,73 @@
        ADD(alias, "ip",
            id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
            id->bInterfaceProtocol);
-       return 1;
+
+       /* Always end in a wildcard, for future extension */
+       if (alias[strlen(alias)-1] != '*')
+               strcat(alias, "*");
+       buf_printf(&mod->dev_table_buf,
+                  "MODULE_ALIAS(\"%s\");\n", alias);
+}
+
+static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
+{
+       unsigned int devlo, devhi;
+       unsigned char chi, clo;
+       int ndigits;
+
+       id->match_flags = TO_NATIVE(id->match_flags);
+       id->idVendor = TO_NATIVE(id->idVendor);
+       id->idProduct = TO_NATIVE(id->idProduct);
+
+       devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ?
+               TO_NATIVE(id->bcdDevice_lo) : 0x0U;
+       devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
+               TO_NATIVE(id->bcdDevice_hi) : ~0x0U;
+
+       /*
+        * Some modules (visor) have empty slots as placeholder for
+        * run-time specification that results in catch-all alias
+        */
+       if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
+               return;
+
+       /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
+       for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; 
ndigits--) {
+               clo = devlo & 0xf;
+               chi = devhi & 0xf;
+               if (chi > 9)    /* it's bcd not hex */
+                       chi = 9;
+               devlo >>= 4;
+               devhi >>= 4;
+
+               if (devlo == devhi || !ndigits) {
+                       do_usb_entry(id, devlo, ndigits, clo, chi, mod);
+                       break;
+               }
+
+               if (clo > 0)
+                       do_usb_entry(id, devlo++, ndigits, clo, 9, mod);
+
+               if (chi < 9)
+                       do_usb_entry(id, devhi--, ndigits, 0, chi, mod);
+       }
+}
+
+static void do_usb_table(void *symval, unsigned long size,
+                        struct module *mod)
+{
+       unsigned int i;
+       const unsigned long id_size = sizeof(struct usb_device_id);
+
+       if (size % id_size || size < id_size) {
+               fprintf(stderr, "*** Warning: %s ids %lu bad size "
+                       "(each on %lu)\n", mod->name, size, id_size);
+       }
+       /* Leave last one: it's the terminator. */
+       size -= id_size;
+
+       for (i = 0; i < size; i += id_size)
+               do_usb_entry_multi(symval + i, mod);
 }
 
 /* Looks like: ieee1394:venNmoNspNverN */
@@ -280,8 +345,8 @@
                do_table(symval, sym->st_size, sizeof(struct pci_device_id),
                         do_pci_entry, mod);
        else if (sym_is(symname, "__mod_usb_device_table"))
-               do_table(symval, sym->st_size, sizeof(struct usb_device_id),
-                        do_usb_entry, mod);
+               /* special case to handle bcdDevice ranges */
+               do_usb_table(symval, sym->st_size, mod);
        else if (sym_is(symname, "__mod_ieee1394_device_table"))
                do_table(symval, sym->st_size, sizeof(struct 
ieee1394_device_id),
                         do_ieee1394_entry, mod);



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id396&op=click
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to