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.

2772 lines
68 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. tuples.c
  5. Abstract:
  6. This module contains the code that parses and processes
  7. the configuration tuples of the PC Cards in the PCMCIA sockets
  8. Author:
  9. Bob Rinne (BobRi) 3-Aug-1994
  10. Jeff McLeman 12-Apr-1994
  11. Ravisankar Pudipeddi (ravisp) 1-Nov-1996
  12. Neil Sandlin (neilsa) 1-Jun-1999
  13. Revision History:
  14. Lotsa cleaning up. Support for PnP.
  15. orthogonalized tuple processing.
  16. Support links etc.
  17. - Ravisankar Pudipeddi (ravisp) 1-Dec-1996
  18. Environment:
  19. Kernel mode
  20. Revision History :
  21. --*/
  22. #include "pch.h"
  23. #define MAX_MISSED_TUPLES 256 // how many bad tuples will we tolerate?
  24. #define MAX_TUPLE_DATA_LENGTH 128 // Enough for the longest tuple
  25. BOOLEAN
  26. CheckLinkTarget(
  27. IN PTUPLE_PACKET TuplePacket
  28. );
  29. UCHAR
  30. ConvertVoltage(
  31. UCHAR MantissaExponentByte,
  32. UCHAR ExtensionByte
  33. );
  34. VOID
  35. PcmciaProcessPower(
  36. IN PTUPLE_PACKET TuplePacket,
  37. UCHAR FeatureByte
  38. );
  39. VOID
  40. PcmciaProcessIoSpace(
  41. IN PTUPLE_PACKET TuplePacket,
  42. PCONFIG_ENTRY ConfigEntry
  43. );
  44. VOID
  45. PcmciaProcessIrq(
  46. IN PTUPLE_PACKET TuplePacket,
  47. PCONFIG_ENTRY ConfigEntry
  48. );
  49. VOID
  50. PcmciaProcessTiming(
  51. IN PTUPLE_PACKET TuplePacket,
  52. IN PCONFIG_ENTRY ConfigEntry
  53. );
  54. VOID
  55. PcmciaProcessMemSpace(
  56. IN PTUPLE_PACKET TuplePacket,
  57. IN PCONFIG_ENTRY ConfigEntry,
  58. IN UCHAR MemSpace
  59. );
  60. VOID
  61. PcmciaMiscFeatures(
  62. IN PTUPLE_PACKET TuplePacket
  63. );
  64. PCONFIG_ENTRY
  65. PcmciaProcessConfigTable(
  66. IN PTUPLE_PACKET TuplePacket
  67. );
  68. VOID
  69. ProcessConfig(
  70. IN PTUPLE_PACKET TuplePacket
  71. );
  72. VOID
  73. ProcessConfigCB(
  74. IN PTUPLE_PACKET TuplePacket
  75. );
  76. NTSTATUS
  77. InitializeTuplePacket(
  78. IN PTUPLE_PACKET TuplePacket
  79. );
  80. NTSTATUS
  81. GetFirstTuple(
  82. IN PTUPLE_PACKET TuplePacket
  83. );
  84. BOOLEAN
  85. TupleMatches(
  86. IN PTUPLE_PACKET TuplePacket
  87. );
  88. NTSTATUS
  89. GetNextTuple(
  90. IN PTUPLE_PACKET TuplePacket
  91. );
  92. NTSTATUS
  93. NextTupleInChain(
  94. IN PTUPLE_PACKET TuplePacket
  95. );
  96. NTSTATUS
  97. GetAnyTuple(
  98. IN PTUPLE_PACKET TuplePacket
  99. );
  100. NTSTATUS
  101. FollowLink(
  102. IN PTUPLE_PACKET TuplePacket
  103. );
  104. NTSTATUS
  105. NextLink(
  106. IN PTUPLE_PACKET TuplePacket
  107. );
  108. NTSTATUS
  109. GetTupleData(
  110. IN PTUPLE_PACKET TuplePacket
  111. );
  112. UCHAR
  113. GetTupleChar(
  114. IN PTUPLE_PACKET TuplePacket
  115. );
  116. NTSTATUS
  117. ProcessLinkTuple(
  118. IN PTUPLE_PACKET TuplePacket
  119. );
  120. BOOLEAN
  121. PcmciaQuickVerifyTupleChain(
  122. IN PUCHAR Buffer,
  123. IN ULONG Length
  124. );
  125. NTSTATUS
  126. PcmciaMemoryCardHack(
  127. IN PSOCKET Socket,
  128. PSOCKET_DATA SocketData
  129. );
  130. VOID
  131. PcmciaCheckForRecognizedDevice(
  132. IN PSOCKET Socket,
  133. IN OUT PSOCKET_DATA SocketData
  134. );
  135. //
  136. // Some useful macros
  137. //
  138. // VOID
  139. // PcmciaCopyIrqConfig(
  140. // IN CONFIG_ENTRY DestConfig,
  141. // IN CONFIG_ENTRY SourceConfig
  142. // )
  143. // Routine Description:
  144. // Copies the IRQ information from SourceConfig to DestConfig
  145. //
  146. // Arguments:
  147. //
  148. // DestConfig - a pointer to the destination configuration entry
  149. // SourceConfig - a pointer to the source configuration entry
  150. //
  151. // Return Values:
  152. // None
  153. //
  154. #define PcmciaCopyIrqConfig(DestConfig, SourceConfig) \
  155. { \
  156. DestConfig->IrqMask = SourceConfig->IrqMask; \
  157. DestConfig->LevelIrq = SourceConfig->LevelIrq; \
  158. DestConfig->ShareDisposition = \
  159. SourceConfig->ShareDisposition; \
  160. }
  161. //
  162. // VOID
  163. // PcmciaCopyIoConfig(
  164. // IN CONFIG_ENTRY DestConfig,
  165. // IN CONFIG_ENTRY SourceConfig
  166. // )
  167. // Routine Description:
  168. // Copies the Io space information from SourceConfig to DestConfig
  169. //
  170. // Arguments:
  171. //
  172. // DestConfig - a pointer to the destination configuration entry
  173. // SourceConfig - a pointer to the source configuration entry
  174. //
  175. // Return Values:
  176. // None
  177. //
  178. #define PcmciaCopyIoConfig(DestConfig, SourceConfig) \
  179. { \
  180. DestConfig->NumberOfIoPortRanges = \
  181. SourceConfig->NumberOfIoPortRanges; \
  182. DestConfig->Io16BitAccess = \
  183. SourceConfig->Io16BitAccess; \
  184. DestConfig->Io8BitAccess = \
  185. SourceConfig->Io8BitAccess; \
  186. RtlCopyMemory(DestConfig->IoPortBase, \
  187. SourceConfig->IoPortBase, \
  188. sizeof(SourceConfig->IoPortBase[0])* \
  189. SourceConfig->NumberOfIoPortRanges); \
  190. RtlCopyMemory(DestConfig->IoPortLength, \
  191. SourceConfig->IoPortLength, \
  192. sizeof(SourceConfig->IoPortLength[0])* \
  193. SourceConfig->NumberOfIoPortRanges); \
  194. RtlCopyMemory(DestConfig->IoPortAlignment, \
  195. SourceConfig->IoPortAlignment, \
  196. sizeof(SourceConfig->IoPortAlignment[0])* \
  197. SourceConfig->NumberOfIoPortRanges); \
  198. }
  199. //
  200. // VOID
  201. // PcmciaCopyMemConfig(
  202. // IN CONFIG_ENTRY DestConfig,
  203. // IN CONFIG_ENTRY SourceConfig
  204. // )
  205. // Routine Description:
  206. // Copies the Memory space information from SourceConfig to DestConfig
  207. //
  208. // Arguments:
  209. //
  210. // DestConfig - a pointer to the destination configuration entry
  211. // SourceConfig - a pointer to the source configuration entry
  212. //
  213. // Return Values:
  214. // None
  215. //
  216. #define PcmciaCopyMemConfig(DestConfig,SourceConfig) \
  217. { \
  218. DestConfig->NumberOfMemoryRanges = \
  219. SourceConfig->NumberOfMemoryRanges; \
  220. RtlCopyMemory(DestConfig->MemoryHostBase, \
  221. SourceConfig->MemoryHostBase, \
  222. sizeof(SourceConfig->MemoryHostBase[0])* \
  223. SourceConfig->NumberOfMemoryRanges); \
  224. RtlCopyMemory(DestConfig->MemoryCardBase, \
  225. SourceConfig->MemoryCardBase, \
  226. sizeof(SourceConfig->MemoryCardBase[0])* \
  227. SourceConfig->NumberOfMemoryRanges); \
  228. RtlCopyMemory(DestConfig->MemoryLength, \
  229. SourceConfig->MemoryLength, \
  230. sizeof(SourceConfig->MemoryLength[0])* \
  231. SourceConfig->NumberOfMemoryRanges); \
  232. }
  233. USHORT VoltageConversionTable[16] = {
  234. 10, 12, 13, 15, 20, 25, 30, 35,
  235. 40, 45, 50, 55, 60, 70, 80, 90
  236. };
  237. UCHAR TplList[] = {
  238. CISTPL_DEVICE,
  239. CISTPL_VERS_1,
  240. CISTPL_CONFIG,
  241. CISTPL_CFTABLE_ENTRY,
  242. CISTPL_MANFID,
  243. CISTPL_END
  244. };
  245. static unsigned short crc16a[] = {
  246. 0000000, 0140301, 0140601, 0000500,
  247. 0141401, 0001700, 0001200, 0141101,
  248. 0143001, 0003300, 0003600, 0143501,
  249. 0002400, 0142701, 0142201, 0002100,
  250. };
  251. static unsigned short crc16b[] = {
  252. 0000000, 0146001, 0154001, 0012000,
  253. 0170001, 0036000, 0024000, 0162001,
  254. 0120001, 0066000, 0074000, 0132001,
  255. 0050000, 0116001, 0104001, 0043000,
  256. };
  257. UCHAR
  258. GetCISChar(
  259. IN PTUPLE_PACKET TuplePacket,
  260. IN ULONG Offset
  261. )
  262. /*++
  263. Routine Description:
  264. Returns the contents of the CIS memory of the PC-Card
  265. in the given socket, at the specified offset
  266. Arguments:
  267. TuplePacket - Pointer to the initialized tuple packet
  268. Offset - Offset at which the CIS memory contents need to be read
  269. This offset is added to the current offset position
  270. of the CIS being read as indicated through the TuplePacket
  271. to obtain the actual offset
  272. Return Value:
  273. The byte at the specified offset of the CIS
  274. --*/
  275. {
  276. PPDO_EXTENSION pdoExtension = TuplePacket->SocketData->PdoExtension;
  277. MEMORY_SPACE MemorySpace;
  278. if (Is16BitCardInSocket(pdoExtension->Socket)) {
  279. if (TuplePacket->Flags & TPLF_COMMON) {
  280. MemorySpace = (TuplePacket->Flags & TPLF_INDIRECT) ?
  281. PCCARD_COMMON_MEMORY_INDIRECT :
  282. PCCARD_COMMON_MEMORY;
  283. } else {
  284. MemorySpace = (TuplePacket->Flags & TPLF_INDIRECT) ?
  285. PCCARD_ATTRIBUTE_MEMORY_INDIRECT :
  286. PCCARD_ATTRIBUTE_MEMORY;
  287. }
  288. } else {
  289. switch((TuplePacket->Flags & TPLF_ASI) >> TPLF_ASI_SHIFT) {
  290. case 0:
  291. MemorySpace = PCCARD_PCI_CONFIGURATION_SPACE;
  292. break;
  293. case 1:
  294. MemorySpace = PCCARD_CARDBUS_BAR0;
  295. break;
  296. case 2:
  297. MemorySpace = PCCARD_CARDBUS_BAR1;
  298. break;
  299. case 3:
  300. MemorySpace = PCCARD_CARDBUS_BAR2;
  301. break;
  302. case 4:
  303. MemorySpace = PCCARD_CARDBUS_BAR3;
  304. break;
  305. case 5:
  306. MemorySpace = PCCARD_CARDBUS_BAR4;
  307. break;
  308. case 6:
  309. MemorySpace = PCCARD_CARDBUS_BAR5;
  310. break;
  311. case 7:
  312. MemorySpace = PCCARD_CARDBUS_ROM;
  313. break;
  314. }
  315. }
  316. return PcmciaReadCISChar(pdoExtension, MemorySpace, TuplePacket->CISOffset + Offset);
  317. }
  318. UCHAR
  319. ConvertVoltage(
  320. UCHAR MantissaExponentByte,
  321. UCHAR ExtensionByte
  322. )
  323. /*++
  324. Routine Description:
  325. Convert the voltage requirements for the PCCARD based on the
  326. mantissa and extension byte.
  327. Arguments:
  328. MantissaExponentByte
  329. ExtensionByte
  330. Return Value:
  331. The voltage specified in tenths of a volt.
  332. --*/
  333. {
  334. SHORT power;
  335. USHORT value;
  336. value = (USHORT) VoltageConversionTable[(MantissaExponentByte >> 3) & 0x0f];
  337. power = 1;
  338. if ((MantissaExponentByte & EXTENSION_BYTE_FOLLOWS) &&
  339. (((value / 10) * 10) == value) &&
  340. (ExtensionByte < 100)) {
  341. value = (10 * value + (ExtensionByte & 0x7f));
  342. power += 1;
  343. }
  344. power = (MantissaExponentByte & 0x07) - 4 - power;
  345. while (power > 0) {
  346. value *= 10;
  347. power--;
  348. }
  349. while (power < 0) {
  350. value /= 10;
  351. power++;
  352. }
  353. return (UCHAR) value;
  354. }
  355. VOID
  356. PcmciaProcessPower(
  357. IN PTUPLE_PACKET TuplePacket,
  358. UCHAR FeatureByte
  359. )
  360. /*++
  361. Routine Description:
  362. Process power information from CIS.
  363. Arguments:
  364. TuplePacket - Pointer the caller supplied, initialized tuple packet
  365. FeatureByte - the feature byte from the tuple containing power information.
  366. Return Value:
  367. none
  368. --*/
  369. {
  370. PSOCKET_DATA SocketData = TuplePacket->SocketData;
  371. UCHAR powerSelect;
  372. UCHAR bit;
  373. UCHAR item;
  374. UCHAR rawItem;
  375. UCHAR extensionByte;
  376. UCHAR index = 0;
  377. UCHAR count = FeatureByte;
  378. UCHAR skipByte;
  379. ASSERT(count <= 3);
  380. while (index < count) {
  381. powerSelect = GetTupleChar(TuplePacket);
  382. for (bit = 0; bit < 7; bit++) {
  383. if (powerSelect & (1 << bit)) {
  384. rawItem = GetTupleChar(TuplePacket);
  385. if (rawItem & EXTENSION_BYTE_FOLLOWS) {
  386. extensionByte = GetTupleChar(TuplePacket);
  387. //
  388. // Skip the rest
  389. //
  390. skipByte = extensionByte;
  391. while (skipByte & EXTENSION_BYTE_FOLLOWS) {
  392. skipByte = GetTupleChar(TuplePacket);
  393. }
  394. } else {
  395. extensionByte = (UCHAR) 0;
  396. }
  397. if (bit == 0) {
  398. //
  399. // Convert nominal power for output.
  400. //
  401. item = ConvertVoltage(rawItem, extensionByte);
  402. switch (index) {
  403. case 0:
  404. SocketData->Vcc = item;
  405. break;
  406. case 1:
  407. SocketData->Vpp2 = SocketData->Vpp1 = item;
  408. break;
  409. case 2:
  410. SocketData->Vpp2 = item;
  411. break;
  412. }
  413. }
  414. }
  415. }
  416. index++;
  417. }
  418. }
  419. VOID
  420. PcmciaProcessIoSpace(
  421. IN PTUPLE_PACKET TuplePacket,
  422. PCONFIG_ENTRY ConfigEntry
  423. )
  424. /*++
  425. Routine Description:
  426. Process I/O space information from CIS.
  427. Arguments:
  428. TuplePacket - Pointer the caller supplied, initialized tuple packet
  429. ConfigEntry - a config entry structure in which to store the information.
  430. Return Value:
  431. none
  432. --*/
  433. {
  434. ULONG address = 0;
  435. ULONG index=0, i;
  436. UCHAR item = GetTupleChar(TuplePacket);
  437. UCHAR ioAddrLines = (item & IO_ADDRESS_LINES_MASK);
  438. UCHAR ranges=0;
  439. UCHAR addressSize=0;
  440. UCHAR lengthSize=0;
  441. ConfigEntry->Io16BitAccess = Is16BitAccess(item);
  442. ConfigEntry->Io8BitAccess = Is8BitAccess(item);
  443. ranges = HasRanges(item);
  444. if ((!ranges) && (!ioAddrLines)) {
  445. //
  446. // The IBM token ring card has a slightly different interpretation
  447. // of the tuple data here. It isn't clear it is incorrect.
  448. //
  449. ranges = 0xFF;
  450. }
  451. if (ranges) {
  452. //
  453. // Specific ranges listed in the tuple.
  454. //
  455. if (ranges == 0xFF) {
  456. //
  457. // Special processing for IBM token ring IoSpace layout.
  458. //
  459. addressSize = 2;
  460. lengthSize = 1;
  461. ranges = 1;
  462. } else {
  463. item = GetTupleChar(TuplePacket);
  464. ranges = item & RANGE_MASK;
  465. ranges++;
  466. addressSize = GetAddressSize(item);
  467. lengthSize = GetLengthSize(item);
  468. }
  469. index = 0;
  470. while (ranges) {
  471. address = 0;
  472. if (addressSize >= 1) {
  473. address = (ULONG) GetTupleChar(TuplePacket);
  474. }
  475. if (addressSize >= 2) {
  476. address |= (GetTupleChar(TuplePacket)) << 8;
  477. }
  478. if (addressSize >= 3) {
  479. address |= (GetTupleChar(TuplePacket)) << 16;
  480. address |= (GetTupleChar(TuplePacket)) << 24;
  481. }
  482. ConfigEntry->IoPortBase[index] = (USHORT) address;
  483. address = 0;
  484. if (lengthSize >= 1) {
  485. address = (ULONG) GetTupleChar(TuplePacket);
  486. }
  487. if (lengthSize >= 2) {
  488. address |= (GetTupleChar(TuplePacket)) << 8;
  489. }
  490. if (lengthSize >= 3) {
  491. address |= (GetTupleChar(TuplePacket)) << 16;
  492. address |= (GetTupleChar(TuplePacket)) << 24;
  493. }
  494. ConfigEntry->IoPortLength[index] = (USHORT) address;
  495. ConfigEntry->IoPortAlignment[index] = 1;
  496. index++;
  497. if (index == MAX_NUMBER_OF_IO_RANGES) {
  498. break;
  499. }
  500. ranges--;
  501. }
  502. ConfigEntry->NumberOfIoPortRanges = (USHORT) index;
  503. }
  504. //
  505. // Handle all combinations as specified in table on p. 80
  506. // (Basic compatibility Layer 1, i/o space encoding guidelines) of
  507. // PC Card standard Metaformat Specification, March 1997 (PCMCIA/JEIDA)
  508. //
  509. if (ioAddrLines) {
  510. //
  511. // A modulo base specified
  512. //
  513. if (addressSize == 0) {
  514. //
  515. // No I/O Base address specified
  516. //
  517. if (lengthSize == 0) {
  518. //
  519. // No ranges specified. This is a pure modulo base case
  520. //
  521. ConfigEntry->NumberOfIoPortRanges = 1;
  522. ConfigEntry->IoPortBase[0] = 0;
  523. ConfigEntry->IoPortLength[0] = (1 << ioAddrLines)-1;
  524. ConfigEntry->IoPortAlignment[0] = (1 << ioAddrLines);
  525. } else {
  526. //
  527. // Length specified. Modulo base is used only to specify alignment.
  528. //
  529. for (i=0; i < ConfigEntry->NumberOfIoPortRanges; i++) {
  530. ConfigEntry->IoPortBase[i] = 0;
  531. ConfigEntry->IoPortAlignment[i] = (1 << ioAddrLines);
  532. }
  533. }
  534. } else {
  535. //
  536. // Alignment specified..
  537. // This fix is for Xircom CE3 card
  538. //
  539. for (i=0; i < ConfigEntry->NumberOfIoPortRanges; i++) {
  540. if (ConfigEntry->IoPortBase[i] != 0) {
  541. //
  542. // Fixed base address supplied....
  543. // Don't specify alignment!
  544. //
  545. continue;
  546. }
  547. ConfigEntry->IoPortAlignment[i] = (1 << ioAddrLines);
  548. }
  549. }
  550. } else {
  551. //
  552. // No Modulo Base. So specific ranges should've been specified
  553. //
  554. if (lengthSize == 0) {
  555. //
  556. // Error! Length HAS to be specified
  557. //
  558. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaProcessIoSpace: Length not specified in TPCE_IO descriptor for PC Card\n"));
  559. } else if (addressSize == 0) {
  560. for (i = 0; i < ConfigEntry->NumberOfIoPortRanges; i++) {
  561. ConfigEntry->IoPortBase[i] = 0x0;
  562. ConfigEntry->IoPortAlignment[i] = 2;
  563. }
  564. } else {
  565. //
  566. // Proper ranges specified
  567. // Don't change anything
  568. }
  569. }
  570. }
  571. VOID
  572. PcmciaProcessIrq(
  573. IN PTUPLE_PACKET TuplePacket,
  574. PCONFIG_ENTRY ConfigEntry
  575. )
  576. /*++
  577. Routine Description:
  578. Process IRQ from CIS.
  579. Arguments:
  580. TuplePacket - Pointer the caller supplied, initialized tuple packet
  581. ConfigEntry - a place to store the IRQ.
  582. Return Value:
  583. none
  584. --*/
  585. {
  586. USHORT mask;
  587. UCHAR level = GetTupleChar(TuplePacket);
  588. if (!level) {
  589. //
  590. // NOTE: It looks like Future Domain messed up on this
  591. // and puts an extra zero byte into the structure.
  592. // skip it for now.
  593. //
  594. level = GetTupleChar(TuplePacket);
  595. }
  596. if (level & 0x20) {
  597. ConfigEntry->LevelIrq = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  598. } else {
  599. ConfigEntry->LevelIrq = CM_RESOURCE_INTERRUPT_LATCHED;
  600. }
  601. if (level & 0x80) {
  602. ConfigEntry->ShareDisposition = CmResourceShareShared;
  603. } else {
  604. ConfigEntry->ShareDisposition = CmResourceShareDeviceExclusive;
  605. }
  606. mask = level & 0x10;
  607. //
  608. // 3COM 3C589-75D5 has a peculiar problem
  609. // where mask bit is 0, but should have been 1.
  610. // Handle this case here
  611. //
  612. if ((mask==0) && ((level & 0xf) == 0)) {
  613. mask = 1;
  614. }
  615. if (mask) {
  616. //
  617. // Each bit set in the mask indicates the corresponding IRQ
  618. // (from 0-15) may be assigned to this card's interrupt req. pin
  619. //
  620. mask = (USHORT) GetTupleChar(TuplePacket);
  621. mask |= ((USHORT) GetTupleChar(TuplePacket)) << 8;
  622. ConfigEntry->IrqMask = mask;
  623. } else {
  624. ConfigEntry->IrqMask = 1 << (level & 0x0f);
  625. }
  626. }
  627. VOID
  628. PcmciaProcessTiming(
  629. IN PTUPLE_PACKET TuplePacket,
  630. IN PCONFIG_ENTRY ConfigEntry
  631. )
  632. /*++
  633. Routine Description:
  634. Move the data pointer around the timing information structure.
  635. No processing of this data occurs at this time.
  636. Arguments:
  637. TuplePacket - Pointer the caller supplied, initialized tuple packet
  638. ConfigEntry - currently unused.
  639. Return Value:
  640. none
  641. --*/
  642. {
  643. UCHAR item = GetTupleChar(TuplePacket);
  644. UCHAR reservedScale = (item & 0xe0) >> 5;
  645. UCHAR readyBusyScale = (item & 0x1c) >> 2;
  646. UCHAR waitScale = (item & 0x03);
  647. //
  648. // NOTE: It looks like the processing of extension bytes is not
  649. // coded correctly in this routine.
  650. //
  651. if (waitScale != 3) {
  652. item = GetTupleChar(TuplePacket);
  653. while (item & EXTENSION_BYTE_FOLLOWS) {
  654. item = GetTupleChar(TuplePacket);
  655. }
  656. }
  657. if (readyBusyScale != 7) {
  658. item = GetTupleChar(TuplePacket);
  659. while (item & EXTENSION_BYTE_FOLLOWS) {
  660. item = GetTupleChar(TuplePacket);
  661. }
  662. }
  663. if (reservedScale != 7) {
  664. item = GetTupleChar(TuplePacket);
  665. while (item & EXTENSION_BYTE_FOLLOWS) {
  666. item = GetTupleChar(TuplePacket);
  667. }
  668. }
  669. }
  670. VOID
  671. PcmciaProcessMemSpace(
  672. IN PTUPLE_PACKET TuplePacket,
  673. IN PCONFIG_ENTRY ConfigEntry,
  674. IN UCHAR MemSpace
  675. )
  676. /*++
  677. Routine Description:
  678. Process memory space requirements from CIS.
  679. Arguments:
  680. TuplePacket - Pointer the caller supplied, initialized tuple packet
  681. ConfigEntry - the socket configuration structure.
  682. MemSpace - the memory space enumerator from the config table entry
  683. structure.
  684. Return Value:
  685. none
  686. --*/
  687. {
  688. ULONG longValue;
  689. ULONG index;
  690. UCHAR lengthSize;
  691. UCHAR addrSize;
  692. UCHAR number;
  693. UCHAR hasHostAddress;
  694. switch (MemSpace) {
  695. case 1: {
  696. //
  697. // Only length is specified
  698. //
  699. longValue = (ULONG) GetTupleChar(TuplePacket);
  700. longValue |= ((ULONG) GetTupleChar(TuplePacket)) << 8;
  701. ConfigEntry->MemoryLength[0] = longValue * 256;
  702. ConfigEntry->NumberOfMemoryRanges++;
  703. break;
  704. }
  705. case 2: {
  706. longValue = (ULONG) GetTupleChar(TuplePacket);
  707. longValue |= ((ULONG) GetTupleChar(TuplePacket)) << 8;
  708. ConfigEntry->MemoryLength[0] = longValue * 256;
  709. longValue = (ULONG) GetTupleChar(TuplePacket);
  710. longValue |= ((ULONG) GetTupleChar(TuplePacket)) << 8;
  711. ConfigEntry->MemoryCardBase[0] =
  712. ConfigEntry->MemoryHostBase[0] = longValue * 256;
  713. ConfigEntry->NumberOfMemoryRanges++;
  714. break;
  715. }
  716. case 3: {
  717. UCHAR item = GetTupleChar(TuplePacket);
  718. lengthSize = (item & 0x18) >> 3;
  719. addrSize = (item & 0x60) >> 5;
  720. number = (item & 0x07) + 1;
  721. hasHostAddress = item & 0x80;
  722. if (number > MAX_NUMBER_OF_MEMORY_RANGES) {
  723. number = MAX_NUMBER_OF_MEMORY_RANGES;
  724. }
  725. for (index = 0; index < (ULONG) number; index++) {
  726. longValue = 0;
  727. if (lengthSize >= 1) {
  728. longValue = (ULONG) GetTupleChar(TuplePacket);
  729. }
  730. if (lengthSize >= 2) {
  731. longValue |= (GetTupleChar(TuplePacket)) << 8;
  732. }
  733. if (lengthSize == 3) {
  734. longValue |= (GetTupleChar(TuplePacket)) << 16;
  735. }
  736. ConfigEntry->MemoryLength[index] = longValue * 256;
  737. longValue = 0;
  738. if (addrSize >= 1) {
  739. longValue = (ULONG) GetTupleChar(TuplePacket);
  740. }
  741. if (addrSize >= 2) {
  742. longValue |= (GetTupleChar(TuplePacket)) << 8;
  743. }
  744. if (addrSize == 3) {
  745. longValue |= (GetTupleChar(TuplePacket)) << 16;
  746. }
  747. ConfigEntry->MemoryCardBase[index] = longValue * 256;
  748. if (hasHostAddress) {
  749. longValue = 0;
  750. if (addrSize >= 1) {
  751. longValue = (ULONG) GetTupleChar(TuplePacket);
  752. }
  753. if (addrSize >= 2) {
  754. longValue |= (GetTupleChar(TuplePacket)) << 8;
  755. }
  756. if (addrSize == 3) {
  757. longValue |= (GetTupleChar(TuplePacket)) << 16;
  758. }
  759. ConfigEntry->MemoryHostBase[index] = longValue * 256;
  760. }
  761. }
  762. ConfigEntry->NumberOfMemoryRanges = (USHORT) number;
  763. break;
  764. }
  765. }
  766. }
  767. PCONFIG_ENTRY
  768. PcmciaProcessConfigTable(
  769. IN PTUPLE_PACKET TuplePacket
  770. )
  771. /*++
  772. Routine Description:
  773. Arguments:
  774. TuplePacket - Pointer the caller supplied, initialized tuple packet
  775. Return Value:
  776. A pointer to a config entry structure if one is created.
  777. --*/
  778. {
  779. PSOCKET_DATA SocketData = TuplePacket->SocketData;
  780. PCONFIG_ENTRY configEntry;
  781. UCHAR item;
  782. UCHAR defaultBit;
  783. UCHAR memSpace;
  784. UCHAR power;
  785. UCHAR misc;
  786. configEntry = ExAllocatePool(NonPagedPool, sizeof(CONFIG_ENTRY));
  787. if (!configEntry) {
  788. return NULL;
  789. }
  790. RtlZeroMemory(configEntry, sizeof(CONFIG_ENTRY));
  791. item = GetTupleChar(TuplePacket);
  792. defaultBit = Default(item);
  793. configEntry->IndexForThisConfiguration = ConfigEntryNumber(item);
  794. if (IntFace(item)) {
  795. //
  796. // This byte indicates type of interface in tuple (i.e. io or memory)
  797. // This could be processed, but for now is just skipped.
  798. //
  799. item = GetTupleChar(TuplePacket);
  800. }
  801. item = GetTupleChar(TuplePacket);
  802. memSpace = MemSpaceInformation(item);
  803. power = PowerInformation(item);
  804. misc = MiscInformation(item);
  805. if (power) {
  806. PcmciaProcessPower(TuplePacket, power);
  807. }
  808. if (TimingInformation(item)) {
  809. PcmciaProcessTiming(TuplePacket, configEntry);
  810. }
  811. if (IoSpaceInformation(item)) {
  812. PcmciaProcessIoSpace(TuplePacket, configEntry);
  813. } else if (!defaultBit && (SocketData->DefaultConfiguration != NULL)) {
  814. PcmciaCopyIoConfig(configEntry, SocketData->DefaultConfiguration);
  815. }
  816. if (IRQInformation(item)) {
  817. PcmciaProcessIrq(TuplePacket, configEntry);
  818. } else if (!defaultBit && (SocketData->DefaultConfiguration != NULL)) {
  819. PcmciaCopyIrqConfig(configEntry,SocketData->DefaultConfiguration);
  820. }
  821. if (memSpace) {
  822. PcmciaProcessMemSpace(TuplePacket, configEntry, memSpace);
  823. } else if (!defaultBit && (SocketData->DefaultConfiguration != NULL)) {
  824. PcmciaCopyMemConfig(configEntry,SocketData->DefaultConfiguration);
  825. }
  826. if (misc) {
  827. PcmciaMiscFeatures(TuplePacket);
  828. } // need default bit processing here too
  829. if (defaultBit) {
  830. //
  831. // Save this config as the default config for this pc-card (which
  832. // may be accessed by subsequent tuples)
  833. //
  834. SocketData->DefaultConfiguration = configEntry;
  835. }
  836. //
  837. // One more configuration
  838. //
  839. SocketData->NumberOfConfigEntries++;
  840. DebugPrint((PCMCIA_DEBUG_TUPLES,
  841. "config entry %08x idx %x ccr %x\n",
  842. configEntry,
  843. configEntry->IndexForThisConfiguration,
  844. SocketData->ConfigRegisterBase
  845. ));
  846. return configEntry;
  847. }
  848. VOID
  849. PcmciaMiscFeatures(
  850. IN PTUPLE_PACKET TuplePacket
  851. )
  852. /*++
  853. Routine Description:
  854. Parse the miscellaneous features field and look for audio supported
  855. bit.
  856. Arguments:
  857. TuplePacket - Pointer the caller supplied, initialized tuple packet
  858. Return Value:
  859. none
  860. --*/
  861. {
  862. PSOCKET_DATA SocketData = TuplePacket->SocketData;
  863. UCHAR item = GetTupleChar(TuplePacket);
  864. DebugPrint((PCMCIA_DEBUG_TUPLES,
  865. "TPCE_MS (%lx) is present in CISTPL_CFTABLE_ENTRY \n",
  866. item));
  867. //
  868. // If the audio bit is set, remember this in the socket information
  869. // structure.
  870. //
  871. if (item & 0x8) {
  872. DebugPrint((PCMCIA_DEBUG_TUPLES,
  873. "Audio bit set in TPCE_MS \n"));
  874. SocketData->Audio = TRUE;
  875. }
  876. //
  877. // Step around the miscellaneous features and its extension bytes.
  878. //
  879. while (item & EXTENSION_BYTE_FOLLOWS) {
  880. item = GetTupleChar(TuplePacket);
  881. }
  882. }
  883. VOID
  884. ProcessConfig(
  885. IN PTUPLE_PACKET TuplePacket
  886. )
  887. /*++
  888. Routine Description:
  889. Parse the CISTPL_CONFIG to extract the last index value and the
  890. configuration register base for the PCCARD.
  891. Arguments:
  892. TuplePacket - Pointer the caller supplied, initialized tuple packet
  893. Return Value:
  894. None
  895. --*/
  896. {
  897. PSOCKET_DATA SocketData = TuplePacket->SocketData;
  898. PUCHAR TupleData = TuplePacket->TupleData;
  899. ULONG base = 0;
  900. UCHAR widthOfBaseAddress;
  901. UCHAR widthOfRegPresentMask;
  902. UCHAR widthOfReservedArea;
  903. UCHAR widthOfInterfaceId;
  904. UCHAR index;
  905. UCHAR subtupleCount = 0;
  906. ULONG InterfaceId;
  907. widthOfBaseAddress = TpccRasz(TupleData[0]) + 1;
  908. widthOfRegPresentMask = TpccRmsz(TupleData[0]) + 1;
  909. widthOfReservedArea = TpccRfsz(TupleData[0]);
  910. ASSERT (widthOfReservedArea == 0);
  911. ASSERT (widthOfRegPresentMask <= 16);
  912. SocketData->LastEntryInCardConfig = TupleData[1];
  913. switch (widthOfBaseAddress) {
  914. case 4:
  915. base = ((ULONG)TupleData[5] << 24);
  916. case 3:
  917. base |= ((ULONG)TupleData[4] << 16);
  918. case 2:
  919. base |= ((ULONG)TupleData[3] << 8);
  920. case 1:
  921. base |= TupleData[2];
  922. break;
  923. default:
  924. DebugPrint((PCMCIA_DEBUG_FAIL,
  925. "ProcessConfig - bad number of bytes %d\n",
  926. widthOfBaseAddress));
  927. break;
  928. }
  929. SocketData->ConfigRegisterBase = base;
  930. DebugPrint((PCMCIA_DEBUG_TUPLES,
  931. "ConfigRegisterBase in attribute memory is 0x%x\n",
  932. SocketData->ConfigRegisterBase));
  933. //
  934. // Copy the register presence mask
  935. //
  936. for (index = 0; index < widthOfRegPresentMask; index++) {
  937. SocketData->RegistersPresentMask[index] = TupleData[2 + widthOfBaseAddress + index];
  938. }
  939. DebugPrint((PCMCIA_DEBUG_TUPLES,
  940. "First Byte in RegPresentMask=%x, width is %d\n",
  941. SocketData->RegistersPresentMask[0], widthOfRegPresentMask));
  942. //
  943. // Look for subtuples
  944. //
  945. index = 2 + widthOfBaseAddress + widthOfRegPresentMask + widthOfReservedArea;
  946. while (((index+5) < TuplePacket->TupleDataMaxLength) &&
  947. (++subtupleCount <= 4) &&
  948. (TupleData[index] == CCST_CIF)) {
  949. widthOfInterfaceId = ((TupleData[index+2] & 0xC0) >> 6) + 1 ;
  950. InterfaceId = 0;
  951. switch (widthOfInterfaceId) {
  952. case 4:
  953. InterfaceId = ((ULONG)TupleData[index+5] << 24);
  954. case 3:
  955. InterfaceId |= ((ULONG)TupleData[index+4] << 16);
  956. case 2:
  957. InterfaceId |= ((ULONG)TupleData[index+3] << 8);
  958. case 1:
  959. InterfaceId |= TupleData[index+2];
  960. break;
  961. default:
  962. DebugPrint((PCMCIA_DEBUG_FAIL,
  963. "ProcessConfig - bad number of bytes %d in subtuple\n",
  964. widthOfInterfaceId));
  965. break;
  966. }
  967. DebugPrint((PCMCIA_DEBUG_TUPLES, "Custom Interface ID %8x\n", InterfaceId));
  968. //
  969. // Currently don't have generic code for recording sub-tuple information,
  970. // all we look for is Zoom Video.
  971. //
  972. if (InterfaceId == 0x141) {
  973. SocketData->Flags |= SDF_ZV;
  974. }
  975. index += (TupleData[index+1] + 2);
  976. }
  977. }
  978. VOID
  979. ProcessConfigCB(
  980. IN PTUPLE_PACKET TuplePacket
  981. )
  982. /*++
  983. Routine Description:
  984. Parse the CISTPL_CONFIG_CB to extract the last index value and the
  985. configuration register base for the PCCARD.
  986. Arguments:
  987. TuplePacket - Pointer the caller supplied, initialized tuple packet
  988. Return Value:
  989. None
  990. --*/
  991. {
  992. PSOCKET_DATA SocketData = TuplePacket->SocketData;
  993. PUCHAR TupleData = TuplePacket->TupleData;
  994. ULONG base = 0;
  995. UCHAR widthOfFields;
  996. widthOfFields = TupleData[0];
  997. if (widthOfFields != 3) {
  998. DebugPrint((PCMCIA_DEBUG_FAIL, "ProcessConfigCB - bad width of fields %d\n", widthOfFields));
  999. return;
  1000. }
  1001. SocketData->LastEntryInCardConfig = TupleData[1];
  1002. base = ((ULONG)TupleData[5] << 24);
  1003. base |= ((ULONG)TupleData[4] << 16);
  1004. base |= ((ULONG)TupleData[3] << 8);
  1005. base |= TupleData[2];
  1006. SocketData->ConfigRegisterBase = base;
  1007. DebugPrint((PCMCIA_DEBUG_TUPLES, "ConfigRegisterBase = %08x\n", SocketData->ConfigRegisterBase));
  1008. }
  1009. VOID
  1010. PcmciaSubstituteUnderscore(
  1011. IN OUT PUCHAR Str
  1012. )
  1013. /*++
  1014. Routine description
  1015. Substitutes underscores ('_' character) for invalid device id
  1016. characters such as spaces & commas in the supplied string
  1017. Parameters
  1018. Str - The string for which the substitution is to take place in situ
  1019. Return Value
  1020. None
  1021. --*/
  1022. {
  1023. if (Str == NULL) {
  1024. return;
  1025. }
  1026. while (*Str) {
  1027. if (*Str == ' ' ||
  1028. *Str == ',' ) {
  1029. *Str = '_';
  1030. }
  1031. Str++;
  1032. }
  1033. }
  1034. /*-------------- Tuple API starts here ----------------------------------------*/
  1035. NTSTATUS
  1036. InitializeTuplePacket(
  1037. IN PTUPLE_PACKET TuplePacket
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Initializes the supplied tuple packet
  1042. Arguments:
  1043. TuplePacket - Pointer the caller supplied tuple packet
  1044. Return Value:
  1045. Status
  1046. --*/
  1047. {
  1048. TuplePacket->Flags = TPLF_IMPLIED_LINK;
  1049. TuplePacket->LinkOffset = 0;
  1050. TuplePacket->CISOffset = 0;
  1051. if (IsCardBusCardInSocket(TuplePacket->Socket)) {
  1052. PPDO_EXTENSION pdoExtension = TuplePacket->SocketData->PdoExtension;
  1053. GetPciConfigSpace(pdoExtension, CBCFG_CISPTR, &TuplePacket->CISOffset, sizeof(TuplePacket->CISOffset));
  1054. DebugPrint((PCMCIA_DEBUG_TUPLES, "CardBus CISPTR = %08x\n", TuplePacket->CISOffset));
  1055. TuplePacket->Flags = TPLF_COMMON | TPLF_IMPLIED_LINK;
  1056. TuplePacket->Flags |= (TuplePacket->CISOffset & 7) << TPLF_ASI_SHIFT;
  1057. TuplePacket->CISOffset &= 0x0ffffff8;
  1058. TuplePacket->LinkOffset = TuplePacket->CISOffset;
  1059. }
  1060. return STATUS_SUCCESS;
  1061. }
  1062. NTSTATUS
  1063. GetFirstTuple(
  1064. IN PTUPLE_PACKET TuplePacket
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Retrieves the very first tuple off the pc-card
  1069. Arguments:
  1070. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1071. Return Value:
  1072. STATUS_SUCCESS if tuple was retrieved
  1073. STATUS_NO_MORE_ENTRIES - if no tuples were found
  1074. this is possible if this is a flash memory card
  1075. --*/
  1076. {
  1077. NTSTATUS status;
  1078. status=InitializeTuplePacket(TuplePacket);
  1079. if (!NT_SUCCESS(status)) {
  1080. return status;
  1081. }
  1082. TuplePacket->TupleCode = GetCISChar(TuplePacket, 0);
  1083. TuplePacket->TupleLink = GetCISChar(TuplePacket, 1);
  1084. if (TuplePacket->TupleCode == CISTPL_LINKTARGET) {
  1085. if ((status=FollowLink(TuplePacket)) == STATUS_NO_MORE_ENTRIES) {
  1086. return status;
  1087. }
  1088. } else if (IsCardBusCardInSocket(TuplePacket->Socket)) {
  1089. //
  1090. // First tuple on Cardbus cards must be link target
  1091. //
  1092. return STATUS_NO_MORE_ENTRIES;
  1093. }
  1094. if (!NT_SUCCESS(status) || TupleMatches(TuplePacket)) {
  1095. return status;
  1096. }
  1097. return GetNextTuple(TuplePacket);
  1098. }
  1099. BOOLEAN
  1100. TupleMatches(
  1101. PTUPLE_PACKET TuplePacket
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Checks if the retrieved tuple matches what
  1106. the caller requested
  1107. Arguments:
  1108. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1109. Return Value:
  1110. TRUE - if the tuple matches
  1111. FALSE - if not
  1112. --*/
  1113. {
  1114. if (TuplePacket->TupleCode == TuplePacket->DesiredTuple) {
  1115. return TRUE;
  1116. }
  1117. if (TuplePacket->DesiredTuple != 0xFF) {
  1118. return FALSE;
  1119. }
  1120. //
  1121. // Requested any tuple , but might not want link tuples
  1122. //
  1123. if (TuplePacket->Attributes & TPLA_RET_LINKS) {
  1124. return TRUE;
  1125. }
  1126. return ((TuplePacket->TupleCode != CISTPL_LONGLINK_CB) &&
  1127. (TuplePacket->TupleCode != CISTPL_INDIRECT) &&
  1128. (TuplePacket->TupleCode != CISTPL_LONGLINK_MFC) &&
  1129. (TuplePacket->TupleCode != CISTPL_LONGLINK_A) &&
  1130. (TuplePacket->TupleCode != CISTPL_LONGLINK_C) &&
  1131. (TuplePacket->TupleCode != CISTPL_NO_LINK) &&
  1132. (TuplePacket->TupleCode != CISTPL_LINKTARGET));
  1133. }
  1134. NTSTATUS
  1135. GetNextTuple(
  1136. IN PTUPLE_PACKET TuplePacket
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Retrieves the next unprocessed tuple that matches
  1141. the caller requested tuple code off the pc-card
  1142. Arguments:
  1143. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1144. Return Value:
  1145. STATUS_SUCCESS if tuple was retrieved
  1146. STATUS_NO_MORE_ENTRIES - if no more tuples were found
  1147. --*/
  1148. {
  1149. ULONG missCount;
  1150. NTSTATUS status;
  1151. for (missCount = 0; missCount < MAX_MISSED_TUPLES; missCount++) {
  1152. if (((status = GetAnyTuple(TuplePacket)) != STATUS_SUCCESS) ||
  1153. TupleMatches(TuplePacket)) {
  1154. break;
  1155. }
  1156. status = STATUS_NO_MORE_ENTRIES;
  1157. }
  1158. return status;
  1159. }
  1160. NTSTATUS
  1161. NextTupleInChain(
  1162. IN PTUPLE_PACKET TuplePacket
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. Retrieves the immediately next unprocessed tuple on the pc-card
  1167. Arguments:
  1168. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1169. Return Value:
  1170. status
  1171. --*/
  1172. {
  1173. NTSTATUS status;
  1174. ULONG i;
  1175. UCHAR link;
  1176. status = STATUS_SUCCESS;
  1177. switch (GetCISChar(TuplePacket, 0)) {
  1178. case CISTPL_END:{
  1179. status = STATUS_NO_MORE_ENTRIES;
  1180. break;
  1181. }
  1182. case CISTPL_NULL: {
  1183. for (i = 0; i < MAX_MISSED_TUPLES; i++) {
  1184. TuplePacket->CISOffset++;
  1185. if (GetCISChar(TuplePacket, 0) != CISTPL_NULL) {
  1186. break;
  1187. }
  1188. }
  1189. if (i >= MAX_MISSED_TUPLES) {
  1190. status = STATUS_DEVICE_NOT_READY;
  1191. }
  1192. break;
  1193. }
  1194. default: {
  1195. link = GetCISChar(TuplePacket, 1);
  1196. if (link == 0xFF) {
  1197. status = STATUS_NO_MORE_ENTRIES;
  1198. } else {
  1199. TuplePacket->CISOffset += link+2;
  1200. }
  1201. break;
  1202. }
  1203. }
  1204. return (status);
  1205. }
  1206. NTSTATUS
  1207. GetAnyTuple(
  1208. IN PTUPLE_PACKET TuplePacket
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. Retrieves the next tuple - regardless of tuple code-
  1213. off the pc-card. If the end of chain is reached on the
  1214. current tuple chain, any links are followed to obtain
  1215. the next tuple.
  1216. Arguments:
  1217. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1218. Return Value:
  1219. STATUS_SUCCESS if tuple was retrieved
  1220. STATUS_NO_MORE_ENTRIES - if no tuples were found
  1221. --*/
  1222. {
  1223. NTSTATUS status;
  1224. if (!NT_SUCCESS((status = NextTupleInChain(TuplePacket)))) {
  1225. /* End of this CIS. Follow a link if it exists */
  1226. if (status == STATUS_DEVICE_NOT_READY) {
  1227. return status;
  1228. }
  1229. if ((status = FollowLink(TuplePacket)) != STATUS_SUCCESS) {
  1230. return status;
  1231. }
  1232. }
  1233. TuplePacket->TupleCode = GetCISChar(TuplePacket, 0);
  1234. TuplePacket->TupleLink = GetCISChar(TuplePacket, 1);
  1235. return (ProcessLinkTuple(TuplePacket));
  1236. }
  1237. NTSTATUS
  1238. FollowLink(
  1239. IN PTUPLE_PACKET TuplePacket
  1240. )
  1241. /*++
  1242. Routine Description:
  1243. Called when the end of tuple chain is encountered:
  1244. this follows links, if any are present
  1245. Arguments:
  1246. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1247. Return Value:
  1248. STATUS_SUCCESS if a link is present
  1249. STATUS_NO_MORE_ENTRIES - if not
  1250. --*/
  1251. {
  1252. if (NextLink(TuplePacket) == STATUS_SUCCESS) {
  1253. return STATUS_SUCCESS;
  1254. }
  1255. // There is no implied or explicit link to follow. If an indirect link
  1256. // has been specified, indirect attribute memory is processed with an
  1257. // implied link to common memory.
  1258. if ((TuplePacket->Flags & TPLF_IND_LINK) && !(TuplePacket->Flags & TPLF_INDIRECT)) {
  1259. // Link to indirect attribute memory at offset 0.
  1260. TuplePacket->Flags &= ~(TPLF_COMMON | TPLF_IND_LINK | TPLF_LINK_MASK);
  1261. TuplePacket->Flags |= TPLF_INDIRECT;
  1262. TuplePacket->CISOffset = 0;
  1263. if (CheckLinkTarget(TuplePacket)) {
  1264. return STATUS_SUCCESS;
  1265. }
  1266. return(NextLink(TuplePacket));
  1267. }
  1268. return STATUS_NO_MORE_ENTRIES;
  1269. }
  1270. BOOLEAN
  1271. CheckLinkTarget(
  1272. IN PTUPLE_PACKET TuplePacket
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. Ensures that the target of a link has the signature
  1277. 'CIS' which indicates it is a valid target,
  1278. as documented in the PC-Card standard
  1279. Arguments:
  1280. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1281. Return Value:
  1282. STATUS_SUCCESS if valid target
  1283. STATUS_NO_MORE_ENTRIES - if not
  1284. --*/
  1285. {
  1286. return (GetCISChar(TuplePacket, 0) == CISTPL_LINKTARGET &&
  1287. GetCISChar(TuplePacket, 1) >= 3 &&
  1288. GetCISChar(TuplePacket, 2) == 'C' &&
  1289. GetCISChar(TuplePacket, 3) == 'I' &&
  1290. GetCISChar(TuplePacket, 4) == 'S');
  1291. }
  1292. NTSTATUS
  1293. NextLink(
  1294. IN PTUPLE_PACKET TuplePacket
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Fetches the next link off the pc-card tuple chain
  1299. if any are present
  1300. Arguments:
  1301. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1302. Return Value:
  1303. STATUS_SUCCESS if a link was present
  1304. STATUS_NO_MORE_ENTRIES - if no links
  1305. --*/
  1306. {
  1307. switch (TuplePacket->Flags & TPLF_LINK_MASK) {
  1308. case TPLF_IMPLIED_LINK:
  1309. case TPLF_LINK_TO_C: {
  1310. TuplePacket->Flags |= TPLF_COMMON;
  1311. TuplePacket->CISOffset = TuplePacket->LinkOffset;
  1312. break;
  1313. }
  1314. case TPLF_LINK_TO_A:{
  1315. TuplePacket->Flags &= ~TPLF_COMMON;
  1316. TuplePacket->CISOffset = TuplePacket->LinkOffset;
  1317. break;
  1318. }
  1319. case TPLF_LINK_TO_CB: {
  1320. //
  1321. // Needs work! We have to switch to the appropriate
  1322. // address space (BARs/Expansion Rom/Config space)
  1323. // depending on the link offset
  1324. //
  1325. TuplePacket->Flags &= ~TPLF_ASI;
  1326. TuplePacket->Flags |= (TuplePacket->LinkOffset & 7) << TPLF_ASI_SHIFT;
  1327. TuplePacket->CISOffset = TuplePacket->LinkOffset & ~7 ;
  1328. break;
  1329. }
  1330. case TPLF_NO_LINK:
  1331. default: {
  1332. return STATUS_NO_MORE_ENTRIES;
  1333. }
  1334. }
  1335. // Validate the link target
  1336. if (!CheckLinkTarget (TuplePacket)) {
  1337. if (TuplePacket->Flags & (TPLF_COMMON | TPLF_INDIRECT)) {
  1338. return(STATUS_NO_MORE_ENTRIES);
  1339. }
  1340. // The R2 PCMCIA spec was not clear on how the link off
  1341. // memory was defined. As a result the offset is often
  1342. // by 2 as defined in the later specs. Therefore if th
  1343. // not found at the proper offset, the offset is divide
  1344. // proper link target is checked for at that offset.
  1345. TuplePacket->CISOffset >>= 1; // Divide by 2
  1346. if (!CheckLinkTarget(TuplePacket)) {
  1347. return(STATUS_NO_MORE_ENTRIES);
  1348. }
  1349. return STATUS_NO_MORE_ENTRIES;
  1350. }
  1351. TuplePacket->Flags &= ~TPLF_LINK_MASK;
  1352. return STATUS_SUCCESS;
  1353. }
  1354. NTSTATUS
  1355. ProcessLinkTuple(
  1356. IN PTUPLE_PACKET TuplePacket
  1357. )
  1358. /*++
  1359. Routine Description:
  1360. Processes an encountered link while traversing the tuple chain
  1361. by storing it for future use - when the link has to be followed
  1362. after end of chain is encountered
  1363. Arguments:
  1364. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1365. Return Value:
  1366. STATUS_SUCCESS
  1367. --*/
  1368. {
  1369. ULONG k;
  1370. switch (TuplePacket->TupleCode) {
  1371. case CISTPL_LONGLINK_CB: {
  1372. // needs to be filled in
  1373. if (TuplePacket->TupleLink < 4) {
  1374. return (STATUS_NO_MORE_ENTRIES);
  1375. }
  1376. TuplePacket->Flags = (TuplePacket->Flags & ~TPLF_LINK_MASK) | TPLF_LINK_TO_CB;
  1377. TuplePacket->LinkOffset = GetCISChar(TuplePacket, TPLL_ADDR) +
  1378. (GetCISChar(TuplePacket, TPLL_ADDR + 1)<<8) +
  1379. (GetCISChar(TuplePacket, TPLL_ADDR + 2)<<16) +
  1380. (GetCISChar(TuplePacket, TPLL_ADDR + 3)<<24);
  1381. break;
  1382. }
  1383. case CISTPL_INDIRECT: {
  1384. TuplePacket->Flags |= TPLF_IND_LINK;
  1385. TuplePacket->LinkOffset = 0; // Don't set link offset for indirect
  1386. SetPdoFlag(TuplePacket->SocketData->PdoExtension, PCMCIA_PDO_INDIRECT_CIS);
  1387. break;
  1388. }
  1389. case CISTPL_LONGLINK_A:
  1390. case CISTPL_LONGLINK_C: {
  1391. if (TuplePacket->TupleLink < 4) {
  1392. return STATUS_NO_MORE_ENTRIES;
  1393. }
  1394. TuplePacket->Flags = ((TuplePacket->Flags & ~TPLF_LINK_MASK) |
  1395. (TuplePacket->TupleCode == CISTPL_LONGLINK_A ?
  1396. TPLF_LINK_TO_A: TPLF_LINK_TO_C));
  1397. TuplePacket->LinkOffset = GetCISChar(TuplePacket, TPLL_ADDR) +
  1398. (GetCISChar(TuplePacket, TPLL_ADDR+1) << 8) +
  1399. (GetCISChar(TuplePacket, TPLL_ADDR+2) << 16) +
  1400. (GetCISChar(TuplePacket, TPLL_ADDR+3) << 24) ;
  1401. break;
  1402. }
  1403. case CISTPL_LONGLINK_MFC:{
  1404. k = TPLMFC_NUM;
  1405. TuplePacket->Socket->NumberOfFunctions = GetCISChar(TuplePacket, TPLMFC_NUM);
  1406. if ((TuplePacket->TupleLink < (TuplePacket->Function*5 + 6)) ||
  1407. (GetCISChar(TuplePacket, k) <= TuplePacket->Function)) {
  1408. return STATUS_NO_MORE_ENTRIES;
  1409. }
  1410. k += TuplePacket->Function*5 + 1;
  1411. TuplePacket->Flags = (TuplePacket->Flags & ~TPLF_LINK_MASK) |
  1412. (GetCISChar(TuplePacket, k) == 0?TPLF_LINK_TO_A:
  1413. TPLF_LINK_TO_C);
  1414. k++;
  1415. TuplePacket->LinkOffset = GetCISChar(TuplePacket, k) +
  1416. (GetCISChar(TuplePacket, k+1) << 8) +
  1417. (GetCISChar(TuplePacket, k+2) << 16) +
  1418. (GetCISChar(TuplePacket, k+3) << 24);
  1419. break;
  1420. }
  1421. case CISTPL_NO_LINK:{
  1422. TuplePacket->Flags = (TuplePacket->Flags & ~TPLF_LINK_MASK) | TPLF_NO_LINK;
  1423. break;
  1424. }
  1425. }
  1426. return STATUS_SUCCESS;
  1427. }
  1428. NTSTATUS
  1429. GetTupleData(
  1430. IN PTUPLE_PACKET TuplePacket
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Retrieves the tuple body for the currently requested
  1435. tuple.
  1436. NOTE: This function assumes that the caller provided
  1437. a big enough buffer in the TuplePacket to hold the tuple
  1438. data. No attempt is made to trap exceptions etc.
  1439. Arguments:
  1440. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1441. Return Value:
  1442. STATUS_SUCCESS if tuple data was retrieved
  1443. STATUS_NO_MORE_ENTRIES - otherwise
  1444. --*/
  1445. {
  1446. PUCHAR bufferPointer;
  1447. USHORT xferLength;
  1448. USHORT tupleOffset;
  1449. TuplePacket->TupleDataIndex = 0;
  1450. xferLength = TuplePacket->TupleDataLength = GetCISChar(TuplePacket, 1);
  1451. if ((tupleOffset = TuplePacket->TupleOffset) > xferLength) {
  1452. return STATUS_NO_MORE_ENTRIES;
  1453. }
  1454. xferLength = MIN((xferLength - tupleOffset), TuplePacket->TupleDataMaxLength);
  1455. for (bufferPointer = TuplePacket->TupleData; xferLength;
  1456. tupleOffset++, bufferPointer++, xferLength--) {
  1457. *bufferPointer = GetCISChar(TuplePacket, tupleOffset + 2);
  1458. }
  1459. return STATUS_SUCCESS;
  1460. }
  1461. UCHAR
  1462. GetTupleChar(
  1463. IN PTUPLE_PACKET TuplePacket
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. Returns the next byte in the current set of tuple data.
  1468. Arguments:
  1469. TuplePacket - Pointer the caller supplied, initialized tuple packet
  1470. Return Value:
  1471. tuple data byte
  1472. --*/
  1473. {
  1474. UCHAR tupleChar = 0;
  1475. if (TuplePacket->TupleDataIndex < TuplePacket->TupleDataMaxLength) {
  1476. tupleChar = TuplePacket->TupleData[TuplePacket->TupleDataIndex++];
  1477. }
  1478. return tupleChar;
  1479. }
  1480. /*------------- End of Tuple API -----------------------*/
  1481. USHORT
  1482. GetCRC(
  1483. IN PSOCKET_DATA SocketData
  1484. )
  1485. /*++
  1486. Routine Description:
  1487. Using the same algorithm as Windows 95, calculate the CRC value
  1488. to be appended with the manufacturer name and device name to
  1489. obtain the unique identifier for the PCCARD.
  1490. Arguments:
  1491. Socket - Pointer to the socket which contains the device
  1492. Function - function number of device
  1493. Return Value:
  1494. A USHORT CRC value.
  1495. --*/
  1496. {
  1497. PSOCKET Socket = SocketData->Socket;
  1498. TUPLE_PACKET tuplePacket;
  1499. PUCHAR tupleData;
  1500. PUCHAR cp;
  1501. PUCHAR cpEnd;
  1502. PUCHAR tplBuffer;
  1503. NTSTATUS status;
  1504. USHORT crc = 0;
  1505. USHORT index;
  1506. USHORT length;
  1507. UCHAR tupleCode;
  1508. UCHAR tmp;
  1509. RtlZeroMemory(&tuplePacket, sizeof(TUPLE_PACKET));
  1510. tuplePacket.DesiredTuple = 0xFF;
  1511. tuplePacket.TupleData = ExAllocatePool(NonPagedPool, MAX_TUPLE_DATA_LENGTH);
  1512. if (tuplePacket.TupleData == NULL) {
  1513. return 0;
  1514. }
  1515. tuplePacket.Socket = Socket;
  1516. tuplePacket.SocketData = SocketData;
  1517. tuplePacket.TupleDataMaxLength = MAX_TUPLE_DATA_LENGTH;
  1518. tuplePacket.TupleOffset = 0;
  1519. tuplePacket.Function = SocketData->Function;
  1520. try{
  1521. status = GetFirstTuple(&tuplePacket);
  1522. //
  1523. // Calculate CRC
  1524. //
  1525. while (NT_SUCCESS(status)) {
  1526. tupleCode = tuplePacket.TupleCode;
  1527. for (index = 0; TplList[index] != CISTPL_END; index++) {
  1528. if (tupleCode == TplList[index]) {
  1529. status = GetTupleData(&tuplePacket);
  1530. if (!NT_SUCCESS(status)) {
  1531. //
  1532. // Bail...
  1533. //
  1534. crc = 0;
  1535. leave;
  1536. };
  1537. tupleData = tuplePacket.TupleData;
  1538. length = tuplePacket.TupleDataLength;
  1539. //
  1540. // This one is included in the CRC calculation
  1541. //
  1542. if (tupleCode == CISTPL_VERS_1) {
  1543. cp = tupleData + 2;
  1544. cpEnd = tupleData + MAX_TUPLE_DATA_LENGTH;
  1545. //
  1546. // Include all of the manufacturer name.
  1547. //
  1548. while ((cp < cpEnd) && *cp) {
  1549. cp++;
  1550. }
  1551. //
  1552. // Include the product string
  1553. //
  1554. cp++;
  1555. while ((cp < cpEnd) && *cp) {
  1556. cp++;
  1557. }
  1558. cp++;
  1559. length = (USHORT)(cp - tupleData);
  1560. }
  1561. if (length >= MAX_TUPLE_DATA_LENGTH) {
  1562. crc = 0;
  1563. leave;
  1564. }
  1565. for (cp = tupleData; length; length--, cp++) {
  1566. tmp = *cp ^ (UCHAR)crc;
  1567. crc = (crc >> 8) ^ crc16a[tmp & 0x0f] ^ crc16b[tmp >> 4];
  1568. }
  1569. break;
  1570. }
  1571. }
  1572. status = GetNextTuple(&tuplePacket);
  1573. }
  1574. } finally {
  1575. if (tuplePacket.TupleData) {
  1576. ExFreePool(tuplePacket.TupleData);
  1577. }
  1578. }
  1579. DebugPrint((PCMCIA_DEBUG_TUPLES, "Checksum=%x\n", crc));
  1580. return crc;
  1581. }
  1582. NTSTATUS
  1583. PcmciaParseFunctionData(
  1584. IN PSOCKET Socket,
  1585. IN PSOCKET_DATA SocketData
  1586. )
  1587. /*++
  1588. Routine Description
  1589. Parses the tuple data for the supplied function
  1590. (SocketPtr->Function)
  1591. Arguments:
  1592. Socket - Pointer to the socket which contains the device
  1593. SocketData - Pointer to the socket data structure for the function
  1594. which will be filled with the parsed information
  1595. Return Value:
  1596. Status
  1597. --*/
  1598. {
  1599. PCONFIG_ENTRY configEntry, prevEntry = NULL;
  1600. TUPLE_PACKET tuplePacket;
  1601. NTSTATUS status;
  1602. if (SocketData->Function >= Socket->NumberOfFunctions) {
  1603. return STATUS_NO_MORE_ENTRIES;
  1604. }
  1605. if (Is16BitCardInSocket(Socket)) {
  1606. //
  1607. // Get the CIS checksum
  1608. //
  1609. SocketData->CisCrc = GetCRC(SocketData);
  1610. }
  1611. RtlZeroMemory(&tuplePacket, sizeof(TUPLE_PACKET));
  1612. tuplePacket.DesiredTuple = 0xFF;
  1613. tuplePacket.TupleData = ExAllocatePool(PagedPool, MAX_TUPLE_DATA_LENGTH);
  1614. if (tuplePacket.TupleData == NULL) {
  1615. return STATUS_INSUFFICIENT_RESOURCES;
  1616. }
  1617. tuplePacket.Socket = Socket;
  1618. tuplePacket.SocketData = SocketData;
  1619. tuplePacket.TupleDataMaxLength = MAX_TUPLE_DATA_LENGTH;
  1620. tuplePacket.TupleOffset = 0;
  1621. tuplePacket.Function = SocketData->Function;
  1622. status = GetFirstTuple(&tuplePacket);
  1623. if (!NT_SUCCESS(status) || (tuplePacket.TupleCode == CISTPL_END)) {
  1624. if (IsCardBusCardInSocket(Socket)) {
  1625. //
  1626. // Couldn't get CIS of cardbus card, no big deal
  1627. //
  1628. status = STATUS_SUCCESS;
  1629. } else if (status != STATUS_DEVICE_NOT_READY) {
  1630. //
  1631. // No CIS, munge it to look like a memory card
  1632. //
  1633. status = PcmciaMemoryCardHack(Socket, SocketData);
  1634. }
  1635. if (tuplePacket.TupleData) {
  1636. ExFreePool(tuplePacket.TupleData);
  1637. }
  1638. return status;
  1639. }
  1640. while (NT_SUCCESS(status)) {
  1641. status = GetTupleData(&tuplePacket);
  1642. ASSERT (NT_SUCCESS(status));
  1643. DebugPrint((PCMCIA_DEBUG_TUPLES, "%04x TUPLE %02x %s\n", tuplePacket.CISOffset,
  1644. tuplePacket.TupleCode, TUPLE_STRING(tuplePacket.TupleCode)));
  1645. switch (tuplePacket.TupleCode) {
  1646. case CISTPL_VERS_1: {
  1647. ULONG byteCount;
  1648. PUCHAR pStart, pCurrent;
  1649. //
  1650. // Extract manufacturer name and card name.
  1651. //
  1652. pStart = pCurrent = tuplePacket.TupleData+2; // To string fields
  1653. byteCount = 0;
  1654. while ((*pCurrent != '\0') && (*pCurrent != (UCHAR)0xff)) {
  1655. if ((byteCount >= MAX_MANFID_LENGTH-1) || (byteCount >= MAX_TUPLE_DATA_LENGTH)) {
  1656. status = STATUS_DEVICE_NOT_READY;
  1657. break;
  1658. }
  1659. byteCount++;
  1660. pCurrent++;
  1661. }
  1662. if (!NT_SUCCESS(status)) {
  1663. break;
  1664. }
  1665. RtlCopyMemory((PUCHAR)SocketData->Mfg, pStart, byteCount);
  1666. //
  1667. // Null terminate
  1668. SocketData->Mfg[byteCount] = '\0';
  1669. DebugPrint((PCMCIA_DEBUG_TUPLES, "Manufacturer: %s\n", SocketData->Mfg));
  1670. PcmciaSubstituteUnderscore(SocketData->Mfg);
  1671. pCurrent++;
  1672. pStart = pCurrent;
  1673. byteCount = 0;
  1674. while ((*pCurrent != '\0') && (*pCurrent != (UCHAR)0xff)) {
  1675. if ((byteCount >= MAX_IDENT_LENGTH-1) || (byteCount >= MAX_TUPLE_DATA_LENGTH)) {
  1676. status = STATUS_DEVICE_NOT_READY;
  1677. break;
  1678. }
  1679. byteCount++;
  1680. pCurrent++;
  1681. }
  1682. if (!NT_SUCCESS(status)) {
  1683. break;
  1684. }
  1685. RtlCopyMemory((PUCHAR)SocketData->Ident, pStart, byteCount);
  1686. //
  1687. // Null terminate
  1688. SocketData->Ident[byteCount] = '\0';
  1689. DebugPrint((PCMCIA_DEBUG_TUPLES, "Identifier: %s\n", SocketData->Ident));
  1690. PcmciaSubstituteUnderscore(SocketData->Ident);
  1691. break;
  1692. }
  1693. //
  1694. // get the device configuration base
  1695. //
  1696. case CISTPL_CONFIG: {
  1697. ProcessConfig(&tuplePacket);
  1698. break;
  1699. }
  1700. case CISTPL_CONFIG_CB: {
  1701. ProcessConfigCB(&tuplePacket);
  1702. break;
  1703. }
  1704. case CISTPL_CFTABLE_ENTRY_CB:
  1705. case CISTPL_CFTABLE_ENTRY: {
  1706. //
  1707. // construct a possible configuration entry for this device
  1708. //
  1709. configEntry = PcmciaProcessConfigTable(&tuplePacket);
  1710. if (configEntry) {
  1711. //
  1712. // Link configurations at the end of the list.
  1713. //
  1714. configEntry->NextEntry = NULL;
  1715. if (prevEntry) {
  1716. prevEntry->NextEntry = configEntry;
  1717. } else {
  1718. SocketData->ConfigEntryChain = configEntry;
  1719. }
  1720. prevEntry = configEntry;
  1721. }
  1722. break;
  1723. }
  1724. case CISTPL_FUNCID: {
  1725. // Mark device type..
  1726. SocketData->DeviceType = * (tuplePacket.TupleData);
  1727. DebugPrint((PCMCIA_DEBUG_TUPLES, "DeviceType: %x\n", SocketData->DeviceType));
  1728. break;
  1729. }
  1730. case CISTPL_MANFID: {
  1731. //
  1732. PUCHAR localBufferPointer = tuplePacket.TupleData;
  1733. SocketData->ManufacturerCode = *(localBufferPointer+1) << 8 | *localBufferPointer;
  1734. SocketData->ManufacturerInfo = *(localBufferPointer+3)<<8 | *(localBufferPointer+2);
  1735. DebugPrint((PCMCIA_DEBUG_TUPLES, "Code: %x, Info: %x\n", SocketData->ManufacturerCode,
  1736. SocketData->ManufacturerInfo));
  1737. break;
  1738. }
  1739. } // end switch on Tuple code
  1740. //
  1741. // Skip to the next tuple
  1742. //
  1743. status = GetNextTuple(&tuplePacket);
  1744. }
  1745. if (tuplePacket.TupleData) {
  1746. ExFreePool(tuplePacket.TupleData);
  1747. }
  1748. if (status == STATUS_DEVICE_NOT_READY) {
  1749. return status;
  1750. }
  1751. //
  1752. // Serial/modem/ATA devices recognized and appropriate
  1753. // fixes for tuples applied here
  1754. //
  1755. PcmciaCheckForRecognizedDevice(Socket,SocketData);
  1756. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x ParseFunctionData: Final PcCard type %x\n",
  1757. Socket, SocketData->DeviceType));
  1758. return STATUS_SUCCESS;
  1759. }
  1760. NTSTATUS
  1761. PcmciaParseFunctionDataForID(
  1762. IN PSOCKET_DATA SocketData
  1763. )
  1764. /*++
  1765. Routine Description
  1766. Parses the tuple data for the supplied function
  1767. (SocketPtr->Function)
  1768. Arguments:
  1769. Socket - Pointer to the socket which contains the device
  1770. SocketData - Pointer to the socket data structure for the function
  1771. which will be filled with the parsed information
  1772. Return Value:
  1773. Status
  1774. --*/
  1775. {
  1776. PSOCKET Socket = SocketData->Socket;
  1777. TUPLE_PACKET tuplePacket;
  1778. PUCHAR localBufferPointer;
  1779. NTSTATUS status;
  1780. USHORT ManufacturerCode = 0;
  1781. USHORT ManufacturerInfo = 0;
  1782. USHORT CisCrc;
  1783. DebugPrint((PCMCIA_DEBUG_TUPLES, "Parsing function %d for ID...\n", SocketData->Function));
  1784. RtlZeroMemory(&tuplePacket, sizeof(TUPLE_PACKET));
  1785. tuplePacket.DesiredTuple = 0xFF;
  1786. tuplePacket.TupleData = ExAllocatePool(NonPagedPool, MAX_TUPLE_DATA_LENGTH);
  1787. if (tuplePacket.TupleData == NULL) {
  1788. return STATUS_INSUFFICIENT_RESOURCES;
  1789. }
  1790. tuplePacket.Socket = Socket;
  1791. tuplePacket.SocketData = SocketData;
  1792. tuplePacket.TupleDataMaxLength = MAX_TUPLE_DATA_LENGTH;
  1793. tuplePacket.TupleOffset = 0;
  1794. tuplePacket.Function = SocketData->Function;
  1795. status = GetFirstTuple(&tuplePacket);
  1796. if (!NT_SUCCESS(status) ||
  1797. (tuplePacket.TupleCode == CISTPL_END)) {
  1798. if (status != STATUS_DEVICE_NOT_READY) {
  1799. if (IsSocketFlagSet(Socket, SOCKET_CARD_MEMORY)) {
  1800. status = STATUS_SUCCESS;
  1801. }
  1802. status = STATUS_NO_MORE_ENTRIES;
  1803. }
  1804. if (tuplePacket.TupleData) {
  1805. ExFreePool(tuplePacket.TupleData);
  1806. }
  1807. return status;
  1808. }
  1809. while (NT_SUCCESS(status)) {
  1810. status = GetTupleData(&tuplePacket);
  1811. ASSERT (NT_SUCCESS(status));
  1812. switch (tuplePacket.TupleCode) {
  1813. case CISTPL_MANFID: {
  1814. localBufferPointer = tuplePacket.TupleData;
  1815. ManufacturerCode = *(localBufferPointer+1) << 8 | *localBufferPointer;
  1816. ManufacturerInfo = *(localBufferPointer+3)<<8 | *(localBufferPointer+2);
  1817. break;
  1818. }
  1819. } // end switch on Tuple code
  1820. //
  1821. // Skip to the next tuple
  1822. //
  1823. status = GetNextTuple(&tuplePacket);
  1824. }
  1825. if (tuplePacket.TupleData) {
  1826. ExFreePool(tuplePacket.TupleData);
  1827. }
  1828. if (SocketData->ManufacturerCode != ManufacturerCode) {
  1829. DebugPrint((PCMCIA_DEBUG_TUPLES, "Verify failed on Manf. Code: %x %x\n", SocketData->ManufacturerCode, ManufacturerCode));
  1830. return STATUS_UNSUCCESSFUL;
  1831. }
  1832. if (SocketData->ManufacturerInfo != ManufacturerInfo) {
  1833. DebugPrint((PCMCIA_DEBUG_TUPLES, "Verify failed on Manf. Info: %x %x\n", SocketData->ManufacturerInfo, ManufacturerInfo));
  1834. return STATUS_UNSUCCESSFUL;
  1835. }
  1836. //
  1837. // Get the CIS checksum
  1838. //
  1839. CisCrc = GetCRC(SocketData);
  1840. if (SocketData->CisCrc != CisCrc) {
  1841. DebugPrint((PCMCIA_DEBUG_TUPLES, "Verify failed on CRC: %x %x\n", SocketData->CisCrc, CisCrc));
  1842. return STATUS_UNSUCCESSFUL;
  1843. }
  1844. DebugPrint((PCMCIA_DEBUG_INFO, "skt %08x R2 CardId verified %x-%x-%x\n", Socket,
  1845. ManufacturerCode,
  1846. ManufacturerInfo,
  1847. CisCrc
  1848. ));
  1849. return STATUS_SUCCESS;
  1850. }
  1851. VOID
  1852. PcmciaCheckForRecognizedDevice(
  1853. IN PSOCKET Socket,
  1854. IN OUT PSOCKET_DATA SocketData
  1855. )
  1856. /*++
  1857. Routine Description:
  1858. Look at the configuration options on the PCCARD to determine if
  1859. it is a serial port / modem / ATA device card.
  1860. Arguments:
  1861. Socket - Pointer to the socket which contains the device
  1862. SocketData - the configuration information on the current PCCARD.
  1863. Return Value:
  1864. None - Modifications are made to the socket data structure.
  1865. --*/
  1866. {
  1867. ULONG modemPorts[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8};
  1868. ULONG ataPorts0[2] = { 0x1f0, 0x170};
  1869. BOOLEAN found = FALSE;
  1870. UCHAR dataByte;
  1871. UCHAR link;
  1872. ULONG index;
  1873. PUCHAR localBufferPointer;
  1874. TUPLE_PACKET tuplePacket;
  1875. PUCHAR tupleData;
  1876. PCONFIG_ENTRY configEntry;
  1877. NTSTATUS status;
  1878. //
  1879. // This piece of code searches the config data for I/O ranges that start at
  1880. // some known industry standard, and updates the devicetype accordingly.
  1881. //
  1882. // This is such an ugly hack, I'm really skeptical that we should be doing
  1883. // this anymore. I assume there must have been some broken hardware that needed
  1884. // it, but that information is now lost. At some point, this whole for loop
  1885. // should just be removed.
  1886. //
  1887. for (configEntry = SocketData->ConfigEntryChain; configEntry; configEntry = configEntry->NextEntry) {
  1888. for (index = 0; index < 4; index++) {
  1889. if (modemPorts[index] == configEntry->IoPortBase[0]) {
  1890. SocketData->DeviceType = PCCARD_TYPE_SERIAL;
  1891. found = TRUE;
  1892. break;
  1893. }
  1894. if (index < 2) {
  1895. if (ataPorts0[index] == configEntry->IoPortBase[0]) {
  1896. if (configEntry->IoPortBase[1] == 0x376 ||
  1897. configEntry->IoPortBase[1] == 0x3f6 ) {
  1898. SocketData->DeviceType = PCCARD_TYPE_ATA;
  1899. found = TRUE;
  1900. break;
  1901. }
  1902. }
  1903. }
  1904. }
  1905. }
  1906. switch(SocketData->DeviceType) {
  1907. case PCCARD_TYPE_ATA:
  1908. //
  1909. // More smudges follow here for ATA cards to rub out buggy tuples
  1910. //
  1911. // Search for configurations which are not viable for ATA devices
  1912. // and mark them invalid so they would not be reported to the I/O subsystem.
  1913. // Also fix buggy tuples on ATA cards
  1914. for (configEntry = SocketData->ConfigEntryChain;
  1915. configEntry != NULL; configEntry = configEntry->NextEntry) {
  1916. //
  1917. // Adjust the IO resource requirement: ATA cards
  1918. // typically have an incorrect length here
  1919. // (+1)
  1920. //
  1921. if (configEntry->IoPortLength[1] > 0) {
  1922. configEntry->IoPortLength[1]=0;
  1923. }
  1924. //
  1925. // This next hack is to work around a problem with Viking SmartCard adapters.
  1926. // This adapter doesn't like I/O ranges that are based at 0x70 or 0xf0,
  1927. // so we bump up the alignment to 0x20 on unrestricted I/O ranges.
  1928. //
  1929. if ((SocketData->ManufacturerCode == 0x1df) && (configEntry->NumberOfIoPortRanges == 1) &&
  1930. (configEntry->IoPortBase[0] == 0) && (configEntry->IoPortLength[0] == 0xf) &&
  1931. (configEntry->IoPortAlignment[0] == 0x10)) {
  1932. // alter alignment
  1933. configEntry->IoPortAlignment[0] = 0x20;
  1934. }
  1935. if (configEntry->NumberOfMemoryRanges) {
  1936. //
  1937. // Don't use this configuration
  1938. //
  1939. configEntry->Flags |= PCMCIA_INVALID_CONFIGURATION;
  1940. }
  1941. }
  1942. break;
  1943. case PCCARD_TYPE_PARALLEL:
  1944. // Search for configurations which are not viable for Parallel devices
  1945. for (configEntry = SocketData->ConfigEntryChain;
  1946. configEntry != NULL; configEntry = configEntry->NextEntry) {
  1947. if (configEntry->NumberOfMemoryRanges) {
  1948. //
  1949. // Don't use this configuration
  1950. //
  1951. configEntry->Flags |= PCMCIA_INVALID_CONFIGURATION;
  1952. }
  1953. }
  1954. break;
  1955. case PCCARD_TYPE_SERIAL: {
  1956. //
  1957. // If card type is serial , check if it's actually a modem...
  1958. //
  1959. UCHAR tupleDataBuffer[MAX_TUPLE_DATA_LENGTH];
  1960. PUCHAR str, pChar;
  1961. RtlZeroMemory(&tuplePacket, sizeof(TUPLE_PACKET));
  1962. tuplePacket.DesiredTuple = CISTPL_FUNCE;
  1963. tuplePacket.TupleData = tupleDataBuffer;
  1964. tuplePacket.Socket = Socket;
  1965. tuplePacket.SocketData = SocketData;
  1966. tuplePacket.TupleDataMaxLength = MAX_TUPLE_DATA_LENGTH;
  1967. tuplePacket.TupleOffset = 0;
  1968. tuplePacket.Function = SocketData->Function;
  1969. status = GetFirstTuple(&tuplePacket);
  1970. while (NT_SUCCESS(status)) {
  1971. status = GetTupleData(&tuplePacket);
  1972. if (!NT_SUCCESS(status) || (tuplePacket.TupleDataLength == 0)) {
  1973. // something bad happened
  1974. break;
  1975. }
  1976. if (tuplePacket.TupleData[0] >=1 &&
  1977. tuplePacket.TupleData[0] <=3) {
  1978. SocketData->DeviceType = PCCARD_TYPE_MODEM;
  1979. return;
  1980. }
  1981. status = GetNextTuple(&tuplePacket);
  1982. }
  1983. if (status == STATUS_DEVICE_NOT_READY) {
  1984. return;
  1985. }
  1986. tuplePacket.DesiredTuple = CISTPL_VERS_1;
  1987. status = GetFirstTuple(&tuplePacket);
  1988. if (!NT_SUCCESS(status)) {
  1989. return;
  1990. }
  1991. status = GetTupleData(&tuplePacket);
  1992. if (!NT_SUCCESS(status) || (tuplePacket.TupleDataLength < 3)) {
  1993. // something bad happened
  1994. return;
  1995. }
  1996. str = tuplePacket.TupleData+2;
  1997. for (;;) {
  1998. if ( *str == 0xFF ) {
  1999. //
  2000. // End of strings
  2001. //
  2002. break;
  2003. }
  2004. //
  2005. // Convert to upper case
  2006. //
  2007. for (pChar = str; *pChar ; pChar++) {
  2008. *pChar = (UCHAR)toupper(*pChar);
  2009. }
  2010. if (strstr(str, "MODEM") ||
  2011. strstr(str, "FAX")) {
  2012. SocketData->DeviceType = PCCARD_TYPE_MODEM;
  2013. break;
  2014. }
  2015. //
  2016. // Move onto next string..
  2017. //
  2018. str = str + strlen(str)+1;
  2019. //
  2020. // Just in case...
  2021. //
  2022. if (str >= (tuplePacket.TupleData + tuplePacket.TupleDataLength)) {
  2023. break;
  2024. }
  2025. }
  2026. break;
  2027. }
  2028. }
  2029. // Search for configurations which are not viable - because
  2030. // the resources requested are not supported by the controller
  2031. // or the OS - and mark them invalid so they would not be requested
  2032. for (configEntry = SocketData->ConfigEntryChain;
  2033. configEntry != NULL; configEntry = configEntry->NextEntry) {
  2034. if ((configEntry->IrqMask == 0) &&
  2035. (configEntry->NumberOfIoPortRanges == 0) &&
  2036. (configEntry->NumberOfMemoryRanges == 0)) {
  2037. //
  2038. // This configuration doesn't need any resources!!
  2039. // Obviously bogus. (IBM Etherjet-3FE2 has one of these)
  2040. //
  2041. configEntry->Flags |= PCMCIA_INVALID_CONFIGURATION;
  2042. }
  2043. }
  2044. }
  2045. BOOLEAN
  2046. PcmciaQuickVerifyTupleChain(
  2047. IN PUCHAR Buffer,
  2048. IN ULONG Length
  2049. )
  2050. /*++
  2051. Routine description:
  2052. This routine is provided as a quick low-level check of the attribute
  2053. data in the passed buffer. The tuples aren't interpreted in context,
  2054. rather the tuple links are followed to see if the chain isn't total
  2055. garbage.
  2056. Note that none of the normal tuple handling functions are called, this
  2057. is to avoid recursion, since this may be called from within normal
  2058. tuple processing.
  2059. Arguments:
  2060. Buffer, Length - defines the buffer that contains attribute data
  2061. Return Value:
  2062. TRUE if the data in this buffer looks like a reasonable tuple chain,
  2063. FALSE otherwise
  2064. --*/
  2065. {
  2066. ULONG TupleCount = 0;
  2067. UCHAR code, link;
  2068. ULONG Offset = 0;
  2069. BOOLEAN retval = TRUE;
  2070. if (Length < 2) {
  2071. return FALSE;
  2072. }
  2073. code = *(PUCHAR)((ULONG_PTR)(Buffer));
  2074. link = *(PUCHAR)((ULONG_PTR)(Buffer)+1);
  2075. while(code != CISTPL_END) {
  2076. if (link == 0xff) {
  2077. break;
  2078. }
  2079. if (code == CISTPL_NULL) {
  2080. Offset += 1;
  2081. } else if (code == CISTPL_NO_LINK) {
  2082. Offset += 2;
  2083. } else {
  2084. Offset += (ULONG)link+2;
  2085. }
  2086. if (Offset >= (Length-1)) {
  2087. retval = FALSE;
  2088. break;
  2089. }
  2090. TupleCount++;
  2091. code = *(PUCHAR)((ULONG_PTR)(Buffer)+Offset);
  2092. link = *(PUCHAR)((ULONG_PTR)(Buffer)+Offset+1);
  2093. }
  2094. if (!TupleCount) {
  2095. retval = FALSE;
  2096. }
  2097. return retval;
  2098. }
  2099. NTSTATUS
  2100. PcmciaMemoryCardHack(
  2101. IN PSOCKET Socket,
  2102. IN PSOCKET_DATA SocketData
  2103. )
  2104. /*++
  2105. Routine Description:
  2106. This routine is called whenever we do not find a CIS of the card.
  2107. We probe the card to determine if it is sram or not.
  2108. Arguments
  2109. SocketPtr - Point to the socket in which this card was found
  2110. SocketData - Pointer to a pointer to the data structure which normally contains
  2111. parsed tuple data. This will be filled in by this routine
  2112. Return Value
  2113. STATUS_SUCCESS
  2114. --*/
  2115. {
  2116. #define JEDEC_SRAM 0x0000 // JEDEC ID for SRAM cards
  2117. #define JEDEC_ROM 0x0002 // JEDEC ID for ROM cards
  2118. #define READ_ID_CMD 0x9090
  2119. PPDO_EXTENSION pdoExtension = SocketData->PdoExtension;
  2120. USHORT OrigValue;
  2121. USHORT ChkValue;
  2122. USHORT ReadIdCmd = READ_ID_CMD;
  2123. PAGED_CODE();
  2124. SetSocketFlag(Socket, SOCKET_CARD_MEMORY);
  2125. SocketData->DeviceType = PCCARD_TYPE_MEMORY;
  2126. SocketData->Flags = SDF_JEDEC_ID;
  2127. SocketData->JedecId = JEDEC_ROM;
  2128. //
  2129. // Like win9x, we probe the card's common memory with a write to offset zero to see if
  2130. // it looks like sram
  2131. //
  2132. if (((*(Socket->SocketFnPtr->PCBReadCardMemory)) (pdoExtension, PCCARD_COMMON_MEMORY, 0, (PUCHAR)&OrigValue, 2) == 2) &&
  2133. ((*(Socket->SocketFnPtr->PCBWriteCardMemory))(pdoExtension, PCCARD_COMMON_MEMORY, 0, (PUCHAR)&ReadIdCmd, 2) == 2) &&
  2134. ((*(Socket->SocketFnPtr->PCBReadCardMemory)) (pdoExtension, PCCARD_COMMON_MEMORY, 0, (PUCHAR)&ChkValue, 2) == 2) &&
  2135. ((*(Socket->SocketFnPtr->PCBWriteCardMemory))(pdoExtension, PCCARD_COMMON_MEMORY, 0, (PUCHAR)&OrigValue, 2) == 2)) {
  2136. if (ChkValue == ReadIdCmd) {
  2137. SocketData->JedecId = JEDEC_SRAM;
  2138. }
  2139. }
  2140. if (pcmciaReportMTD0002AsError && (SocketData->JedecId == JEDEC_ROM)) {
  2141. return STATUS_DEVICE_NOT_READY;
  2142. }
  2143. return STATUS_SUCCESS;
  2144. }