Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 *      names.c  --  USB name database manipulation routines
  3 *
  4 *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
  5 *
  6 *      This program is free software; you can redistribute it and/or modify
  7 *      it under the terms of the GNU General Public License as published by
  8 *      the Free Software Foundation; either version 2 of the License, or
  9 *      (at your option) any later version.
 10 *
 11 *      This program is distributed in the hope that it will be useful,
 12 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 *      GNU General Public License for more details.
 15 *
 16 *      You should have received a copy of the GNU General Public License
 17 *      along with this program; if not, write to the Free Software
 18 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 19 *
 20 *
 21 *
 22 *
 23 *
 24 *	Copyright (C) 2005 Takahiro Hirofuchi
 25 *		- names_deinit() is added.
 26 *
 27 */
 28
 29#include <sys/types.h>
 30#include <sys/stat.h>
 31#include <fcntl.h>
 32#include <dirent.h>
 33#include <string.h>
 34#include <errno.h>
 35#include <stdlib.h>
 36#include <unistd.h>
 37#include <stdio.h>
 38#include <ctype.h>
 39
 40#include "names.h"
 41#include "usbip_common.h"
 42
 43struct vendor {
 44	struct vendor *next;
 45	u_int16_t vendorid;
 46	char name[1];
 47};
 48
 49struct product {
 50	struct product *next;
 51	u_int16_t vendorid, productid;
 52	char name[1];
 53};
 54
 55struct class {
 56	struct class *next;
 57	u_int8_t classid;
 58	char name[1];
 59};
 60
 61struct subclass {
 62	struct subclass *next;
 63	u_int8_t classid, subclassid;
 64	char name[1];
 65};
 66
 67struct protocol {
 68	struct protocol *next;
 69	u_int8_t classid, subclassid, protocolid;
 70	char name[1];
 71};
 72
 73struct genericstrtable {
 74	struct genericstrtable *next;
 75	unsigned int num;
 76	char name[1];
 77};
 78
 79
 80#define HASH1  0x10
 81#define HASH2  0x02
 82#define HASHSZ 16
 83
 84static unsigned int hashnum(unsigned int num)
 85{
 86	unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
 87
 88	for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
 89		if (num & mask1)
 90			num ^= mask2;
 91	return num & (HASHSZ-1);
 92}
 93
 94
 95static struct vendor *vendors[HASHSZ] = { NULL, };
 96static struct product *products[HASHSZ] = { NULL, };
 97static struct class *classes[HASHSZ] = { NULL, };
 98static struct subclass *subclasses[HASHSZ] = { NULL, };
 99static struct protocol *protocols[HASHSZ] = { NULL, };
100
101const char *names_vendor(u_int16_t vendorid)
102{
103	struct vendor *v;
104
105	v = vendors[hashnum(vendorid)];
106	for (; v; v = v->next)
107		if (v->vendorid == vendorid)
108			return v->name;
109	return NULL;
110}
111
112const char *names_product(u_int16_t vendorid, u_int16_t productid)
113{
114	struct product *p;
115
116	p = products[hashnum((vendorid << 16) | productid)];
117	for (; p; p = p->next)
118		if (p->vendorid == vendorid && p->productid == productid)
119			return p->name;
120	return NULL;
121}
122
123const char *names_class(u_int8_t classid)
124{
125	struct class *c;
126
127	c = classes[hashnum(classid)];
128	for (; c; c = c->next)
129		if (c->classid == classid)
130			return c->name;
131	return NULL;
132}
133
134const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
135{
136	struct subclass *s;
137
138	s = subclasses[hashnum((classid << 8) | subclassid)];
139	for (; s; s = s->next)
140		if (s->classid == classid && s->subclassid == subclassid)
141			return s->name;
142	return NULL;
143}
144
145const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
146			   u_int8_t protocolid)
147{
148	struct protocol *p;
149
150	p = protocols[hashnum((classid << 16) | (subclassid << 8)
151			      | protocolid)];
152	for (; p; p = p->next)
153		if (p->classid == classid && p->subclassid == subclassid &&
154		    p->protocolid == protocolid)
155			return p->name;
156	return NULL;
157}
158
159/* add a cleanup function by takahiro */
160struct pool {
161	struct pool *next;
162	void *mem;
163};
164
165static struct pool *pool_head;
166
167static void *my_malloc(size_t size)
168{
169	struct pool *p;
170
171	p = calloc(1, sizeof(struct pool));
172	if (!p)
173		return NULL;
174
175	p->mem = calloc(1, size);
176	if (!p->mem) {
177		free(p);
178		return NULL;
179	}
180
181	p->next = pool_head;
182	pool_head = p;
183
184	return p->mem;
185}
186
187void names_free(void)
188{
189	struct pool *pool;
190
191	if (!pool_head)
192		return;
193
194	for (pool = pool_head; pool != NULL; ) {
195		struct pool *tmp;
196
197		if (pool->mem)
198			free(pool->mem);
199
200		tmp = pool;
201		pool = pool->next;
202		free(tmp);
203	}
204}
205
206static int new_vendor(const char *name, u_int16_t vendorid)
207{
208	struct vendor *v;
209	unsigned int h = hashnum(vendorid);
210
211	v = vendors[h];
212	for (; v; v = v->next)
213		if (v->vendorid == vendorid)
214			return -1;
215	v = my_malloc(sizeof(struct vendor) + strlen(name));
216	if (!v)
217		return -1;
218	strcpy(v->name, name);
219	v->vendorid = vendorid;
220	v->next = vendors[h];
221	vendors[h] = v;
222	return 0;
223}
224
225static int new_product(const char *name, u_int16_t vendorid,
226		       u_int16_t productid)
227{
228	struct product *p;
229	unsigned int h = hashnum((vendorid << 16) | productid);
230
231	p = products[h];
232	for (; p; p = p->next)
233		if (p->vendorid == vendorid && p->productid == productid)
234			return -1;
235	p = my_malloc(sizeof(struct product) + strlen(name));
236	if (!p)
237		return -1;
238	strcpy(p->name, name);
239	p->vendorid = vendorid;
240	p->productid = productid;
241	p->next = products[h];
242	products[h] = p;
243	return 0;
244}
245
246static int new_class(const char *name, u_int8_t classid)
247{
248	struct class *c;
249	unsigned int h = hashnum(classid);
250
251	c = classes[h];
252	for (; c; c = c->next)
253		if (c->classid == classid)
254			return -1;
255	c = my_malloc(sizeof(struct class) + strlen(name));
256	if (!c)
257		return -1;
258	strcpy(c->name, name);
259	c->classid = classid;
260	c->next = classes[h];
261	classes[h] = c;
262	return 0;
263}
264
265static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
266{
267	struct subclass *s;
268	unsigned int h = hashnum((classid << 8) | subclassid);
269
270	s = subclasses[h];
271	for (; s; s = s->next)
272		if (s->classid == classid && s->subclassid == subclassid)
273			return -1;
274	s = my_malloc(sizeof(struct subclass) + strlen(name));
275	if (!s)
276		return -1;
277	strcpy(s->name, name);
278	s->classid = classid;
279	s->subclassid = subclassid;
280	s->next = subclasses[h];
281	subclasses[h] = s;
282	return 0;
283}
284
285static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
286			u_int8_t protocolid)
287{
288	struct protocol *p;
289	unsigned int h = hashnum((classid << 16) | (subclassid << 8)
290				 | protocolid);
291
292	p = protocols[h];
293	for (; p; p = p->next)
294		if (p->classid == classid && p->subclassid == subclassid
295		    && p->protocolid == protocolid)
296			return -1;
297	p = my_malloc(sizeof(struct protocol) + strlen(name));
298	if (!p)
299		return -1;
300	strcpy(p->name, name);
301	p->classid = classid;
302	p->subclassid = subclassid;
303	p->protocolid = protocolid;
304	p->next = protocols[h];
305	protocols[h] = p;
306	return 0;
307}
308
309static void parse(FILE *f)
310{
311	char buf[512], *cp;
312	unsigned int linectr = 0;
313	int lastvendor = -1;
314	int lastclass = -1;
315	int lastsubclass = -1;
316	int lasthut = -1;
317	int lastlang = -1;
318	unsigned int u;
319
320	while (fgets(buf, sizeof(buf), f)) {
321		linectr++;
322		/* remove line ends */
323		cp = strchr(buf, '\r');
324		if (cp)
325			*cp = 0;
326		cp = strchr(buf, '\n');
327		if (cp)
328			*cp = 0;
329		if (buf[0] == '#' || !buf[0])
330			continue;
331		cp = buf;
332		if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
333		    buf[3] == 'S' && buf[4] == 'D' &&
334		    buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
335		    buf[7] == ' ') {
336			continue;
337		}
338		if (buf[0] == 'P' && buf[1] == 'H' &&
339		    buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
340			continue;
341		}
342		if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
343		    buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
344			continue;
345		}
346		if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
347			lasthut = lastclass = lastvendor = lastsubclass = -1;
348			/*
349			 * set 1 as pseudo-id to indicate that the parser is
350			 * in a `L' section.
351			 */
352			lastlang = 1;
353			continue;
354		}
355		if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
356			/* class spec */
357			cp = buf+2;
358			while (isspace(*cp))
359				cp++;
360			if (!isxdigit(*cp)) {
361				err("Invalid class spec at line %u", linectr);
362				continue;
363			}
364			u = strtoul(cp, &cp, 16);
365			while (isspace(*cp))
366				cp++;
367			if (!*cp) {
368				err("Invalid class spec at line %u", linectr);
369				continue;
370			}
371			if (new_class(cp, u))
372				err("Duplicate class spec at line %u class %04x %s",
373				    linectr, u, cp);
374			dbg("line %5u class %02x %s", linectr, u, cp);
375			lasthut = lastlang = lastvendor = lastsubclass = -1;
376			lastclass = u;
377			continue;
378		}
379		if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
380			/* audio terminal type spec */
381			continue;
382		}
383		if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
384		    && isspace(buf[3])) {
385			/* HID Descriptor bCountryCode */
386			continue;
387		}
388		if (isxdigit(*cp)) {
389			/* vendor */
390			u = strtoul(cp, &cp, 16);
391			while (isspace(*cp))
392				cp++;
393			if (!*cp) {
394				err("Invalid vendor spec at line %u", linectr);
395				continue;
396			}
397			if (new_vendor(cp, u))
398				err("Duplicate vendor spec at line %u vendor %04x %s",
399				    linectr, u, cp);
400			dbg("line %5u vendor %04x %s", linectr, u, cp);
401			lastvendor = u;
402			lasthut = lastlang = lastclass = lastsubclass = -1;
403			continue;
404		}
405		if (buf[0] == '\t' && isxdigit(buf[1])) {
406			/* product or subclass spec */
407			u = strtoul(buf+1, &cp, 16);
408			while (isspace(*cp))
409				cp++;
410			if (!*cp) {
411				err("Invalid product/subclass spec at line %u",
412				    linectr);
413				continue;
414			}
415			if (lastvendor != -1) {
416				if (new_product(cp, lastvendor, u))
417					err("Duplicate product spec at line %u product %04x:%04x %s",
418					    linectr, lastvendor, u, cp);
419				dbg("line %5u product %04x:%04x %s", linectr,
420				    lastvendor, u, cp);
421				continue;
422			}
423			if (lastclass != -1) {
424				if (new_subclass(cp, lastclass, u))
425					err("Duplicate subclass spec at line %u class %02x:%02x %s",
426					    linectr, lastclass, u, cp);
427				dbg("line %5u subclass %02x:%02x %s", linectr,
428				    lastclass, u, cp);
429				lastsubclass = u;
430				continue;
431			}
432			if (lasthut != -1) {
433				/* do not store hut */
434				continue;
435			}
436			if (lastlang != -1) {
437				/* do not store langid */
438				continue;
439			}
440			err("Product/Subclass spec without prior Vendor/Class spec at line %u",
441			    linectr);
442			continue;
443		}
444		if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
445			/* protocol spec */
446			u = strtoul(buf+2, &cp, 16);
447			while (isspace(*cp))
448				cp++;
449			if (!*cp) {
450				err("Invalid protocol spec at line %u",
451				    linectr);
452				continue;
453			}
454			if (lastclass != -1 && lastsubclass != -1) {
455				if (new_protocol(cp, lastclass, lastsubclass,
456						 u))
457					err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
458					    linectr, lastclass, lastsubclass,
459					    u, cp);
460				dbg("line %5u protocol %02x:%02x:%02x %s",
461				    linectr, lastclass, lastsubclass, u, cp);
462				continue;
463			}
464			err("Protocol spec without prior Class and Subclass spec at line %u",
465			    linectr);
466			continue;
467		}
468		if (buf[0] == 'H' && buf[1] == 'I' &&
469		    buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
470			continue;
471		}
472		if (buf[0] == 'H' && buf[1] == 'U' &&
473		    buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
474			lastlang = lastclass = lastvendor = lastsubclass = -1;
475			/*
476			 * set 1 as pseudo-id to indicate that the parser is
477			 * in a `HUT' section.
478			 */
479			lasthut = 1;
480			continue;
481		}
482		if (buf[0] == 'R' && buf[1] == ' ')
483			continue;
484
485		if (buf[0] == 'V' && buf[1] == 'T')
486			continue;
487
488		err("Unknown line at line %u", linectr);
489	}
490}
491
492
493int names_init(char *n)
494{
495	FILE *f;
496
497	f = fopen(n, "r");
498	if (!f)
499		return errno;
500
501	parse(f);
502	fclose(f);
503	return 0;
504}