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 118fa443bc3SThomas Weißschuh static inline void add_guid(char *str, guid_t guid) 119fa443bc3SThomas Weißschuh { 120fa443bc3SThomas Weißschuh int len = strlen(str); 121fa443bc3SThomas Weißschuh 122fa443bc3SThomas Weißschuh sprintf(str + len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 123fa443bc3SThomas Weißschuh guid.b[3], guid.b[2], guid.b[1], guid.b[0], 124fa443bc3SThomas Weißschuh guid.b[5], guid.b[4], guid.b[7], guid.b[6], 125fa443bc3SThomas Weißschuh guid.b[8], guid.b[9], guid.b[10], guid.b[11], 126fa443bc3SThomas Weißschuh guid.b[12], guid.b[13], guid.b[14], guid.b[15]); 127fa443bc3SThomas Weißschuh } 128fa443bc3SThomas 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 static void do_input(char *alias, 7381d8f430cSRusty Russell kernel_ulong_t *arr, unsigned int min, unsigned int max) 7391d8f430cSRusty Russell { 7401d8f430cSRusty Russell unsigned int i; 741ddc5d341SDmitry Torokhov 7426543becfSAndreas Schwab for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) 7436543becfSAndreas Schwab arr[i] = TO_NATIVE(arr[i]); 744ddc5d341SDmitry Torokhov for (i = min; i < max; i++) 745e0e92632SHans de Goede if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) 7461d8f430cSRusty Russell sprintf(alias + strlen(alias), "%X,*", i); 7471d8f430cSRusty Russell } 7481d8f430cSRusty Russell 74909c3e01bSDmitry Torokhov /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ 7506543becfSAndreas Schwab static int do_input_entry(const char *filename, void *symval, 7511d8f430cSRusty Russell char *alias) 7521d8f430cSRusty Russell { 7536543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, flags); 7546543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, bustype); 7556543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, vendor); 7566543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, product); 7576543becfSAndreas Schwab DEF_FIELD(symval, input_device_id, version); 7586543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, evbit); 7596543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, keybit); 7606543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, relbit); 7616543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, absbit); 7626543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, mscbit); 7636543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ledbit); 7646543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, sndbit); 7656543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, ffbit); 7666543becfSAndreas Schwab DEF_FIELD_ADDR(symval, input_device_id, swbit); 7676543becfSAndreas Schwab 7681d8f430cSRusty Russell sprintf(alias, "input:"); 7691d8f430cSRusty Russell 7706543becfSAndreas Schwab ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); 7716543becfSAndreas Schwab ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); 7726543becfSAndreas Schwab ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); 7736543becfSAndreas Schwab ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); 7741d8f430cSRusty Russell 7751d8f430cSRusty Russell sprintf(alias + strlen(alias), "-e*"); 7766543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) 7776543becfSAndreas Schwab do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); 7781d8f430cSRusty Russell sprintf(alias + strlen(alias), "k*"); 7796543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) 7806543becfSAndreas Schwab do_input(alias, *keybit, 781dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MIN_INTERESTING, 782dc24f0e7SSam Ravnborg INPUT_DEVICE_ID_KEY_MAX); 7831d8f430cSRusty Russell sprintf(alias + strlen(alias), "r*"); 7846543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) 7856543becfSAndreas Schwab do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); 7861d8f430cSRusty Russell sprintf(alias + strlen(alias), "a*"); 7876543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) 7886543becfSAndreas Schwab do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); 7891d8f430cSRusty Russell sprintf(alias + strlen(alias), "m*"); 7906543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) 7916543becfSAndreas Schwab do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); 7921d8f430cSRusty Russell sprintf(alias + strlen(alias), "l*"); 7936543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) 7946543becfSAndreas Schwab do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); 7951d8f430cSRusty Russell sprintf(alias + strlen(alias), "s*"); 7966543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) 7976543becfSAndreas Schwab do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); 7981d8f430cSRusty Russell sprintf(alias + strlen(alias), "f*"); 7996543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) 8006543becfSAndreas Schwab do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); 8011d8f430cSRusty Russell sprintf(alias + strlen(alias), "w*"); 8026543becfSAndreas Schwab if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) 8036543becfSAndreas Schwab do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); 8041d8f430cSRusty Russell return 1; 8051d8f430cSRusty Russell } 8061d8f430cSRusty Russell 8076543becfSAndreas Schwab static int do_eisa_entry(const char *filename, void *symval, 80807563c71SMichael Tokarev char *alias) 80907563c71SMichael Tokarev { 8106543becfSAndreas Schwab DEF_FIELD_ADDR(symval, eisa_device_id, sig); 8116543becfSAndreas Schwab if (sig[0]) 8126543becfSAndreas Schwab sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); 813ac551828SJean Delvare else 814ac551828SJean Delvare strcat(alias, "*"); 81507563c71SMichael Tokarev return 1; 81607563c71SMichael Tokarev } 81707563c71SMichael Tokarev 818f3cf2673SKyle McMartin /* Looks like: parisc:tNhvNrevNsvN */ 8196543becfSAndreas Schwab static int do_parisc_entry(const char *filename, void *symval, 820f3cf2673SKyle McMartin char *alias) 821f3cf2673SKyle McMartin { 8226543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hw_type); 8236543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion); 8246543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, hversion_rev); 8256543becfSAndreas Schwab DEF_FIELD(symval, parisc_device_id, sversion); 826f3cf2673SKyle McMartin 827f3cf2673SKyle McMartin strcpy(alias, "parisc:"); 8286543becfSAndreas Schwab ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); 8296543becfSAndreas Schwab ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); 8306543becfSAndreas Schwab ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); 8316543becfSAndreas Schwab ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); 832f3cf2673SKyle McMartin 833ac551828SJean Delvare add_wildcard(alias); 834f3cf2673SKyle McMartin return 1; 835f3cf2673SKyle McMartin } 836f3cf2673SKyle McMartin 837d59b66c7SPierre Ossman /* Looks like: sdio:cNvNdN. */ 838d59b66c7SPierre Ossman static int do_sdio_entry(const char *filename, 8396543becfSAndreas Schwab void *symval, char *alias) 840d59b66c7SPierre Ossman { 8416543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, class); 8426543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, vendor); 8436543becfSAndreas Schwab DEF_FIELD(symval, sdio_device_id, device); 844d59b66c7SPierre Ossman 845d59b66c7SPierre Ossman strcpy(alias, "sdio:"); 8466543becfSAndreas Schwab ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); 8476543becfSAndreas Schwab ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); 8486543becfSAndreas Schwab ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); 849ac551828SJean Delvare add_wildcard(alias); 850038a5008SLinus Torvalds return 1; 851038a5008SLinus Torvalds } 852d59b66c7SPierre Ossman 85361e115a5SMichael Buesch /* Looks like: ssb:vNidNrevN. */ 85461e115a5SMichael Buesch static int do_ssb_entry(const char *filename, 8556543becfSAndreas Schwab void *symval, char *alias) 85661e115a5SMichael Buesch { 8576543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, vendor); 8586543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, coreid); 8596543becfSAndreas Schwab DEF_FIELD(symval, ssb_device_id, revision); 86061e115a5SMichael Buesch 86161e115a5SMichael Buesch strcpy(alias, "ssb:"); 8626543becfSAndreas Schwab ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); 8636543becfSAndreas Schwab ADD(alias, "id", coreid != SSB_ANY_ID, coreid); 8646543becfSAndreas Schwab ADD(alias, "rev", revision != SSB_ANY_REV, revision); 865ac551828SJean Delvare add_wildcard(alias); 866d59b66c7SPierre Ossman return 1; 867d59b66c7SPierre Ossman } 868d59b66c7SPierre Ossman 8698369ae33SRafał Miłecki /* Looks like: bcma:mNidNrevNclN. */ 8708369ae33SRafał Miłecki static int do_bcma_entry(const char *filename, 8716543becfSAndreas Schwab void *symval, char *alias) 8728369ae33SRafał Miłecki { 8736543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, manuf); 8746543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, id); 8756543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, rev); 8766543becfSAndreas Schwab DEF_FIELD(symval, bcma_device_id, class); 8778369ae33SRafał Miłecki 8788369ae33SRafał Miłecki strcpy(alias, "bcma:"); 8796543becfSAndreas Schwab ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); 8806543becfSAndreas Schwab ADD(alias, "id", id != BCMA_ANY_ID, id); 8816543becfSAndreas Schwab ADD(alias, "rev", rev != BCMA_ANY_REV, rev); 8826543becfSAndreas Schwab ADD(alias, "cl", class != BCMA_ANY_CLASS, class); 8838369ae33SRafał Miłecki add_wildcard(alias); 8848369ae33SRafał Miłecki return 1; 8858369ae33SRafał Miłecki } 8868369ae33SRafał Miłecki 887b01d9f28SRusty Russell /* Looks like: virtio:dNvN */ 8886543becfSAndreas Schwab static int do_virtio_entry(const char *filename, void *symval, 889b01d9f28SRusty Russell char *alias) 890b01d9f28SRusty Russell { 8916543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, device); 8926543becfSAndreas Schwab DEF_FIELD(symval, virtio_device_id, vendor); 893b01d9f28SRusty Russell 894b01d9f28SRusty Russell strcpy(alias, "virtio:"); 8956543becfSAndreas Schwab ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); 8966543becfSAndreas Schwab ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); 897b01d9f28SRusty Russell 898ac551828SJean Delvare add_wildcard(alias); 899b01d9f28SRusty Russell return 1; 900b01d9f28SRusty Russell } 901b01d9f28SRusty Russell 902d2ee52aaSK. Y. Srinivasan /* 903d2ee52aaSK. Y. Srinivasan * Looks like: vmbus:guid 904d2ee52aaSK. Y. Srinivasan * Each byte of the guid will be represented by two hex characters 905d2ee52aaSK. Y. Srinivasan * in the name. 906d2ee52aaSK. Y. Srinivasan */ 907d2ee52aaSK. Y. Srinivasan 9086543becfSAndreas Schwab static int do_vmbus_entry(const char *filename, void *symval, 909d2ee52aaSK. Y. Srinivasan char *alias) 910d2ee52aaSK. Y. Srinivasan { 911d2ee52aaSK. Y. Srinivasan int i; 9126543becfSAndreas Schwab DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); 9136543becfSAndreas Schwab char guid_name[(sizeof(*guid) + 1) * 2]; 914d2ee52aaSK. Y. Srinivasan 9156543becfSAndreas Schwab for (i = 0; i < (sizeof(*guid) * 2); i += 2) 916af3ff643SK. Y. Srinivasan sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); 917d2ee52aaSK. Y. Srinivasan 918d2ee52aaSK. Y. Srinivasan strcpy(alias, "vmbus:"); 919d2ee52aaSK. Y. Srinivasan strcat(alias, guid_name); 920d2ee52aaSK. Y. Srinivasan 921d2ee52aaSK. Y. Srinivasan return 1; 922d2ee52aaSK. Y. Srinivasan } 923d2ee52aaSK. Y. Srinivasan 9245b7d1277SAndrew F. Davis /* Looks like: rpmsg:S */ 9255b7d1277SAndrew F. Davis static int do_rpmsg_entry(const char *filename, void *symval, 9265b7d1277SAndrew F. Davis char *alias) 9275b7d1277SAndrew F. Davis { 9285b7d1277SAndrew F. Davis DEF_FIELD_ADDR(symval, rpmsg_device_id, name); 9295b7d1277SAndrew F. Davis sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name); 9305b7d1277SAndrew F. Davis 9315b7d1277SAndrew F. Davis return 1; 9325b7d1277SAndrew F. Davis } 9335b7d1277SAndrew F. Davis 934d2653e92SJean Delvare /* Looks like: i2c:S */ 9356543becfSAndreas Schwab static int do_i2c_entry(const char *filename, void *symval, 936d2653e92SJean Delvare char *alias) 937d2653e92SJean Delvare { 9386543becfSAndreas Schwab DEF_FIELD_ADDR(symval, i2c_device_id, name); 9396543becfSAndreas Schwab sprintf(alias, I2C_MODULE_PREFIX "%s", *name); 940d2653e92SJean Delvare 941d2653e92SJean Delvare return 1; 942d2653e92SJean Delvare } 943d2653e92SJean Delvare 9441ce589adSBoris Brezillon static int do_i3c_entry(const char *filename, void *symval, 9451ce589adSBoris Brezillon char *alias) 9461ce589adSBoris Brezillon { 9471ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, match_flags); 9481ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, dcr); 9491ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, manuf_id); 9501ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, part_id); 9511ce589adSBoris Brezillon DEF_FIELD(symval, i3c_device_id, extra_info); 9521ce589adSBoris Brezillon 9531ce589adSBoris Brezillon strcpy(alias, "i3c:"); 9541ce589adSBoris Brezillon ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr); 9551ce589adSBoris Brezillon ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id); 9561ce589adSBoris Brezillon ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id); 9571ce589adSBoris Brezillon ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info); 9581ce589adSBoris Brezillon 9591ce589adSBoris Brezillon return 1; 9601ce589adSBoris Brezillon } 9611ce589adSBoris Brezillon 962e0626e38SAnton Vorontsov /* Looks like: spi:S */ 9636543becfSAndreas Schwab static int do_spi_entry(const char *filename, void *symval, 96475368bf6SAnton Vorontsov char *alias) 96575368bf6SAnton Vorontsov { 9666543becfSAndreas Schwab DEF_FIELD_ADDR(symval, spi_device_id, name); 9676543becfSAndreas Schwab sprintf(alias, SPI_MODULE_PREFIX "%s", *name); 96875368bf6SAnton Vorontsov 96975368bf6SAnton Vorontsov return 1; 97075368bf6SAnton Vorontsov } 97175368bf6SAnton Vorontsov 972d945b697SDavid Woodhouse static const struct dmifield { 973d945b697SDavid Woodhouse const char *prefix; 974d945b697SDavid Woodhouse int field; 975d945b697SDavid Woodhouse } dmi_fields[] = { 976d945b697SDavid Woodhouse { "bvn", DMI_BIOS_VENDOR }, 977d945b697SDavid Woodhouse { "bvr", DMI_BIOS_VERSION }, 978d945b697SDavid Woodhouse { "bd", DMI_BIOS_DATE }, 979f5152f4dSErwan Velu { "br", DMI_BIOS_RELEASE }, 980f5152f4dSErwan Velu { "efr", DMI_EC_FIRMWARE_RELEASE }, 981d945b697SDavid Woodhouse { "svn", DMI_SYS_VENDOR }, 982d945b697SDavid Woodhouse { "pn", DMI_PRODUCT_NAME }, 983d945b697SDavid Woodhouse { "pvr", DMI_PRODUCT_VERSION }, 984d945b697SDavid Woodhouse { "rvn", DMI_BOARD_VENDOR }, 985d945b697SDavid Woodhouse { "rn", DMI_BOARD_NAME }, 986d945b697SDavid Woodhouse { "rvr", DMI_BOARD_VERSION }, 987d945b697SDavid Woodhouse { "cvn", DMI_CHASSIS_VENDOR }, 988d945b697SDavid Woodhouse { "ct", DMI_CHASSIS_TYPE }, 989d945b697SDavid Woodhouse { "cvr", DMI_CHASSIS_VERSION }, 990d945b697SDavid Woodhouse { NULL, DMI_NONE } 991d945b697SDavid Woodhouse }; 992d945b697SDavid Woodhouse 993d945b697SDavid Woodhouse static void dmi_ascii_filter(char *d, const char *s) 994d945b697SDavid Woodhouse { 995d945b697SDavid Woodhouse /* Filter out characters we don't want to see in the modalias string */ 996d945b697SDavid Woodhouse for (; *s; s++) 997d945b697SDavid Woodhouse if (*s > ' ' && *s < 127 && *s != ':') 998d945b697SDavid Woodhouse *(d++) = *s; 999d945b697SDavid Woodhouse 1000d945b697SDavid Woodhouse *d = 0; 1001d945b697SDavid Woodhouse } 1002d945b697SDavid Woodhouse 1003d945b697SDavid Woodhouse 10046543becfSAndreas Schwab static int do_dmi_entry(const char *filename, void *symval, 1005d945b697SDavid Woodhouse char *alias) 1006d945b697SDavid Woodhouse { 1007d945b697SDavid Woodhouse int i, j; 10086543becfSAndreas Schwab DEF_FIELD_ADDR(symval, dmi_system_id, matches); 1009d945b697SDavid Woodhouse sprintf(alias, "dmi*"); 1010d945b697SDavid Woodhouse 1011d945b697SDavid Woodhouse for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { 1012d945b697SDavid Woodhouse for (j = 0; j < 4; j++) { 10136543becfSAndreas Schwab if ((*matches)[j].slot && 10146543becfSAndreas Schwab (*matches)[j].slot == dmi_fields[i].field) { 1015d945b697SDavid Woodhouse sprintf(alias + strlen(alias), ":%s*", 1016d945b697SDavid Woodhouse dmi_fields[i].prefix); 1017d945b697SDavid Woodhouse dmi_ascii_filter(alias + strlen(alias), 10186543becfSAndreas Schwab (*matches)[j].substr); 1019d945b697SDavid Woodhouse strcat(alias, "*"); 1020d945b697SDavid Woodhouse } 1021d945b697SDavid Woodhouse } 1022d945b697SDavid Woodhouse } 1023d945b697SDavid Woodhouse 1024d945b697SDavid Woodhouse strcat(alias, ":"); 1025d945b697SDavid Woodhouse return 1; 1026d945b697SDavid Woodhouse } 102757fee4a5SEric Miao 102857fee4a5SEric Miao static int do_platform_entry(const char *filename, 10296543becfSAndreas Schwab void *symval, char *alias) 103057fee4a5SEric Miao { 10316543becfSAndreas Schwab DEF_FIELD_ADDR(symval, platform_device_id, name); 10326543becfSAndreas Schwab sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); 103357fee4a5SEric Miao return 1; 103457fee4a5SEric Miao } 103557fee4a5SEric Miao 10368626d3b4SDavid Woodhouse static int do_mdio_entry(const char *filename, 10376543becfSAndreas Schwab void *symval, char *alias) 10388626d3b4SDavid Woodhouse { 10398626d3b4SDavid Woodhouse int i; 10406543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id); 10416543becfSAndreas Schwab DEF_FIELD(symval, mdio_device_id, phy_id_mask); 10428626d3b4SDavid Woodhouse 10438626d3b4SDavid Woodhouse alias += sprintf(alias, MDIO_MODULE_PREFIX); 10448626d3b4SDavid Woodhouse 10458626d3b4SDavid Woodhouse for (i = 0; i < 32; i++) { 10466543becfSAndreas Schwab if (!((phy_id_mask >> (31-i)) & 1)) 10478626d3b4SDavid Woodhouse *(alias++) = '?'; 10486543becfSAndreas Schwab else if ((phy_id >> (31-i)) & 1) 10498626d3b4SDavid Woodhouse *(alias++) = '1'; 10508626d3b4SDavid Woodhouse else 10518626d3b4SDavid Woodhouse *(alias++) = '0'; 10528626d3b4SDavid Woodhouse } 10538626d3b4SDavid Woodhouse 10548626d3b4SDavid Woodhouse /* Terminate the string */ 10558626d3b4SDavid Woodhouse *alias = 0; 10568626d3b4SDavid Woodhouse 10578626d3b4SDavid Woodhouse return 1; 10588626d3b4SDavid Woodhouse } 10598626d3b4SDavid Woodhouse 1060bf54a2b3SGeert Uytterhoeven /* Looks like: zorro:iN. */ 10616543becfSAndreas Schwab static int do_zorro_entry(const char *filename, void *symval, 1062bf54a2b3SGeert Uytterhoeven char *alias) 1063bf54a2b3SGeert Uytterhoeven { 10646543becfSAndreas Schwab DEF_FIELD(symval, zorro_device_id, id); 1065bf54a2b3SGeert Uytterhoeven strcpy(alias, "zorro:"); 10666543becfSAndreas Schwab ADD(alias, "i", id != ZORRO_WILDCARD, id); 1067bf54a2b3SGeert Uytterhoeven return 1; 1068bf54a2b3SGeert Uytterhoeven } 1069bf54a2b3SGeert Uytterhoeven 1070fedb3d27SOndrej Zary /* looks like: "pnp:dD" */ 1071fedb3d27SOndrej Zary static int do_isapnp_entry(const char *filename, 10726543becfSAndreas Schwab void *symval, char *alias) 1073fedb3d27SOndrej Zary { 10746543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, vendor); 10756543becfSAndreas Schwab DEF_FIELD(symval, isapnp_device_id, function); 1076fedb3d27SOndrej Zary sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", 10776543becfSAndreas Schwab 'A' + ((vendor >> 2) & 0x3f) - 1, 10786543becfSAndreas Schwab 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 10796543becfSAndreas Schwab 'A' + ((vendor >> 8) & 0x1f) - 1, 10806543becfSAndreas Schwab (function >> 4) & 0x0f, function & 0x0f, 10816543becfSAndreas Schwab (function >> 12) & 0x0f, (function >> 8) & 0x0f); 1082fedb3d27SOndrej Zary return 1; 1083fedb3d27SOndrej Zary } 1084fedb3d27SOndrej Zary 1085849e0ad2SJens Taprogge /* Looks like: "ipack:fNvNdN". */ 1086849e0ad2SJens Taprogge static int do_ipack_entry(const char *filename, 10876543becfSAndreas Schwab void *symval, char *alias) 1088849e0ad2SJens Taprogge { 10896543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, format); 10906543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, vendor); 10916543becfSAndreas Schwab DEF_FIELD(symval, ipack_device_id, device); 1092849e0ad2SJens Taprogge strcpy(alias, "ipack:"); 10936543becfSAndreas Schwab ADD(alias, "f", format != IPACK_ANY_FORMAT, format); 10946543becfSAndreas Schwab ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); 10956543becfSAndreas Schwab ADD(alias, "d", device != IPACK_ANY_ID, device); 1096849e0ad2SJens Taprogge add_wildcard(alias); 1097849e0ad2SJens Taprogge return 1; 1098849e0ad2SJens Taprogge } 1099849e0ad2SJens Taprogge 1100523817bdSDave Martin /* 1101523817bdSDave Martin * Append a match expression for a single masked hex digit. 1102523817bdSDave Martin * outp points to a pointer to the character at which to append. 1103523817bdSDave Martin * *outp is updated on return to point just after the appended text, 1104523817bdSDave Martin * to facilitate further appending. 1105523817bdSDave Martin */ 1106523817bdSDave Martin static void append_nibble_mask(char **outp, 1107523817bdSDave Martin unsigned int nibble, unsigned int mask) 1108523817bdSDave Martin { 1109523817bdSDave Martin char *p = *outp; 1110523817bdSDave Martin unsigned int i; 1111523817bdSDave Martin 1112523817bdSDave Martin switch (mask) { 1113523817bdSDave Martin case 0: 1114523817bdSDave Martin *p++ = '?'; 1115523817bdSDave Martin break; 1116523817bdSDave Martin 1117523817bdSDave Martin case 0xf: 1118523817bdSDave Martin p += sprintf(p, "%X", nibble); 1119523817bdSDave Martin break; 1120523817bdSDave Martin 1121523817bdSDave Martin default: 1122523817bdSDave Martin /* 1123523817bdSDave Martin * Dumbly emit a match pattern for all possible matching 1124523817bdSDave Martin * digits. This could be improved in some cases using ranges, 1125523817bdSDave Martin * but it has the advantage of being trivially correct, and is 1126523817bdSDave Martin * often optimal. 1127523817bdSDave Martin */ 1128523817bdSDave Martin *p++ = '['; 1129523817bdSDave Martin for (i = 0; i < 0x10; i++) 1130523817bdSDave Martin if ((i & mask) == nibble) 1131523817bdSDave Martin p += sprintf(p, "%X", i); 1132523817bdSDave Martin *p++ = ']'; 1133523817bdSDave Martin } 1134523817bdSDave Martin 1135523817bdSDave Martin /* Ensure that the string remains NUL-terminated: */ 1136523817bdSDave Martin *p = '\0'; 1137523817bdSDave Martin 1138523817bdSDave Martin /* Advance the caller's end-of-string pointer: */ 1139523817bdSDave Martin *outp = p; 1140523817bdSDave Martin } 1141523817bdSDave Martin 1142523817bdSDave Martin /* 1143523817bdSDave Martin * looks like: "amba:dN" 1144523817bdSDave Martin * 1145523817bdSDave Martin * N is exactly 8 digits, where each is an upper-case hex digit, or 1146523817bdSDave Martin * a ? or [] pattern matching exactly one digit. 1147523817bdSDave Martin */ 1148523817bdSDave Martin static int do_amba_entry(const char *filename, 11496543becfSAndreas Schwab void *symval, char *alias) 1150523817bdSDave Martin { 1151523817bdSDave Martin unsigned int digit; 1152523817bdSDave Martin char *p = alias; 11536543becfSAndreas Schwab DEF_FIELD(symval, amba_id, id); 11546543becfSAndreas Schwab DEF_FIELD(symval, amba_id, mask); 1155523817bdSDave Martin 11566543becfSAndreas Schwab if ((id & mask) != id) 1157523817bdSDave Martin fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " 1158523817bdSDave Martin "id=0x%08X, mask=0x%08X. Please fix this driver.\n", 11596543becfSAndreas Schwab filename, id, mask); 1160523817bdSDave Martin 1161523817bdSDave Martin p += sprintf(alias, "amba:d"); 1162523817bdSDave Martin for (digit = 0; digit < 8; digit++) 1163523817bdSDave Martin append_nibble_mask(&p, 11646543becfSAndreas Schwab (id >> (4 * (7 - digit))) & 0xf, 11656543becfSAndreas Schwab (mask >> (4 * (7 - digit))) & 0xf); 1166523817bdSDave Martin 1167523817bdSDave Martin return 1; 1168523817bdSDave Martin } 1169523817bdSDave Martin 11708286ae03SJames Hogan /* 11718286ae03SJames Hogan * looks like: "mipscdmm:tN" 11728286ae03SJames Hogan * 11738286ae03SJames Hogan * N is exactly 2 digits, where each is an upper-case hex digit, or 11748286ae03SJames Hogan * a ? or [] pattern matching exactly one digit. 11758286ae03SJames Hogan */ 11768286ae03SJames Hogan static int do_mips_cdmm_entry(const char *filename, 11778286ae03SJames Hogan void *symval, char *alias) 11788286ae03SJames Hogan { 11798286ae03SJames Hogan DEF_FIELD(symval, mips_cdmm_device_id, type); 11808286ae03SJames Hogan 11818286ae03SJames Hogan sprintf(alias, "mipscdmm:t%02X*", type); 11828286ae03SJames Hogan return 1; 11838286ae03SJames Hogan } 11848286ae03SJames Hogan 11852b9c1f03SArd Biesheuvel /* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* 1186644e9cbbSAndi Kleen * All fields are numbers. It would be nicer to use strings for vendor 1187644e9cbbSAndi Kleen * and feature, but getting those out of the build system here is too 1188644e9cbbSAndi Kleen * complicated. 1189644e9cbbSAndi Kleen */ 1190644e9cbbSAndi Kleen 11916543becfSAndreas Schwab static int do_x86cpu_entry(const char *filename, void *symval, 1192644e9cbbSAndi Kleen char *alias) 1193644e9cbbSAndi Kleen { 11946543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, feature); 11956543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, family); 11966543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, model); 11976543becfSAndreas Schwab DEF_FIELD(symval, x86_cpu_id, vendor); 1198644e9cbbSAndi Kleen 11992b9c1f03SArd Biesheuvel strcpy(alias, "cpu:type:x86,"); 12002b9c1f03SArd Biesheuvel ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); 12012b9c1f03SArd Biesheuvel ADD(alias, "fam", family != X86_FAMILY_ANY, family); 12022b9c1f03SArd Biesheuvel ADD(alias, "mod", model != X86_MODEL_ANY, model); 12035467bddaSBen Hutchings strcat(alias, ":feature:*"); 12046543becfSAndreas Schwab if (feature != X86_FEATURE_ANY) 12056543becfSAndreas Schwab sprintf(alias + strlen(alias), "%04X*", feature); 1206644e9cbbSAndi Kleen return 1; 1207644e9cbbSAndi Kleen } 1208644e9cbbSAndi Kleen 120967bad2fdSArd Biesheuvel /* LOOKS like cpu:type:*:feature:*FEAT* */ 121067bad2fdSArd Biesheuvel static int do_cpu_entry(const char *filename, void *symval, char *alias) 121167bad2fdSArd Biesheuvel { 121267bad2fdSArd Biesheuvel DEF_FIELD(symval, cpu_feature, feature); 121367bad2fdSArd Biesheuvel 121467bad2fdSArd Biesheuvel sprintf(alias, "cpu:type:*:feature:*%04X*", feature); 121567bad2fdSArd Biesheuvel return 1; 121667bad2fdSArd Biesheuvel } 121767bad2fdSArd Biesheuvel 1218b26864caSTomas Winkler /* Looks like: mei:S:uuid:N:* */ 1219e5354107SSamuel Ortiz static int do_mei_entry(const char *filename, void *symval, 1220e5354107SSamuel Ortiz char *alias) 1221e5354107SSamuel Ortiz { 1222e5354107SSamuel Ortiz DEF_FIELD_ADDR(symval, mei_cl_device_id, name); 1223c93b76b3STomas Winkler DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid); 1224b26864caSTomas Winkler DEF_FIELD(symval, mei_cl_device_id, version); 1225e5354107SSamuel Ortiz 1226c93b76b3STomas Winkler sprintf(alias, MEI_CL_MODULE_PREFIX); 1227c93b76b3STomas Winkler sprintf(alias + strlen(alias), "%s:", (*name)[0] ? *name : "*"); 1228c93b76b3STomas Winkler add_uuid(alias, *uuid); 1229b26864caSTomas Winkler ADD(alias, ":", version != MEI_CL_VERSION_ANY, version); 1230c93b76b3STomas Winkler 1231c93b76b3STomas Winkler strcat(alias, ":*"); 1232e5354107SSamuel Ortiz 1233e5354107SSamuel Ortiz return 1; 1234e5354107SSamuel Ortiz } 1235e5354107SSamuel Ortiz 12363bdbb62fSAlexandre Bounine /* Looks like: rapidio:vNdNavNadN */ 12373bdbb62fSAlexandre Bounine static int do_rio_entry(const char *filename, 12383bdbb62fSAlexandre Bounine void *symval, char *alias) 12393bdbb62fSAlexandre Bounine { 12403bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, did); 12413bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, vid); 12423bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_did); 12433bdbb62fSAlexandre Bounine DEF_FIELD(symval, rio_device_id, asm_vid); 12443bdbb62fSAlexandre Bounine 12453bdbb62fSAlexandre Bounine strcpy(alias, "rapidio:"); 12463bdbb62fSAlexandre Bounine ADD(alias, "v", vid != RIO_ANY_ID, vid); 12473bdbb62fSAlexandre Bounine ADD(alias, "d", did != RIO_ANY_ID, did); 12483bdbb62fSAlexandre Bounine ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); 12493bdbb62fSAlexandre Bounine ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); 12503bdbb62fSAlexandre Bounine 12513bdbb62fSAlexandre Bounine add_wildcard(alias); 12523bdbb62fSAlexandre Bounine return 1; 12533bdbb62fSAlexandre Bounine } 12543bdbb62fSAlexandre Bounine 1255289fcff4SHeikki Krogerus /* Looks like: ulpi:vNpN */ 1256289fcff4SHeikki Krogerus static int do_ulpi_entry(const char *filename, void *symval, 1257289fcff4SHeikki Krogerus char *alias) 1258289fcff4SHeikki Krogerus { 1259289fcff4SHeikki Krogerus DEF_FIELD(symval, ulpi_device_id, vendor); 1260289fcff4SHeikki Krogerus DEF_FIELD(symval, ulpi_device_id, product); 1261289fcff4SHeikki Krogerus 1262289fcff4SHeikki Krogerus sprintf(alias, "ulpi:v%04xp%04x", vendor, product); 1263289fcff4SHeikki Krogerus 1264289fcff4SHeikki Krogerus return 1; 1265289fcff4SHeikki Krogerus } 1266289fcff4SHeikki Krogerus 1267da23ac1eSSubhransu S. Prusty /* Looks like: hdaudio:vNrNaN */ 1268da23ac1eSSubhransu S. Prusty static int do_hda_entry(const char *filename, void *symval, char *alias) 1269da23ac1eSSubhransu S. Prusty { 1270da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, vendor_id); 1271da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, rev_id); 1272da23ac1eSSubhransu S. Prusty DEF_FIELD(symval, hda_device_id, api_version); 1273da23ac1eSSubhransu S. Prusty 1274da23ac1eSSubhransu S. Prusty strcpy(alias, "hdaudio:"); 1275da23ac1eSSubhransu S. Prusty ADD(alias, "v", vendor_id != 0, vendor_id); 1276da23ac1eSSubhransu S. Prusty ADD(alias, "r", rev_id != 0, rev_id); 1277da23ac1eSSubhransu S. Prusty ADD(alias, "a", api_version != 0, api_version); 1278da23ac1eSSubhransu S. Prusty 1279da23ac1eSSubhransu S. Prusty add_wildcard(alias); 1280da23ac1eSSubhransu S. Prusty return 1; 1281da23ac1eSSubhransu S. Prusty } 1282da23ac1eSSubhransu S. Prusty 1283b5924268SPierre-Louis Bossart /* Looks like: sdw:mNpNvNcN */ 12849251345dSVinod Koul static int do_sdw_entry(const char *filename, void *symval, char *alias) 12859251345dSVinod Koul { 12869251345dSVinod Koul DEF_FIELD(symval, sdw_device_id, mfg_id); 12879251345dSVinod Koul DEF_FIELD(symval, sdw_device_id, part_id); 1288b5924268SPierre-Louis Bossart DEF_FIELD(symval, sdw_device_id, sdw_version); 1289b5924268SPierre-Louis Bossart DEF_FIELD(symval, sdw_device_id, class_id); 12909251345dSVinod Koul 12919251345dSVinod Koul strcpy(alias, "sdw:"); 12929251345dSVinod Koul ADD(alias, "m", mfg_id != 0, mfg_id); 12939251345dSVinod Koul ADD(alias, "p", part_id != 0, part_id); 1294b5924268SPierre-Louis Bossart ADD(alias, "v", sdw_version != 0, sdw_version); 1295b5924268SPierre-Louis Bossart ADD(alias, "c", class_id != 0, class_id); 12969251345dSVinod Koul 12979251345dSVinod Koul add_wildcard(alias); 12989251345dSVinod Koul return 1; 12999251345dSVinod Koul } 13009251345dSVinod Koul 13010afef456SStuart Yoder /* Looks like: fsl-mc:vNdN */ 13020afef456SStuart Yoder static int do_fsl_mc_entry(const char *filename, void *symval, 13030afef456SStuart Yoder char *alias) 13040afef456SStuart Yoder { 13050afef456SStuart Yoder DEF_FIELD(symval, fsl_mc_device_id, vendor); 13060afef456SStuart Yoder DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); 13070afef456SStuart Yoder 13080afef456SStuart Yoder sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); 13090afef456SStuart Yoder return 1; 13100afef456SStuart Yoder } 13110afef456SStuart Yoder 1312d1ff7024SMika Westerberg /* Looks like: tbsvc:kSpNvNrN */ 1313d1ff7024SMika Westerberg static int do_tbsvc_entry(const char *filename, void *symval, char *alias) 1314d1ff7024SMika Westerberg { 1315d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, match_flags); 1316d1ff7024SMika Westerberg DEF_FIELD_ADDR(symval, tb_service_id, protocol_key); 1317d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_id); 1318d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_version); 1319d1ff7024SMika Westerberg DEF_FIELD(symval, tb_service_id, protocol_revision); 1320d1ff7024SMika Westerberg 1321d1ff7024SMika Westerberg strcpy(alias, "tbsvc:"); 1322d1ff7024SMika Westerberg if (match_flags & TBSVC_MATCH_PROTOCOL_KEY) 1323d1ff7024SMika Westerberg sprintf(alias + strlen(alias), "k%s", *protocol_key); 1324d1ff7024SMika Westerberg else 1325d1ff7024SMika Westerberg strcat(alias + strlen(alias), "k*"); 1326d1ff7024SMika Westerberg ADD(alias, "p", match_flags & TBSVC_MATCH_PROTOCOL_ID, protocol_id); 1327d1ff7024SMika Westerberg ADD(alias, "v", match_flags & TBSVC_MATCH_PROTOCOL_VERSION, 1328d1ff7024SMika Westerberg protocol_version); 1329d1ff7024SMika Westerberg ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION, 1330d1ff7024SMika Westerberg protocol_revision); 1331d1ff7024SMika Westerberg 1332d1ff7024SMika Westerberg add_wildcard(alias); 1333d1ff7024SMika Westerberg return 1; 1334d1ff7024SMika Westerberg } 1335d1ff7024SMika Westerberg 13368a37d87dSHeikki Krogerus /* Looks like: typec:idNmN */ 13378a37d87dSHeikki Krogerus static int do_typec_entry(const char *filename, void *symval, char *alias) 13388a37d87dSHeikki Krogerus { 13398a37d87dSHeikki Krogerus DEF_FIELD(symval, typec_device_id, svid); 13408a37d87dSHeikki Krogerus DEF_FIELD(symval, typec_device_id, mode); 13418a37d87dSHeikki Krogerus 13428a37d87dSHeikki Krogerus sprintf(alias, "typec:id%04X", svid); 13438a37d87dSHeikki Krogerus ADD(alias, "m", mode != TYPEC_ANY_MODE, mode); 13448a37d87dSHeikki Krogerus 13458a37d87dSHeikki Krogerus return 1; 13468a37d87dSHeikki Krogerus } 13478a37d87dSHeikki Krogerus 13480fc1db9dSSumit Garg /* Looks like: tee:uuid */ 13490fc1db9dSSumit Garg static int do_tee_entry(const char *filename, void *symval, char *alias) 13500fc1db9dSSumit Garg { 13510fc1db9dSSumit Garg DEF_FIELD(symval, tee_client_device_id, uuid); 13520fc1db9dSSumit Garg 13530fc1db9dSSumit Garg sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 13540fc1db9dSSumit Garg uuid.b[0], uuid.b[1], uuid.b[2], uuid.b[3], uuid.b[4], 13550fc1db9dSSumit Garg uuid.b[5], uuid.b[6], uuid.b[7], uuid.b[8], uuid.b[9], 13560fc1db9dSSumit Garg uuid.b[10], uuid.b[11], uuid.b[12], uuid.b[13], uuid.b[14], 13570fc1db9dSSumit Garg uuid.b[15]); 13580fc1db9dSSumit Garg 13590fc1db9dSSumit Garg add_wildcard(alias); 13600fc1db9dSSumit Garg return 1; 13610fc1db9dSSumit Garg } 13620fc1db9dSSumit Garg 13630bc44b2bSMattias Jacobsson /* Looks like: wmi:guid */ 13640bc44b2bSMattias Jacobsson static int do_wmi_entry(const char *filename, void *symval, char *alias) 13650bc44b2bSMattias Jacobsson { 13660bc44b2bSMattias Jacobsson int len; 13670bc44b2bSMattias Jacobsson DEF_FIELD_ADDR(symval, wmi_device_id, guid_string); 13680bc44b2bSMattias Jacobsson 13690bc44b2bSMattias Jacobsson if (strlen(*guid_string) != UUID_STRING_LEN) { 13700bc44b2bSMattias Jacobsson warn("Invalid WMI device id 'wmi:%s' in '%s'\n", 13710bc44b2bSMattias Jacobsson *guid_string, filename); 13720bc44b2bSMattias Jacobsson return 0; 13730bc44b2bSMattias Jacobsson } 13740bc44b2bSMattias Jacobsson 13750bc44b2bSMattias Jacobsson len = snprintf(alias, ALIAS_SIZE, WMI_MODULE_PREFIX "%s", *guid_string); 13760bc44b2bSMattias Jacobsson if (len < 0 || len >= ALIAS_SIZE) { 13770bc44b2bSMattias Jacobsson warn("Could not generate all MODULE_ALIAS's in '%s'\n", 13780bc44b2bSMattias Jacobsson filename); 13790bc44b2bSMattias Jacobsson return 0; 13800bc44b2bSMattias Jacobsson } 13810bc44b2bSMattias Jacobsson return 1; 13820bc44b2bSMattias Jacobsson } 13830bc44b2bSMattias Jacobsson 1384e6b0de46SManivannan Sadhasivam /* Looks like: mhi:S */ 1385e6b0de46SManivannan Sadhasivam static int do_mhi_entry(const char *filename, void *symval, char *alias) 1386e6b0de46SManivannan Sadhasivam { 1387e6b0de46SManivannan Sadhasivam DEF_FIELD_ADDR(symval, mhi_device_id, chan); 1388e6b0de46SManivannan Sadhasivam sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan); 13897de3697eSDave Ertman return 1; 13907de3697eSDave Ertman } 13917de3697eSDave Ertman 1392c268c0a8SManivannan Sadhasivam /* Looks like: mhi_ep:S */ 1393c268c0a8SManivannan Sadhasivam static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) 1394c268c0a8SManivannan Sadhasivam { 1395c268c0a8SManivannan Sadhasivam DEF_FIELD_ADDR(symval, mhi_device_id, chan); 1396c268c0a8SManivannan Sadhasivam sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan); 1397c268c0a8SManivannan Sadhasivam 1398c268c0a8SManivannan Sadhasivam return 1; 1399c268c0a8SManivannan Sadhasivam } 1400c268c0a8SManivannan Sadhasivam 1401fa443bc3SThomas Weißschuh /* Looks like: ishtp:{guid} */ 1402fa443bc3SThomas Weißschuh static int do_ishtp_entry(const char *filename, void *symval, char *alias) 1403fa443bc3SThomas Weißschuh { 1404fa443bc3SThomas Weißschuh DEF_FIELD(symval, ishtp_device_id, guid); 1405fa443bc3SThomas Weißschuh 1406fa443bc3SThomas Weißschuh strcpy(alias, ISHTP_MODULE_PREFIX "{"); 1407fa443bc3SThomas Weißschuh add_guid(alias, guid); 1408fa443bc3SThomas Weißschuh strcat(alias, "}"); 1409fa443bc3SThomas Weißschuh 1410fa443bc3SThomas Weißschuh return 1; 1411fa443bc3SThomas Weißschuh } 1412fa443bc3SThomas Weißschuh 14137de3697eSDave Ertman static int do_auxiliary_entry(const char *filename, void *symval, char *alias) 14147de3697eSDave Ertman { 14157de3697eSDave Ertman DEF_FIELD_ADDR(symval, auxiliary_device_id, name); 14167de3697eSDave Ertman sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name); 1417e6b0de46SManivannan Sadhasivam 1418e6b0de46SManivannan Sadhasivam return 1; 1419e6b0de46SManivannan Sadhasivam } 1420e6b0de46SManivannan Sadhasivam 1421eb0e90a8SMaximilian Luz /* 1422eb0e90a8SMaximilian Luz * Looks like: ssam:dNcNtNiNfN 1423eb0e90a8SMaximilian Luz * 1424eb0e90a8SMaximilian Luz * N is exactly 2 digits, where each is an upper-case hex digit. 1425eb0e90a8SMaximilian Luz */ 1426eb0e90a8SMaximilian Luz static int do_ssam_entry(const char *filename, void *symval, char *alias) 1427eb0e90a8SMaximilian Luz { 1428eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, match_flags); 1429eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, domain); 1430eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, category); 1431eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, target); 1432eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, instance); 1433eb0e90a8SMaximilian Luz DEF_FIELD(symval, ssam_device_id, function); 1434eb0e90a8SMaximilian Luz 1435eb0e90a8SMaximilian Luz sprintf(alias, "ssam:d%02Xc%02X", domain, category); 1436eb0e90a8SMaximilian Luz ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target); 1437eb0e90a8SMaximilian Luz ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); 1438eb0e90a8SMaximilian Luz ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); 1439eb0e90a8SMaximilian Luz 1440eb0e90a8SMaximilian Luz return 1; 1441eb0e90a8SMaximilian Luz } 1442eb0e90a8SMaximilian Luz 14434a224aceSXu Yilun /* Looks like: dfl:tNfN */ 14444a224aceSXu Yilun static int do_dfl_entry(const char *filename, void *symval, char *alias) 14454a224aceSXu Yilun { 14464a224aceSXu Yilun DEF_FIELD(symval, dfl_device_id, type); 14474a224aceSXu Yilun DEF_FIELD(symval, dfl_device_id, feature_id); 14484a224aceSXu Yilun 14494a224aceSXu Yilun sprintf(alias, "dfl:t%04Xf%04X", type, feature_id); 14504a224aceSXu Yilun 14514a224aceSXu Yilun add_wildcard(alias); 14524a224aceSXu Yilun return 1; 14534a224aceSXu Yilun } 14544a224aceSXu Yilun 1455626596e2SRusty Russell /* Does namelen bytes of name exactly match the symbol? */ 1456626596e2SRusty Russell static bool sym_is(const char *name, unsigned namelen, const char *symbol) 14571da177e4SLinus Torvalds { 1458626596e2SRusty Russell if (namelen != strlen(symbol)) 1459626596e2SRusty Russell return false; 14601da177e4SLinus Torvalds 1461626596e2SRusty Russell return memcmp(name, symbol, namelen) == 0; 14621da177e4SLinus Torvalds } 14631da177e4SLinus Torvalds 14641da177e4SLinus Torvalds static void do_table(void *symval, unsigned long size, 14651da177e4SLinus Torvalds unsigned long id_size, 1466fb33d816SSam Ravnborg const char *device_id, 1467f880eea6SMasahiro Yamada int (*do_entry)(const char *filename, void *symval, char *alias), 14681da177e4SLinus Torvalds struct module *mod) 14691da177e4SLinus Torvalds { 14701da177e4SLinus Torvalds unsigned int i; 1471841f1b8fSMattias Jacobsson char alias[ALIAS_SIZE]; 14721da177e4SLinus Torvalds 1473e0049825SKees Cook device_id_check(mod->name, device_id, size, id_size, symval); 14741da177e4SLinus Torvalds /* Leave last one: it's the terminator. */ 14751da177e4SLinus Torvalds size -= id_size; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds for (i = 0; i < size; i += id_size) { 14781da177e4SLinus Torvalds if (do_entry(mod->name, symval+i, alias)) { 14791da177e4SLinus Torvalds buf_printf(&mod->dev_table_buf, 14801da177e4SLinus Torvalds "MODULE_ALIAS(\"%s\");\n", alias); 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds } 14841da177e4SLinus Torvalds 1485ec91e78dSMasahiro Yamada static const struct devtable devtable[] = { 1486ec91e78dSMasahiro Yamada {"hid", SIZE_hid_device_id, do_hid_entry}, 1487ec91e78dSMasahiro Yamada {"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry}, 1488ec91e78dSMasahiro Yamada {"pci", SIZE_pci_device_id, do_pci_entry}, 1489ec91e78dSMasahiro Yamada {"ccw", SIZE_ccw_device_id, do_ccw_entry}, 1490ec91e78dSMasahiro Yamada {"ap", SIZE_ap_device_id, do_ap_entry}, 1491ec91e78dSMasahiro Yamada {"css", SIZE_css_device_id, do_css_entry}, 1492ec91e78dSMasahiro Yamada {"serio", SIZE_serio_device_id, do_serio_entry}, 1493ec91e78dSMasahiro Yamada {"acpi", SIZE_acpi_device_id, do_acpi_entry}, 1494ec91e78dSMasahiro Yamada {"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry}, 1495ec91e78dSMasahiro Yamada {"vio", SIZE_vio_device_id, do_vio_entry}, 1496ec91e78dSMasahiro Yamada {"input", SIZE_input_device_id, do_input_entry}, 1497ec91e78dSMasahiro Yamada {"eisa", SIZE_eisa_device_id, do_eisa_entry}, 1498ec91e78dSMasahiro Yamada {"parisc", SIZE_parisc_device_id, do_parisc_entry}, 1499ec91e78dSMasahiro Yamada {"sdio", SIZE_sdio_device_id, do_sdio_entry}, 1500ec91e78dSMasahiro Yamada {"ssb", SIZE_ssb_device_id, do_ssb_entry}, 1501ec91e78dSMasahiro Yamada {"bcma", SIZE_bcma_device_id, do_bcma_entry}, 1502ec91e78dSMasahiro Yamada {"virtio", SIZE_virtio_device_id, do_virtio_entry}, 1503ec91e78dSMasahiro Yamada {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry}, 1504ec91e78dSMasahiro Yamada {"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry}, 1505ec91e78dSMasahiro Yamada {"i2c", SIZE_i2c_device_id, do_i2c_entry}, 15061ce589adSBoris Brezillon {"i3c", SIZE_i3c_device_id, do_i3c_entry}, 1507ec91e78dSMasahiro Yamada {"spi", SIZE_spi_device_id, do_spi_entry}, 1508ec91e78dSMasahiro Yamada {"dmi", SIZE_dmi_system_id, do_dmi_entry}, 1509ec91e78dSMasahiro Yamada {"platform", SIZE_platform_device_id, do_platform_entry}, 1510ec91e78dSMasahiro Yamada {"mdio", SIZE_mdio_device_id, do_mdio_entry}, 1511ec91e78dSMasahiro Yamada {"zorro", SIZE_zorro_device_id, do_zorro_entry}, 1512ec91e78dSMasahiro Yamada {"isapnp", SIZE_isapnp_device_id, do_isapnp_entry}, 1513ec91e78dSMasahiro Yamada {"ipack", SIZE_ipack_device_id, do_ipack_entry}, 1514ec91e78dSMasahiro Yamada {"amba", SIZE_amba_id, do_amba_entry}, 1515ec91e78dSMasahiro Yamada {"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry}, 1516ec91e78dSMasahiro Yamada {"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry}, 1517ec91e78dSMasahiro Yamada {"cpu", SIZE_cpu_feature, do_cpu_entry}, 1518ec91e78dSMasahiro Yamada {"mei", SIZE_mei_cl_device_id, do_mei_entry}, 1519ec91e78dSMasahiro Yamada {"rapidio", SIZE_rio_device_id, do_rio_entry}, 1520ec91e78dSMasahiro Yamada {"ulpi", SIZE_ulpi_device_id, do_ulpi_entry}, 1521ec91e78dSMasahiro Yamada {"hdaudio", SIZE_hda_device_id, do_hda_entry}, 1522ec91e78dSMasahiro Yamada {"sdw", SIZE_sdw_device_id, do_sdw_entry}, 1523ec91e78dSMasahiro Yamada {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, 1524ec91e78dSMasahiro Yamada {"tbsvc", SIZE_tb_service_id, do_tbsvc_entry}, 1525ec91e78dSMasahiro Yamada {"typec", SIZE_typec_device_id, do_typec_entry}, 15260fc1db9dSSumit Garg {"tee", SIZE_tee_client_device_id, do_tee_entry}, 15270bc44b2bSMattias Jacobsson {"wmi", SIZE_wmi_device_id, do_wmi_entry}, 1528e6b0de46SManivannan Sadhasivam {"mhi", SIZE_mhi_device_id, do_mhi_entry}, 1529c268c0a8SManivannan Sadhasivam {"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry}, 15307de3697eSDave Ertman {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, 1531eb0e90a8SMaximilian Luz {"ssam", SIZE_ssam_device_id, do_ssam_entry}, 15324a224aceSXu Yilun {"dfl", SIZE_dfl_device_id, do_dfl_entry}, 1533fa443bc3SThomas Weißschuh {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, 1534ec91e78dSMasahiro Yamada }; 1535ec91e78dSMasahiro Yamada 15361da177e4SLinus Torvalds /* Create MODULE_ALIAS() statements. 15371da177e4SLinus Torvalds * At this time, we cannot write the actual output C source yet, 15381da177e4SLinus Torvalds * so we write into the mod->dev_table_buf buffer. */ 15391da177e4SLinus Torvalds void handle_moddevtable(struct module *mod, struct elf_info *info, 15401da177e4SLinus Torvalds Elf_Sym *sym, const char *symname) 15411da177e4SLinus Torvalds { 15421da177e4SLinus Torvalds void *symval; 1543e0049825SKees Cook char *zeros = NULL; 154421bdd17bSTom Gundersen const char *name, *identifier; 1545626596e2SRusty Russell unsigned int namelen; 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds /* We're looking for a section relative symbol */ 15481ce53adfSDenys Vlasenko if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) 15491da177e4SLinus Torvalds return; 15501da177e4SLinus Torvalds 1551e88aa7bbSDavid Miller /* We're looking for an object */ 1552e88aa7bbSDavid Miller if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 1553e88aa7bbSDavid Miller return; 1554e88aa7bbSDavid Miller 1555153e04b3SMasahiro Yamada /* All our symbols are of form __mod_<name>__<identifier>_device_table. */ 1556153e04b3SMasahiro Yamada if (strncmp(symname, "__mod_", strlen("__mod_"))) 1557626596e2SRusty Russell return; 1558153e04b3SMasahiro Yamada name = symname + strlen("__mod_"); 1559626596e2SRusty Russell namelen = strlen(name); 1560626596e2SRusty Russell if (namelen < strlen("_device_table")) 1561626596e2SRusty Russell return; 1562626596e2SRusty Russell if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) 1563626596e2SRusty Russell return; 156421bdd17bSTom Gundersen identifier = strstr(name, "__"); 156521bdd17bSTom Gundersen if (!identifier) 156621bdd17bSTom Gundersen return; 156721bdd17bSTom Gundersen namelen = identifier - name; 1568626596e2SRusty Russell 1569e0049825SKees Cook /* Handle all-NULL symbols allocated into .bss */ 15701ce53adfSDenys Vlasenko if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { 1571e0049825SKees Cook zeros = calloc(1, sym->st_size); 1572e0049825SKees Cook symval = zeros; 1573e0049825SKees Cook } else { 1574*abe864b8SMasahiro Yamada symval = sym_get_data(info, sym); 1575e0049825SKees Cook } 15761da177e4SLinus Torvalds 1577626596e2SRusty Russell /* First handle the "special" cases */ 1578626596e2SRusty Russell if (sym_is(name, namelen, "usb")) 1579b19dcd93SRoman Kagan do_usb_table(symval, sym->st_size, mod); 1580acbef7b7SPhilipp Zabel if (sym_is(name, namelen, "of")) 1581acbef7b7SPhilipp Zabel do_of_table(symval, sym->st_size, mod); 1582626596e2SRusty Russell else if (sym_is(name, namelen, "pnp")) 158322454cb9SKay Sievers do_pnp_device_entry(symval, sym->st_size, mod); 1584626596e2SRusty Russell else if (sym_is(name, namelen, "pnp_card")) 15850c81eed4SKay Sievers do_pnp_card_entries(symval, sym->st_size, mod); 1586626596e2SRusty Russell else { 1587ec91e78dSMasahiro Yamada int i; 1588626596e2SRusty Russell 1589ec91e78dSMasahiro Yamada for (i = 0; i < ARRAY_SIZE(devtable); i++) { 1590ec91e78dSMasahiro Yamada const struct devtable *p = &devtable[i]; 1591ec91e78dSMasahiro Yamada 1592ec91e78dSMasahiro Yamada if (sym_is(name, namelen, p->device_id)) { 1593ec91e78dSMasahiro Yamada do_table(symval, sym->st_size, p->id_size, 1594f880eea6SMasahiro Yamada p->device_id, p->do_entry, mod); 1595626596e2SRusty Russell break; 1596626596e2SRusty Russell } 1597626596e2SRusty Russell } 1598626596e2SRusty Russell } 1599e0049825SKees Cook free(zeros); 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds 16021da177e4SLinus Torvalds /* Now add out buffered information to the generated C source */ 16031da177e4SLinus Torvalds void add_moddevtable(struct buffer *buf, struct module *mod) 16041da177e4SLinus Torvalds { 16051da177e4SLinus Torvalds buf_printf(buf, "\n"); 16061da177e4SLinus Torvalds buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); 16071da177e4SLinus Torvalds free(mod->dev_table_buf.p); 16081da177e4SLinus Torvalds } 1609