diff options
Diffstat (limited to 'tools/usb/usbip/libsrc/names.c')
| -rw-r--r-- | tools/usb/usbip/libsrc/names.c | 504 | 
1 files changed, 504 insertions, 0 deletions
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c new file mode 100644 index 000000000000..81ff8522405c --- /dev/null +++ b/tools/usb/usbip/libsrc/names.c @@ -0,0 +1,504 @@ +/* + *      names.c  --  USB name database manipulation routines + * + *      Copyright (C) 1999, 2000  Thomas Sailer ([email protected]) + * + *      This program is free software; you can redistribute it and/or modify + *      it under the terms of the GNU General Public License as published by + *      the Free Software Foundation; either version 2 of the License, or + *      (at your option) any later version. + * + *      This program is distributed in the hope that it will be useful, + *      but WITHOUT ANY WARRANTY; without even the implied warranty of + *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *      GNU General Public License for more details. + * + *      You should have received a copy of the GNU General Public License + *      along with this program; if not, write to the Free Software + *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * + * + * + *	Copyright (C) 2005 Takahiro Hirofuchi + *		- names_deinit() is added. + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> + +#include "names.h" +#include "usbip_common.h" + +struct vendor { +	struct vendor *next; +	u_int16_t vendorid; +	char name[1]; +}; + +struct product { +	struct product *next; +	u_int16_t vendorid, productid; +	char name[1]; +}; + +struct class { +	struct class *next; +	u_int8_t classid; +	char name[1]; +}; + +struct subclass { +	struct subclass *next; +	u_int8_t classid, subclassid; +	char name[1]; +}; + +struct protocol { +	struct protocol *next; +	u_int8_t classid, subclassid, protocolid; +	char name[1]; +}; + +struct genericstrtable { +	struct genericstrtable *next; +	unsigned int num; +	char name[1]; +}; + + +#define HASH1  0x10 +#define HASH2  0x02 +#define HASHSZ 16 + +static unsigned int hashnum(unsigned int num) +{ +	unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; + +	for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) +		if (num & mask1) +			num ^= mask2; +	return num & (HASHSZ-1); +} + + +static struct vendor *vendors[HASHSZ] = { NULL, }; +static struct product *products[HASHSZ] = { NULL, }; +static struct class *classes[HASHSZ] = { NULL, }; +static struct subclass *subclasses[HASHSZ] = { NULL, }; +static struct protocol *protocols[HASHSZ] = { NULL, }; + +const char *names_vendor(u_int16_t vendorid) +{ +	struct vendor *v; + +	v = vendors[hashnum(vendorid)]; +	for (; v; v = v->next) +		if (v->vendorid == vendorid) +			return v->name; +	return NULL; +} + +const char *names_product(u_int16_t vendorid, u_int16_t productid) +{ +	struct product *p; + +	p = products[hashnum((vendorid << 16) | productid)]; +	for (; p; p = p->next) +		if (p->vendorid == vendorid && p->productid == productid) +			return p->name; +	return NULL; +} + +const char *names_class(u_int8_t classid) +{ +	struct class *c; + +	c = classes[hashnum(classid)]; +	for (; c; c = c->next) +		if (c->classid == classid) +			return c->name; +	return NULL; +} + +const char *names_subclass(u_int8_t classid, u_int8_t subclassid) +{ +	struct subclass *s; + +	s = subclasses[hashnum((classid << 8) | subclassid)]; +	for (; s; s = s->next) +		if (s->classid == classid && s->subclassid == subclassid) +			return s->name; +	return NULL; +} + +const char *names_protocol(u_int8_t classid, u_int8_t subclassid, +			   u_int8_t protocolid) +{ +	struct protocol *p; + +	p = protocols[hashnum((classid << 16) | (subclassid << 8) +			      | protocolid)]; +	for (; p; p = p->next) +		if (p->classid == classid && p->subclassid == subclassid && +		    p->protocolid == protocolid) +			return p->name; +	return NULL; +} + +/* add a cleanup function by takahiro */ +struct pool { +	struct pool *next; +	void *mem; +}; + +static struct pool *pool_head; + +static void *my_malloc(size_t size) +{ +	struct pool *p; + +	p = calloc(1, sizeof(struct pool)); +	if (!p) +		return NULL; + +	p->mem = calloc(1, size); +	if (!p->mem) { +		free(p); +		return NULL; +	} + +	p->next = pool_head; +	pool_head = p; + +	return p->mem; +} + +void names_free(void) +{ +	struct pool *pool; + +	if (!pool_head) +		return; + +	for (pool = pool_head; pool != NULL; ) { +		struct pool *tmp; + +		if (pool->mem) +			free(pool->mem); + +		tmp = pool; +		pool = pool->next; +		free(tmp); +	} +} + +static int new_vendor(const char *name, u_int16_t vendorid) +{ +	struct vendor *v; +	unsigned int h = hashnum(vendorid); + +	v = vendors[h]; +	for (; v; v = v->next) +		if (v->vendorid == vendorid) +			return -1; +	v = my_malloc(sizeof(struct vendor) + strlen(name)); +	if (!v) +		return -1; +	strcpy(v->name, name); +	v->vendorid = vendorid; +	v->next = vendors[h]; +	vendors[h] = v; +	return 0; +} + +static int new_product(const char *name, u_int16_t vendorid, +		       u_int16_t productid) +{ +	struct product *p; +	unsigned int h = hashnum((vendorid << 16) | productid); + +	p = products[h]; +	for (; p; p = p->next) +		if (p->vendorid == vendorid && p->productid == productid) +			return -1; +	p = my_malloc(sizeof(struct product) + strlen(name)); +	if (!p) +		return -1; +	strcpy(p->name, name); +	p->vendorid = vendorid; +	p->productid = productid; +	p->next = products[h]; +	products[h] = p; +	return 0; +} + +static int new_class(const char *name, u_int8_t classid) +{ +	struct class *c; +	unsigned int h = hashnum(classid); + +	c = classes[h]; +	for (; c; c = c->next) +		if (c->classid == classid) +			return -1; +	c = my_malloc(sizeof(struct class) + strlen(name)); +	if (!c) +		return -1; +	strcpy(c->name, name); +	c->classid = classid; +	c->next = classes[h]; +	classes[h] = c; +	return 0; +} + +static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) +{ +	struct subclass *s; +	unsigned int h = hashnum((classid << 8) | subclassid); + +	s = subclasses[h]; +	for (; s; s = s->next) +		if (s->classid == classid && s->subclassid == subclassid) +			return -1; +	s = my_malloc(sizeof(struct subclass) + strlen(name)); +	if (!s) +		return -1; +	strcpy(s->name, name); +	s->classid = classid; +	s->subclassid = subclassid; +	s->next = subclasses[h]; +	subclasses[h] = s; +	return 0; +} + +static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, +			u_int8_t protocolid) +{ +	struct protocol *p; +	unsigned int h = hashnum((classid << 16) | (subclassid << 8) +				 | protocolid); + +	p = protocols[h]; +	for (; p; p = p->next) +		if (p->classid == classid && p->subclassid == subclassid +		    && p->protocolid == protocolid) +			return -1; +	p = my_malloc(sizeof(struct protocol) + strlen(name)); +	if (!p) +		return -1; +	strcpy(p->name, name); +	p->classid = classid; +	p->subclassid = subclassid; +	p->protocolid = protocolid; +	p->next = protocols[h]; +	protocols[h] = p; +	return 0; +} + +static void parse(FILE *f) +{ +	char buf[512], *cp; +	unsigned int linectr = 0; +	int lastvendor = -1; +	int lastclass = -1; +	int lastsubclass = -1; +	int lasthut = -1; +	int lastlang = -1; +	unsigned int u; + +	while (fgets(buf, sizeof(buf), f)) { +		linectr++; +		/* remove line ends */ +		cp = strchr(buf, '\r'); +		if (cp) +			*cp = 0; +		cp = strchr(buf, '\n'); +		if (cp) +			*cp = 0; +		if (buf[0] == '#' || !buf[0]) +			continue; +		cp = buf; +		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && +		    buf[3] == 'S' && buf[4] == 'D' && +		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ +		    buf[7] == ' ') { +			continue; +		} +		if (buf[0] == 'P' && buf[1] == 'H' && +		    buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { +			continue; +		} +		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && +		    buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { +			continue; +		} +		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { +			lasthut = lastclass = lastvendor = lastsubclass = -1; +			/* +			 * set 1 as pseudo-id to indicate that the parser is +			 * in a `L' section. +			 */ +			lastlang = 1; +			continue; +		} +		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { +			/* class spec */ +			cp = buf+2; +			while (isspace(*cp)) +				cp++; +			if (!isxdigit(*cp)) { +				err("Invalid class spec at line %u", linectr); +				continue; +			} +			u = strtoul(cp, &cp, 16); +			while (isspace(*cp)) +				cp++; +			if (!*cp) { +				err("Invalid class spec at line %u", linectr); +				continue; +			} +			if (new_class(cp, u)) +				err("Duplicate class spec at line %u class %04x %s", +				    linectr, u, cp); +			dbg("line %5u class %02x %s", linectr, u, cp); +			lasthut = lastlang = lastvendor = lastsubclass = -1; +			lastclass = u; +			continue; +		} +		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { +			/* audio terminal type spec */ +			continue; +		} +		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' +		    && isspace(buf[3])) { +			/* HID Descriptor bCountryCode */ +			continue; +		} +		if (isxdigit(*cp)) { +			/* vendor */ +			u = strtoul(cp, &cp, 16); +			while (isspace(*cp)) +				cp++; +			if (!*cp) { +				err("Invalid vendor spec at line %u", linectr); +				continue; +			} +			if (new_vendor(cp, u)) +				err("Duplicate vendor spec at line %u vendor %04x %s", +				    linectr, u, cp); +			dbg("line %5u vendor %04x %s", linectr, u, cp); +			lastvendor = u; +			lasthut = lastlang = lastclass = lastsubclass = -1; +			continue; +		} +		if (buf[0] == '\t' && isxdigit(buf[1])) { +			/* product or subclass spec */ +			u = strtoul(buf+1, &cp, 16); +			while (isspace(*cp)) +				cp++; +			if (!*cp) { +				err("Invalid product/subclass spec at line %u", +				    linectr); +				continue; +			} +			if (lastvendor != -1) { +				if (new_product(cp, lastvendor, u)) +					err("Duplicate product spec at line %u product %04x:%04x %s", +					    linectr, lastvendor, u, cp); +				dbg("line %5u product %04x:%04x %s", linectr, +				    lastvendor, u, cp); +				continue; +			} +			if (lastclass != -1) { +				if (new_subclass(cp, lastclass, u)) +					err("Duplicate subclass spec at line %u class %02x:%02x %s", +					    linectr, lastclass, u, cp); +				dbg("line %5u subclass %02x:%02x %s", linectr, +				    lastclass, u, cp); +				lastsubclass = u; +				continue; +			} +			if (lasthut != -1) { +				/* do not store hut */ +				continue; +			} +			if (lastlang != -1) { +				/* do not store langid */ +				continue; +			} +			err("Product/Subclass spec without prior Vendor/Class spec at line %u", +			    linectr); +			continue; +		} +		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { +			/* protocol spec */ +			u = strtoul(buf+2, &cp, 16); +			while (isspace(*cp)) +				cp++; +			if (!*cp) { +				err("Invalid protocol spec at line %u", +				    linectr); +				continue; +			} +			if (lastclass != -1 && lastsubclass != -1) { +				if (new_protocol(cp, lastclass, lastsubclass, +						 u)) +					err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", +					    linectr, lastclass, lastsubclass, +					    u, cp); +				dbg("line %5u protocol %02x:%02x:%02x %s", +				    linectr, lastclass, lastsubclass, u, cp); +				continue; +			} +			err("Protocol spec without prior Class and Subclass spec at line %u", +			    linectr); +			continue; +		} +		if (buf[0] == 'H' && buf[1] == 'I' && +		    buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { +			continue; +		} +		if (buf[0] == 'H' && buf[1] == 'U' && +		    buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { +			lastlang = lastclass = lastvendor = lastsubclass = -1; +			/* +			 * set 1 as pseudo-id to indicate that the parser is +			 * in a `HUT' section. +			 */ +			lasthut = 1; +			continue; +		} +		if (buf[0] == 'R' && buf[1] == ' ') +			continue; + +		if (buf[0] == 'V' && buf[1] == 'T') +			continue; + +		err("Unknown line at line %u", linectr); +	} +} + + +int names_init(char *n) +{ +	FILE *f; + +	f = fopen(n, "r"); +	if (!f) +		return errno; + +	parse(f); +	fclose(f); +	return 0; +}  |