162306a36Sopenharmony_ci/* Simple code to turn various tables in an ELF file into alias definitions.
262306a36Sopenharmony_ci * This deals with kernel datastructures where they should be
362306a36Sopenharmony_ci * dealt with: in the kernel source.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2002-2003  Rusty Russell, IBM Corporation
662306a36Sopenharmony_ci *           2003       Kai Germaschewski
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This software may be used and distributed according to the terms
1062306a36Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "modpost.h"
1462306a36Sopenharmony_ci#include "devicetable-offsets.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* We use the ELF typedefs for kernel_ulong_t but bite the bullet and
1762306a36Sopenharmony_ci * use either stdint.h or inttypes.h for the rest. */
1862306a36Sopenharmony_ci#if KERNEL_ELFCLASS == ELFCLASS32
1962306a36Sopenharmony_citypedef Elf32_Addr	kernel_ulong_t;
2062306a36Sopenharmony_ci#define BITS_PER_LONG 32
2162306a36Sopenharmony_ci#else
2262306a36Sopenharmony_citypedef Elf64_Addr	kernel_ulong_t;
2362306a36Sopenharmony_ci#define BITS_PER_LONG 64
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci#ifdef __sun__
2662306a36Sopenharmony_ci#include <inttypes.h>
2762306a36Sopenharmony_ci#else
2862306a36Sopenharmony_ci#include <stdint.h>
2962306a36Sopenharmony_ci#endif
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <ctype.h>
3262306a36Sopenharmony_ci#include <stdbool.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_citypedef uint32_t	__u32;
3562306a36Sopenharmony_citypedef uint16_t	__u16;
3662306a36Sopenharmony_citypedef unsigned char	__u8;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* UUID types for backward compatibility, don't use in new code */
3962306a36Sopenharmony_citypedef struct {
4062306a36Sopenharmony_ci	__u8 b[16];
4162306a36Sopenharmony_ci} guid_t;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_citypedef struct {
4462306a36Sopenharmony_ci	__u8 b[16];
4562306a36Sopenharmony_ci} uuid_t;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define	UUID_STRING_LEN		36
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* MEI UUID type, don't use anywhere else */
5062306a36Sopenharmony_citypedef struct {
5162306a36Sopenharmony_ci	__u8 b[16];
5262306a36Sopenharmony_ci} uuid_le;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* Big exception to the "don't include kernel headers into userspace, which
5562306a36Sopenharmony_ci * even potentially has different endianness and word sizes, since
5662306a36Sopenharmony_ci * we handle those differences explicitly below */
5762306a36Sopenharmony_ci#include "../../include/linux/mod_devicetable.h"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* This array collects all instances that use the generic do_table */
6062306a36Sopenharmony_cistruct devtable {
6162306a36Sopenharmony_ci	const char *device_id; /* name of table, __mod_<name>__*_device_table. */
6262306a36Sopenharmony_ci	unsigned long id_size;
6362306a36Sopenharmony_ci	int (*do_entry)(const char *filename, void *symval, char *alias);
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Size of alias provided to do_entry functions */
6762306a36Sopenharmony_ci#define ALIAS_SIZE 500
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Define a variable f that holds the value of field f of struct devid
7062306a36Sopenharmony_ci * based at address m.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_ci#define DEF_FIELD(m, devid, f) \
7362306a36Sopenharmony_ci	typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* Define a variable v that holds the address of field f of struct devid
7662306a36Sopenharmony_ci * based at address m.  Due to the way typeof works, for a field of type
7762306a36Sopenharmony_ci * T[N] the variable has type T(*)[N], _not_ T*.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ci#define DEF_FIELD_ADDR_VAR(m, devid, f, v) \
8062306a36Sopenharmony_ci	typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Define a variable f that holds the address of field f of struct devid
8362306a36Sopenharmony_ci * based at address m.  Due to the way typeof works, for a field of type
8462306a36Sopenharmony_ci * T[N] the variable has type T(*)[N], _not_ T*.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci#define DEF_FIELD_ADDR(m, devid, f) \
8762306a36Sopenharmony_ci	DEF_FIELD_ADDR_VAR(m, devid, f, f)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define ADD(str, sep, cond, field)                              \
9062306a36Sopenharmony_cido {                                                            \
9162306a36Sopenharmony_ci        strcat(str, sep);                                       \
9262306a36Sopenharmony_ci        if (cond)                                               \
9362306a36Sopenharmony_ci                sprintf(str + strlen(str),                      \
9462306a36Sopenharmony_ci                        sizeof(field) == 1 ? "%02X" :           \
9562306a36Sopenharmony_ci                        sizeof(field) == 2 ? "%04X" :           \
9662306a36Sopenharmony_ci                        sizeof(field) == 4 ? "%08X" : "",       \
9762306a36Sopenharmony_ci                        field);                                 \
9862306a36Sopenharmony_ci        else                                                    \
9962306a36Sopenharmony_ci                sprintf(str + strlen(str), "*");                \
10062306a36Sopenharmony_ci} while(0)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/* End in a wildcard, for future extension */
10362306a36Sopenharmony_cistatic inline void add_wildcard(char *str)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	int len = strlen(str);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (str[len - 1] != '*')
10862306a36Sopenharmony_ci		strcat(str + len, "*");
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic inline void add_uuid(char *str, uuid_le uuid)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	int len = strlen(str);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	sprintf(str + len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
11662306a36Sopenharmony_ci		uuid.b[3], uuid.b[2], uuid.b[1], uuid.b[0],
11762306a36Sopenharmony_ci		uuid.b[5], uuid.b[4], uuid.b[7], uuid.b[6],
11862306a36Sopenharmony_ci		uuid.b[8], uuid.b[9], uuid.b[10], uuid.b[11],
11962306a36Sopenharmony_ci		uuid.b[12], uuid.b[13], uuid.b[14], uuid.b[15]);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic inline void add_guid(char *str, guid_t guid)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	int len = strlen(str);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	sprintf(str + len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
12762306a36Sopenharmony_ci		guid.b[3], guid.b[2], guid.b[1], guid.b[0],
12862306a36Sopenharmony_ci		guid.b[5], guid.b[4], guid.b[7], guid.b[6],
12962306a36Sopenharmony_ci		guid.b[8], guid.b[9], guid.b[10], guid.b[11],
13062306a36Sopenharmony_ci		guid.b[12], guid.b[13], guid.b[14], guid.b[15]);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/**
13462306a36Sopenharmony_ci * Check that sizeof(device_id type) are consistent with size of section
13562306a36Sopenharmony_ci * in .o file. If in-consistent then userspace and kernel does not agree
13662306a36Sopenharmony_ci * on actual size which is a bug.
13762306a36Sopenharmony_ci * Also verify that the final entry in the table is all zeros.
13862306a36Sopenharmony_ci * Ignore both checks if build host differ from target host and size differs.
13962306a36Sopenharmony_ci **/
14062306a36Sopenharmony_cistatic void device_id_check(const char *modname, const char *device_id,
14162306a36Sopenharmony_ci			    unsigned long size, unsigned long id_size,
14262306a36Sopenharmony_ci			    void *symval)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	int i;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (size % id_size || size < id_size) {
14762306a36Sopenharmony_ci		fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo of the size of section __mod_%s__<identifier>_device_table=%lu.\n"
14862306a36Sopenharmony_ci		      "Fix definition of struct %s_device_id in mod_devicetable.h\n",
14962306a36Sopenharmony_ci		      modname, device_id, id_size, device_id, size, device_id);
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	/* Verify last one is a terminator */
15262306a36Sopenharmony_ci	for (i = 0; i < id_size; i++ ) {
15362306a36Sopenharmony_ci		if (*(uint8_t*)(symval+size-id_size+i)) {
15462306a36Sopenharmony_ci			fprintf(stderr,
15562306a36Sopenharmony_ci				"%s: struct %s_device_id is %lu bytes.  The last of %lu is:\n",
15662306a36Sopenharmony_ci				modname, device_id, id_size, size / id_size);
15762306a36Sopenharmony_ci			for (i = 0; i < id_size; i++ )
15862306a36Sopenharmony_ci				fprintf(stderr,"0x%02x ",
15962306a36Sopenharmony_ci					*(uint8_t*)(symval+size-id_size+i) );
16062306a36Sopenharmony_ci			fprintf(stderr,"\n");
16162306a36Sopenharmony_ci			fatal("%s: struct %s_device_id is not terminated with a NULL entry!\n",
16262306a36Sopenharmony_ci			      modname, device_id);
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* USB is special because the bcdDevice can be matched against a numeric range */
16862306a36Sopenharmony_ci/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
16962306a36Sopenharmony_cistatic void do_usb_entry(void *symval,
17062306a36Sopenharmony_ci			 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
17162306a36Sopenharmony_ci			 unsigned char range_lo, unsigned char range_hi,
17262306a36Sopenharmony_ci			 unsigned char max, struct module *mod)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	char alias[500];
17562306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, match_flags);
17662306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, idVendor);
17762306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, idProduct);
17862306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bcdDevice_lo);
17962306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bDeviceClass);
18062306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bDeviceSubClass);
18162306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bDeviceProtocol);
18262306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bInterfaceClass);
18362306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bInterfaceSubClass);
18462306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bInterfaceProtocol);
18562306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bInterfaceNumber);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	strcpy(alias, "usb:");
18862306a36Sopenharmony_ci	ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR,
18962306a36Sopenharmony_ci	    idVendor);
19062306a36Sopenharmony_ci	ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
19162306a36Sopenharmony_ci	    idProduct);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	strcat(alias, "d");
19462306a36Sopenharmony_ci	if (bcdDevice_initial_digits)
19562306a36Sopenharmony_ci		sprintf(alias + strlen(alias), "%0*X",
19662306a36Sopenharmony_ci			bcdDevice_initial_digits, bcdDevice_initial);
19762306a36Sopenharmony_ci	if (range_lo == range_hi)
19862306a36Sopenharmony_ci		sprintf(alias + strlen(alias), "%X", range_lo);
19962306a36Sopenharmony_ci	else if (range_lo > 0 || range_hi < max) {
20062306a36Sopenharmony_ci		if (range_lo > 0x9 || range_hi < 0xA)
20162306a36Sopenharmony_ci			sprintf(alias + strlen(alias),
20262306a36Sopenharmony_ci				"[%X-%X]",
20362306a36Sopenharmony_ci				range_lo,
20462306a36Sopenharmony_ci				range_hi);
20562306a36Sopenharmony_ci		else {
20662306a36Sopenharmony_ci			sprintf(alias + strlen(alias),
20762306a36Sopenharmony_ci				range_lo < 0x9 ? "[%X-9" : "[%X",
20862306a36Sopenharmony_ci				range_lo);
20962306a36Sopenharmony_ci			sprintf(alias + strlen(alias),
21062306a36Sopenharmony_ci				range_hi > 0xA ? "A-%X]" : "%X]",
21162306a36Sopenharmony_ci				range_hi);
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1))
21562306a36Sopenharmony_ci		strcat(alias, "*");
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
21862306a36Sopenharmony_ci	    bDeviceClass);
21962306a36Sopenharmony_ci	ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
22062306a36Sopenharmony_ci	    bDeviceSubClass);
22162306a36Sopenharmony_ci	ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
22262306a36Sopenharmony_ci	    bDeviceProtocol);
22362306a36Sopenharmony_ci	ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
22462306a36Sopenharmony_ci	    bInterfaceClass);
22562306a36Sopenharmony_ci	ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
22662306a36Sopenharmony_ci	    bInterfaceSubClass);
22762306a36Sopenharmony_ci	ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
22862306a36Sopenharmony_ci	    bInterfaceProtocol);
22962306a36Sopenharmony_ci	ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
23062306a36Sopenharmony_ci	    bInterfaceNumber);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	add_wildcard(alias);
23362306a36Sopenharmony_ci	buf_printf(&mod->dev_table_buf,
23462306a36Sopenharmony_ci		   "MODULE_ALIAS(\"%s\");\n", alias);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/* Handles increment/decrement of BCD formatted integers */
23862306a36Sopenharmony_ci/* Returns the previous value, so it works like i++ or i-- */
23962306a36Sopenharmony_cistatic unsigned int incbcd(unsigned int *bcd,
24062306a36Sopenharmony_ci			   int inc,
24162306a36Sopenharmony_ci			   unsigned char max,
24262306a36Sopenharmony_ci			   size_t chars)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	unsigned int init = *bcd, i, j;
24562306a36Sopenharmony_ci	unsigned long long c, dec = 0;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* If bcd is not in BCD format, just increment */
24862306a36Sopenharmony_ci	if (max > 0x9) {
24962306a36Sopenharmony_ci		*bcd += inc;
25062306a36Sopenharmony_ci		return init;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Convert BCD to Decimal */
25462306a36Sopenharmony_ci	for (i=0 ; i < chars ; i++) {
25562306a36Sopenharmony_ci		c = (*bcd >> (i << 2)) & 0xf;
25662306a36Sopenharmony_ci		c = c > 9 ? 9 : c; /* force to bcd just in case */
25762306a36Sopenharmony_ci		for (j=0 ; j < i ; j++)
25862306a36Sopenharmony_ci			c = c * 10;
25962306a36Sopenharmony_ci		dec += c;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Do our increment/decrement */
26362306a36Sopenharmony_ci	dec += inc;
26462306a36Sopenharmony_ci	*bcd  = 0;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* Convert back to BCD */
26762306a36Sopenharmony_ci	for (i=0 ; i < chars ; i++) {
26862306a36Sopenharmony_ci		for (c=1,j=0 ; j < i ; j++)
26962306a36Sopenharmony_ci			c = c * 10;
27062306a36Sopenharmony_ci		c = (dec / c) % 10;
27162306a36Sopenharmony_ci		*bcd += c << (i << 2);
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	return init;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic void do_usb_entry_multi(void *symval, struct module *mod)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	unsigned int devlo, devhi;
27962306a36Sopenharmony_ci	unsigned char chi, clo, max;
28062306a36Sopenharmony_ci	int ndigits;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, match_flags);
28362306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, idVendor);
28462306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, idProduct);
28562306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bcdDevice_lo);
28662306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bcdDevice_hi);
28762306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bDeviceClass);
28862306a36Sopenharmony_ci	DEF_FIELD(symval, usb_device_id, bInterfaceClass);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ?
29162306a36Sopenharmony_ci		bcdDevice_lo : 0x0U;
29262306a36Sopenharmony_ci	devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
29362306a36Sopenharmony_ci		bcdDevice_hi : ~0x0U;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Figure out if this entry is in bcd or hex format */
29662306a36Sopenharmony_ci	max = 0x9; /* Default to decimal format */
29762306a36Sopenharmony_ci	for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) {
29862306a36Sopenharmony_ci		clo = (devlo >> (ndigits << 2)) & 0xf;
29962306a36Sopenharmony_ci		chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf;
30062306a36Sopenharmony_ci		if (clo > max || chi > max) {
30162306a36Sopenharmony_ci			max = 0xf;
30262306a36Sopenharmony_ci			break;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/*
30762306a36Sopenharmony_ci	 * Some modules (visor) have empty slots as placeholder for
30862306a36Sopenharmony_ci	 * run-time specification that results in catch-all alias
30962306a36Sopenharmony_ci	 */
31062306a36Sopenharmony_ci	if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass))
31162306a36Sopenharmony_ci		return;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
31462306a36Sopenharmony_ci	for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {
31562306a36Sopenharmony_ci		clo = devlo & 0xf;
31662306a36Sopenharmony_ci		chi = devhi & 0xf;
31762306a36Sopenharmony_ci		if (chi > max)	/* If we are in bcd mode, truncate if necessary */
31862306a36Sopenharmony_ci			chi = max;
31962306a36Sopenharmony_ci		devlo >>= 4;
32062306a36Sopenharmony_ci		devhi >>= 4;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		if (devlo == devhi || !ndigits) {
32362306a36Sopenharmony_ci			do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod);
32462306a36Sopenharmony_ci			break;
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		if (clo > 0x0)
32862306a36Sopenharmony_ci			do_usb_entry(symval,
32962306a36Sopenharmony_ci				     incbcd(&devlo, 1, max,
33062306a36Sopenharmony_ci					    sizeof(bcdDevice_lo) * 2),
33162306a36Sopenharmony_ci				     ndigits, clo, max, max, mod);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		if (chi < max)
33462306a36Sopenharmony_ci			do_usb_entry(symval,
33562306a36Sopenharmony_ci				     incbcd(&devhi, -1, max,
33662306a36Sopenharmony_ci					    sizeof(bcdDevice_lo) * 2),
33762306a36Sopenharmony_ci				     ndigits, 0x0, chi, max, mod);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void do_usb_table(void *symval, unsigned long size,
34262306a36Sopenharmony_ci			 struct module *mod)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	unsigned int i;
34562306a36Sopenharmony_ci	const unsigned long id_size = SIZE_usb_device_id;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	device_id_check(mod->name, "usb", size, id_size, symval);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* Leave last one: it's the terminator. */
35062306a36Sopenharmony_ci	size -= id_size;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = 0; i < size; i += id_size)
35362306a36Sopenharmony_ci		do_usb_entry_multi(symval + i, mod);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void do_of_entry_multi(void *symval, struct module *mod)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	char alias[500];
35962306a36Sopenharmony_ci	int len;
36062306a36Sopenharmony_ci	char *tmp;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, of_device_id, name);
36362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, of_device_id, type);
36462306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, of_device_id, compatible);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*",
36762306a36Sopenharmony_ci		      (*type)[0] ? *type : "*");
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if ((*compatible)[0])
37062306a36Sopenharmony_ci		sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "",
37162306a36Sopenharmony_ci			*compatible);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Replace all whitespace with underscores */
37462306a36Sopenharmony_ci	for (tmp = alias; tmp && *tmp; tmp++)
37562306a36Sopenharmony_ci		if (isspace(*tmp))
37662306a36Sopenharmony_ci			*tmp = '_';
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
37962306a36Sopenharmony_ci	strcat(alias, "C");
38062306a36Sopenharmony_ci	add_wildcard(alias);
38162306a36Sopenharmony_ci	buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void do_of_table(void *symval, unsigned long size,
38562306a36Sopenharmony_ci			struct module *mod)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	unsigned int i;
38862306a36Sopenharmony_ci	const unsigned long id_size = SIZE_of_device_id;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	device_id_check(mod->name, "of", size, id_size, symval);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Leave last one: it's the terminator. */
39362306a36Sopenharmony_ci	size -= id_size;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	for (i = 0; i < size; i += id_size)
39662306a36Sopenharmony_ci		do_of_entry_multi(symval + i, mod);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/* Looks like: hid:bNvNpN */
40062306a36Sopenharmony_cistatic int do_hid_entry(const char *filename,
40162306a36Sopenharmony_ci			     void *symval, char *alias)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	DEF_FIELD(symval, hid_device_id, bus);
40462306a36Sopenharmony_ci	DEF_FIELD(symval, hid_device_id, group);
40562306a36Sopenharmony_ci	DEF_FIELD(symval, hid_device_id, vendor);
40662306a36Sopenharmony_ci	DEF_FIELD(symval, hid_device_id, product);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	sprintf(alias, "hid:");
40962306a36Sopenharmony_ci	ADD(alias, "b", bus != HID_BUS_ANY, bus);
41062306a36Sopenharmony_ci	ADD(alias, "g", group != HID_GROUP_ANY, group);
41162306a36Sopenharmony_ci	ADD(alias, "v", vendor != HID_ANY_ID, vendor);
41262306a36Sopenharmony_ci	ADD(alias, "p", product != HID_ANY_ID, product);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return 1;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/* Looks like: ieee1394:venNmoNspNverN */
41862306a36Sopenharmony_cistatic int do_ieee1394_entry(const char *filename,
41962306a36Sopenharmony_ci			     void *symval, char *alias)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	DEF_FIELD(symval, ieee1394_device_id, match_flags);
42262306a36Sopenharmony_ci	DEF_FIELD(symval, ieee1394_device_id, vendor_id);
42362306a36Sopenharmony_ci	DEF_FIELD(symval, ieee1394_device_id, model_id);
42462306a36Sopenharmony_ci	DEF_FIELD(symval, ieee1394_device_id, specifier_id);
42562306a36Sopenharmony_ci	DEF_FIELD(symval, ieee1394_device_id, version);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	strcpy(alias, "ieee1394:");
42862306a36Sopenharmony_ci	ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID,
42962306a36Sopenharmony_ci	    vendor_id);
43062306a36Sopenharmony_ci	ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID,
43162306a36Sopenharmony_ci	    model_id);
43262306a36Sopenharmony_ci	ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID,
43362306a36Sopenharmony_ci	    specifier_id);
43462306a36Sopenharmony_ci	ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION,
43562306a36Sopenharmony_ci	    version);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	add_wildcard(alias);
43862306a36Sopenharmony_ci	return 1;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/* Looks like: pci:vNdNsvNsdNbcNscNiN or <prefix>_pci:vNdNsvNsdNbcNscNiN. */
44262306a36Sopenharmony_cistatic int do_pci_entry(const char *filename,
44362306a36Sopenharmony_ci			void *symval, char *alias)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	/* Class field can be divided into these three. */
44662306a36Sopenharmony_ci	unsigned char baseclass, subclass, interface,
44762306a36Sopenharmony_ci		baseclass_mask, subclass_mask, interface_mask;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, vendor);
45062306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, device);
45162306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, subvendor);
45262306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, subdevice);
45362306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, class);
45462306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, class_mask);
45562306a36Sopenharmony_ci	DEF_FIELD(symval, pci_device_id, override_only);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	switch (override_only) {
45862306a36Sopenharmony_ci	case 0:
45962306a36Sopenharmony_ci		strcpy(alias, "pci:");
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	case PCI_ID_F_VFIO_DRIVER_OVERRIDE:
46262306a36Sopenharmony_ci		strcpy(alias, "vfio_pci:");
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	default:
46562306a36Sopenharmony_ci		warn("Unknown PCI driver_override alias %08X\n",
46662306a36Sopenharmony_ci		     override_only);
46762306a36Sopenharmony_ci		return 0;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	ADD(alias, "v", vendor != PCI_ANY_ID, vendor);
47162306a36Sopenharmony_ci	ADD(alias, "d", device != PCI_ANY_ID, device);
47262306a36Sopenharmony_ci	ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor);
47362306a36Sopenharmony_ci	ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	baseclass = (class) >> 16;
47662306a36Sopenharmony_ci	baseclass_mask = (class_mask) >> 16;
47762306a36Sopenharmony_ci	subclass = (class) >> 8;
47862306a36Sopenharmony_ci	subclass_mask = (class_mask) >> 8;
47962306a36Sopenharmony_ci	interface = class;
48062306a36Sopenharmony_ci	interface_mask = class_mask;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if ((baseclass_mask != 0 && baseclass_mask != 0xFF)
48362306a36Sopenharmony_ci	    || (subclass_mask != 0 && subclass_mask != 0xFF)
48462306a36Sopenharmony_ci	    || (interface_mask != 0 && interface_mask != 0xFF)) {
48562306a36Sopenharmony_ci		warn("Can't handle masks in %s:%04X\n",
48662306a36Sopenharmony_ci		     filename, class_mask);
48762306a36Sopenharmony_ci		return 0;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ADD(alias, "bc", baseclass_mask == 0xFF, baseclass);
49162306a36Sopenharmony_ci	ADD(alias, "sc", subclass_mask == 0xFF, subclass);
49262306a36Sopenharmony_ci	ADD(alias, "i", interface_mask == 0xFF, interface);
49362306a36Sopenharmony_ci	add_wildcard(alias);
49462306a36Sopenharmony_ci	return 1;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/* looks like: "ccw:tNmNdtNdmN" */
49862306a36Sopenharmony_cistatic int do_ccw_entry(const char *filename,
49962306a36Sopenharmony_ci			void *symval, char *alias)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	DEF_FIELD(symval, ccw_device_id, match_flags);
50262306a36Sopenharmony_ci	DEF_FIELD(symval, ccw_device_id, cu_type);
50362306a36Sopenharmony_ci	DEF_FIELD(symval, ccw_device_id, cu_model);
50462306a36Sopenharmony_ci	DEF_FIELD(symval, ccw_device_id, dev_type);
50562306a36Sopenharmony_ci	DEF_FIELD(symval, ccw_device_id, dev_model);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	strcpy(alias, "ccw:");
50862306a36Sopenharmony_ci	ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE,
50962306a36Sopenharmony_ci	    cu_type);
51062306a36Sopenharmony_ci	ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL,
51162306a36Sopenharmony_ci	    cu_model);
51262306a36Sopenharmony_ci	ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE,
51362306a36Sopenharmony_ci	    dev_type);
51462306a36Sopenharmony_ci	ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL,
51562306a36Sopenharmony_ci	    dev_model);
51662306a36Sopenharmony_ci	add_wildcard(alias);
51762306a36Sopenharmony_ci	return 1;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/* looks like: "ap:tN" */
52162306a36Sopenharmony_cistatic int do_ap_entry(const char *filename,
52262306a36Sopenharmony_ci		       void *symval, char *alias)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	DEF_FIELD(symval, ap_device_id, dev_type);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	sprintf(alias, "ap:t%02X*", dev_type);
52762306a36Sopenharmony_ci	return 1;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci/* looks like: "css:tN" */
53162306a36Sopenharmony_cistatic int do_css_entry(const char *filename,
53262306a36Sopenharmony_ci			void *symval, char *alias)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	DEF_FIELD(symval, css_device_id, type);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	sprintf(alias, "css:t%01X", type);
53762306a36Sopenharmony_ci	return 1;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/* Looks like: "serio:tyNprNidNexN" */
54162306a36Sopenharmony_cistatic int do_serio_entry(const char *filename,
54262306a36Sopenharmony_ci			  void *symval, char *alias)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	DEF_FIELD(symval, serio_device_id, type);
54562306a36Sopenharmony_ci	DEF_FIELD(symval, serio_device_id, proto);
54662306a36Sopenharmony_ci	DEF_FIELD(symval, serio_device_id, id);
54762306a36Sopenharmony_ci	DEF_FIELD(symval, serio_device_id, extra);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	strcpy(alias, "serio:");
55062306a36Sopenharmony_ci	ADD(alias, "ty", type != SERIO_ANY, type);
55162306a36Sopenharmony_ci	ADD(alias, "pr", proto != SERIO_ANY, proto);
55262306a36Sopenharmony_ci	ADD(alias, "id", id != SERIO_ANY, id);
55362306a36Sopenharmony_ci	ADD(alias, "ex", extra != SERIO_ANY, extra);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	add_wildcard(alias);
55662306a36Sopenharmony_ci	return 1;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or
56062306a36Sopenharmony_ci *             "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if)
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * NOTE: Each driver should use one of the following : _HID, _CIDs
56362306a36Sopenharmony_ci *       or _CLS. Also, bb, ss, and pp can be substituted with ??
56462306a36Sopenharmony_ci *       as don't care byte.
56562306a36Sopenharmony_ci */
56662306a36Sopenharmony_cistatic int do_acpi_entry(const char *filename,
56762306a36Sopenharmony_ci			void *symval, char *alias)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, acpi_device_id, id);
57062306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, acpi_device_id, cls);
57162306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (id && strlen((const char *)*id))
57462306a36Sopenharmony_ci		sprintf(alias, "acpi*:%s:*", *id);
57562306a36Sopenharmony_ci	else if (cls) {
57662306a36Sopenharmony_ci		int i, byte_shift, cnt = 0;
57762306a36Sopenharmony_ci		unsigned int msk;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		sprintf(&alias[cnt], "acpi*:");
58062306a36Sopenharmony_ci		cnt = 6;
58162306a36Sopenharmony_ci		for (i = 1; i <= 3; i++) {
58262306a36Sopenharmony_ci			byte_shift = 8 * (3-i);
58362306a36Sopenharmony_ci			msk = (*cls_msk >> byte_shift) & 0xFF;
58462306a36Sopenharmony_ci			if (msk)
58562306a36Sopenharmony_ci				sprintf(&alias[cnt], "%02x",
58662306a36Sopenharmony_ci					(*cls >> byte_shift) & 0xFF);
58762306a36Sopenharmony_ci			else
58862306a36Sopenharmony_ci				sprintf(&alias[cnt], "??");
58962306a36Sopenharmony_ci			cnt += 2;
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci		sprintf(&alias[cnt], ":*");
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	return 1;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/* looks like: "pnp:dD" */
59762306a36Sopenharmony_cistatic void do_pnp_device_entry(void *symval, unsigned long size,
59862306a36Sopenharmony_ci				struct module *mod)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	const unsigned long id_size = SIZE_pnp_device_id;
60162306a36Sopenharmony_ci	const unsigned int count = (size / id_size)-1;
60262306a36Sopenharmony_ci	unsigned int i;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	device_id_check(mod->name, "pnp", size, id_size, symval);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
60762306a36Sopenharmony_ci		DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id);
60862306a36Sopenharmony_ci		char acpi_id[sizeof(*id)];
60962306a36Sopenharmony_ci		int j;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		buf_printf(&mod->dev_table_buf,
61262306a36Sopenharmony_ci			   "MODULE_ALIAS(\"pnp:d%s*\");\n", *id);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		/* fix broken pnp bus lowercasing */
61562306a36Sopenharmony_ci		for (j = 0; j < sizeof(acpi_id); j++)
61662306a36Sopenharmony_ci			acpi_id[j] = toupper((*id)[j]);
61762306a36Sopenharmony_ci		buf_printf(&mod->dev_table_buf,
61862306a36Sopenharmony_ci			   "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci/* looks like: "pnp:dD" for every device of the card */
62362306a36Sopenharmony_cistatic void do_pnp_card_entries(void *symval, unsigned long size,
62462306a36Sopenharmony_ci				struct module *mod)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	const unsigned long id_size = SIZE_pnp_card_device_id;
62762306a36Sopenharmony_ci	const unsigned int count = (size / id_size)-1;
62862306a36Sopenharmony_ci	unsigned int i;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	device_id_check(mod->name, "pnp", size, id_size, symval);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
63362306a36Sopenharmony_ci		unsigned int j;
63462306a36Sopenharmony_ci		DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		for (j = 0; j < PNP_MAX_DEVICES; j++) {
63762306a36Sopenharmony_ci			const char *id = (char *)(*devs)[j].id;
63862306a36Sopenharmony_ci			int i2, j2;
63962306a36Sopenharmony_ci			int dup = 0;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci			if (!id[0])
64262306a36Sopenharmony_ci				break;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci			/* find duplicate, already added value */
64562306a36Sopenharmony_ci			for (i2 = 0; i2 < i && !dup; i2++) {
64662306a36Sopenharmony_ci				DEF_FIELD_ADDR_VAR(symval + i2 * id_size,
64762306a36Sopenharmony_ci						   pnp_card_device_id,
64862306a36Sopenharmony_ci						   devs, devs_dup);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci				for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) {
65162306a36Sopenharmony_ci					const char *id2 =
65262306a36Sopenharmony_ci						(char *)(*devs_dup)[j2].id;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci					if (!id2[0])
65562306a36Sopenharmony_ci						break;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci					if (!strcmp(id, id2)) {
65862306a36Sopenharmony_ci						dup = 1;
65962306a36Sopenharmony_ci						break;
66062306a36Sopenharmony_ci					}
66162306a36Sopenharmony_ci				}
66262306a36Sopenharmony_ci			}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci			/* add an individual alias for every device entry */
66562306a36Sopenharmony_ci			if (!dup) {
66662306a36Sopenharmony_ci				char acpi_id[PNP_ID_LEN];
66762306a36Sopenharmony_ci				int k;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci				buf_printf(&mod->dev_table_buf,
67062306a36Sopenharmony_ci					   "MODULE_ALIAS(\"pnp:d%s*\");\n", id);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci				/* fix broken pnp bus lowercasing */
67362306a36Sopenharmony_ci				for (k = 0; k < sizeof(acpi_id); k++)
67462306a36Sopenharmony_ci					acpi_id[k] = toupper(id[k]);
67562306a36Sopenharmony_ci				buf_printf(&mod->dev_table_buf,
67662306a36Sopenharmony_ci					   "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
67762306a36Sopenharmony_ci			}
67862306a36Sopenharmony_ci		}
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
68362306a36Sopenharmony_cistatic int do_pcmcia_entry(const char *filename,
68462306a36Sopenharmony_ci			   void *symval, char *alias)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	unsigned int i;
68762306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, match_flags);
68862306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, manf_id);
68962306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, card_id);
69062306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, func_id);
69162306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, function);
69262306a36Sopenharmony_ci	DEF_FIELD(symval, pcmcia_device_id, device_no);
69362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	for (i=0; i<4; i++) {
69662306a36Sopenharmony_ci		(*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]);
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	strcpy(alias, "pcmcia:");
70062306a36Sopenharmony_ci	ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
70162306a36Sopenharmony_ci	    manf_id);
70262306a36Sopenharmony_ci	ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
70362306a36Sopenharmony_ci	    card_id);
70462306a36Sopenharmony_ci	ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID,
70562306a36Sopenharmony_ci	    func_id);
70662306a36Sopenharmony_ci	ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION,
70762306a36Sopenharmony_ci	    function);
70862306a36Sopenharmony_ci	ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
70962306a36Sopenharmony_ci	    device_no);
71062306a36Sopenharmony_ci	ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]);
71162306a36Sopenharmony_ci	ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]);
71262306a36Sopenharmony_ci	ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]);
71362306a36Sopenharmony_ci	ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	add_wildcard(alias);
71662306a36Sopenharmony_ci	return 1;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic int do_vio_entry(const char *filename, void *symval,
72062306a36Sopenharmony_ci		char *alias)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	char *tmp;
72362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, vio_device_id, type);
72462306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, vio_device_id, compat);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*",
72762306a36Sopenharmony_ci			(*compat)[0] ? *compat : "*");
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* Replace all whitespace with underscores */
73062306a36Sopenharmony_ci	for (tmp = alias; tmp && *tmp; tmp++)
73162306a36Sopenharmony_ci		if (isspace (*tmp))
73262306a36Sopenharmony_ci			*tmp = '_';
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	add_wildcard(alias);
73562306a36Sopenharmony_ci	return 1;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic void do_input(char *alias,
73962306a36Sopenharmony_ci		     kernel_ulong_t *arr, unsigned int min, unsigned int max)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	unsigned int i;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++)
74462306a36Sopenharmony_ci		arr[i] = TO_NATIVE(arr[i]);
74562306a36Sopenharmony_ci	for (i = min; i < max; i++)
74662306a36Sopenharmony_ci		if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG)))
74762306a36Sopenharmony_ci			sprintf(alias + strlen(alias), "%X,*", i);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */
75162306a36Sopenharmony_cistatic int do_input_entry(const char *filename, void *symval,
75262306a36Sopenharmony_ci			  char *alias)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	DEF_FIELD(symval, input_device_id, flags);
75562306a36Sopenharmony_ci	DEF_FIELD(symval, input_device_id, bustype);
75662306a36Sopenharmony_ci	DEF_FIELD(symval, input_device_id, vendor);
75762306a36Sopenharmony_ci	DEF_FIELD(symval, input_device_id, product);
75862306a36Sopenharmony_ci	DEF_FIELD(symval, input_device_id, version);
75962306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, evbit);
76062306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, keybit);
76162306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, relbit);
76262306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, absbit);
76362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, mscbit);
76462306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, ledbit);
76562306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, sndbit);
76662306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, ffbit);
76762306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, input_device_id, swbit);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	sprintf(alias, "input:");
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype);
77262306a36Sopenharmony_ci	ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor);
77362306a36Sopenharmony_ci	ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product);
77462306a36Sopenharmony_ci	ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "-e*");
77762306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_EVBIT)
77862306a36Sopenharmony_ci		do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX);
77962306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "k*");
78062306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
78162306a36Sopenharmony_ci		do_input(alias, *keybit,
78262306a36Sopenharmony_ci			 INPUT_DEVICE_ID_KEY_MIN_INTERESTING,
78362306a36Sopenharmony_ci			 INPUT_DEVICE_ID_KEY_MAX);
78462306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "r*");
78562306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_RELBIT)
78662306a36Sopenharmony_ci		do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX);
78762306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "a*");
78862306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
78962306a36Sopenharmony_ci		do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
79062306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "m*");
79162306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_MSCIT)
79262306a36Sopenharmony_ci		do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
79362306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "l*");
79462306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
79562306a36Sopenharmony_ci		do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
79662306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "s*");
79762306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
79862306a36Sopenharmony_ci		do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
79962306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "f*");
80062306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_FFBIT)
80162306a36Sopenharmony_ci		do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
80262306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "w*");
80362306a36Sopenharmony_ci	if (flags & INPUT_DEVICE_ID_MATCH_SWBIT)
80462306a36Sopenharmony_ci		do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);
80562306a36Sopenharmony_ci	return 1;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic int do_eisa_entry(const char *filename, void *symval,
80962306a36Sopenharmony_ci		char *alias)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, eisa_device_id, sig);
81262306a36Sopenharmony_ci	if (sig[0])
81362306a36Sopenharmony_ci		sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig);
81462306a36Sopenharmony_ci	else
81562306a36Sopenharmony_ci		strcat(alias, "*");
81662306a36Sopenharmony_ci	return 1;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/* Looks like: parisc:tNhvNrevNsvN */
82062306a36Sopenharmony_cistatic int do_parisc_entry(const char *filename, void *symval,
82162306a36Sopenharmony_ci		char *alias)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	DEF_FIELD(symval, parisc_device_id, hw_type);
82462306a36Sopenharmony_ci	DEF_FIELD(symval, parisc_device_id, hversion);
82562306a36Sopenharmony_ci	DEF_FIELD(symval, parisc_device_id, hversion_rev);
82662306a36Sopenharmony_ci	DEF_FIELD(symval, parisc_device_id, sversion);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	strcpy(alias, "parisc:");
82962306a36Sopenharmony_ci	ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type);
83062306a36Sopenharmony_ci	ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion);
83162306a36Sopenharmony_ci	ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev);
83262306a36Sopenharmony_ci	ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	add_wildcard(alias);
83562306a36Sopenharmony_ci	return 1;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci/* Looks like: sdio:cNvNdN. */
83962306a36Sopenharmony_cistatic int do_sdio_entry(const char *filename,
84062306a36Sopenharmony_ci			void *symval, char *alias)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci	DEF_FIELD(symval, sdio_device_id, class);
84362306a36Sopenharmony_ci	DEF_FIELD(symval, sdio_device_id, vendor);
84462306a36Sopenharmony_ci	DEF_FIELD(symval, sdio_device_id, device);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	strcpy(alias, "sdio:");
84762306a36Sopenharmony_ci	ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class);
84862306a36Sopenharmony_ci	ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor);
84962306a36Sopenharmony_ci	ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device);
85062306a36Sopenharmony_ci	add_wildcard(alias);
85162306a36Sopenharmony_ci	return 1;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci/* Looks like: ssb:vNidNrevN. */
85562306a36Sopenharmony_cistatic int do_ssb_entry(const char *filename,
85662306a36Sopenharmony_ci			void *symval, char *alias)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	DEF_FIELD(symval, ssb_device_id, vendor);
85962306a36Sopenharmony_ci	DEF_FIELD(symval, ssb_device_id, coreid);
86062306a36Sopenharmony_ci	DEF_FIELD(symval, ssb_device_id, revision);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	strcpy(alias, "ssb:");
86362306a36Sopenharmony_ci	ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor);
86462306a36Sopenharmony_ci	ADD(alias, "id", coreid != SSB_ANY_ID, coreid);
86562306a36Sopenharmony_ci	ADD(alias, "rev", revision != SSB_ANY_REV, revision);
86662306a36Sopenharmony_ci	add_wildcard(alias);
86762306a36Sopenharmony_ci	return 1;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci/* Looks like: bcma:mNidNrevNclN. */
87162306a36Sopenharmony_cistatic int do_bcma_entry(const char *filename,
87262306a36Sopenharmony_ci			 void *symval, char *alias)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	DEF_FIELD(symval, bcma_device_id, manuf);
87562306a36Sopenharmony_ci	DEF_FIELD(symval, bcma_device_id, id);
87662306a36Sopenharmony_ci	DEF_FIELD(symval, bcma_device_id, rev);
87762306a36Sopenharmony_ci	DEF_FIELD(symval, bcma_device_id, class);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	strcpy(alias, "bcma:");
88062306a36Sopenharmony_ci	ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf);
88162306a36Sopenharmony_ci	ADD(alias, "id", id != BCMA_ANY_ID, id);
88262306a36Sopenharmony_ci	ADD(alias, "rev", rev != BCMA_ANY_REV, rev);
88362306a36Sopenharmony_ci	ADD(alias, "cl", class != BCMA_ANY_CLASS, class);
88462306a36Sopenharmony_ci	add_wildcard(alias);
88562306a36Sopenharmony_ci	return 1;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci/* Looks like: virtio:dNvN */
88962306a36Sopenharmony_cistatic int do_virtio_entry(const char *filename, void *symval,
89062306a36Sopenharmony_ci			   char *alias)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	DEF_FIELD(symval, virtio_device_id, device);
89362306a36Sopenharmony_ci	DEF_FIELD(symval, virtio_device_id, vendor);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	strcpy(alias, "virtio:");
89662306a36Sopenharmony_ci	ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device);
89762306a36Sopenharmony_ci	ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	add_wildcard(alias);
90062306a36Sopenharmony_ci	return 1;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/*
90462306a36Sopenharmony_ci * Looks like: vmbus:guid
90562306a36Sopenharmony_ci * Each byte of the guid will be represented by two hex characters
90662306a36Sopenharmony_ci * in the name.
90762306a36Sopenharmony_ci */
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic int do_vmbus_entry(const char *filename, void *symval,
91062306a36Sopenharmony_ci			  char *alias)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	int i;
91362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid);
91462306a36Sopenharmony_ci	char guid_name[(sizeof(*guid) + 1) * 2];
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	for (i = 0; i < (sizeof(*guid) * 2); i += 2)
91762306a36Sopenharmony_ci		sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	strcpy(alias, "vmbus:");
92062306a36Sopenharmony_ci	strcat(alias, guid_name);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return 1;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/* Looks like: rpmsg:S */
92662306a36Sopenharmony_cistatic int do_rpmsg_entry(const char *filename, void *symval,
92762306a36Sopenharmony_ci			  char *alias)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, rpmsg_device_id, name);
93062306a36Sopenharmony_ci	sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	return 1;
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci/* Looks like: i2c:S */
93662306a36Sopenharmony_cistatic int do_i2c_entry(const char *filename, void *symval,
93762306a36Sopenharmony_ci			char *alias)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, i2c_device_id, name);
94062306a36Sopenharmony_ci	sprintf(alias, I2C_MODULE_PREFIX "%s", *name);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return 1;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic int do_i3c_entry(const char *filename, void *symval,
94662306a36Sopenharmony_ci			char *alias)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	DEF_FIELD(symval, i3c_device_id, match_flags);
94962306a36Sopenharmony_ci	DEF_FIELD(symval, i3c_device_id, dcr);
95062306a36Sopenharmony_ci	DEF_FIELD(symval, i3c_device_id, manuf_id);
95162306a36Sopenharmony_ci	DEF_FIELD(symval, i3c_device_id, part_id);
95262306a36Sopenharmony_ci	DEF_FIELD(symval, i3c_device_id, extra_info);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	strcpy(alias, "i3c:");
95562306a36Sopenharmony_ci	ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr);
95662306a36Sopenharmony_ci	ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id);
95762306a36Sopenharmony_ci	ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id);
95862306a36Sopenharmony_ci	ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return 1;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci/* Looks like: spi:S */
96462306a36Sopenharmony_cistatic int do_spi_entry(const char *filename, void *symval,
96562306a36Sopenharmony_ci			char *alias)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, spi_device_id, name);
96862306a36Sopenharmony_ci	sprintf(alias, SPI_MODULE_PREFIX "%s", *name);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	return 1;
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic const struct dmifield {
97462306a36Sopenharmony_ci	const char *prefix;
97562306a36Sopenharmony_ci	int field;
97662306a36Sopenharmony_ci} dmi_fields[] = {
97762306a36Sopenharmony_ci	{ "bvn", DMI_BIOS_VENDOR },
97862306a36Sopenharmony_ci	{ "bvr", DMI_BIOS_VERSION },
97962306a36Sopenharmony_ci	{ "bd",  DMI_BIOS_DATE },
98062306a36Sopenharmony_ci	{ "br",  DMI_BIOS_RELEASE },
98162306a36Sopenharmony_ci	{ "efr", DMI_EC_FIRMWARE_RELEASE },
98262306a36Sopenharmony_ci	{ "svn", DMI_SYS_VENDOR },
98362306a36Sopenharmony_ci	{ "pn",  DMI_PRODUCT_NAME },
98462306a36Sopenharmony_ci	{ "pvr", DMI_PRODUCT_VERSION },
98562306a36Sopenharmony_ci	{ "rvn", DMI_BOARD_VENDOR },
98662306a36Sopenharmony_ci	{ "rn",  DMI_BOARD_NAME },
98762306a36Sopenharmony_ci	{ "rvr", DMI_BOARD_VERSION },
98862306a36Sopenharmony_ci	{ "cvn", DMI_CHASSIS_VENDOR },
98962306a36Sopenharmony_ci	{ "ct",  DMI_CHASSIS_TYPE },
99062306a36Sopenharmony_ci	{ "cvr", DMI_CHASSIS_VERSION },
99162306a36Sopenharmony_ci	{ NULL,  DMI_NONE }
99262306a36Sopenharmony_ci};
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cistatic void dmi_ascii_filter(char *d, const char *s)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	/* Filter out characters we don't want to see in the modalias string */
99762306a36Sopenharmony_ci	for (; *s; s++)
99862306a36Sopenharmony_ci		if (*s > ' ' && *s < 127 && *s != ':')
99962306a36Sopenharmony_ci			*(d++) = *s;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	*d = 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic int do_dmi_entry(const char *filename, void *symval,
100662306a36Sopenharmony_ci			char *alias)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	int i, j;
100962306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, dmi_system_id, matches);
101062306a36Sopenharmony_ci	sprintf(alias, "dmi*");
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
101362306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
101462306a36Sopenharmony_ci			if ((*matches)[j].slot &&
101562306a36Sopenharmony_ci			    (*matches)[j].slot == dmi_fields[i].field) {
101662306a36Sopenharmony_ci				sprintf(alias + strlen(alias), ":%s*",
101762306a36Sopenharmony_ci					dmi_fields[i].prefix);
101862306a36Sopenharmony_ci				dmi_ascii_filter(alias + strlen(alias),
101962306a36Sopenharmony_ci						 (*matches)[j].substr);
102062306a36Sopenharmony_ci				strcat(alias, "*");
102162306a36Sopenharmony_ci			}
102262306a36Sopenharmony_ci		}
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	strcat(alias, ":");
102662306a36Sopenharmony_ci	return 1;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic int do_platform_entry(const char *filename,
103062306a36Sopenharmony_ci			     void *symval, char *alias)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, platform_device_id, name);
103362306a36Sopenharmony_ci	sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name);
103462306a36Sopenharmony_ci	return 1;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int do_mdio_entry(const char *filename,
103862306a36Sopenharmony_ci			 void *symval, char *alias)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	int i;
104162306a36Sopenharmony_ci	DEF_FIELD(symval, mdio_device_id, phy_id);
104262306a36Sopenharmony_ci	DEF_FIELD(symval, mdio_device_id, phy_id_mask);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	alias += sprintf(alias, MDIO_MODULE_PREFIX);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
104762306a36Sopenharmony_ci		if (!((phy_id_mask >> (31-i)) & 1))
104862306a36Sopenharmony_ci			*(alias++) = '?';
104962306a36Sopenharmony_ci		else if ((phy_id >> (31-i)) & 1)
105062306a36Sopenharmony_ci			*(alias++) = '1';
105162306a36Sopenharmony_ci		else
105262306a36Sopenharmony_ci			*(alias++) = '0';
105362306a36Sopenharmony_ci	}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* Terminate the string */
105662306a36Sopenharmony_ci	*alias = 0;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return 1;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci/* Looks like: zorro:iN. */
106262306a36Sopenharmony_cistatic int do_zorro_entry(const char *filename, void *symval,
106362306a36Sopenharmony_ci			  char *alias)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	DEF_FIELD(symval, zorro_device_id, id);
106662306a36Sopenharmony_ci	strcpy(alias, "zorro:");
106762306a36Sopenharmony_ci	ADD(alias, "i", id != ZORRO_WILDCARD, id);
106862306a36Sopenharmony_ci	return 1;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/* looks like: "pnp:dD" */
107262306a36Sopenharmony_cistatic int do_isapnp_entry(const char *filename,
107362306a36Sopenharmony_ci			   void *symval, char *alias)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	DEF_FIELD(symval, isapnp_device_id, vendor);
107662306a36Sopenharmony_ci	DEF_FIELD(symval, isapnp_device_id, function);
107762306a36Sopenharmony_ci	sprintf(alias, "pnp:d%c%c%c%x%x%x%x*",
107862306a36Sopenharmony_ci		'A' + ((vendor >> 2) & 0x3f) - 1,
107962306a36Sopenharmony_ci		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
108062306a36Sopenharmony_ci		'A' + ((vendor >> 8) & 0x1f) - 1,
108162306a36Sopenharmony_ci		(function >> 4) & 0x0f, function & 0x0f,
108262306a36Sopenharmony_ci		(function >> 12) & 0x0f, (function >> 8) & 0x0f);
108362306a36Sopenharmony_ci	return 1;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci/* Looks like: "ipack:fNvNdN". */
108762306a36Sopenharmony_cistatic int do_ipack_entry(const char *filename,
108862306a36Sopenharmony_ci			  void *symval, char *alias)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	DEF_FIELD(symval, ipack_device_id, format);
109162306a36Sopenharmony_ci	DEF_FIELD(symval, ipack_device_id, vendor);
109262306a36Sopenharmony_ci	DEF_FIELD(symval, ipack_device_id, device);
109362306a36Sopenharmony_ci	strcpy(alias, "ipack:");
109462306a36Sopenharmony_ci	ADD(alias, "f", format != IPACK_ANY_FORMAT, format);
109562306a36Sopenharmony_ci	ADD(alias, "v", vendor != IPACK_ANY_ID, vendor);
109662306a36Sopenharmony_ci	ADD(alias, "d", device != IPACK_ANY_ID, device);
109762306a36Sopenharmony_ci	add_wildcard(alias);
109862306a36Sopenharmony_ci	return 1;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci/*
110262306a36Sopenharmony_ci * Append a match expression for a single masked hex digit.
110362306a36Sopenharmony_ci * outp points to a pointer to the character at which to append.
110462306a36Sopenharmony_ci *	*outp is updated on return to point just after the appended text,
110562306a36Sopenharmony_ci *	to facilitate further appending.
110662306a36Sopenharmony_ci */
110762306a36Sopenharmony_cistatic void append_nibble_mask(char **outp,
110862306a36Sopenharmony_ci			       unsigned int nibble, unsigned int mask)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	char *p = *outp;
111162306a36Sopenharmony_ci	unsigned int i;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	switch (mask) {
111462306a36Sopenharmony_ci	case 0:
111562306a36Sopenharmony_ci		*p++ = '?';
111662306a36Sopenharmony_ci		break;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	case 0xf:
111962306a36Sopenharmony_ci		p += sprintf(p, "%X",  nibble);
112062306a36Sopenharmony_ci		break;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	default:
112362306a36Sopenharmony_ci		/*
112462306a36Sopenharmony_ci		 * Dumbly emit a match pattern for all possible matching
112562306a36Sopenharmony_ci		 * digits.  This could be improved in some cases using ranges,
112662306a36Sopenharmony_ci		 * but it has the advantage of being trivially correct, and is
112762306a36Sopenharmony_ci		 * often optimal.
112862306a36Sopenharmony_ci		 */
112962306a36Sopenharmony_ci		*p++ = '[';
113062306a36Sopenharmony_ci		for (i = 0; i < 0x10; i++)
113162306a36Sopenharmony_ci			if ((i & mask) == nibble)
113262306a36Sopenharmony_ci				p += sprintf(p, "%X", i);
113362306a36Sopenharmony_ci		*p++ = ']';
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	/* Ensure that the string remains NUL-terminated: */
113762306a36Sopenharmony_ci	*p = '\0';
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* Advance the caller's end-of-string pointer: */
114062306a36Sopenharmony_ci	*outp = p;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci/*
114462306a36Sopenharmony_ci * looks like: "amba:dN"
114562306a36Sopenharmony_ci *
114662306a36Sopenharmony_ci * N is exactly 8 digits, where each is an upper-case hex digit, or
114762306a36Sopenharmony_ci *	a ? or [] pattern matching exactly one digit.
114862306a36Sopenharmony_ci */
114962306a36Sopenharmony_cistatic int do_amba_entry(const char *filename,
115062306a36Sopenharmony_ci			 void *symval, char *alias)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	unsigned int digit;
115362306a36Sopenharmony_ci	char *p = alias;
115462306a36Sopenharmony_ci	DEF_FIELD(symval, amba_id, id);
115562306a36Sopenharmony_ci	DEF_FIELD(symval, amba_id, mask);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	if ((id & mask) != id)
115862306a36Sopenharmony_ci		fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X.  Please fix this driver.\n",
115962306a36Sopenharmony_ci		      filename, id, mask);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	p += sprintf(alias, "amba:d");
116262306a36Sopenharmony_ci	for (digit = 0; digit < 8; digit++)
116362306a36Sopenharmony_ci		append_nibble_mask(&p,
116462306a36Sopenharmony_ci				   (id >> (4 * (7 - digit))) & 0xf,
116562306a36Sopenharmony_ci				   (mask >> (4 * (7 - digit))) & 0xf);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	return 1;
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci/*
117162306a36Sopenharmony_ci * looks like: "mipscdmm:tN"
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * N is exactly 2 digits, where each is an upper-case hex digit, or
117462306a36Sopenharmony_ci *	a ? or [] pattern matching exactly one digit.
117562306a36Sopenharmony_ci */
117662306a36Sopenharmony_cistatic int do_mips_cdmm_entry(const char *filename,
117762306a36Sopenharmony_ci			      void *symval, char *alias)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	DEF_FIELD(symval, mips_cdmm_device_id, type);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	sprintf(alias, "mipscdmm:t%02X*", type);
118262306a36Sopenharmony_ci	return 1;
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,*
118662306a36Sopenharmony_ci * All fields are numbers. It would be nicer to use strings for vendor
118762306a36Sopenharmony_ci * and feature, but getting those out of the build system here is too
118862306a36Sopenharmony_ci * complicated.
118962306a36Sopenharmony_ci */
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic int do_x86cpu_entry(const char *filename, void *symval,
119262306a36Sopenharmony_ci			   char *alias)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	DEF_FIELD(symval, x86_cpu_id, feature);
119562306a36Sopenharmony_ci	DEF_FIELD(symval, x86_cpu_id, family);
119662306a36Sopenharmony_ci	DEF_FIELD(symval, x86_cpu_id, model);
119762306a36Sopenharmony_ci	DEF_FIELD(symval, x86_cpu_id, vendor);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	strcpy(alias, "cpu:type:x86,");
120062306a36Sopenharmony_ci	ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor);
120162306a36Sopenharmony_ci	ADD(alias, "fam", family != X86_FAMILY_ANY, family);
120262306a36Sopenharmony_ci	ADD(alias, "mod", model  != X86_MODEL_ANY,  model);
120362306a36Sopenharmony_ci	strcat(alias, ":feature:*");
120462306a36Sopenharmony_ci	if (feature != X86_FEATURE_ANY)
120562306a36Sopenharmony_ci		sprintf(alias + strlen(alias), "%04X*", feature);
120662306a36Sopenharmony_ci	return 1;
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci/* LOOKS like cpu:type:*:feature:*FEAT* */
121062306a36Sopenharmony_cistatic int do_cpu_entry(const char *filename, void *symval, char *alias)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	DEF_FIELD(symval, cpu_feature, feature);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	sprintf(alias, "cpu:type:*:feature:*%04X*", feature);
121562306a36Sopenharmony_ci	return 1;
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci/* Looks like: mei:S:uuid:N:* */
121962306a36Sopenharmony_cistatic int do_mei_entry(const char *filename, void *symval,
122062306a36Sopenharmony_ci			char *alias)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
122362306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid);
122462306a36Sopenharmony_ci	DEF_FIELD(symval, mei_cl_device_id, version);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	sprintf(alias, MEI_CL_MODULE_PREFIX);
122762306a36Sopenharmony_ci	sprintf(alias + strlen(alias), "%s:",  (*name)[0]  ? *name : "*");
122862306a36Sopenharmony_ci	add_uuid(alias, *uuid);
122962306a36Sopenharmony_ci	ADD(alias, ":", version != MEI_CL_VERSION_ANY, version);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	strcat(alias, ":*");
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return 1;
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci/* Looks like: rapidio:vNdNavNadN */
123762306a36Sopenharmony_cistatic int do_rio_entry(const char *filename,
123862306a36Sopenharmony_ci			void *symval, char *alias)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	DEF_FIELD(symval, rio_device_id, did);
124162306a36Sopenharmony_ci	DEF_FIELD(symval, rio_device_id, vid);
124262306a36Sopenharmony_ci	DEF_FIELD(symval, rio_device_id, asm_did);
124362306a36Sopenharmony_ci	DEF_FIELD(symval, rio_device_id, asm_vid);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	strcpy(alias, "rapidio:");
124662306a36Sopenharmony_ci	ADD(alias, "v", vid != RIO_ANY_ID, vid);
124762306a36Sopenharmony_ci	ADD(alias, "d", did != RIO_ANY_ID, did);
124862306a36Sopenharmony_ci	ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid);
124962306a36Sopenharmony_ci	ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	add_wildcard(alias);
125262306a36Sopenharmony_ci	return 1;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci/* Looks like: ulpi:vNpN */
125662306a36Sopenharmony_cistatic int do_ulpi_entry(const char *filename, void *symval,
125762306a36Sopenharmony_ci			 char *alias)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	DEF_FIELD(symval, ulpi_device_id, vendor);
126062306a36Sopenharmony_ci	DEF_FIELD(symval, ulpi_device_id, product);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	sprintf(alias, "ulpi:v%04xp%04x", vendor, product);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	return 1;
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/* Looks like: hdaudio:vNrNaN */
126862306a36Sopenharmony_cistatic int do_hda_entry(const char *filename, void *symval, char *alias)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	DEF_FIELD(symval, hda_device_id, vendor_id);
127162306a36Sopenharmony_ci	DEF_FIELD(symval, hda_device_id, rev_id);
127262306a36Sopenharmony_ci	DEF_FIELD(symval, hda_device_id, api_version);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	strcpy(alias, "hdaudio:");
127562306a36Sopenharmony_ci	ADD(alias, "v", vendor_id != 0, vendor_id);
127662306a36Sopenharmony_ci	ADD(alias, "r", rev_id != 0, rev_id);
127762306a36Sopenharmony_ci	ADD(alias, "a", api_version != 0, api_version);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	add_wildcard(alias);
128062306a36Sopenharmony_ci	return 1;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci/* Looks like: sdw:mNpNvNcN */
128462306a36Sopenharmony_cistatic int do_sdw_entry(const char *filename, void *symval, char *alias)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	DEF_FIELD(symval, sdw_device_id, mfg_id);
128762306a36Sopenharmony_ci	DEF_FIELD(symval, sdw_device_id, part_id);
128862306a36Sopenharmony_ci	DEF_FIELD(symval, sdw_device_id, sdw_version);
128962306a36Sopenharmony_ci	DEF_FIELD(symval, sdw_device_id, class_id);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	strcpy(alias, "sdw:");
129262306a36Sopenharmony_ci	ADD(alias, "m", mfg_id != 0, mfg_id);
129362306a36Sopenharmony_ci	ADD(alias, "p", part_id != 0, part_id);
129462306a36Sopenharmony_ci	ADD(alias, "v", sdw_version != 0, sdw_version);
129562306a36Sopenharmony_ci	ADD(alias, "c", class_id != 0, class_id);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	add_wildcard(alias);
129862306a36Sopenharmony_ci	return 1;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci/* Looks like: fsl-mc:vNdN */
130262306a36Sopenharmony_cistatic int do_fsl_mc_entry(const char *filename, void *symval,
130362306a36Sopenharmony_ci			   char *alias)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	DEF_FIELD(symval, fsl_mc_device_id, vendor);
130662306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type);
130962306a36Sopenharmony_ci	return 1;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci/* Looks like: tbsvc:kSpNvNrN */
131362306a36Sopenharmony_cistatic int do_tbsvc_entry(const char *filename, void *symval, char *alias)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	DEF_FIELD(symval, tb_service_id, match_flags);
131662306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, tb_service_id, protocol_key);
131762306a36Sopenharmony_ci	DEF_FIELD(symval, tb_service_id, protocol_id);
131862306a36Sopenharmony_ci	DEF_FIELD(symval, tb_service_id, protocol_version);
131962306a36Sopenharmony_ci	DEF_FIELD(symval, tb_service_id, protocol_revision);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	strcpy(alias, "tbsvc:");
132262306a36Sopenharmony_ci	if (match_flags & TBSVC_MATCH_PROTOCOL_KEY)
132362306a36Sopenharmony_ci		sprintf(alias + strlen(alias), "k%s", *protocol_key);
132462306a36Sopenharmony_ci	else
132562306a36Sopenharmony_ci		strcat(alias + strlen(alias), "k*");
132662306a36Sopenharmony_ci	ADD(alias, "p", match_flags & TBSVC_MATCH_PROTOCOL_ID, protocol_id);
132762306a36Sopenharmony_ci	ADD(alias, "v", match_flags & TBSVC_MATCH_PROTOCOL_VERSION,
132862306a36Sopenharmony_ci	    protocol_version);
132962306a36Sopenharmony_ci	ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION,
133062306a36Sopenharmony_ci	    protocol_revision);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	add_wildcard(alias);
133362306a36Sopenharmony_ci	return 1;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci/* Looks like: typec:idNmN */
133762306a36Sopenharmony_cistatic int do_typec_entry(const char *filename, void *symval, char *alias)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	DEF_FIELD(symval, typec_device_id, svid);
134062306a36Sopenharmony_ci	DEF_FIELD(symval, typec_device_id, mode);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	sprintf(alias, "typec:id%04X", svid);
134362306a36Sopenharmony_ci	ADD(alias, "m", mode != TYPEC_ANY_MODE, mode);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	return 1;
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci/* Looks like: tee:uuid */
134962306a36Sopenharmony_cistatic int do_tee_entry(const char *filename, void *symval, char *alias)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, tee_client_device_id, uuid);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
135462306a36Sopenharmony_ci		uuid->b[0], uuid->b[1], uuid->b[2], uuid->b[3], uuid->b[4],
135562306a36Sopenharmony_ci		uuid->b[5], uuid->b[6], uuid->b[7], uuid->b[8], uuid->b[9],
135662306a36Sopenharmony_ci		uuid->b[10], uuid->b[11], uuid->b[12], uuid->b[13], uuid->b[14],
135762306a36Sopenharmony_ci		uuid->b[15]);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	add_wildcard(alias);
136062306a36Sopenharmony_ci	return 1;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci/* Looks like: wmi:guid */
136462306a36Sopenharmony_cistatic int do_wmi_entry(const char *filename, void *symval, char *alias)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	int len;
136762306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, wmi_device_id, guid_string);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	if (strlen(*guid_string) != UUID_STRING_LEN) {
137062306a36Sopenharmony_ci		warn("Invalid WMI device id 'wmi:%s' in '%s'\n",
137162306a36Sopenharmony_ci				*guid_string, filename);
137262306a36Sopenharmony_ci		return 0;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	len = snprintf(alias, ALIAS_SIZE, WMI_MODULE_PREFIX "%s", *guid_string);
137662306a36Sopenharmony_ci	if (len < 0 || len >= ALIAS_SIZE) {
137762306a36Sopenharmony_ci		warn("Could not generate all MODULE_ALIAS's in '%s'\n",
137862306a36Sopenharmony_ci				filename);
137962306a36Sopenharmony_ci		return 0;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci	return 1;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci/* Looks like: mhi:S */
138562306a36Sopenharmony_cistatic int do_mhi_entry(const char *filename, void *symval, char *alias)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, mhi_device_id, chan);
138862306a36Sopenharmony_ci	sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan);
138962306a36Sopenharmony_ci	return 1;
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci/* Looks like: mhi_ep:S */
139362306a36Sopenharmony_cistatic int do_mhi_ep_entry(const char *filename, void *symval, char *alias)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, mhi_device_id, chan);
139662306a36Sopenharmony_ci	sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return 1;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci/* Looks like: ishtp:{guid} */
140262306a36Sopenharmony_cistatic int do_ishtp_entry(const char *filename, void *symval, char *alias)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, ishtp_device_id, guid);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	strcpy(alias, ISHTP_MODULE_PREFIX "{");
140762306a36Sopenharmony_ci	add_guid(alias, *guid);
140862306a36Sopenharmony_ci	strcat(alias, "}");
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	return 1;
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic int do_auxiliary_entry(const char *filename, void *symval, char *alias)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	DEF_FIELD_ADDR(symval, auxiliary_device_id, name);
141662306a36Sopenharmony_ci	sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	return 1;
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci/*
142262306a36Sopenharmony_ci * Looks like: ssam:dNcNtNiNfN
142362306a36Sopenharmony_ci *
142462306a36Sopenharmony_ci * N is exactly 2 digits, where each is an upper-case hex digit.
142562306a36Sopenharmony_ci */
142662306a36Sopenharmony_cistatic int do_ssam_entry(const char *filename, void *symval, char *alias)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, match_flags);
142962306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, domain);
143062306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, category);
143162306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, target);
143262306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, instance);
143362306a36Sopenharmony_ci	DEF_FIELD(symval, ssam_device_id, function);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	sprintf(alias, "ssam:d%02Xc%02X", domain, category);
143662306a36Sopenharmony_ci	ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target);
143762306a36Sopenharmony_ci	ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance);
143862306a36Sopenharmony_ci	ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	return 1;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci/* Looks like: dfl:tNfN */
144462306a36Sopenharmony_cistatic int do_dfl_entry(const char *filename, void *symval, char *alias)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	DEF_FIELD(symval, dfl_device_id, type);
144762306a36Sopenharmony_ci	DEF_FIELD(symval, dfl_device_id, feature_id);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	sprintf(alias, "dfl:t%04Xf%04X", type, feature_id);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	add_wildcard(alias);
145262306a36Sopenharmony_ci	return 1;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci/* Looks like: cdx:vNdN */
145662306a36Sopenharmony_cistatic int do_cdx_entry(const char *filename, void *symval,
145762306a36Sopenharmony_ci			char *alias)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	DEF_FIELD(symval, cdx_device_id, vendor);
146062306a36Sopenharmony_ci	DEF_FIELD(symval, cdx_device_id, device);
146162306a36Sopenharmony_ci	DEF_FIELD(symval, cdx_device_id, override_only);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	switch (override_only) {
146462306a36Sopenharmony_ci	case 0:
146562306a36Sopenharmony_ci		strcpy(alias, "cdx:");
146662306a36Sopenharmony_ci		break;
146762306a36Sopenharmony_ci	case CDX_ID_F_VFIO_DRIVER_OVERRIDE:
146862306a36Sopenharmony_ci		strcpy(alias, "vfio_cdx:");
146962306a36Sopenharmony_ci		break;
147062306a36Sopenharmony_ci	default:
147162306a36Sopenharmony_ci		warn("Unknown CDX driver_override alias %08X\n",
147262306a36Sopenharmony_ci		     override_only);
147362306a36Sopenharmony_ci		return 0;
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	ADD(alias, "v", vendor != CDX_ANY_ID, vendor);
147762306a36Sopenharmony_ci	ADD(alias, "d", device != CDX_ANY_ID, device);
147862306a36Sopenharmony_ci	return 1;
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci/* Does namelen bytes of name exactly match the symbol? */
148262306a36Sopenharmony_cistatic bool sym_is(const char *name, unsigned namelen, const char *symbol)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	if (namelen != strlen(symbol))
148562306a36Sopenharmony_ci		return false;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return memcmp(name, symbol, namelen) == 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic void do_table(void *symval, unsigned long size,
149162306a36Sopenharmony_ci		     unsigned long id_size,
149262306a36Sopenharmony_ci		     const char *device_id,
149362306a36Sopenharmony_ci		     int (*do_entry)(const char *filename, void *symval, char *alias),
149462306a36Sopenharmony_ci		     struct module *mod)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	unsigned int i;
149762306a36Sopenharmony_ci	char alias[ALIAS_SIZE];
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	device_id_check(mod->name, device_id, size, id_size, symval);
150062306a36Sopenharmony_ci	/* Leave last one: it's the terminator. */
150162306a36Sopenharmony_ci	size -= id_size;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	for (i = 0; i < size; i += id_size) {
150462306a36Sopenharmony_ci		if (do_entry(mod->name, symval+i, alias)) {
150562306a36Sopenharmony_ci			buf_printf(&mod->dev_table_buf,
150662306a36Sopenharmony_ci				   "MODULE_ALIAS(\"%s\");\n", alias);
150762306a36Sopenharmony_ci		}
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cistatic const struct devtable devtable[] = {
151262306a36Sopenharmony_ci	{"hid", SIZE_hid_device_id, do_hid_entry},
151362306a36Sopenharmony_ci	{"ieee1394", SIZE_ieee1394_device_id, do_ieee1394_entry},
151462306a36Sopenharmony_ci	{"pci", SIZE_pci_device_id, do_pci_entry},
151562306a36Sopenharmony_ci	{"ccw", SIZE_ccw_device_id, do_ccw_entry},
151662306a36Sopenharmony_ci	{"ap", SIZE_ap_device_id, do_ap_entry},
151762306a36Sopenharmony_ci	{"css", SIZE_css_device_id, do_css_entry},
151862306a36Sopenharmony_ci	{"serio", SIZE_serio_device_id, do_serio_entry},
151962306a36Sopenharmony_ci	{"acpi", SIZE_acpi_device_id, do_acpi_entry},
152062306a36Sopenharmony_ci	{"pcmcia", SIZE_pcmcia_device_id, do_pcmcia_entry},
152162306a36Sopenharmony_ci	{"vio", SIZE_vio_device_id, do_vio_entry},
152262306a36Sopenharmony_ci	{"input", SIZE_input_device_id, do_input_entry},
152362306a36Sopenharmony_ci	{"eisa", SIZE_eisa_device_id, do_eisa_entry},
152462306a36Sopenharmony_ci	{"parisc", SIZE_parisc_device_id, do_parisc_entry},
152562306a36Sopenharmony_ci	{"sdio", SIZE_sdio_device_id, do_sdio_entry},
152662306a36Sopenharmony_ci	{"ssb", SIZE_ssb_device_id, do_ssb_entry},
152762306a36Sopenharmony_ci	{"bcma", SIZE_bcma_device_id, do_bcma_entry},
152862306a36Sopenharmony_ci	{"virtio", SIZE_virtio_device_id, do_virtio_entry},
152962306a36Sopenharmony_ci	{"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry},
153062306a36Sopenharmony_ci	{"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry},
153162306a36Sopenharmony_ci	{"i2c", SIZE_i2c_device_id, do_i2c_entry},
153262306a36Sopenharmony_ci	{"i3c", SIZE_i3c_device_id, do_i3c_entry},
153362306a36Sopenharmony_ci	{"spi", SIZE_spi_device_id, do_spi_entry},
153462306a36Sopenharmony_ci	{"dmi", SIZE_dmi_system_id, do_dmi_entry},
153562306a36Sopenharmony_ci	{"platform", SIZE_platform_device_id, do_platform_entry},
153662306a36Sopenharmony_ci	{"mdio", SIZE_mdio_device_id, do_mdio_entry},
153762306a36Sopenharmony_ci	{"zorro", SIZE_zorro_device_id, do_zorro_entry},
153862306a36Sopenharmony_ci	{"isapnp", SIZE_isapnp_device_id, do_isapnp_entry},
153962306a36Sopenharmony_ci	{"ipack", SIZE_ipack_device_id, do_ipack_entry},
154062306a36Sopenharmony_ci	{"amba", SIZE_amba_id, do_amba_entry},
154162306a36Sopenharmony_ci	{"mipscdmm", SIZE_mips_cdmm_device_id, do_mips_cdmm_entry},
154262306a36Sopenharmony_ci	{"x86cpu", SIZE_x86_cpu_id, do_x86cpu_entry},
154362306a36Sopenharmony_ci	{"cpu", SIZE_cpu_feature, do_cpu_entry},
154462306a36Sopenharmony_ci	{"mei", SIZE_mei_cl_device_id, do_mei_entry},
154562306a36Sopenharmony_ci	{"rapidio", SIZE_rio_device_id, do_rio_entry},
154662306a36Sopenharmony_ci	{"ulpi", SIZE_ulpi_device_id, do_ulpi_entry},
154762306a36Sopenharmony_ci	{"hdaudio", SIZE_hda_device_id, do_hda_entry},
154862306a36Sopenharmony_ci	{"sdw", SIZE_sdw_device_id, do_sdw_entry},
154962306a36Sopenharmony_ci	{"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry},
155062306a36Sopenharmony_ci	{"tbsvc", SIZE_tb_service_id, do_tbsvc_entry},
155162306a36Sopenharmony_ci	{"typec", SIZE_typec_device_id, do_typec_entry},
155262306a36Sopenharmony_ci	{"tee", SIZE_tee_client_device_id, do_tee_entry},
155362306a36Sopenharmony_ci	{"wmi", SIZE_wmi_device_id, do_wmi_entry},
155462306a36Sopenharmony_ci	{"mhi", SIZE_mhi_device_id, do_mhi_entry},
155562306a36Sopenharmony_ci	{"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry},
155662306a36Sopenharmony_ci	{"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
155762306a36Sopenharmony_ci	{"ssam", SIZE_ssam_device_id, do_ssam_entry},
155862306a36Sopenharmony_ci	{"dfl", SIZE_dfl_device_id, do_dfl_entry},
155962306a36Sopenharmony_ci	{"ishtp", SIZE_ishtp_device_id, do_ishtp_entry},
156062306a36Sopenharmony_ci	{"cdx", SIZE_cdx_device_id, do_cdx_entry},
156162306a36Sopenharmony_ci};
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci/* Create MODULE_ALIAS() statements.
156462306a36Sopenharmony_ci * At this time, we cannot write the actual output C source yet,
156562306a36Sopenharmony_ci * so we write into the mod->dev_table_buf buffer. */
156662306a36Sopenharmony_civoid handle_moddevtable(struct module *mod, struct elf_info *info,
156762306a36Sopenharmony_ci			Elf_Sym *sym, const char *symname)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	void *symval;
157062306a36Sopenharmony_ci	char *zeros = NULL;
157162306a36Sopenharmony_ci	const char *name, *identifier;
157262306a36Sopenharmony_ci	unsigned int namelen;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	/* We're looking for a section relative symbol */
157562306a36Sopenharmony_ci	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
157662306a36Sopenharmony_ci		return;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	/* We're looking for an object */
157962306a36Sopenharmony_ci	if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
158062306a36Sopenharmony_ci		return;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	/* All our symbols are of form __mod_<name>__<identifier>_device_table. */
158362306a36Sopenharmony_ci	if (strncmp(symname, "__mod_", strlen("__mod_")))
158462306a36Sopenharmony_ci		return;
158562306a36Sopenharmony_ci	name = symname + strlen("__mod_");
158662306a36Sopenharmony_ci	namelen = strlen(name);
158762306a36Sopenharmony_ci	if (namelen < strlen("_device_table"))
158862306a36Sopenharmony_ci		return;
158962306a36Sopenharmony_ci	if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
159062306a36Sopenharmony_ci		return;
159162306a36Sopenharmony_ci	identifier = strstr(name, "__");
159262306a36Sopenharmony_ci	if (!identifier)
159362306a36Sopenharmony_ci		return;
159462306a36Sopenharmony_ci	namelen = identifier - name;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	/* Handle all-NULL symbols allocated into .bss */
159762306a36Sopenharmony_ci	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
159862306a36Sopenharmony_ci		zeros = calloc(1, sym->st_size);
159962306a36Sopenharmony_ci		symval = zeros;
160062306a36Sopenharmony_ci	} else {
160162306a36Sopenharmony_ci		symval = sym_get_data(info, sym);
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	/* First handle the "special" cases */
160562306a36Sopenharmony_ci	if (sym_is(name, namelen, "usb"))
160662306a36Sopenharmony_ci		do_usb_table(symval, sym->st_size, mod);
160762306a36Sopenharmony_ci	else if (sym_is(name, namelen, "of"))
160862306a36Sopenharmony_ci		do_of_table(symval, sym->st_size, mod);
160962306a36Sopenharmony_ci	else if (sym_is(name, namelen, "pnp"))
161062306a36Sopenharmony_ci		do_pnp_device_entry(symval, sym->st_size, mod);
161162306a36Sopenharmony_ci	else if (sym_is(name, namelen, "pnp_card"))
161262306a36Sopenharmony_ci		do_pnp_card_entries(symval, sym->st_size, mod);
161362306a36Sopenharmony_ci	else {
161462306a36Sopenharmony_ci		int i;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(devtable); i++) {
161762306a36Sopenharmony_ci			const struct devtable *p = &devtable[i];
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci			if (sym_is(name, namelen, p->device_id)) {
162062306a36Sopenharmony_ci				do_table(symval, sym->st_size, p->id_size,
162162306a36Sopenharmony_ci					 p->device_id, p->do_entry, mod);
162262306a36Sopenharmony_ci				break;
162362306a36Sopenharmony_ci			}
162462306a36Sopenharmony_ci		}
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci	free(zeros);
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci/* Now add out buffered information to the generated C source */
163062306a36Sopenharmony_civoid add_moddevtable(struct buffer *buf, struct module *mod)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	buf_printf(buf, "\n");
163362306a36Sopenharmony_ci	buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
163462306a36Sopenharmony_ci	free(mod->dev_table_buf.p);
163562306a36Sopenharmony_ci}
1636