modpost: file2alias: check prototype of handler
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / scripts / mod / file2alias.c
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
13 #include "modpost.h"
14 #include "devicetable-offsets.h"
15
16 /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and
17 * use either stdint.h or inttypes.h for the rest. */
18 #if KERNEL_ELFCLASS == ELFCLASS32
19 typedef Elf32_Addr kernel_ulong_t;
20 #define BITS_PER_LONG 32
21 #else
22 typedef Elf64_Addr kernel_ulong_t;
23 #define BITS_PER_LONG 64
24 #endif
25 #ifdef __sun__
26 #include <inttypes.h>
27 #else
28 #include <stdint.h>
29 #endif
30
31 #include <ctype.h>
32 #include <stdbool.h>
33
34 typedef uint32_t __u32;
35 typedef uint16_t __u16;
36 typedef unsigned char __u8;
37
38 /* Big exception to the "don't include kernel headers into userspace, which
39 * even potentially has different endianness and word sizes, since
40 * we handle those differences explicitly below */
41 #include "../../include/linux/mod_devicetable.h"
42
43 /* This array collects all instances that use the generic do_table */
44 struct devtable {
45 const char *device_id; /* name of table, __mod_<name>_device_table. */
46 unsigned long id_size;
47 int (*do_entry)(const char *filename, void *symval, char *alias);
48 };
49
50 /* Define a variable f that holds the value of field f of struct devid
51 * based at address m.
52 */
53 #define DEF_FIELD(m, devid, f) \
54 typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
55 /* Define a variable f that holds the address of field f of struct devid
56 * based at address m. Due to the way typeof works, for a field of type
57 * T[N] the variable has type T(*)[N], _not_ T*.
58 */
59 #define DEF_FIELD_ADDR(m, devid, f) \
60 typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f)
61
62 #define ADD(str, sep, cond, field) \
63 do { \
64 strcat(str, sep); \
65 if (cond) \
66 sprintf(str + strlen(str), \
67 sizeof(field) == 1 ? "%02X" : \
68 sizeof(field) == 2 ? "%04X" : \
69 sizeof(field) == 4 ? "%08X" : "", \
70 field); \
71 else \
72 sprintf(str + strlen(str), "*"); \
73 } while(0)
74
75 /* Always end in a wildcard, for future extension */
76 static inline void add_wildcard(char *str)
77 {
78 int len = strlen(str);
79
80 if (str[len - 1] != '*')
81 strcat(str + len, "*");
82 }
83
84 /**
85 * Check that sizeof(device_id type) are consistent with size of section
86 * in .o file. If in-consistent then userspace and kernel does not agree
87 * on actual size which is a bug.
88 * Also verify that the final entry in the table is all zeros.
89 * Ignore both checks if build host differ from target host and size differs.
90 **/
91 static void device_id_check(const char *modname, const char *device_id,
92 unsigned long size, unsigned long id_size,
93 void *symval)
94 {
95 int i;
96
97 if (size % id_size || size < id_size) {
98 fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo "
99 "of the size of section __mod_%s_device_table=%lu.\n"
100 "Fix definition of struct %s_device_id "
101 "in mod_devicetable.h\n",
102 modname, device_id, id_size, device_id, size, device_id);
103 }
104 /* Verify last one is a terminator */
105 for (i = 0; i < id_size; i++ ) {
106 if (*(uint8_t*)(symval+size-id_size+i)) {
107 fprintf(stderr,"%s: struct %s_device_id is %lu bytes. "
108 "The last of %lu is:\n",
109 modname, device_id, id_size, size / id_size);
110 for (i = 0; i < id_size; i++ )
111 fprintf(stderr,"0x%02x ",
112 *(uint8_t*)(symval+size-id_size+i) );
113 fprintf(stderr,"\n");
114 fatal("%s: struct %s_device_id is not terminated "
115 "with a NULL entry!\n", modname, device_id);
116 }
117 }
118 }
119
120 /* USB is special because the bcdDevice can be matched against a numeric range */
121 /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
122 static void do_usb_entry(void *symval,
123 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
124 unsigned char range_lo, unsigned char range_hi,
125 unsigned char max, struct module *mod)
126 {
127 char alias[500];
128 DEF_FIELD(symval, usb_device_id, match_flags);
129 DEF_FIELD(symval, usb_device_id, idVendor);
130 DEF_FIELD(symval, usb_device_id, idProduct);
131 DEF_FIELD(symval, usb_device_id, bcdDevice_lo);
132 DEF_FIELD(symval, usb_device_id, bDeviceClass);
133 DEF_FIELD(symval, usb_device_id, bDeviceSubClass);
134 DEF_FIELD(symval, usb_device_id, bDeviceProtocol);
135 DEF_FIELD(symval, usb_device_id, bInterfaceClass);
136 DEF_FIELD(symval, usb_device_id, bInterfaceSubClass);
137 DEF_FIELD(symval, usb_device_id, bInterfaceProtocol);
138 DEF_FIELD(symval, usb_device_id, bInterfaceNumber);
139
140 strcpy(alias, "usb:");
141 ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR,
142 idVendor);
143 ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
144 idProduct);
145
146 strcat(alias, "d");
147 if (bcdDevice_initial_digits)
148 sprintf(alias + strlen(alias), "%0*X",
149 bcdDevice_initial_digits, bcdDevice_initial);
150 if (range_lo == range_hi)
151 sprintf(alias + strlen(alias), "%X", range_lo);
152 else if (range_lo > 0 || range_hi < max) {
153 if (range_lo > 0x9 || range_hi < 0xA)
154 sprintf(alias + strlen(alias),
155 "[%X-%X]",
156 range_lo,
157 range_hi);
158 else {
159 sprintf(alias + strlen(alias),
160 range_lo < 0x9 ? "[%X-9" : "[%X",
161 range_lo);
162 sprintf(alias + strlen(alias),
163 range_hi > 0xA ? "A-%X]" : "%X]",
164 range_hi);
165 }
166 }
167 if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1))
168 strcat(alias, "*");
169
170 ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
171 bDeviceClass);
172 ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
173 bDeviceSubClass);
174 ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
175 bDeviceProtocol);
176 ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
177 bInterfaceClass);
178 ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
179 bInterfaceSubClass);
180 ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
181 bInterfaceProtocol);
182 ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
183 bInterfaceNumber);
184
185 add_wildcard(alias);
186 buf_printf(&mod->dev_table_buf,
187 "MODULE_ALIAS(\"%s\");\n", alias);
188 }
189
190 /* Handles increment/decrement of BCD formatted integers */
191 /* Returns the previous value, so it works like i++ or i-- */
192 static unsigned int incbcd(unsigned int *bcd,
193 int inc,
194 unsigned char max,
195 size_t chars)
196 {
197 unsigned int init = *bcd, i, j;
198 unsigned long long c, dec = 0;
199
200 /* If bcd is not in BCD format, just increment */
201 if (max > 0x9) {
202 *bcd += inc;
203 return init;
204 }
205
206 /* Convert BCD to Decimal */
207 for (i=0 ; i < chars ; i++) {
208 c = (*bcd >> (i << 2)) & 0xf;
209 c = c > 9 ? 9 : c; /* force to bcd just in case */
210 for (j=0 ; j < i ; j++)
211 c = c * 10;
212 dec += c;
213 }
214
215 /* Do our increment/decrement */
216 dec += inc;
217 *bcd = 0;
218
219 /* Convert back to BCD */
220 for (i=0 ; i < chars ; i++) {
221 for (c=1,j=0 ; j < i ; j++)
222 c = c * 10;
223 c = (dec / c) % 10;
224 *bcd += c << (i << 2);
225 }
226 return init;
227 }
228
229 static void do_usb_entry_multi(void *symval, struct module *mod)
230 {
231 unsigned int devlo, devhi;
232 unsigned char chi, clo, max;
233 int ndigits;
234
235 DEF_FIELD(symval, usb_device_id, match_flags);
236 DEF_FIELD(symval, usb_device_id, idVendor);
237 DEF_FIELD(symval, usb_device_id, idProduct);
238 DEF_FIELD(symval, usb_device_id, bcdDevice_lo);
239 DEF_FIELD(symval, usb_device_id, bcdDevice_hi);
240 DEF_FIELD(symval, usb_device_id, bDeviceClass);
241 DEF_FIELD(symval, usb_device_id, bInterfaceClass);
242
243 devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ?
244 bcdDevice_lo : 0x0U;
245 devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
246 bcdDevice_hi : ~0x0U;
247
248 /* Figure out if this entry is in bcd or hex format */
249 max = 0x9; /* Default to decimal format */
250 for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) {
251 clo = (devlo >> (ndigits << 2)) & 0xf;
252 chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf;
253 if (clo > max || chi > max) {
254 max = 0xf;
255 break;
256 }
257 }
258
259 /*
260 * Some modules (visor) have empty slots as placeholder for
261 * run-time specification that results in catch-all alias
262 */
263 if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass))
264 return;
265
266 /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
267 for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {
268 clo = devlo & 0xf;
269 chi = devhi & 0xf;
270 if (chi > max) /* If we are in bcd mode, truncate if necessary */
271 chi = max;
272 devlo >>= 4;
273 devhi >>= 4;
274
275 if (devlo == devhi || !ndigits) {
276 do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod);
277 break;
278 }
279
280 if (clo > 0x0)
281 do_usb_entry(symval,
282 incbcd(&devlo, 1, max,
283 sizeof(bcdDevice_lo) * 2),
284 ndigits, clo, max, max, mod);
285
286 if (chi < max)
287 do_usb_entry(symval,
288 incbcd(&devhi, -1, max,
289 sizeof(bcdDevice_lo) * 2),
290 ndigits, 0x0, chi, max, mod);
291 }
292 }
293
294 static void do_usb_table(void *symval, unsigned long size,
295 struct module *mod)
296 {
297 unsigned int i;
298 const unsigned long id_size = SIZE_usb_device_id;
299
300 device_id_check(mod->name, "usb", size, id_size, symval);
301
302 /* Leave last one: it's the terminator. */
303 size -= id_size;
304
305 for (i = 0; i < size; i += id_size)
306 do_usb_entry_multi(symval + i, mod);
307 }
308
309 /* Looks like: hid:bNvNpN */
310 static int do_hid_entry(const char *filename,
311 void *symval, char *alias)
312 {
313 DEF_FIELD(symval, hid_device_id, bus);
314 DEF_FIELD(symval, hid_device_id, group);
315 DEF_FIELD(symval, hid_device_id, vendor);
316 DEF_FIELD(symval, hid_device_id, product);
317
318 sprintf(alias, "hid:");
319 ADD(alias, "b", bus != HID_BUS_ANY, bus);
320 ADD(alias, "g", group != HID_GROUP_ANY, group);
321 ADD(alias, "v", vendor != HID_ANY_ID, vendor);
322 ADD(alias, "p", product != HID_ANY_ID, product);
323
324 return 1;
325 }
326
327 /* Looks like: ieee1394:venNmoNspNverN */
328 static int do_ieee1394_entry(const char *filename,
329 void *symval, char *alias)
330 {
331 DEF_FIELD(symval, ieee1394_device_id, match_flags);
332 DEF_FIELD(symval, ieee1394_device_id, vendor_id);
333 DEF_FIELD(symval, ieee1394_device_id, model_id);
334 DEF_FIELD(symval, ieee1394_device_id, specifier_id);
335 DEF_FIELD(symval, ieee1394_device_id, version);
336
337 strcpy(alias, "ieee1394:");
338 ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID,
339 vendor_id);
340 ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID,
341 model_id);
342 ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID,
343 specifier_id);
344 ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION,
345 version);
346
347 add_wildcard(alias);
348 return 1;
349 }
350
351 /* Looks like: pci:vNdNsvNsdNbcNscNiN. */
352 static int do_pci_entry(const char *filename,
353 void *symval, char *alias)
354 {
355 /* Class field can be divided into these three. */
356 unsigned char baseclass, subclass, interface,
357 baseclass_mask, subclass_mask, interface_mask;
358
359 DEF_FIELD(symval, pci_device_id, vendor);
360 DEF_FIELD(symval, pci_device_id, device);
361 DEF_FIELD(symval, pci_device_id, subvendor);
362 DEF_FIELD(symval, pci_device_id, subdevice);
363 DEF_FIELD(symval, pci_device_id, class);
364 DEF_FIELD(symval, pci_device_id, class_mask);
365
366 strcpy(alias, "pci:");
367 ADD(alias, "v", vendor != PCI_ANY_ID, vendor);
368 ADD(alias, "d", device != PCI_ANY_ID, device);
369 ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor);
370 ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice);
371
372 baseclass = (class) >> 16;
373 baseclass_mask = (class_mask) >> 16;
374 subclass = (class) >> 8;
375 subclass_mask = (class_mask) >> 8;
376 interface = class;
377 interface_mask = class_mask;
378
379 if ((baseclass_mask != 0 && baseclass_mask != 0xFF)
380 || (subclass_mask != 0 && subclass_mask != 0xFF)
381 || (interface_mask != 0 && interface_mask != 0xFF)) {
382 warn("Can't handle masks in %s:%04X\n",
383 filename, class_mask);
384 return 0;
385 }
386
387 ADD(alias, "bc", baseclass_mask == 0xFF, baseclass);
388 ADD(alias, "sc", subclass_mask == 0xFF, subclass);
389 ADD(alias, "i", interface_mask == 0xFF, interface);
390 add_wildcard(alias);
391 return 1;
392 }
393
394 /* looks like: "ccw:tNmNdtNdmN" */
395 static int do_ccw_entry(const char *filename,
396 void *symval, char *alias)
397 {
398 DEF_FIELD(symval, ccw_device_id, match_flags);
399 DEF_FIELD(symval, ccw_device_id, cu_type);
400 DEF_FIELD(symval, ccw_device_id, cu_model);
401 DEF_FIELD(symval, ccw_device_id, dev_type);
402 DEF_FIELD(symval, ccw_device_id, dev_model);
403
404 strcpy(alias, "ccw:");
405 ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE,
406 cu_type);
407 ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL,
408 cu_model);
409 ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE,
410 dev_type);
411 ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL,
412 dev_model);
413 add_wildcard(alias);
414 return 1;
415 }
416
417 /* looks like: "ap:tN" */
418 static int do_ap_entry(const char *filename,
419 void *symval, char *alias)
420 {
421 DEF_FIELD(symval, ap_device_id, dev_type);
422
423 sprintf(alias, "ap:t%02X*", dev_type);
424 return 1;
425 }
426
427 /* looks like: "css:tN" */
428 static int do_css_entry(const char *filename,
429 void *symval, char *alias)
430 {
431 DEF_FIELD(symval, css_device_id, type);
432
433 sprintf(alias, "css:t%01X", type);
434 return 1;
435 }
436
437 /* Looks like: "serio:tyNprNidNexN" */
438 static int do_serio_entry(const char *filename,
439 void *symval, char *alias)
440 {
441 DEF_FIELD(symval, serio_device_id, type);
442 DEF_FIELD(symval, serio_device_id, proto);
443 DEF_FIELD(symval, serio_device_id, id);
444 DEF_FIELD(symval, serio_device_id, extra);
445
446 strcpy(alias, "serio:");
447 ADD(alias, "ty", type != SERIO_ANY, type);
448 ADD(alias, "pr", proto != SERIO_ANY, proto);
449 ADD(alias, "id", id != SERIO_ANY, id);
450 ADD(alias, "ex", extra != SERIO_ANY, extra);
451
452 add_wildcard(alias);
453 return 1;
454 }
455
456 /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */
457 static int do_acpi_entry(const char *filename,
458 void *symval, char *alias)
459 {
460 DEF_FIELD_ADDR(symval, acpi_device_id, id);
461 sprintf(alias, "acpi*:%s:*", *id);
462 return 1;
463 }
464
465 /* looks like: "pnp:dD" */
466 static void do_pnp_device_entry(void *symval, unsigned long size,
467 struct module *mod)
468 {
469 const unsigned long id_size = SIZE_pnp_device_id;
470 const unsigned int count = (size / id_size)-1;
471 unsigned int i;
472
473 device_id_check(mod->name, "pnp", size, id_size, symval);
474
475 for (i = 0; i < count; i++) {
476 DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id);
477 char acpi_id[sizeof(*id)];
478 int j;
479
480 buf_printf(&mod->dev_table_buf,
481 "MODULE_ALIAS(\"pnp:d%s*\");\n", *id);
482
483 /* fix broken pnp bus lowercasing */
484 for (j = 0; j < sizeof(acpi_id); j++)
485 acpi_id[j] = toupper((*id)[j]);
486 buf_printf(&mod->dev_table_buf,
487 "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
488 }
489 }
490
491 /* looks like: "pnp:dD" for every device of the card */
492 static void do_pnp_card_entries(void *symval, unsigned long size,
493 struct module *mod)
494 {
495 const unsigned long id_size = SIZE_pnp_card_device_id;
496 const unsigned int count = (size / id_size)-1;
497 unsigned int i;
498
499 device_id_check(mod->name, "pnp", size, id_size, symval);
500
501 for (i = 0; i < count; i++) {
502 unsigned int j;
503 DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs);
504
505 for (j = 0; j < PNP_MAX_DEVICES; j++) {
506 const char *id = (char *)(*devs)[j].id;
507 int i2, j2;
508 int dup = 0;
509
510 if (!id[0])
511 break;
512
513 /* find duplicate, already added value */
514 for (i2 = 0; i2 < i && !dup; i2++) {
515 DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs);
516
517 for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) {
518 const char *id2 = (char *)(*devs)[j2].id;
519
520 if (!id2[0])
521 break;
522
523 if (!strcmp(id, id2)) {
524 dup = 1;
525 break;
526 }
527 }
528 }
529
530 /* add an individual alias for every device entry */
531 if (!dup) {
532 char acpi_id[PNP_ID_LEN];
533 int k;
534
535 buf_printf(&mod->dev_table_buf,
536 "MODULE_ALIAS(\"pnp:d%s*\");\n", id);
537
538 /* fix broken pnp bus lowercasing */
539 for (k = 0; k < sizeof(acpi_id); k++)
540 acpi_id[k] = toupper(id[k]);
541 buf_printf(&mod->dev_table_buf,
542 "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
543 }
544 }
545 }
546 }
547
548 /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
549 static int do_pcmcia_entry(const char *filename,
550 void *symval, char *alias)
551 {
552 unsigned int i;
553 DEF_FIELD(symval, pcmcia_device_id, match_flags);
554 DEF_FIELD(symval, pcmcia_device_id, manf_id);
555 DEF_FIELD(symval, pcmcia_device_id, card_id);
556 DEF_FIELD(symval, pcmcia_device_id, func_id);
557 DEF_FIELD(symval, pcmcia_device_id, function);
558 DEF_FIELD(symval, pcmcia_device_id, device_no);
559 DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);
560
561 for (i=0; i<4; i++) {
562 (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]);
563 }
564
565 strcpy(alias, "pcmcia:");
566 ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
567 manf_id);
568 ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
569 card_id);
570 ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID,
571 func_id);
572 ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION,
573 function);
574 ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
575 device_no);
576 ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]);
577 ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]);
578 ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]);
579 ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);
580
581 add_wildcard(alias);
582 return 1;
583 }
584
585 static int do_of_entry (const char *filename, void *symval, char *alias)
586 {
587 int len;
588 char *tmp;
589 DEF_FIELD_ADDR(symval, of_device_id, name);
590 DEF_FIELD_ADDR(symval, of_device_id, type);
591 DEF_FIELD_ADDR(symval, of_device_id, compatible);
592
593 len = sprintf (alias, "of:N%sT%s",
594 (*name)[0] ? *name : "*",
595 (*type)[0] ? *type : "*");
596
597 if (compatible[0])
598 sprintf (&alias[len], "%sC%s",
599 (*type)[0] ? "*" : "",
600 *compatible);
601
602 /* Replace all whitespace with underscores */
603 for (tmp = alias; tmp && *tmp; tmp++)
604 if (isspace (*tmp))
605 *tmp = '_';
606
607 add_wildcard(alias);
608 return 1;
609 }
610
611 static int do_vio_entry(const char *filename, void *symval,
612 char *alias)
613 {
614 char *tmp;
615 DEF_FIELD_ADDR(symval, vio_device_id, type);
616 DEF_FIELD_ADDR(symval, vio_device_id, compat);
617
618 sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*",
619 (*compat)[0] ? *compat : "*");
620
621 /* Replace all whitespace with underscores */
622 for (tmp = alias; tmp && *tmp; tmp++)
623 if (isspace (*tmp))
624 *tmp = '_';
625
626 add_wildcard(alias);
627 return 1;
628 }
629
630 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
631
632 static void do_input(char *alias,
633 kernel_ulong_t *arr, unsigned int min, unsigned int max)
634 {
635 unsigned int i;
636
637 for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++)
638 arr[i] = TO_NATIVE(arr[i]);
639 for (i = min; i < max; i++)
640 if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG)))
641 sprintf(alias + strlen(alias), "%X,*", i);
642 }
643
644 /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */
645 static int do_input_entry(const char *filename, void *symval,
646 char *alias)
647 {
648 DEF_FIELD(symval, input_device_id, flags);
649 DEF_FIELD(symval, input_device_id, bustype);
650 DEF_FIELD(symval, input_device_id, vendor);
651 DEF_FIELD(symval, input_device_id, product);
652 DEF_FIELD(symval, input_device_id, version);
653 DEF_FIELD_ADDR(symval, input_device_id, evbit);
654 DEF_FIELD_ADDR(symval, input_device_id, keybit);
655 DEF_FIELD_ADDR(symval, input_device_id, relbit);
656 DEF_FIELD_ADDR(symval, input_device_id, absbit);
657 DEF_FIELD_ADDR(symval, input_device_id, mscbit);
658 DEF_FIELD_ADDR(symval, input_device_id, ledbit);
659 DEF_FIELD_ADDR(symval, input_device_id, sndbit);
660 DEF_FIELD_ADDR(symval, input_device_id, ffbit);
661 DEF_FIELD_ADDR(symval, input_device_id, swbit);
662
663 sprintf(alias, "input:");
664
665 ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype);
666 ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor);
667 ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product);
668 ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version);
669
670 sprintf(alias + strlen(alias), "-e*");
671 if (flags & INPUT_DEVICE_ID_MATCH_EVBIT)
672 do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX);
673 sprintf(alias + strlen(alias), "k*");
674 if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
675 do_input(alias, *keybit,
676 INPUT_DEVICE_ID_KEY_MIN_INTERESTING,
677 INPUT_DEVICE_ID_KEY_MAX);
678 sprintf(alias + strlen(alias), "r*");
679 if (flags & INPUT_DEVICE_ID_MATCH_RELBIT)
680 do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX);
681 sprintf(alias + strlen(alias), "a*");
682 if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
683 do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
684 sprintf(alias + strlen(alias), "m*");
685 if (flags & INPUT_DEVICE_ID_MATCH_MSCIT)
686 do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
687 sprintf(alias + strlen(alias), "l*");
688 if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
689 do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
690 sprintf(alias + strlen(alias), "s*");
691 if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
692 do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
693 sprintf(alias + strlen(alias), "f*");
694 if (flags & INPUT_DEVICE_ID_MATCH_FFBIT)
695 do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
696 sprintf(alias + strlen(alias), "w*");
697 if (flags & INPUT_DEVICE_ID_MATCH_SWBIT)
698 do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);
699 return 1;
700 }
701
702 static int do_eisa_entry(const char *filename, void *symval,
703 char *alias)
704 {
705 DEF_FIELD_ADDR(symval, eisa_device_id, sig);
706 if (sig[0])
707 sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig);
708 else
709 strcat(alias, "*");
710 return 1;
711 }
712
713 /* Looks like: parisc:tNhvNrevNsvN */
714 static int do_parisc_entry(const char *filename, void *symval,
715 char *alias)
716 {
717 DEF_FIELD(symval, parisc_device_id, hw_type);
718 DEF_FIELD(symval, parisc_device_id, hversion);
719 DEF_FIELD(symval, parisc_device_id, hversion_rev);
720 DEF_FIELD(symval, parisc_device_id, sversion);
721
722 strcpy(alias, "parisc:");
723 ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type);
724 ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion);
725 ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev);
726 ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion);
727
728 add_wildcard(alias);
729 return 1;
730 }
731
732 /* Looks like: sdio:cNvNdN. */
733 static int do_sdio_entry(const char *filename,
734 void *symval, char *alias)
735 {
736 DEF_FIELD(symval, sdio_device_id, class);
737 DEF_FIELD(symval, sdio_device_id, vendor);
738 DEF_FIELD(symval, sdio_device_id, device);
739
740 strcpy(alias, "sdio:");
741 ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class);
742 ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor);
743 ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device);
744 add_wildcard(alias);
745 return 1;
746 }
747
748 /* Looks like: ssb:vNidNrevN. */
749 static int do_ssb_entry(const char *filename,
750 void *symval, char *alias)
751 {
752 DEF_FIELD(symval, ssb_device_id, vendor);
753 DEF_FIELD(symval, ssb_device_id, coreid);
754 DEF_FIELD(symval, ssb_device_id, revision);
755
756 strcpy(alias, "ssb:");
757 ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor);
758 ADD(alias, "id", coreid != SSB_ANY_ID, coreid);
759 ADD(alias, "rev", revision != SSB_ANY_REV, revision);
760 add_wildcard(alias);
761 return 1;
762 }
763
764 /* Looks like: bcma:mNidNrevNclN. */
765 static int do_bcma_entry(const char *filename,
766 void *symval, char *alias)
767 {
768 DEF_FIELD(symval, bcma_device_id, manuf);
769 DEF_FIELD(symval, bcma_device_id, id);
770 DEF_FIELD(symval, bcma_device_id, rev);
771 DEF_FIELD(symval, bcma_device_id, class);
772
773 strcpy(alias, "bcma:");
774 ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf);
775 ADD(alias, "id", id != BCMA_ANY_ID, id);
776 ADD(alias, "rev", rev != BCMA_ANY_REV, rev);
777 ADD(alias, "cl", class != BCMA_ANY_CLASS, class);
778 add_wildcard(alias);
779 return 1;
780 }
781
782 /* Looks like: virtio:dNvN */
783 static int do_virtio_entry(const char *filename, void *symval,
784 char *alias)
785 {
786 DEF_FIELD(symval, virtio_device_id, device);
787 DEF_FIELD(symval, virtio_device_id, vendor);
788
789 strcpy(alias, "virtio:");
790 ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device);
791 ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor);
792
793 add_wildcard(alias);
794 return 1;
795 }
796
797 /*
798 * Looks like: vmbus:guid
799 * Each byte of the guid will be represented by two hex characters
800 * in the name.
801 */
802
803 static int do_vmbus_entry(const char *filename, void *symval,
804 char *alias)
805 {
806 int i;
807 DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid);
808 char guid_name[(sizeof(*guid) + 1) * 2];
809
810 for (i = 0; i < (sizeof(*guid) * 2); i += 2)
811 sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2]));
812
813 strcpy(alias, "vmbus:");
814 strcat(alias, guid_name);
815
816 return 1;
817 }
818
819 /* Looks like: i2c:S */
820 static int do_i2c_entry(const char *filename, void *symval,
821 char *alias)
822 {
823 DEF_FIELD_ADDR(symval, i2c_device_id, name);
824 sprintf(alias, I2C_MODULE_PREFIX "%s", *name);
825
826 return 1;
827 }
828
829 /* Looks like: spi:S */
830 static int do_spi_entry(const char *filename, void *symval,
831 char *alias)
832 {
833 DEF_FIELD_ADDR(symval, spi_device_id, name);
834 sprintf(alias, SPI_MODULE_PREFIX "%s", *name);
835
836 return 1;
837 }
838
839 static const struct dmifield {
840 const char *prefix;
841 int field;
842 } dmi_fields[] = {
843 { "bvn", DMI_BIOS_VENDOR },
844 { "bvr", DMI_BIOS_VERSION },
845 { "bd", DMI_BIOS_DATE },
846 { "svn", DMI_SYS_VENDOR },
847 { "pn", DMI_PRODUCT_NAME },
848 { "pvr", DMI_PRODUCT_VERSION },
849 { "rvn", DMI_BOARD_VENDOR },
850 { "rn", DMI_BOARD_NAME },
851 { "rvr", DMI_BOARD_VERSION },
852 { "cvn", DMI_CHASSIS_VENDOR },
853 { "ct", DMI_CHASSIS_TYPE },
854 { "cvr", DMI_CHASSIS_VERSION },
855 { NULL, DMI_NONE }
856 };
857
858 static void dmi_ascii_filter(char *d, const char *s)
859 {
860 /* Filter out characters we don't want to see in the modalias string */
861 for (; *s; s++)
862 if (*s > ' ' && *s < 127 && *s != ':')
863 *(d++) = *s;
864
865 *d = 0;
866 }
867
868
869 static int do_dmi_entry(const char *filename, void *symval,
870 char *alias)
871 {
872 int i, j;
873 DEF_FIELD_ADDR(symval, dmi_system_id, matches);
874 sprintf(alias, "dmi*");
875
876 for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
877 for (j = 0; j < 4; j++) {
878 if ((*matches)[j].slot &&
879 (*matches)[j].slot == dmi_fields[i].field) {
880 sprintf(alias + strlen(alias), ":%s*",
881 dmi_fields[i].prefix);
882 dmi_ascii_filter(alias + strlen(alias),
883 (*matches)[j].substr);
884 strcat(alias, "*");
885 }
886 }
887 }
888
889 strcat(alias, ":");
890 return 1;
891 }
892
893 static int do_platform_entry(const char *filename,
894 void *symval, char *alias)
895 {
896 DEF_FIELD_ADDR(symval, platform_device_id, name);
897 sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name);
898 return 1;
899 }
900
901 static int do_mdio_entry(const char *filename,
902 void *symval, char *alias)
903 {
904 int i;
905 DEF_FIELD(symval, mdio_device_id, phy_id);
906 DEF_FIELD(symval, mdio_device_id, phy_id_mask);
907
908 alias += sprintf(alias, MDIO_MODULE_PREFIX);
909
910 for (i = 0; i < 32; i++) {
911 if (!((phy_id_mask >> (31-i)) & 1))
912 *(alias++) = '?';
913 else if ((phy_id >> (31-i)) & 1)
914 *(alias++) = '1';
915 else
916 *(alias++) = '0';
917 }
918
919 /* Terminate the string */
920 *alias = 0;
921
922 return 1;
923 }
924
925 /* Looks like: zorro:iN. */
926 static int do_zorro_entry(const char *filename, void *symval,
927 char *alias)
928 {
929 DEF_FIELD(symval, zorro_device_id, id);
930 strcpy(alias, "zorro:");
931 ADD(alias, "i", id != ZORRO_WILDCARD, id);
932 return 1;
933 }
934
935 /* looks like: "pnp:dD" */
936 static int do_isapnp_entry(const char *filename,
937 void *symval, char *alias)
938 {
939 DEF_FIELD(symval, isapnp_device_id, vendor);
940 DEF_FIELD(symval, isapnp_device_id, function);
941 sprintf(alias, "pnp:d%c%c%c%x%x%x%x*",
942 'A' + ((vendor >> 2) & 0x3f) - 1,
943 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
944 'A' + ((vendor >> 8) & 0x1f) - 1,
945 (function >> 4) & 0x0f, function & 0x0f,
946 (function >> 12) & 0x0f, (function >> 8) & 0x0f);
947 return 1;
948 }
949
950 /* Looks like: "ipack:fNvNdN". */
951 static int do_ipack_entry(const char *filename,
952 void *symval, char *alias)
953 {
954 DEF_FIELD(symval, ipack_device_id, format);
955 DEF_FIELD(symval, ipack_device_id, vendor);
956 DEF_FIELD(symval, ipack_device_id, device);
957 strcpy(alias, "ipack:");
958 ADD(alias, "f", format != IPACK_ANY_FORMAT, format);
959 ADD(alias, "v", vendor != IPACK_ANY_ID, vendor);
960 ADD(alias, "d", device != IPACK_ANY_ID, device);
961 add_wildcard(alias);
962 return 1;
963 }
964
965 /*
966 * Append a match expression for a single masked hex digit.
967 * outp points to a pointer to the character at which to append.
968 * *outp is updated on return to point just after the appended text,
969 * to facilitate further appending.
970 */
971 static void append_nibble_mask(char **outp,
972 unsigned int nibble, unsigned int mask)
973 {
974 char *p = *outp;
975 unsigned int i;
976
977 switch (mask) {
978 case 0:
979 *p++ = '?';
980 break;
981
982 case 0xf:
983 p += sprintf(p, "%X", nibble);
984 break;
985
986 default:
987 /*
988 * Dumbly emit a match pattern for all possible matching
989 * digits. This could be improved in some cases using ranges,
990 * but it has the advantage of being trivially correct, and is
991 * often optimal.
992 */
993 *p++ = '[';
994 for (i = 0; i < 0x10; i++)
995 if ((i & mask) == nibble)
996 p += sprintf(p, "%X", i);
997 *p++ = ']';
998 }
999
1000 /* Ensure that the string remains NUL-terminated: */
1001 *p = '\0';
1002
1003 /* Advance the caller's end-of-string pointer: */
1004 *outp = p;
1005 }
1006
1007 /*
1008 * looks like: "amba:dN"
1009 *
1010 * N is exactly 8 digits, where each is an upper-case hex digit, or
1011 * a ? or [] pattern matching exactly one digit.
1012 */
1013 static int do_amba_entry(const char *filename,
1014 void *symval, char *alias)
1015 {
1016 unsigned int digit;
1017 char *p = alias;
1018 DEF_FIELD(symval, amba_id, id);
1019 DEF_FIELD(symval, amba_id, mask);
1020
1021 if ((id & mask) != id)
1022 fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: "
1023 "id=0x%08X, mask=0x%08X. Please fix this driver.\n",
1024 filename, id, mask);
1025
1026 p += sprintf(alias, "amba:d");
1027 for (digit = 0; digit < 8; digit++)
1028 append_nibble_mask(&p,
1029 (id >> (4 * (7 - digit))) & 0xf,
1030 (mask >> (4 * (7 - digit))) & 0xf);
1031
1032 return 1;
1033 }
1034
1035 /* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,*
1036 * All fields are numbers. It would be nicer to use strings for vendor
1037 * and feature, but getting those out of the build system here is too
1038 * complicated.
1039 */
1040
1041 static int do_x86cpu_entry(const char *filename, void *symval,
1042 char *alias)
1043 {
1044 DEF_FIELD(symval, x86_cpu_id, feature);
1045 DEF_FIELD(symval, x86_cpu_id, family);
1046 DEF_FIELD(symval, x86_cpu_id, model);
1047 DEF_FIELD(symval, x86_cpu_id, vendor);
1048
1049 strcpy(alias, "x86cpu:");
1050 ADD(alias, "vendor:", vendor != X86_VENDOR_ANY, vendor);
1051 ADD(alias, ":family:", family != X86_FAMILY_ANY, family);
1052 ADD(alias, ":model:", model != X86_MODEL_ANY, model);
1053 strcat(alias, ":feature:*");
1054 if (feature != X86_FEATURE_ANY)
1055 sprintf(alias + strlen(alias), "%04X*", feature);
1056 return 1;
1057 }
1058
1059 /* LOOKS like cpu:type:*:feature:*FEAT* */
1060 static int do_cpu_entry(const char *filename, void *symval, char *alias)
1061 {
1062 DEF_FIELD(symval, cpu_feature, feature);
1063
1064 sprintf(alias, "cpu:type:*:feature:*%04X*", feature);
1065 return 1;
1066 }
1067
1068 /* Looks like: mei:S */
1069 static int do_mei_entry(const char *filename, void *symval,
1070 char *alias)
1071 {
1072 DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
1073
1074 sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name);
1075
1076 return 1;
1077 }
1078
1079 /* Does namelen bytes of name exactly match the symbol? */
1080 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
1081 {
1082 if (namelen != strlen(symbol))
1083 return false;
1084
1085 return memcmp(name, symbol, namelen) == 0;
1086 }
1087
1088 static void do_table(void *symval, unsigned long size,
1089 unsigned long id_size,
1090 const char *device_id,
1091 int (*do_entry)(const char *filename, void *symval, char *alias),
1092 struct module *mod)
1093 {
1094 unsigned int i;
1095 char alias[500];
1096
1097 device_id_check(mod->name, device_id, size, id_size, symval);
1098 /* Leave last one: it's the terminator. */
1099 size -= id_size;
1100
1101 for (i = 0; i < size; i += id_size) {
1102 if (do_entry(mod->name, symval+i, alias)) {
1103 buf_printf(&mod->dev_table_buf,
1104 "MODULE_ALIAS(\"%s\");\n", alias);
1105 }
1106 }
1107 }
1108
1109 static const struct devtable devtable[] = {
1110 {"hid", SIZE_hid_device_id, do_hid_entry},
1111 {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry},
1112 {"pci", SIZE_pci_device_id, do_pci_entry},
1113 {"ccw", SIZE_ccw_device_id, do_ccw_entry},
1114 {"ap", SIZE_ap_device_id, do_ap_entry},
1115 {"css", SIZE_css_device_id, do_css_entry},
1116 {"serio", SIZE_serio_device_id, do_serio_entry},
1117 {"acpi", SIZE_acpi_device_id, do_acpi_entry},
1118 {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry},
1119 {"of", SIZE_of_device_id, do_of_entry},
1120 {"vio", SIZE_vio_device_id, do_vio_entry},
1121 {"input", SIZE_input_device_id, do_input_entry},
1122 {"eisa", SIZE_eisa_device_id, do_eisa_entry},
1123 {"parisc", SIZE_parisc_device_id, do_parisc_entry},
1124 {"sdio", SIZE_sdio_device_id, do_sdio_entry},
1125 {"ssb", SIZE_ssb_device_id, do_ssb_entry},
1126 {"bcma", SIZE_bcma_device_id, do_bcma_entry},
1127 {"virtio", SIZE_virtio_device_id, do_virtio_entry},
1128 {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry},
1129 {"i2c", SIZE_i2c_device_id, do_i2c_entry},
1130 {"spi", SIZE_spi_device_id, do_spi_entry},
1131 {"dmi", SIZE_dmi_system_id, do_dmi_entry},
1132 {"platform", SIZE_platform_device_id, do_platform_entry},
1133 {"mdio", SIZE_mdio_device_id, do_mdio_entry},
1134 {"zorro", SIZE_zorro_device_id, do_zorro_entry},
1135 {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry},
1136 {"ipack", SIZE_ipack_device_id, do_ipack_entry},
1137 {"amba", SIZE_amba_id, do_amba_entry},
1138 {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry},
1139 {"cpu", SIZE_cpu_feature, do_cpu_entry},
1140 {"mei", SIZE_mei_cl_device_id, do_mei_entry},
1141 };
1142
1143 /* Create MODULE_ALIAS() statements.
1144 * At this time, we cannot write the actual output C source yet,
1145 * so we write into the mod->dev_table_buf buffer. */
1146 void handle_moddevtable(struct module *mod, struct elf_info *info,
1147 Elf_Sym *sym, const char *symname)
1148 {
1149 void *symval;
1150 char *zeros = NULL;
1151 const char *name;
1152 unsigned int namelen;
1153
1154 /* We're looking for a section relative symbol */
1155 if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
1156 return;
1157
1158 /* We're looking for an object */
1159 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
1160 return;
1161
1162 /* All our symbols are of form <prefix>__mod_XXX_device_table. */
1163 name = strstr(symname, "__mod_");
1164 if (!name)
1165 return;
1166 name += strlen("__mod_");
1167 namelen = strlen(name);
1168 if (namelen < strlen("_device_table"))
1169 return;
1170 if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
1171 return;
1172 namelen -= strlen("_device_table");
1173
1174 /* Handle all-NULL symbols allocated into .bss */
1175 if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
1176 zeros = calloc(1, sym->st_size);
1177 symval = zeros;
1178 } else {
1179 symval = (void *)info->hdr
1180 + info->sechdrs[get_secindex(info, sym)].sh_offset
1181 + sym->st_value;
1182 }
1183
1184 /* First handle the "special" cases */
1185 if (sym_is(name, namelen, "usb"))
1186 do_usb_table(symval, sym->st_size, mod);
1187 else if (sym_is(name, namelen, "pnp"))
1188 do_pnp_device_entry(symval, sym->st_size, mod);
1189 else if (sym_is(name, namelen, "pnp_card"))
1190 do_pnp_card_entries(symval, sym->st_size, mod);
1191 else {
1192 int i;
1193
1194 for (i = 0; i < ARRAY_SIZE(devtable); i++) {
1195 const struct devtable *p = &devtable[i];
1196
1197 if (sym_is(name, namelen, p->device_id)) {
1198 do_table(symval, sym->st_size, p->id_size,
1199 p->device_id, p->do_entry, mod);
1200 break;
1201 }
1202 }
1203 }
1204 free(zeros);
1205 }
1206
1207 /* Now add out buffered information to the generated C source */
1208 void add_moddevtable(struct buffer *buf, struct module *mod)
1209 {
1210 buf_printf(buf, "\n");
1211 buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
1212 free(mod->dev_table_buf.p);
1213 }