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 15 /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and 16 * use either stdint.h or inttypes.h for the rest. */ 17 #if KERNEL_ELFCLASS == ELFCLASS32 18 typedef Elf32_Addr kernel_ulong_t; 19 #define BITS_PER_LONG 32 20 #else 21 typedef Elf64_Addr kernel_ulong_t; 22 #define BITS_PER_LONG 64 23 #endif 24 #ifdef __sun__ 25 #include <inttypes.h> 26 #else 27 #include <stdint.h> 28 #endif 29 30 #include <ctype.h> 31 32 typedef uint32_t __u32; 33 typedef uint16_t __u16; 34 typedef unsigned char __u8; 35 36 /* Big exception to the "don't include kernel headers into userspace, which 37 * even potentially has different endianness and word sizes, since 38 * we handle those differences explicitly below */ 39 #include "../../include/linux/mod_devicetable.h" 40 41 #define ADD(str, sep, cond, field) \ 42 do { \ 43 strcat(str, sep); \ 44 if (cond) \ 45 sprintf(str + strlen(str), \ 46 sizeof(field) == 1 ? "%02X" : \ 47 sizeof(field) == 2 ? "%04X" : \ 48 sizeof(field) == 4 ? "%08X" : "", \ 49 field); \ 50 else \ 51 sprintf(str + strlen(str), "*"); \ 52 } while(0) 53 54 /* Always end in a wildcard, for future extension */ 55 static inline void add_wildcard(char *str) 56 { 57 int len = strlen(str); 58 59 if (str[len - 1] != '*') 60 strcat(str + len, "*"); 61 } 62 63 unsigned int cross_build = 0; 64 /** 65 * Check that sizeof(device_id type) are consistent with size of section 66 * in .o file. If in-consistent then userspace and kernel does not agree 67 * on actual size which is a bug. 68 * Also verify that the final entry in the table is all zeros. 69 * Ignore both checks if build host differ from target host and size differs. 70 **/ 71 static void device_id_check(const char *modname, const char *device_id, 72 unsigned long size, unsigned long id_size, 73 void *symval) 74 { 75 int i; 76 77 if (size % id_size || size < id_size) { 78 if (cross_build != 0) 79 return; 80 fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " 81 "of the size of section __mod_%s_device_table=%lu.\n" 82 "Fix definition of struct %s_device_id " 83 "in mod_devicetable.h\n", 84 modname, device_id, id_size, device_id, size, device_id); 85 } 86 /* Verify last one is a terminator */ 87 for (i = 0; i < id_size; i++ ) { 88 if (*(uint8_t*)(symval+size-id_size+i)) { 89 fprintf(stderr,"%s: struct %s_device_id is %lu bytes. " 90 "The last of %lu is:\n", 91 modname, device_id, id_size, size / id_size); 92 for (i = 0; i < id_size; i++ ) 93 fprintf(stderr,"0x%02x ", 94 *(uint8_t*)(symval+size-id_size+i) ); 95 fprintf(stderr,"\n"); 96 fatal("%s: struct %s_device_id is not terminated " 97 "with a NULL entry!\n", modname, device_id); 98 } 99 } 100 } 101 102 /* USB is special because the bcdDevice can be matched against a numeric range */ 103 /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ 104 static void do_usb_entry(struct usb_device_id *id, 105 unsigned int bcdDevice_initial, int bcdDevice_initial_digits, 106 unsigned char range_lo, unsigned char range_hi, 107 struct module *mod) 108 { 109 char alias[500]; 110 strcpy(alias, "usb:"); 111 ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, 112 id->idVendor); 113 ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT, 114 id->idProduct); 115 116 strcat(alias, "d"); 117 if (bcdDevice_initial_digits) 118 sprintf(alias + strlen(alias), "%0*X", 119 bcdDevice_initial_digits, bcdDevice_initial); 120 if (range_lo == range_hi) 121 sprintf(alias + strlen(alias), "%u", range_lo); 122 else if (range_lo > 0 || range_hi < 9) 123 sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi); 124 if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1)) 125 strcat(alias, "*"); 126 127 ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, 128 id->bDeviceClass); 129 ADD(alias, "dsc", 130 id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, 131 id->bDeviceSubClass); 132 ADD(alias, "dp", 133 id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, 134 id->bDeviceProtocol); 135 ADD(alias, "ic", 136 id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, 137 id->bInterfaceClass); 138 ADD(alias, "isc", 139 id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, 140 id->bInterfaceSubClass); 141 ADD(alias, "ip", 142 id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, 143 id->bInterfaceProtocol); 144 145 add_wildcard(alias); 146 buf_printf(&mod->dev_table_buf, 147 "MODULE_ALIAS(\"%s\");\n", alias); 148 } 149 150 static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) 151 { 152 unsigned int devlo, devhi; 153 unsigned char chi, clo; 154 int ndigits; 155 156 id->match_flags = TO_NATIVE(id->match_flags); 157 id->idVendor = TO_NATIVE(id->idVendor); 158 id->idProduct = TO_NATIVE(id->idProduct); 159 160 devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? 161 TO_NATIVE(id->bcdDevice_lo) : 0x0U; 162 devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? 163 TO_NATIVE(id->bcdDevice_hi) : ~0x0U; 164 165 /* 166 * Some modules (visor) have empty slots as placeholder for 167 * run-time specification that results in catch-all alias 168 */ 169 if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass)) 170 return; 171 172 /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ 173 for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { 174 clo = devlo & 0xf; 175 chi = devhi & 0xf; 176 if (chi > 9) /* it's bcd not hex */ 177 chi = 9; 178 devlo >>= 4; 179 devhi >>= 4; 180 181 if (devlo == devhi || !ndigits) { 182 do_usb_entry(id, devlo, ndigits, clo, chi, mod); 183 break; 184 } 185 186 if (clo > 0) 187 do_usb_entry(id, devlo++, ndigits, clo, 9, mod); 188 189 if (chi < 9) 190 do_usb_entry(id, devhi--, ndigits, 0, chi, mod); 191 } 192 } 193 194 static void do_usb_table(void *symval, unsigned long size, 195 struct module *mod) 196 { 197 unsigned int i; 198 const unsigned long id_size = sizeof(struct usb_device_id); 199 200 device_id_check(mod->name, "usb", size, id_size, symval); 201 202 /* Leave last one: it's the terminator. */ 203 size -= id_size; 204 205 for (i = 0; i < size; i += id_size) 206 do_usb_entry_multi(symval + i, mod); 207 } 208 209 /* Looks like: hid:bNvNpN */ 210 static int do_hid_entry(const char *filename, 211 struct hid_device_id *id, char *alias) 212 { 213 id->vendor = TO_NATIVE(id->vendor); 214 id->product = TO_NATIVE(id->product); 215 216 sprintf(alias, "hid:b%04X", id->bus); 217 ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); 218 ADD(alias, "p", id->product != HID_ANY_ID, id->product); 219 220 return 1; 221 } 222 223 /* Looks like: ieee1394:venNmoNspNverN */ 224 static int do_ieee1394_entry(const char *filename, 225 struct ieee1394_device_id *id, char *alias) 226 { 227 id->match_flags = TO_NATIVE(id->match_flags); 228 id->vendor_id = TO_NATIVE(id->vendor_id); 229 id->model_id = TO_NATIVE(id->model_id); 230 id->specifier_id = TO_NATIVE(id->specifier_id); 231 id->version = TO_NATIVE(id->version); 232 233 strcpy(alias, "ieee1394:"); 234 ADD(alias, "ven", id->match_flags & IEEE1394_MATCH_VENDOR_ID, 235 id->vendor_id); 236 ADD(alias, "mo", id->match_flags & IEEE1394_MATCH_MODEL_ID, 237 id->model_id); 238 ADD(alias, "sp", id->match_flags & IEEE1394_MATCH_SPECIFIER_ID, 239 id->specifier_id); 240 ADD(alias, "ver", id->match_flags & IEEE1394_MATCH_VERSION, 241 id->version); 242 243 add_wildcard(alias); 244 return 1; 245 } 246 247 /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ 248 static int do_pci_entry(const char *filename, 249 struct pci_device_id *id, char *alias) 250 { 251 /* Class field can be divided into these three. */ 252 unsigned char baseclass, subclass, interface, 253 baseclass_mask, subclass_mask, interface_mask; 254 255 id->vendor = TO_NATIVE(id->vendor); 256 id->device = TO_NATIVE(id->device); 257 id->subvendor = TO_NATIVE(id->subvendor); 258 id->subdevice = TO_NATIVE(id->subdevice); 259 id->class = TO_NATIVE(id->class); 260 id->class_mask = TO_NATIVE(id->class_mask); 261 262 strcpy(alias, "pci:"); 263 ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor); 264 ADD(alias, "d", id->device != PCI_ANY_ID, id->device); 265 ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor); 266 ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice); 267 268 baseclass = (id->class) >> 16; 269 baseclass_mask = (id->class_mask) >> 16; 270 subclass = (id->class) >> 8; 271 subclass_mask = (id->class_mask) >> 8; 272 interface = id->class; 273 interface_mask = id->class_mask; 274 275 if ((baseclass_mask != 0 && baseclass_mask != 0xFF) 276 || (subclass_mask != 0 && subclass_mask != 0xFF) 277 || (interface_mask != 0 && interface_mask != 0xFF)) { 278 warn("Can't handle masks in %s:%04X\n", 279 filename, id->class_mask); 280 return 0; 281 } 282 283 ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); 284 ADD(alias, "sc", subclass_mask == 0xFF, subclass); 285 ADD(alias, "i", interface_mask == 0xFF, interface); 286 add_wildcard(alias); 287 return 1; 288 } 289 290 /* looks like: "ccw:tNmNdtNdmN" */ 291 static int do_ccw_entry(const char *filename, 292 struct ccw_device_id *id, char *alias) 293 { 294 id->match_flags = TO_NATIVE(id->match_flags); 295 id->cu_type = TO_NATIVE(id->cu_type); 296 id->cu_model = TO_NATIVE(id->cu_model); 297 id->dev_type = TO_NATIVE(id->dev_type); 298 id->dev_model = TO_NATIVE(id->dev_model); 299 300 strcpy(alias, "ccw:"); 301 ADD(alias, "t", id->match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, 302 id->cu_type); 303 ADD(alias, "m", id->match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, 304 id->cu_model); 305 ADD(alias, "dt", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, 306 id->dev_type); 307 ADD(alias, "dm", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, 308 id->dev_model); 309 add_wildcard(alias); 310 return 1; 311 } 312 313 /* looks like: "ap:tN" */ 314 static int do_ap_entry(const char *filename, 315 struct ap_device_id *id, char *alias) 316 { 317 sprintf(alias, "ap:t%02X*", id->dev_type); 318 return 1; 319 } 320 321 /* looks like: "css:tN" */ 322 static int do_css_entry(const char *filename, 323 struct css_device_id *id, char *alias) 324 { 325 sprintf(alias, "css:t%01X", id->type); 326 return 1; 327 } 328 329 /* Looks like: "serio:tyNprNidNexN" */ 330 static int do_serio_entry(const char *filename, 331 struct serio_device_id *id, char *alias) 332 { 333 id->type = TO_NATIVE(id->type); 334 id->proto = TO_NATIVE(id->proto); 335 id->id = TO_NATIVE(id->id); 336 id->extra = TO_NATIVE(id->extra); 337 338 strcpy(alias, "serio:"); 339 ADD(alias, "ty", id->type != SERIO_ANY, id->type); 340 ADD(alias, "pr", id->proto != SERIO_ANY, id->proto); 341 ADD(alias, "id", id->id != SERIO_ANY, id->id); 342 ADD(alias, "ex", id->extra != SERIO_ANY, id->extra); 343 344 add_wildcard(alias); 345 return 1; 346 } 347 348 /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ 349 static int do_acpi_entry(const char *filename, 350 struct acpi_device_id *id, char *alias) 351 { 352 sprintf(alias, "acpi*:%s:*", id->id); 353 return 1; 354 } 355 356 /* looks like: "pnp:dD" */ 357 static void do_pnp_device_entry(void *symval, unsigned long size, 358 struct module *mod) 359 { 360 const unsigned long id_size = sizeof(struct pnp_device_id); 361 const unsigned int count = (size / id_size)-1; 362 const struct pnp_device_id *devs = symval; 363 unsigned int i; 364 365 device_id_check(mod->name, "pnp", size, id_size, symval); 366 367 for (i = 0; i < count; i++) { 368 const char *id = (char *)devs[i].id; 369 370 buf_printf(&mod->dev_table_buf, 371 "MODULE_ALIAS(\"pnp:d%s*\");\n", id); 372 buf_printf(&mod->dev_table_buf, 373 "MODULE_ALIAS(\"acpi*:%s:*\");\n", id); 374 } 375 } 376 377 /* looks like: "pnp:dD" for every device of the card */ 378 static void do_pnp_card_entries(void *symval, unsigned long size, 379 struct module *mod) 380 { 381 const unsigned long id_size = sizeof(struct pnp_card_device_id); 382 const unsigned int count = (size / id_size)-1; 383 const struct pnp_card_device_id *cards = symval; 384 unsigned int i; 385 386 device_id_check(mod->name, "pnp", size, id_size, symval); 387 388 for (i = 0; i < count; i++) { 389 unsigned int j; 390 const struct pnp_card_device_id *card = &cards[i]; 391 392 for (j = 0; j < PNP_MAX_DEVICES; j++) { 393 const char *id = (char *)card->devs[j].id; 394 int i2, j2; 395 int dup = 0; 396 397 if (!id[0]) 398 break; 399 400 /* find duplicate, already added value */ 401 for (i2 = 0; i2 < i && !dup; i2++) { 402 const struct pnp_card_device_id *card2 = &cards[i2]; 403 404 for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { 405 const char *id2 = (char *)card2->devs[j2].id; 406 407 if (!id2[0]) 408 break; 409 410 if (!strcmp(id, id2)) { 411 dup = 1; 412 break; 413 } 414 } 415 } 416 417 /* add an individual alias for every device entry */ 418 if (!dup) { 419 buf_printf(&mod->dev_table_buf, 420 "MODULE_ALIAS(\"pnp:d%s*\");\n", id); 421 buf_printf(&mod->dev_table_buf, 422 "MODULE_ALIAS(\"acpi*:%s:*\");\n", id); 423 } 424 } 425 } 426 } 427 428 /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ 429 static int do_pcmcia_entry(const char *filename, 430 struct pcmcia_device_id *id, char *alias) 431 { 432 unsigned int i; 433 434 id->match_flags = TO_NATIVE(id->match_flags); 435 id->manf_id = TO_NATIVE(id->manf_id); 436 id->card_id = TO_NATIVE(id->card_id); 437 id->func_id = TO_NATIVE(id->func_id); 438 id->function = TO_NATIVE(id->function); 439 id->device_no = TO_NATIVE(id->device_no); 440 441 for (i=0; i<4; i++) { 442 id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]); 443 } 444 445 strcpy(alias, "pcmcia:"); 446 ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, 447 id->manf_id); 448 ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, 449 id->card_id); 450 ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, 451 id->func_id); 452 ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, 453 id->function); 454 ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, 455 id->device_no); 456 ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]); 457 ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]); 458 ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]); 459 ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]); 460 461 add_wildcard(alias); 462 return 1; 463 } 464 465 466 467 static int do_of_entry (const char *filename, struct of_device_id *of, char *alias) 468 { 469 int len; 470 char *tmp; 471 len = sprintf (alias, "of:N%sT%s", 472 of->name[0] ? of->name : "*", 473 of->type[0] ? of->type : "*"); 474 475 if (of->compatible[0]) 476 sprintf (&alias[len], "%sC%s", 477 of->type[0] ? "*" : "", 478 of->compatible); 479 480 /* Replace all whitespace with underscores */ 481 for (tmp = alias; tmp && *tmp; tmp++) 482 if (isspace (*tmp)) 483 *tmp = '_'; 484 485 add_wildcard(alias); 486 return 1; 487 } 488 489 static int do_vio_entry(const char *filename, struct vio_device_id *vio, 490 char *alias) 491 { 492 char *tmp; 493 494 sprintf(alias, "vio:T%sS%s", vio->type[0] ? vio->type : "*", 495 vio->compat[0] ? vio->compat : "*"); 496 497 /* Replace all whitespace with underscores */ 498 for (tmp = alias; tmp && *tmp; tmp++) 499 if (isspace (*tmp)) 500 *tmp = '_'; 501 502 add_wildcard(alias); 503 return 1; 504 } 505 506 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 507 508 static void do_input(char *alias, 509 kernel_ulong_t *arr, unsigned int min, unsigned int max) 510 { 511 unsigned int i; 512 513 for (i = min; i < max; i++) 514 if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) 515 sprintf(alias + strlen(alias), "%X,*", i); 516 } 517 518 /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ 519 static int do_input_entry(const char *filename, struct input_device_id *id, 520 char *alias) 521 { 522 sprintf(alias, "input:"); 523 524 ADD(alias, "b", id->flags & INPUT_DEVICE_ID_MATCH_BUS, id->bustype); 525 ADD(alias, "v", id->flags & INPUT_DEVICE_ID_MATCH_VENDOR, id->vendor); 526 ADD(alias, "p", id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT, id->product); 527 ADD(alias, "e", id->flags & INPUT_DEVICE_ID_MATCH_VERSION, id->version); 528 529 sprintf(alias + strlen(alias), "-e*"); 530 if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) 531 do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX); 532 sprintf(alias + strlen(alias), "k*"); 533 if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) 534 do_input(alias, id->keybit, 535 INPUT_DEVICE_ID_KEY_MIN_INTERESTING, 536 INPUT_DEVICE_ID_KEY_MAX); 537 sprintf(alias + strlen(alias), "r*"); 538 if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT) 539 do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX); 540 sprintf(alias + strlen(alias), "a*"); 541 if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT) 542 do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX); 543 sprintf(alias + strlen(alias), "m*"); 544 if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT) 545 do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); 546 sprintf(alias + strlen(alias), "l*"); 547 if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT) 548 do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX); 549 sprintf(alias + strlen(alias), "s*"); 550 if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT) 551 do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX); 552 sprintf(alias + strlen(alias), "f*"); 553 if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT) 554 do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX); 555 sprintf(alias + strlen(alias), "w*"); 556 if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT) 557 do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX); 558 return 1; 559 } 560 561 static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, 562 char *alias) 563 { 564 if (eisa->sig[0]) 565 sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig); 566 else 567 strcat(alias, "*"); 568 return 1; 569 } 570 571 /* Looks like: parisc:tNhvNrevNsvN */ 572 static int do_parisc_entry(const char *filename, struct parisc_device_id *id, 573 char *alias) 574 { 575 id->hw_type = TO_NATIVE(id->hw_type); 576 id->hversion = TO_NATIVE(id->hversion); 577 id->hversion_rev = TO_NATIVE(id->hversion_rev); 578 id->sversion = TO_NATIVE(id->sversion); 579 580 strcpy(alias, "parisc:"); 581 ADD(alias, "t", id->hw_type != PA_HWTYPE_ANY_ID, id->hw_type); 582 ADD(alias, "hv", id->hversion != PA_HVERSION_ANY_ID, id->hversion); 583 ADD(alias, "rev", id->hversion_rev != PA_HVERSION_REV_ANY_ID, id->hversion_rev); 584 ADD(alias, "sv", id->sversion != PA_SVERSION_ANY_ID, id->sversion); 585 586 add_wildcard(alias); 587 return 1; 588 } 589 590 /* Looks like: sdio:cNvNdN. */ 591 static int do_sdio_entry(const char *filename, 592 struct sdio_device_id *id, char *alias) 593 { 594 id->class = TO_NATIVE(id->class); 595 id->vendor = TO_NATIVE(id->vendor); 596 id->device = TO_NATIVE(id->device); 597 598 strcpy(alias, "sdio:"); 599 ADD(alias, "c", id->class != (__u8)SDIO_ANY_ID, id->class); 600 ADD(alias, "v", id->vendor != (__u16)SDIO_ANY_ID, id->vendor); 601 ADD(alias, "d", id->device != (__u16)SDIO_ANY_ID, id->device); 602 add_wildcard(alias); 603 return 1; 604 } 605 606 /* Looks like: ssb:vNidNrevN. */ 607 static int do_ssb_entry(const char *filename, 608 struct ssb_device_id *id, char *alias) 609 { 610 id->vendor = TO_NATIVE(id->vendor); 611 id->coreid = TO_NATIVE(id->coreid); 612 id->revision = TO_NATIVE(id->revision); 613 614 strcpy(alias, "ssb:"); 615 ADD(alias, "v", id->vendor != SSB_ANY_VENDOR, id->vendor); 616 ADD(alias, "id", id->coreid != SSB_ANY_ID, id->coreid); 617 ADD(alias, "rev", id->revision != SSB_ANY_REV, id->revision); 618 add_wildcard(alias); 619 return 1; 620 } 621 622 /* Looks like: virtio:dNvN */ 623 static int do_virtio_entry(const char *filename, struct virtio_device_id *id, 624 char *alias) 625 { 626 id->device = TO_NATIVE(id->device); 627 id->vendor = TO_NATIVE(id->vendor); 628 629 strcpy(alias, "virtio:"); 630 ADD(alias, "d", 1, id->device); 631 ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor); 632 633 add_wildcard(alias); 634 return 1; 635 } 636 637 /* Looks like: i2c:S */ 638 static int do_i2c_entry(const char *filename, struct i2c_device_id *id, 639 char *alias) 640 { 641 sprintf(alias, I2C_MODULE_PREFIX "%s", id->name); 642 643 return 1; 644 } 645 646 static const struct dmifield { 647 const char *prefix; 648 int field; 649 } dmi_fields[] = { 650 { "bvn", DMI_BIOS_VENDOR }, 651 { "bvr", DMI_BIOS_VERSION }, 652 { "bd", DMI_BIOS_DATE }, 653 { "svn", DMI_SYS_VENDOR }, 654 { "pn", DMI_PRODUCT_NAME }, 655 { "pvr", DMI_PRODUCT_VERSION }, 656 { "rvn", DMI_BOARD_VENDOR }, 657 { "rn", DMI_BOARD_NAME }, 658 { "rvr", DMI_BOARD_VERSION }, 659 { "cvn", DMI_CHASSIS_VENDOR }, 660 { "ct", DMI_CHASSIS_TYPE }, 661 { "cvr", DMI_CHASSIS_VERSION }, 662 { NULL, DMI_NONE } 663 }; 664 665 static void dmi_ascii_filter(char *d, const char *s) 666 { 667 /* Filter out characters we don't want to see in the modalias string */ 668 for (; *s; s++) 669 if (*s > ' ' && *s < 127 && *s != ':') 670 *(d++) = *s; 671 672 *d = 0; 673 } 674 675 676 static int do_dmi_entry(const char *filename, struct dmi_system_id *id, 677 char *alias) 678 { 679 int i, j; 680 681 sprintf(alias, "dmi*"); 682 683 for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { 684 for (j = 0; j < 4; j++) { 685 if (id->matches[j].slot && 686 id->matches[j].slot == dmi_fields[i].field) { 687 sprintf(alias + strlen(alias), ":%s*", 688 dmi_fields[i].prefix); 689 dmi_ascii_filter(alias + strlen(alias), 690 id->matches[j].substr); 691 strcat(alias, "*"); 692 } 693 } 694 } 695 696 strcat(alias, ":"); 697 return 1; 698 } 699 /* Ignore any prefix, eg. some architectures prepend _ */ 700 static inline int sym_is(const char *symbol, const char *name) 701 { 702 const char *match; 703 704 match = strstr(symbol, name); 705 if (!match) 706 return 0; 707 return match[strlen(symbol)] == '\0'; 708 } 709 710 static void do_table(void *symval, unsigned long size, 711 unsigned long id_size, 712 const char *device_id, 713 void *function, 714 struct module *mod) 715 { 716 unsigned int i; 717 char alias[500]; 718 int (*do_entry)(const char *, void *entry, char *alias) = function; 719 720 device_id_check(mod->name, device_id, size, id_size, symval); 721 /* Leave last one: it's the terminator. */ 722 size -= id_size; 723 724 for (i = 0; i < size; i += id_size) { 725 if (do_entry(mod->name, symval+i, alias)) { 726 buf_printf(&mod->dev_table_buf, 727 "MODULE_ALIAS(\"%s\");\n", alias); 728 } 729 } 730 } 731 732 /* Create MODULE_ALIAS() statements. 733 * At this time, we cannot write the actual output C source yet, 734 * so we write into the mod->dev_table_buf buffer. */ 735 void handle_moddevtable(struct module *mod, struct elf_info *info, 736 Elf_Sym *sym, const char *symname) 737 { 738 void *symval; 739 char *zeros = NULL; 740 741 /* We're looking for a section relative symbol */ 742 if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum) 743 return; 744 745 /* Handle all-NULL symbols allocated into .bss */ 746 if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) { 747 zeros = calloc(1, sym->st_size); 748 symval = zeros; 749 } else { 750 symval = (void *)info->hdr 751 + info->sechdrs[sym->st_shndx].sh_offset 752 + sym->st_value; 753 } 754 755 if (sym_is(symname, "__mod_pci_device_table")) 756 do_table(symval, sym->st_size, 757 sizeof(struct pci_device_id), "pci", 758 do_pci_entry, mod); 759 else if (sym_is(symname, "__mod_usb_device_table")) 760 /* special case to handle bcdDevice ranges */ 761 do_usb_table(symval, sym->st_size, mod); 762 else if (sym_is(symname, "__mod_hid_device_table")) 763 do_table(symval, sym->st_size, 764 sizeof(struct hid_device_id), "hid", 765 do_hid_entry, mod); 766 else if (sym_is(symname, "__mod_ieee1394_device_table")) 767 do_table(symval, sym->st_size, 768 sizeof(struct ieee1394_device_id), "ieee1394", 769 do_ieee1394_entry, mod); 770 else if (sym_is(symname, "__mod_ccw_device_table")) 771 do_table(symval, sym->st_size, 772 sizeof(struct ccw_device_id), "ccw", 773 do_ccw_entry, mod); 774 else if (sym_is(symname, "__mod_ap_device_table")) 775 do_table(symval, sym->st_size, 776 sizeof(struct ap_device_id), "ap", 777 do_ap_entry, mod); 778 else if (sym_is(symname, "__mod_css_device_table")) 779 do_table(symval, sym->st_size, 780 sizeof(struct css_device_id), "css", 781 do_css_entry, mod); 782 else if (sym_is(symname, "__mod_serio_device_table")) 783 do_table(symval, sym->st_size, 784 sizeof(struct serio_device_id), "serio", 785 do_serio_entry, mod); 786 else if (sym_is(symname, "__mod_acpi_device_table")) 787 do_table(symval, sym->st_size, 788 sizeof(struct acpi_device_id), "acpi", 789 do_acpi_entry, mod); 790 else if (sym_is(symname, "__mod_pnp_device_table")) 791 do_pnp_device_entry(symval, sym->st_size, mod); 792 else if (sym_is(symname, "__mod_pnp_card_device_table")) 793 do_pnp_card_entries(symval, sym->st_size, mod); 794 else if (sym_is(symname, "__mod_pcmcia_device_table")) 795 do_table(symval, sym->st_size, 796 sizeof(struct pcmcia_device_id), "pcmcia", 797 do_pcmcia_entry, mod); 798 else if (sym_is(symname, "__mod_of_device_table")) 799 do_table(symval, sym->st_size, 800 sizeof(struct of_device_id), "of", 801 do_of_entry, mod); 802 else if (sym_is(symname, "__mod_vio_device_table")) 803 do_table(symval, sym->st_size, 804 sizeof(struct vio_device_id), "vio", 805 do_vio_entry, mod); 806 else if (sym_is(symname, "__mod_input_device_table")) 807 do_table(symval, sym->st_size, 808 sizeof(struct input_device_id), "input", 809 do_input_entry, mod); 810 else if (sym_is(symname, "__mod_eisa_device_table")) 811 do_table(symval, sym->st_size, 812 sizeof(struct eisa_device_id), "eisa", 813 do_eisa_entry, mod); 814 else if (sym_is(symname, "__mod_parisc_device_table")) 815 do_table(symval, sym->st_size, 816 sizeof(struct parisc_device_id), "parisc", 817 do_parisc_entry, mod); 818 else if (sym_is(symname, "__mod_sdio_device_table")) 819 do_table(symval, sym->st_size, 820 sizeof(struct sdio_device_id), "sdio", 821 do_sdio_entry, mod); 822 else if (sym_is(symname, "__mod_ssb_device_table")) 823 do_table(symval, sym->st_size, 824 sizeof(struct ssb_device_id), "ssb", 825 do_ssb_entry, mod); 826 else if (sym_is(symname, "__mod_virtio_device_table")) 827 do_table(symval, sym->st_size, 828 sizeof(struct virtio_device_id), "virtio", 829 do_virtio_entry, mod); 830 else if (sym_is(symname, "__mod_i2c_device_table")) 831 do_table(symval, sym->st_size, 832 sizeof(struct i2c_device_id), "i2c", 833 do_i2c_entry, mod); 834 else if (sym_is(symname, "__mod_dmi_device_table")) 835 do_table(symval, sym->st_size, 836 sizeof(struct dmi_system_id), "dmi", 837 do_dmi_entry, mod); 838 free(zeros); 839 } 840 841 /* Now add out buffered information to the generated C source */ 842 void add_moddevtable(struct buffer *buf, struct module *mod) 843 { 844 buf_printf(buf, "\n"); 845 buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); 846 free(mod->dev_table_buf.p); 847 } 848