11da177e4SLinus Torvalds /* Simple code to turn various tables in an ELF file into alias definitions. 21da177e4SLinus Torvalds * This deals with kernel datastructures where they should be 31da177e4SLinus Torvalds * dealt with: in the kernel source. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright 2002-2003 Rusty Russell, IBM Corporation 61da177e4SLinus Torvalds * 2003 Kai Germaschewski 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This software may be used and distributed according to the terms 101da177e4SLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include "modpost.h" 146543becfSAndreas Schwab #include "devicetable-offsets.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and 171da177e4SLinus Torvalds * use either stdint.h or inttypes.h for the rest. */ 181da177e4SLinus Torvalds #if KERNEL_ELFCLASS == ELFCLASS32 191da177e4SLinus Torvalds typedef Elf32_Addr kernel_ulong_t; 201d8f430cSRusty Russell #define BITS_PER_LONG 32 211da177e4SLinus Torvalds #else 221da177e4SLinus Torvalds typedef Elf64_Addr kernel_ulong_t; 231d8f430cSRusty Russell #define BITS_PER_LONG 64 241da177e4SLinus Torvalds #endif 251da177e4SLinus Torvalds #ifdef __sun__ 261da177e4SLinus Torvalds #include <inttypes.h> 271da177e4SLinus Torvalds #else 281da177e4SLinus Torvalds #include <stdint.h> 291da177e4SLinus Torvalds #endif 301da177e4SLinus Torvalds 315e655772SJeff Mahoney #include <ctype.h> 32626596e2SRusty Russell #include <stdbool.h> 335e655772SJeff Mahoney 341da177e4SLinus Torvalds typedef uint32_t __u32; 351da177e4SLinus Torvalds typedef uint16_t __u16; 361da177e4SLinus Torvalds typedef unsigned char __u8; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* Big exception to the "don't include kernel headers into userspace, which 391da177e4SLinus Torvalds * even potentially has different endianness and word sizes, since 401da177e4SLinus Torvalds * we handle those differences explicitly below */ 411da177e4SLinus Torvalds #include "../../include/linux/mod_devicetable.h" 421da177e4SLinus Torvalds 43e49ce141SRusty Russell /* This array collects all instances that use the generic do_table */ 44e49ce141SRusty Russell struct devtable { 45e49ce141SRusty Russell const char *device_id; /* name of table, __mod_<name>_device_table. */ 46e49ce141SRusty Russell unsigned long id_size; 47e49ce141SRusty Russell void *function; 48e49ce141SRusty Russell }; 49e49ce141SRusty Russell 50dd2a3acaSAndreas Bießmann #define ___cat(a,b) a ## b 51dd2a3acaSAndreas Bießmann #define __cat(a,b) ___cat(a,b) 52dd2a3acaSAndreas Bießmann 53dd2a3acaSAndreas Bießmann /* we need some special handling for this host tool running eventually on 54dd2a3acaSAndreas Bießmann * Darwin. The Mach-O section handling is a bit different than ELF section 55dd2a3acaSAndreas Bießmann * handling. The differnces in detail are: 56dd2a3acaSAndreas Bießmann * a) we have segments which have sections 57dd2a3acaSAndreas Bießmann * b) we need a API call to get the respective section symbols */ 58dd2a3acaSAndreas Bießmann #if defined(__MACH__) 59dd2a3acaSAndreas Bießmann #include <mach-o/getsect.h> 60dd2a3acaSAndreas Bießmann 61dd2a3acaSAndreas Bießmann #define INIT_SECTION(name) do { \ 62dd2a3acaSAndreas Bießmann unsigned long name ## _len; \ 63dd2a3acaSAndreas Bießmann char *__cat(pstart_,name) = getsectdata("__TEXT", \ 64dd2a3acaSAndreas Bießmann #name, &__cat(name,_len)); \ 65dd2a3acaSAndreas Bießmann char *__cat(pstop_,name) = __cat(pstart_,name) + \ 66dd2a3acaSAndreas Bießmann __cat(name, _len); \ 67dd2a3acaSAndreas Bießmann __cat(__start_,name) = (void *)__cat(pstart_,name); \ 68dd2a3acaSAndreas Bießmann __cat(__stop_,name) = (void *)__cat(pstop_,name); \ 69dd2a3acaSAndreas Bießmann } while (0) 70dd2a3acaSAndreas Bießmann #define SECTION(name) __attribute__((section("__TEXT, " #name))) 71dd2a3acaSAndreas Bießmann 72dd2a3acaSAndreas Bießmann struct devtable **__start___devtable, **__stop___devtable; 73dd2a3acaSAndreas Bießmann #else 74dd2a3acaSAndreas Bießmann #define INIT_SECTION(name) /* no-op for ELF */ 75dd2a3acaSAndreas Bießmann #define SECTION(name) __attribute__((section(#name))) 76dd2a3acaSAndreas Bießmann 77e49ce141SRusty Russell /* We construct a table of pointers in an ELF section (pointers generally 78e49ce141SRusty Russell * go unpadded by gcc). ld creates boundary syms for us. */ 79e49ce141SRusty Russell extern struct devtable *__start___devtable[], *__stop___devtable[]; 80dd2a3acaSAndreas Bießmann #endif /* __MACH__ */ 81e49ce141SRusty Russell 82e49ce141SRusty Russell #if __GNUC__ == 3 && __GNUC_MINOR__ < 3 83e49ce141SRusty Russell # define __used __attribute__((__unused__)) 84e49ce141SRusty Russell #else 85e49ce141SRusty Russell # define __used __attribute__((__used__)) 86e49ce141SRusty Russell #endif 87e49ce141SRusty Russell 886543becfSAndreas Schwab /* Define a variable f that holds the value of field f of struct devid 896543becfSAndreas Schwab * based at address m. 906543becfSAndreas Schwab */ 916543becfSAndreas Schwab #define DEF_FIELD(m, devid, f) \ 926543becfSAndreas Schwab typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) 936543becfSAndreas Schwab /* Define a variable f that holds the address of field f of struct devid 946543becfSAndreas Schwab * based at address m. Due to the way typeof works, for a field of type 956543becfSAndreas Schwab * T[N] the variable has type T(*)[N], _not_ T*. 966543becfSAndreas Schwab */ 976543becfSAndreas Schwab #define DEF_FIELD_ADDR(m, devid, f) \ 986543becfSAndreas Schwab typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) 996543becfSAndreas Schwab 100e49ce141SRusty Russell /* Add a table entry. We test function type matches while we're here. */ 101e49ce141SRusty Russell #define ADD_TO_DEVTABLE(device_id, type, function) \ 102e49ce141SRusty Russell static struct devtable __cat(devtable,__LINE__) = { \ 103e49ce141SRusty Russell device_id + 0*sizeof((function)((const char *)NULL, \ 1046543becfSAndreas Schwab (void *)NULL, \ 105e49ce141SRusty Russell (char *)NULL)), \ 1066543becfSAndreas Schwab SIZE_##type, (function) }; \ 107dd2a3acaSAndreas Bießmann static struct devtable *SECTION(__devtable) __used \ 108dd2a3acaSAndreas Bießmann __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) 109e49ce141SRusty Russell 1101da177e4SLinus Torvalds #define ADD(str, sep, cond, field) \ 1111da177e4SLinus Torvalds do { \ 1121da177e4SLinus Torvalds strcat(str, sep); \ 1131da177e4SLinus Torvalds if (cond) \ 1141da177e4SLinus Torvalds sprintf(str + strlen(str), \ 1151da177e4SLinus Torvalds sizeof(field) == 1 ? "%02X" : \ 1161da177e4SLinus Torvalds sizeof(field) == 2 ? "%04X" : \ 1171da177e4SLinus Torvalds sizeof(field) == 4 ? "%08X" : "", \ 1181da177e4SLinus Torvalds field); \ 1191da177e4SLinus Torvalds else \ 1201da177e4SLinus Torvalds sprintf(str + strlen(str), "*"); \ 1211da177e4SLinus Torvalds } while(0) 1221da177e4SLinus Torvalds 123ac551828SJean Delvare /* Always end in a wildcard, for future extension */ 124ac551828SJean Delvare static inline void add_wildcard(char *str) 125ac551828SJean Delvare { 126ac551828SJean Delvare int len = strlen(str); 127ac551828SJean Delvare 128ac551828SJean Delvare if (str[len - 1] != '*') 129ac551828SJean Delvare strcat(str + len, "*"); 130ac551828SJean Delvare } 131ac551828SJean Delvare 132fb33d816SSam Ravnborg /** 133fb33d816SSam Ravnborg * Check that sizeof(device_id type) are consistent with size of section 134fb33d816SSam Ravnborg * in .o file. If in-consistent then userspace and kernel does not agree 135fb33d816SSam Ravnborg * on actual size which is a bug. 136e0049825SKees Cook * Also verify that the final entry in the table is all zeros. 1374ce6efedSSam Ravnborg * Ignore both checks if build host differ from target host and size differs. 138fb33d816SSam Ravnborg **/ 139e0049825SKees Cook static void device_id_check(const char *modname, const char *device_id, 140e0049825SKees Cook unsigned long size, unsigned long id_size, 141e0049825SKees Cook void *symval) 142fb33d816SSam Ravnborg { 143e0049825SKees Cook int i; 144e0049825SKees Cook 145fb33d816SSam Ravnborg if (size % id_size || size < id_size) { 146fb33d816SSam Ravnborg fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " 147fb33d816SSam Ravnborg "of the size of section __mod_%s_device_table=%lu.\n" 148fb33d816SSam Ravnborg "Fix definition of struct %s_device_id " 149fb33d816SSam Ravnborg "in mod_devicetable.h\n", 150fb33d816SSam Ravnborg modname, device_id, id_size, device_id, size, device_id); 151fb33d816SSam Ravnborg } 152e0049825SKees Cook /* Verify last one is a terminator */ 153e0049825SKees Cook for (i = 0; i < id_size; i++ ) { 154e0049825SKees Cook if (*(uint8_t*)(symval+size-id_size+i)) { 155e0049825SKees Cook fprintf(stderr,"%s: struct %s_device_id is %lu bytes. " 156e0049825SKees Cook "The last of %lu is:\n", 157e0049825SKees Cook modname, device_id, id_size, size / id_size); 158e0049825SKees Cook for (i = 0; i < id_size; i++ ) 159e0049825SKees Cook fprintf(stderr,"0x%02x ", 160e0049825SKees Cook *(uint8_t*)(symval+size-id_size+i) ); 161e0049825SKees Cook fprintf(stderr,"\n"); 162e0049825SKees Cook fatal("%s: struct %s_device_id is not terminated " 163e0049825SKees Cook "with a NULL entry!\n", modname, device_id); 164e0049825SKees Cook } 165e0049825SKees Cook } 166fb33d816SSam Ravnborg } 167fb33d816SSam Ravnborg 168b19dcd93SRoman Kagan /* USB is special because the bcdDevice can be matched against a numeric range */ 16981df2d59SBjørn Mork /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ 1706543becfSAndreas Schwab static void do_usb_entry(void *symval, 171b19dcd93SRoman Kagan unsigned int bcdDevice_initial, int bcdDevice_initial_digits, 172b19dcd93SRoman Kagan unsigned char range_lo, unsigned char range_hi, 173afe2dab4SNathaniel McCallum unsigned char max, struct module *mod) 1741da177e4SLinus Torvalds { 175b19dcd93SRoman Kagan char alias[500]; 1766543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, match_flags); 1776543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idVendor); 1786543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idProduct); 1796543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_lo); 1806543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceClass); 1816543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceSubClass); 1826543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceProtocol); 1836543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceClass); 1846543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); 1856543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); 1866543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceNumber); 1876543becfSAndreas Schwab 1881da177e4SLinus Torvalds strcpy(alias, "usb:"); 1896543becfSAndreas Schwab ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, 1906543becfSAndreas Schwab idVendor); 1916543becfSAndreas Schwab ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, 1926543becfSAndreas Schwab idProduct); 193b19dcd93SRoman Kagan 194b19dcd93SRoman Kagan strcat(alias, "d"); 195b19dcd93SRoman Kagan if (bcdDevice_initial_digits) 196b19dcd93SRoman Kagan sprintf(alias + strlen(alias), "%0*X", 197b19dcd93SRoman Kagan bcdDevice_initial_digits, bcdDevice_initial); 198b19dcd93SRoman Kagan if (range_lo == range_hi) 199afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), "%X", range_lo); 200afe2dab4SNathaniel McCallum else if (range_lo > 0 || range_hi < max) { 201afe2dab4SNathaniel McCallum if (range_lo > 0x9 || range_hi < 0xA) 202afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 203afe2dab4SNathaniel McCallum "[%X-%X]", 204afe2dab4SNathaniel McCallum range_lo, 205afe2dab4SNathaniel McCallum range_hi); 206afe2dab4SNathaniel McCallum else { 207afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 208afe2dab4SNathaniel McCallum range_lo < 0x9 ? "[%X-9" : "[%X", 209afe2dab4SNathaniel McCallum range_lo); 210afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 211afe2dab4SNathaniel McCallum range_hi > 0xA ? "a-%X]" : "%X]", 212afe2dab4SNathaniel McCallum range_lo); 213afe2dab4SNathaniel McCallum } 214afe2dab4SNathaniel McCallum } 2156543becfSAndreas Schwab if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) 216b19dcd93SRoman Kagan strcat(alias, "*"); 217b19dcd93SRoman Kagan 2186543becfSAndreas Schwab ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, 2196543becfSAndreas Schwab bDeviceClass); 2206543becfSAndreas Schwab ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, 2216543becfSAndreas Schwab bDeviceSubClass); 2226543becfSAndreas Schwab ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, 2236543becfSAndreas Schwab bDeviceProtocol); 2246543becfSAndreas Schwab ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, 2256543becfSAndreas Schwab bInterfaceClass); 2266543becfSAndreas Schwab ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, 2276543becfSAndreas Schwab bInterfaceSubClass); 2286543becfSAndreas Schwab ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, 2296543becfSAndreas Schwab bInterfaceProtocol); 2306543becfSAndreas Schwab ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, 2316543becfSAndreas Schwab bInterfaceNumber); 232b19dcd93SRoman Kagan 233ac551828SJean Delvare add_wildcard(alias); 234b19dcd93SRoman Kagan buf_printf(&mod->dev_table_buf, 235b19dcd93SRoman Kagan "MODULE_ALIAS(\"%s\");\n", alias); 236b19dcd93SRoman Kagan } 237b19dcd93SRoman Kagan 23855f49f26SNathaniel McCallum /* Handles increment/decrement of BCD formatted integers */ 23955f49f26SNathaniel McCallum /* Returns the previous value, so it works like i++ or i-- */ 24055f49f26SNathaniel McCallum static unsigned int incbcd(unsigned int *bcd, 24155f49f26SNathaniel McCallum int inc, 24255f49f26SNathaniel McCallum unsigned char max, 24355f49f26SNathaniel McCallum size_t chars) 24455f49f26SNathaniel McCallum { 24555f49f26SNathaniel McCallum unsigned int init = *bcd, i, j; 24655f49f26SNathaniel McCallum unsigned long long c, dec = 0; 24755f49f26SNathaniel McCallum 24855f49f26SNathaniel McCallum /* If bcd is not in BCD format, just increment */ 24955f49f26SNathaniel McCallum if (max > 0x9) { 25055f49f26SNathaniel McCallum *bcd += inc; 25155f49f26SNathaniel McCallum return init; 25255f49f26SNathaniel McCallum } 25355f49f26SNathaniel McCallum 25455f49f26SNathaniel McCallum /* Convert BCD to Decimal */ 25555f49f26SNathaniel McCallum for (i=0 ; i < chars ; i++) { 25655f49f26SNathaniel McCallum c = (*bcd >> (i << 2)) & 0xf; 25755f49f26SNathaniel McCallum c = c > 9 ? 9 : c; /* force to bcd just in case */ 25855f49f26SNathaniel McCallum for (j=0 ; j < i ; j++) 25955f49f26SNathaniel McCallum c = c * 10; 26055f49f26SNathaniel McCallum dec += c; 26155f49f26SNathaniel McCallum } 26255f49f26SNathaniel McCallum 26355f49f26SNathaniel McCallum /* Do our increment/decrement */ 26455f49f26SNathaniel McCallum dec += inc; 26555f49f26SNathaniel McCallum *bcd = 0; 26655f49f26SNathaniel McCallum 26755f49f26SNathaniel McCallum /* Convert back to BCD */ 26855f49f26SNathaniel McCallum for (i=0 ; i < chars ; i++) { 26955f49f26SNathaniel McCallum for (c=1,j=0 ; j < i ; j++) 27055f49f26SNathaniel McCallum c = c * 10; 27155f49f26SNathaniel McCallum c = (dec / c) % 10; 27255f49f26SNathaniel McCallum *bcd += c << (i << 2); 27355f49f26SNathaniel McCallum } 27455f49f26SNathaniel McCallum return init; 27555f49f26SNathaniel McCallum } 27655f49f26SNathaniel McCallum 2776543becfSAndreas Schwab static void do_usb_entry_multi(void *symval, struct module *mod) 278b19dcd93SRoman Kagan { 279b19dcd93SRoman Kagan unsigned int devlo, devhi; 280afe2dab4SNathaniel McCallum unsigned char chi, clo, max; 281b19dcd93SRoman Kagan int ndigits; 282b19dcd93SRoman Kagan 2836543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, match_flags); 2846543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idVendor); 2856543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idProduct); 2866543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_lo); 2876543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_hi); 2886543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceClass); 2896543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceClass); 290b19dcd93SRoman Kagan 2916543becfSAndreas Schwab devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? 2926543becfSAndreas Schwab bcdDevice_lo : 0x0U; 2936543becfSAndreas Schwab devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? 2946543becfSAndreas Schwab bcdDevice_hi : ~0x0U; 295b19dcd93SRoman Kagan 296afe2dab4SNathaniel McCallum /* Figure out if this entry is in bcd or hex format */ 297afe2dab4SNathaniel McCallum max = 0x9; /* Default to decimal format */ 2986543becfSAndreas Schwab for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) { 299afe2dab4SNathaniel McCallum clo = (devlo >> (ndigits << 2)) & 0xf; 300afe2dab4SNathaniel McCallum chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf; 301afe2dab4SNathaniel McCallum if (clo > max || chi > max) { 302afe2dab4SNathaniel McCallum max = 0xf; 303afe2dab4SNathaniel McCallum break; 304afe2dab4SNathaniel McCallum } 305afe2dab4SNathaniel McCallum } 306afe2dab4SNathaniel McCallum 307b19dcd93SRoman Kagan /* 308b19dcd93SRoman Kagan * Some modules (visor) have empty slots as placeholder for 309b19dcd93SRoman Kagan * run-time specification that results in catch-all alias 310b19dcd93SRoman Kagan */ 3116543becfSAndreas Schwab if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass)) 312b19dcd93SRoman Kagan return; 313b19dcd93SRoman Kagan 314b19dcd93SRoman Kagan /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ 3156543becfSAndreas Schwab for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { 316b19dcd93SRoman Kagan clo = devlo & 0xf; 317b19dcd93SRoman Kagan chi = devhi & 0xf; 318afe2dab4SNathaniel McCallum if (chi > max) /* If we are in bcd mode, truncate if necessary */ 319afe2dab4SNathaniel McCallum chi = max; 320b19dcd93SRoman Kagan devlo >>= 4; 321b19dcd93SRoman Kagan devhi >>= 4; 322b19dcd93SRoman Kagan 323b19dcd93SRoman Kagan if (devlo == devhi || !ndigits) { 3246543becfSAndreas Schwab do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod); 325b19dcd93SRoman Kagan break; 326b19dcd93SRoman Kagan } 327b19dcd93SRoman Kagan 328afe2dab4SNathaniel McCallum if (clo > 0x0) 3296543becfSAndreas Schwab do_usb_entry(symval, 33055f49f26SNathaniel McCallum incbcd(&devlo, 1, max, 3316543becfSAndreas Schwab sizeof(bcdDevice_lo) * 2), 33255f49f26SNathaniel McCallum ndigits, clo, max, max, mod); 333b19dcd93SRoman Kagan 334afe2dab4SNathaniel McCallum if (chi < max) 3356543becfSAndreas Schwab do_usb_entry(symval, 33655f49f26SNathaniel McCallum incbcd(&devhi, -1, max, 3376543becfSAndreas Schwab sizeof(bcdDevice_lo) * 2), 33855f49f26SNathaniel McCallum ndigits, 0x0, chi, max, mod); 339b19dcd93SRoman Kagan } 340b19dcd93SRoman Kagan } 341b19dcd93SRoman Kagan 342b19dcd93SRoman Kagan static void do_usb_table(void *symval, unsigned long size, 343b19dcd93SRoman Kagan struct module *mod) 344b19dcd93SRoman Kagan { 345b19dcd93SRoman Kagan unsigned int i; 3466543becfSAndreas Schwab const unsigned long id_size = SIZE_usb_device_id; 347b19dcd93SRoman Kagan 348e0049825SKees Cook device_id_check(mod->name, "usb", size, id_size, symval); 349fb33d816SSam Ravnborg 350b19dcd93SRoman Kagan /* Leave last one: it's the terminator. */ 351b19dcd93SRoman Kagan size -= id_size; 352b19dcd93SRoman Kagan 353b19dcd93SRoman Kagan for (i = 0; i < size; i += id_size) 354b19dcd93SRoman Kagan do_usb_entry_multi(symval + i, mod); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 357e8c84f9aSJiri Slaby /* Looks like: hid:bNvNpN */ 358e8c84f9aSJiri Slaby static int do_hid_entry(const char *filename, 3596543becfSAndreas Schwab void *symval, char *alias) 360e8c84f9aSJiri Slaby { 3616543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, bus); 3626543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, group); 3636543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, vendor); 3646543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, product); 365e8c84f9aSJiri Slaby 3667431fb76SHenrik Rydberg sprintf(alias, "hid:"); 3676543becfSAndreas Schwab ADD(alias, "b", bus != HID_BUS_ANY, bus); 3686543becfSAndreas Schwab ADD(alias, "g", group != HID_GROUP_ANY, group); 3696543becfSAndreas Schwab ADD(alias, "v", vendor != HID_ANY_ID, vendor); 3706543becfSAndreas Schwab ADD(alias, "p", product != HID_ANY_ID, product); 371e8c84f9aSJiri Slaby 372e8c84f9aSJiri Slaby return 1; 373e8c84f9aSJiri Slaby } 3746543becfSAndreas Schwab ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); 375e8c84f9aSJiri Slaby 3761da177e4SLinus Torvalds /* Looks like: ieee1394:venNmoNspNverN */ 3771da177e4SLinus Torvalds static int do_ieee1394_entry(const char *filename, 3786543becfSAndreas Schwab void *symval, char *alias) 3791da177e4SLinus Torvalds { 3806543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, match_flags); 3816543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, vendor_id); 3826543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, model_id); 3836543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, specifier_id); 3846543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, version); 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds strcpy(alias, "ieee1394:"); 3876543becfSAndreas Schwab ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, 3886543becfSAndreas Schwab vendor_id); 3896543becfSAndreas Schwab ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, 3906543becfSAndreas Schwab model_id); 3916543becfSAndreas Schwab ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, 3926543becfSAndreas Schwab specifier_id); 3936543becfSAndreas Schwab ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, 3946543becfSAndreas Schwab version); 3951da177e4SLinus Torvalds 396ac551828SJean Delvare add_wildcard(alias); 3971da177e4SLinus Torvalds return 1; 3981da177e4SLinus Torvalds } 3996543becfSAndreas Schwab ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ 4021da177e4SLinus Torvalds static int do_pci_entry(const char *filename, 4036543becfSAndreas Schwab void *symval, char *alias) 4041da177e4SLinus Torvalds { 4051da177e4SLinus Torvalds /* Class field can be divided into these three. */ 4061da177e4SLinus Torvalds unsigned char baseclass, subclass, interface, 4071da177e4SLinus Torvalds baseclass_mask, subclass_mask, interface_mask; 4081da177e4SLinus Torvalds 4096543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, vendor); 4106543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, device); 4116543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, subvendor); 4126543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, subdevice); 4136543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, class); 4146543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, class_mask); 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds strcpy(alias, "pci:"); 4176543becfSAndreas Schwab ADD(alias, "v", vendor != PCI_ANY_ID, vendor); 4186543becfSAndreas Schwab ADD(alias, "d", device != PCI_ANY_ID, device); 4196543becfSAndreas Schwab ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); 4206543becfSAndreas Schwab ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); 4211da177e4SLinus Torvalds 4226543becfSAndreas Schwab baseclass = (class) >> 16; 4236543becfSAndreas Schwab baseclass_mask = (class_mask) >> 16; 4246543becfSAndreas Schwab subclass = (class) >> 8; 4256543becfSAndreas Schwab subclass_mask = (class_mask) >> 8; 4266543becfSAndreas Schwab interface = class; 4276543becfSAndreas Schwab interface_mask = class_mask; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds if ((baseclass_mask != 0 && baseclass_mask != 0xFF) 4301da177e4SLinus Torvalds || (subclass_mask != 0 && subclass_mask != 0xFF) 4311da177e4SLinus Torvalds || (interface_mask != 0 && interface_mask != 0xFF)) { 432cb80514dSSam Ravnborg warn("Can't handle masks in %s:%04X\n", 4336543becfSAndreas Schwab filename, class_mask); 4341da177e4SLinus Torvalds return 0; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); 4381da177e4SLinus Torvalds ADD(alias, "sc", subclass_mask == 0xFF, subclass); 4391da177e4SLinus Torvalds ADD(alias, "i", interface_mask == 0xFF, interface); 440ac551828SJean Delvare add_wildcard(alias); 4411da177e4SLinus Torvalds return 1; 4421da177e4SLinus Torvalds } 4436543becfSAndreas Schwab ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* looks like: "ccw:tNmNdtNdmN" */ 4461da177e4SLinus Torvalds static int do_ccw_entry(const char *filename, 4476543becfSAndreas Schwab void *symval, char *alias) 4481da177e4SLinus Torvalds { 4496543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, match_flags); 4506543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, cu_type); 4516543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, cu_model); 4526543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, dev_type); 4536543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, dev_model); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds strcpy(alias, "ccw:"); 4566543becfSAndreas Schwab ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, 4576543becfSAndreas Schwab cu_type); 4586543becfSAndreas Schwab ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, 4596543becfSAndreas Schwab cu_model); 4606543becfSAndreas Schwab ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, 4616543becfSAndreas Schwab dev_type); 4626543becfSAndreas Schwab ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, 4636543becfSAndreas Schwab dev_model); 464ac551828SJean Delvare add_wildcard(alias); 4651da177e4SLinus Torvalds return 1; 4661da177e4SLinus Torvalds } 4676543becfSAndreas Schwab ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); 4681da177e4SLinus Torvalds 4691534c382SMartin Schwidefsky /* looks like: "ap:tN" */ 4701534c382SMartin Schwidefsky static int do_ap_entry(const char *filename, 4716543becfSAndreas Schwab void *symval, char *alias) 4721534c382SMartin Schwidefsky { 4736543becfSAndreas Schwab DEF_FIELD(symval, ap_device_id, dev_type); 4746543becfSAndreas Schwab 4756543becfSAndreas Schwab sprintf(alias, "ap:t%02X*", dev_type); 4761534c382SMartin Schwidefsky return 1; 4771534c382SMartin Schwidefsky } 4786543becfSAndreas Schwab ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); 4791534c382SMartin Schwidefsky 4807e9db9eaSCornelia Huck /* looks like: "css:tN" */ 4817e9db9eaSCornelia Huck static int do_css_entry(const char *filename, 4826543becfSAndreas Schwab void *symval, char *alias) 4837e9db9eaSCornelia Huck { 4846543becfSAndreas Schwab DEF_FIELD(symval, css_device_id, type); 4856543becfSAndreas Schwab 4866543becfSAndreas Schwab sprintf(alias, "css:t%01X", type); 4877e9db9eaSCornelia Huck return 1; 4887e9db9eaSCornelia Huck } 4896543becfSAndreas Schwab ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); 4907e9db9eaSCornelia Huck 4911da177e4SLinus Torvalds /* Looks like: "serio:tyNprNidNexN" */ 4921da177e4SLinus Torvalds static int do_serio_entry(const char *filename, 4936543becfSAndreas Schwab void *symval, char *alias) 4941da177e4SLinus Torvalds { 4956543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, type); 4966543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, proto); 4976543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, id); 4986543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, extra); 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds strcpy(alias, "serio:"); 5016543becfSAndreas Schwab ADD(alias, "ty", type != SERIO_ANY, type); 5026543becfSAndreas Schwab ADD(alias, "pr", proto != SERIO_ANY, proto); 5036543becfSAndreas Schwab ADD(alias, "id", id != SERIO_ANY, id); 5046543becfSAndreas Schwab ADD(alias, "ex", extra != SERIO_ANY, extra); 5051da177e4SLinus Torvalds 506ac551828SJean Delvare add_wildcard(alias); 5071da177e4SLinus Torvalds return 1; 5081da177e4SLinus Torvalds } 5096543becfSAndreas Schwab ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); 5101da177e4SLinus Torvalds 51129b71a1cSThomas Renninger /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ 51229b71a1cSThomas Renninger static int do_acpi_entry(const char *filename, 5136543becfSAndreas Schwab void *symval, char *alias) 51429b71a1cSThomas Renninger { 5156543becfSAndreas Schwab DEF_FIELD_ADDR(symval, acpi_device_id, id); 5166543becfSAndreas Schwab sprintf(alias, "acpi*:%s:*", *id); 51729b71a1cSThomas Renninger return 1; 51829b71a1cSThomas Renninger } 5196543becfSAndreas Schwab ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); 52029b71a1cSThomas Renninger 5211da177e4SLinus Torvalds /* looks like: "pnp:dD" */ 52222454cb9SKay Sievers static void do_pnp_device_entry(void *symval, unsigned long size, 52322454cb9SKay Sievers struct module *mod) 5241da177e4SLinus Torvalds { 5256543becfSAndreas Schwab const unsigned long id_size = SIZE_pnp_device_id; 5265e4c6564SKay Sievers const unsigned int count = (size / id_size)-1; 5275e4c6564SKay Sievers unsigned int i; 52822454cb9SKay Sievers 52922454cb9SKay Sievers device_id_check(mod->name, "pnp", size, id_size, symval); 53022454cb9SKay Sievers 5315e4c6564SKay Sievers for (i = 0; i < count; i++) { 5326543becfSAndreas Schwab DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); 5336543becfSAndreas Schwab char acpi_id[sizeof(*id)]; 53472638f59SKay Sievers int j; 5355e4c6564SKay Sievers 53622454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 5376543becfSAndreas Schwab "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); 53872638f59SKay Sievers 53972638f59SKay Sievers /* fix broken pnp bus lowercasing */ 54072638f59SKay Sievers for (j = 0; j < sizeof(acpi_id); j++) 5416543becfSAndreas Schwab acpi_id[j] = toupper((*id)[j]); 54222454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 54372638f59SKay Sievers "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); 5445e4c6564SKay Sievers } 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 5470c81eed4SKay Sievers /* looks like: "pnp:dD" for every device of the card */ 5480c81eed4SKay Sievers static void do_pnp_card_entries(void *symval, unsigned long size, 5490c81eed4SKay Sievers struct module *mod) 5501da177e4SLinus Torvalds { 5516543becfSAndreas Schwab const unsigned long id_size = SIZE_pnp_card_device_id; 5520c81eed4SKay Sievers const unsigned int count = (size / id_size)-1; 5530c81eed4SKay Sievers unsigned int i; 5541da177e4SLinus Torvalds 5550c81eed4SKay Sievers device_id_check(mod->name, "pnp", size, id_size, symval); 5560c81eed4SKay Sievers 5570c81eed4SKay Sievers for (i = 0; i < count; i++) { 5580c81eed4SKay Sievers unsigned int j; 5596543becfSAndreas Schwab DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs); 5600c81eed4SKay Sievers 5610c81eed4SKay Sievers for (j = 0; j < PNP_MAX_DEVICES; j++) { 5626543becfSAndreas Schwab const char *id = (char *)(*devs)[j].id; 5630c81eed4SKay Sievers int i2, j2; 5640c81eed4SKay Sievers int dup = 0; 5650c81eed4SKay Sievers 5660c81eed4SKay Sievers if (!id[0]) 5671da177e4SLinus Torvalds break; 5680c81eed4SKay Sievers 5690c81eed4SKay Sievers /* find duplicate, already added value */ 5700c81eed4SKay Sievers for (i2 = 0; i2 < i && !dup; i2++) { 5716543becfSAndreas Schwab DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs); 5720c81eed4SKay Sievers 5730c81eed4SKay Sievers for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { 5746543becfSAndreas Schwab const char *id2 = (char *)(*devs)[j2].id; 5750c81eed4SKay Sievers 5760c81eed4SKay Sievers if (!id2[0]) 5770c81eed4SKay Sievers break; 5780c81eed4SKay Sievers 5790c81eed4SKay Sievers if (!strcmp(id, id2)) { 5800c81eed4SKay Sievers dup = 1; 5810c81eed4SKay Sievers break; 5821da177e4SLinus Torvalds } 5830c81eed4SKay Sievers } 5840c81eed4SKay Sievers } 5850c81eed4SKay Sievers 5860c81eed4SKay Sievers /* add an individual alias for every device entry */ 58722454cb9SKay Sievers if (!dup) { 5886543becfSAndreas Schwab char acpi_id[PNP_ID_LEN]; 58972638f59SKay Sievers int k; 59072638f59SKay Sievers 5910c81eed4SKay Sievers buf_printf(&mod->dev_table_buf, 5920c81eed4SKay Sievers "MODULE_ALIAS(\"pnp:d%s*\");\n", id); 59372638f59SKay Sievers 59472638f59SKay Sievers /* fix broken pnp bus lowercasing */ 59572638f59SKay Sievers for (k = 0; k < sizeof(acpi_id); k++) 59672638f59SKay Sievers acpi_id[k] = toupper(id[k]); 59722454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 59872638f59SKay Sievers "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); 59922454cb9SKay Sievers } 6000c81eed4SKay Sievers } 6010c81eed4SKay Sievers } 6021da177e4SLinus Torvalds } 6031da177e4SLinus Torvalds 60490829cfeSDominik Brodowski /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ 60590829cfeSDominik Brodowski static int do_pcmcia_entry(const char *filename, 6066543becfSAndreas Schwab void *symval, char *alias) 60790829cfeSDominik Brodowski { 60890829cfeSDominik Brodowski unsigned int i; 6096543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, match_flags); 6106543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, manf_id); 6116543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, card_id); 6126543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, func_id); 6136543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, function); 6146543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, device_no); 6156543becfSAndreas Schwab DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash); 6164fb7edceSKars de Jong 61790829cfeSDominik Brodowski for (i=0; i<4; i++) { 6186543becfSAndreas Schwab (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); 61990829cfeSDominik Brodowski } 62090829cfeSDominik Brodowski 62190829cfeSDominik Brodowski strcpy(alias, "pcmcia:"); 6226543becfSAndreas Schwab ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, 6236543becfSAndreas Schwab manf_id); 6246543becfSAndreas Schwab ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, 6256543becfSAndreas Schwab card_id); 6266543becfSAndreas Schwab ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, 6276543becfSAndreas Schwab func_id); 6286543becfSAndreas Schwab ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, 6296543becfSAndreas Schwab function); 6306543becfSAndreas Schwab ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, 6316543becfSAndreas Schwab device_no); 6326543becfSAndreas Schwab ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]); 6336543becfSAndreas Schwab ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]); 6346543becfSAndreas Schwab ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); 6356543becfSAndreas Schwab ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]); 63690829cfeSDominik Brodowski 637ac551828SJean Delvare add_wildcard(alias); 63890829cfeSDominik Brodowski return 1; 63990829cfeSDominik Brodowski } 6406543becfSAndreas Schwab ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); 64190829cfeSDominik Brodowski 6426543becfSAndreas Schwab static int do_of_entry (const char *filename, void *symval, char *alias) 6435e655772SJeff Mahoney { 644d1ab4235SSylvain Munaut int len; 6455e655772SJeff Mahoney char *tmp; 6466543becfSAndreas Schwab DEF_FIELD_ADDR(symval, of_device_id, name); 6476543becfSAndreas Schwab DEF_FIELD_ADDR(symval, of_device_id, type); 6486543becfSAndreas Schwab DEF_FIELD_ADDR(symval, of_device_id, compatible); 649d1ab4235SSylvain Munaut 6506543becfSAndreas Schwab len = sprintf (alias, "of:N%sT%s", 6516543becfSAndreas Schwab (*name)[0] ? *name : "*", 6526543becfSAndreas Schwab (*type)[0] ? *type : "*"); 6536543becfSAndreas Schwab 6546543becfSAndreas Schwab if (compatible[0]) 655d1ab4235SSylvain Munaut sprintf (&alias[len], "%sC%s", 6566543becfSAndreas Schwab (*type)[0] ? "*" : "", 6576543becfSAndreas Schwab *compatible); 6585e655772SJeff Mahoney 6595e655772SJeff Mahoney /* Replace all whitespace with underscores */ 6605e655772SJeff Mahoney for (tmp = alias; tmp && *tmp; tmp++) 6615e655772SJeff Mahoney if (isspace (*tmp)) 6625e655772SJeff Mahoney *tmp = '_'; 6635e655772SJeff Mahoney 664ac551828SJean Delvare add_wildcard(alias); 6655e655772SJeff Mahoney return 1; 6665e655772SJeff Mahoney } 6676543becfSAndreas Schwab ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); 6685e655772SJeff Mahoney 6696543becfSAndreas Schwab static int do_vio_entry(const char *filename, void *symval, 670fb120da6SStephen Rothwell char *alias) 671fb120da6SStephen Rothwell { 672fb120da6SStephen Rothwell char *tmp; 6736543becfSAndreas Schwab DEF_FIELD_ADDR(symval, vio_device_id, type); 6746543becfSAndreas Schwab DEF_FIELD_ADDR(symval, vio_device_id, compat); 675fb120da6SStephen Rothwell 6766543becfSAndreas Schwab sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", 6776543becfSAndreas Schwab (*compat)[0] ? *compat : "*"); 678fb120da6SStephen Rothwell 679fb120da6SStephen Rothwell /* Replace all whitespace with underscores */ 680fb120da6SStephen Rothwell for (tmp = alias; tmp && *tmp; tmp++) 681fb120da6SStephen Rothwell if (isspace (*tmp)) 682fb120da6SStephen Rothwell *tmp = '_'; 683fb120da6SStephen Rothwell 684ac551828SJean Delvare add_wildcard(alias); 685fb120da6SStephen Rothwell return 1; 686fb120da6SStephen Rothwell } 6876543becfSAndreas Schwab ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); 688fb120da6SStephen Rothwell 6891d8f430cSRusty Russell #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 6901d8f430cSRusty Russell 6911d8f430cSRusty Russell static void do_input(char *alias, 6921d8f430cSRusty Russell kernel_ulong_t *arr, unsigned int min, unsigned int max) 6931d8f430cSRusty Russell { 6941d8f430cSRusty Russell unsigned int i; 695ddc5d341SDmitry Torokhov 6966543becfSAndreas Schwab for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) 6976543becfSAndreas Schwab arr[i] = TO_NATIVE(arr[i]); 698ddc5d341SDmitry Torokhov for (i = min; i < max; i++) 699e0e92632SHans de Goede if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) 7001d8f430cSRusty Russell sprintf(alias + strlen(alias), "%X,*", i); 7011d8f430cSRusty Russell } 7021d8f430cSRusty Russell 7031d8f430cSRusty Russell /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ 7046543becfSAndreas Schwab static int do_input_entry(const char *filename, void *symval, 7051d8f430cSRusty Russell char *alias) 7061d8f430cSRusty Russell { 7076543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, flags); 7086543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, bustype); 7096543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, vendor); 7106543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, product); 7116543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, version); 7126543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, evbit); 7136543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, keybit); 7146543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, relbit); 7156543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, absbit); 7166543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, mscbit); 7176543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ledbit); 7186543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, sndbit); 7196543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ffbit); 7206543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, swbit); 7216543becfSAndreas Schwab 7221d8f430cSRusty Russell sprintf(alias, "input:"); 7231d8f430cSRusty Russell 7246543becfSAndreas Schwab ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); 7256543becfSAndreas Schwab ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); 7266543becfSAndreas Schwab ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); 7276543becfSAndreas Schwab ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); 7281d8f430cSRusty Russell 7291d8f430cSRusty Russell sprintf(alias + strlen(alias), "-e*"); 7306543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) 7316543becfSAndreas Schwab do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); 7321d8f430cSRusty Russell sprintf(alias + strlen(alias), "k*"); 7336543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) 7346543becfSAndreas Schwab do_input(alias, *keybit, 735dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MIN_INTERESTING, 736dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MAX); 7371d8f430cSRusty Russell sprintf(alias + strlen(alias), "r*"); 7386543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) 7396543becfSAndreas Schwab do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); 7401d8f430cSRusty Russell sprintf(alias + strlen(alias), "a*"); 7416543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) 7426543becfSAndreas Schwab do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); 7431d8f430cSRusty Russell sprintf(alias + strlen(alias), "m*"); 7446543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) 7456543becfSAndreas Schwab do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); 7461d8f430cSRusty Russell sprintf(alias + strlen(alias), "l*"); 7476543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) 7486543becfSAndreas Schwab do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); 7491d8f430cSRusty Russell sprintf(alias + strlen(alias), "s*"); 7506543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) 7516543becfSAndreas Schwab do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); 7521d8f430cSRusty Russell sprintf(alias + strlen(alias), "f*"); 7536543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) 7546543becfSAndreas Schwab do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); 7551d8f430cSRusty Russell sprintf(alias + strlen(alias), "w*"); 7566543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) 7576543becfSAndreas Schwab do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); 7581d8f430cSRusty Russell return 1; 7591d8f430cSRusty Russell } 7606543becfSAndreas Schwab ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); 7611d8f430cSRusty Russell 7626543becfSAndreas Schwab static int do_eisa_entry(const char *filename, void *symval, 76307563c71SMichael Tokarev char *alias) 76407563c71SMichael Tokarev { 7656543becfSAndreas Schwab DEF_FIELD_ADDR(symval, eisa_device_id, sig); 7666543becfSAndreas Schwab if (sig[0]) 7676543becfSAndreas Schwab sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); 768ac551828SJean Delvare else 769ac551828SJean Delvare strcat(alias, "*"); 77007563c71SMichael Tokarev return 1; 77107563c71SMichael Tokarev } 7726543becfSAndreas Schwab ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); 77307563c71SMichael Tokarev 774f3cf2673SKyle McMartin /* Looks like: parisc:tNhvNrevNsvN */ 7756543becfSAndreas Schwab static int do_parisc_entry(const char *filename, void *symval, 776f3cf2673SKyle McMartin char *alias) 777f3cf2673SKyle McMartin { 7786543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hw_type); 7796543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion); 7806543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion_rev); 7816543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, sversion); 782f3cf2673SKyle McMartin 783f3cf2673SKyle McMartin strcpy(alias, "parisc:"); 7846543becfSAndreas Schwab ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); 7856543becfSAndreas Schwab ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); 7866543becfSAndreas Schwab ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); 7876543becfSAndreas Schwab ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); 788f3cf2673SKyle McMartin 789ac551828SJean Delvare add_wildcard(alias); 790f3cf2673SKyle McMartin return 1; 791f3cf2673SKyle McMartin } 7926543becfSAndreas Schwab ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); 793f3cf2673SKyle McMartin 794d59b66c7SPierre Ossman /* Looks like: sdio:cNvNdN. */ 795d59b66c7SPierre Ossman static int do_sdio_entry(const char *filename, 7966543becfSAndreas Schwab void *symval, char *alias) 797d59b66c7SPierre Ossman { 7986543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, class); 7996543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, vendor); 8006543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, device); 801d59b66c7SPierre Ossman 802d59b66c7SPierre Ossman strcpy(alias, "sdio:"); 8036543becfSAndreas Schwab ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); 8046543becfSAndreas Schwab ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); 8056543becfSAndreas Schwab ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); 806ac551828SJean Delvare add_wildcard(alias); 807038a5008SLinus Torvalds return 1; 808038a5008SLinus Torvalds } 8096543becfSAndreas Schwab ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); 810d59b66c7SPierre Ossman 81161e115a5SMichael Buesch /* Looks like: ssb:vNidNrevN. */ 81261e115a5SMichael Buesch static int do_ssb_entry(const char *filename, 8136543becfSAndreas Schwab void *symval, char *alias) 81461e115a5SMichael Buesch { 8156543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, vendor); 8166543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, coreid); 8176543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, revision); 81861e115a5SMichael Buesch 81961e115a5SMichael Buesch strcpy(alias, "ssb:"); 8206543becfSAndreas Schwab ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); 8216543becfSAndreas Schwab ADD(alias, "id", coreid != SSB_ANY_ID, coreid); 8226543becfSAndreas Schwab ADD(alias, "rev", revision != SSB_ANY_REV, revision); 823ac551828SJean Delvare add_wildcard(alias); 824d59b66c7SPierre Ossman return 1; 825d59b66c7SPierre Ossman } 8266543becfSAndreas Schwab ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); 827d59b66c7SPierre Ossman 8288369ae33SRafał Miłecki /* Looks like: bcma:mNidNrevNclN. */ 8298369ae33SRafał Miłecki static int do_bcma_entry(const char *filename, 8306543becfSAndreas Schwab void *symval, char *alias) 8318369ae33SRafał Miłecki { 8326543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, manuf); 8336543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, id); 8346543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, rev); 8356543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, class); 8368369ae33SRafał Miłecki 8378369ae33SRafał Miłecki strcpy(alias, "bcma:"); 8386543becfSAndreas Schwab ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); 8396543becfSAndreas Schwab ADD(alias, "id", id != BCMA_ANY_ID, id); 8406543becfSAndreas Schwab ADD(alias, "rev", rev != BCMA_ANY_REV, rev); 8416543becfSAndreas Schwab ADD(alias, "cl", class != BCMA_ANY_CLASS, class); 8428369ae33SRafał Miłecki add_wildcard(alias); 8438369ae33SRafał Miłecki return 1; 8448369ae33SRafał Miłecki } 8456543becfSAndreas Schwab ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); 8468369ae33SRafał Miłecki 847b01d9f28SRusty Russell /* Looks like: virtio:dNvN */ 8486543becfSAndreas Schwab static int do_virtio_entry(const char *filename, void *symval, 849b01d9f28SRusty Russell char *alias) 850b01d9f28SRusty Russell { 8516543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, device); 8526543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, vendor); 853b01d9f28SRusty Russell 854b01d9f28SRusty Russell strcpy(alias, "virtio:"); 8556543becfSAndreas Schwab ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); 8566543becfSAndreas Schwab ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); 857b01d9f28SRusty Russell 858ac551828SJean Delvare add_wildcard(alias); 859b01d9f28SRusty Russell return 1; 860b01d9f28SRusty Russell } 8616543becfSAndreas Schwab ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); 862b01d9f28SRusty Russell 863d2ee52aaSK. Y. Srinivasan /* 864d2ee52aaSK. Y. Srinivasan * Looks like: vmbus:guid 865d2ee52aaSK. Y. Srinivasan * Each byte of the guid will be represented by two hex characters 866d2ee52aaSK. Y. Srinivasan * in the name. 867d2ee52aaSK. Y. Srinivasan */ 868d2ee52aaSK. Y. Srinivasan 8696543becfSAndreas Schwab static int do_vmbus_entry(const char *filename, void *symval, 870d2ee52aaSK. Y. Srinivasan char *alias) 871d2ee52aaSK. Y. Srinivasan { 872d2ee52aaSK. Y. Srinivasan int i; 8736543becfSAndreas Schwab DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); 8746543becfSAndreas Schwab char guid_name[(sizeof(*guid) + 1) * 2]; 875d2ee52aaSK. Y. Srinivasan 8766543becfSAndreas Schwab for (i = 0; i < (sizeof(*guid) * 2); i += 2) 8776543becfSAndreas Schwab sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); 878d2ee52aaSK. Y. Srinivasan 879d2ee52aaSK. Y. Srinivasan strcpy(alias, "vmbus:"); 880d2ee52aaSK. Y. Srinivasan strcat(alias, guid_name); 881d2ee52aaSK. Y. Srinivasan 882d2ee52aaSK. Y. Srinivasan return 1; 883d2ee52aaSK. Y. Srinivasan } 8846543becfSAndreas Schwab ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); 885d2ee52aaSK. Y. Srinivasan 886d2653e92SJean Delvare /* Looks like: i2c:S */ 8876543becfSAndreas Schwab static int do_i2c_entry(const char *filename, void *symval, 888d2653e92SJean Delvare char *alias) 889d2653e92SJean Delvare { 8906543becfSAndreas Schwab DEF_FIELD_ADDR(symval, i2c_device_id, name); 8916543becfSAndreas Schwab sprintf(alias, I2C_MODULE_PREFIX "%s", *name); 892d2653e92SJean Delvare 893d2653e92SJean Delvare return 1; 894d2653e92SJean Delvare } 8956543becfSAndreas Schwab ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); 896d2653e92SJean Delvare 897e0626e38SAnton Vorontsov /* Looks like: spi:S */ 8986543becfSAndreas Schwab static int do_spi_entry(const char *filename, void *symval, 89975368bf6SAnton Vorontsov char *alias) 90075368bf6SAnton Vorontsov { 9016543becfSAndreas Schwab DEF_FIELD_ADDR(symval, spi_device_id, name); 9026543becfSAndreas Schwab sprintf(alias, SPI_MODULE_PREFIX "%s", *name); 90375368bf6SAnton Vorontsov 90475368bf6SAnton Vorontsov return 1; 90575368bf6SAnton Vorontsov } 9066543becfSAndreas Schwab ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); 90775368bf6SAnton Vorontsov 908d945b697SDavid Woodhouse static const struct dmifield { 909d945b697SDavid Woodhouse const char *prefix; 910d945b697SDavid Woodhouse int field; 911d945b697SDavid Woodhouse } dmi_fields[] = { 912d945b697SDavid Woodhouse { "bvn", DMI_BIOS_VENDOR }, 913d945b697SDavid Woodhouse { "bvr", DMI_BIOS_VERSION }, 914d945b697SDavid Woodhouse { "bd", DMI_BIOS_DATE }, 915d945b697SDavid Woodhouse { "svn", DMI_SYS_VENDOR }, 916d945b697SDavid Woodhouse { "pn", DMI_PRODUCT_NAME }, 917d945b697SDavid Woodhouse { "pvr", DMI_PRODUCT_VERSION }, 918d945b697SDavid Woodhouse { "rvn", DMI_BOARD_VENDOR }, 919d945b697SDavid Woodhouse { "rn", DMI_BOARD_NAME }, 920d945b697SDavid Woodhouse { "rvr", DMI_BOARD_VERSION }, 921d945b697SDavid Woodhouse { "cvn", DMI_CHASSIS_VENDOR }, 922d945b697SDavid Woodhouse { "ct", DMI_CHASSIS_TYPE }, 923d945b697SDavid Woodhouse { "cvr", DMI_CHASSIS_VERSION }, 924d945b697SDavid Woodhouse { NULL, DMI_NONE } 925d945b697SDavid Woodhouse }; 926d945b697SDavid Woodhouse 927d945b697SDavid Woodhouse static void dmi_ascii_filter(char *d, const char *s) 928d945b697SDavid Woodhouse { 929d945b697SDavid Woodhouse /* Filter out characters we don't want to see in the modalias string */ 930d945b697SDavid Woodhouse for (; *s; s++) 931d945b697SDavid Woodhouse if (*s > ' ' && *s < 127 && *s != ':') 932d945b697SDavid Woodhouse *(d++) = *s; 933d945b697SDavid Woodhouse 934d945b697SDavid Woodhouse *d = 0; 935d945b697SDavid Woodhouse } 936d945b697SDavid Woodhouse 937d945b697SDavid Woodhouse 9386543becfSAndreas Schwab static int do_dmi_entry(const char *filename, void *symval, 939d945b697SDavid Woodhouse char *alias) 940d945b697SDavid Woodhouse { 941d945b697SDavid Woodhouse int i, j; 9426543becfSAndreas Schwab DEF_FIELD_ADDR(symval, dmi_system_id, matches); 943d945b697SDavid Woodhouse sprintf(alias, "dmi*"); 944d945b697SDavid Woodhouse 945d945b697SDavid Woodhouse for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { 946d945b697SDavid Woodhouse for (j = 0; j < 4; j++) { 9476543becfSAndreas Schwab if ((*matches)[j].slot && 9486543becfSAndreas Schwab (*matches)[j].slot == dmi_fields[i].field) { 949d945b697SDavid Woodhouse sprintf(alias + strlen(alias), ":%s*", 950d945b697SDavid Woodhouse dmi_fields[i].prefix); 951d945b697SDavid Woodhouse dmi_ascii_filter(alias + strlen(alias), 9526543becfSAndreas Schwab (*matches)[j].substr); 953d945b697SDavid Woodhouse strcat(alias, "*"); 954d945b697SDavid Woodhouse } 955d945b697SDavid Woodhouse } 956d945b697SDavid Woodhouse } 957d945b697SDavid Woodhouse 958d945b697SDavid Woodhouse strcat(alias, ":"); 959d945b697SDavid Woodhouse return 1; 960d945b697SDavid Woodhouse } 9616543becfSAndreas Schwab ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); 96257fee4a5SEric Miao 96357fee4a5SEric Miao static int do_platform_entry(const char *filename, 9646543becfSAndreas Schwab void *symval, char *alias) 96557fee4a5SEric Miao { 9666543becfSAndreas Schwab DEF_FIELD_ADDR(symval, platform_device_id, name); 9676543becfSAndreas Schwab sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); 96857fee4a5SEric Miao return 1; 96957fee4a5SEric Miao } 9706543becfSAndreas Schwab ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); 97157fee4a5SEric Miao 9728626d3b4SDavid Woodhouse static int do_mdio_entry(const char *filename, 9736543becfSAndreas Schwab void *symval, char *alias) 9748626d3b4SDavid Woodhouse { 9758626d3b4SDavid Woodhouse int i; 9766543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id); 9776543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id_mask); 9788626d3b4SDavid Woodhouse 9798626d3b4SDavid Woodhouse alias += sprintf(alias, MDIO_MODULE_PREFIX); 9808626d3b4SDavid Woodhouse 9818626d3b4SDavid Woodhouse for (i = 0; i < 32; i++) { 9826543becfSAndreas Schwab if (!((phy_id_mask >> (31-i)) & 1)) 9838626d3b4SDavid Woodhouse *(alias++) = '?'; 9846543becfSAndreas Schwab else if ((phy_id >> (31-i)) & 1) 9858626d3b4SDavid Woodhouse *(alias++) = '1'; 9868626d3b4SDavid Woodhouse else 9878626d3b4SDavid Woodhouse *(alias++) = '0'; 9888626d3b4SDavid Woodhouse } 9898626d3b4SDavid Woodhouse 9908626d3b4SDavid Woodhouse /* Terminate the string */ 9918626d3b4SDavid Woodhouse *alias = 0; 9928626d3b4SDavid Woodhouse 9938626d3b4SDavid Woodhouse return 1; 9948626d3b4SDavid Woodhouse } 9956543becfSAndreas Schwab ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); 9968626d3b4SDavid Woodhouse 997bf54a2b3SGeert Uytterhoeven /* Looks like: zorro:iN. */ 9986543becfSAndreas Schwab static int do_zorro_entry(const char *filename, void *symval, 999bf54a2b3SGeert Uytterhoeven char *alias) 1000bf54a2b3SGeert Uytterhoeven { 10016543becfSAndreas Schwab DEF_FIELD(symval, zorro_device_id, id); 1002bf54a2b3SGeert Uytterhoeven strcpy(alias, "zorro:"); 10036543becfSAndreas Schwab ADD(alias, "i", id != ZORRO_WILDCARD, id); 1004bf54a2b3SGeert Uytterhoeven return 1; 1005bf54a2b3SGeert Uytterhoeven } 10066543becfSAndreas Schwab ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); 1007bf54a2b3SGeert Uytterhoeven 1008fedb3d27SOndrej Zary /* looks like: "pnp:dD" */ 1009fedb3d27SOndrej Zary static int do_isapnp_entry(const char *filename, 10106543becfSAndreas Schwab void *symval, char *alias) 1011fedb3d27SOndrej Zary { 10126543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, vendor); 10136543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, function); 1014fedb3d27SOndrej Zary sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", 10156543becfSAndreas Schwab 'A' + ((vendor >> 2) & 0x3f) - 1, 10166543becfSAndreas Schwab 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 10176543becfSAndreas Schwab 'A' + ((vendor >> 8) & 0x1f) - 1, 10186543becfSAndreas Schwab (function >> 4) & 0x0f, function & 0x0f, 10196543becfSAndreas Schwab (function >> 12) & 0x0f, (function >> 8) & 0x0f); 1020fedb3d27SOndrej Zary return 1; 1021fedb3d27SOndrej Zary } 10226543becfSAndreas Schwab ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); 1023fedb3d27SOndrej Zary 1024849e0ad2SJens Taprogge /* Looks like: "ipack:fNvNdN". */ 1025849e0ad2SJens Taprogge static int do_ipack_entry(const char *filename, 10266543becfSAndreas Schwab void *symval, char *alias) 1027849e0ad2SJens Taprogge { 10286543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, format); 10296543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, vendor); 10306543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, device); 1031849e0ad2SJens Taprogge strcpy(alias, "ipack:"); 10326543becfSAndreas Schwab ADD(alias, "f", format != IPACK_ANY_FORMAT, format); 10336543becfSAndreas Schwab ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); 10346543becfSAndreas Schwab ADD(alias, "d", device != IPACK_ANY_ID, device); 1035849e0ad2SJens Taprogge add_wildcard(alias); 1036849e0ad2SJens Taprogge return 1; 1037849e0ad2SJens Taprogge } 10386543becfSAndreas Schwab ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); 1039849e0ad2SJens Taprogge 1040523817bdSDave Martin /* 1041523817bdSDave Martin * Append a match expression for a single masked hex digit. 1042523817bdSDave Martin * outp points to a pointer to the character at which to append. 1043523817bdSDave Martin * *outp is updated on return to point just after the appended text, 1044523817bdSDave Martin * to facilitate further appending. 1045523817bdSDave Martin */ 1046523817bdSDave Martin static void append_nibble_mask(char **outp, 1047523817bdSDave Martin unsigned int nibble, unsigned int mask) 1048523817bdSDave Martin { 1049523817bdSDave Martin char *p = *outp; 1050523817bdSDave Martin unsigned int i; 1051523817bdSDave Martin 1052523817bdSDave Martin switch (mask) { 1053523817bdSDave Martin case 0: 1054523817bdSDave Martin *p++ = '?'; 1055523817bdSDave Martin break; 1056523817bdSDave Martin 1057523817bdSDave Martin case 0xf: 1058523817bdSDave Martin p += sprintf(p, "%X", nibble); 1059523817bdSDave Martin break; 1060523817bdSDave Martin 1061523817bdSDave Martin default: 1062523817bdSDave Martin /* 1063523817bdSDave Martin * Dumbly emit a match pattern for all possible matching 1064523817bdSDave Martin * digits. This could be improved in some cases using ranges, 1065523817bdSDave Martin * but it has the advantage of being trivially correct, and is 1066523817bdSDave Martin * often optimal. 1067523817bdSDave Martin */ 1068523817bdSDave Martin *p++ = '['; 1069523817bdSDave Martin for (i = 0; i < 0x10; i++) 1070523817bdSDave Martin if ((i & mask) == nibble) 1071523817bdSDave Martin p += sprintf(p, "%X", i); 1072523817bdSDave Martin *p++ = ']'; 1073523817bdSDave Martin } 1074523817bdSDave Martin 1075523817bdSDave Martin /* Ensure that the string remains NUL-terminated: */ 1076523817bdSDave Martin *p = '\0'; 1077523817bdSDave Martin 1078523817bdSDave Martin /* Advance the caller's end-of-string pointer: */ 1079523817bdSDave Martin *outp = p; 1080523817bdSDave Martin } 1081523817bdSDave Martin 1082523817bdSDave Martin /* 1083523817bdSDave Martin * looks like: "amba:dN" 1084523817bdSDave Martin * 1085523817bdSDave Martin * N is exactly 8 digits, where each is an upper-case hex digit, or 1086523817bdSDave Martin * a ? or [] pattern matching exactly one digit. 1087523817bdSDave Martin */ 1088523817bdSDave Martin static int do_amba_entry(const char *filename, 10896543becfSAndreas Schwab void *symval, char *alias) 1090523817bdSDave Martin { 1091523817bdSDave Martin unsigned int digit; 1092523817bdSDave Martin char *p = alias; 10936543becfSAndreas Schwab DEF_FIELD(symval, amba_id, id); 10946543becfSAndreas Schwab DEF_FIELD(symval, amba_id, mask); 1095523817bdSDave Martin 10966543becfSAndreas Schwab if ((id & mask) != id) 1097523817bdSDave Martin fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " 1098523817bdSDave Martin "id=0x%08X, mask=0x%08X. Please fix this driver.\n", 10996543becfSAndreas Schwab filename, id, mask); 1100523817bdSDave Martin 1101523817bdSDave Martin p += sprintf(alias, "amba:d"); 1102523817bdSDave Martin for (digit = 0; digit < 8; digit++) 1103523817bdSDave Martin append_nibble_mask(&p, 11046543becfSAndreas Schwab (id >> (4 * (7 - digit))) & 0xf, 11056543becfSAndreas Schwab (mask >> (4 * (7 - digit))) & 0xf); 1106523817bdSDave Martin 1107523817bdSDave Martin return 1; 1108523817bdSDave Martin } 11096543becfSAndreas Schwab ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); 1110523817bdSDave Martin 1111644e9cbbSAndi Kleen /* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,* 1112644e9cbbSAndi Kleen * All fields are numbers. It would be nicer to use strings for vendor 1113644e9cbbSAndi Kleen * and feature, but getting those out of the build system here is too 1114644e9cbbSAndi Kleen * complicated. 1115644e9cbbSAndi Kleen */ 1116644e9cbbSAndi Kleen 11176543becfSAndreas Schwab static int do_x86cpu_entry(const char *filename, void *symval, 1118644e9cbbSAndi Kleen char *alias) 1119644e9cbbSAndi Kleen { 11206543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, feature); 11216543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, family); 11226543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, model); 11236543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, vendor); 1124644e9cbbSAndi Kleen 1125644e9cbbSAndi Kleen strcpy(alias, "x86cpu:"); 11266543becfSAndreas Schwab ADD(alias, "vendor:", vendor != X86_VENDOR_ANY, vendor); 11276543becfSAndreas Schwab ADD(alias, ":family:", family != X86_FAMILY_ANY, family); 11286543becfSAndreas Schwab ADD(alias, ":model:", model != X86_MODEL_ANY, model); 11295467bddaSBen Hutchings strcat(alias, ":feature:*"); 11306543becfSAndreas Schwab if (feature != X86_FEATURE_ANY) 11316543becfSAndreas Schwab sprintf(alias + strlen(alias), "%04X*", feature); 1132644e9cbbSAndi Kleen return 1; 1133644e9cbbSAndi Kleen } 11346543becfSAndreas Schwab ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); 1135644e9cbbSAndi Kleen 1136e5354107SSamuel Ortiz /* Looks like: mei:S */ 1137e5354107SSamuel Ortiz static int do_mei_entry(const char *filename, void *symval, 1138e5354107SSamuel Ortiz char *alias) 1139e5354107SSamuel Ortiz { 1140e5354107SSamuel Ortiz DEF_FIELD_ADDR(symval, mei_cl_device_id, name); 1141e5354107SSamuel Ortiz 1142e5354107SSamuel Ortiz sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name); 1143e5354107SSamuel Ortiz 1144e5354107SSamuel Ortiz return 1; 1145e5354107SSamuel Ortiz } 1146e5354107SSamuel Ortiz ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); 1147e5354107SSamuel Ortiz 1148*3bdbb62fSAlexandre Bounine /* Looks like: rapidio:vNdNavNadN */ 1149*3bdbb62fSAlexandre Bounine static int do_rio_entry(const char *filename, 1150*3bdbb62fSAlexandre Bounine void *symval, char *alias) 1151*3bdbb62fSAlexandre Bounine { 1152*3bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, did); 1153*3bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, vid); 1154*3bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_did); 1155*3bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_vid); 1156*3bdbb62fSAlexandre Bounine 1157*3bdbb62fSAlexandre Bounine strcpy(alias, "rapidio:"); 1158*3bdbb62fSAlexandre Bounine ADD(alias, "v", vid != RIO_ANY_ID, vid); 1159*3bdbb62fSAlexandre Bounine ADD(alias, "d", did != RIO_ANY_ID, did); 1160*3bdbb62fSAlexandre Bounine ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); 1161*3bdbb62fSAlexandre Bounine ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); 1162*3bdbb62fSAlexandre Bounine 1163*3bdbb62fSAlexandre Bounine add_wildcard(alias); 1164*3bdbb62fSAlexandre Bounine return 1; 1165*3bdbb62fSAlexandre Bounine } 1166*3bdbb62fSAlexandre Bounine ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); 1167*3bdbb62fSAlexandre Bounine 1168626596e2SRusty Russell /* Does namelen bytes of name exactly match the symbol? */ 1169626596e2SRusty Russell static bool sym_is(const char *name, unsigned namelen, const char *symbol) 11701da177e4SLinus Torvalds { 1171626596e2SRusty Russell if (namelen != strlen(symbol)) 1172626596e2SRusty Russell return false; 11731da177e4SLinus Torvalds 1174626596e2SRusty Russell return memcmp(name, symbol, namelen) == 0; 11751da177e4SLinus Torvalds } 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds static void do_table(void *symval, unsigned long size, 11781da177e4SLinus Torvalds unsigned long id_size, 1179fb33d816SSam Ravnborg const char *device_id, 11801da177e4SLinus Torvalds void *function, 11811da177e4SLinus Torvalds struct module *mod) 11821da177e4SLinus Torvalds { 11831da177e4SLinus Torvalds unsigned int i; 11841da177e4SLinus Torvalds char alias[500]; 11851da177e4SLinus Torvalds int (*do_entry)(const char *, void *entry, char *alias) = function; 11861da177e4SLinus Torvalds 1187e0049825SKees Cook device_id_check(mod->name, device_id, size, id_size, symval); 11881da177e4SLinus Torvalds /* Leave last one: it's the terminator. */ 11891da177e4SLinus Torvalds size -= id_size; 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds for (i = 0; i < size; i += id_size) { 11921da177e4SLinus Torvalds if (do_entry(mod->name, symval+i, alias)) { 11931da177e4SLinus Torvalds buf_printf(&mod->dev_table_buf, 11941da177e4SLinus Torvalds "MODULE_ALIAS(\"%s\");\n", alias); 11951da177e4SLinus Torvalds } 11961da177e4SLinus Torvalds } 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds 11991da177e4SLinus Torvalds /* Create MODULE_ALIAS() statements. 12001da177e4SLinus Torvalds * At this time, we cannot write the actual output C source yet, 12011da177e4SLinus Torvalds * so we write into the mod->dev_table_buf buffer. */ 12021da177e4SLinus Torvalds void handle_moddevtable(struct module *mod, struct elf_info *info, 12031da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 12041da177e4SLinus Torvalds { 12051da177e4SLinus Torvalds void *symval; 1206e0049825SKees Cook char *zeros = NULL; 1207626596e2SRusty Russell const char *name; 1208626596e2SRusty Russell unsigned int namelen; 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds /* We're looking for a section relative symbol */ 12111ce53adfSDenys Vlasenko if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) 12121da177e4SLinus Torvalds return; 12131da177e4SLinus Torvalds 1214e88aa7bbSDavid Miller /* We're looking for an object */ 1215e88aa7bbSDavid Miller if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 1216e88aa7bbSDavid Miller return; 1217e88aa7bbSDavid Miller 1218626596e2SRusty Russell /* All our symbols are of form <prefix>__mod_XXX_device_table. */ 1219626596e2SRusty Russell name = strstr(symname, "__mod_"); 1220626596e2SRusty Russell if (!name) 1221626596e2SRusty Russell return; 1222626596e2SRusty Russell name += strlen("__mod_"); 1223626596e2SRusty Russell namelen = strlen(name); 1224626596e2SRusty Russell if (namelen < strlen("_device_table")) 1225626596e2SRusty Russell return; 1226626596e2SRusty Russell if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) 1227626596e2SRusty Russell return; 1228626596e2SRusty Russell namelen -= strlen("_device_table"); 1229626596e2SRusty Russell 1230e0049825SKees Cook /* Handle all-NULL symbols allocated into .bss */ 12311ce53adfSDenys Vlasenko if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { 1232e0049825SKees Cook zeros = calloc(1, sym->st_size); 1233e0049825SKees Cook symval = zeros; 1234e0049825SKees Cook } else { 12351da177e4SLinus Torvalds symval = (void *)info->hdr 12361ce53adfSDenys Vlasenko + info->sechdrs[get_secindex(info, sym)].sh_offset 12371da177e4SLinus Torvalds + sym->st_value; 1238e0049825SKees Cook } 12391da177e4SLinus Torvalds 1240626596e2SRusty Russell /* First handle the "special" cases */ 1241626596e2SRusty Russell if (sym_is(name, namelen, "usb")) 1242b19dcd93SRoman Kagan do_usb_table(symval, sym->st_size, mod); 1243626596e2SRusty Russell else if (sym_is(name, namelen, "pnp")) 124422454cb9SKay Sievers do_pnp_device_entry(symval, sym->st_size, mod); 1245626596e2SRusty Russell else if (sym_is(name, namelen, "pnp_card")) 12460c81eed4SKay Sievers do_pnp_card_entries(symval, sym->st_size, mod); 1247626596e2SRusty Russell else { 1248e49ce141SRusty Russell struct devtable **p; 1249dd2a3acaSAndreas Bießmann INIT_SECTION(__devtable); 1250626596e2SRusty Russell 1251e49ce141SRusty Russell for (p = __start___devtable; p < __stop___devtable; p++) { 1252e49ce141SRusty Russell if (sym_is(name, namelen, (*p)->device_id)) { 1253e49ce141SRusty Russell do_table(symval, sym->st_size, (*p)->id_size, 1254e49ce141SRusty Russell (*p)->device_id, (*p)->function, mod); 1255626596e2SRusty Russell break; 1256626596e2SRusty Russell } 1257626596e2SRusty Russell } 1258626596e2SRusty Russell } 1259e0049825SKees Cook free(zeros); 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds /* Now add out buffered information to the generated C source */ 12631da177e4SLinus Torvalds void add_moddevtable(struct buffer *buf, struct module *mod) 12641da177e4SLinus Torvalds { 12651da177e4SLinus Torvalds buf_printf(buf, "\n"); 12661da177e4SLinus Torvalds buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); 12671da177e4SLinus Torvalds free(mod->dev_table_buf.p); 12681da177e4SLinus Torvalds } 1269