]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/ndiscvt/inf.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / usr.sbin / ndiscvt / inf.c
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 __FBSDID("$FreeBSD$");
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40
41 #include <sys/queue.h>
42
43 #include "inf.h"
44
45 extern FILE *yyin;
46 int yyparse (void);
47
48 const char *words[W_MAX];       /* More than we'll need. */
49 int idx;
50
51 static struct section_head sh;
52 static struct reg_head rh;
53 static struct assign_head ah;
54
55 static char     *sstrdup        (const char *);
56 static struct assign
57                 *find_assign    (const char *, const char *);
58 static struct assign
59                 *find_next_assign
60                                 (struct assign *);
61 static struct section
62                 *find_section   (const char *);
63 static void     dump_deviceids_pci      (void);
64 static void     dump_deviceids_pcmcia   (void);
65 static void     dump_pci_id     (const char *);
66 static void     dump_pcmcia_id  (const char *);
67 static void     dump_regvals    (void);
68 static void     dump_paramreg   (const struct section *,
69                                 const struct reg *, int);
70
71 static FILE     *ofp;
72
73 int
74 inf_parse (FILE *fp, FILE *outfp)
75 {
76         TAILQ_INIT(&sh);
77         TAILQ_INIT(&rh);
78         TAILQ_INIT(&ah);
79
80         ofp = outfp;
81         yyin = fp;
82         yyparse();
83
84         dump_deviceids_pci();
85         dump_deviceids_pcmcia();
86         fprintf(outfp, "#ifdef NDIS_REGVALS\n");
87         dump_regvals();
88         fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
89
90         return (0);
91 }
92
93 void
94 section_add (const char *s)
95 {
96         struct section *sec;
97
98         sec = malloc(sizeof(struct section));
99         bzero(sec, sizeof(struct section));
100         sec->name = s;
101         TAILQ_INSERT_TAIL(&sh, sec, link);
102
103         return;
104 }
105
106 static struct assign *
107 find_assign (const char *s, const char *k)
108 {
109         struct assign *assign;
110         char newkey[256];
111
112         /* Deal with string section lookups. */
113
114         if (k != NULL && k[0] == '%') {
115                 bzero(newkey, sizeof(newkey));
116                 strncpy(newkey, k + 1, strlen(k) - 2);
117                 k = newkey;
118         }
119
120         TAILQ_FOREACH(assign, &ah, link) {
121                 if (strcasecmp(assign->section->name, s) == 0) {
122                         if (k == NULL)
123                                 return(assign);
124                         else
125                                 if (strcasecmp(assign->key, k) == 0)
126                                         return(assign);
127                 }
128         }
129         return(NULL);
130 }
131
132 static struct assign *
133 find_next_assign (struct assign *a)
134 {
135         struct assign *assign;
136
137         TAILQ_FOREACH(assign, &ah, link) {
138                 if (assign == a)
139                         break;
140         }
141
142         assign = assign->link.tqe_next;
143
144         if (assign == NULL || assign->section != a->section)
145                 return(NULL);
146
147         return (assign);
148 }
149
150 static const char *
151 stringcvt(const char *s)
152 {
153         struct assign *manf;
154
155         manf = find_assign("strings", s);
156         if (manf == NULL)
157                 return(s);
158         return(manf->vals[0]);
159 }
160
161 struct section *
162 find_section (const char *s)
163 {
164         struct section *section;
165
166         TAILQ_FOREACH(section, &sh, link) {
167                 if (strcasecmp(section->name, s) == 0)
168                         return(section);
169         }
170         return(NULL);
171 }
172
173 static void
174 dump_pcmcia_id(const char *s)
175 {
176         char *manstr, *devstr;
177         char *p0, *p;
178
179         p0 = __DECONST(char *, s);
180
181         p = strchr(p0, '\\');
182         if (p == NULL)
183                 return;
184         p0 = p + 1;
185
186         p = strchr(p0, '-');
187         if (p == NULL)
188                 return;
189         *p = '\0';
190
191         manstr = p0;
192
193         /* Convert any underscores to spaces. */
194
195         while (*p0 != '\0') {
196                 if (*p0 == '_')
197                         *p0 = ' ';
198                 p0++;
199         }
200
201         p0 = p + 1;
202         p = strchr(p0, '-');
203         if (p == NULL)
204                 return;
205         *p = '\0';
206
207         devstr = p0;
208
209         /* Convert any underscores to spaces. */
210
211         while (*p0 != '\0') {
212                 if (*p0 == '_')
213                         *p0 = ' ';
214                 p0++;
215         }
216
217         fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
218         return;
219 }
220
221 static void
222 dump_pci_id(const char *s)
223 {
224         char *p;
225         char vidstr[7], didstr[7], subsysstr[14];
226
227         p = strcasestr(s, "VEN_");
228         if (p == NULL)
229                 return;
230         p += 4;
231         strcpy(vidstr, "0x");
232         strncat(vidstr, p, 4);
233         p = strcasestr(s, "DEV_");
234         if (p == NULL)
235                 return;
236         p += 4;
237         strcpy(didstr, "0x");
238         strncat(didstr, p, 4);
239         if (p == NULL)
240                 return;
241         p = strcasestr(s, "SUBSYS_");
242         if (p == NULL)
243                 strcpy(subsysstr, "0x00000000");
244         else {
245                 p += 7;
246                 strcpy(subsysstr, "0x");
247                 strncat(subsysstr, p, 8);
248         }
249
250         fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
251         return;
252 }
253
254 static void
255 dump_deviceids_pci()
256 {
257         struct assign *manf, *dev;
258         struct section *sec;
259         struct assign *assign;
260         char xpsec[256];
261         int first = 1, found = 0;
262
263         /* Find manufacturer name */
264         manf = find_assign("Manufacturer", NULL);
265
266 nextmanf:
267
268         /* Find manufacturer section */
269         if (manf->vals[1] != NULL &&
270             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
271             strcasecmp(manf->vals[1], "NTx86") == 0 ||
272             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
273             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
274                 /* Handle Windows XP INF files. */
275                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
276                     manf->vals[0], manf->vals[1]);
277                 sec = find_section(xpsec);
278         } else
279                 sec = find_section(manf->vals[0]);
280
281         /* See if there are any PCI device definitions. */
282
283         TAILQ_FOREACH(assign, &ah, link) {
284                 if (assign->section == sec) {
285                         dev = find_assign("strings", assign->key);
286                         if (strcasestr(assign->vals[1], "PCI") != NULL) {
287                                 found++;
288                                 break;
289                         }
290                 }
291         }
292
293         if (found == 0)
294                 goto done;
295
296         found = 0;
297
298         if (first == 1) {
299                 /* Emit start of PCI device table */
300                 fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
301                 first = 0;
302         }
303
304 retry:
305
306         /*
307          * Now run through all the device names listed
308          * in the manufacturer section and dump out the
309          * device descriptions and vendor/device IDs.
310          */
311
312         TAILQ_FOREACH(assign, &ah, link) {
313                 if (assign->section == sec) {
314                         dev = find_assign("strings", assign->key);
315                         /* Emit device IDs. */
316                         if (strcasestr(assign->vals[1], "PCI") != NULL)
317                                 dump_pci_id(assign->vals[1]);
318                         else
319                                 continue;
320                         /* Emit device description */
321                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
322                         found++;
323                 }
324         }
325
326         /* Someone tried to fool us. Shame on them. */
327         if (!found) {
328                 found++;
329                 sec = find_section(manf->vals[0]);
330                 goto retry;
331         }
332
333         /* Handle Manufacturer sections with multiple entries. */
334         manf = find_next_assign(manf);
335
336         if (manf != NULL)
337                 goto nextmanf;
338
339 done:
340         /* Emit end of table */
341
342         fprintf(ofp, "\n\n");
343
344         return;
345 }
346
347 static void
348 dump_deviceids_pcmcia()
349 {
350         struct assign *manf, *dev;
351         struct section *sec;
352         struct assign *assign;
353         char xpsec[256];
354         int first = 1, found = 0;
355
356         /* Find manufacturer name */
357         manf = find_assign("Manufacturer", NULL);
358
359 nextmanf:
360
361         /* Find manufacturer section */
362         if (manf->vals[1] != NULL &&
363             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
364             strcasecmp(manf->vals[1], "NTx86") == 0 ||
365             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
366             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
367                 /* Handle Windows XP INF files. */
368                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
369                     manf->vals[0], manf->vals[1]);
370                 sec = find_section(xpsec);
371         } else
372                 sec = find_section(manf->vals[0]);
373
374         /* See if there are any PCMCIA device definitions. */
375
376         TAILQ_FOREACH(assign, &ah, link) {
377                 if (assign->section == sec) {
378                         dev = find_assign("strings", assign->key);
379                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
380                                 found++;
381                                 break;
382                         }
383                 }
384         }
385
386         if (found == 0)
387                 goto done;
388
389         found = 0;
390
391         if (first == 1) {
392                 /* Emit start of PCMCIA device table */
393                 fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
394                 first = 0;
395         }
396
397 retry:
398
399         /*
400          * Now run through all the device names listed
401          * in the manufacturer section and dump out the
402          * device descriptions and vendor/device IDs.
403          */
404
405         TAILQ_FOREACH(assign, &ah, link) {
406                 if (assign->section == sec) {
407                         dev = find_assign("strings", assign->key);
408                         /* Emit device IDs. */
409                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
410                                 dump_pcmcia_id(assign->vals[1]);
411                         else
412                                 continue;
413                         /* Emit device description */
414                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
415                         found++;
416                 }
417         }
418
419         /* Someone tried to fool us. Shame on them. */
420         if (!found) {
421                 found++;
422                 sec = find_section(manf->vals[0]);
423                 goto retry;
424         }
425
426         /* Handle Manufacturer sections with multiple entries. */
427         manf = find_next_assign(manf);
428
429         if (manf != NULL)
430                 goto nextmanf;
431
432 done:
433         /* Emit end of table */
434
435         fprintf(ofp, "\n\n");
436
437         return;
438 }
439
440 static void
441 dump_addreg(const char *s, int devidx)
442 {
443         struct section *sec;
444         struct reg *reg;
445
446         /* Find the addreg section */
447         sec = find_section(s);
448
449         /* Dump all the keys defined in it. */
450         TAILQ_FOREACH(reg, &rh, link) {
451                 /*
452                  * Keys with an empty subkey are very easy to parse,
453                  * so just deal with them here. If a parameter key
454                  * of the same name also exists, prefer that one and
455                  * skip this one.
456                  */
457                 if (reg->section == sec) {
458                         if (reg->subkey == NULL) {
459                                 fprintf(ofp, "\n\t{ \"%s\",", reg->key);
460                                 fprintf(ofp,"\n\t\"%s \",", reg->key);
461                                 fprintf(ofp, "\n\t{ \"%s\" }, %d },",
462                                     reg->value == NULL ? "" :
463                                     stringcvt(reg->value), devidx);
464                         } else if (strncasecmp(reg->subkey,
465                             "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
466                             (reg->key != NULL && strcasecmp(reg->key,
467                             "ParamDesc") == 0))
468                                 dump_paramreg(sec, reg, devidx);
469                 }
470         }
471
472         return;
473 }
474
475 static void
476 dump_enumreg(const struct section *s, const struct reg *r)
477 {
478         struct reg *reg;
479         char enumkey[256];
480
481         sprintf(enumkey, "%s\\enum", r->subkey);
482         TAILQ_FOREACH(reg, &rh, link) {
483                 if (reg->section != s)
484                         continue;
485                 if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
486                         continue;
487                 fprintf(ofp, " [%s=%s]", reg->key,
488                     stringcvt(reg->value));
489         }
490         return;
491 }
492
493 static void
494 dump_editreg(const struct section *s, const struct reg *r)
495 {
496         struct reg *reg;
497
498         TAILQ_FOREACH(reg, &rh, link) {
499                 if (reg->section != s)
500                         continue;
501                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
502                         continue;
503                 if (reg->key == NULL)
504                         continue;
505                 if (strcasecmp(reg->key, "LimitText") == 0)
506                         fprintf(ofp, " [maxchars=%s]", reg->value);
507                 if (strcasecmp(reg->key, "Optional") == 0 &&
508                     strcmp(reg->value, "1") == 0)
509                         fprintf(ofp, " [optional]");
510         }
511         return;
512 }
513
514 /* Use this for int too */
515 static void
516 dump_dwordreg(const struct section *s, const struct reg *r)
517 {
518         struct reg *reg;
519
520         TAILQ_FOREACH(reg, &rh, link) {
521                 if (reg->section != s)
522                         continue;
523                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
524                         continue;
525                 if (reg->key == NULL)
526                         continue;
527                 if (strcasecmp(reg->key, "min") == 0)
528                         fprintf(ofp, " [min=%s]", reg->value);
529                 if (strcasecmp(reg->key, "max") == 0)
530                         fprintf(ofp, " [max=%s]", reg->value);
531         }
532         return;
533 }
534
535 static void
536 dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
537 {
538         struct reg *reg;
539         TAILQ_FOREACH(reg, &rh, link) {
540                 if (reg->section != s)
541                         continue;
542                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
543                         continue;
544                 if (reg->key == NULL || strcasecmp(reg->key, "Default"))
545                         continue;
546                 fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
547                     stringcvt(reg->value), devidx);
548                 return;
549         }
550         /* Default registry entry missing */
551         fprintf(ofp, "\n\t{ \"\" }, %d },", devidx);
552         return;
553 }
554
555 static void
556 dump_paramdesc(const struct section *s, const struct reg *r)
557 {
558         struct reg *reg;
559         TAILQ_FOREACH(reg, &rh, link) {
560                 if (reg->section != s)
561                         continue;
562                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
563                         continue;
564                 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
565                         continue;
566                 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
567                         break;
568         }
569         return;
570 }
571
572 static void
573 dump_typeinfo(const struct section *s, const struct reg *r)
574 {
575         struct reg *reg;
576         TAILQ_FOREACH(reg, &rh, link) {
577                 if (reg->section != s)
578                         continue;
579                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
580                         continue;
581                 if (reg->key == NULL)
582                         continue;
583                 if (strcasecmp(reg->key, "type"))
584                         continue;
585                 if (strcasecmp(reg->value, "dword") == 0 ||
586                     strcasecmp(reg->value, "int") == 0)
587                         dump_dwordreg(s, r);
588                 if (strcasecmp(reg->value, "enum") == 0)
589                         dump_enumreg(s, r);
590                 if (strcasecmp(reg->value, "edit") == 0)
591                         dump_editreg(s, r);
592         }
593         return;
594 }
595
596 static void
597 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
598 {
599         const char *keyname;
600
601         keyname = r->subkey + strlen("Ndi\\params\\");
602         fprintf(ofp, "\n\t{ \"%s\",", keyname);
603         dump_paramdesc(s, r);
604         dump_typeinfo(s, r);
605         fprintf(ofp, "\",");
606         dump_defaultinfo(s, r, devidx);
607
608         return;
609 }
610
611 static void
612 dump_regvals(void)
613 {
614         struct assign *manf, *dev;
615         struct section *sec;
616         struct assign *assign;
617         char sname[256];
618         int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
619
620         /* Find signature to check for special case of WinNT. */
621         assign = find_assign("version", "signature");
622         if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
623                 is_winnt++;
624
625         /* Emit start of block */
626         fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
627
628         /* Find manufacturer name */
629         manf = find_assign("Manufacturer", NULL);
630
631 nextmanf:
632
633         /* Find manufacturer section */
634         if (manf->vals[1] != NULL &&
635             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
636             strcasecmp(manf->vals[1], "NTx86") == 0 ||
637             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
638             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
639                 is_winxp++;
640                 /* Handle Windows XP INF files. */
641                 snprintf(sname, sizeof(sname), "%s.%s",
642                     manf->vals[0], manf->vals[1]);
643                 sec = find_section(sname);
644         } else
645                 sec = find_section(manf->vals[0]);
646
647 retry:
648
649         TAILQ_FOREACH(assign, &ah, link) {
650                 if (assign->section == sec) {
651                         found++;
652                         /*
653                          * Find all the AddReg sections.
654                          * Look for section names with .NT, unless
655                          * this is a WinXP .INF file.
656                          */
657
658                         if (is_winxp) {
659                                 sprintf(sname, "%s.NTx86", assign->vals[0]);
660                                 dev = find_assign(sname, "AddReg");
661                                 if (dev == NULL) {
662                                         sprintf(sname, "%s.NT",
663                                             assign->vals[0]);
664                                         dev = find_assign(sname, "AddReg");
665                                 }
666                                 if (dev == NULL)
667                                         dev = find_assign(assign->vals[0],
668                                             "AddReg");
669                         } else {
670                                 sprintf(sname, "%s.NT", assign->vals[0]);
671                                 dev = find_assign(sname, "AddReg");
672                                 if (dev == NULL && is_winnt)
673                                         dev = find_assign(assign->vals[0],
674                                             "AddReg");
675                         }
676                         /* Section not found. */
677                         if (dev == NULL)
678                                 continue;
679                         for (i = 0; i < W_MAX; i++) {
680                                 if (dev->vals[i] != NULL)
681                                         dump_addreg(dev->vals[i], devidx);
682                         }
683                         devidx++;
684                 }
685         }
686
687         if (!found) {
688                 sec = find_section(manf->vals[0]);
689                 is_winxp = 0;
690                 found++;
691                 goto retry;
692         }
693
694         manf = find_next_assign(manf);
695
696         if (manf != NULL)
697                 goto nextmanf;
698
699         fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
700
701         return;
702 }
703
704 void
705 assign_add (const char *a)
706 {
707         struct assign *assign;
708         int i;
709
710         assign = malloc(sizeof(struct assign));
711         bzero(assign, sizeof(struct assign));
712         assign->section = TAILQ_LAST(&sh, section_head);
713         assign->key = sstrdup(a);
714         for (i = 0; i < idx; i++)
715                 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
716         TAILQ_INSERT_TAIL(&ah, assign, link);
717
718         clear_words();
719         return;
720 }
721
722 void
723 define_add (const char *d __unused)
724 {
725 #ifdef notdef
726         fprintf(stderr, "define \"%s\"\n", d);
727 #endif
728         return;
729 }
730
731 static char *
732 sstrdup(const char *str)
733 {
734         if (str != NULL && strlen(str))
735                 return (strdup(str));
736         return (NULL);
737 }
738
739 static int
740 satoi (const char *nptr)
741 {
742         if (nptr != NULL && strlen(nptr))
743                 return (atoi(nptr));
744         return (0);
745 }
746
747 void
748 regkey_add (const char *r)
749 {
750         struct reg *reg;
751
752         reg = malloc(sizeof(struct reg));
753         bzero(reg, sizeof(struct reg));
754         reg->section = TAILQ_LAST(&sh, section_head);
755         reg->root = sstrdup(r);
756         reg->subkey = sstrdup(words[3]);
757         reg->key = sstrdup(words[2]);
758         reg->flags = satoi(words[1]);
759         reg->value = sstrdup(words[0]);
760         TAILQ_INSERT_TAIL(&rh, reg, link);
761
762         free(__DECONST(char *, r));
763         clear_words();
764         return;
765 }
766
767 void
768 push_word (const char *w)
769 {
770         if (w && strlen(w))
771                 words[idx++] = w;
772         else
773                 words[idx++] = NULL;
774         return;
775 }
776
777 void
778 clear_words (void)
779 {
780         int i;
781
782         for (i = 0; i < idx; i++) {
783                 if (words[i]) {
784                         free(__DECONST(char *, words[i]));
785                 }
786         }
787         idx = 0;
788         bzero(words, sizeof(words));
789         return;
790 }