Leaked source code of windows server 2003
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.

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