1/*
2 * Copyright (c) 2003
3 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34#ifdef __FreeBSD__
35__FBSDID("$FreeBSD: src/usr.sbin/ndiscvt/inf.c,v 1.13.2.1 2005/02/18 16:30:10 wpaul Exp $");
36#endif
37#ifdef __NetBSD__
38__RCSID("$NetBSD: inf.c,v 1.3 2006/04/18 16:49:19 rittera Exp $");
39#endif
40
41
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <sys/types.h>
46#ifdef __NetBSD__
47#include <sys/stdint.h>
48#endif
49
50#include <sys/queue.h>
51
52#include "inf.h"
53
54#ifndef __DECONST
55#define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
56#endif
57
58
59extern FILE *ndiscvt_in;
60int ndiscvt_parse (void);
61
62const char *words[W_MAX];	/* More than we'll need. */
63int idx;
64
65static struct section_head sh;
66static struct reg_head rh;
67static struct assign_head ah;
68
69static char	*sstrdup	(const char *);
70static struct assign
71		*find_assign	(const char *, const char *);
72static struct section
73		*find_section	(const char *);
74static void	dump_deviceids_pci	(void);
75static void	dump_deviceids_pcmcia	(void);
76static void	dump_pci_id	(const char *);
77static void	dump_pcmcia_id	(const char *);
78static void	dump_regvals	(void);
79static void	dump_paramreg	(const struct section *,
80				const struct reg *, int);
81
82static FILE	*ofp;
83
84int
85inf_parse (FILE *fp, FILE *outfp)
86{
87	TAILQ_INIT(&sh);
88	TAILQ_INIT(&rh);
89	TAILQ_INIT(&ah);
90
91	ofp = outfp;
92	ndiscvt_in = fp;
93	ndiscvt_parse();
94
95	dump_deviceids_pci();
96	dump_deviceids_pcmcia();
97	fprintf(outfp, "#ifdef NDIS_REGVALS\n");
98	dump_regvals();
99	fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
100
101	return (0);
102}
103
104void
105section_add (const char *s)
106{
107	struct section *sec;
108
109	sec = malloc(sizeof(struct section));
110	bzero(sec, sizeof(struct section));
111	sec->name = s;
112	TAILQ_INSERT_TAIL(&sh, sec, link);
113
114	return;
115}
116
117static struct assign *
118find_assign (const char *s, const char *k)
119{
120	struct assign *assign;
121	char newkey[256];
122
123	/* Deal with string section lookups. */
124
125	if (k != NULL && k[0] == '%') {
126		bzero(newkey, sizeof(newkey));
127		strncpy(newkey, k + 1, strlen(k) - 2);
128		k = newkey;
129	}
130
131	TAILQ_FOREACH(assign, &ah, link) {
132		if (strcasecmp(assign->section->name, s) == 0) {
133			if (k == NULL)
134				return(assign);
135			else
136				if (strcasecmp(assign->key, k) == 0)
137					return(assign);
138		}
139	}
140	return(NULL);
141}
142
143static const char *
144stringcvt(const char *s)
145{
146	struct assign *manf;
147
148	manf = find_assign("strings", s);
149	if (manf == NULL)
150		return(s);
151	return(manf->vals[0]);
152}
153
154struct section *
155find_section (const char *s)
156{
157	struct section *section;
158
159	TAILQ_FOREACH(section, &sh, link) {
160		if (strcasecmp(section->name, s) == 0)
161			return(section);
162	}
163	return(NULL);
164}
165
166static void
167dump_pcmcia_id(const char *s)
168{
169	char *manstr, *devstr;
170	char *p0, *p;
171
172	p0 = __DECONST(char *, s);
173
174	p = strchr(p0, '\\');
175	if (p == NULL)
176		return;
177	p0 = p + 1;
178
179	p = strchr(p0, '-');
180	if (p == NULL)
181		return;
182	*p = '\0';
183
184	manstr = p0;
185
186	/* Convert any underscores to spaces. */
187
188	while (*p0 != '\0') {
189		if (*p0 == '_')
190			*p0 = ' ';
191		p0++;
192	}
193
194	p0 = p + 1;
195	p = strchr(p0, '-');
196	if (p == NULL)
197		return;
198	*p = '\0';
199
200	devstr = p0;
201
202	/* Convert any underscores to spaces. */
203
204	while (*p0 != '\0') {
205		if (*p0 == '_')
206			*p0 = ' ';
207		p0++;
208	}
209
210	fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
211	return;
212}
213
214static void
215dump_pci_id(const char *s)
216{
217	char *p;
218	char vidstr[7], didstr[7], subsysstr[14];
219
220	p = strcasestr(s, "VEN_");
221	if (p == NULL)
222		return;
223	p += 4;
224	strcpy(vidstr, "0x");
225	strncat(vidstr, p, 4);
226	p = strcasestr(s, "DEV_");
227	if (p == NULL)
228		return;
229	p += 4;
230	strcpy(didstr, "0x");
231	strncat(didstr, p, 4);
232	if (p == NULL)
233		return;
234	p = strcasestr(s, "SUBSYS_");
235	if (p == NULL)
236		strcpy(subsysstr, "0x00000000");
237	else {
238		p += 7;
239		strcpy(subsysstr, "0x");
240		strncat(subsysstr, p, 8);
241	}
242
243	fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
244	return;
245}
246
247static void
248dump_deviceids_pci()
249{
250	struct assign *manf, *dev;
251	struct section *sec;
252	struct assign *assign;
253	char xpsec[256];
254	int found = 0;
255
256	/* Find manufacturer name */
257	manf = find_assign("Manufacturer", NULL);
258
259	/* Find manufacturer section */
260	if (manf->vals[1] != NULL &&
261	    (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
262	    strcasecmp(manf->vals[1], "NTx86") == 0 ||
263	    strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
264	    strcasecmp(manf->vals[1], "NTamd64") == 0)) {
265		/* Handle Windows XP INF files. */
266		snprintf(xpsec, sizeof(xpsec), "%s.%s",
267		    manf->vals[0], manf->vals[1]);
268		sec = find_section(xpsec);
269	} else
270		sec = find_section(manf->vals[0]);
271
272	/* See if there are any PCI device definitions. */
273
274	TAILQ_FOREACH(assign, &ah, link) {
275		if (assign->section == sec) {
276			dev = find_assign("strings", assign->key);
277			if (strcasestr(assign->vals[1], "PCI") != NULL) {
278				found++;
279				break;
280			}
281		}
282	}
283
284	if (found == 0)
285		return;
286
287	found = 0;
288
289	/* Emit start of PCI device table */
290	fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
291
292retry:
293
294	/*
295	 * Now run through all the device names listed
296	 * in the manufacturer section and dump out the
297	 * device descriptions and vendor/device IDs.
298	 */
299
300	TAILQ_FOREACH(assign, &ah, link) {
301		if (assign->section == sec) {
302			dev = find_assign("strings", assign->key);
303			/* Emit device IDs. */
304			if (strcasestr(assign->vals[1], "PCI") != NULL)
305				dump_pci_id(assign->vals[1]);
306			else
307				continue;
308			/* Emit device description */
309			fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
310			found++;
311		}
312	}
313
314	/* Someone tried to fool us. Shame on them. */
315	if (!found) {
316		found++;
317		sec = find_section(manf->vals[0]);
318		goto retry;
319	}
320
321	/* Emit end of table */
322
323	fprintf(ofp, "\n\n");
324
325}
326
327static void
328dump_deviceids_pcmcia()
329{
330	struct assign *manf, *dev;
331	struct section *sec;
332	struct assign *assign;
333	char xpsec[256];
334	int found = 0;
335
336	/* Find manufacturer name */
337	manf = find_assign("Manufacturer", NULL);
338
339	/* Find manufacturer section */
340	if (manf->vals[1] != NULL &&
341	    (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
342	    strcasecmp(manf->vals[1], "NTx86") == 0 ||
343	    strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
344	    strcasecmp(manf->vals[1], "NTamd64") == 0)) {
345		/* Handle Windows XP INF files. */
346		snprintf(xpsec, sizeof(xpsec), "%s.%s",
347		    manf->vals[0], manf->vals[1]);
348		sec = find_section(xpsec);
349	} else
350		sec = find_section(manf->vals[0]);
351
352	/* See if there are any PCMCIA device definitions. */
353
354	TAILQ_FOREACH(assign, &ah, link) {
355		if (assign->section == sec) {
356			dev = find_assign("strings", assign->key);
357			if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
358				found++;
359				break;
360			}
361		}
362	}
363
364	if (found == 0)
365		return;
366
367	found = 0;
368
369	/* Emit start of PCMCIA device table */
370	fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
371
372retry:
373
374	/*
375	 * Now run through all the device names listed
376	 * in the manufacturer section and dump out the
377	 * device descriptions and vendor/device IDs.
378	 */
379
380	TAILQ_FOREACH(assign, &ah, link) {
381		if (assign->section == sec) {
382			dev = find_assign("strings", assign->key);
383			/* Emit device IDs. */
384			if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
385				dump_pcmcia_id(assign->vals[1]);
386			else
387				continue;
388			/* Emit device description */
389			fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
390			found++;
391		}
392	}
393
394	/* Someone tried to fool us. Shame on them. */
395	if (!found) {
396		found++;
397		sec = find_section(manf->vals[0]);
398		goto retry;
399	}
400
401	/* Emit end of table */
402
403	fprintf(ofp, "\n\n");
404
405}
406
407static void
408dump_addreg(const char *s, int devidx)
409{
410	struct section *sec;
411	struct reg *reg;
412
413	/* Find the addreg section */
414	sec = find_section(s);
415
416	/* Dump all the keys defined in it. */
417	TAILQ_FOREACH(reg, &rh, link) {
418		/*
419		 * Keys with an empty subkey are very easy to parse,
420		 * so just deal with them here. If a parameter key
421		 * of the same name also exists, prefer that one and
422		 * skip this one.
423		 */
424		if (reg->section == sec) {
425			if (reg->subkey == NULL) {
426				fprintf(ofp, "\n\t{ \"%s\",", reg->key);
427				fprintf(ofp,"\n\t\"%s \",", reg->key);
428				fprintf(ofp, "\n\t{ \"%s\" }, %d },",
429				    reg->value == NULL ? "" :
430				    stringcvt(reg->value), devidx);
431			} else if (strncasecmp(reg->subkey,
432			    "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
433			    (reg->key != NULL && strcasecmp(reg->key,
434			    "ParamDesc") == 0))
435				dump_paramreg(sec, reg, devidx);
436		}
437	}
438
439	return;
440}
441
442static void
443dump_enumreg(const struct section *s, const struct reg *r)
444{
445	struct reg *reg;
446	char enumkey[256];
447
448	sprintf(enumkey, "%s\\enum", r->subkey);
449	TAILQ_FOREACH(reg, &rh, link) {
450		if (reg->section != s)
451			continue;
452		if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
453			continue;
454		fprintf(ofp, " [%s=%s]", reg->key,
455		    stringcvt(reg->value));
456	}
457	return;
458}
459
460static void
461dump_editreg(const struct section *s, const struct reg *r)
462{
463	struct reg *reg;
464
465	TAILQ_FOREACH(reg, &rh, link) {
466		if (reg->section != s)
467			continue;
468		if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
469			continue;
470		if (reg->key == NULL)
471			continue;
472		if (strcasecmp(reg->key, "LimitText") == 0)
473			fprintf(ofp, " [maxchars=%s]", reg->value);
474		if (strcasecmp(reg->key, "Optional") == 0 &&
475		    strcmp(reg->value, "1") == 0)
476			fprintf(ofp, " [optional]");
477	}
478	return;
479}
480
481/* Use this for int too */
482static void
483dump_dwordreg(const struct section *s, const struct reg *r)
484{
485	struct reg *reg;
486
487	TAILQ_FOREACH(reg, &rh, link) {
488		if (reg->section != s)
489			continue;
490		if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
491			continue;
492		if (reg->key == NULL)
493			continue;
494		if (strcasecmp(reg->key, "min") == 0)
495			fprintf(ofp, " [min=%s]", reg->value);
496		if (strcasecmp(reg->key, "max") == 0)
497			fprintf(ofp, " [max=%s]", reg->value);
498	}
499	return;
500}
501
502static void
503dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
504{
505	struct reg *reg;
506	TAILQ_FOREACH(reg, &rh, link) {
507		if (reg->section != s)
508			continue;
509		if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
510			continue;
511		if (reg->key == NULL || strcasecmp(reg->key, "Default"))
512			continue;
513		fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
514		    stringcvt(reg->value), devidx);
515			break;
516	}
517	return;
518}
519
520static void
521dump_paramdesc(const struct section *s, const struct reg *r)
522{
523	struct reg *reg;
524	TAILQ_FOREACH(reg, &rh, link) {
525		if (reg->section != s)
526			continue;
527		if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
528			continue;
529		if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
530			continue;
531		fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
532			break;
533	}
534	return;
535}
536
537static void
538dump_typeinfo(const struct section *s, const struct reg *r)
539{
540	struct reg *reg;
541	TAILQ_FOREACH(reg, &rh, link) {
542		if (reg->section != s)
543			continue;
544		if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
545			continue;
546		if (reg->key == NULL)
547			continue;
548		if (strcasecmp(reg->key, "type"))
549			continue;
550		if (strcasecmp(reg->value, "dword") == 0 ||
551		    strcasecmp(reg->value, "int") == 0)
552			dump_dwordreg(s, r);
553		if (strcasecmp(reg->value, "enum") == 0)
554			dump_enumreg(s, r);
555		if (strcasecmp(reg->value, "edit") == 0)
556			dump_editreg(s, r);
557	}
558	return;
559}
560
561static void
562dump_paramreg(const struct section *s, const struct reg *r, int devidx)
563{
564	const char *keyname;
565
566	keyname = r->subkey + strlen("Ndi\\params\\");
567	fprintf(ofp, "\n\t{ \"%s\",", keyname);
568	dump_paramdesc(s, r);
569	dump_typeinfo(s, r);
570	fprintf(ofp, "\",");
571	dump_defaultinfo(s, r, devidx);
572
573	return;
574}
575
576static void
577dump_regvals(void)
578{
579	struct assign *manf, *dev;
580	struct section *sec;
581	struct assign *assign;
582	char sname[256];
583	int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
584
585	/* Find signature to check for special case of WinNT. */
586	assign = find_assign("version", "signature");
587	if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
588		is_winnt++;
589
590	/* Find manufacturer name */
591	manf = find_assign("Manufacturer", NULL);
592
593	/* Find manufacturer section */
594	if (manf->vals[1] != NULL &&
595	    (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
596	    strcasecmp(manf->vals[1], "NTx86") == 0 ||
597	    strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
598	    strcasecmp(manf->vals[1], "NTamd64") == 0)) {
599		is_winxp++;
600		/* Handle Windows XP INF files. */
601		snprintf(sname, sizeof(sname), "%s.%s",
602		    manf->vals[0], manf->vals[1]);
603		sec = find_section(sname);
604	} else
605		sec = find_section(manf->vals[0]);
606
607	/* Emit start of block */
608	fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
609
610retry:
611
612	TAILQ_FOREACH(assign, &ah, link) {
613		if (assign->section == sec) {
614			found++;
615			/*
616			 * Find all the AddReg sections.
617			 * Look for section names with .NT, unless
618			 * this is a WinXP .INF file.
619			 */
620
621			if (is_winxp) {
622				sprintf(sname, "%s.NTx86", assign->vals[0]);
623				dev = find_assign(sname, "AddReg");
624				if (dev == NULL) {
625					sprintf(sname, "%s.NT",
626					    assign->vals[0]);
627					dev = find_assign(sname, "AddReg");
628				}
629				if (dev == NULL)
630					dev = find_assign(assign->vals[0],
631					    "AddReg");
632			} else {
633				sprintf(sname, "%s.NT", assign->vals[0]);
634				dev = find_assign(sname, "AddReg");
635				if (dev == NULL && is_winnt)
636					dev = find_assign(assign->vals[0],
637					    "AddReg");
638			}
639			/* Section not found. */
640			if (dev == NULL)
641				continue;
642			for (i = 0; i < W_MAX; i++) {
643				if (dev->vals[i] != NULL)
644					dump_addreg(dev->vals[i], devidx);
645			}
646			devidx++;
647		}
648	}
649
650	if (!found) {
651		sec = find_section(manf->vals[0]);
652		is_winxp = 0;
653		found++;
654		goto retry;
655	}
656
657	fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
658
659	return;
660}
661
662void
663assign_add (const char *a)
664{
665	struct assign *assign;
666	int i;
667
668	assign = malloc(sizeof(struct assign));
669	bzero(assign, sizeof(struct assign));
670	assign->section = TAILQ_LAST(&sh, section_head);
671	assign->key = sstrdup(a);
672	for (i = 0; i < idx; i++)
673		assign->vals[(idx - 1) - i] = sstrdup(words[i]);
674	TAILQ_INSERT_TAIL(&ah, assign, link);
675
676	clear_words();
677	return;
678}
679
680void
681define_add (const char *d __unused)
682{
683#ifdef notdef
684	fprintf(stderr, "define \"%s\"\n", d);
685#endif
686	return;
687}
688
689static char *
690sstrdup(const char *str)
691{
692	if (str != NULL && strlen(str))
693		return (strdup(str));
694	return (NULL);
695}
696
697static int
698satoi (const char *nptr)
699{
700	if (nptr != NULL && strlen(nptr))
701		return (atoi(nptr));
702	return (0);
703}
704
705void
706regkey_add (const char *r)
707{
708	struct reg *reg;
709
710	reg = malloc(sizeof(struct reg));
711	bzero(reg, sizeof(struct reg));
712	reg->section = TAILQ_LAST(&sh, section_head);
713	reg->root = sstrdup(r);
714	reg->subkey = sstrdup(words[3]);
715	reg->key = sstrdup(words[2]);
716	reg->flags = satoi(words[1]);
717	reg->value = sstrdup(words[0]);
718	TAILQ_INSERT_TAIL(&rh, reg, link);
719
720	free(__DECONST(char *, r));
721	clear_words();
722	return;
723}
724
725void
726push_word (const char *w)
727{
728	if (w && strlen(w))
729		words[idx++] = w;
730	else
731		words[idx++] = NULL;
732	return;
733}
734
735void
736clear_words (void)
737{
738	int i;
739
740	for (i = 0; i < idx; i++) {
741		if (words[i]) {
742			free(__DECONST(char *, words[i]));
743		}
744	}
745	idx = 0;
746	bzero(words, sizeof(words));
747	return;
748}
749