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.

874 lines
19 KiB

  1. /*++
  2. Copyright (c) 1998 Gemplus Development
  3. Name:
  4. gprelcmd.c
  5. Description:
  6. This module holds the functions used for the PC Card I/O.
  7. Environment:
  8. Kernel Mode
  9. Revision History:
  10. 06/04/99: (Y. Nadeau + M. Veillette)
  11. - Code Review
  12. 24/03/99: V1.00.004 (Y. Nadeau)
  13. - Fix to GprllWait to work in DPC
  14. 06/05/98: V1.00.003 (P. Plouidy)
  15. - Power management for NT5
  16. 10/02/98: V1.00.002 (P. Plouidy)
  17. - Plug and Play for NT5
  18. 03/07/97: V1.00.001 (P. Plouidy)
  19. - Start of development.
  20. --*/
  21. //
  22. // Include section:
  23. // - stdio.h: standards definitons.
  24. // - ntddk.h: DDK Windows NT general definitons.
  25. // - ntdef.h: Windows NT general definitons.
  26. //
  27. #include <stdio.h>
  28. #include <ntddk.h>
  29. #include <ntdef.h>
  30. #include "gprelcmd.h"
  31. //
  32. // Function definition section:
  33. //
  34. #if DBG
  35. void GPR_Debug_Buffer(
  36. PUCHAR pBuffer,
  37. DWORD Lenght)
  38. {
  39. USHORT index;
  40. SmartcardDebug(
  41. DEBUG_TRACE,
  42. (" LEN=%d CMD=",
  43. Lenght)
  44. );
  45. for(index=0;index<Lenght;index++)
  46. {
  47. SmartcardDebug(
  48. DEBUG_TRACE,
  49. ("%02X,",
  50. pBuffer[index])
  51. );
  52. }
  53. SmartcardDebug(
  54. DEBUG_TRACE,
  55. ("\n")
  56. );
  57. }
  58. #endif
  59. NTSTATUS GDDK_Translate(
  60. const BYTE IFDStatus,
  61. const UCHAR Tag
  62. )
  63. /*++
  64. Routine Description:
  65. Translate IFD status in NT status codes.
  66. Arguments:
  67. IFDStatus - is the value to translate.
  68. IoctlType - is the current smart card ioctl.
  69. Return Value:
  70. the translated code status.
  71. --*/
  72. {
  73. switch (IFDStatus)
  74. {
  75. case 0x00 : return STATUS_SUCCESS;
  76. case 0x01 : return STATUS_NO_SUCH_DEVICE;
  77. case 0x02 : return STATUS_NO_SUCH_DEVICE;
  78. case 0x03 : return STATUS_INVALID_PARAMETER;
  79. case 0x04 : return STATUS_IO_TIMEOUT;
  80. case 0x05 : return STATUS_INVALID_PARAMETER;
  81. case 0x09 : return STATUS_INVALID_PARAMETER;
  82. case 0x0C : return STATUS_DEVICE_PROTOCOL_ERROR;
  83. case 0x0D : return STATUS_SUCCESS;
  84. case 0x10 : return STATUS_UNRECOGNIZED_MEDIA;
  85. case 0x11 : return STATUS_UNRECOGNIZED_MEDIA;
  86. case 0x12 : return STATUS_INVALID_PARAMETER;
  87. case 0x13 : return STATUS_CONNECTION_ABORTED;
  88. case 0x14 : return STATUS_UNRECOGNIZED_MEDIA;
  89. case 0x15 : return STATUS_UNRECOGNIZED_MEDIA;
  90. case 0x16 : return STATUS_INVALID_PARAMETER;
  91. case 0x17 : return STATUS_UNRECOGNIZED_MEDIA;
  92. case 0x18 : return STATUS_UNRECOGNIZED_MEDIA;
  93. case 0x19 : return STATUS_INVALID_PARAMETER;
  94. case 0x1A : return STATUS_INVALID_PARAMETER;
  95. case 0x1B : return STATUS_INVALID_PARAMETER;
  96. case 0x1C : return STATUS_INVALID_PARAMETER;
  97. case 0x1D : return STATUS_UNRECOGNIZED_MEDIA;
  98. case 0x1E : return STATUS_INVALID_PARAMETER;
  99. case 0x1F : return STATUS_INVALID_PARAMETER;
  100. case 0x20 : return STATUS_INVALID_PARAMETER;
  101. case 0x30 : return STATUS_IO_TIMEOUT;
  102. case 0xA0 : return STATUS_SUCCESS;
  103. case 0xA1 : return STATUS_UNRECOGNIZED_MEDIA;
  104. case 0xA2 :
  105. if (Tag == OPEN_SESSION_CMD)
  106. { return STATUS_UNRECOGNIZED_MEDIA;}
  107. else
  108. { return STATUS_IO_TIMEOUT; }
  109. case 0xA3 : return STATUS_PARITY_ERROR;
  110. case 0xA4 : return STATUS_REQUEST_ABORTED;
  111. case 0xA5 : return STATUS_REQUEST_ABORTED;
  112. case 0xA6 : return STATUS_REQUEST_ABORTED;
  113. case 0xA7 : return STATUS_UNRECOGNIZED_MEDIA;
  114. case 0xCF : return STATUS_INVALID_PARAMETER;
  115. case 0xE4 : return STATUS_UNRECOGNIZED_MEDIA;
  116. case 0xE5 : return STATUS_SUCCESS;
  117. case 0xE7 : return STATUS_SUCCESS;
  118. case 0xF7 : return STATUS_NO_MEDIA;
  119. case 0xF8 : return STATUS_UNRECOGNIZED_MEDIA;
  120. case 0xFB : return STATUS_NO_MEDIA;
  121. default : return STATUS_INVALID_PARAMETER;
  122. }
  123. }
  124. /*++
  125. Routine Description :
  126. Read a byte at IO address
  127. --*/
  128. BOOLEAN G_ReadByte(const USHORT BIOAddr,UCHAR *Value)
  129. {
  130. *Value = READ_PORT_UCHAR((PUCHAR) BIOAddr);
  131. return(TRUE);
  132. }
  133. /*++
  134. Routine Description :
  135. Write a byte at IO address
  136. --*/
  137. BOOLEAN G_WriteByte(const USHORT BIOAddr,UCHAR *Value)
  138. {
  139. WRITE_PORT_UCHAR((PUCHAR) BIOAddr,*Value);
  140. return(TRUE);
  141. }
  142. /*++
  143. Routine Description :
  144. Read a buffer of "Len" bytes at IO address
  145. --*/
  146. BOOLEAN G_ReadBuf(const USHORT BIOAddr,const USHORT Len,UCHAR *Buffer)
  147. {
  148. USHORT i;
  149. for(i=0;i<Len;i++)
  150. {
  151. *(Buffer+i) = READ_PORT_UCHAR((UCHAR *) UlongToPtr(BIOAddr+i));
  152. }
  153. #if DBG
  154. // Excluse reader status reply
  155. if(! ((Buffer[0] == 0xA2) && (Buffer[1]==4)) )
  156. {
  157. SmartcardDebug(
  158. DEBUG_TRACE,
  159. ("%s!G_ReadBuf:",
  160. SC_DRIVER_NAME)
  161. );
  162. GPR_Debug_Buffer(Buffer, Len );
  163. }
  164. #endif
  165. return(TRUE);
  166. }
  167. /*++
  168. Routine Description :
  169. Write a buffer of "Len" bytes at IO address
  170. --*/
  171. BOOLEAN G_WriteBuf(const USHORT BIOAddr,const USHORT Len,UCHAR *Buffer)
  172. {
  173. USHORT i;
  174. for(i=0;i<Len;i++)
  175. {
  176. WRITE_PORT_UCHAR((UCHAR *) UlongToPtr(BIOAddr + i),*(Buffer+i));
  177. }
  178. #if DBG
  179. // Excluse reader status cmd
  180. if(! ((Buffer[0] == 0xA0) && (Buffer[2] == 0x02)) )
  181. {
  182. SmartcardDebug(
  183. DEBUG_TRACE,
  184. ("%s!G_WriteBuf:",
  185. SC_DRIVER_NAME)
  186. );
  187. GPR_Debug_Buffer(Buffer,Len);
  188. }
  189. #endif
  190. return(TRUE);
  191. }
  192. /*++
  193. Routine Description :
  194. Mask a register located at a specified address with a specified
  195. byte
  196. --*/
  197. BOOLEAN G_MaskRegister(
  198. const USHORT BIOAddr,
  199. const UCHAR Mask,
  200. const UCHAR BitState)
  201. {
  202. if(BitState == 0)
  203. {
  204. WRITE_PORT_UCHAR((PUCHAR)BIOAddr,(UCHAR) (READ_PORT_UCHAR((PUCHAR)BIOAddr) & ~Mask));
  205. }
  206. else
  207. {
  208. WRITE_PORT_UCHAR((PUCHAR)BIOAddr,(UCHAR) (READ_PORT_UCHAR((PUCHAR)BIOAddr) | Mask));
  209. }
  210. return(TRUE);
  211. }
  212. /*++
  213. Routine Description :
  214. Read a byte to an input address port
  215. --*/
  216. UCHAR GprllReadRegister(
  217. const PREADER_EXTENSION pReaderExt,
  218. const SHORT GPRRegister
  219. )
  220. {
  221. //
  222. // Locals variables:
  223. // value holds the result of the read operation.
  224. //
  225. UCHAR value;
  226. value = 0x0;
  227. G_ReadByte((const USHORT)
  228. (((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) GPRRegister),
  229. &value
  230. );
  231. return(value);
  232. }
  233. /*++
  234. Routine Description :
  235. Call the G_MaskRegister function in the lower level
  236. --*/
  237. void GprllMaskHandshakeRegister(
  238. const PREADER_EXTENSION pReaderExt,
  239. const UCHAR Mask,
  240. const UCHAR BitState
  241. )
  242. {
  243. G_MaskRegister((const USHORT)
  244. (((const USHORT) (pReaderExt->BaseIoAddress))
  245. + (const USHORT) REGISTER_HANDSHAKE),
  246. (const UCHAR) Mask,
  247. (const UCHAR) BitState);
  248. // YN
  249. // get hardware time to update register
  250. GprllWait(1);
  251. }
  252. NTSTATUS GprllKeWaitAckEvent(
  253. const PREADER_EXTENSION pReaderExt,
  254. const UCHAR Tx
  255. )
  256. /*++
  257. Routine Description:
  258. This function Wait the acknowledge of the GPR after
  259. a send command to IOPort. We made a smart verification
  260. of the timer depending of the Tag command.
  261. Arguments In:
  262. pReaderExt holds the pointer to the READER_EXTENSION structure.
  263. Tx holds the command type
  264. Return Value:
  265. NTStatus
  266. --*/
  267. {
  268. UCHAR T; // Tag return
  269. LARGE_INTEGER lTimeout;
  270. NTSTATUS NTStatus = STATUS_SUCCESS;
  271. ULONG NbLoop = 0;
  272. ULONG NbSecondTotal;
  273. ULONG ElapsedSecond = 0;
  274. ULONG TimeInLoop =1;
  275. BOOLEAN Continue = TRUE;
  276. ULONG i = 0;
  277. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  278. // Make a smart timer depending on type of command
  279. if( (Tx & 0xf0) == APDU_EXCHANGE_CMD)
  280. {
  281. NbSecondTotal = pReaderExt->CmdTimeOut;
  282. }
  283. else
  284. {
  285. NbSecondTotal = GPR_CMD_TIME;
  286. }
  287. NbLoop = (NbSecondTotal / TimeInLoop);
  288. while( (Continue) && (ElapsedSecond < NbSecondTotal) )
  289. {
  290. ElapsedSecond += TimeInLoop;
  291. lTimeout.QuadPart = -((LONGLONG)TimeInLoop * 10000000);
  292. //Wait the acknowledge of the GPR
  293. NTStatus = KeWaitForSingleObject(
  294. &(pReaderExt->GPRAckEvent),
  295. Executive,
  296. KernelMode,
  297. TRUE,
  298. &lTimeout
  299. );
  300. if(NTStatus == STATUS_TIMEOUT)
  301. {
  302. // Verify if the reader was been
  303. // remove during exchange
  304. lTimeout.QuadPart = 0;
  305. NTStatus = KeWaitForSingleObject(
  306. &(pReaderExt->ReaderRemoved),
  307. Executive,
  308. KernelMode,
  309. FALSE,
  310. &lTimeout
  311. );
  312. SmartcardDebug(
  313. DEBUG_PROTOCOL,
  314. ( "%s!GprllKeWaitAckEvent: TIMEOUT KeWaitForSingleObject=%X(hex)\n",
  315. SC_DRIVER_NAME,
  316. NTStatus)
  317. );
  318. if (NTStatus == STATUS_SUCCESS)
  319. {
  320. NTStatus = STATUS_DEVICE_REMOVED;
  321. Continue = FALSE;
  322. }
  323. // Read the T register
  324. // <== Test if GPR hasn't been removed STATUS_DEVICE_NOT_CONNECTED
  325. // Reading T out
  326. T = GprllReadRegister(pReaderExt,REGISTER_T);
  327. if ( T == 0xFF )
  328. {
  329. NTStatus = STATUS_DEVICE_REMOVED;
  330. Continue = FALSE;
  331. }
  332. // Else is a Timeout
  333. }
  334. else
  335. {
  336. Continue = FALSE;
  337. NTStatus = STATUS_SUCCESS;
  338. }
  339. }
  340. return NTStatus;
  341. }
  342. NTSTATUS GprllTLVExchange(
  343. const PREADER_EXTENSION pReaderExt,
  344. const UCHAR Ti,
  345. const USHORT Li,
  346. const UCHAR *Vi,
  347. UCHAR *To,
  348. USHORT *Lo,
  349. UCHAR *Vo
  350. )
  351. /*++
  352. Routine Description :
  353. Exchange data with GPR with a TLV command.
  354. Arguments
  355. In:
  356. pReaderExt holds the pointer to the READER_EXTENSION structure.
  357. Ti holds the command type
  358. Li holds the command length
  359. Vi holds the command data
  360. Out:
  361. To holds the command response type
  362. Lo holds the command response length
  363. Vo holds the command response data
  364. Return Value
  365. NTStatus
  366. STATUS_SUCCESS is Ok
  367. else if an error condition is raised:
  368. STATUS_DEVICE_PROTOCOL_ERROR
  369. STATUS_INVALID_DEVICE_STATE
  370. STATUS_DEVICE_NOT_CONNECTED
  371. STATUS_UNRECOGNIZED_MEDIA
  372. and others received IFDstatus corresponding to NTSTATUS
  373. --*/
  374. {
  375. // Local variables
  376. // - T is type of TLV protocol
  377. // - new_Ti is the Ti modified
  378. // - L is length in TLV protocol
  379. // - V is data filed in TLV protocol
  380. NTSTATUS NTStatus = STATUS_SUCCESS;
  381. UCHAR T;
  382. UCHAR new_Ti;
  383. USHORT L;
  384. UCHAR V[GPR_BUFFER_SIZE];
  385. //Verification of Li
  386. if ( (USHORT) Li >= GPR_BUFFER_SIZE )
  387. {
  388. return (STATUS_DEVICE_PROTOCOL_ERROR);
  389. }
  390. new_Ti = Ti;
  391. //
  392. // Write the TLV
  393. // by Write TLV if Li <= 28 or By ChainIn if Li > 28
  394. //
  395. if (Li<=MAX_V_LEN)
  396. {
  397. GprllSendCmd(pReaderExt,new_Ti,Li,Vi);
  398. NTStatus = GprllKeWaitAckEvent(
  399. pReaderExt,
  400. Ti
  401. );
  402. if (STATUS_SUCCESS != NTStatus)
  403. {
  404. // YN
  405. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  406. return NTStatus;
  407. }
  408. // GPR Command to read I/O Window:
  409. // In the handshake register, set to 0 bit 2(IREQ) , and set to 1 bit 1 (INTR)
  410. }
  411. else
  412. {
  413. NTStatus = GprllSendChainUp(
  414. pReaderExt,
  415. new_Ti,
  416. Li,
  417. Vi
  418. );
  419. if (STATUS_SUCCESS != NTStatus)
  420. {
  421. // YN
  422. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  423. return(NTStatus);
  424. }
  425. }
  426. // Read the T register, need to know if new data to exchange
  427. T = pReaderExt->To;
  428. // Read Answer by Read TLV or Chain Out method if To = Ti + 6
  429. if ( T == (new_Ti + 6) )
  430. {
  431. NTStatus = GprllReadChainUp(pReaderExt,&T,&L,V);
  432. if (STATUS_SUCCESS != NTStatus )
  433. {
  434. // YN
  435. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  436. return(NTStatus);
  437. }
  438. }
  439. else
  440. {
  441. L = pReaderExt->Lo;
  442. ASSERT(pReaderExt->Vo !=0);
  443. memcpy(V,pReaderExt->Vo,L);
  444. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  445. }
  446. // Verify if Response buffer len is large enough
  447. // to contain data received from the reader
  448. //
  449. if( L > *Lo )
  450. {
  451. *To=T;
  452. *Lo=1;
  453. Vo[0]=14;
  454. return(STATUS_UNRECOGNIZED_MEDIA);
  455. }
  456. // Translate answer
  457. *To=T;
  458. *Lo=L;
  459. memcpy(Vo,V,(SHORT)L);
  460. return (GDDK_Translate(Vo[0], Ti));
  461. }
  462. void GprllSendCmd(
  463. const PREADER_EXTENSION pReaderExt,
  464. const UCHAR Ti,
  465. const USHORT Li,
  466. const UCHAR *Vi
  467. )
  468. /*++
  469. Routine Description :
  470. Write TLV into I/O Window and
  471. Send Command to GPR to read I/O Window
  472. Arguments:
  473. pReaderExt holds the pointer to the READER_EXTENSION structure.
  474. Ti holds the command type
  475. Li holds the command length
  476. Vi holds the command data
  477. --*/
  478. {
  479. // Local variables
  480. // - TLV is an intermediate buffer.
  481. UCHAR TLV[2 + MAX_V_LEN];
  482. USHORT Li_max;
  483. //Write Ti, Li and Vi[]
  484. TLV[0] = Ti;
  485. TLV[1] = (UCHAR) Li;
  486. ASSERT(Vi != 0);
  487. Li_max = Li;
  488. if (Li_max > MAX_V_LEN)
  489. {
  490. Li_max = MAX_V_LEN;
  491. }
  492. memcpy(TLV+2,Vi,Li_max);
  493. G_WriteBuf((const USHORT)
  494. (((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) REGISTER_T),
  495. (const USHORT) (Li_max + 2),
  496. (UCHAR *) TLV
  497. );
  498. // GPR Command to read I/O Window:
  499. // In the handshake register, set to 0 bit 2(IREQ) , and set to 1 bit 1 (INTR)
  500. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  501. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_INTR,1);
  502. }
  503. void GprllReadResp(
  504. const PREADER_EXTENSION pReaderExt
  505. )
  506. /*++
  507. Routine Description :
  508. Read no chainning TLV into I/O Window and
  509. Send Command to GPR to read I/O Window
  510. Arguments
  511. In:
  512. pReaderExt holds the pointer to the READER_EXTENSION structure.
  513. Out:
  514. To holds the command response type
  515. Lo holds the command response length
  516. Vo holds the command response data
  517. --*/
  518. {
  519. //Local variables
  520. // - TLV is an intermediate buffer.
  521. UCHAR TLV[2 + MAX_V_LEN];
  522. TLV[0] = 0x0;
  523. // Read To, Lo and Vo[]
  524. G_ReadBuf((const USHORT)
  525. (((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) REGISTER_T),
  526. MAX_V_LEN + 2,
  527. TLV);
  528. pReaderExt->To = TLV[0];
  529. // maximum number of character is set by the TLV buffer
  530. pReaderExt->Lo = TLV[1];
  531. if (pReaderExt->Lo > MAX_V_LEN)
  532. {
  533. pReaderExt->Lo = MAX_V_LEN;
  534. }
  535. memcpy(pReaderExt->Vo,TLV+2,pReaderExt->Lo);
  536. // Acquit the Hand shake:
  537. // In the handshake register, set to 0 bit 2 (BUSY/IREQ)
  538. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  539. }
  540. NTSTATUS GprllSendChainUp(
  541. const PREADER_EXTENSION pReaderExt,
  542. const UCHAR Ti,
  543. const USHORT Li,
  544. const UCHAR *Vi
  545. )
  546. /*++
  547. Routine Description : Send chainning TLV to GPR
  548. Arguments:
  549. In:
  550. pReaderExt holds the pointer to the READER_EXTENSION structure.
  551. Ti holds the command type
  552. Li holds the command length
  553. Vi holds the command data
  554. Out: Nothing
  555. --*/
  556. {
  557. // Local variables
  558. // - Tc is type of TLV protocol ( TLV chaining method )
  559. // - Lc is Length of TLV protocol ( chaining method )
  560. // - Vc is 28 bytes max of data to send
  561. // - Length is an temporary var to store Li
  562. UCHAR Tc;
  563. UCHAR Response;
  564. UCHAR Lo;
  565. USHORT Lc;
  566. USHORT Length;
  567. UCHAR Vc[MAX_V_LEN];
  568. NTSTATUS NTStatus = STATUS_SUCCESS;
  569. Length=Li;
  570. //Prepare Tc (Add 4 to Ti for chaining method)
  571. Tc=Ti+4;
  572. Vc[0] = 0x0;
  573. while ( Length > 0 )
  574. {
  575. //Prepare Lc
  576. //If length TLV > 28 Length = 28 else it's last command L = Length
  577. if ( Length > MAX_V_LEN )
  578. {
  579. Lc=MAX_V_LEN;
  580. }
  581. else
  582. {
  583. Lc=Length;
  584. Tc=Ti;
  585. }
  586. //Prepare Vc
  587. memcpy(Vc,Vi+Li-Length,Lc);
  588. //Write to I/O window
  589. // Dont need the answer - handled by the interrupt function.
  590. GprllSendCmd(pReaderExt,Tc,Lc,Vc);
  591. NTStatus = GprllKeWaitAckEvent(
  592. pReaderExt,
  593. Ti
  594. );
  595. if(STATUS_SUCCESS != NTStatus)
  596. {
  597. return NTStatus;
  598. }
  599. //If an error test Response
  600. Response = GprllReadRegister(pReaderExt,REGISTER_V);
  601. if(0x00 != Response)
  602. {
  603. Lo = GprllReadRegister(pReaderExt,REGISTER_L);
  604. if (Lo == 0x01)
  605. {
  606. return (GDDK_Translate(Response, Ti));
  607. }
  608. else
  609. {
  610. // This is not a exchange is a cmd to reader
  611. // we don't care about the reader status.
  612. return (NTStatus);
  613. }
  614. }
  615. Length=Length-Lc;
  616. }
  617. return(NTStatus);
  618. }
  619. NTSTATUS GprllReadChainUp(
  620. const PREADER_EXTENSION pReaderExt,
  621. UCHAR *To,
  622. USHORT *Lo,
  623. UCHAR *Vo
  624. )
  625. /*++
  626. Routine Description : Receive chainning TLV response from GPR
  627. Arguments
  628. In:
  629. pReaderExt holds the pointer to the READER_EXTENSION structure.
  630. Out:
  631. To holds the command response type
  632. Lo holds the command response length
  633. Vo holds the command response data
  634. --*/
  635. {
  636. // Local variables
  637. // - Tc is type of TLV protocol ( TLV chaining method )
  638. // - Lc is Length of TLV protocol ( chaining method )
  639. // - Length is an temporary var to store Lo
  640. UCHAR Tc;
  641. USHORT Lc;
  642. SHORT Lenght;
  643. NTSTATUS NTStatus = STATUS_SUCCESS;
  644. // Reading T out
  645. Tc = GprllReadRegister(pReaderExt,REGISTER_T);
  646. *To=Tc-4;
  647. Lenght = 0;
  648. do
  649. {
  650. // Read TLV
  651. Tc = pReaderExt->To;
  652. Lc = pReaderExt->Lo;
  653. ASSERT(pReaderExt->Vo != 0);
  654. // The Vo buffer is limited by the caller local variable.
  655. if ( Lenght + (SHORT) pReaderExt->Lo > GPR_BUFFER_SIZE)
  656. {
  657. return (STATUS_BUFFER_TOO_SMALL);
  658. }
  659. memcpy(Vo+Lenght,pReaderExt->Vo,pReaderExt->Lo);
  660. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  661. // Prepare Lo
  662. *Lo=(USHORT)Lenght+Lc;
  663. Lenght=Lenght+Lc;
  664. // GPR send the next Chainning TLV
  665. // In the handshake register, set to 0 bit 2(IREQ) and set to 1 bit 1 (INTR)
  666. if ((*To) != Tc )
  667. {
  668. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
  669. GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_INTR,1);
  670. NTStatus = GprllKeWaitAckEvent(
  671. pReaderExt,
  672. *To
  673. );
  674. if(STATUS_SUCCESS != NTStatus)
  675. {
  676. return NTStatus;
  677. }
  678. }
  679. // (End do) if To=Tc -> Last Chainning TLV
  680. } while( (*To) != Tc );
  681. return(NTStatus);
  682. }
  683. void GprllWait(
  684. const LONG lWaitingTime
  685. )
  686. /*++
  687. Routine Description : This function puts the driver in a waiting state
  688. for a timeout. If IRQL < DISPATCH_LEVEL, use normal fonction to process
  689. this delay. use KeStallExecutionProcessor, just when GprllWait is called
  690. in the context of DPC routine.
  691. Arguments
  692. pReaderExt: Pointer to the current ReaderExtension structure.
  693. lWaitingTime: Timeout value in ms
  694. --*/
  695. {
  696. LARGE_INTEGER Delay;
  697. if( KeGetCurrentIrql() >= DISPATCH_LEVEL )
  698. {
  699. ULONG Cnt = 20 * lWaitingTime;
  700. while( Cnt-- )
  701. {
  702. // KeStallExecutionProcessor: counted in us
  703. KeStallExecutionProcessor( 50 );
  704. }
  705. }
  706. else
  707. {
  708. Delay.QuadPart = (LONGLONG)-10 * 1000 * lWaitingTime;
  709. // KeDelayExecutionThread: counted in 100 ns
  710. KeDelayExecutionThread( KernelMode, FALSE, &Delay );
  711. }
  712. return;
  713. }