aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);