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; 37b144ce2dSGreg Kroah-Hartman typedef struct { 38b144ce2dSGreg Kroah-Hartman __u8 b[16]; 39389c9af7SHeikki Krogerus } guid_t; 40389c9af7SHeikki Krogerus 41389c9af7SHeikki Krogerus /* backwards compatibility, don't use in new code */ 42389c9af7SHeikki Krogerus typedef struct { 43389c9af7SHeikki Krogerus __u8 b[16]; 44b144ce2dSGreg Kroah-Hartman } uuid_le; 450fc1db9dSSumit Garg typedef struct { 460fc1db9dSSumit Garg __u8 b[16]; 470fc1db9dSSumit Garg } uuid_t; 48eacc95eaSMattias Jacobsson #define UUID_STRING_LEN 36 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* Big exception to the "don't include kernel headers into userspace, which 511da177e4SLinus Torvalds * even potentially has different endianness and word sizes, since 521da177e4SLinus Torvalds * we handle those differences explicitly below */ 531da177e4SLinus Torvalds #include "../../include/linux/mod_devicetable.h" 541da177e4SLinus Torvalds 55e49ce141SRusty Russell /* This array collects all instances that use the generic do_table */ 56e49ce141SRusty Russell struct devtable { 5721bdd17bSTom Gundersen const char *device_id; /* name of table, __mod_<name>__*_device_table. */ 58e49ce141SRusty Russell unsigned long id_size; 59f880eea6SMasahiro Yamada int (*do_entry)(const char *filename, void *symval, char *alias); 60e49ce141SRusty Russell }; 61e49ce141SRusty Russell 62841f1b8fSMattias Jacobsson /* Size of alias provided to do_entry functions */ 63841f1b8fSMattias Jacobsson #define ALIAS_SIZE 500 64841f1b8fSMattias Jacobsson 656543becfSAndreas Schwab /* Define a variable f that holds the value of field f of struct devid 666543becfSAndreas Schwab * based at address m. 676543becfSAndreas Schwab */ 686543becfSAndreas Schwab #define DEF_FIELD(m, devid, f) \ 696543becfSAndreas Schwab typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) 70c2b1a922SLeonardo Bras 71c2b1a922SLeonardo Bras /* Define a variable v that holds the address of field f of struct devid 72c2b1a922SLeonardo Bras * based at address m. Due to the way typeof works, for a field of type 73c2b1a922SLeonardo Bras * T[N] the variable has type T(*)[N], _not_ T*. 74c2b1a922SLeonardo Bras */ 75c2b1a922SLeonardo Bras #define DEF_FIELD_ADDR_VAR(m, devid, f, v) \ 76c2b1a922SLeonardo Bras typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f) 77c2b1a922SLeonardo Bras 786543becfSAndreas Schwab /* Define a variable f that holds the address of field f of struct devid 796543becfSAndreas Schwab * based at address m. Due to the way typeof works, for a field of type 806543becfSAndreas Schwab * T[N] the variable has type T(*)[N], _not_ T*. 816543becfSAndreas Schwab */ 826543becfSAndreas Schwab #define DEF_FIELD_ADDR(m, devid, f) \ 83c2b1a922SLeonardo Bras DEF_FIELD_ADDR_VAR(m, devid, f, f) 846543becfSAndreas Schwab 851da177e4SLinus Torvalds #define ADD(str, sep, cond, field) \ 861da177e4SLinus Torvalds do { \ 871da177e4SLinus Torvalds strcat(str, sep); \ 881da177e4SLinus Torvalds if (cond) \ 891da177e4SLinus Torvalds sprintf(str + strlen(str), \ 901da177e4SLinus Torvalds sizeof(field) == 1 ? "%02X" : \ 911da177e4SLinus Torvalds sizeof(field) == 2 ? "%04X" : \ 921da177e4SLinus Torvalds sizeof(field) == 4 ? "%08X" : "", \ 931da177e4SLinus Torvalds field); \ 941da177e4SLinus Torvalds else \ 951da177e4SLinus Torvalds sprintf(str + strlen(str), "*"); \ 961da177e4SLinus Torvalds } while(0) 971da177e4SLinus Torvalds 982f632369SJavier Martinez Canillas /* End in a wildcard, for future extension */ 99ac551828SJean Delvare static inline void add_wildcard(char *str) 100ac551828SJean Delvare { 101ac551828SJean Delvare int len = strlen(str); 102ac551828SJean Delvare 103ac551828SJean Delvare if (str[len - 1] != '*') 104ac551828SJean Delvare strcat(str + len, "*"); 105ac551828SJean Delvare } 106ac551828SJean Delvare 107b144ce2dSGreg Kroah-Hartman static inline void add_uuid(char *str, uuid_le uuid) 108c93b76b3STomas Winkler { 109c93b76b3STomas Winkler int len = strlen(str); 110c93b76b3STomas Winkler 11159796edcSPrarit Bhargava sprintf(str + len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 11259796edcSPrarit Bhargava uuid.b[3], uuid.b[2], uuid.b[1], uuid.b[0], 11359796edcSPrarit Bhargava uuid.b[5], uuid.b[4], uuid.b[7], uuid.b[6], 11459796edcSPrarit Bhargava uuid.b[8], uuid.b[9], uuid.b[10], uuid.b[11], 11559796edcSPrarit Bhargava uuid.b[12], uuid.b[13], uuid.b[14], uuid.b[15]); 116c93b76b3STomas Winkler } 117c93b76b3STomas Winkler 118*fa443bc3SThomas Weißschuh static inline void add_guid(char *str, guid_t guid) 119*fa443bc3SThomas Weißschuh { 120*fa443bc3SThomas Weißschuh int len = strlen(str); 121*fa443bc3SThomas Weißschuh 122*fa443bc3SThomas Weißschuh sprintf(str + len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 123*fa443bc3SThomas Weißschuh guid.b[3], guid.b[2], guid.b[1], guid.b[0], 124*fa443bc3SThomas Weißschuh guid.b[5], guid.b[4], guid.b[7], guid.b[6], 125*fa443bc3SThomas Weißschuh guid.b[8], guid.b[9], guid.b[10], guid.b[11], 126*fa443bc3SThomas Weißschuh guid.b[12], guid.b[13], guid.b[14], guid.b[15]); 127*fa443bc3SThomas Weißschuh } 128*fa443bc3SThomas Weißschuh 129fb33d816SSam Ravnborg /** 130fb33d816SSam Ravnborg * Check that sizeof(device_id type) are consistent with size of section 131fb33d816SSam Ravnborg * in .o file. If in-consistent then userspace and kernel does not agree 132fb33d816SSam Ravnborg * on actual size which is a bug. 133e0049825SKees Cook * Also verify that the final entry in the table is all zeros. 1344ce6efedSSam Ravnborg * Ignore both checks if build host differ from target host and size differs. 135fb33d816SSam Ravnborg **/ 136e0049825SKees Cook static void device_id_check(const char *modname, const char *device_id, 137e0049825SKees Cook unsigned long size, unsigned long id_size, 138e0049825SKees Cook void *symval) 139fb33d816SSam Ravnborg { 140e0049825SKees Cook int i; 141e0049825SKees Cook 142fb33d816SSam Ravnborg if (size % id_size || size < id_size) { 143fb33d816SSam Ravnborg fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " 14421bdd17bSTom Gundersen "of the size of " 14521bdd17bSTom Gundersen "section __mod_%s__<identifier>_device_table=%lu.\n" 146fb33d816SSam Ravnborg "Fix definition of struct %s_device_id " 147fb33d816SSam Ravnborg "in mod_devicetable.h\n", 148fb33d816SSam Ravnborg modname, device_id, id_size, device_id, size, device_id); 149fb33d816SSam Ravnborg } 150e0049825SKees Cook /* Verify last one is a terminator */ 151e0049825SKees Cook for (i = 0; i < id_size; i++ ) { 152e0049825SKees Cook if (*(uint8_t*)(symval+size-id_size+i)) { 153e0049825SKees Cook fprintf(stderr,"%s: struct %s_device_id is %lu bytes. " 154e0049825SKees Cook "The last of %lu is:\n", 155e0049825SKees Cook modname, device_id, id_size, size / id_size); 156e0049825SKees Cook for (i = 0; i < id_size; i++ ) 157e0049825SKees Cook fprintf(stderr,"0x%02x ", 158e0049825SKees Cook *(uint8_t*)(symval+size-id_size+i) ); 159e0049825SKees Cook fprintf(stderr,"\n"); 160e0049825SKees Cook fatal("%s: struct %s_device_id is not terminated " 161e0049825SKees Cook "with a NULL entry!\n", modname, device_id); 162e0049825SKees Cook } 163e0049825SKees Cook } 164fb33d816SSam Ravnborg } 165fb33d816SSam Ravnborg 166b19dcd93SRoman Kagan /* USB is special because the bcdDevice can be matched against a numeric range */ 16781df2d59SBjørn Mork /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ 1686543becfSAndreas Schwab static void do_usb_entry(void *symval, 169b19dcd93SRoman Kagan unsigned int bcdDevice_initial, int bcdDevice_initial_digits, 170b19dcd93SRoman Kagan unsigned char range_lo, unsigned char range_hi, 171afe2dab4SNathaniel McCallum unsigned char max, struct module *mod) 1721da177e4SLinus Torvalds { 173b19dcd93SRoman Kagan char alias[500]; 1746543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, match_flags); 1756543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idVendor); 1766543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idProduct); 1776543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_lo); 1786543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceClass); 1796543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceSubClass); 1806543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceProtocol); 1816543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceClass); 1826543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); 1836543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); 1846543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceNumber); 1856543becfSAndreas Schwab 1861da177e4SLinus Torvalds strcpy(alias, "usb:"); 1876543becfSAndreas Schwab ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, 1886543becfSAndreas Schwab idVendor); 1896543becfSAndreas Schwab ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, 1906543becfSAndreas Schwab idProduct); 191b19dcd93SRoman Kagan 192b19dcd93SRoman Kagan strcat(alias, "d"); 193b19dcd93SRoman Kagan if (bcdDevice_initial_digits) 194b19dcd93SRoman Kagan sprintf(alias + strlen(alias), "%0*X", 195b19dcd93SRoman Kagan bcdDevice_initial_digits, bcdDevice_initial); 196b19dcd93SRoman Kagan if (range_lo == range_hi) 197afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), "%X", range_lo); 198afe2dab4SNathaniel McCallum else if (range_lo > 0 || range_hi < max) { 199afe2dab4SNathaniel McCallum if (range_lo > 0x9 || range_hi < 0xA) 200afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 201afe2dab4SNathaniel McCallum "[%X-%X]", 202afe2dab4SNathaniel McCallum range_lo, 203afe2dab4SNathaniel McCallum range_hi); 204afe2dab4SNathaniel McCallum else { 205afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 206afe2dab4SNathaniel McCallum range_lo < 0x9 ? "[%X-9" : "[%X", 207afe2dab4SNathaniel McCallum range_lo); 208afe2dab4SNathaniel McCallum sprintf(alias + strlen(alias), 20903b56329SJan Moskyto Matejka range_hi > 0xA ? "A-%X]" : "%X]", 21003b56329SJan Moskyto Matejka range_hi); 211afe2dab4SNathaniel McCallum } 212afe2dab4SNathaniel McCallum } 2136543becfSAndreas Schwab if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) 214b19dcd93SRoman Kagan strcat(alias, "*"); 215b19dcd93SRoman Kagan 2166543becfSAndreas Schwab ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, 2176543becfSAndreas Schwab bDeviceClass); 2186543becfSAndreas Schwab ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, 2196543becfSAndreas Schwab bDeviceSubClass); 2206543becfSAndreas Schwab ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, 2216543becfSAndreas Schwab bDeviceProtocol); 2226543becfSAndreas Schwab ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, 2236543becfSAndreas Schwab bInterfaceClass); 2246543becfSAndreas Schwab ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, 2256543becfSAndreas Schwab bInterfaceSubClass); 2266543becfSAndreas Schwab ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, 2276543becfSAndreas Schwab bInterfaceProtocol); 2286543becfSAndreas Schwab ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, 2296543becfSAndreas Schwab bInterfaceNumber); 230b19dcd93SRoman Kagan 231ac551828SJean Delvare add_wildcard(alias); 232b19dcd93SRoman Kagan buf_printf(&mod->dev_table_buf, 233b19dcd93SRoman Kagan "MODULE_ALIAS(\"%s\");\n", alias); 234b19dcd93SRoman Kagan } 235b19dcd93SRoman Kagan 23655f49f26SNathaniel McCallum /* Handles increment/decrement of BCD formatted integers */ 23755f49f26SNathaniel McCallum /* Returns the previous value, so it works like i++ or i-- */ 23855f49f26SNathaniel McCallum static unsigned int incbcd(unsigned int *bcd, 23955f49f26SNathaniel McCallum int inc, 24055f49f26SNathaniel McCallum unsigned char max, 24155f49f26SNathaniel McCallum size_t chars) 24255f49f26SNathaniel McCallum { 24355f49f26SNathaniel McCallum unsigned int init = *bcd, i, j; 24455f49f26SNathaniel McCallum unsigned long long c, dec = 0; 24555f49f26SNathaniel McCallum 24655f49f26SNathaniel McCallum /* If bcd is not in BCD format, just increment */ 24755f49f26SNathaniel McCallum if (max > 0x9) { 24855f49f26SNathaniel McCallum *bcd += inc; 24955f49f26SNathaniel McCallum return init; 25055f49f26SNathaniel McCallum } 25155f49f26SNathaniel McCallum 25255f49f26SNathaniel McCallum /* Convert BCD to Decimal */ 25355f49f26SNathaniel McCallum for (i=0 ; i < chars ; i++) { 25455f49f26SNathaniel McCallum c = (*bcd >> (i << 2)) & 0xf; 25555f49f26SNathaniel McCallum c = c > 9 ? 9 : c; /* force to bcd just in case */ 25655f49f26SNathaniel McCallum for (j=0 ; j < i ; j++) 25755f49f26SNathaniel McCallum c = c * 10; 25855f49f26SNathaniel McCallum dec += c; 25955f49f26SNathaniel McCallum } 26055f49f26SNathaniel McCallum 26155f49f26SNathaniel McCallum /* Do our increment/decrement */ 26255f49f26SNathaniel McCallum dec += inc; 26355f49f26SNathaniel McCallum *bcd = 0; 26455f49f26SNathaniel McCallum 26555f49f26SNathaniel McCallum /* Convert back to BCD */ 26655f49f26SNathaniel McCallum for (i=0 ; i < chars ; i++) { 26755f49f26SNathaniel McCallum for (c=1,j=0 ; j < i ; j++) 26855f49f26SNathaniel McCallum c = c * 10; 26955f49f26SNathaniel McCallum c = (dec / c) % 10; 27055f49f26SNathaniel McCallum *bcd += c << (i << 2); 27155f49f26SNathaniel McCallum } 27255f49f26SNathaniel McCallum return init; 27355f49f26SNathaniel McCallum } 27455f49f26SNathaniel McCallum 2756543becfSAndreas Schwab static void do_usb_entry_multi(void *symval, struct module *mod) 276b19dcd93SRoman Kagan { 277b19dcd93SRoman Kagan unsigned int devlo, devhi; 278afe2dab4SNathaniel McCallum unsigned char chi, clo, max; 279b19dcd93SRoman Kagan int ndigits; 280b19dcd93SRoman Kagan 2816543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, match_flags); 2826543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idVendor); 2836543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, idProduct); 2846543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_lo); 2856543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bcdDevice_hi); 2866543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bDeviceClass); 2876543becfSAndreas Schwab DEF_FIELD(symval, usb_device_id, bInterfaceClass); 288b19dcd93SRoman Kagan 2896543becfSAndreas Schwab devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? 2906543becfSAndreas Schwab bcdDevice_lo : 0x0U; 2916543becfSAndreas Schwab devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? 2926543becfSAndreas Schwab bcdDevice_hi : ~0x0U; 293b19dcd93SRoman Kagan 294afe2dab4SNathaniel McCallum /* Figure out if this entry is in bcd or hex format */ 295afe2dab4SNathaniel McCallum max = 0x9; /* Default to decimal format */ 2966543becfSAndreas Schwab for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) { 297afe2dab4SNathaniel McCallum clo = (devlo >> (ndigits << 2)) & 0xf; 298afe2dab4SNathaniel McCallum chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf; 299afe2dab4SNathaniel McCallum if (clo > max || chi > max) { 300afe2dab4SNathaniel McCallum max = 0xf; 301afe2dab4SNathaniel McCallum break; 302afe2dab4SNathaniel McCallum } 303afe2dab4SNathaniel McCallum } 304afe2dab4SNathaniel McCallum 305b19dcd93SRoman Kagan /* 306b19dcd93SRoman Kagan * Some modules (visor) have empty slots as placeholder for 307b19dcd93SRoman Kagan * run-time specification that results in catch-all alias 308b19dcd93SRoman Kagan */ 3096543becfSAndreas Schwab if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass)) 310b19dcd93SRoman Kagan return; 311b19dcd93SRoman Kagan 312b19dcd93SRoman Kagan /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ 3136543becfSAndreas Schwab for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { 314b19dcd93SRoman Kagan clo = devlo & 0xf; 315b19dcd93SRoman Kagan chi = devhi & 0xf; 316afe2dab4SNathaniel McCallum if (chi > max) /* If we are in bcd mode, truncate if necessary */ 317afe2dab4SNathaniel McCallum chi = max; 318b19dcd93SRoman Kagan devlo >>= 4; 319b19dcd93SRoman Kagan devhi >>= 4; 320b19dcd93SRoman Kagan 321b19dcd93SRoman Kagan if (devlo == devhi || !ndigits) { 3226543becfSAndreas Schwab do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod); 323b19dcd93SRoman Kagan break; 324b19dcd93SRoman Kagan } 325b19dcd93SRoman Kagan 326afe2dab4SNathaniel McCallum if (clo > 0x0) 3276543becfSAndreas Schwab do_usb_entry(symval, 32855f49f26SNathaniel McCallum incbcd(&devlo, 1, max, 3296543becfSAndreas Schwab sizeof(bcdDevice_lo) * 2), 33055f49f26SNathaniel McCallum ndigits, clo, max, max, mod); 331b19dcd93SRoman Kagan 332afe2dab4SNathaniel McCallum if (chi < max) 3336543becfSAndreas Schwab do_usb_entry(symval, 33455f49f26SNathaniel McCallum incbcd(&devhi, -1, max, 3356543becfSAndreas Schwab sizeof(bcdDevice_lo) * 2), 33655f49f26SNathaniel McCallum ndigits, 0x0, chi, max, mod); 337b19dcd93SRoman Kagan } 338b19dcd93SRoman Kagan } 339b19dcd93SRoman Kagan 340b19dcd93SRoman Kagan static void do_usb_table(void *symval, unsigned long size, 341b19dcd93SRoman Kagan struct module *mod) 342b19dcd93SRoman Kagan { 343b19dcd93SRoman Kagan unsigned int i; 3446543becfSAndreas Schwab const unsigned long id_size = SIZE_usb_device_id; 345b19dcd93SRoman Kagan 346e0049825SKees Cook device_id_check(mod->name, "usb", size, id_size, symval); 347fb33d816SSam Ravnborg 348b19dcd93SRoman Kagan /* Leave last one: it's the terminator. */ 349b19dcd93SRoman Kagan size -= id_size; 350b19dcd93SRoman Kagan 351b19dcd93SRoman Kagan for (i = 0; i < size; i += id_size) 352b19dcd93SRoman Kagan do_usb_entry_multi(symval + i, mod); 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 355acbef7b7SPhilipp Zabel static void do_of_entry_multi(void *symval, struct module *mod) 356acbef7b7SPhilipp Zabel { 357acbef7b7SPhilipp Zabel char alias[500]; 358acbef7b7SPhilipp Zabel int len; 359acbef7b7SPhilipp Zabel char *tmp; 360acbef7b7SPhilipp Zabel 361acbef7b7SPhilipp Zabel DEF_FIELD_ADDR(symval, of_device_id, name); 362acbef7b7SPhilipp Zabel DEF_FIELD_ADDR(symval, of_device_id, type); 363acbef7b7SPhilipp Zabel DEF_FIELD_ADDR(symval, of_device_id, compatible); 364acbef7b7SPhilipp Zabel 365acbef7b7SPhilipp Zabel len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", 366acbef7b7SPhilipp Zabel (*type)[0] ? *type : "*"); 367acbef7b7SPhilipp Zabel 368b3c0a4daSWolfram Sang if ((*compatible)[0]) 369acbef7b7SPhilipp Zabel sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", 370acbef7b7SPhilipp Zabel *compatible); 371acbef7b7SPhilipp Zabel 372acbef7b7SPhilipp Zabel /* Replace all whitespace with underscores */ 373acbef7b7SPhilipp Zabel for (tmp = alias; tmp && *tmp; tmp++) 374acbef7b7SPhilipp Zabel if (isspace(*tmp)) 375acbef7b7SPhilipp Zabel *tmp = '_'; 376acbef7b7SPhilipp Zabel 377acbef7b7SPhilipp Zabel buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); 378acbef7b7SPhilipp Zabel strcat(alias, "C"); 379acbef7b7SPhilipp Zabel add_wildcard(alias); 380acbef7b7SPhilipp Zabel buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); 381acbef7b7SPhilipp Zabel } 382acbef7b7SPhilipp Zabel 383acbef7b7SPhilipp Zabel static void do_of_table(void *symval, unsigned long size, 384acbef7b7SPhilipp Zabel struct module *mod) 385acbef7b7SPhilipp Zabel { 386acbef7b7SPhilipp Zabel unsigned int i; 387acbef7b7SPhilipp Zabel const unsigned long id_size = SIZE_of_device_id; 388acbef7b7SPhilipp Zabel 389acbef7b7SPhilipp Zabel device_id_check(mod->name, "of", size, id_size, symval); 390acbef7b7SPhilipp Zabel 391acbef7b7SPhilipp Zabel /* Leave last one: it's the terminator. */ 392acbef7b7SPhilipp Zabel size -= id_size; 393acbef7b7SPhilipp Zabel 394acbef7b7SPhilipp Zabel for (i = 0; i < size; i += id_size) 395acbef7b7SPhilipp Zabel do_of_entry_multi(symval + i, mod); 396acbef7b7SPhilipp Zabel } 397acbef7b7SPhilipp Zabel 398e8c84f9aSJiri Slaby /* Looks like: hid:bNvNpN */ 399e8c84f9aSJiri Slaby static int do_hid_entry(const char *filename, 4006543becfSAndreas Schwab void *symval, char *alias) 401e8c84f9aSJiri Slaby { 4026543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, bus); 4036543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, group); 4046543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, vendor); 4056543becfSAndreas Schwab DEF_FIELD(symval, hid_device_id, product); 406e8c84f9aSJiri Slaby 4077431fb76SHenrik Rydberg sprintf(alias, "hid:"); 4086543becfSAndreas Schwab ADD(alias, "b", bus != HID_BUS_ANY, bus); 4096543becfSAndreas Schwab ADD(alias, "g", group != HID_GROUP_ANY, group); 4106543becfSAndreas Schwab ADD(alias, "v", vendor != HID_ANY_ID, vendor); 4116543becfSAndreas Schwab ADD(alias, "p", product != HID_ANY_ID, product); 412e8c84f9aSJiri Slaby 413e8c84f9aSJiri Slaby return 1; 414e8c84f9aSJiri Slaby } 415e8c84f9aSJiri Slaby 4161da177e4SLinus Torvalds /* Looks like: ieee1394:venNmoNspNverN */ 4171da177e4SLinus Torvalds static int do_ieee1394_entry(const char *filename, 4186543becfSAndreas Schwab void *symval, char *alias) 4191da177e4SLinus Torvalds { 4206543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, match_flags); 4216543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, vendor_id); 4226543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, model_id); 4236543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, specifier_id); 4246543becfSAndreas Schwab DEF_FIELD(symval, ieee1394_device_id, version); 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds strcpy(alias, "ieee1394:"); 4276543becfSAndreas Schwab ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, 4286543becfSAndreas Schwab vendor_id); 4296543becfSAndreas Schwab ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, 4306543becfSAndreas Schwab model_id); 4316543becfSAndreas Schwab ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, 4326543becfSAndreas Schwab specifier_id); 4336543becfSAndreas Schwab ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, 4346543becfSAndreas Schwab version); 4351da177e4SLinus Torvalds 436ac551828SJean Delvare add_wildcard(alias); 4371da177e4SLinus Torvalds return 1; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 440cc6711b0SMax Gurtovoy /* Looks like: pci:vNdNsvNsdNbcNscNiN or <prefix>_pci:vNdNsvNsdNbcNscNiN. */ 4411da177e4SLinus Torvalds static int do_pci_entry(const char *filename, 4426543becfSAndreas Schwab void *symval, char *alias) 4431da177e4SLinus Torvalds { 4441da177e4SLinus Torvalds /* Class field can be divided into these three. */ 4451da177e4SLinus Torvalds unsigned char baseclass, subclass, interface, 4461da177e4SLinus Torvalds baseclass_mask, subclass_mask, interface_mask; 4471da177e4SLinus Torvalds 4486543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, vendor); 4496543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, device); 4506543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, subvendor); 4516543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, subdevice); 4526543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, class); 4536543becfSAndreas Schwab DEF_FIELD(symval, pci_device_id, class_mask); 454cc6711b0SMax Gurtovoy DEF_FIELD(symval, pci_device_id, override_only); 4551da177e4SLinus Torvalds 456cc6711b0SMax Gurtovoy switch (override_only) { 457cc6711b0SMax Gurtovoy case 0: 4581da177e4SLinus Torvalds strcpy(alias, "pci:"); 459cc6711b0SMax Gurtovoy break; 460cc6711b0SMax Gurtovoy case PCI_ID_F_VFIO_DRIVER_OVERRIDE: 461cc6711b0SMax Gurtovoy strcpy(alias, "vfio_pci:"); 462cc6711b0SMax Gurtovoy break; 463cc6711b0SMax Gurtovoy default: 464cc6711b0SMax Gurtovoy warn("Unknown PCI driver_override alias %08X\n", 465cc6711b0SMax Gurtovoy override_only); 466cc6711b0SMax Gurtovoy return 0; 467cc6711b0SMax Gurtovoy } 468cc6711b0SMax Gurtovoy 4696543becfSAndreas Schwab ADD(alias, "v", vendor != PCI_ANY_ID, vendor); 4706543becfSAndreas Schwab ADD(alias, "d", device != PCI_ANY_ID, device); 4716543becfSAndreas Schwab ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); 4726543becfSAndreas Schwab ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); 4731da177e4SLinus Torvalds 4746543becfSAndreas Schwab baseclass = (class) >> 16; 4756543becfSAndreas Schwab baseclass_mask = (class_mask) >> 16; 4766543becfSAndreas Schwab subclass = (class) >> 8; 4776543becfSAndreas Schwab subclass_mask = (class_mask) >> 8; 4786543becfSAndreas Schwab interface = class; 4796543becfSAndreas Schwab interface_mask = class_mask; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if ((baseclass_mask != 0 && baseclass_mask != 0xFF) 4821da177e4SLinus Torvalds || (subclass_mask != 0 && subclass_mask != 0xFF) 4831da177e4SLinus Torvalds || (interface_mask != 0 && interface_mask != 0xFF)) { 484cb80514dSSam Ravnborg warn("Can't handle masks in %s:%04X\n", 4856543becfSAndreas Schwab filename, class_mask); 4861da177e4SLinus Torvalds return 0; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); 4901da177e4SLinus Torvalds ADD(alias, "sc", subclass_mask == 0xFF, subclass); 4911da177e4SLinus Torvalds ADD(alias, "i", interface_mask == 0xFF, interface); 492ac551828SJean Delvare add_wildcard(alias); 4931da177e4SLinus Torvalds return 1; 4941da177e4SLinus Torvalds } 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds /* looks like: "ccw:tNmNdtNdmN" */ 4971da177e4SLinus Torvalds static int do_ccw_entry(const char *filename, 4986543becfSAndreas Schwab void *symval, char *alias) 4991da177e4SLinus Torvalds { 5006543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, match_flags); 5016543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, cu_type); 5026543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, cu_model); 5036543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, dev_type); 5046543becfSAndreas Schwab DEF_FIELD(symval, ccw_device_id, dev_model); 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds strcpy(alias, "ccw:"); 5076543becfSAndreas Schwab ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, 5086543becfSAndreas Schwab cu_type); 5096543becfSAndreas Schwab ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, 5106543becfSAndreas Schwab cu_model); 5116543becfSAndreas Schwab ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, 5126543becfSAndreas Schwab dev_type); 5136543becfSAndreas Schwab ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, 5146543becfSAndreas Schwab dev_model); 515ac551828SJean Delvare add_wildcard(alias); 5161da177e4SLinus Torvalds return 1; 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds 5191534c382SMartin Schwidefsky /* looks like: "ap:tN" */ 5201534c382SMartin Schwidefsky static int do_ap_entry(const char *filename, 5216543becfSAndreas Schwab void *symval, char *alias) 5221534c382SMartin Schwidefsky { 5236543becfSAndreas Schwab DEF_FIELD(symval, ap_device_id, dev_type); 5246543becfSAndreas Schwab 5256543becfSAndreas Schwab sprintf(alias, "ap:t%02X*", dev_type); 5261534c382SMartin Schwidefsky return 1; 5271534c382SMartin Schwidefsky } 5281534c382SMartin Schwidefsky 5297e9db9eaSCornelia Huck /* looks like: "css:tN" */ 5307e9db9eaSCornelia Huck static int do_css_entry(const char *filename, 5316543becfSAndreas Schwab void *symval, char *alias) 5327e9db9eaSCornelia Huck { 5336543becfSAndreas Schwab DEF_FIELD(symval, css_device_id, type); 5346543becfSAndreas Schwab 5356543becfSAndreas Schwab sprintf(alias, "css:t%01X", type); 5367e9db9eaSCornelia Huck return 1; 5377e9db9eaSCornelia Huck } 5387e9db9eaSCornelia Huck 5391da177e4SLinus Torvalds /* Looks like: "serio:tyNprNidNexN" */ 5401da177e4SLinus Torvalds static int do_serio_entry(const char *filename, 5416543becfSAndreas Schwab void *symval, char *alias) 5421da177e4SLinus Torvalds { 5436543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, type); 5446543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, proto); 5456543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, id); 5466543becfSAndreas Schwab DEF_FIELD(symval, serio_device_id, extra); 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds strcpy(alias, "serio:"); 5496543becfSAndreas Schwab ADD(alias, "ty", type != SERIO_ANY, type); 5506543becfSAndreas Schwab ADD(alias, "pr", proto != SERIO_ANY, proto); 5516543becfSAndreas Schwab ADD(alias, "id", id != SERIO_ANY, id); 5526543becfSAndreas Schwab ADD(alias, "ex", extra != SERIO_ANY, extra); 5531da177e4SLinus Torvalds 554ac551828SJean Delvare add_wildcard(alias); 5551da177e4SLinus Torvalds return 1; 5561da177e4SLinus Torvalds } 5571da177e4SLinus Torvalds 55826095a01SSuthikulpanit, Suravee /* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or 55926095a01SSuthikulpanit, Suravee * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) 56026095a01SSuthikulpanit, Suravee * 56126095a01SSuthikulpanit, Suravee * NOTE: Each driver should use one of the following : _HID, _CIDs 56226095a01SSuthikulpanit, Suravee * or _CLS. Also, bb, ss, and pp can be substituted with ?? 56326095a01SSuthikulpanit, Suravee * as don't care byte. 56426095a01SSuthikulpanit, Suravee */ 56529b71a1cSThomas Renninger static int do_acpi_entry(const char *filename, 5666543becfSAndreas Schwab void *symval, char *alias) 56729b71a1cSThomas Renninger { 5686543becfSAndreas Schwab DEF_FIELD_ADDR(symval, acpi_device_id, id); 56926095a01SSuthikulpanit, Suravee DEF_FIELD_ADDR(symval, acpi_device_id, cls); 57026095a01SSuthikulpanit, Suravee DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk); 57126095a01SSuthikulpanit, Suravee 57226095a01SSuthikulpanit, Suravee if (id && strlen((const char *)*id)) 5736543becfSAndreas Schwab sprintf(alias, "acpi*:%s:*", *id); 57426095a01SSuthikulpanit, Suravee else if (cls) { 57526095a01SSuthikulpanit, Suravee int i, byte_shift, cnt = 0; 57626095a01SSuthikulpanit, Suravee unsigned int msk; 57726095a01SSuthikulpanit, Suravee 57826095a01SSuthikulpanit, Suravee sprintf(&alias[cnt], "acpi*:"); 57926095a01SSuthikulpanit, Suravee cnt = 6; 58026095a01SSuthikulpanit, Suravee for (i = 1; i <= 3; i++) { 58126095a01SSuthikulpanit, Suravee byte_shift = 8 * (3-i); 58226095a01SSuthikulpanit, Suravee msk = (*cls_msk >> byte_shift) & 0xFF; 58326095a01SSuthikulpanit, Suravee if (msk) 58426095a01SSuthikulpanit, Suravee sprintf(&alias[cnt], "%02x", 58526095a01SSuthikulpanit, Suravee (*cls >> byte_shift) & 0xFF); 58626095a01SSuthikulpanit, Suravee else 58726095a01SSuthikulpanit, Suravee sprintf(&alias[cnt], "??"); 58826095a01SSuthikulpanit, Suravee cnt += 2; 58926095a01SSuthikulpanit, Suravee } 59026095a01SSuthikulpanit, Suravee sprintf(&alias[cnt], ":*"); 59126095a01SSuthikulpanit, Suravee } 59229b71a1cSThomas Renninger return 1; 59329b71a1cSThomas Renninger } 59429b71a1cSThomas Renninger 5951da177e4SLinus Torvalds /* looks like: "pnp:dD" */ 59622454cb9SKay Sievers static void do_pnp_device_entry(void *symval, unsigned long size, 59722454cb9SKay Sievers struct module *mod) 5981da177e4SLinus Torvalds { 5996543becfSAndreas Schwab const unsigned long id_size = SIZE_pnp_device_id; 6005e4c6564SKay Sievers const unsigned int count = (size / id_size)-1; 6015e4c6564SKay Sievers unsigned int i; 60222454cb9SKay Sievers 60322454cb9SKay Sievers device_id_check(mod->name, "pnp", size, id_size, symval); 60422454cb9SKay Sievers 6055e4c6564SKay Sievers for (i = 0; i < count; i++) { 6066543becfSAndreas Schwab DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); 6076543becfSAndreas Schwab char acpi_id[sizeof(*id)]; 60872638f59SKay Sievers int j; 6095e4c6564SKay Sievers 61022454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 6116543becfSAndreas Schwab "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); 61272638f59SKay Sievers 61372638f59SKay Sievers /* fix broken pnp bus lowercasing */ 61472638f59SKay Sievers for (j = 0; j < sizeof(acpi_id); j++) 6156543becfSAndreas Schwab acpi_id[j] = toupper((*id)[j]); 61622454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 61772638f59SKay Sievers "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); 6185e4c6564SKay Sievers } 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds 6210c81eed4SKay Sievers /* looks like: "pnp:dD" for every device of the card */ 6220c81eed4SKay Sievers static void do_pnp_card_entries(void *symval, unsigned long size, 6230c81eed4SKay Sievers struct module *mod) 6241da177e4SLinus Torvalds { 6256543becfSAndreas Schwab const unsigned long id_size = SIZE_pnp_card_device_id; 6260c81eed4SKay Sievers const unsigned int count = (size / id_size)-1; 6270c81eed4SKay Sievers unsigned int i; 6281da177e4SLinus Torvalds 6290c81eed4SKay Sievers device_id_check(mod->name, "pnp", size, id_size, symval); 6300c81eed4SKay Sievers 6310c81eed4SKay Sievers for (i = 0; i < count; i++) { 6320c81eed4SKay Sievers unsigned int j; 6336543becfSAndreas Schwab DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs); 6340c81eed4SKay Sievers 6350c81eed4SKay Sievers for (j = 0; j < PNP_MAX_DEVICES; j++) { 6366543becfSAndreas Schwab const char *id = (char *)(*devs)[j].id; 6370c81eed4SKay Sievers int i2, j2; 6380c81eed4SKay Sievers int dup = 0; 6390c81eed4SKay Sievers 6400c81eed4SKay Sievers if (!id[0]) 6411da177e4SLinus Torvalds break; 6420c81eed4SKay Sievers 6430c81eed4SKay Sievers /* find duplicate, already added value */ 6440c81eed4SKay Sievers for (i2 = 0; i2 < i && !dup; i2++) { 645c2b1a922SLeonardo Bras DEF_FIELD_ADDR_VAR(symval + i2 * id_size, 646c2b1a922SLeonardo Bras pnp_card_device_id, 647c2b1a922SLeonardo Bras devs, devs_dup); 6480c81eed4SKay Sievers 6490c81eed4SKay Sievers for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { 650c2b1a922SLeonardo Bras const char *id2 = 651c2b1a922SLeonardo Bras (char *)(*devs_dup)[j2].id; 6520c81eed4SKay Sievers 6530c81eed4SKay Sievers if (!id2[0]) 6540c81eed4SKay Sievers break; 6550c81eed4SKay Sievers 6560c81eed4SKay Sievers if (!strcmp(id, id2)) { 6570c81eed4SKay Sievers dup = 1; 6580c81eed4SKay Sievers break; 6591da177e4SLinus Torvalds } 6600c81eed4SKay Sievers } 6610c81eed4SKay Sievers } 6620c81eed4SKay Sievers 6630c81eed4SKay Sievers /* add an individual alias for every device entry */ 66422454cb9SKay Sievers if (!dup) { 6656543becfSAndreas Schwab char acpi_id[PNP_ID_LEN]; 66672638f59SKay Sievers int k; 66772638f59SKay Sievers 6680c81eed4SKay Sievers buf_printf(&mod->dev_table_buf, 6690c81eed4SKay Sievers "MODULE_ALIAS(\"pnp:d%s*\");\n", id); 67072638f59SKay Sievers 67172638f59SKay Sievers /* fix broken pnp bus lowercasing */ 67272638f59SKay Sievers for (k = 0; k < sizeof(acpi_id); k++) 67372638f59SKay Sievers acpi_id[k] = toupper(id[k]); 67422454cb9SKay Sievers buf_printf(&mod->dev_table_buf, 67572638f59SKay Sievers "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); 67622454cb9SKay Sievers } 6770c81eed4SKay Sievers } 6780c81eed4SKay Sievers } 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 68190829cfeSDominik Brodowski /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ 68290829cfeSDominik Brodowski static int do_pcmcia_entry(const char *filename, 6836543becfSAndreas Schwab void *symval, char *alias) 68490829cfeSDominik Brodowski { 68590829cfeSDominik Brodowski unsigned int i; 6866543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, match_flags); 6876543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, manf_id); 6886543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, card_id); 6896543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, func_id); 6906543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, function); 6916543becfSAndreas Schwab DEF_FIELD(symval, pcmcia_device_id, device_no); 6926543becfSAndreas Schwab DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash); 6934fb7edceSKars de Jong 69490829cfeSDominik Brodowski for (i=0; i<4; i++) { 6956543becfSAndreas Schwab (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); 69690829cfeSDominik Brodowski } 69790829cfeSDominik Brodowski 69890829cfeSDominik Brodowski strcpy(alias, "pcmcia:"); 6996543becfSAndreas Schwab ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, 7006543becfSAndreas Schwab manf_id); 7016543becfSAndreas Schwab ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, 7026543becfSAndreas Schwab card_id); 7036543becfSAndreas Schwab ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, 7046543becfSAndreas Schwab func_id); 7056543becfSAndreas Schwab ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, 7066543becfSAndreas Schwab function); 7076543becfSAndreas Schwab ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, 7086543becfSAndreas Schwab device_no); 7096543becfSAndreas Schwab ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]); 7106543becfSAndreas Schwab ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]); 7116543becfSAndreas Schwab ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); 7126543becfSAndreas Schwab ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]); 71390829cfeSDominik Brodowski 714ac551828SJean Delvare add_wildcard(alias); 71590829cfeSDominik Brodowski return 1; 71690829cfeSDominik Brodowski } 71790829cfeSDominik Brodowski 7186543becfSAndreas Schwab static int do_vio_entry(const char *filename, void *symval, 719fb120da6SStephen Rothwell char *alias) 720fb120da6SStephen Rothwell { 721fb120da6SStephen Rothwell char *tmp; 7226543becfSAndreas Schwab DEF_FIELD_ADDR(symval, vio_device_id, type); 7236543becfSAndreas Schwab DEF_FIELD_ADDR(symval, vio_device_id, compat); 724fb120da6SStephen Rothwell 7256543becfSAndreas Schwab sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", 7266543becfSAndreas Schwab (*compat)[0] ? *compat : "*"); 727fb120da6SStephen Rothwell 728fb120da6SStephen Rothwell /* Replace all whitespace with underscores */ 729fb120da6SStephen Rothwell for (tmp = alias; tmp && *tmp; tmp++) 730fb120da6SStephen Rothwell if (isspace (*tmp)) 731fb120da6SStephen Rothwell *tmp = '_'; 732fb120da6SStephen Rothwell 733ac551828SJean Delvare add_wildcard(alias); 734fb120da6SStephen Rothwell return 1; 735fb120da6SStephen Rothwell } 736fb120da6SStephen Rothwell 7371d8f430cSRusty Russell #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 7381d8f430cSRusty Russell 7391d8f430cSRusty Russell static void do_input(char *alias, 7401d8f430cSRusty Russell kernel_ulong_t *arr, unsigned int min, unsigned int max) 7411d8f430cSRusty Russell { 7421d8f430cSRusty Russell unsigned int i; 743ddc5d341SDmitry Torokhov 7446543becfSAndreas Schwab for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) 7456543becfSAndreas Schwab arr[i] = TO_NATIVE(arr[i]); 746ddc5d341SDmitry Torokhov for (i = min; i < max; i++) 747e0e92632SHans de Goede if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) 7481d8f430cSRusty Russell sprintf(alias + strlen(alias), "%X,*", i); 7491d8f430cSRusty Russell } 7501d8f430cSRusty Russell 75109c3e01bSDmitry Torokhov /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ 7526543becfSAndreas Schwab static int do_input_entry(const char *filename, void *symval, 7531d8f430cSRusty Russell char *alias) 7541d8f430cSRusty Russell { 7556543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, flags); 7566543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, bustype); 7576543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, vendor); 7586543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, product); 7596543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, version); 7606543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, evbit); 7616543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, keybit); 7626543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, relbit); 7636543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, absbit); 7646543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, mscbit); 7656543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ledbit); 7666543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, sndbit); 7676543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ffbit); 7686543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, swbit); 7696543becfSAndreas Schwab 7701d8f430cSRusty Russell sprintf(alias, "input:"); 7711d8f430cSRusty Russell 7726543becfSAndreas Schwab ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); 7736543becfSAndreas Schwab ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); 7746543becfSAndreas Schwab ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); 7756543becfSAndreas Schwab ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); 7761d8f430cSRusty Russell 7771d8f430cSRusty Russell sprintf(alias + strlen(alias), "-e*"); 7786543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) 7796543becfSAndreas Schwab do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); 7801d8f430cSRusty Russell sprintf(alias + strlen(alias), "k*"); 7816543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) 7826543becfSAndreas Schwab do_input(alias, *keybit, 783dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MIN_INTERESTING, 784dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MAX); 7851d8f430cSRusty Russell sprintf(alias + strlen(alias), "r*"); 7866543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) 7876543becfSAndreas Schwab do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); 7881d8f430cSRusty Russell sprintf(alias + strlen(alias), "a*"); 7896543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) 7906543becfSAndreas Schwab do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); 7911d8f430cSRusty Russell sprintf(alias + strlen(alias), "m*"); 7926543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) 7936543becfSAndreas Schwab do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); 7941d8f430cSRusty Russell sprintf(alias + strlen(alias), "l*"); 7956543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) 7966543becfSAndreas Schwab do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); 7971d8f430cSRusty Russell sprintf(alias + strlen(alias), "s*"); 7986543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) 7996543becfSAndreas Schwab do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); 8001d8f430cSRusty Russell sprintf(alias + strlen(alias), "f*"); 8016543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) 8026543becfSAndreas Schwab do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); 8031d8f430cSRusty Russell sprintf(alias + strlen(alias), "w*"); 8046543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) 8056543becfSAndreas Schwab do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); 8061d8f430cSRusty Russell return 1; 8071d8f430cSRusty Russell } 8081d8f430cSRusty Russell 8096543becfSAndreas Schwab static int do_eisa_entry(const char *filename, void *symval, 81007563c71SMichael Tokarev char *alias) 81107563c71SMichael Tokarev { 8126543becfSAndreas Schwab DEF_FIELD_ADDR(symval, eisa_device_id, sig); 8136543becfSAndreas Schwab if (sig[0]) 8146543becfSAndreas Schwab sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); 815ac551828SJean Delvare else 816ac551828SJean Delvare strcat(alias, "*"); 81707563c71SMichael Tokarev return 1; 81807563c71SMichael Tokarev } 81907563c71SMichael Tokarev 820f3cf2673SKyle McMartin /* Looks like: parisc:tNhvNrevNsvN */ 8216543becfSAndreas Schwab static int do_parisc_entry(const char *filename, void *symval, 822f3cf2673SKyle McMartin char *alias) 823f3cf2673SKyle McMartin { 8246543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hw_type); 8256543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion); 8266543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion_rev); 8276543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, sversion); 828f3cf2673SKyle McMartin 829f3cf2673SKyle McMartin strcpy(alias, "parisc:"); 8306543becfSAndreas Schwab ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); 8316543becfSAndreas Schwab ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); 8326543becfSAndreas Schwab ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); 8336543becfSAndreas Schwab ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); 834f3cf2673SKyle McMartin 835ac551828SJean Delvare add_wildcard(alias); 836f3cf2673SKyle McMartin return 1; 837f3cf2673SKyle McMartin } 838f3cf2673SKyle McMartin 839d59b66c7SPierre Ossman /* Looks like: sdio:cNvNdN. */ 840d59b66c7SPierre Ossman static int do_sdio_entry(const char *filename, 8416543becfSAndreas Schwab void *symval, char *alias) 842d59b66c7SPierre Ossman { 8436543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, class); 8446543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, vendor); 8456543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, device); 846d59b66c7SPierre Ossman 847d59b66c7SPierre Ossman strcpy(alias, "sdio:"); 8486543becfSAndreas Schwab ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); 8496543becfSAndreas Schwab ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); 8506543becfSAndreas Schwab ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); 851ac551828SJean Delvare add_wildcard(alias); 852038a5008SLinus Torvalds return 1; 853038a5008SLinus Torvalds } 854d59b66c7SPierre Ossman 85561e115a5SMichael Buesch /* Looks like: ssb:vNidNrevN. */ 85661e115a5SMichael Buesch static int do_ssb_entry(const char *filename, 8576543becfSAndreas Schwab void *symval, char *alias) 85861e115a5SMichael Buesch { 8596543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, vendor); 8606543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, coreid); 8616543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, revision); 86261e115a5SMichael Buesch 86361e115a5SMichael Buesch strcpy(alias, "ssb:"); 8646543becfSAndreas Schwab ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); 8656543becfSAndreas Schwab ADD(alias, "id", coreid != SSB_ANY_ID, coreid); 8666543becfSAndreas Schwab ADD(alias, "rev", revision != SSB_ANY_REV, revision); 867ac551828SJean Delvare add_wildcard(alias); 868d59b66c7SPierre Ossman return 1; 869d59b66c7SPierre Ossman } 870d59b66c7SPierre Ossman 8718369ae33SRafał Miłecki /* Looks like: bcma:mNidNrevNclN. */ 8728369ae33SRafał Miłecki static int do_bcma_entry(const char *filename, 8736543becfSAndreas Schwab void *symval, char *alias) 8748369ae33SRafał Miłecki { 8756543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, manuf); 8766543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, id); 8776543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, rev); 8786543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, class); 8798369ae33SRafał Miłecki 8808369ae33SRafał Miłecki strcpy(alias, "bcma:"); 8816543becfSAndreas Schwab ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); 8826543becfSAndreas Schwab ADD(alias, "id", id != BCMA_ANY_ID, id); 8836543becfSAndreas Schwab ADD(alias, "rev", rev != BCMA_ANY_REV, rev); 8846543becfSAndreas Schwab ADD(alias, "cl", class != BCMA_ANY_CLASS, class); 8858369ae33SRafał Miłecki add_wildcard(alias); 8868369ae33SRafał Miłecki return 1; 8878369ae33SRafał Miłecki } 8888369ae33SRafał Miłecki 889b01d9f28SRusty Russell /* Looks like: virtio:dNvN */ 8906543becfSAndreas Schwab static int do_virtio_entry(const char *filename, void *symval, 891b01d9f28SRusty Russell char *alias) 892b01d9f28SRusty Russell { 8936543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, device); 8946543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, vendor); 895b01d9f28SRusty Russell 896b01d9f28SRusty Russell strcpy(alias, "virtio:"); 8976543becfSAndreas Schwab ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); 8986543becfSAndreas Schwab ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); 899b01d9f28SRusty Russell 900ac551828SJean Delvare add_wildcard(alias); 901b01d9f28SRusty Russell return 1; 902b01d9f28SRusty Russell } 903b01d9f28SRusty Russell 904d2ee52aaSK. Y. Srinivasan /* 905d2ee52aaSK. Y. Srinivasan * Looks like: vmbus:guid 906d2ee52aaSK. Y. Srinivasan * Each byte of the guid will be represented by two hex characters 907d2ee52aaSK. Y. Srinivasan * in the name. 908d2ee52aaSK. Y. Srinivasan */ 909d2ee52aaSK. Y. Srinivasan 9106543becfSAndreas Schwab static int do_vmbus_entry(const char *filename, void *symval, 911d2ee52aaSK. Y. Srinivasan char *alias) 912d2ee52aaSK. Y. Srinivasan { 913d2ee52aaSK. Y. Srinivasan int i; 9146543becfSAndreas Schwab DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); 9156543becfSAndreas Schwab char guid_name[(sizeof(*guid) + 1) * 2]; 916d2ee52aaSK. Y. Srinivasan 9176543becfSAndreas Schwab for (i = 0; i < (sizeof(*guid) * 2); i += 2) 918af3ff643SK. Y. Srinivasan sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); 919d2ee52aaSK. Y. Srinivasan 920d2ee52aaSK. Y. Srinivasan strcpy(alias, "vmbus:"); 921d2ee52aaSK. Y. Srinivasan strcat(alias, guid_name); 922d2ee52aaSK. Y. Srinivasan 923d2ee52aaSK. Y. Srinivasan return 1; 924d2ee52aaSK. Y. Srinivasan } 925d2ee52aaSK. Y. Srinivasan 9265b7d1277SAndrew F. Davis /* Looks like: rpmsg:S */ 9275b7d1277SAndrew F. Davis static int do_rpmsg_entry(const char *filename, void *symval, 9285b7d1277SAndrew F. Davis char *alias) 9295b7d1277SAndrew F. Davis { 9305b7d1277SAndrew F. Davis DEF_FIELD_ADDR(symval, rpmsg_device_id, name); 9315b7d1277SAndrew F. Davis sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name); 9325b7d1277SAndrew F. Davis 9335b7d1277SAndrew F. Davis return 1; 9345b7d1277SAndrew F. Davis } 9355b7d1277SAndrew F. Davis 936d2653e92SJean Delvare /* Looks like: i2c:S */ 9376543becfSAndreas Schwab static int do_i2c_entry(const char *filename, void *symval, 938d2653e92SJean Delvare char *alias) 939d2653e92SJean Delvare { 9406543becfSAndreas Schwab DEF_FIELD_ADDR(symval, i2c_device_id, name); 9416543becfSAndreas Schwab sprintf(alias, I2C_MODULE_PREFIX "%s", *name); 942d2653e92SJean Delvare 943d2653e92SJean Delvare return 1; 944d2653e92SJean Delvare } 945d2653e92SJean Delvare 9461ce589adSBoris Brezillon static int do_i3c_entry(const char *filename, void *symval, 9471ce589adSBoris Brezillon char *alias) 9481ce589adSBoris Brezillon { 9491ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, match_flags); 9501ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, dcr); 9511ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, manuf_id); 9521ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, part_id); 9531ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, extra_info); 9541ce589adSBoris Brezillon 9551ce589adSBoris Brezillon strcpy(alias, "i3c:"); 9561ce589adSBoris Brezillon ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr); 9571ce589adSBoris Brezillon ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id); 9581ce589adSBoris Brezillon ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id); 9591ce589adSBoris Brezillon ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info); 9601ce589adSBoris Brezillon 9611ce589adSBoris Brezillon return 1; 9621ce589adSBoris Brezillon } 9631ce589adSBoris Brezillon 964e0626e38SAnton Vorontsov /* Looks like: spi:S */ 9656543becfSAndreas Schwab static int do_spi_entry(const char *filename, void *symval, 96675368bf6SAnton Vorontsov char *alias) 96775368bf6SAnton Vorontsov { 9686543becfSAndreas Schwab DEF_FIELD_ADDR(symval, spi_device_id, name); 9696543becfSAndreas Schwab sprintf(alias, SPI_MODULE_PREFIX "%s", *name); 97075368bf6SAnton Vorontsov 97175368bf6SAnton Vorontsov return 1; 97275368bf6SAnton Vorontsov } 97375368bf6SAnton Vorontsov 974d945b697SDavid Woodhouse static const struct dmifield { 975d945b697SDavid Woodhouse const char *prefix; 976d945b697SDavid Woodhouse int field; 977d945b697SDavid Woodhouse } dmi_fields[] = { 978d945b697SDavid Woodhouse { "bvn", DMI_BIOS_VENDOR }, 979d945b697SDavid Woodhouse { "bvr", DMI_BIOS_VERSION }, 980d945b697SDavid Woodhouse { "bd", DMI_BIOS_DATE }, 981f5152f4dSErwan Velu { "br", DMI_BIOS_RELEASE }, 982f5152f4dSErwan Velu { "efr", DMI_EC_FIRMWARE_RELEASE }, 983d945b697SDavid Woodhouse { "svn", DMI_SYS_VENDOR }, 984d945b697SDavid Woodhouse { "pn", DMI_PRODUCT_NAME }, 985d945b697SDavid Woodhouse { "pvr", DMI_PRODUCT_VERSION }, 986d945b697SDavid Woodhouse { "rvn", DMI_BOARD_VENDOR }, 987d945b697SDavid Woodhouse { "rn", DMI_BOARD_NAME }, 988d945b697SDavid Woodhouse { "rvr", DMI_BOARD_VERSION }, 989d945b697SDavid Woodhouse { "cvn", DMI_CHASSIS_VENDOR }, 990d945b697SDavid Woodhouse { "ct", DMI_CHASSIS_TYPE }, 991d945b697SDavid Woodhouse { "cvr", DMI_CHASSIS_VERSION }, 992d945b697SDavid Woodhouse { NULL, DMI_NONE } 993d945b697SDavid Woodhouse }; 994d945b697SDavid Woodhouse 995d945b697SDavid Woodhouse static void dmi_ascii_filter(char *d, const char *s) 996d945b697SDavid Woodhouse { 997d945b697SDavid Woodhouse /* Filter out characters we don't want to see in the modalias string */ 998d945b697SDavid Woodhouse for (; *s; s++) 999d945b697SDavid Woodhouse if (*s > ' ' && *s < 127 && *s != ':') 1000d945b697SDavid Woodhouse *(d++) = *s; 1001d945b697SDavid Woodhouse 1002d945b697SDavid Woodhouse *d = 0; 1003d945b697SDavid Woodhouse } 1004d945b697SDavid Woodhouse 1005d945b697SDavid Woodhouse 10066543becfSAndreas Schwab static int do_dmi_entry(const char *filename, void *symval, 1007d945b697SDavid Woodhouse char *alias) 1008d945b697SDavid Woodhouse { 1009d945b697SDavid Woodhouse int i, j; 10106543becfSAndreas Schwab DEF_FIELD_ADDR(symval, dmi_system_id, matches); 1011d945b697SDavid Woodhouse sprintf(alias, "dmi*"); 1012d945b697SDavid Woodhouse 1013d945b697SDavid Woodhouse for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { 1014d945b697SDavid Woodhouse for (j = 0; j < 4; j++) { 10156543becfSAndreas Schwab if ((*matches)[j].slot && 10166543becfSAndreas Schwab (*matches)[j].slot == dmi_fields[i].field) { 1017d945b697SDavid Woodhouse sprintf(alias + strlen(alias), ":%s*", 1018d945b697SDavid Woodhouse dmi_fields[i].prefix); 1019d945b697SDavid Woodhouse dmi_ascii_filter(alias + strlen(alias), 10206543becfSAndreas Schwab (*matches)[j].substr); 1021d945b697SDavid Woodhouse strcat(alias, "*"); 1022d945b697SDavid Woodhouse } 1023d945b697SDavid Woodhouse } 1024d945b697SDavid Woodhouse } 1025d945b697SDavid Woodhouse 1026d945b697SDavid Woodhouse strcat(alias, ":"); 1027d945b697SDavid Woodhouse return 1; 1028d945b697SDavid Woodhouse } 102957fee4a5SEric Miao 103057fee4a5SEric Miao static int do_platform_entry(const char *filename, 10316543becfSAndreas Schwab void *symval, char *alias) 103257fee4a5SEric Miao { 10336543becfSAndreas Schwab DEF_FIELD_ADDR(symval, platform_device_id, name); 10346543becfSAndreas Schwab sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); 103557fee4a5SEric Miao return 1; 103657fee4a5SEric Miao } 103757fee4a5SEric Miao 10388626d3b4SDavid Woodhouse static int do_mdio_entry(const char *filename, 10396543becfSAndreas Schwab void *symval, char *alias) 10408626d3b4SDavid Woodhouse { 10418626d3b4SDavid Woodhouse int i; 10426543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id); 10436543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id_mask); 10448626d3b4SDavid Woodhouse 10458626d3b4SDavid Woodhouse alias += sprintf(alias, MDIO_MODULE_PREFIX); 10468626d3b4SDavid Woodhouse 10478626d3b4SDavid Woodhouse for (i = 0; i < 32; i++) { 10486543becfSAndreas Schwab if (!((phy_id_mask >> (31-i)) & 1)) 10498626d3b4SDavid Woodhouse *(alias++) = '?'; 10506543becfSAndreas Schwab else if ((phy_id >> (31-i)) & 1) 10518626d3b4SDavid Woodhouse *(alias++) = '1'; 10528626d3b4SDavid Woodhouse else 10538626d3b4SDavid Woodhouse *(alias++) = '0'; 10548626d3b4SDavid Woodhouse } 10558626d3b4SDavid Woodhouse 10568626d3b4SDavid Woodhouse /* Terminate the string */ 10578626d3b4SDavid Woodhouse *alias = 0; 10588626d3b4SDavid Woodhouse 10598626d3b4SDavid Woodhouse return 1; 10608626d3b4SDavid Woodhouse } 10618626d3b4SDavid Woodhouse 1062bf54a2b3SGeert Uytterhoeven /* Looks like: zorro:iN. */ 10636543becfSAndreas Schwab static int do_zorro_entry(const char *filename, void *symval, 1064bf54a2b3SGeert Uytterhoeven char *alias) 1065bf54a2b3SGeert Uytterhoeven { 10666543becfSAndreas Schwab DEF_FIELD(symval, zorro_device_id, id); 1067bf54a2b3SGeert Uytterhoeven strcpy(alias, "zorro:"); 10686543becfSAndreas Schwab ADD(alias, "i", id != ZORRO_WILDCARD, id); 1069bf54a2b3SGeert Uytterhoeven return 1; 1070bf54a2b3SGeert Uytterhoeven } 1071bf54a2b3SGeert Uytterhoeven 1072fedb3d27SOndrej Zary /* looks like: "pnp:dD" */ 1073fedb3d27SOndrej Zary static int do_isapnp_entry(const char *filename, 10746543becfSAndreas Schwab void *symval, char *alias) 1075fedb3d27SOndrej Zary { 10766543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, vendor); 10776543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, function); 1078fedb3d27SOndrej Zary sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", 10796543becfSAndreas Schwab 'A' + ((vendor >> 2) & 0x3f) - 1, 10806543becfSAndreas Schwab 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 10816543becfSAndreas Schwab 'A' + ((vendor >> 8) & 0x1f) - 1, 10826543becfSAndreas Schwab (function >> 4) & 0x0f, function & 0x0f, 10836543becfSAndreas Schwab (function >> 12) & 0x0f, (function >> 8) & 0x0f); 1084fedb3d27SOndrej Zary return 1; 1085fedb3d27SOndrej Zary } 1086fedb3d27SOndrej Zary 1087849e0ad2SJens Taprogge /* Looks like: "ipack:fNvNdN". */ 1088849e0ad2SJens Taprogge static int do_ipack_entry(const char *filename, 10896543becfSAndreas Schwab void *symval, char *alias) 1090849e0ad2SJens Taprogge { 10916543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, format); 10926543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, vendor); 10936543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, device); 1094849e0ad2SJens Taprogge strcpy(alias, "ipack:"); 10956543becfSAndreas Schwab ADD(alias, "f", format != IPACK_ANY_FORMAT, format); 10966543becfSAndreas Schwab ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); 10976543becfSAndreas Schwab ADD(alias, "d", device != IPACK_ANY_ID, device); 1098849e0ad2SJens Taprogge add_wildcard(alias); 1099849e0ad2SJens Taprogge return 1; 1100849e0ad2SJens Taprogge } 1101849e0ad2SJens Taprogge 1102523817bdSDave Martin /* 1103523817bdSDave Martin * Append a match expression for a single masked hex digit. 1104523817bdSDave Martin * outp points to a pointer to the character at which to append. 1105523817bdSDave Martin * *outp is updated on return to point just after the appended text, 1106523817bdSDave Martin * to facilitate further appending. 1107523817bdSDave Martin */ 1108523817bdSDave Martin static void append_nibble_mask(char **outp, 1109523817bdSDave Martin unsigned int nibble, unsigned int mask) 1110523817bdSDave Martin { 1111523817bdSDave Martin char *p = *outp; 1112523817bdSDave Martin unsigned int i; 1113523817bdSDave Martin 1114523817bdSDave Martin switch (mask) { 1115523817bdSDave Martin case 0: 1116523817bdSDave Martin *p++ = '?'; 1117523817bdSDave Martin break; 1118523817bdSDave Martin 1119523817bdSDave Martin case 0xf: 1120523817bdSDave Martin p += sprintf(p, "%X", nibble); 1121523817bdSDave Martin break; 1122523817bdSDave Martin 1123523817bdSDave Martin default: 1124523817bdSDave Martin /* 1125523817bdSDave Martin * Dumbly emit a match pattern for all possible matching 1126523817bdSDave Martin * digits. This could be improved in some cases using ranges, 1127523817bdSDave Martin * but it has the advantage of being trivially correct, and is 1128523817bdSDave Martin * often optimal. 1129523817bdSDave Martin */ 1130523817bdSDave Martin *p++ = '['; 1131523817bdSDave Martin for (i = 0; i < 0x10; i++) 1132523817bdSDave Martin if ((i & mask) == nibble) 1133523817bdSDave Martin p += sprintf(p, "%X", i); 1134523817bdSDave Martin *p++ = ']'; 1135523817bdSDave Martin } 1136523817bdSDave Martin 1137523817bdSDave Martin /* Ensure that the string remains NUL-terminated: */ 1138523817bdSDave Martin *p = '\0'; 1139523817bdSDave Martin 1140523817bdSDave Martin /* Advance the caller's end-of-string pointer: */ 1141523817bdSDave Martin *outp = p; 1142523817bdSDave Martin } 1143523817bdSDave Martin 1144523817bdSDave Martin /* 1145523817bdSDave Martin * looks like: "amba:dN" 1146523817bdSDave Martin * 1147523817bdSDave Martin * N is exactly 8 digits, where each is an upper-case hex digit, or 1148523817bdSDave Martin * a ? or [] pattern matching exactly one digit. 1149523817bdSDave Martin */ 1150523817bdSDave Martin static int do_amba_entry(const char *filename, 11516543becfSAndreas Schwab void *symval, char *alias) 1152523817bdSDave Martin { 1153523817bdSDave Martin unsigned int digit; 1154523817bdSDave Martin char *p = alias; 11556543becfSAndreas Schwab DEF_FIELD(symval, amba_id, id); 11566543becfSAndreas Schwab DEF_FIELD(symval, amba_id, mask); 1157523817bdSDave Martin 11586543becfSAndreas Schwab if ((id & mask) != id) 1159523817bdSDave Martin fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " 1160523817bdSDave Martin "id=0x%08X, mask=0x%08X. Please fix this driver.\n", 11616543becfSAndreas Schwab filename, id, mask); 1162523817bdSDave Martin 1163523817bdSDave Martin p += sprintf(alias, "amba:d"); 1164523817bdSDave Martin for (digit = 0; digit < 8; digit++) 1165523817bdSDave Martin append_nibble_mask(&p, 11666543becfSAndreas Schwab (id >> (4 * (7 - digit))) & 0xf, 11676543becfSAndreas Schwab (mask >> (4 * (7 - digit))) & 0xf); 1168523817bdSDave Martin 1169523817bdSDave Martin return 1; 1170523817bdSDave Martin } 1171523817bdSDave Martin 11728286ae03SJames Hogan /* 11738286ae03SJames Hogan * looks like: "mipscdmm:tN" 11748286ae03SJames Hogan * 11758286ae03SJames Hogan * N is exactly 2 digits, where each is an upper-case hex digit, or 11768286ae03SJames Hogan * a ? or [] pattern matching exactly one digit. 11778286ae03SJames Hogan */ 11788286ae03SJames Hogan static int do_mips_cdmm_entry(const char *filename, 11798286ae03SJames Hogan void *symval, char *alias) 11808286ae03SJames Hogan { 11818286ae03SJames Hogan DEF_FIELD(symval, mips_cdmm_device_id, type); 11828286ae03SJames Hogan 11838286ae03SJames Hogan sprintf(alias, "mipscdmm:t%02X*", type); 11848286ae03SJames Hogan return 1; 11858286ae03SJames Hogan } 11868286ae03SJames Hogan 11872b9c1f03SArd Biesheuvel /* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* 1188644e9cbbSAndi Kleen * All fields are numbers. It would be nicer to use strings for vendor 1189644e9cbbSAndi Kleen * and feature, but getting those out of the build system here is too 1190644e9cbbSAndi Kleen * complicated. 1191644e9cbbSAndi Kleen */ 1192644e9cbbSAndi Kleen 11936543becfSAndreas Schwab static int do_x86cpu_entry(const char *filename, void *symval, 1194644e9cbbSAndi Kleen char *alias) 1195644e9cbbSAndi Kleen { 11966543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, feature); 11976543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, family); 11986543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, model); 11996543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, vendor); 1200644e9cbbSAndi Kleen 12012b9c1f03SArd Biesheuvel strcpy(alias, "cpu:type:x86,"); 12022b9c1f03SArd Biesheuvel ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); 12032b9c1f03SArd Biesheuvel ADD(alias, "fam", family != X86_FAMILY_ANY, family); 12042b9c1f03SArd Biesheuvel ADD(alias, "mod", model != X86_MODEL_ANY, model); 12055467bddaSBen Hutchings strcat(alias, ":feature:*"); 12066543becfSAndreas Schwab if (feature != X86_FEATURE_ANY) 12076543becfSAndreas Schwab sprintf(alias + strlen(alias), "%04X*", feature); 1208644e9cbbSAndi Kleen return 1; 1209644e9cbbSAndi Kleen } 1210644e9cbbSAndi Kleen 121167bad2fdSArd Biesheuvel /* LOOKS like cpu:type:*:feature:*FEAT* */ 121267bad2fdSArd Biesheuvel static int do_cpu_entry(const char *filename, void *symval, char *alias) 121367bad2fdSArd Biesheuvel { 121467bad2fdSArd Biesheuvel DEF_FIELD(symval, cpu_feature, feature); 121567bad2fdSArd Biesheuvel 121667bad2fdSArd Biesheuvel sprintf(alias, "cpu:type:*:feature:*%04X*", feature); 121767bad2fdSArd Biesheuvel return 1; 121867bad2fdSArd Biesheuvel } 121967bad2fdSArd Biesheuvel 1220b26864caSTomas Winkler /* Looks like: mei:S:uuid:N:* */ 1221e5354107SSamuel Ortiz static int do_mei_entry(const char *filename, void *symval, 1222e5354107SSamuel Ortiz char *alias) 1223e5354107SSamuel Ortiz { 1224e5354107SSamuel Ortiz DEF_FIELD_ADDR(symval, mei_cl_device_id, name); 1225c93b76b3STomas Winkler DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid); 1226b26864caSTomas Winkler DEF_FIELD(symval, mei_cl_device_id, version); 1227e5354107SSamuel Ortiz 1228c93b76b3STomas Winkler sprintf(alias, MEI_CL_MODULE_PREFIX); 1229c93b76b3STomas Winkler sprintf(alias + strlen(alias), "%s:", (*name)[0] ? *name : "*"); 1230c93b76b3STomas Winkler add_uuid(alias, *uuid); 1231b26864caSTomas Winkler ADD(alias, ":", version != MEI_CL_VERSION_ANY, version); 1232c93b76b3STomas Winkler 1233c93b76b3STomas Winkler strcat(alias, ":*"); 1234e5354107SSamuel Ortiz 1235e5354107SSamuel Ortiz return 1; 1236e5354107SSamuel Ortiz } 1237e5354107SSamuel Ortiz 12383bdbb62fSAlexandre Bounine /* Looks like: rapidio:vNdNavNadN */ 12393bdbb62fSAlexandre Bounine static int do_rio_entry(const char *filename, 12403bdbb62fSAlexandre Bounine void *symval, char *alias) 12413bdbb62fSAlexandre Bounine { 12423bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, did); 12433bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, vid); 12443bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_did); 12453bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_vid); 12463bdbb62fSAlexandre Bounine 12473bdbb62fSAlexandre Bounine strcpy(alias, "rapidio:"); 12483bdbb62fSAlexandre Bounine ADD(alias, "v", vid != RIO_ANY_ID, vid); 12493bdbb62fSAlexandre Bounine ADD(alias, "d", did != RIO_ANY_ID, did); 12503bdbb62fSAlexandre Bounine ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); 12513bdbb62fSAlexandre Bounine ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); 12523bdbb62fSAlexandre Bounine 12533bdbb62fSAlexandre Bounine add_wildcard(alias); 12543bdbb62fSAlexandre Bounine return 1; 12553bdbb62fSAlexandre Bounine } 12563bdbb62fSAlexandre Bounine 1257289fcff4SHeikki Krogerus /* Looks like: ulpi:vNpN */ 1258289fcff4SHeikki Krogerus static int do_ulpi_entry(const char *filename, void *symval, 1259289fcff4SHeikki Krogerus char *alias) 1260289fcff4SHeikki Krogerus { 1261289fcff4SHeikki Krogerus DEF_FIELD(symval, ulpi_device_id, vendor); 1262289fcff4SHeikki Krogerus DEF_FIELD(symval, ulpi_device_id, product); 1263289fcff4SHeikki Krogerus 1264289fcff4SHeikki Krogerus sprintf(alias, "ulpi:v%04xp%04x", vendor, product); 1265289fcff4SHeikki Krogerus 1266289fcff4SHeikki Krogerus return 1; 1267289fcff4SHeikki Krogerus } 1268289fcff4SHeikki Krogerus 1269da23ac1eSSubhransu S. Prusty /* Looks like: hdaudio:vNrNaN */ 1270da23ac1eSSubhransu S. Prusty static int do_hda_entry(const char *filename, void *symval, char *alias) 1271da23ac1eSSubhransu S. Prusty { 1272da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, vendor_id); 1273da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, rev_id); 1274da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, api_version); 1275da23ac1eSSubhransu S. Prusty 1276da23ac1eSSubhransu S. Prusty strcpy(alias, "hdaudio:"); 1277da23ac1eSSubhransu S. Prusty ADD(alias, "v", vendor_id != 0, vendor_id); 1278da23ac1eSSubhransu S. Prusty ADD(alias, "r", rev_id != 0, rev_id); 1279da23ac1eSSubhransu S. Prusty ADD(alias, "a", api_version != 0, api_version); 1280da23ac1eSSubhransu S. Prusty 1281da23ac1eSSubhransu S. Prusty add_wildcard(alias); 1282da23ac1eSSubhransu S. Prusty return 1; 1283da23ac1eSSubhransu S. Prusty } 1284da23ac1eSSubhransu S. Prusty 1285b5924268SPierre-Louis Bossart /* Looks like: sdw:mNpNvNcN */ 12869251345dSVinod Koul static int do_sdw_entry(const char *filename, void *symval, char *alias) 12879251345dSVinod Koul { 12889251345dSVinod Koul DEF_FIELD(symval, sdw_device_id, mfg_id); 12899251345dSVinod Koul DEF_FIELD(symval, sdw_device_id, part_id); 1290b5924268SPierre-Louis Bossart DEF_FIELD(symval, sdw_device_id, sdw_version); 1291b5924268SPierre-Louis Bossart DEF_FIELD(symval, sdw_device_id, class_id); 12929251345dSVinod Koul 12939251345dSVinod Koul strcpy(alias, "sdw:"); 12949251345dSVinod Koul ADD(alias, "m", mfg_id != 0, mfg_id); 12959251345dSVinod Koul ADD(alias, "p", part_id != 0, part_id); 1296b5924268SPierre-Louis Bossart ADD(alias, "v", sdw_version != 0, sdw_version); 1297b5924268SPierre-Louis Bossart ADD(alias, "c", class_id != 0, class_id); 12989251345dSVinod Koul 12999251345dSVinod Koul add_wildcard(alias); 13009251345dSVinod Koul return 1; 13019251345dSVinod Koul } 13029251345dSVinod Koul 13030afef456SStuart Yoder /* Looks like: fsl-mc:vNdN */ 13040afef456SStuart Yoder static int do_fsl_mc_entry(const char *filename, void *symval, 13050afef456SStuart Yoder char *alias) 13060afef456SStuart Yoder { 13070afef456SStuart Yoder DEF_FIELD(symval, fsl_mc_device_id, vendor); 13080afef456SStuart Yoder DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); 13090afef456SStuart Yoder 13100afef456SStuart Yoder sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); 13110afef456SStuart Yoder return 1; 13120afef456SStuart Yoder } 13130afef456SStuart Yoder 1314d1ff7024SMika Westerberg /* Looks like: tbsvc:kSpNvNrN */ 1315d1ff7024SMika Westerberg static int do_tbsvc_entry(const char *filename, void *symval, char *alias) 1316d1ff7024SMika Westerberg { 1317d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, match_flags); 1318d1ff7024SMika Westerberg DEF_FIELD_ADDR(symval, tb_service_id, protocol_key); 1319d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_id); 1320d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_version); 1321d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_revision); 1322d1ff7024SMika Westerberg 1323d1ff7024SMika Westerberg strcpy(alias, "tbsvc:"); 1324d1ff7024SMika Westerberg if (match_flags & TBSVC_MATCH_PROTOCOL_KEY) 1325d1ff7024SMika Westerberg sprintf(alias + strlen(alias), "k%s", *protocol_key); 1326d1ff7024SMika Westerberg else 1327d1ff7024SMika Westerberg strcat(alias + strlen(alias), "k*"); 1328d1ff7024SMika Westerberg ADD(alias, "p", match_flags & TBSVC_MATCH_PROTOCOL_ID, protocol_id); 1329d1ff7024SMika Westerberg ADD(alias, "v", match_flags & TBSVC_MATCH_PROTOCOL_VERSION, 1330d1ff7024SMika Westerberg protocol_version); 1331d1ff7024SMika Westerberg ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION, 1332d1ff7024SMika Westerberg protocol_revision); 1333d1ff7024SMika Westerberg 1334d1ff7024SMika Westerberg add_wildcard(alias); 1335d1ff7024SMika Westerberg return 1; 1336d1ff7024SMika Westerberg } 1337d1ff7024SMika Westerberg 13388a37d87dSHeikki Krogerus /* Looks like: typec:idNmN */ 13398a37d87dSHeikki Krogerus static int do_typec_entry(const char *filename, void *symval, char *alias) 13408a37d87dSHeikki Krogerus { 13418a37d87dSHeikki Krogerus DEF_FIELD(symval, typec_device_id, svid); 13428a37d87dSHeikki Krogerus DEF_FIELD(symval, typec_device_id, mode); 13438a37d87dSHeikki Krogerus 13448a37d87dSHeikki Krogerus sprintf(alias, "typec:id%04X", svid); 13458a37d87dSHeikki Krogerus ADD(alias, "m", mode != TYPEC_ANY_MODE, mode); 13468a37d87dSHeikki Krogerus 13478a37d87dSHeikki Krogerus return 1; 13488a37d87dSHeikki Krogerus } 13498a37d87dSHeikki Krogerus 13500fc1db9dSSumit Garg /* Looks like: tee:uuid */ 13510fc1db9dSSumit Garg static int do_tee_entry(const char *filename, void *symval, char *alias) 13520fc1db9dSSumit Garg { 13530fc1db9dSSumit Garg DEF_FIELD(symval, tee_client_device_id, uuid); 13540fc1db9dSSumit Garg 13550fc1db9dSSumit Garg sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 13560fc1db9dSSumit Garg uuid.b[0], uuid.b[1], uuid.b[2], uuid.b[3], uuid.b[4], 13570fc1db9dSSumit Garg uuid.b[5], uuid.b[6], uuid.b[7], uuid.b[8], uuid.b[9], 13580fc1db9dSSumit Garg uuid.b[10], uuid.b[11], uuid.b[12], uuid.b[13], uuid.b[14], 13590fc1db9dSSumit Garg uuid.b[15]); 13600fc1db9dSSumit Garg 13610fc1db9dSSumit Garg add_wildcard(alias); 13620fc1db9dSSumit Garg return 1; 13630fc1db9dSSumit Garg } 13640fc1db9dSSumit Garg 13650bc44b2bSMattias Jacobsson /* Looks like: wmi:guid */ 13660bc44b2bSMattias Jacobsson static int do_wmi_entry(const char *filename, void *symval, char *alias) 13670bc44b2bSMattias Jacobsson { 13680bc44b2bSMattias Jacobsson int len; 13690bc44b2bSMattias Jacobsson DEF_FIELD_ADDR(symval, wmi_device_id, guid_string); 13700bc44b2bSMattias Jacobsson 13710bc44b2bSMattias Jacobsson if (strlen(*guid_string) != UUID_STRING_LEN) { 13720bc44b2bSMattias Jacobsson warn("Invalid WMI device id 'wmi:%s' in '%s'\n", 13730bc44b2bSMattias Jacobsson *guid_string, filename); 13740bc44b2bSMattias Jacobsson return 0; 13750bc44b2bSMattias Jacobsson } 13760bc44b2bSMattias Jacobsson 13770bc44b2bSMattias Jacobsson len = snprintf(alias, ALIAS_SIZE, WMI_MODULE_PREFIX "%s", *guid_string); 13780bc44b2bSMattias Jacobsson if (len < 0 || len >= ALIAS_SIZE) { 13790bc44b2bSMattias Jacobsson warn("Could not generate all MODULE_ALIAS's in '%s'\n", 13800bc44b2bSMattias Jacobsson filename); 13810bc44b2bSMattias Jacobsson return 0; 13820bc44b2bSMattias Jacobsson } 13830bc44b2bSMattias Jacobsson return 1; 13840bc44b2bSMattias Jacobsson } 13850bc44b2bSMattias Jacobsson 1386e6b0de46SManivannan Sadhasivam /* Looks like: mhi:S */ 1387e6b0de46SManivannan Sadhasivam static int do_mhi_entry(const char *filename, void *symval, char *alias) 1388e6b0de46SManivannan Sadhasivam { 1389e6b0de46SManivannan Sadhasivam DEF_FIELD_ADDR(symval, mhi_device_id, chan); 1390e6b0de46SManivannan Sadhasivam sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan); 13917de3697eSDave Ertman return 1; 13927de3697eSDave Ertman } 13937de3697eSDave Ertman 1394*fa443bc3SThomas Weißschuh /* Looks like: ishtp:{guid} */ 1395*fa443bc3SThomas Weißschuh static int do_ishtp_entry(const char *filename, void *symval, char *alias) 1396*fa443bc3SThomas Weißschuh { 1397*fa443bc3SThomas Weißschuh DEF_FIELD(symval, ishtp_device_id, guid); 1398*fa443bc3SThomas Weißschuh 1399*fa443bc3SThomas Weißschuh strcpy(alias, ISHTP_MODULE_PREFIX "{"); 1400*fa443bc3SThomas Weißschuh add_guid(alias, guid); 1401*fa443bc3SThomas Weißschuh strcat(alias, "}"); 1402*fa443bc3SThomas Weißschuh 1403*fa443bc3SThomas Weißschuh return 1; 1404*fa443bc3SThomas Weißschuh } 1405*fa443bc3SThomas Weißschuh 14067de3697eSDave Ertman static int do_auxiliary_entry(const char *filename, void *symval, char *alias) 14077de3697eSDave Ertman { 14087de3697eSDave Ertman DEF_FIELD_ADDR(symval, auxiliary_device_id, name); 14097de3697eSDave Ertman sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name); 1410e6b0de46SManivannan Sadhasivam 1411e6b0de46SManivannan Sadhasivam return 1; 1412e6b0de46SManivannan Sadhasivam } 1413e6b0de46SManivannan Sadhasivam 1414eb0e90a8SMaximilian Luz /* 1415eb0e90a8SMaximilian Luz * Looks like: ssam:dNcNtNiNfN 1416eb0e90a8SMaximilian Luz * 1417eb0e90a8SMaximilian Luz * N is exactly 2 digits, where each is an upper-case hex digit. 1418eb0e90a8SMaximilian Luz */ 1419eb0e90a8SMaximilian Luz static int do_ssam_entry(const char *filename, void *symval, char *alias) 1420eb0e90a8SMaximilian Luz { 1421eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, match_flags); 1422eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, domain); 1423eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, category); 1424eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, target); 1425eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, instance); 1426eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, function); 1427eb0e90a8SMaximilian Luz 1428eb0e90a8SMaximilian Luz sprintf(alias, "ssam:d%02Xc%02X", domain, category); 1429eb0e90a8SMaximilian Luz ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target); 1430eb0e90a8SMaximilian Luz ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); 1431eb0e90a8SMaximilian Luz ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); 1432eb0e90a8SMaximilian Luz 1433eb0e90a8SMaximilian Luz return 1; 1434eb0e90a8SMaximilian Luz } 1435eb0e90a8SMaximilian Luz 14364a224aceSXu Yilun /* Looks like: dfl:tNfN */ 14374a224aceSXu Yilun static int do_dfl_entry(const char *filename, void *symval, char *alias) 14384a224aceSXu Yilun { 14394a224aceSXu Yilun DEF_FIELD(symval, dfl_device_id, type); 14404a224aceSXu Yilun DEF_FIELD(symval, dfl_device_id, feature_id); 14414a224aceSXu Yilun 14424a224aceSXu Yilun sprintf(alias, "dfl:t%04Xf%04X", type, feature_id); 14434a224aceSXu Yilun 14444a224aceSXu Yilun add_wildcard(alias); 14454a224aceSXu Yilun return 1; 14464a224aceSXu Yilun } 14474a224aceSXu Yilun 1448626596e2SRusty Russell /* Does namelen bytes of name exactly match the symbol? */ 1449626596e2SRusty Russell static bool sym_is(const char *name, unsigned namelen, const char *symbol) 14501da177e4SLinus Torvalds { 1451626596e2SRusty Russell if (namelen != strlen(symbol)) 1452626596e2SRusty Russell return false; 14531da177e4SLinus Torvalds 1454626596e2SRusty Russell return memcmp(name, symbol, namelen) == 0; 14551da177e4SLinus Torvalds } 14561da177e4SLinus Torvalds 14571da177e4SLinus Torvalds static void do_table(void *symval, unsigned long size, 14581da177e4SLinus Torvalds unsigned long id_size, 1459fb33d816SSam Ravnborg const char *device_id, 1460f880eea6SMasahiro Yamada int (*do_entry)(const char *filename, void *symval, char *alias), 14611da177e4SLinus Torvalds struct module *mod) 14621da177e4SLinus Torvalds { 14631da177e4SLinus Torvalds unsigned int i; 1464841f1b8fSMattias Jacobsson char alias[ALIAS_SIZE]; 14651da177e4SLinus Torvalds 1466e0049825SKees Cook device_id_check(mod->name, device_id, size, id_size, symval); 14671da177e4SLinus Torvalds /* Leave last one: it's the terminator. */ 14681da177e4SLinus Torvalds size -= id_size; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds for (i = 0; i < size; i += id_size) { 14711da177e4SLinus Torvalds if (do_entry(mod->name, symval+i, alias)) { 14721da177e4SLinus Torvalds buf_printf(&mod->dev_table_buf, 14731da177e4SLinus Torvalds "MODULE_ALIAS(\"%s\");\n", alias); 14741da177e4SLinus Torvalds } 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds } 14771da177e4SLinus Torvalds 1478ec91e78dSMasahiro Yamada static const struct devtable devtable[] = { 1479ec91e78dSMasahiro Yamada {"hid", SIZE_hid_device_id, do_hid_entry}, 1480ec91e78dSMasahiro Yamada {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, 1481ec91e78dSMasahiro Yamada {"pci", SIZE_pci_device_id, do_pci_entry}, 1482ec91e78dSMasahiro Yamada {"ccw", SIZE_ccw_device_id, do_ccw_entry}, 1483ec91e78dSMasahiro Yamada {"ap", SIZE_ap_device_id, do_ap_entry}, 1484ec91e78dSMasahiro Yamada {"css", SIZE_css_device_id, do_css_entry}, 1485ec91e78dSMasahiro Yamada {"serio", SIZE_serio_device_id, do_serio_entry}, 1486ec91e78dSMasahiro Yamada {"acpi", SIZE_acpi_device_id, do_acpi_entry}, 1487ec91e78dSMasahiro Yamada {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, 1488ec91e78dSMasahiro Yamada {"vio", SIZE_vio_device_id, do_vio_entry}, 1489ec91e78dSMasahiro Yamada {"input", SIZE_input_device_id, do_input_entry}, 1490ec91e78dSMasahiro Yamada {"eisa", SIZE_eisa_device_id, do_eisa_entry}, 1491ec91e78dSMasahiro Yamada {"parisc", SIZE_parisc_device_id, do_parisc_entry}, 1492ec91e78dSMasahiro Yamada {"sdio", SIZE_sdio_device_id, do_sdio_entry}, 1493ec91e78dSMasahiro Yamada {"ssb", SIZE_ssb_device_id, do_ssb_entry}, 1494ec91e78dSMasahiro Yamada {"bcma", SIZE_bcma_device_id, do_bcma_entry}, 1495ec91e78dSMasahiro Yamada {"virtio", SIZE_virtio_device_id, do_virtio_entry}, 1496ec91e78dSMasahiro Yamada {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, 1497ec91e78dSMasahiro Yamada {"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry}, 1498ec91e78dSMasahiro Yamada {"i2c", SIZE_i2c_device_id, do_i2c_entry}, 14991ce589adSBoris Brezillon {"i3c", SIZE_i3c_device_id, do_i3c_entry}, 1500ec91e78dSMasahiro Yamada {"spi", SIZE_spi_device_id, do_spi_entry}, 1501ec91e78dSMasahiro Yamada {"dmi", SIZE_dmi_system_id, do_dmi_entry}, 1502ec91e78dSMasahiro Yamada {"platform", SIZE_platform_device_id, do_platform_entry}, 1503ec91e78dSMasahiro Yamada {"mdio", SIZE_mdio_device_id, do_mdio_entry}, 1504ec91e78dSMasahiro Yamada {"zorro", SIZE_zorro_device_id, do_zorro_entry}, 1505ec91e78dSMasahiro Yamada {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, 1506ec91e78dSMasahiro Yamada {"ipack", SIZE_ipack_device_id, do_ipack_entry}, 1507ec91e78dSMasahiro Yamada {"amba", SIZE_amba_id, do_amba_entry}, 1508ec91e78dSMasahiro Yamada {"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry}, 1509ec91e78dSMasahiro Yamada {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, 1510ec91e78dSMasahiro Yamada {"cpu", SIZE_cpu_feature, do_cpu_entry}, 1511ec91e78dSMasahiro Yamada {"mei", SIZE_mei_cl_device_id, do_mei_entry}, 1512ec91e78dSMasahiro Yamada {"rapidio", SIZE_rio_device_id, do_rio_entry}, 1513ec91e78dSMasahiro Yamada {"ulpi", SIZE_ulpi_device_id, do_ulpi_entry}, 1514ec91e78dSMasahiro Yamada {"hdaudio", SIZE_hda_device_id, do_hda_entry}, 1515ec91e78dSMasahiro Yamada {"sdw", SIZE_sdw_device_id, do_sdw_entry}, 1516ec91e78dSMasahiro Yamada {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, 1517ec91e78dSMasahiro Yamada {"tbsvc", SIZE_tb_service_id, do_tbsvc_entry}, 1518ec91e78dSMasahiro Yamada {"typec", SIZE_typec_device_id, do_typec_entry}, 15190fc1db9dSSumit Garg {"tee", SIZE_tee_client_device_id, do_tee_entry}, 15200bc44b2bSMattias Jacobsson {"wmi", SIZE_wmi_device_id, do_wmi_entry}, 1521e6b0de46SManivannan Sadhasivam {"mhi", SIZE_mhi_device_id, do_mhi_entry}, 15227de3697eSDave Ertman {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, 1523eb0e90a8SMaximilian Luz {"ssam", SIZE_ssam_device_id, do_ssam_entry}, 15244a224aceSXu Yilun {"dfl", SIZE_dfl_device_id, do_dfl_entry}, 1525*fa443bc3SThomas Weißschuh {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, 1526ec91e78dSMasahiro Yamada }; 1527ec91e78dSMasahiro Yamada 15281da177e4SLinus Torvalds /* Create MODULE_ALIAS() statements. 15291da177e4SLinus Torvalds * At this time, we cannot write the actual output C source yet, 15301da177e4SLinus Torvalds * so we write into the mod->dev_table_buf buffer. */ 15311da177e4SLinus Torvalds void handle_moddevtable(struct module *mod, struct elf_info *info, 15321da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 15331da177e4SLinus Torvalds { 15341da177e4SLinus Torvalds void *symval; 1535e0049825SKees Cook char *zeros = NULL; 153621bdd17bSTom Gundersen const char *name, *identifier; 1537626596e2SRusty Russell unsigned int namelen; 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds /* We're looking for a section relative symbol */ 15401ce53adfSDenys Vlasenko if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) 15411da177e4SLinus Torvalds return; 15421da177e4SLinus Torvalds 1543e88aa7bbSDavid Miller /* We're looking for an object */ 1544e88aa7bbSDavid Miller if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 1545e88aa7bbSDavid Miller return; 1546e88aa7bbSDavid Miller 1547153e04b3SMasahiro Yamada /* All our symbols are of form __mod_<name>__<identifier>_device_table. */ 1548153e04b3SMasahiro Yamada if (strncmp(symname, "__mod_", strlen("__mod_"))) 1549626596e2SRusty Russell return; 1550153e04b3SMasahiro Yamada name = symname + strlen("__mod_"); 1551626596e2SRusty Russell namelen = strlen(name); 1552626596e2SRusty Russell if (namelen < strlen("_device_table")) 1553626596e2SRusty Russell return; 1554626596e2SRusty Russell if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) 1555626596e2SRusty Russell return; 155621bdd17bSTom Gundersen identifier = strstr(name, "__"); 155721bdd17bSTom Gundersen if (!identifier) 155821bdd17bSTom Gundersen return; 155921bdd17bSTom Gundersen namelen = identifier - name; 1560626596e2SRusty Russell 1561e0049825SKees Cook /* Handle all-NULL symbols allocated into .bss */ 15621ce53adfSDenys Vlasenko if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { 1563e0049825SKees Cook zeros = calloc(1, sym->st_size); 1564e0049825SKees Cook symval = zeros; 1565e0049825SKees Cook } else { 15661da177e4SLinus Torvalds symval = (void *)info->hdr 15671ce53adfSDenys Vlasenko + info->sechdrs[get_secindex(info, sym)].sh_offset 15681da177e4SLinus Torvalds + sym->st_value; 1569e0049825SKees Cook } 15701da177e4SLinus Torvalds 1571626596e2SRusty Russell /* First handle the "special" cases */ 1572626596e2SRusty Russell if (sym_is(name, namelen, "usb")) 1573b19dcd93SRoman Kagan do_usb_table(symval, sym->st_size, mod); 1574acbef7b7SPhilipp Zabel if (sym_is(name, namelen, "of")) 1575acbef7b7SPhilipp Zabel do_of_table(symval, sym->st_size, mod); 1576626596e2SRusty Russell else if (sym_is(name, namelen, "pnp")) 157722454cb9SKay Sievers do_pnp_device_entry(symval, sym->st_size, mod); 1578626596e2SRusty Russell else if (sym_is(name, namelen, "pnp_card")) 15790c81eed4SKay Sievers do_pnp_card_entries(symval, sym->st_size, mod); 1580626596e2SRusty Russell else { 1581ec91e78dSMasahiro Yamada int i; 1582626596e2SRusty Russell 1583ec91e78dSMasahiro Yamada for (i = 0; i < ARRAY_SIZE(devtable); i++) { 1584ec91e78dSMasahiro Yamada const struct devtable *p = &devtable[i]; 1585ec91e78dSMasahiro Yamada 1586ec91e78dSMasahiro Yamada if (sym_is(name, namelen, p->device_id)) { 1587ec91e78dSMasahiro Yamada do_table(symval, sym->st_size, p->id_size, 1588f880eea6SMasahiro Yamada p->device_id, p->do_entry, mod); 1589626596e2SRusty Russell break; 1590626596e2SRusty Russell } 1591626596e2SRusty Russell } 1592626596e2SRusty Russell } 1593e0049825SKees Cook free(zeros); 15941da177e4SLinus Torvalds } 15951da177e4SLinus Torvalds 15961da177e4SLinus Torvalds /* Now add out buffered information to the generated C source */ 15971da177e4SLinus Torvalds void add_moddevtable(struct buffer *buf, struct module *mod) 15981da177e4SLinus Torvalds { 15991da177e4SLinus Torvalds buf_printf(buf, "\n"); 16001da177e4SLinus Torvalds buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); 16011da177e4SLinus Torvalds free(mod->dev_table_buf.p); 16021da177e4SLinus Torvalds } 1603