Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* Simple code to turn various tables in an ELF file into alias definitions. |
2 | * This deals with kernel datastructures where they should be | |
3 | * dealt with: in the kernel source. | |
4 | * | |
5 | * Copyright 2002-2003 Rusty Russell, IBM Corporation | |
6 | * 2003 Kai Germaschewski | |
7 | * | |
8 | * | |
9 | * This software may be used and distributed according to the terms | |
10 | * of the GNU General Public License, incorporated herein by reference. | |
11 | */ | |
12 | ||
f4fdb17c MY |
13 | #include <stdarg.h> |
14 | #include <stdio.h> | |
15 | ||
16 | #include "list.h" | |
17 | #include "xalloc.h" | |
18 | ||
1da177e4 | 19 | #include "modpost.h" |
6543becf | 20 | #include "devicetable-offsets.h" |
1da177e4 LT |
21 | |
22 | /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and | |
23 | * use either stdint.h or inttypes.h for the rest. */ | |
24 | #if KERNEL_ELFCLASS == ELFCLASS32 | |
25 | typedef Elf32_Addr kernel_ulong_t; | |
1d8f430c | 26 | #define BITS_PER_LONG 32 |
1da177e4 LT |
27 | #else |
28 | typedef Elf64_Addr kernel_ulong_t; | |
1d8f430c | 29 | #define BITS_PER_LONG 64 |
1da177e4 LT |
30 | #endif |
31 | #ifdef __sun__ | |
32 | #include <inttypes.h> | |
33 | #else | |
34 | #include <stdint.h> | |
35 | #endif | |
36 | ||
5e655772 | 37 | #include <ctype.h> |
626596e2 | 38 | #include <stdbool.h> |
5e655772 | 39 | |
f4fdb17c MY |
40 | /** |
41 | * module_alias_printf - add auto-generated MODULE_ALIAS() | |
42 | * | |
43 | * @mod: module | |
44 | * @append_wildcard: append '*' for future extension if not exist yet | |
45 | * @fmt: printf(3)-like format | |
46 | */ | |
47 | static void __attribute__((format (printf, 3, 4))) | |
48 | module_alias_printf(struct module *mod, bool append_wildcard, | |
49 | const char *fmt, ...) | |
50 | { | |
d92b7a3b | 51 | struct module_alias *new, *als; |
f4fdb17c MY |
52 | size_t len; |
53 | int n; | |
54 | va_list ap; | |
55 | ||
56 | /* Determine required size. */ | |
57 | va_start(ap, fmt); | |
58 | n = vsnprintf(NULL, 0, fmt, ap); | |
59 | va_end(ap); | |
60 | ||
61 | if (n < 0) { | |
62 | error("vsnprintf failed\n"); | |
63 | return; | |
64 | } | |
65 | ||
66 | len = n + 1; /* extra byte for '\0' */ | |
67 | ||
68 | if (append_wildcard) | |
69 | len++; /* extra byte for '*' */ | |
70 | ||
71 | new = xmalloc(sizeof(*new) + len); | |
72 | ||
73 | /* Now, really print it to the allocated buffer */ | |
74 | va_start(ap, fmt); | |
75 | n = vsnprintf(new->str, len, fmt, ap); | |
76 | va_end(ap); | |
77 | ||
78 | if (n < 0) { | |
79 | error("vsnprintf failed\n"); | |
80 | free(new); | |
81 | return; | |
82 | } | |
83 | ||
84 | if (append_wildcard && (n == 0 || new->str[n - 1] != '*')) { | |
85 | new->str[n] = '*'; | |
86 | new->str[n + 1] = '\0'; | |
87 | } | |
88 | ||
d92b7a3b MY |
89 | /* avoid duplication */ |
90 | list_for_each_entry(als, &mod->aliases, node) { | |
91 | if (!strcmp(als->str, new->str)) { | |
92 | free(new); | |
93 | return; | |
94 | } | |
95 | } | |
96 | ||
f4fdb17c MY |
97 | list_add_tail(&new->node, &mod->aliases); |
98 | } | |
99 | ||
1da177e4 LT |
100 | typedef uint32_t __u32; |
101 | typedef uint16_t __u16; | |
102 | typedef unsigned char __u8; | |
24804329 AS |
103 | |
104 | /* UUID types for backward compatibility, don't use in new code */ | |
389c9af7 HK |
105 | typedef struct { |
106 | __u8 b[16]; | |
107 | } guid_t; | |
108 | ||
0fc1db9d SG |
109 | typedef struct { |
110 | __u8 b[16]; | |
111 | } uuid_t; | |
24804329 | 112 | |
eacc95ea | 113 | #define UUID_STRING_LEN 36 |
1da177e4 | 114 | |
24804329 AS |
115 | /* MEI UUID type, don't use anywhere else */ |
116 | typedef struct { | |
117 | __u8 b[16]; | |
118 | } uuid_le; | |
119 | ||
1da177e4 | 120 | /* Big exception to the "don't include kernel headers into userspace, which |
62070fa4 | 121 | * even potentially has different endianness and word sizes, since |
1da177e4 LT |
122 | * we handle those differences explicitly below */ |
123 | #include "../../include/linux/mod_devicetable.h" | |
124 | ||
e49ce141 | 125 | struct devtable { |
054a9cd3 | 126 | const char *device_id; |
e49ce141 | 127 | unsigned long id_size; |
6d3b3dd2 | 128 | void (*do_entry)(struct module *mod, void *symval); |
e49ce141 RR |
129 | }; |
130 | ||
6543becf AS |
131 | /* Define a variable f that holds the value of field f of struct devid |
132 | * based at address m. | |
133 | */ | |
134 | #define DEF_FIELD(m, devid, f) \ | |
8fe1a63d MY |
135 | typeof(((struct devid *)0)->f) f = \ |
136 | get_unaligned_native((typeof(f) *)((m) + OFF_##devid##_##f)) | |
c2b1a922 | 137 | |
6543becf AS |
138 | /* Define a variable f that holds the address of field f of struct devid |
139 | * based at address m. Due to the way typeof works, for a field of type | |
140 | * T[N] the variable has type T(*)[N], _not_ T*. | |
141 | */ | |
142 | #define DEF_FIELD_ADDR(m, devid, f) \ | |
c4d1a9f9 | 143 | typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) |
6543becf | 144 | |
1da177e4 LT |
145 | #define ADD(str, sep, cond, field) \ |
146 | do { \ | |
147 | strcat(str, sep); \ | |
148 | if (cond) \ | |
149 | sprintf(str + strlen(str), \ | |
150 | sizeof(field) == 1 ? "%02X" : \ | |
151 | sizeof(field) == 2 ? "%04X" : \ | |
152 | sizeof(field) == 4 ? "%08X" : "", \ | |
153 | field); \ | |
154 | else \ | |
155 | sprintf(str + strlen(str), "*"); \ | |
156 | } while(0) | |
157 | ||
b144ce2d | 158 | static inline void add_uuid(char *str, uuid_le uuid) |
c93b76b3 TW |
159 | { |
160 | int len = strlen(str); | |
c93b76b3 | 161 | |
59796edc PB |
162 | sprintf(str + len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
163 | uuid.b[3], uuid.b[2], uuid.b[1], uuid.b[0], | |
164 | uuid.b[5], uuid.b[4], uuid.b[7], uuid.b[6], | |
165 | uuid.b[8], uuid.b[9], uuid.b[10], uuid.b[11], | |
166 | uuid.b[12], uuid.b[13], uuid.b[14], uuid.b[15]); | |
c93b76b3 TW |
167 | } |
168 | ||
fa443bc3 TW |
169 | static inline void add_guid(char *str, guid_t guid) |
170 | { | |
171 | int len = strlen(str); | |
172 | ||
173 | sprintf(str + len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", | |
174 | guid.b[3], guid.b[2], guid.b[1], guid.b[0], | |
175 | guid.b[5], guid.b[4], guid.b[7], guid.b[6], | |
176 | guid.b[8], guid.b[9], guid.b[10], guid.b[11], | |
177 | guid.b[12], guid.b[13], guid.b[14], guid.b[15]); | |
178 | } | |
179 | ||
b19dcd93 | 180 | /* USB is special because the bcdDevice can be matched against a numeric range */ |
81df2d59 | 181 | /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ |
6543becf | 182 | static void do_usb_entry(void *symval, |
b19dcd93 RK |
183 | unsigned int bcdDevice_initial, int bcdDevice_initial_digits, |
184 | unsigned char range_lo, unsigned char range_hi, | |
afe2dab4 | 185 | unsigned char max, struct module *mod) |
1da177e4 | 186 | { |
b19dcd93 | 187 | char alias[500]; |
6543becf AS |
188 | DEF_FIELD(symval, usb_device_id, match_flags); |
189 | DEF_FIELD(symval, usb_device_id, idVendor); | |
190 | DEF_FIELD(symval, usb_device_id, idProduct); | |
191 | DEF_FIELD(symval, usb_device_id, bcdDevice_lo); | |
192 | DEF_FIELD(symval, usb_device_id, bDeviceClass); | |
193 | DEF_FIELD(symval, usb_device_id, bDeviceSubClass); | |
194 | DEF_FIELD(symval, usb_device_id, bDeviceProtocol); | |
195 | DEF_FIELD(symval, usb_device_id, bInterfaceClass); | |
196 | DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); | |
197 | DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); | |
198 | DEF_FIELD(symval, usb_device_id, bInterfaceNumber); | |
199 | ||
1da177e4 | 200 | strcpy(alias, "usb:"); |
6543becf AS |
201 | ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, |
202 | idVendor); | |
203 | ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, | |
204 | idProduct); | |
b19dcd93 RK |
205 | |
206 | strcat(alias, "d"); | |
207 | if (bcdDevice_initial_digits) | |
208 | sprintf(alias + strlen(alias), "%0*X", | |
209 | bcdDevice_initial_digits, bcdDevice_initial); | |
210 | if (range_lo == range_hi) | |
afe2dab4 NM |
211 | sprintf(alias + strlen(alias), "%X", range_lo); |
212 | else if (range_lo > 0 || range_hi < max) { | |
213 | if (range_lo > 0x9 || range_hi < 0xA) | |
214 | sprintf(alias + strlen(alias), | |
215 | "[%X-%X]", | |
216 | range_lo, | |
217 | range_hi); | |
218 | else { | |
219 | sprintf(alias + strlen(alias), | |
220 | range_lo < 0x9 ? "[%X-9" : "[%X", | |
221 | range_lo); | |
222 | sprintf(alias + strlen(alias), | |
03b56329 JMM |
223 | range_hi > 0xA ? "A-%X]" : "%X]", |
224 | range_hi); | |
afe2dab4 NM |
225 | } |
226 | } | |
6543becf | 227 | if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) |
b19dcd93 RK |
228 | strcat(alias, "*"); |
229 | ||
6543becf AS |
230 | ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, |
231 | bDeviceClass); | |
232 | ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, | |
233 | bDeviceSubClass); | |
234 | ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, | |
235 | bDeviceProtocol); | |
236 | ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, | |
237 | bInterfaceClass); | |
238 | ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, | |
239 | bInterfaceSubClass); | |
240 | ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, | |
241 | bInterfaceProtocol); | |
242 | ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, | |
243 | bInterfaceNumber); | |
b19dcd93 | 244 | |
f4fdb17c | 245 | module_alias_printf(mod, true, "%s", alias); |
b19dcd93 RK |
246 | } |
247 | ||
55f49f26 NM |
248 | /* Handles increment/decrement of BCD formatted integers */ |
249 | /* Returns the previous value, so it works like i++ or i-- */ | |
250 | static unsigned int incbcd(unsigned int *bcd, | |
251 | int inc, | |
252 | unsigned char max, | |
253 | size_t chars) | |
254 | { | |
255 | unsigned int init = *bcd, i, j; | |
256 | unsigned long long c, dec = 0; | |
257 | ||
258 | /* If bcd is not in BCD format, just increment */ | |
259 | if (max > 0x9) { | |
260 | *bcd += inc; | |
261 | return init; | |
262 | } | |
263 | ||
264 | /* Convert BCD to Decimal */ | |
265 | for (i=0 ; i < chars ; i++) { | |
266 | c = (*bcd >> (i << 2)) & 0xf; | |
267 | c = c > 9 ? 9 : c; /* force to bcd just in case */ | |
268 | for (j=0 ; j < i ; j++) | |
269 | c = c * 10; | |
270 | dec += c; | |
271 | } | |
272 | ||
273 | /* Do our increment/decrement */ | |
274 | dec += inc; | |
275 | *bcd = 0; | |
276 | ||
277 | /* Convert back to BCD */ | |
278 | for (i=0 ; i < chars ; i++) { | |
279 | for (c=1,j=0 ; j < i ; j++) | |
280 | c = c * 10; | |
281 | c = (dec / c) % 10; | |
282 | *bcd += c << (i << 2); | |
283 | } | |
284 | return init; | |
285 | } | |
286 | ||
abd20428 | 287 | static void do_usb_entry_multi(struct module *mod, void *symval) |
b19dcd93 RK |
288 | { |
289 | unsigned int devlo, devhi; | |
afe2dab4 | 290 | unsigned char chi, clo, max; |
b19dcd93 RK |
291 | int ndigits; |
292 | ||
6543becf AS |
293 | DEF_FIELD(symval, usb_device_id, match_flags); |
294 | DEF_FIELD(symval, usb_device_id, idVendor); | |
295 | DEF_FIELD(symval, usb_device_id, idProduct); | |
296 | DEF_FIELD(symval, usb_device_id, bcdDevice_lo); | |
297 | DEF_FIELD(symval, usb_device_id, bcdDevice_hi); | |
298 | DEF_FIELD(symval, usb_device_id, bDeviceClass); | |
299 | DEF_FIELD(symval, usb_device_id, bInterfaceClass); | |
b19dcd93 | 300 | |
6543becf AS |
301 | devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? |
302 | bcdDevice_lo : 0x0U; | |
303 | devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? | |
304 | bcdDevice_hi : ~0x0U; | |
b19dcd93 | 305 | |
afe2dab4 NM |
306 | /* Figure out if this entry is in bcd or hex format */ |
307 | max = 0x9; /* Default to decimal format */ | |
6543becf | 308 | for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) { |
afe2dab4 NM |
309 | clo = (devlo >> (ndigits << 2)) & 0xf; |
310 | chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf; | |
311 | if (clo > max || chi > max) { | |
312 | max = 0xf; | |
313 | break; | |
314 | } | |
315 | } | |
316 | ||
b19dcd93 RK |
317 | /* |
318 | * Some modules (visor) have empty slots as placeholder for | |
319 | * run-time specification that results in catch-all alias | |
320 | */ | |
6543becf | 321 | if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass)) |
b19dcd93 RK |
322 | return; |
323 | ||
324 | /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ | |
6543becf | 325 | for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { |
b19dcd93 RK |
326 | clo = devlo & 0xf; |
327 | chi = devhi & 0xf; | |
afe2dab4 NM |
328 | if (chi > max) /* If we are in bcd mode, truncate if necessary */ |
329 | chi = max; | |
b19dcd93 RK |
330 | devlo >>= 4; |
331 | devhi >>= 4; | |
332 | ||
333 | if (devlo == devhi || !ndigits) { | |
6543becf | 334 | do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod); |
b19dcd93 RK |
335 | break; |
336 | } | |
337 | ||
afe2dab4 | 338 | if (clo > 0x0) |
6543becf | 339 | do_usb_entry(symval, |
55f49f26 | 340 | incbcd(&devlo, 1, max, |
6543becf | 341 | sizeof(bcdDevice_lo) * 2), |
55f49f26 | 342 | ndigits, clo, max, max, mod); |
b19dcd93 | 343 | |
afe2dab4 | 344 | if (chi < max) |
6543becf | 345 | do_usb_entry(symval, |
55f49f26 | 346 | incbcd(&devhi, -1, max, |
6543becf | 347 | sizeof(bcdDevice_lo) * 2), |
55f49f26 | 348 | ndigits, 0x0, chi, max, mod); |
b19dcd93 RK |
349 | } |
350 | } | |
351 | ||
c58854c8 | 352 | static void do_of_entry(struct module *mod, void *symval) |
acbef7b7 PZ |
353 | { |
354 | char alias[500]; | |
355 | int len; | |
356 | char *tmp; | |
357 | ||
358 | DEF_FIELD_ADDR(symval, of_device_id, name); | |
359 | DEF_FIELD_ADDR(symval, of_device_id, type); | |
360 | DEF_FIELD_ADDR(symval, of_device_id, compatible); | |
361 | ||
362 | len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", | |
363 | (*type)[0] ? *type : "*"); | |
364 | ||
b3c0a4da | 365 | if ((*compatible)[0]) |
acbef7b7 PZ |
366 | sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", |
367 | *compatible); | |
368 | ||
369 | /* Replace all whitespace with underscores */ | |
370 | for (tmp = alias; tmp && *tmp; tmp++) | |
371 | if (isspace(*tmp)) | |
372 | *tmp = '_'; | |
373 | ||
f4fdb17c MY |
374 | module_alias_printf(mod, false, "%s", alias); |
375 | module_alias_printf(mod, false, "%sC*", alias); | |
acbef7b7 PZ |
376 | } |
377 | ||
e8c84f9a | 378 | /* Looks like: hid:bNvNpN */ |
6d3b3dd2 | 379 | static void do_hid_entry(struct module *mod, void *symval) |
e8c84f9a | 380 | { |
6d3b3dd2 MY |
381 | char alias[256] = {}; |
382 | ||
6543becf AS |
383 | DEF_FIELD(symval, hid_device_id, bus); |
384 | DEF_FIELD(symval, hid_device_id, group); | |
385 | DEF_FIELD(symval, hid_device_id, vendor); | |
386 | DEF_FIELD(symval, hid_device_id, product); | |
e8c84f9a | 387 | |
6543becf AS |
388 | ADD(alias, "b", bus != HID_BUS_ANY, bus); |
389 | ADD(alias, "g", group != HID_GROUP_ANY, group); | |
390 | ADD(alias, "v", vendor != HID_ANY_ID, vendor); | |
391 | ADD(alias, "p", product != HID_ANY_ID, product); | |
e8c84f9a | 392 | |
6d3b3dd2 | 393 | module_alias_printf(mod, false, "hid:%s", alias); |
e8c84f9a JS |
394 | } |
395 | ||
1da177e4 | 396 | /* Looks like: ieee1394:venNmoNspNverN */ |
6d3b3dd2 | 397 | static void do_ieee1394_entry(struct module *mod, void *symval) |
1da177e4 | 398 | { |
6d3b3dd2 MY |
399 | char alias[256] = {}; |
400 | ||
6543becf AS |
401 | DEF_FIELD(symval, ieee1394_device_id, match_flags); |
402 | DEF_FIELD(symval, ieee1394_device_id, vendor_id); | |
403 | DEF_FIELD(symval, ieee1394_device_id, model_id); | |
404 | DEF_FIELD(symval, ieee1394_device_id, specifier_id); | |
405 | DEF_FIELD(symval, ieee1394_device_id, version); | |
1da177e4 | 406 | |
6543becf AS |
407 | ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, |
408 | vendor_id); | |
409 | ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, | |
410 | model_id); | |
411 | ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, | |
412 | specifier_id); | |
413 | ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, | |
414 | version); | |
1da177e4 | 415 | |
6d3b3dd2 | 416 | module_alias_printf(mod, true, "ieee1394:%s", alias); |
1da177e4 LT |
417 | } |
418 | ||
cc6711b0 | 419 | /* Looks like: pci:vNdNsvNsdNbcNscNiN or <prefix>_pci:vNdNsvNsdNbcNscNiN. */ |
6d3b3dd2 | 420 | static void do_pci_entry(struct module *mod, void *symval) |
1da177e4 | 421 | { |
6d3b3dd2 | 422 | char alias[256]; |
1da177e4 LT |
423 | /* Class field can be divided into these three. */ |
424 | unsigned char baseclass, subclass, interface, | |
425 | baseclass_mask, subclass_mask, interface_mask; | |
426 | ||
6543becf AS |
427 | DEF_FIELD(symval, pci_device_id, vendor); |
428 | DEF_FIELD(symval, pci_device_id, device); | |
429 | DEF_FIELD(symval, pci_device_id, subvendor); | |
430 | DEF_FIELD(symval, pci_device_id, subdevice); | |
431 | DEF_FIELD(symval, pci_device_id, class); | |
432 | DEF_FIELD(symval, pci_device_id, class_mask); | |
cc6711b0 MG |
433 | DEF_FIELD(symval, pci_device_id, override_only); |
434 | ||
435 | switch (override_only) { | |
436 | case 0: | |
437 | strcpy(alias, "pci:"); | |
438 | break; | |
439 | case PCI_ID_F_VFIO_DRIVER_OVERRIDE: | |
440 | strcpy(alias, "vfio_pci:"); | |
441 | break; | |
442 | default: | |
443 | warn("Unknown PCI driver_override alias %08X\n", | |
444 | override_only); | |
cc6711b0 | 445 | } |
1da177e4 | 446 | |
6543becf AS |
447 | ADD(alias, "v", vendor != PCI_ANY_ID, vendor); |
448 | ADD(alias, "d", device != PCI_ANY_ID, device); | |
449 | ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); | |
450 | ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); | |
451 | ||
452 | baseclass = (class) >> 16; | |
453 | baseclass_mask = (class_mask) >> 16; | |
454 | subclass = (class) >> 8; | |
455 | subclass_mask = (class_mask) >> 8; | |
456 | interface = class; | |
457 | interface_mask = class_mask; | |
1da177e4 LT |
458 | |
459 | if ((baseclass_mask != 0 && baseclass_mask != 0xFF) | |
460 | || (subclass_mask != 0 && subclass_mask != 0xFF) | |
461 | || (interface_mask != 0 && interface_mask != 0xFF)) { | |
cb80514d | 462 | warn("Can't handle masks in %s:%04X\n", |
c7c24d60 | 463 | mod->name, class_mask); |
6d3b3dd2 | 464 | return; |
1da177e4 LT |
465 | } |
466 | ||
467 | ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); | |
468 | ADD(alias, "sc", subclass_mask == 0xFF, subclass); | |
469 | ADD(alias, "i", interface_mask == 0xFF, interface); | |
6d3b3dd2 MY |
470 | |
471 | module_alias_printf(mod, true, "%s", alias); | |
1da177e4 LT |
472 | } |
473 | ||
62070fa4 | 474 | /* looks like: "ccw:tNmNdtNdmN" */ |
6d3b3dd2 | 475 | static void do_ccw_entry(struct module *mod, void *symval) |
1da177e4 | 476 | { |
6d3b3dd2 MY |
477 | char alias[256] = {}; |
478 | ||
6543becf AS |
479 | DEF_FIELD(symval, ccw_device_id, match_flags); |
480 | DEF_FIELD(symval, ccw_device_id, cu_type); | |
481 | DEF_FIELD(symval, ccw_device_id, cu_model); | |
482 | DEF_FIELD(symval, ccw_device_id, dev_type); | |
483 | DEF_FIELD(symval, ccw_device_id, dev_model); | |
1da177e4 | 484 | |
6543becf AS |
485 | ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, |
486 | cu_type); | |
487 | ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, | |
488 | cu_model); | |
489 | ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, | |
490 | dev_type); | |
491 | ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, | |
492 | dev_model); | |
6d3b3dd2 MY |
493 | |
494 | module_alias_printf(mod, true, "ccw:%s", alias); | |
1da177e4 LT |
495 | } |
496 | ||
1534c382 | 497 | /* looks like: "ap:tN" */ |
6d3b3dd2 | 498 | static void do_ap_entry(struct module *mod, void *symval) |
1534c382 | 499 | { |
6543becf AS |
500 | DEF_FIELD(symval, ap_device_id, dev_type); |
501 | ||
6d3b3dd2 | 502 | module_alias_printf(mod, false, "ap:t%02X*", dev_type); |
1534c382 MS |
503 | } |
504 | ||
7e9db9ea | 505 | /* looks like: "css:tN" */ |
6d3b3dd2 | 506 | static void do_css_entry(struct module *mod, void *symval) |
7e9db9ea | 507 | { |
6543becf AS |
508 | DEF_FIELD(symval, css_device_id, type); |
509 | ||
6d3b3dd2 | 510 | module_alias_printf(mod, false, "css:t%01X", type); |
7e9db9ea CH |
511 | } |
512 | ||
1da177e4 | 513 | /* Looks like: "serio:tyNprNidNexN" */ |
6d3b3dd2 | 514 | static void do_serio_entry(struct module *mod, void *symval) |
1da177e4 | 515 | { |
6d3b3dd2 MY |
516 | char alias[256] = {}; |
517 | ||
6543becf AS |
518 | DEF_FIELD(symval, serio_device_id, type); |
519 | DEF_FIELD(symval, serio_device_id, proto); | |
520 | DEF_FIELD(symval, serio_device_id, id); | |
521 | DEF_FIELD(symval, serio_device_id, extra); | |
1da177e4 | 522 | |
6543becf AS |
523 | ADD(alias, "ty", type != SERIO_ANY, type); |
524 | ADD(alias, "pr", proto != SERIO_ANY, proto); | |
525 | ADD(alias, "id", id != SERIO_ANY, id); | |
526 | ADD(alias, "ex", extra != SERIO_ANY, extra); | |
1da177e4 | 527 | |
6d3b3dd2 | 528 | module_alias_printf(mod, true, "serio:%s", alias); |
1da177e4 LT |
529 | } |
530 | ||
26095a01 SS |
531 | /* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or |
532 | * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) | |
533 | * | |
534 | * NOTE: Each driver should use one of the following : _HID, _CIDs | |
535 | * or _CLS. Also, bb, ss, and pp can be substituted with ?? | |
536 | * as don't care byte. | |
537 | */ | |
6d3b3dd2 | 538 | static void do_acpi_entry(struct module *mod, void *symval) |
29b71a1c | 539 | { |
6543becf | 540 | DEF_FIELD_ADDR(symval, acpi_device_id, id); |
2e766a1f MY |
541 | DEF_FIELD(symval, acpi_device_id, cls); |
542 | DEF_FIELD(symval, acpi_device_id, cls_msk); | |
26095a01 | 543 | |
b7bca42d | 544 | if ((*id)[0]) |
6d3b3dd2 | 545 | module_alias_printf(mod, false, "acpi*:%s:*", *id); |
2e766a1f | 546 | else { |
6d3b3dd2 | 547 | char alias[256]; |
26095a01 SS |
548 | int i, byte_shift, cnt = 0; |
549 | unsigned int msk; | |
550 | ||
26095a01 SS |
551 | for (i = 1; i <= 3; i++) { |
552 | byte_shift = 8 * (3-i); | |
2e766a1f | 553 | msk = (cls_msk >> byte_shift) & 0xFF; |
26095a01 SS |
554 | if (msk) |
555 | sprintf(&alias[cnt], "%02x", | |
2e766a1f | 556 | (cls >> byte_shift) & 0xFF); |
26095a01 SS |
557 | else |
558 | sprintf(&alias[cnt], "??"); | |
559 | cnt += 2; | |
560 | } | |
6d3b3dd2 | 561 | module_alias_printf(mod, false, "acpi*:%s:*", alias); |
26095a01 | 562 | } |
29b71a1c TR |
563 | } |
564 | ||
1da177e4 | 565 | /* looks like: "pnp:dD" */ |
600dbaf1 | 566 | static void do_pnp_device_entry(struct module *mod, void *symval) |
1da177e4 | 567 | { |
600dbaf1 MY |
568 | DEF_FIELD_ADDR(symval, pnp_device_id, id); |
569 | char acpi_id[sizeof(*id)]; | |
72638f59 | 570 | |
600dbaf1 MY |
571 | /* fix broken pnp bus lowercasing */ |
572 | for (unsigned int i = 0; i < sizeof(acpi_id); i++) | |
573 | acpi_id[i] = toupper((*id)[i]); | |
574 | module_alias_printf(mod, false, "pnp:d%s*", *id); | |
575 | module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); | |
1da177e4 LT |
576 | } |
577 | ||
0c81eed4 | 578 | /* looks like: "pnp:dD" for every device of the card */ |
a5d8d417 | 579 | static void do_pnp_card_entry(struct module *mod, void *symval) |
1da177e4 | 580 | { |
a5d8d417 | 581 | DEF_FIELD_ADDR(symval, pnp_card_device_id, devs); |
0c81eed4 | 582 | |
a5d8d417 MY |
583 | for (unsigned int i = 0; i < PNP_MAX_DEVICES; i++) { |
584 | const char *id = (char *)(*devs)[i].id; | |
585 | char acpi_id[PNP_ID_LEN]; | |
0c81eed4 | 586 | |
a5d8d417 MY |
587 | if (!id[0]) |
588 | break; | |
0c81eed4 | 589 | |
a5d8d417 MY |
590 | /* fix broken pnp bus lowercasing */ |
591 | for (unsigned int j = 0; j < sizeof(acpi_id); j++) | |
592 | acpi_id[j] = toupper(id[j]); | |
72638f59 | 593 | |
a5d8d417 MY |
594 | /* add an individual alias for every device entry */ |
595 | module_alias_printf(mod, false, "pnp:d%s*", id); | |
596 | module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); | |
1da177e4 | 597 | } |
1da177e4 LT |
598 | } |
599 | ||
90829cfe | 600 | /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ |
6d3b3dd2 | 601 | static void do_pcmcia_entry(struct module *mod, void *symval) |
90829cfe | 602 | { |
6d3b3dd2 | 603 | char alias[256] = {}; |
8fe1a63d | 604 | |
6543becf AS |
605 | DEF_FIELD(symval, pcmcia_device_id, match_flags); |
606 | DEF_FIELD(symval, pcmcia_device_id, manf_id); | |
607 | DEF_FIELD(symval, pcmcia_device_id, card_id); | |
608 | DEF_FIELD(symval, pcmcia_device_id, func_id); | |
609 | DEF_FIELD(symval, pcmcia_device_id, function); | |
610 | DEF_FIELD(symval, pcmcia_device_id, device_no); | |
611 | DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash); | |
4fb7edce | 612 | |
6543becf AS |
613 | ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, |
614 | manf_id); | |
615 | ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, | |
616 | card_id); | |
617 | ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, | |
618 | func_id); | |
619 | ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, | |
620 | function); | |
621 | ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, | |
622 | device_no); | |
8fe1a63d MY |
623 | ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, |
624 | get_unaligned_native(*prod_id_hash + 0)); | |
625 | ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, | |
626 | get_unaligned_native(*prod_id_hash + 1)); | |
627 | ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, | |
628 | get_unaligned_native(*prod_id_hash + 2)); | |
629 | ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, | |
630 | get_unaligned_native(*prod_id_hash + 3)); | |
90829cfe | 631 | |
6d3b3dd2 | 632 | module_alias_printf(mod, true, "pcmcia:%s", alias); |
90829cfe | 633 | } |
90829cfe | 634 | |
6d3b3dd2 | 635 | static void do_vio_entry(struct module *mod, void *symval) |
fb120da6 | 636 | { |
6d3b3dd2 | 637 | char alias[256]; |
fb120da6 | 638 | char *tmp; |
6543becf AS |
639 | DEF_FIELD_ADDR(symval, vio_device_id, type); |
640 | DEF_FIELD_ADDR(symval, vio_device_id, compat); | |
fb120da6 | 641 | |
6543becf AS |
642 | sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", |
643 | (*compat)[0] ? *compat : "*"); | |
fb120da6 SR |
644 | |
645 | /* Replace all whitespace with underscores */ | |
646 | for (tmp = alias; tmp && *tmp; tmp++) | |
647 | if (isspace (*tmp)) | |
648 | *tmp = '_'; | |
649 | ||
6d3b3dd2 | 650 | module_alias_printf(mod, true, "%s", alias); |
fb120da6 SR |
651 | } |
652 | ||
1d8f430c RR |
653 | static void do_input(char *alias, |
654 | kernel_ulong_t *arr, unsigned int min, unsigned int max) | |
655 | { | |
656 | unsigned int i; | |
ddc5d341 | 657 | |
bf36b4bf | 658 | for (i = min; i <= max; i++) |
8fe1a63d MY |
659 | if (get_unaligned_native(arr + i / BITS_PER_LONG) & |
660 | (1ULL << (i % BITS_PER_LONG))) | |
ddc5d341 | 661 | sprintf(alias + strlen(alias), "%X,*", i); |
1d8f430c RR |
662 | } |
663 | ||
09c3e01b | 664 | /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ |
6d3b3dd2 | 665 | static void do_input_entry(struct module *mod, void *symval) |
1d8f430c | 666 | { |
6d3b3dd2 MY |
667 | char alias[256] = {}; |
668 | ||
6543becf AS |
669 | DEF_FIELD(symval, input_device_id, flags); |
670 | DEF_FIELD(symval, input_device_id, bustype); | |
671 | DEF_FIELD(symval, input_device_id, vendor); | |
672 | DEF_FIELD(symval, input_device_id, product); | |
673 | DEF_FIELD(symval, input_device_id, version); | |
674 | DEF_FIELD_ADDR(symval, input_device_id, evbit); | |
675 | DEF_FIELD_ADDR(symval, input_device_id, keybit); | |
676 | DEF_FIELD_ADDR(symval, input_device_id, relbit); | |
677 | DEF_FIELD_ADDR(symval, input_device_id, absbit); | |
678 | DEF_FIELD_ADDR(symval, input_device_id, mscbit); | |
679 | DEF_FIELD_ADDR(symval, input_device_id, ledbit); | |
680 | DEF_FIELD_ADDR(symval, input_device_id, sndbit); | |
681 | DEF_FIELD_ADDR(symval, input_device_id, ffbit); | |
682 | DEF_FIELD_ADDR(symval, input_device_id, swbit); | |
683 | ||
6543becf AS |
684 | ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); |
685 | ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); | |
686 | ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); | |
687 | ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); | |
1d8f430c RR |
688 | |
689 | sprintf(alias + strlen(alias), "-e*"); | |
6543becf AS |
690 | if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) |
691 | do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); | |
1d8f430c | 692 | sprintf(alias + strlen(alias), "k*"); |
6543becf AS |
693 | if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) |
694 | do_input(alias, *keybit, | |
dc24f0e7 SR |
695 | INPUT_DEVICE_ID_KEY_MIN_INTERESTING, |
696 | INPUT_DEVICE_ID_KEY_MAX); | |
1d8f430c | 697 | sprintf(alias + strlen(alias), "r*"); |
6543becf AS |
698 | if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) |
699 | do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); | |
1d8f430c | 700 | sprintf(alias + strlen(alias), "a*"); |
6543becf AS |
701 | if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) |
702 | do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); | |
1d8f430c | 703 | sprintf(alias + strlen(alias), "m*"); |
6543becf AS |
704 | if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) |
705 | do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); | |
1d8f430c | 706 | sprintf(alias + strlen(alias), "l*"); |
6543becf AS |
707 | if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) |
708 | do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); | |
1d8f430c | 709 | sprintf(alias + strlen(alias), "s*"); |
6543becf AS |
710 | if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) |
711 | do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); | |
1d8f430c | 712 | sprintf(alias + strlen(alias), "f*"); |
6543becf AS |
713 | if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) |
714 | do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); | |
1d8f430c | 715 | sprintf(alias + strlen(alias), "w*"); |
6543becf AS |
716 | if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) |
717 | do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); | |
6d3b3dd2 MY |
718 | |
719 | module_alias_printf(mod, false, "input:%s", alias); | |
1d8f430c RR |
720 | } |
721 | ||
6d3b3dd2 | 722 | static void do_eisa_entry(struct module *mod, void *symval) |
07563c71 | 723 | { |
6543becf | 724 | DEF_FIELD_ADDR(symval, eisa_device_id, sig); |
6d3b3dd2 | 725 | module_alias_printf(mod, false, EISA_DEVICE_MODALIAS_FMT "*", *sig); |
07563c71 MT |
726 | } |
727 | ||
f3cf2673 | 728 | /* Looks like: parisc:tNhvNrevNsvN */ |
6d3b3dd2 | 729 | static void do_parisc_entry(struct module *mod, void *symval) |
f3cf2673 | 730 | { |
6d3b3dd2 MY |
731 | char alias[256] = {}; |
732 | ||
6543becf AS |
733 | DEF_FIELD(symval, parisc_device_id, hw_type); |
734 | DEF_FIELD(symval, parisc_device_id, hversion); | |
735 | DEF_FIELD(symval, parisc_device_id, hversion_rev); | |
736 | DEF_FIELD(symval, parisc_device_id, sversion); | |
f3cf2673 | 737 | |
6543becf AS |
738 | ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); |
739 | ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); | |
740 | ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); | |
741 | ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); | |
f3cf2673 | 742 | |
6d3b3dd2 | 743 | module_alias_printf(mod, true, "parisc:%s", alias); |
f3cf2673 KM |
744 | } |
745 | ||
d59b66c7 | 746 | /* Looks like: sdio:cNvNdN. */ |
6d3b3dd2 | 747 | static void do_sdio_entry(struct module *mod, void *symval) |
d59b66c7 | 748 | { |
6d3b3dd2 MY |
749 | char alias[256] = {}; |
750 | ||
6543becf AS |
751 | DEF_FIELD(symval, sdio_device_id, class); |
752 | DEF_FIELD(symval, sdio_device_id, vendor); | |
753 | DEF_FIELD(symval, sdio_device_id, device); | |
d59b66c7 | 754 | |
6543becf AS |
755 | ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); |
756 | ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); | |
757 | ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); | |
6d3b3dd2 MY |
758 | |
759 | module_alias_printf(mod, true, "sdio:%s", alias); | |
038a5008 LT |
760 | } |
761 | ||
61e115a5 | 762 | /* Looks like: ssb:vNidNrevN. */ |
6d3b3dd2 | 763 | static void do_ssb_entry(struct module *mod, void *symval) |
61e115a5 | 764 | { |
6d3b3dd2 MY |
765 | char alias[256] = {}; |
766 | ||
6543becf AS |
767 | DEF_FIELD(symval, ssb_device_id, vendor); |
768 | DEF_FIELD(symval, ssb_device_id, coreid); | |
769 | DEF_FIELD(symval, ssb_device_id, revision); | |
d59b66c7 | 770 | |
6543becf AS |
771 | ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); |
772 | ADD(alias, "id", coreid != SSB_ANY_ID, coreid); | |
773 | ADD(alias, "rev", revision != SSB_ANY_REV, revision); | |
6d3b3dd2 MY |
774 | |
775 | module_alias_printf(mod, true, "ssb:%s", alias); | |
d59b66c7 PO |
776 | } |
777 | ||
8369ae33 | 778 | /* Looks like: bcma:mNidNrevNclN. */ |
6d3b3dd2 | 779 | static void do_bcma_entry(struct module *mod, void *symval) |
8369ae33 | 780 | { |
6d3b3dd2 MY |
781 | char alias[256] = {}; |
782 | ||
6543becf AS |
783 | DEF_FIELD(symval, bcma_device_id, manuf); |
784 | DEF_FIELD(symval, bcma_device_id, id); | |
785 | DEF_FIELD(symval, bcma_device_id, rev); | |
786 | DEF_FIELD(symval, bcma_device_id, class); | |
8369ae33 | 787 | |
6543becf AS |
788 | ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); |
789 | ADD(alias, "id", id != BCMA_ANY_ID, id); | |
790 | ADD(alias, "rev", rev != BCMA_ANY_REV, rev); | |
791 | ADD(alias, "cl", class != BCMA_ANY_CLASS, class); | |
6d3b3dd2 MY |
792 | |
793 | module_alias_printf(mod, true, "bcma:%s", alias); | |
8369ae33 RM |
794 | } |
795 | ||
b01d9f28 | 796 | /* Looks like: virtio:dNvN */ |
6d3b3dd2 | 797 | static void do_virtio_entry(struct module *mod, void *symval) |
b01d9f28 | 798 | { |
6d3b3dd2 MY |
799 | char alias[256] = {}; |
800 | ||
6543becf AS |
801 | DEF_FIELD(symval, virtio_device_id, device); |
802 | DEF_FIELD(symval, virtio_device_id, vendor); | |
b01d9f28 | 803 | |
6543becf AS |
804 | ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); |
805 | ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); | |
b01d9f28 | 806 | |
6d3b3dd2 | 807 | module_alias_printf(mod, true, "virtio:%s", alias); |
b01d9f28 RR |
808 | } |
809 | ||
d2ee52aa S |
810 | /* |
811 | * Looks like: vmbus:guid | |
812 | * Each byte of the guid will be represented by two hex characters | |
813 | * in the name. | |
814 | */ | |
6d3b3dd2 | 815 | static void do_vmbus_entry(struct module *mod, void *symval) |
d2ee52aa | 816 | { |
6543becf | 817 | DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); |
e1352d7e | 818 | char guid_name[sizeof(*guid) * 2 + 1]; |
d2ee52aa | 819 | |
e1352d7e MY |
820 | for (int i = 0; i < sizeof(*guid); i++) |
821 | sprintf(&guid_name[i * 2], "%02x", guid->b[i]); | |
d2ee52aa | 822 | |
6d3b3dd2 | 823 | module_alias_printf(mod, false, "vmbus:%s", guid_name); |
d2ee52aa S |
824 | } |
825 | ||
5b7d1277 | 826 | /* Looks like: rpmsg:S */ |
6d3b3dd2 | 827 | static void do_rpmsg_entry(struct module *mod, void *symval) |
5b7d1277 AD |
828 | { |
829 | DEF_FIELD_ADDR(symval, rpmsg_device_id, name); | |
5b7d1277 | 830 | |
6d3b3dd2 | 831 | module_alias_printf(mod, false, RPMSG_DEVICE_MODALIAS_FMT, *name); |
5b7d1277 | 832 | } |
5b7d1277 | 833 | |
d2653e92 | 834 | /* Looks like: i2c:S */ |
6d3b3dd2 | 835 | static void do_i2c_entry(struct module *mod, void *symval) |
d2653e92 | 836 | { |
6543becf | 837 | DEF_FIELD_ADDR(symval, i2c_device_id, name); |
d2653e92 | 838 | |
6d3b3dd2 | 839 | module_alias_printf(mod, false, I2C_MODULE_PREFIX "%s", *name); |
d2653e92 JD |
840 | } |
841 | ||
6d3b3dd2 | 842 | static void do_i3c_entry(struct module *mod, void *symval) |
1ce589ad | 843 | { |
6d3b3dd2 MY |
844 | char alias[256] = {}; |
845 | ||
1ce589ad BB |
846 | DEF_FIELD(symval, i3c_device_id, match_flags); |
847 | DEF_FIELD(symval, i3c_device_id, dcr); | |
848 | DEF_FIELD(symval, i3c_device_id, manuf_id); | |
849 | DEF_FIELD(symval, i3c_device_id, part_id); | |
850 | DEF_FIELD(symval, i3c_device_id, extra_info); | |
851 | ||
1ce589ad BB |
852 | ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr); |
853 | ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id); | |
854 | ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id); | |
855 | ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info); | |
856 | ||
6d3b3dd2 | 857 | module_alias_printf(mod, false, "i3c:%s", alias); |
1ce589ad BB |
858 | } |
859 | ||
6d3b3dd2 | 860 | static void do_slim_entry(struct module *mod, void *symval) |
b4b81830 MY |
861 | { |
862 | DEF_FIELD(symval, slim_device_id, manf_id); | |
863 | DEF_FIELD(symval, slim_device_id, prod_code); | |
864 | ||
6d3b3dd2 | 865 | module_alias_printf(mod, false, "slim:%x:%x:*", manf_id, prod_code); |
b4b81830 MY |
866 | } |
867 | ||
e0626e38 | 868 | /* Looks like: spi:S */ |
6d3b3dd2 | 869 | static void do_spi_entry(struct module *mod, void *symval) |
75368bf6 | 870 | { |
6543becf | 871 | DEF_FIELD_ADDR(symval, spi_device_id, name); |
75368bf6 | 872 | |
6d3b3dd2 | 873 | module_alias_printf(mod, false, SPI_MODULE_PREFIX "%s", *name); |
75368bf6 AV |
874 | } |
875 | ||
d945b697 DW |
876 | static const struct dmifield { |
877 | const char *prefix; | |
878 | int field; | |
879 | } dmi_fields[] = { | |
880 | { "bvn", DMI_BIOS_VENDOR }, | |
881 | { "bvr", DMI_BIOS_VERSION }, | |
882 | { "bd", DMI_BIOS_DATE }, | |
f5152f4d EV |
883 | { "br", DMI_BIOS_RELEASE }, |
884 | { "efr", DMI_EC_FIRMWARE_RELEASE }, | |
d945b697 DW |
885 | { "svn", DMI_SYS_VENDOR }, |
886 | { "pn", DMI_PRODUCT_NAME }, | |
887 | { "pvr", DMI_PRODUCT_VERSION }, | |
888 | { "rvn", DMI_BOARD_VENDOR }, | |
889 | { "rn", DMI_BOARD_NAME }, | |
890 | { "rvr", DMI_BOARD_VERSION }, | |
891 | { "cvn", DMI_CHASSIS_VENDOR }, | |
892 | { "ct", DMI_CHASSIS_TYPE }, | |
893 | { "cvr", DMI_CHASSIS_VERSION }, | |
894 | { NULL, DMI_NONE } | |
895 | }; | |
896 | ||
897 | static void dmi_ascii_filter(char *d, const char *s) | |
898 | { | |
899 | /* Filter out characters we don't want to see in the modalias string */ | |
900 | for (; *s; s++) | |
901 | if (*s > ' ' && *s < 127 && *s != ':') | |
902 | *(d++) = *s; | |
903 | ||
904 | *d = 0; | |
905 | } | |
906 | ||
907 | ||
6d3b3dd2 | 908 | static void do_dmi_entry(struct module *mod, void *symval) |
d945b697 | 909 | { |
6d3b3dd2 | 910 | char alias[256] = {}; |
d945b697 | 911 | int i, j; |
6543becf | 912 | DEF_FIELD_ADDR(symval, dmi_system_id, matches); |
d945b697 DW |
913 | |
914 | for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { | |
915 | for (j = 0; j < 4; j++) { | |
6543becf AS |
916 | if ((*matches)[j].slot && |
917 | (*matches)[j].slot == dmi_fields[i].field) { | |
d945b697 DW |
918 | sprintf(alias + strlen(alias), ":%s*", |
919 | dmi_fields[i].prefix); | |
920 | dmi_ascii_filter(alias + strlen(alias), | |
6543becf | 921 | (*matches)[j].substr); |
d945b697 DW |
922 | strcat(alias, "*"); |
923 | } | |
924 | } | |
925 | } | |
926 | ||
6d3b3dd2 | 927 | module_alias_printf(mod, false, "dmi*%s:", alias); |
d945b697 | 928 | } |
57fee4a5 | 929 | |
6d3b3dd2 | 930 | static void do_platform_entry(struct module *mod, void *symval) |
57fee4a5 | 931 | { |
6543becf | 932 | DEF_FIELD_ADDR(symval, platform_device_id, name); |
6d3b3dd2 MY |
933 | |
934 | module_alias_printf(mod, false, PLATFORM_MODULE_PREFIX "%s", *name); | |
57fee4a5 EM |
935 | } |
936 | ||
6d3b3dd2 | 937 | static void do_mdio_entry(struct module *mod, void *symval) |
8626d3b4 | 938 | { |
6d3b3dd2 | 939 | char id[33]; |
8626d3b4 | 940 | int i; |
6543becf AS |
941 | DEF_FIELD(symval, mdio_device_id, phy_id); |
942 | DEF_FIELD(symval, mdio_device_id, phy_id_mask); | |
8626d3b4 | 943 | |
8626d3b4 | 944 | for (i = 0; i < 32; i++) { |
6543becf | 945 | if (!((phy_id_mask >> (31-i)) & 1)) |
6d3b3dd2 | 946 | id[i] = '?'; |
6543becf | 947 | else if ((phy_id >> (31-i)) & 1) |
6d3b3dd2 | 948 | id[i] = '1'; |
8626d3b4 | 949 | else |
6d3b3dd2 | 950 | id[i] = '0'; |
8626d3b4 DW |
951 | } |
952 | ||
953 | /* Terminate the string */ | |
6d3b3dd2 | 954 | id[32] = '\0'; |
8626d3b4 | 955 | |
6d3b3dd2 | 956 | module_alias_printf(mod, false, MDIO_MODULE_PREFIX "%s", id); |
8626d3b4 DW |
957 | } |
958 | ||
bf54a2b3 | 959 | /* Looks like: zorro:iN. */ |
6d3b3dd2 | 960 | static void do_zorro_entry(struct module *mod, void *symval) |
bf54a2b3 | 961 | { |
6d3b3dd2 | 962 | char alias[256] = {}; |
6543becf | 963 | DEF_FIELD(symval, zorro_device_id, id); |
6d3b3dd2 | 964 | |
6543becf | 965 | ADD(alias, "i", id != ZORRO_WILDCARD, id); |
6d3b3dd2 MY |
966 | |
967 | module_alias_printf(mod, false, "zorro:%s", alias); | |
bf54a2b3 GU |
968 | } |
969 | ||
fedb3d27 | 970 | /* looks like: "pnp:dD" */ |
6d3b3dd2 | 971 | static void do_isapnp_entry(struct module *mod, void *symval) |
fedb3d27 | 972 | { |
6543becf AS |
973 | DEF_FIELD(symval, isapnp_device_id, vendor); |
974 | DEF_FIELD(symval, isapnp_device_id, function); | |
6d3b3dd2 | 975 | module_alias_printf(mod, false, "pnp:d%c%c%c%x%x%x%x*", |
6543becf AS |
976 | 'A' + ((vendor >> 2) & 0x3f) - 1, |
977 | 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, | |
978 | 'A' + ((vendor >> 8) & 0x1f) - 1, | |
979 | (function >> 4) & 0x0f, function & 0x0f, | |
980 | (function >> 12) & 0x0f, (function >> 8) & 0x0f); | |
fedb3d27 OZ |
981 | } |
982 | ||
849e0ad2 | 983 | /* Looks like: "ipack:fNvNdN". */ |
6d3b3dd2 | 984 | static void do_ipack_entry(struct module *mod, void *symval) |
849e0ad2 | 985 | { |
6d3b3dd2 | 986 | char alias[256] = {}; |
6543becf AS |
987 | DEF_FIELD(symval, ipack_device_id, format); |
988 | DEF_FIELD(symval, ipack_device_id, vendor); | |
989 | DEF_FIELD(symval, ipack_device_id, device); | |
6d3b3dd2 | 990 | |
6543becf AS |
991 | ADD(alias, "f", format != IPACK_ANY_FORMAT, format); |
992 | ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); | |
993 | ADD(alias, "d", device != IPACK_ANY_ID, device); | |
6d3b3dd2 MY |
994 | |
995 | module_alias_printf(mod, true, "ipack:%s", alias); | |
849e0ad2 | 996 | } |
849e0ad2 | 997 | |
523817bd DM |
998 | /* |
999 | * Append a match expression for a single masked hex digit. | |
1000 | * outp points to a pointer to the character at which to append. | |
1001 | * *outp is updated on return to point just after the appended text, | |
1002 | * to facilitate further appending. | |
1003 | */ | |
1004 | static void append_nibble_mask(char **outp, | |
1005 | unsigned int nibble, unsigned int mask) | |
1006 | { | |
1007 | char *p = *outp; | |
1008 | unsigned int i; | |
1009 | ||
1010 | switch (mask) { | |
1011 | case 0: | |
1012 | *p++ = '?'; | |
1013 | break; | |
1014 | ||
1015 | case 0xf: | |
1016 | p += sprintf(p, "%X", nibble); | |
1017 | break; | |
1018 | ||
1019 | default: | |
1020 | /* | |
1021 | * Dumbly emit a match pattern for all possible matching | |
1022 | * digits. This could be improved in some cases using ranges, | |
1023 | * but it has the advantage of being trivially correct, and is | |
1024 | * often optimal. | |
1025 | */ | |
1026 | *p++ = '['; | |
1027 | for (i = 0; i < 0x10; i++) | |
1028 | if ((i & mask) == nibble) | |
1029 | p += sprintf(p, "%X", i); | |
1030 | *p++ = ']'; | |
1031 | } | |
1032 | ||
1033 | /* Ensure that the string remains NUL-terminated: */ | |
1034 | *p = '\0'; | |
1035 | ||
1036 | /* Advance the caller's end-of-string pointer: */ | |
1037 | *outp = p; | |
1038 | } | |
1039 | ||
1040 | /* | |
1041 | * looks like: "amba:dN" | |
1042 | * | |
1043 | * N is exactly 8 digits, where each is an upper-case hex digit, or | |
1044 | * a ? or [] pattern matching exactly one digit. | |
1045 | */ | |
6d3b3dd2 | 1046 | static void do_amba_entry(struct module *mod, void *symval) |
523817bd | 1047 | { |
6d3b3dd2 | 1048 | char alias[256]; |
523817bd DM |
1049 | unsigned int digit; |
1050 | char *p = alias; | |
6543becf AS |
1051 | DEF_FIELD(symval, amba_id, id); |
1052 | DEF_FIELD(symval, amba_id, mask); | |
523817bd | 1053 | |
6543becf | 1054 | if ((id & mask) != id) |
0d2573a2 | 1055 | fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X. Please fix this driver.\n", |
c7c24d60 | 1056 | mod->name, id, mask); |
523817bd | 1057 | |
523817bd DM |
1058 | for (digit = 0; digit < 8; digit++) |
1059 | append_nibble_mask(&p, | |
6543becf AS |
1060 | (id >> (4 * (7 - digit))) & 0xf, |
1061 | (mask >> (4 * (7 - digit))) & 0xf); | |
523817bd | 1062 | |
6d3b3dd2 | 1063 | module_alias_printf(mod, false, "amba:d%s", alias); |
523817bd DM |
1064 | } |
1065 | ||
8286ae03 JH |
1066 | /* |
1067 | * looks like: "mipscdmm:tN" | |
1068 | * | |
1069 | * N is exactly 2 digits, where each is an upper-case hex digit, or | |
1070 | * a ? or [] pattern matching exactly one digit. | |
1071 | */ | |
6d3b3dd2 | 1072 | static void do_mips_cdmm_entry(struct module *mod, void *symval) |
8286ae03 JH |
1073 | { |
1074 | DEF_FIELD(symval, mips_cdmm_device_id, type); | |
1075 | ||
6d3b3dd2 | 1076 | module_alias_printf(mod, false, "mipscdmm:t%02X*", type); |
8286ae03 | 1077 | } |
8286ae03 | 1078 | |
2b9c1f03 | 1079 | /* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* |
644e9cbb AK |
1080 | * All fields are numbers. It would be nicer to use strings for vendor |
1081 | * and feature, but getting those out of the build system here is too | |
1082 | * complicated. | |
1083 | */ | |
1084 | ||
6d3b3dd2 | 1085 | static void do_x86cpu_entry(struct module *mod, void *symval) |
644e9cbb | 1086 | { |
6d3b3dd2 MY |
1087 | char alias[256] = {}; |
1088 | ||
6543becf AS |
1089 | DEF_FIELD(symval, x86_cpu_id, feature); |
1090 | DEF_FIELD(symval, x86_cpu_id, family); | |
1091 | DEF_FIELD(symval, x86_cpu_id, model); | |
1092 | DEF_FIELD(symval, x86_cpu_id, vendor); | |
644e9cbb | 1093 | |
2b9c1f03 AB |
1094 | ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); |
1095 | ADD(alias, "fam", family != X86_FAMILY_ANY, family); | |
1096 | ADD(alias, "mod", model != X86_MODEL_ANY, model); | |
5467bdda | 1097 | strcat(alias, ":feature:*"); |
6543becf AS |
1098 | if (feature != X86_FEATURE_ANY) |
1099 | sprintf(alias + strlen(alias), "%04X*", feature); | |
6d3b3dd2 MY |
1100 | |
1101 | module_alias_printf(mod, false, "cpu:type:x86,%s", alias); | |
644e9cbb | 1102 | } |
644e9cbb | 1103 | |
67bad2fd | 1104 | /* LOOKS like cpu:type:*:feature:*FEAT* */ |
6d3b3dd2 | 1105 | static void do_cpu_entry(struct module *mod, void *symval) |
67bad2fd AB |
1106 | { |
1107 | DEF_FIELD(symval, cpu_feature, feature); | |
1108 | ||
6d3b3dd2 | 1109 | module_alias_printf(mod, false, "cpu:type:*:feature:*%04X*", feature); |
67bad2fd | 1110 | } |
67bad2fd | 1111 | |
b26864ca | 1112 | /* Looks like: mei:S:uuid:N:* */ |
6d3b3dd2 | 1113 | static void do_mei_entry(struct module *mod, void *symval) |
e5354107 | 1114 | { |
6d3b3dd2 MY |
1115 | char alias[256] = {}; |
1116 | ||
e5354107 | 1117 | DEF_FIELD_ADDR(symval, mei_cl_device_id, name); |
c93b76b3 | 1118 | DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid); |
b26864ca | 1119 | DEF_FIELD(symval, mei_cl_device_id, version); |
c93b76b3 | 1120 | |
c93b76b3 | 1121 | add_uuid(alias, *uuid); |
b26864ca | 1122 | ADD(alias, ":", version != MEI_CL_VERSION_ANY, version); |
e5354107 | 1123 | |
6d3b3dd2 MY |
1124 | module_alias_printf(mod, false, MEI_CL_MODULE_PREFIX "%s:%s:*", |
1125 | (*name)[0] ? *name : "*", alias); | |
e5354107 | 1126 | } |
e5354107 | 1127 | |
3bdbb62f | 1128 | /* Looks like: rapidio:vNdNavNadN */ |
6d3b3dd2 | 1129 | static void do_rio_entry(struct module *mod, void *symval) |
3bdbb62f | 1130 | { |
6d3b3dd2 MY |
1131 | char alias[256] = {}; |
1132 | ||
3bdbb62f AB |
1133 | DEF_FIELD(symval, rio_device_id, did); |
1134 | DEF_FIELD(symval, rio_device_id, vid); | |
1135 | DEF_FIELD(symval, rio_device_id, asm_did); | |
1136 | DEF_FIELD(symval, rio_device_id, asm_vid); | |
1137 | ||
3bdbb62f AB |
1138 | ADD(alias, "v", vid != RIO_ANY_ID, vid); |
1139 | ADD(alias, "d", did != RIO_ANY_ID, did); | |
1140 | ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); | |
1141 | ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); | |
1142 | ||
6d3b3dd2 | 1143 | module_alias_printf(mod, true, "rapidio:%s", alias); |
3bdbb62f | 1144 | } |
3bdbb62f | 1145 | |
289fcff4 | 1146 | /* Looks like: ulpi:vNpN */ |
6d3b3dd2 | 1147 | static void do_ulpi_entry(struct module *mod, void *symval) |
289fcff4 HK |
1148 | { |
1149 | DEF_FIELD(symval, ulpi_device_id, vendor); | |
1150 | DEF_FIELD(symval, ulpi_device_id, product); | |
1151 | ||
6d3b3dd2 | 1152 | module_alias_printf(mod, false, "ulpi:v%04xp%04x", vendor, product); |
289fcff4 | 1153 | } |
289fcff4 | 1154 | |
da23ac1e | 1155 | /* Looks like: hdaudio:vNrNaN */ |
6d3b3dd2 | 1156 | static void do_hda_entry(struct module *mod, void *symval) |
da23ac1e | 1157 | { |
6d3b3dd2 MY |
1158 | char alias[256] = {}; |
1159 | ||
da23ac1e SP |
1160 | DEF_FIELD(symval, hda_device_id, vendor_id); |
1161 | DEF_FIELD(symval, hda_device_id, rev_id); | |
1162 | DEF_FIELD(symval, hda_device_id, api_version); | |
1163 | ||
da23ac1e SP |
1164 | ADD(alias, "v", vendor_id != 0, vendor_id); |
1165 | ADD(alias, "r", rev_id != 0, rev_id); | |
1166 | ADD(alias, "a", api_version != 0, api_version); | |
1167 | ||
6d3b3dd2 | 1168 | module_alias_printf(mod, true, "hdaudio:%s", alias); |
da23ac1e | 1169 | } |
da23ac1e | 1170 | |
b5924268 | 1171 | /* Looks like: sdw:mNpNvNcN */ |
6d3b3dd2 | 1172 | static void do_sdw_entry(struct module *mod, void *symval) |
9251345d | 1173 | { |
6d3b3dd2 MY |
1174 | char alias[256] = {}; |
1175 | ||
9251345d VK |
1176 | DEF_FIELD(symval, sdw_device_id, mfg_id); |
1177 | DEF_FIELD(symval, sdw_device_id, part_id); | |
b5924268 PLB |
1178 | DEF_FIELD(symval, sdw_device_id, sdw_version); |
1179 | DEF_FIELD(symval, sdw_device_id, class_id); | |
9251345d | 1180 | |
9251345d VK |
1181 | ADD(alias, "m", mfg_id != 0, mfg_id); |
1182 | ADD(alias, "p", part_id != 0, part_id); | |
b5924268 PLB |
1183 | ADD(alias, "v", sdw_version != 0, sdw_version); |
1184 | ADD(alias, "c", class_id != 0, class_id); | |
9251345d | 1185 | |
6d3b3dd2 | 1186 | module_alias_printf(mod, true, "sdw:%s", alias); |
9251345d | 1187 | } |
9251345d | 1188 | |
0afef456 | 1189 | /* Looks like: fsl-mc:vNdN */ |
6d3b3dd2 | 1190 | static void do_fsl_mc_entry(struct module *mod, void *symval) |
0afef456 SY |
1191 | { |
1192 | DEF_FIELD(symval, fsl_mc_device_id, vendor); | |
1193 | DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); | |
1194 | ||
6d3b3dd2 | 1195 | module_alias_printf(mod, false, "fsl-mc:v%08Xd%s", vendor, *obj_type); |
0afef456 | 1196 | } |
0afef456 | 1197 | |
d1ff7024 | 1198 | /* Looks like: tbsvc:kSpNvNrN */ |
6d3b3dd2 | 1199 | static void do_tbsvc_entry(struct module *mod, void *symval) |
d1ff7024 | 1200 | { |
6d3b3dd2 MY |
1201 | char alias[256] = {}; |
1202 | ||
d1ff7024 MW |
1203 | DEF_FIELD(symval, tb_service_id, match_flags); |
1204 | DEF_FIELD_ADDR(symval, tb_service_id, protocol_key); | |
1205 | DEF_FIELD(symval, tb_service_id, protocol_id); | |
1206 | DEF_FIELD(symval, tb_service_id, protocol_version); | |
1207 | DEF_FIELD(symval, tb_service_id, protocol_revision); | |
1208 | ||
d1ff7024 MW |
1209 | if (match_flags & TBSVC_MATCH_PROTOCOL_KEY) |
1210 | sprintf(alias + strlen(alias), "k%s", *protocol_key); | |
1211 | else | |
1212 | strcat(alias + strlen(alias), "k*"); | |
1213 | ADD(alias, "p", match_flags & TBSVC_MATCH_PROTOCOL_ID, protocol_id); | |
1214 | ADD(alias, "v", match_flags & TBSVC_MATCH_PROTOCOL_VERSION, | |
1215 | protocol_version); | |
1216 | ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION, | |
1217 | protocol_revision); | |
1218 | ||
6d3b3dd2 | 1219 | module_alias_printf(mod, true, "tbsvc:%s", alias); |
d1ff7024 | 1220 | } |
d1ff7024 | 1221 | |
8541bf02 | 1222 | /* Looks like: typec:idN */ |
6d3b3dd2 | 1223 | static void do_typec_entry(struct module *mod, void *symval) |
8a37d87d HK |
1224 | { |
1225 | DEF_FIELD(symval, typec_device_id, svid); | |
8a37d87d | 1226 | |
8541bf02 | 1227 | module_alias_printf(mod, false, "typec:id%04X", svid); |
8a37d87d | 1228 | } |
8a37d87d | 1229 | |
0fc1db9d | 1230 | /* Looks like: tee:uuid */ |
6d3b3dd2 | 1231 | static void do_tee_entry(struct module *mod, void *symval) |
0fc1db9d | 1232 | { |
7f54e00e | 1233 | DEF_FIELD_ADDR(symval, tee_client_device_id, uuid); |
0fc1db9d | 1234 | |
6d3b3dd2 MY |
1235 | module_alias_printf(mod, true, |
1236 | "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
7f54e00e MY |
1237 | uuid->b[0], uuid->b[1], uuid->b[2], uuid->b[3], uuid->b[4], |
1238 | uuid->b[5], uuid->b[6], uuid->b[7], uuid->b[8], uuid->b[9], | |
1239 | uuid->b[10], uuid->b[11], uuid->b[12], uuid->b[13], uuid->b[14], | |
1240 | uuid->b[15]); | |
0fc1db9d SG |
1241 | } |
1242 | ||
0bc44b2b | 1243 | /* Looks like: wmi:guid */ |
6d3b3dd2 | 1244 | static void do_wmi_entry(struct module *mod, void *symval) |
0bc44b2b | 1245 | { |
0bc44b2b MJ |
1246 | DEF_FIELD_ADDR(symval, wmi_device_id, guid_string); |
1247 | ||
1248 | if (strlen(*guid_string) != UUID_STRING_LEN) { | |
1249 | warn("Invalid WMI device id 'wmi:%s' in '%s'\n", | |
c7c24d60 | 1250 | *guid_string, mod->name); |
6d3b3dd2 | 1251 | return; |
0bc44b2b MJ |
1252 | } |
1253 | ||
6d3b3dd2 | 1254 | module_alias_printf(mod, false, WMI_MODULE_PREFIX "%s", *guid_string); |
0bc44b2b MJ |
1255 | } |
1256 | ||
e6b0de46 | 1257 | /* Looks like: mhi:S */ |
6d3b3dd2 | 1258 | static void do_mhi_entry(struct module *mod, void *symval) |
e6b0de46 MS |
1259 | { |
1260 | DEF_FIELD_ADDR(symval, mhi_device_id, chan); | |
6d3b3dd2 | 1261 | module_alias_printf(mod, false, MHI_DEVICE_MODALIAS_FMT, *chan); |
7de3697e DE |
1262 | } |
1263 | ||
c268c0a8 | 1264 | /* Looks like: mhi_ep:S */ |
6d3b3dd2 | 1265 | static void do_mhi_ep_entry(struct module *mod, void *symval) |
c268c0a8 MS |
1266 | { |
1267 | DEF_FIELD_ADDR(symval, mhi_device_id, chan); | |
c268c0a8 | 1268 | |
6d3b3dd2 | 1269 | module_alias_printf(mod, false, MHI_EP_DEVICE_MODALIAS_FMT, *chan); |
c268c0a8 MS |
1270 | } |
1271 | ||
fa443bc3 | 1272 | /* Looks like: ishtp:{guid} */ |
6d3b3dd2 | 1273 | static void do_ishtp_entry(struct module *mod, void *symval) |
fa443bc3 | 1274 | { |
6d3b3dd2 | 1275 | char alias[256] = {}; |
ac96a15a | 1276 | DEF_FIELD_ADDR(symval, ishtp_device_id, guid); |
fa443bc3 | 1277 | |
ac96a15a | 1278 | add_guid(alias, *guid); |
fa443bc3 | 1279 | |
6d3b3dd2 | 1280 | module_alias_printf(mod, false, ISHTP_MODULE_PREFIX "{%s}", alias); |
fa443bc3 TW |
1281 | } |
1282 | ||
6d3b3dd2 | 1283 | static void do_auxiliary_entry(struct module *mod, void *symval) |
7de3697e DE |
1284 | { |
1285 | DEF_FIELD_ADDR(symval, auxiliary_device_id, name); | |
e6b0de46 | 1286 | |
6d3b3dd2 | 1287 | module_alias_printf(mod, false, AUXILIARY_MODULE_PREFIX "%s", *name); |
e6b0de46 MS |
1288 | } |
1289 | ||
eb0e90a8 ML |
1290 | /* |
1291 | * Looks like: ssam:dNcNtNiNfN | |
1292 | * | |
1293 | * N is exactly 2 digits, where each is an upper-case hex digit. | |
1294 | */ | |
6d3b3dd2 | 1295 | static void do_ssam_entry(struct module *mod, void *symval) |
eb0e90a8 | 1296 | { |
6d3b3dd2 MY |
1297 | char alias[256] = {}; |
1298 | ||
eb0e90a8 ML |
1299 | DEF_FIELD(symval, ssam_device_id, match_flags); |
1300 | DEF_FIELD(symval, ssam_device_id, domain); | |
1301 | DEF_FIELD(symval, ssam_device_id, category); | |
1302 | DEF_FIELD(symval, ssam_device_id, target); | |
1303 | DEF_FIELD(symval, ssam_device_id, instance); | |
1304 | DEF_FIELD(symval, ssam_device_id, function); | |
1305 | ||
eb0e90a8 ML |
1306 | ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target); |
1307 | ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); | |
1308 | ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); | |
1309 | ||
6d3b3dd2 MY |
1310 | module_alias_printf(mod, false, "ssam:d%02Xc%02X%s", |
1311 | domain, category, alias); | |
eb0e90a8 ML |
1312 | } |
1313 | ||
4a224ace | 1314 | /* Looks like: dfl:tNfN */ |
6d3b3dd2 | 1315 | static void do_dfl_entry(struct module *mod, void *symval) |
4a224ace XY |
1316 | { |
1317 | DEF_FIELD(symval, dfl_device_id, type); | |
1318 | DEF_FIELD(symval, dfl_device_id, feature_id); | |
1319 | ||
6d3b3dd2 | 1320 | module_alias_printf(mod, true, "dfl:t%04Xf%04X", type, feature_id); |
4a224ace XY |
1321 | } |
1322 | ||
2959ab24 | 1323 | /* Looks like: cdx:vNdN */ |
6d3b3dd2 | 1324 | static void do_cdx_entry(struct module *mod, void *symval) |
2959ab24 | 1325 | { |
6d3b3dd2 MY |
1326 | char alias[256]; |
1327 | ||
2959ab24 NG |
1328 | DEF_FIELD(symval, cdx_device_id, vendor); |
1329 | DEF_FIELD(symval, cdx_device_id, device); | |
fa10f413 AG |
1330 | DEF_FIELD(symval, cdx_device_id, subvendor); |
1331 | DEF_FIELD(symval, cdx_device_id, subdevice); | |
1332 | DEF_FIELD(symval, cdx_device_id, class); | |
1333 | DEF_FIELD(symval, cdx_device_id, class_mask); | |
234489ac | 1334 | DEF_FIELD(symval, cdx_device_id, override_only); |
2959ab24 | 1335 | |
234489ac NG |
1336 | switch (override_only) { |
1337 | case 0: | |
1338 | strcpy(alias, "cdx:"); | |
1339 | break; | |
1340 | case CDX_ID_F_VFIO_DRIVER_OVERRIDE: | |
1341 | strcpy(alias, "vfio_cdx:"); | |
1342 | break; | |
1343 | default: | |
1344 | warn("Unknown CDX driver_override alias %08X\n", | |
1345 | override_only); | |
6d3b3dd2 | 1346 | return; |
234489ac NG |
1347 | } |
1348 | ||
1349 | ADD(alias, "v", vendor != CDX_ANY_ID, vendor); | |
1350 | ADD(alias, "d", device != CDX_ANY_ID, device); | |
fa10f413 AG |
1351 | ADD(alias, "sv", subvendor != CDX_ANY_ID, subvendor); |
1352 | ADD(alias, "sd", subdevice != CDX_ANY_ID, subdevice); | |
1353 | ADD(alias, "c", class_mask == 0xFFFFFF, class); | |
1354 | ||
6d3b3dd2 | 1355 | module_alias_printf(mod, false, "%s", alias); |
2959ab24 NG |
1356 | } |
1357 | ||
6d3b3dd2 | 1358 | static void do_vchiq_entry(struct module *mod, void *symval) |
1fa05877 UJ |
1359 | { |
1360 | DEF_FIELD_ADDR(symval, vchiq_device_id, name); | |
1fa05877 | 1361 | |
6d3b3dd2 | 1362 | module_alias_printf(mod, false, "vchiq:%s", *name); |
1fa05877 UJ |
1363 | } |
1364 | ||
f1cebae1 | 1365 | /* Looks like: coreboot:tN */ |
6d3b3dd2 | 1366 | static void do_coreboot_entry(struct module *mod, void *symval) |
f1cebae1 NP |
1367 | { |
1368 | DEF_FIELD(symval, coreboot_device_id, tag); | |
f1cebae1 | 1369 | |
6d3b3dd2 | 1370 | module_alias_printf(mod, false, "coreboot:t%08X", tag); |
f1cebae1 NP |
1371 | } |
1372 | ||
626596e2 RR |
1373 | /* Does namelen bytes of name exactly match the symbol? */ |
1374 | static bool sym_is(const char *name, unsigned namelen, const char *symbol) | |
1da177e4 | 1375 | { |
626596e2 RR |
1376 | if (namelen != strlen(symbol)) |
1377 | return false; | |
1da177e4 | 1378 | |
626596e2 | 1379 | return memcmp(name, symbol, namelen) == 0; |
1da177e4 LT |
1380 | } |
1381 | ||
2b1bd507 | 1382 | static void do_table(const char *name, void *symval, unsigned long size, |
1da177e4 | 1383 | unsigned long id_size, |
fb33d816 | 1384 | const char *device_id, |
6d3b3dd2 | 1385 | void (*do_entry)(struct module *mod, void *symval), |
1da177e4 LT |
1386 | struct module *mod) |
1387 | { | |
1388 | unsigned int i; | |
1da177e4 | 1389 | |
2b1bd507 MY |
1390 | if (size % id_size || size < id_size) { |
1391 | error("%s: type mismatch between %s[] and MODULE_DEVICE_TABLE(%s, ...)\n", | |
1392 | mod->name, name, device_id); | |
1393 | return; | |
1394 | } | |
1395 | ||
1396 | /* Verify the last entry is a terminator */ | |
1397 | for (i = size - id_size; i < size; i++) { | |
1398 | if (*(uint8_t *)(symval + i)) { | |
1399 | error("%s: %s[] is not terminated with a NULL entry\n", | |
1400 | mod->name, name); | |
1401 | return; | |
1402 | } | |
1403 | } | |
1404 | ||
1da177e4 LT |
1405 | /* Leave last one: it's the terminator. */ |
1406 | size -= id_size; | |
1407 | ||
6d3b3dd2 MY |
1408 | for (i = 0; i < size; i += id_size) |
1409 | do_entry(mod, symval + i); | |
1da177e4 LT |
1410 | } |
1411 | ||
ec91e78d MY |
1412 | static const struct devtable devtable[] = { |
1413 | {"hid", SIZE_hid_device_id, do_hid_entry}, | |
1414 | {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, | |
1415 | {"pci", SIZE_pci_device_id, do_pci_entry}, | |
1416 | {"ccw", SIZE_ccw_device_id, do_ccw_entry}, | |
1417 | {"ap", SIZE_ap_device_id, do_ap_entry}, | |
1418 | {"css", SIZE_css_device_id, do_css_entry}, | |
1419 | {"serio", SIZE_serio_device_id, do_serio_entry}, | |
1420 | {"acpi", SIZE_acpi_device_id, do_acpi_entry}, | |
1421 | {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, | |
1422 | {"vio", SIZE_vio_device_id, do_vio_entry}, | |
1423 | {"input", SIZE_input_device_id, do_input_entry}, | |
1424 | {"eisa", SIZE_eisa_device_id, do_eisa_entry}, | |
1425 | {"parisc", SIZE_parisc_device_id, do_parisc_entry}, | |
1426 | {"sdio", SIZE_sdio_device_id, do_sdio_entry}, | |
1427 | {"ssb", SIZE_ssb_device_id, do_ssb_entry}, | |
1428 | {"bcma", SIZE_bcma_device_id, do_bcma_entry}, | |
1429 | {"virtio", SIZE_virtio_device_id, do_virtio_entry}, | |
1430 | {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, | |
1431 | {"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry}, | |
1432 | {"i2c", SIZE_i2c_device_id, do_i2c_entry}, | |
1ce589ad | 1433 | {"i3c", SIZE_i3c_device_id, do_i3c_entry}, |
b4b81830 | 1434 | {"slim", SIZE_slim_device_id, do_slim_entry}, |
ec91e78d MY |
1435 | {"spi", SIZE_spi_device_id, do_spi_entry}, |
1436 | {"dmi", SIZE_dmi_system_id, do_dmi_entry}, | |
1437 | {"platform", SIZE_platform_device_id, do_platform_entry}, | |
1438 | {"mdio", SIZE_mdio_device_id, do_mdio_entry}, | |
1439 | {"zorro", SIZE_zorro_device_id, do_zorro_entry}, | |
1440 | {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, | |
1441 | {"ipack", SIZE_ipack_device_id, do_ipack_entry}, | |
1442 | {"amba", SIZE_amba_id, do_amba_entry}, | |
1443 | {"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry}, | |
1444 | {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, | |
1445 | {"cpu", SIZE_cpu_feature, do_cpu_entry}, | |
1446 | {"mei", SIZE_mei_cl_device_id, do_mei_entry}, | |
1447 | {"rapidio", SIZE_rio_device_id, do_rio_entry}, | |
1448 | {"ulpi", SIZE_ulpi_device_id, do_ulpi_entry}, | |
1449 | {"hdaudio", SIZE_hda_device_id, do_hda_entry}, | |
1450 | {"sdw", SIZE_sdw_device_id, do_sdw_entry}, | |
1451 | {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, | |
1452 | {"tbsvc", SIZE_tb_service_id, do_tbsvc_entry}, | |
1453 | {"typec", SIZE_typec_device_id, do_typec_entry}, | |
0fc1db9d | 1454 | {"tee", SIZE_tee_client_device_id, do_tee_entry}, |
0bc44b2b | 1455 | {"wmi", SIZE_wmi_device_id, do_wmi_entry}, |
e6b0de46 | 1456 | {"mhi", SIZE_mhi_device_id, do_mhi_entry}, |
c268c0a8 | 1457 | {"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry}, |
7de3697e | 1458 | {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, |
eb0e90a8 | 1459 | {"ssam", SIZE_ssam_device_id, do_ssam_entry}, |
4a224ace | 1460 | {"dfl", SIZE_dfl_device_id, do_dfl_entry}, |
fa443bc3 | 1461 | {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, |
2959ab24 | 1462 | {"cdx", SIZE_cdx_device_id, do_cdx_entry}, |
1fa05877 | 1463 | {"vchiq", SIZE_vchiq_device_id, do_vchiq_entry}, |
f1cebae1 | 1464 | {"coreboot", SIZE_coreboot_device_id, do_coreboot_entry}, |
c58854c8 | 1465 | {"of", SIZE_of_device_id, do_of_entry}, |
abd20428 | 1466 | {"usb", SIZE_usb_device_id, do_usb_entry_multi}, |
600dbaf1 | 1467 | {"pnp", SIZE_pnp_device_id, do_pnp_device_entry}, |
a5d8d417 | 1468 | {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, |
ec91e78d MY |
1469 | }; |
1470 | ||
1da177e4 LT |
1471 | /* Create MODULE_ALIAS() statements. |
1472 | * At this time, we cannot write the actual output C source yet, | |
1473 | * so we write into the mod->dev_table_buf buffer. */ | |
1474 | void handle_moddevtable(struct module *mod, struct elf_info *info, | |
1475 | Elf_Sym *sym, const char *symname) | |
1476 | { | |
1477 | void *symval; | |
e0049825 | 1478 | char *zeros = NULL; |
9a8ace8b MY |
1479 | const char *type, *name; |
1480 | size_t typelen; | |
054a9cd3 | 1481 | static const char *prefix = "__mod_device_table__"; |
1da177e4 LT |
1482 | |
1483 | /* We're looking for a section relative symbol */ | |
1ce53adf | 1484 | if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) |
1da177e4 LT |
1485 | return; |
1486 | ||
e88aa7bb DM |
1487 | /* We're looking for an object */ |
1488 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) | |
1489 | return; | |
1490 | ||
054a9cd3 MY |
1491 | /* All our symbols are of form __mod_device_table__<type>__<name>. */ |
1492 | if (!strstarts(symname, prefix)) | |
626596e2 | 1493 | return; |
054a9cd3 MY |
1494 | type = symname + strlen(prefix); |
1495 | ||
9a8ace8b MY |
1496 | name = strstr(type, "__"); |
1497 | if (!name) | |
21bdd17b | 1498 | return; |
9a8ace8b | 1499 | typelen = name - type; |
2b1bd507 | 1500 | name += strlen("__"); |
626596e2 | 1501 | |
e0049825 | 1502 | /* Handle all-NULL symbols allocated into .bss */ |
1ce53adf | 1503 | if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { |
e0049825 KC |
1504 | zeros = calloc(1, sym->st_size); |
1505 | symval = zeros; | |
1506 | } else { | |
abe864b8 | 1507 | symval = sym_get_data(info, sym); |
e0049825 | 1508 | } |
1da177e4 | 1509 | |
abd20428 MY |
1510 | for (int i = 0; i < ARRAY_SIZE(devtable); i++) { |
1511 | const struct devtable *p = &devtable[i]; | |
626596e2 | 1512 | |
9a8ace8b | 1513 | if (sym_is(type, typelen, p->device_id)) { |
2b1bd507 | 1514 | do_table(name, symval, sym->st_size, p->id_size, |
abd20428 MY |
1515 | p->device_id, p->do_entry, mod); |
1516 | break; | |
626596e2 RR |
1517 | } |
1518 | } | |
abd20428 | 1519 | |
e0049825 | 1520 | free(zeros); |
1da177e4 | 1521 | } |