Skip to content
Snippets Groups Projects
file2alias.c 37.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	DEF_FIELD(symval, zorro_device_id, id);
    
    	strcpy(alias, "zorro:");
    
    	ADD(alias, "i", id != ZORRO_WILDCARD, id);
    
    ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry);
    
    /* looks like: "pnp:dD" */
    static int do_isapnp_entry(const char *filename,
    
    	DEF_FIELD(symval, isapnp_device_id, vendor);
    	DEF_FIELD(symval, isapnp_device_id, function);
    
    	sprintf(alias, "pnp:d%c%c%c%x%x%x%x*",
    
    		'A' + ((vendor >> 2) & 0x3f) - 1,
    		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
    		'A' + ((vendor >> 8) & 0x1f) - 1,
    		(function >> 4) & 0x0f, function & 0x0f,
    		(function >> 12) & 0x0f, (function >> 8) & 0x0f);
    
    ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry);
    
    /* Looks like: "ipack:fNvNdN". */
    static int do_ipack_entry(const char *filename,
    
    	DEF_FIELD(symval, ipack_device_id, format);
    	DEF_FIELD(symval, ipack_device_id, vendor);
    	DEF_FIELD(symval, ipack_device_id, device);
    
    	strcpy(alias, "ipack:");
    
    	ADD(alias, "f", format != IPACK_ANY_FORMAT, format);
    	ADD(alias, "v", vendor != IPACK_ANY_ID, vendor);
    	ADD(alias, "d", device != IPACK_ANY_ID, device);
    
    	add_wildcard(alias);
    	return 1;
    }
    
    ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry);
    
    /*
     * Append a match expression for a single masked hex digit.
     * outp points to a pointer to the character at which to append.
     *	*outp is updated on return to point just after the appended text,
     *	to facilitate further appending.
     */
    static void append_nibble_mask(char **outp,
    			       unsigned int nibble, unsigned int mask)
    {
    	char *p = *outp;
    	unsigned int i;
    
    	switch (mask) {
    	case 0:
    		*p++ = '?';
    		break;
    
    	case 0xf:
    		p += sprintf(p, "%X",  nibble);
    		break;
    
    	default:
    		/*
    		 * Dumbly emit a match pattern for all possible matching
    		 * digits.  This could be improved in some cases using ranges,
    		 * but it has the advantage of being trivially correct, and is
    		 * often optimal.
    		 */
    		*p++ = '[';
    		for (i = 0; i < 0x10; i++)
    			if ((i & mask) == nibble)
    				p += sprintf(p, "%X", i);
    		*p++ = ']';
    	}
    
    	/* Ensure that the string remains NUL-terminated: */
    	*p = '\0';
    
    	/* Advance the caller's end-of-string pointer: */
    	*outp = p;
    }
    
    /*
     * looks like: "amba:dN"
     *
     * N is exactly 8 digits, where each is an upper-case hex digit, or
     *	a ? or [] pattern matching exactly one digit.
     */
    static int do_amba_entry(const char *filename,
    
    	DEF_FIELD(symval, amba_id, id);
    	DEF_FIELD(symval, amba_id, mask);
    
    		fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: "
    		      "id=0x%08X, mask=0x%08X.  Please fix this driver.\n",
    
    
    	p += sprintf(alias, "amba:d");
    	for (digit = 0; digit < 8; digit++)
    		append_nibble_mask(&p,
    
    				   (id >> (4 * (7 - digit))) & 0xf,
    				   (mask >> (4 * (7 - digit))) & 0xf);
    
    ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry);
    
    /* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,*
     * All fields are numbers. It would be nicer to use strings for vendor
     * and feature, but getting those out of the build system here is too
     * complicated.
     */
    
    
    static int do_x86cpu_entry(const char *filename, void *symval,
    
    	DEF_FIELD(symval, x86_cpu_id, feature);
    	DEF_FIELD(symval, x86_cpu_id, family);
    	DEF_FIELD(symval, x86_cpu_id, model);
    	DEF_FIELD(symval, x86_cpu_id, vendor);
    
    
    	strcpy(alias, "x86cpu:");
    
    	ADD(alias, "vendor:",  vendor != X86_VENDOR_ANY, vendor);
    	ADD(alias, ":family:", family != X86_FAMILY_ANY, family);
    	ADD(alias, ":model:",  model  != X86_MODEL_ANY,  model);
    
    	strcat(alias, ":feature:*");
    
    	if (feature != X86_FEATURE_ANY)
    		sprintf(alias + strlen(alias), "%04X*", feature);
    
    ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry);
    
    /* Looks like: mei:S */
    static int do_mei_entry(const char *filename, void *symval,
    			char *alias)
    {
    	DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
    
    	sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name);
    
    	return 1;
    }
    ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry);
    
    
    /* Looks like: rapidio:vNdNavNadN */
    static int do_rio_entry(const char *filename,
    			void *symval, char *alias)
    {
    	DEF_FIELD(symval, rio_device_id, did);
    	DEF_FIELD(symval, rio_device_id, vid);
    	DEF_FIELD(symval, rio_device_id, asm_did);
    	DEF_FIELD(symval, rio_device_id, asm_vid);
    
    	strcpy(alias, "rapidio:");
    	ADD(alias, "v", vid != RIO_ANY_ID, vid);
    	ADD(alias, "d", did != RIO_ANY_ID, did);
    	ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid);
    	ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did);
    
    	add_wildcard(alias);
    	return 1;
    }
    ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry);
    
    
    /* Does namelen bytes of name exactly match the symbol? */
    static bool sym_is(const char *name, unsigned namelen, const char *symbol)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	if (namelen != strlen(symbol))
    		return false;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	return memcmp(name, symbol, namelen) == 0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void do_table(void *symval, unsigned long size,
    		     unsigned long id_size,
    
    		     const char *device_id,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		     void *function,
    		     struct module *mod)
    {
    	unsigned int i;
    	char alias[500];
    	int (*do_entry)(const char *, void *entry, char *alias) = function;
    
    
    	device_id_check(mod->name, device_id, size, id_size, symval);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/* Leave last one: it's the terminator. */
    	size -= id_size;
    
    	for (i = 0; i < size; i += id_size) {
    		if (do_entry(mod->name, symval+i, alias)) {
    			buf_printf(&mod->dev_table_buf,
    				   "MODULE_ALIAS(\"%s\");\n", alias);
    		}
    	}
    }
    
    /* Create MODULE_ALIAS() statements.
     * At this time, we cannot write the actual output C source yet,
     * so we write into the mod->dev_table_buf buffer. */
    void handle_moddevtable(struct module *mod, struct elf_info *info,
    			Elf_Sym *sym, const char *symname)
    {
    	void *symval;
    
    	const char *name;
    	unsigned int namelen;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* We're looking for a section relative symbol */
    
    	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		return;
    
    
    	/* We're looking for an object */
    	if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
    		return;
    
    
    	/* All our symbols are of form <prefix>__mod_XXX_device_table. */
    	name = strstr(symname, "__mod_");
    	if (!name)
    		return;
    	name += strlen("__mod_");
    	namelen = strlen(name);
    	if (namelen < strlen("_device_table"))
    		return;
    	if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
    		return;
    	namelen -= strlen("_device_table");
    
    
    	/* Handle all-NULL symbols allocated into .bss */
    
    	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
    
    		zeros = calloc(1, sym->st_size);
    		symval = zeros;
    	} else {
    		symval = (void *)info->hdr
    
    			+ info->sechdrs[get_secindex(info, sym)].sh_offset
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	/* First handle the "special" cases */
    	if (sym_is(name, namelen, "usb"))
    
    		do_usb_table(symval, sym->st_size, mod);
    
    	else if (sym_is(name, namelen, "pnp"))
    
    		do_pnp_device_entry(symval, sym->st_size, mod);
    
    	else if (sym_is(name, namelen, "pnp_card"))
    
    		do_pnp_card_entries(symval, sym->st_size, mod);
    
    		struct devtable **p;
    
    		INIT_SECTION(__devtable);
    
    		for (p = __start___devtable; p < __stop___devtable; p++) {
    			if (sym_is(name, namelen, (*p)->device_id)) {
    				do_table(symval, sym->st_size, (*p)->id_size,
    					 (*p)->device_id, (*p)->function, mod);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /* Now add out buffered information to the generated C source */
    void add_moddevtable(struct buffer *buf, struct module *mod)
    {
    	buf_printf(buf, "\n");
    	buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
    	free(mod->dev_table_buf.p);
    }