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