]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ndiscvt/inf.c
This commit was generated by cvs2svn to compensate for changes in r173619,
[FreeBSD/FreeBSD.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 found = 0;
262
263         /* Emit start of PCI device table */
264         fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
265
266         /* Find manufacturer name */
267         manf = find_assign("Manufacturer", NULL);
268
269 nextmanf:
270
271         /* Find manufacturer section */
272         if (manf->vals[1] != NULL &&
273             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
274             strcasecmp(manf->vals[1], "NTx86") == 0 ||
275             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
276             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
277                 /* Handle Windows XP INF files. */
278                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
279                     manf->vals[0], manf->vals[1]);
280                 sec = find_section(xpsec);
281         } else
282                 sec = find_section(manf->vals[0]);
283
284         /* See if there are any PCI device definitions. */
285
286         TAILQ_FOREACH(assign, &ah, link) {
287                 if (assign->section == sec) {
288                         dev = find_assign("strings", assign->key);
289                         if (strcasestr(assign->vals[1], "PCI") != NULL) {
290                                 found++;
291                                 break;
292                         }
293                 }
294         }
295
296         if (found == 0)
297                 goto done;
298
299         found = 0;
300
301 retry:
302
303         /*
304          * Now run through all the device names listed
305          * in the manufacturer section and dump out the
306          * device descriptions and vendor/device IDs.
307          */
308
309         TAILQ_FOREACH(assign, &ah, link) {
310                 if (assign->section == sec) {
311                         dev = find_assign("strings", assign->key);
312                         /* Emit device IDs. */
313                         if (strcasestr(assign->vals[1], "PCI") != NULL)
314                                 dump_pci_id(assign->vals[1]);
315                         else
316                                 continue;
317                         /* Emit device description */
318                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
319                         found++;
320                 }
321         }
322
323         /* Someone tried to fool us. Shame on them. */
324         if (!found) {
325                 found++;
326                 sec = find_section(manf->vals[0]);
327                 goto retry;
328         }
329
330         /* Handle Manufacturer sections with multiple entries. */
331         manf = find_next_assign(manf);
332
333         if (manf != NULL)
334                 goto nextmanf;
335
336 done:
337         /* Emit end of table */
338
339         fprintf(ofp, "\n\n");
340
341         return;
342 }
343
344 static void
345 dump_deviceids_pcmcia()
346 {
347         struct assign *manf, *dev;
348         struct section *sec;
349         struct assign *assign;
350         char xpsec[256];
351         int found = 0;
352
353         /* Find manufacturer name */
354         manf = find_assign("Manufacturer", NULL);
355
356 nextmanf:
357
358         /* Find manufacturer section */
359         if (manf->vals[1] != NULL &&
360             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
361             strcasecmp(manf->vals[1], "NTx86") == 0 ||
362             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
363             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
364                 /* Handle Windows XP INF files. */
365                 snprintf(xpsec, sizeof(xpsec), "%s.%s",
366                     manf->vals[0], manf->vals[1]);
367                 sec = find_section(xpsec);
368         } else
369                 sec = find_section(manf->vals[0]);
370
371         /* See if there are any PCMCIA device definitions. */
372
373         TAILQ_FOREACH(assign, &ah, link) {
374                 if (assign->section == sec) {
375                         dev = find_assign("strings", assign->key);
376                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
377                                 found++;
378                                 break;
379                         }
380                 }
381         }
382
383         if (found == 0)
384                 goto done;
385
386         found = 0;
387
388         /* Emit start of PCMCIA device table */
389         fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
390
391 retry:
392
393         /*
394          * Now run through all the device names listed
395          * in the manufacturer section and dump out the
396          * device descriptions and vendor/device IDs.
397          */
398
399         TAILQ_FOREACH(assign, &ah, link) {
400                 if (assign->section == sec) {
401                         dev = find_assign("strings", assign->key);
402                         /* Emit device IDs. */
403                         if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
404                                 dump_pcmcia_id(assign->vals[1]);
405                         else
406                                 continue;
407                         /* Emit device description */
408                         fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
409                         found++;
410                 }
411         }
412
413         /* Someone tried to fool us. Shame on them. */
414         if (!found) {
415                 found++;
416                 sec = find_section(manf->vals[0]);
417                 goto retry;
418         }
419
420         /* Handle Manufacturer sections with multiple entries. */
421         manf = find_next_assign(manf);
422
423         if (manf != NULL)
424                 goto nextmanf;
425
426 done:
427         /* Emit end of table */
428
429         fprintf(ofp, "\n\n");
430
431         return;
432 }
433
434 static void
435 dump_addreg(const char *s, int devidx)
436 {
437         struct section *sec;
438         struct reg *reg;
439
440         /* Find the addreg section */
441         sec = find_section(s);
442
443         /* Dump all the keys defined in it. */
444         TAILQ_FOREACH(reg, &rh, link) {
445                 /*
446                  * Keys with an empty subkey are very easy to parse,
447                  * so just deal with them here. If a parameter key
448                  * of the same name also exists, prefer that one and
449                  * skip this one.
450                  */
451                 if (reg->section == sec) {
452                         if (reg->subkey == NULL) {
453                                 fprintf(ofp, "\n\t{ \"%s\",", reg->key);
454                                 fprintf(ofp,"\n\t\"%s \",", reg->key);
455                                 fprintf(ofp, "\n\t{ \"%s\" }, %d },",
456                                     reg->value == NULL ? "" :
457                                     stringcvt(reg->value), devidx);
458                         } else if (strncasecmp(reg->subkey,
459                             "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
460                             (reg->key != NULL && strcasecmp(reg->key,
461                             "ParamDesc") == 0))
462                                 dump_paramreg(sec, reg, devidx);
463                 }
464         }
465
466         return;
467 }
468
469 static void
470 dump_enumreg(const struct section *s, const struct reg *r)
471 {
472         struct reg *reg;
473         char enumkey[256];
474
475         sprintf(enumkey, "%s\\enum", r->subkey);
476         TAILQ_FOREACH(reg, &rh, link) {
477                 if (reg->section != s)
478                         continue;
479                 if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
480                         continue;
481                 fprintf(ofp, " [%s=%s]", reg->key,
482                     stringcvt(reg->value));
483         }
484         return;
485 }
486
487 static void
488 dump_editreg(const struct section *s, const struct reg *r)
489 {
490         struct reg *reg;
491
492         TAILQ_FOREACH(reg, &rh, link) {
493                 if (reg->section != s)
494                         continue;
495                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
496                         continue;
497                 if (reg->key == NULL)
498                         continue;
499                 if (strcasecmp(reg->key, "LimitText") == 0)
500                         fprintf(ofp, " [maxchars=%s]", reg->value);
501                 if (strcasecmp(reg->key, "Optional") == 0 &&
502                     strcmp(reg->value, "1") == 0)
503                         fprintf(ofp, " [optional]");
504         }
505         return;
506 }
507
508 /* Use this for int too */
509 static void
510 dump_dwordreg(const struct section *s, const struct reg *r)
511 {
512         struct reg *reg;
513
514         TAILQ_FOREACH(reg, &rh, link) {
515                 if (reg->section != s)
516                         continue;
517                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
518                         continue;
519                 if (reg->key == NULL)
520                         continue;
521                 if (strcasecmp(reg->key, "min") == 0)
522                         fprintf(ofp, " [min=%s]", reg->value);
523                 if (strcasecmp(reg->key, "max") == 0)
524                         fprintf(ofp, " [max=%s]", reg->value);
525         }
526         return;
527 }
528
529 static void
530 dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
531 {
532         struct reg *reg;
533         TAILQ_FOREACH(reg, &rh, link) {
534                 if (reg->section != s)
535                         continue;
536                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
537                         continue;
538                 if (reg->key == NULL || strcasecmp(reg->key, "Default"))
539                         continue;
540                 fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
541                     stringcvt(reg->value), devidx);
542                         break;
543         }
544         return;
545 }
546
547 static void
548 dump_paramdesc(const struct section *s, const struct reg *r)
549 {
550         struct reg *reg;
551         TAILQ_FOREACH(reg, &rh, link) {
552                 if (reg->section != s)
553                         continue;
554                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
555                         continue;
556                 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
557                         continue;
558                 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
559                         break;
560         }
561         return;
562 }
563
564 static void
565 dump_typeinfo(const struct section *s, const struct reg *r)
566 {
567         struct reg *reg;
568         TAILQ_FOREACH(reg, &rh, link) {
569                 if (reg->section != s)
570                         continue;
571                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
572                         continue;
573                 if (reg->key == NULL)
574                         continue;
575                 if (strcasecmp(reg->key, "type"))
576                         continue;
577                 if (strcasecmp(reg->value, "dword") == 0 ||
578                     strcasecmp(reg->value, "int") == 0)
579                         dump_dwordreg(s, r);
580                 if (strcasecmp(reg->value, "enum") == 0)
581                         dump_enumreg(s, r);
582                 if (strcasecmp(reg->value, "edit") == 0)
583                         dump_editreg(s, r);
584         }
585         return;
586 }
587
588 static void
589 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
590 {
591         const char *keyname;
592
593         keyname = r->subkey + strlen("Ndi\\params\\");
594         fprintf(ofp, "\n\t{ \"%s\",", keyname);
595         dump_paramdesc(s, r);
596         dump_typeinfo(s, r);
597         fprintf(ofp, "\",");
598         dump_defaultinfo(s, r, devidx);
599
600         return;
601 }
602
603 static void
604 dump_regvals(void)
605 {
606         struct assign *manf, *dev;
607         struct section *sec;
608         struct assign *assign;
609         char sname[256];
610         int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
611
612         /* Find signature to check for special case of WinNT. */
613         assign = find_assign("version", "signature");
614         if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
615                 is_winnt++;
616
617         /* Emit start of block */
618         fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
619
620         /* Find manufacturer name */
621         manf = find_assign("Manufacturer", NULL);
622
623 nextmanf:
624
625         /* Find manufacturer section */
626         if (manf->vals[1] != NULL &&
627             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
628             strcasecmp(manf->vals[1], "NTx86") == 0 ||
629             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
630             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
631                 is_winxp++;
632                 /* Handle Windows XP INF files. */
633                 snprintf(sname, sizeof(sname), "%s.%s",
634                     manf->vals[0], manf->vals[1]);
635                 sec = find_section(sname);
636         } else
637                 sec = find_section(manf->vals[0]);
638
639 retry:
640
641         TAILQ_FOREACH(assign, &ah, link) {
642                 if (assign->section == sec) {
643                         found++;
644                         /*
645                          * Find all the AddReg sections.
646                          * Look for section names with .NT, unless
647                          * this is a WinXP .INF file.
648                          */
649
650                         if (is_winxp) {
651                                 sprintf(sname, "%s.NTx86", assign->vals[0]);
652                                 dev = find_assign(sname, "AddReg");
653                                 if (dev == NULL) {
654                                         sprintf(sname, "%s.NT",
655                                             assign->vals[0]);
656                                         dev = find_assign(sname, "AddReg");
657                                 }
658                                 if (dev == NULL)
659                                         dev = find_assign(assign->vals[0],
660                                             "AddReg");
661                         } else {
662                                 sprintf(sname, "%s.NT", assign->vals[0]);
663                                 dev = find_assign(sname, "AddReg");
664                                 if (dev == NULL && is_winnt)
665                                         dev = find_assign(assign->vals[0],
666                                             "AddReg");
667                         }
668                         /* Section not found. */
669                         if (dev == NULL)
670                                 continue;
671                         for (i = 0; i < W_MAX; i++) {
672                                 if (dev->vals[i] != NULL)
673                                         dump_addreg(dev->vals[i], devidx);
674                         }
675                         devidx++;
676                 }
677         }
678
679         if (!found) {
680                 sec = find_section(manf->vals[0]);
681                 is_winxp = 0;
682                 found++;
683                 goto retry;
684         }
685
686         manf = find_next_assign(manf);
687
688         if (manf != NULL)
689                 goto nextmanf;
690
691         fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
692
693         return;
694 }
695
696 void
697 assign_add (const char *a)
698 {
699         struct assign *assign;
700         int i;
701
702         assign = malloc(sizeof(struct assign));
703         bzero(assign, sizeof(struct assign));
704         assign->section = TAILQ_LAST(&sh, section_head);
705         assign->key = sstrdup(a);
706         for (i = 0; i < idx; i++)
707                 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
708         TAILQ_INSERT_TAIL(&ah, assign, link);
709
710         clear_words();
711         return;
712 }
713
714 void
715 define_add (const char *d __unused)
716 {
717 #ifdef notdef
718         fprintf(stderr, "define \"%s\"\n", d);
719 #endif
720         return;
721 }
722
723 static char *
724 sstrdup(const char *str)
725 {
726         if (str != NULL && strlen(str))
727                 return (strdup(str));
728         return (NULL);
729 }
730
731 static int
732 satoi (const char *nptr)
733 {
734         if (nptr != NULL && strlen(nptr))
735                 return (atoi(nptr));
736         return (0);
737 }
738
739 void
740 regkey_add (const char *r)
741 {
742         struct reg *reg;
743
744         reg = malloc(sizeof(struct reg));
745         bzero(reg, sizeof(struct reg));
746         reg->section = TAILQ_LAST(&sh, section_head);
747         reg->root = sstrdup(r);
748         reg->subkey = sstrdup(words[3]);
749         reg->key = sstrdup(words[2]);
750         reg->flags = satoi(words[1]);
751         reg->value = sstrdup(words[0]);
752         TAILQ_INSERT_TAIL(&rh, reg, link);
753
754         free(__DECONST(char *, r));
755         clear_words();
756         return;
757 }
758
759 void
760 push_word (const char *w)
761 {
762         if (w && strlen(w))
763                 words[idx++] = w;
764         else
765                 words[idx++] = NULL;
766         return;
767 }
768
769 void
770 clear_words (void)
771 {
772         int i;
773
774         for (i = 0; i < idx; i++) {
775                 if (words[i]) {
776                         free(__DECONST(char *, words[i]));
777                 }
778         }
779         idx = 0;
780         bzero(words, sizeof(words));
781         return;
782 }