Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

986 lines
24 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blconfig.c
  5. Abstract:
  6. This module implements the OS loader configuration initialization.
  7. Author:
  8. David N. Cutler (davec) 9-Sep-1991
  9. Revision History:
  10. --*/
  11. #include "bootlib.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. ULONG
  15. BlMatchToken (
  16. IN PCHAR TokenValue,
  17. IN CHAR * FIRMWARE_PTR TokenArray[]
  18. );
  19. PCHAR
  20. BlGetNextToken (
  21. IN PCHAR TokenString,
  22. OUT PCHAR OutputToken,
  23. OUT PULONG UnitNumber
  24. );
  25. //
  26. // Define types of adapters that can be booted from.
  27. //
  28. typedef enum _ADAPTER_TYPES {
  29. AdapterEisa,
  30. AdapterScsi,
  31. AdapterMulti,
  32. AdapterNet,
  33. AdapterRamdisk,
  34. AdapterMaximum
  35. } ADAPTER_TYPES;
  36. //
  37. // Define type of controllers that can be booted from.
  38. //
  39. typedef enum _CONTROLLER_TYPES {
  40. ControllerDisk,
  41. ControllerCdrom,
  42. ControllerMaximum
  43. } CONTROLLER_TYPES;
  44. //
  45. // Define type of peripheral that can be booted from.
  46. //
  47. typedef enum _PERIPHERAL_TYPES {
  48. PeripheralRigidDisk,
  49. PeripheralFloppyDisk,
  50. #if defined(ELTORITO)
  51. PeripheralElTorito,
  52. #endif
  53. PeripheralMaximum
  54. } PERIPHERAL_TYPES;
  55. //
  56. // Define the ARC pathname mnemonics.
  57. //
  58. CHAR * FIRMWARE_PTR MnemonicTable[] = {
  59. "arc",
  60. "cpu",
  61. "fpu",
  62. "pic",
  63. "pdc",
  64. "sic",
  65. "sdc",
  66. "sc",
  67. "eisa",
  68. "tc",
  69. "scsi",
  70. "dti",
  71. "multi",
  72. "disk",
  73. "tape",
  74. "cdrom",
  75. "worm",
  76. "serial",
  77. "net",
  78. "video",
  79. "par",
  80. "point",
  81. "key",
  82. "audio",
  83. "other",
  84. "rdisk",
  85. "fdisk",
  86. "tape",
  87. "modem",
  88. "monitor",
  89. "print",
  90. "pointer",
  91. "keyboard",
  92. "term",
  93. "other"
  94. };
  95. CHAR * FIRMWARE_PTR BlAdapterTypes[AdapterMaximum + 1] = {"eisa","scsi","multi","net","ramdisk",NULL};
  96. CHAR * FIRMWARE_PTR BlControllerTypes[ControllerMaximum + 1] = {"disk","cdrom",NULL};
  97. #if defined(ELTORITO)
  98. CHAR * FIRMWARE_PTR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk","cdrom",NULL};
  99. #else
  100. CHAR * FIRMWARE_PTR BlPeripheralTypes[PeripheralMaximum + 1] = {"rdisk","fdisk",NULL};
  101. #endif
  102. ARC_STATUS
  103. BlConfigurationInitialize (
  104. IN PCONFIGURATION_COMPONENT Parent,
  105. IN PCONFIGURATION_COMPONENT_DATA ParentEntry
  106. )
  107. /*++
  108. Routine Description:
  109. This routine traverses the firmware configuration tree from the specified
  110. parent entry and constructs the corresponding NT configuration tree.
  111. Arguments:
  112. None.
  113. Return Value:
  114. ESUCCESS is returned if the initialization is successful. Otherwise,
  115. an unsuccessful status that describes the error is returned.
  116. --*/
  117. {
  118. PCONFIGURATION_COMPONENT Child;
  119. PCONFIGURATION_COMPONENT_DATA ChildEntry;
  120. PCHAR ConfigurationData;
  121. PCONFIGURATION_COMPONENT_DATA PreviousSibling;
  122. PCONFIGURATION_COMPONENT Sibling;
  123. PCONFIGURATION_COMPONENT_DATA SiblingEntry;
  124. ARC_STATUS Status;
  125. //
  126. // Traverse the child configuration tree and allocate, initialize, and
  127. // construct the corresponding NT configuration tree.
  128. //
  129. Child = ArcGetChild(Parent);
  130. while (Child != NULL) {
  131. //
  132. // Allocate an entry of the appropriate size to hold the child
  133. // configuration information.
  134. //
  135. ChildEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap(
  136. sizeof(CONFIGURATION_COMPONENT_DATA) +
  137. Child->IdentifierLength +
  138. Child->ConfigurationDataLength);
  139. if (ChildEntry == NULL) {
  140. return ENOMEM;
  141. }
  142. //
  143. // Initialize the tree pointers and copy the component data.
  144. //
  145. if (ParentEntry == NULL) {
  146. BlLoaderBlock->ConfigurationRoot = ChildEntry;
  147. } else {
  148. ParentEntry->Child = ChildEntry;
  149. }
  150. ChildEntry->Parent = ParentEntry;
  151. ChildEntry->Sibling = NULL;
  152. ChildEntry->Child = NULL;
  153. RtlMoveMemory((PVOID)&ChildEntry->ComponentEntry,
  154. (PVOID)Child,
  155. sizeof(CONFIGURATION_COMPONENT));
  156. ConfigurationData = (PCHAR)(ChildEntry + 1);
  157. //
  158. // If configuration data is specified, then copy the configuration
  159. // data.
  160. //
  161. if (Child->ConfigurationDataLength != 0) {
  162. ChildEntry->ConfigurationData = (PVOID)ConfigurationData;
  163. Status = ArcGetConfigurationData((PVOID)ConfigurationData,
  164. Child);
  165. if (Status != ESUCCESS) {
  166. return Status;
  167. }
  168. ConfigurationData += Child->ConfigurationDataLength;
  169. } else {
  170. ChildEntry->ConfigurationData = NULL;
  171. }
  172. //
  173. // If identifier data is specified, then copy the identifier data.
  174. //
  175. if (Child->IdentifierLength !=0) {
  176. ChildEntry->ComponentEntry.Identifier = ConfigurationData;
  177. RtlMoveMemory((PVOID)ConfigurationData,
  178. (PVOID)Child->Identifier,
  179. Child->IdentifierLength);
  180. } else {
  181. ChildEntry->ComponentEntry.Identifier = NULL;
  182. }
  183. //
  184. // Traverse the sibling configuration tree and allocate, initialize,
  185. // and construct the corresponding NT configuration tree.
  186. //
  187. PreviousSibling = ChildEntry;
  188. Sibling = ArcGetPeer(Child);
  189. while (Sibling != NULL) {
  190. //
  191. // Allocate an entry of the appropriate size to hold the sibling
  192. // configuration information.
  193. //
  194. SiblingEntry = (PCONFIGURATION_COMPONENT_DATA)BlAllocateHeap(
  195. sizeof(CONFIGURATION_COMPONENT_DATA) +
  196. Sibling->IdentifierLength +
  197. Sibling->ConfigurationDataLength);
  198. if (SiblingEntry == NULL) {
  199. return ENOMEM;
  200. }
  201. //
  202. // Initialize the tree pointers and copy the component data.
  203. //
  204. SiblingEntry->Parent = ParentEntry;
  205. SiblingEntry->Sibling = NULL;
  206. ChildEntry->Child = NULL;
  207. RtlMoveMemory((PVOID)&SiblingEntry->ComponentEntry,
  208. (PVOID)Sibling,
  209. sizeof(CONFIGURATION_COMPONENT));
  210. ConfigurationData = (PCHAR)(SiblingEntry + 1);
  211. //
  212. // If configuration data is specified, then copy the configuration
  213. // data.
  214. //
  215. if (Sibling->ConfigurationDataLength != 0) {
  216. SiblingEntry->ConfigurationData = (PVOID)ConfigurationData;
  217. Status = ArcGetConfigurationData((PVOID)ConfigurationData,
  218. Sibling);
  219. if (Status != ESUCCESS) {
  220. return Status;
  221. }
  222. ConfigurationData += Sibling->ConfigurationDataLength;
  223. } else {
  224. SiblingEntry->ConfigurationData = NULL;
  225. }
  226. //
  227. // If identifier data is specified, then copy the identifier data.
  228. //
  229. if (Sibling->IdentifierLength !=0) {
  230. SiblingEntry->ComponentEntry.Identifier = ConfigurationData;
  231. RtlMoveMemory((PVOID)ConfigurationData,
  232. (PVOID)Sibling->Identifier,
  233. Sibling->IdentifierLength);
  234. } else {
  235. SiblingEntry->ComponentEntry.Identifier = NULL;
  236. }
  237. //
  238. // If the sibling has a child, then generate the tree for the
  239. // child.
  240. //
  241. if (ArcGetChild(Sibling) != NULL) {
  242. Status = BlConfigurationInitialize(Sibling, SiblingEntry);
  243. if (Status != ESUCCESS) {
  244. return Status;
  245. }
  246. }
  247. //
  248. // Set new sibling pointers and get the next sibling tree entry.
  249. //
  250. PreviousSibling->Sibling = SiblingEntry;
  251. PreviousSibling = SiblingEntry;
  252. Sibling = ArcGetPeer(Sibling);
  253. }
  254. //
  255. // Set new parent pointers and get the next child tree entry.
  256. //
  257. Parent = Child;
  258. ParentEntry = ChildEntry;
  259. Child = ArcGetChild(Child);
  260. }
  261. return ESUCCESS;
  262. }
  263. BOOLEAN
  264. BlSearchConfigTree(
  265. IN PCONFIGURATION_COMPONENT_DATA Node,
  266. IN CONFIGURATION_CLASS Class,
  267. IN CONFIGURATION_TYPE Type,
  268. IN ULONG Key,
  269. IN PNODE_CALLBACK CallbackRoutine
  270. )
  271. /*++
  272. Routine Description:
  273. Conduct a depth-first search of the firmware configuration tree starting
  274. at a given node, looking for nodes that match a given class and type.
  275. When a matching node is found, call a callback routine.
  276. Arguments:
  277. CurrentNode - node at which to begin the search.
  278. Class - configuration class to match, or -1 to match any class
  279. Type - configuration type to match, or -1 to match any class
  280. Key - key to match, or -1 to match any key
  281. FoundRoutine - pointer to a routine to be called when a node whose
  282. class and type match the class and type passed in is located.
  283. The routine takes a pointer to the configuration node and must
  284. return a boolean indicating whether to continue with the traversal.
  285. Return Value:
  286. FALSE if the caller should abandon the search.
  287. --*/
  288. {
  289. PCONFIGURATION_COMPONENT_DATA Child;
  290. do {
  291. if (Child = Node->Child) {
  292. if (!BlSearchConfigTree(Child,
  293. Class,
  294. Type,
  295. Key,
  296. CallbackRoutine)) {
  297. return(FALSE);
  298. }
  299. }
  300. if (((Class == -1) || (Node->ComponentEntry.Class == Class))
  301. &&((Type == -1) || (Node->ComponentEntry.Type == Type))
  302. &&((Key == (ULONG)-1) || (Node->ComponentEntry.Key == Key))) {
  303. if (!CallbackRoutine(Node)) {
  304. return(FALSE);
  305. }
  306. }
  307. Node = Node->Sibling;
  308. } while ( Node != NULL );
  309. return(TRUE);
  310. }
  311. VOID
  312. BlGetPathnameFromComponent(
  313. IN PCONFIGURATION_COMPONENT_DATA Component,
  314. OUT PCHAR ArcName
  315. )
  316. /*++
  317. Routine Description:
  318. This function builds an ARC pathname for the specified component.
  319. Arguments:
  320. Component - Supplies a pointer to a configuration component.
  321. ArcName - Returns the ARC name of the specified component. Caller must
  322. provide a large enough buffer.
  323. Return Value:
  324. None.
  325. --*/
  326. {
  327. if (Component->Parent != NULL) {
  328. BlGetPathnameFromComponent(Component->Parent,ArcName);
  329. //
  330. // append our segment to the arcname
  331. //
  332. sprintf(ArcName+strlen(ArcName),
  333. "%s(%d)",
  334. MnemonicTable[Component->ComponentEntry.Type],
  335. Component->ComponentEntry.Key);
  336. } else {
  337. //
  338. // We are the parent, initialize the string and return
  339. //
  340. ArcName[0] = '\0';
  341. }
  342. return;
  343. }
  344. BOOLEAN
  345. BlGetPathMnemonicKey(
  346. IN PCHAR OpenPath,
  347. IN PCHAR Mnemonic,
  348. IN PULONG Key
  349. )
  350. /*++
  351. Routine Description:
  352. This routine looks for the given Mnemonic in OpenPath.
  353. If Mnemonic is a component of the path, then it converts the key
  354. value to an integer wich is returned in Key.
  355. Arguments:
  356. OpenPath - Pointer to a string that contains an ARC pathname.
  357. Mnemonic - Pointer to a string that contains a ARC Mnemonic
  358. Key - Pointer to a ULONG where the Key value is stored.
  359. Return Value:
  360. FALSE if mnemonic is found in path and a valid key is converted.
  361. TRUE otherwise.
  362. --*/
  363. {
  364. PCHAR Tmp;
  365. CHAR Digits[9];
  366. ULONG i;
  367. CHAR String[16];
  368. //
  369. // Construct a string of the form ")mnemonic("
  370. //
  371. String[0]=')';
  372. for(i=1;*Mnemonic;i++) {
  373. String[i] = * Mnemonic++;
  374. }
  375. String[i++]='(';
  376. String[i]='\0';
  377. if ((Tmp=strstr(OpenPath,&String[1])) == NULL) {
  378. return TRUE;
  379. }
  380. if (Tmp != OpenPath) {
  381. if ((Tmp=strstr(OpenPath,String)) == NULL) {
  382. return TRUE;
  383. }
  384. } else {
  385. i--;
  386. }
  387. //
  388. // skip the mnemonic and convert the value in between parentheses to integer
  389. //
  390. Tmp+=i;
  391. for (i=0;i<sizeof(Digits) - 1;i++) {
  392. if (*Tmp == ')') {
  393. Digits[i] = '\0';
  394. break;
  395. }
  396. Digits[i] = *Tmp++;
  397. }
  398. Digits[i]='\0';
  399. *Key = atoi(Digits);
  400. return FALSE;
  401. }
  402. ARC_STATUS
  403. BlGenerateDeviceNames (
  404. IN PCHAR ArcDeviceName,
  405. OUT PCHAR ArcCanonicalName,
  406. OUT OPTIONAL PCHAR NtDevicePrefix
  407. )
  408. /*++
  409. Routine Description:
  410. This routine generates an NT device name prefix and a canonical ARC
  411. device name from an ARC device name.
  412. Arguments:
  413. ArcDeviceName - Supplies a pointer to a zero terminated ARC device
  414. name.
  415. ArcCanonicalName - Supplies a pointer to a variable that receives the
  416. ARC canonical device name.
  417. NtDevicePrefix - If present, supplies a pointer to a variable that receives the
  418. NT device name prefix.
  419. Return Value:
  420. ESUCCESS is returned if an NT device name prefix and the canonical
  421. ARC device name are successfully generated from the ARC device name.
  422. Otherwise, an invalid argument status is returned.
  423. --*/
  424. {
  425. CHAR AdapterPath[64];
  426. CHAR AdapterName[32];
  427. ULONG AdapterNumber;
  428. CHAR ControllerName[32];
  429. ULONG ControllerNumber;
  430. ULONG MatchIndex;
  431. CHAR PartitionName[32];
  432. ULONG PartitionNumber;
  433. CHAR PeripheralName[32];
  434. ULONG PeripheralNumber;
  435. CHAR TokenValue[32];
  436. //
  437. // Get the adapter and make sure it is valid.
  438. //
  439. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  440. &AdapterName[0],
  441. &AdapterNumber);
  442. if (ArcDeviceName == NULL) {
  443. return EINVAL;
  444. }
  445. MatchIndex = BlMatchToken(&AdapterName[0], &BlAdapterTypes[0]);
  446. if (MatchIndex == AdapterMaximum) {
  447. return EINVAL;
  448. }
  449. sprintf(AdapterPath, "%s(%d)", AdapterName, AdapterNumber);
  450. if ((MatchIndex == AdapterNet) || (MatchIndex == AdapterRamdisk)) {
  451. strcpy(ArcCanonicalName, AdapterPath);
  452. if (ARGUMENT_PRESENT(NtDevicePrefix)) {
  453. *NtDevicePrefix = 0;
  454. }
  455. return ESUCCESS;
  456. }
  457. //
  458. // The next token is either another adapter or a controller. ARC
  459. // names can have multiple adapters. (e.g. "multi(0)scsi(0)disk(0)...")
  460. // Iterate until we find a token that is not an adapter.
  461. //
  462. do {
  463. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  464. &ControllerName[0],
  465. &ControllerNumber);
  466. if (ArcDeviceName == NULL) {
  467. return EINVAL;
  468. }
  469. MatchIndex = BlMatchToken(&ControllerName[0], &BlAdapterTypes[0]);
  470. if (MatchIndex == AdapterMaximum) {
  471. //
  472. // If it is not an adapter, we must have reached the last
  473. // adapter in the name. Fall through to the controller logic.
  474. //
  475. break;
  476. } else {
  477. //
  478. // We have found another adapter, add it to
  479. // the canonical adapter path
  480. //
  481. sprintf(AdapterPath+strlen(AdapterPath),
  482. "%s(%d)",
  483. ControllerName,
  484. ControllerNumber);
  485. }
  486. } while ( TRUE );
  487. MatchIndex = BlMatchToken(&ControllerName[0], &BlControllerTypes[0]);
  488. switch (MatchIndex) {
  489. //
  490. // Cdrom controller.
  491. //
  492. // Get the peripheral name and make sure it is valid.
  493. //
  494. case ControllerCdrom:
  495. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  496. &PeripheralName[0],
  497. &PeripheralNumber);
  498. if (ArcDeviceName == NULL) {
  499. return EINVAL;
  500. }
  501. if (_stricmp(&PeripheralName[0], "fdisk") != 0) {
  502. return EINVAL;
  503. }
  504. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  505. &TokenValue[0],
  506. &MatchIndex);
  507. if (ArcDeviceName != NULL) {
  508. return EINVAL;
  509. }
  510. sprintf(ArcCanonicalName,
  511. "%s%s(%d)%s(%d)",
  512. &AdapterPath[0],
  513. &ControllerName[0],
  514. ControllerNumber,
  515. &PeripheralName[0],
  516. PeripheralNumber);
  517. if (ARGUMENT_PRESENT(NtDevicePrefix)) {
  518. strcpy(NtDevicePrefix, "\\Device\\CDRom");
  519. }
  520. break;
  521. //
  522. // Disk controller.
  523. //
  524. // Get the peripheral and make sure it is valid.
  525. //
  526. case ControllerDisk:
  527. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  528. &PeripheralName[0],
  529. &PeripheralNumber);
  530. if (ArcDeviceName == NULL) {
  531. return EINVAL;
  532. }
  533. MatchIndex = BlMatchToken(&PeripheralName[0], &BlPeripheralTypes[0]);
  534. switch (MatchIndex) {
  535. //
  536. // Rigid Disk.
  537. //
  538. // If a partition is specified, then parse the partition number.
  539. //
  540. case PeripheralRigidDisk:
  541. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  542. &PartitionName[0],
  543. &PartitionNumber);
  544. if (ArcDeviceName == NULL) {
  545. strcpy(&PartitionName[0], "partition");
  546. PartitionNumber = 1;
  547. } else {
  548. if (_stricmp(&PartitionName[0], "partition") != 0) {
  549. return EINVAL;
  550. }
  551. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  552. &TokenValue[0],
  553. &MatchIndex);
  554. if (ArcDeviceName != NULL) {
  555. return EINVAL;
  556. }
  557. }
  558. sprintf(ArcCanonicalName,
  559. "%s%s(%d)%s(%d)%s(%d)",
  560. &AdapterPath[0],
  561. &ControllerName[0],
  562. ControllerNumber,
  563. &PeripheralName[0],
  564. PeripheralNumber,
  565. &PartitionName[0],
  566. PartitionNumber);
  567. if (ARGUMENT_PRESENT(NtDevicePrefix)) {
  568. strcpy(NtDevicePrefix, "\\Device\\Harddisk");
  569. }
  570. break;
  571. //
  572. // Floppy disk.
  573. //
  574. case PeripheralFloppyDisk:
  575. #if defined(ARCI386)
  576. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  577. &PartitionName[0],
  578. &PartitionNumber);
  579. if (ArcDeviceName == NULL) {
  580. strcpy(&PartitionName[0], "partition");
  581. PartitionNumber = 1;
  582. } else {
  583. if (_stricmp(&PartitionName[0], "partition") != 0) {
  584. return EINVAL;
  585. }
  586. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  587. &TokenValue[0],
  588. &MatchIndex);
  589. if (ArcDeviceName != NULL) {
  590. return EINVAL;
  591. }
  592. }
  593. sprintf(ArcCanonicalName,
  594. "%s%s(%d)%s(%d)%s(%d)",
  595. &AdapterPath[0],
  596. &ControllerName[0],
  597. ControllerNumber,
  598. &PeripheralName[0],
  599. PeripheralNumber,
  600. &PartitionName[0],
  601. PartitionNumber);
  602. #else
  603. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  604. &TokenValue[0],
  605. &MatchIndex);
  606. if (ArcDeviceName != NULL) {
  607. return EINVAL;
  608. }
  609. sprintf(ArcCanonicalName,
  610. "%s%s(%d)%s(%d)",
  611. &AdapterPath[0],
  612. &ControllerName[0],
  613. ControllerNumber,
  614. &PeripheralName[0],
  615. PeripheralNumber);
  616. #endif // defined(NEC_98)
  617. if (ARGUMENT_PRESENT(NtDevicePrefix)) {
  618. strcpy(NtDevicePrefix, "\\Device\\Floppy");
  619. }
  620. break;
  621. #if defined(ELTORITO)
  622. //
  623. // El Torito CD-ROM.
  624. //
  625. case PeripheralElTorito:
  626. ArcDeviceName = BlGetNextToken(ArcDeviceName,
  627. &TokenValue[0],
  628. &MatchIndex);
  629. if (ArcDeviceName != NULL) {
  630. return EINVAL;
  631. }
  632. sprintf(ArcCanonicalName,
  633. "%s%s(%d)%s(%d)",
  634. &AdapterPath[0],
  635. &ControllerName[0],
  636. ControllerNumber,
  637. &PeripheralName[0],
  638. PeripheralNumber);
  639. if (ARGUMENT_PRESENT(NtDevicePrefix)) {
  640. strcpy(NtDevicePrefix, "\\Device\\CDRom");
  641. }
  642. break;
  643. #endif
  644. //
  645. // Invalid peripheral.
  646. //
  647. default:
  648. return EINVAL;
  649. }
  650. break;
  651. //
  652. // Invalid controller.
  653. //
  654. default:
  655. return EINVAL;
  656. }
  657. return ESUCCESS;
  658. }
  659. PCHAR
  660. BlGetNextToken (
  661. IN PCHAR TokenString,
  662. OUT PCHAR OutputToken,
  663. OUT PULONG UnitNumber
  664. )
  665. /*++
  666. Routine Description:
  667. This routine scans the specified token string for the next token and
  668. unit number. The token format is:
  669. name[(unit)]
  670. Arguments:
  671. TokenString - Supplies a pointer to a zero terminated token string.
  672. OutputToken - Supplies a pointer to a variable that receives the next
  673. token.
  674. UnitNumber - Supplies a pointer to a variable that receives the unit
  675. number.
  676. Return Value:
  677. If another token exists in the token string, then a pointer to the
  678. start of the next token is returned. Otherwise, a value of NULL is
  679. returned.
  680. --*/
  681. {
  682. //
  683. // If there are more characters in the token string, then parse the
  684. // next token. Otherwise, return a value of NULL.
  685. //
  686. if (*TokenString == '\0') {
  687. return NULL;
  688. } else {
  689. while ((*TokenString != '\0') && (*TokenString != '(')) {
  690. *OutputToken++ = *TokenString++;
  691. }
  692. *OutputToken = '\0';
  693. //
  694. // If a unit number is specified, then convert it to binary.
  695. // Otherwise, default the unit number to zero.
  696. //
  697. *UnitNumber = 0;
  698. if (*TokenString == '(') {
  699. TokenString += 1;
  700. while ((*TokenString != '\0') && (*TokenString != ')')) {
  701. *UnitNumber = (*UnitNumber * 10) + (*TokenString++ - '0');
  702. }
  703. if (*TokenString == ')') {
  704. TokenString += 1;
  705. }
  706. }
  707. }
  708. return TokenString;
  709. }
  710. ULONG
  711. BlMatchToken (
  712. IN PCHAR TokenValue,
  713. IN CHAR * FIRMWARE_PTR TokenArray[]
  714. )
  715. /*++
  716. Routine Description:
  717. This routine attempts to match a token with an array of possible
  718. values.
  719. Arguments:
  720. TokenValue - Supplies a pointer to a zero terminated token value.
  721. TokenArray - Supplies a pointer to a vector of pointers to null terminated
  722. match strings.
  723. Return Value:
  724. If a token match is located, then the index of the matching value is
  725. returned as the function value. Otherwise, an index one greater than
  726. the size of the match array is returned.
  727. --*/
  728. {
  729. ULONG Index;
  730. PCHAR MatchString;
  731. PCHAR TokenString;
  732. //
  733. // Scan the match array until either a match is found or all of
  734. // the match strings have been scanned.
  735. //
  736. Index = 0;
  737. while (TokenArray[Index] != NULL) {
  738. MatchString = TokenArray[Index];
  739. TokenString = TokenValue;
  740. while ((*MatchString != '\0') && (*TokenString != '\0')) {
  741. if (toupper(*MatchString) != toupper(*TokenString)) {
  742. break;
  743. }
  744. MatchString += 1;
  745. TokenString += 1;
  746. }
  747. if ((*MatchString == '\0') && (*TokenString == '\0')) {
  748. break;
  749. }
  750. Index += 1;
  751. }
  752. return Index;
  753. }