aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/mod
diff options
context:
space:
mode:
authorRoman Kagan <rkagan@mail.ru>2005-04-22 18:07:01 -0400
committerGreg KH <gregkh@suse.de>2005-04-22 18:07:01 -0400
commitb19dcd9341a81ff6e04fcec396f77eeb91570584 (patch)
treef2eebbf7142d5d36ffb44d365ad3eca539ff5127 /scripts/mod
parent2e0a6b8cd27375089f8356e7f1ce2319059696eb (diff)
[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 <rkagan@mail.ru> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'scripts/mod')
-rw-r--r--scripts/mod/file2alias.c111
1 files changed, 88 insertions, 23 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index d54b52d3bb6f..32197efe67ed 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -47,32 +47,31 @@ do { \
47 sprintf(str + strlen(str), "*"); \ 47 sprintf(str + strlen(str), "*"); \
48} while(0) 48} while(0)
49 49
50/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */ 50/* USB is special because the bcdDevice can be matched against a numeric range */
51static int do_usb_entry(const char *filename, 51/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */
52 struct usb_device_id *id, char *alias) 52static void do_usb_entry(struct usb_device_id *id,
53 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
54 unsigned char range_lo, unsigned char range_hi,
55 struct module *mod)
53{ 56{
54 id->match_flags = TO_NATIVE(id->match_flags); 57 char alias[500];
55 id->idVendor = TO_NATIVE(id->idVendor);
56 id->idProduct = TO_NATIVE(id->idProduct);
57 id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
58 id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
59
60 /*
61 * Some modules (visor) have empty slots as placeholder for
62 * run-time specification that results in catch-all alias
63 */
64 if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
65 return 1;
66
67 strcpy(alias, "usb:"); 58 strcpy(alias, "usb:");
68 ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, 59 ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
69 id->idVendor); 60 id->idVendor);
70 ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT, 61 ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
71 id->idProduct); 62 id->idProduct);
72 ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO, 63
73 id->bcdDevice_lo); 64 strcat(alias, "d");
74 ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI, 65 if (bcdDevice_initial_digits)
75 id->bcdDevice_hi); 66 sprintf(alias + strlen(alias), "%0*X",
67 bcdDevice_initial_digits, bcdDevice_initial);
68 if (range_lo == range_hi)
69 sprintf(alias + strlen(alias), "%u", range_lo);
70 else if (range_lo > 0 || range_hi < 9)
71 sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi);
72 if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1))
73 strcat(alias, "*");
74
76 ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, 75 ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
77 id->bDeviceClass); 76 id->bDeviceClass);
78 ADD(alias, "dsc", 77 ADD(alias, "dsc",
@@ -90,7 +89,73 @@ static int do_usb_entry(const char *filename,
90 ADD(alias, "ip", 89 ADD(alias, "ip",
91 id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, 90 id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
92 id->bInterfaceProtocol); 91 id->bInterfaceProtocol);
93 return 1; 92
93 /* Always end in a wildcard, for future extension */
94 if (alias[strlen(alias)-1] != '*')
95 strcat(alias, "*");
96 buf_printf(&mod->dev_table_buf,
97 "MODULE_ALIAS(\"%s\");\n", alias);
98}
99
100static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
101{
102 unsigned int devlo, devhi;
103 unsigned char chi, clo;
104 int ndigits;
105
106 id->match_flags = TO_NATIVE(id->match_flags);
107 id->idVendor = TO_NATIVE(id->idVendor);
108 id->idProduct = TO_NATIVE(id->idProduct);
109
110 devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ?
111 TO_NATIVE(id->bcdDevice_lo) : 0x0U;
112 devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
113 TO_NATIVE(id->bcdDevice_hi) : ~0x0U;
114
115 /*
116 * Some modules (visor) have empty slots as placeholder for
117 * run-time specification that results in catch-all alias
118 */
119 if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
120 return;
121
122 /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
123 for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {
124 clo = devlo & 0xf;
125 chi = devhi & 0xf;
126 if (chi > 9) /* it's bcd not hex */
127 chi = 9;
128 devlo >>= 4;
129 devhi >>= 4;
130
131 if (devlo == devhi || !ndigits) {
132 do_usb_entry(id, devlo, ndigits, clo, chi, mod);
133 break;
134 }
135
136 if (clo > 0)
137 do_usb_entry(id, devlo++, ndigits, clo, 9, mod);
138
139 if (chi < 9)
140 do_usb_entry(id, devhi--, ndigits, 0, chi, mod);
141 }
142}
143
144static void do_usb_table(void *symval, unsigned long size,
145 struct module *mod)
146{
147 unsigned int i;
148 const unsigned long id_size = sizeof(struct usb_device_id);
149
150 if (size % id_size || size < id_size) {
151 fprintf(stderr, "*** Warning: %s ids %lu bad size "
152 "(each on %lu)\n", mod->name, size, id_size);
153 }
154 /* Leave last one: it's the terminator. */
155 size -= id_size;
156
157 for (i = 0; i < size; i += id_size)
158 do_usb_entry_multi(symval + i, mod);
94} 159}
95 160
96/* Looks like: ieee1394:venNmoNspNverN */ 161/* Looks like: ieee1394:venNmoNspNverN */
@@ -280,8 +345,8 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
280 do_table(symval, sym->st_size, sizeof(struct pci_device_id), 345 do_table(symval, sym->st_size, sizeof(struct pci_device_id),
281 do_pci_entry, mod); 346 do_pci_entry, mod);
282 else if (sym_is(symname, "__mod_usb_device_table")) 347 else if (sym_is(symname, "__mod_usb_device_table"))
283 do_table(symval, sym->st_size, sizeof(struct usb_device_id), 348 /* special case to handle bcdDevice ranges */
284 do_usb_entry, mod); 349 do_usb_table(symval, sym->st_size, mod);
285 else if (sym_is(symname, "__mod_ieee1394_device_table")) 350 else if (sym_is(symname, "__mod_ieee1394_device_table"))
286 do_table(symval, sym->st_size, sizeof(struct ieee1394_device_id), 351 do_table(symval, sym->st_size, sizeof(struct ieee1394_device_id),
287 do_ieee1394_entry, mod); 352 do_ieee1394_entry, mod);