]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ndiscvt/inf.c
This commit was generated by cvs2svn to compensate for changes in r178843,
[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                 return;
543         }
544         /* Default registry entry missing */
545         fprintf(ofp, "\n\t{ \"\" }, %d },", devidx);
546         return;
547 }
548
549 static void
550 dump_paramdesc(const struct section *s, const struct reg *r)
551 {
552         struct reg *reg;
553         TAILQ_FOREACH(reg, &rh, link) {
554                 if (reg->section != s)
555                         continue;
556                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
557                         continue;
558                 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
559                         continue;
560                 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
561                         break;
562         }
563         return;
564 }
565
566 static void
567 dump_typeinfo(const struct section *s, const struct reg *r)
568 {
569         struct reg *reg;
570         TAILQ_FOREACH(reg, &rh, link) {
571                 if (reg->section != s)
572                         continue;
573                 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
574                         continue;
575                 if (reg->key == NULL)
576                         continue;
577                 if (strcasecmp(reg->key, "type"))
578                         continue;
579                 if (strcasecmp(reg->value, "dword") == 0 ||
580                     strcasecmp(reg->value, "int") == 0)
581                         dump_dwordreg(s, r);
582                 if (strcasecmp(reg->value, "enum") == 0)
583                         dump_enumreg(s, r);
584                 if (strcasecmp(reg->value, "edit") == 0)
585                         dump_editreg(s, r);
586         }
587         return;
588 }
589
590 static void
591 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
592 {
593         const char *keyname;
594
595         keyname = r->subkey + strlen("Ndi\\params\\");
596         fprintf(ofp, "\n\t{ \"%s\",", keyname);
597         dump_paramdesc(s, r);
598         dump_typeinfo(s, r);
599         fprintf(ofp, "\",");
600         dump_defaultinfo(s, r, devidx);
601
602         return;
603 }
604
605 static void
606 dump_regvals(void)
607 {
608         struct assign *manf, *dev;
609         struct section *sec;
610         struct assign *assign;
611         char sname[256];
612         int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
613
614         /* Find signature to check for special case of WinNT. */
615         assign = find_assign("version", "signature");
616         if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
617                 is_winnt++;
618
619         /* Emit start of block */
620         fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
621
622         /* Find manufacturer name */
623         manf = find_assign("Manufacturer", NULL);
624
625 nextmanf:
626
627         /* Find manufacturer section */
628         if (manf->vals[1] != NULL &&
629             (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
630             strcasecmp(manf->vals[1], "NTx86") == 0 ||
631             strcasecmp(manf->vals[1], "NTx86.5.1") == 0 ||
632             strcasecmp(manf->vals[1], "NTamd64") == 0)) {
633                 is_winxp++;
634                 /* Handle Windows XP INF files. */
635                 snprintf(sname, sizeof(sname), "%s.%s",
636                     manf->vals[0], manf->vals[1]);
637                 sec = find_section(sname);
638         } else
639                 sec = find_section(manf->vals[0]);
640
641 retry:
642
643         TAILQ_FOREACH(assign, &ah, link) {
644                 if (assign->section == sec) {
645                         found++;
646                         /*
647                          * Find all the AddReg sections.
648                          * Look for section names with .NT, unless
649                          * this is a WinXP .INF file.
650                          */
651
652                         if (is_winxp) {
653                                 sprintf(sname, "%s.NTx86", assign->vals[0]);
654                                 dev = find_assign(sname, "AddReg");
655                                 if (dev == NULL) {
656                                         sprintf(sname, "%s.NT",
657                                             assign->vals[0]);
658                                         dev = find_assign(sname, "AddReg");
659                                 }
660                                 if (dev == NULL)
661                                         dev = find_assign(assign->vals[0],
662                                             "AddReg");
663                         } else {
664                                 sprintf(sname, "%s.NT", assign->vals[0]);
665                                 dev = find_assign(sname, "AddReg");
666                                 if (dev == NULL && is_winnt)
667                                         dev = find_assign(assign->vals[0],
668                                             "AddReg");
669                         }
670                         /* Section not found. */
671                         if (dev == NULL)
672                                 continue;
673                         for (i = 0; i < W_MAX; i++) {
674                                 if (dev->vals[i] != NULL)
675                                         dump_addreg(dev->vals[i], devidx);
676                         }
677                         devidx++;
678                 }
679         }
680
681         if (!found) {
682                 sec = find_section(manf->vals[0]);
683                 is_winxp = 0;
684                 found++;
685                 goto retry;
686         }
687
688         manf = find_next_assign(manf);
689
690         if (manf != NULL)
691                 goto nextmanf;
692
693         fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
694
695         return;
696 }
697
698 void
699 assign_add (const char *a)
700 {
701         struct assign *assign;
702         int i;
703
704         assign = malloc(sizeof(struct assign));
705         bzero(assign, sizeof(struct assign));
706         assign->section = TAILQ_LAST(&sh, section_head);
707         assign->key = sstrdup(a);
708         for (i = 0; i < idx; i++)
709                 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
710         TAILQ_INSERT_TAIL(&ah, assign, link);
711
712         clear_words();
713         return;
714 }
715
716 void
717 define_add (const char *d __unused)
718 {
719 #ifdef notdef
720         fprintf(stderr, "define \"%s\"\n", d);
721 #endif
722         return;
723 }
724
725 static char *
726 sstrdup(const char *str)
727 {
728         if (str != NULL && strlen(str))
729                 return (strdup(str));
730         return (NULL);
731 }
732
733 static int
734 satoi (const char *nptr)
735 {
736         if (nptr != NULL && strlen(nptr))
737                 return (atoi(nptr));
738         return (0);
739 }
740
741 void
742 regkey_add (const char *r)
743 {
744         struct reg *reg;
745
746         reg = malloc(sizeof(struct reg));
747         bzero(reg, sizeof(struct reg));
748         reg->section = TAILQ_LAST(&sh, section_head);
749         reg->root = sstrdup(r);
750         reg->subkey = sstrdup(words[3]);
751         reg->key = sstrdup(words[2]);
752         reg->flags = satoi(words[1]);
753         reg->value = sstrdup(words[0]);
754         TAILQ_INSERT_TAIL(&rh, reg, link);
755
756         free(__DECONST(char *, r));
757         clear_words();
758         return;
759 }
760
761 void
762 push_word (const char *w)
763 {
764         if (w && strlen(w))
765                 words[idx++] = w;
766         else
767                 words[idx++] = NULL;
768         return;
769 }
770
771 void
772 clear_words (void)
773 {
774         int i;
775
776         for (i = 0; i < idx; i++) {
777                 if (words[i]) {
778                         free(__DECONST(char *, words[i]));
779                 }
780         }
781         idx = 0;
782         bzero(words, sizeof(words));
783         return;
784 }