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.

989 lines
30 KiB

  1. /*++
  2. Module Name:
  3. L220FLTR.c
  4. Abstract:
  5. This module contains the input filter routine and the notification
  6. procedure for insertion/removal events.
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. Revision History:
  11. - Created December 1996 by Klaus Schutz (kschutz)
  12. - Modified December 1997 by Brian Manahan for use with
  13. our 220 reader.
  14. --*/
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include "L220SCR.h"
  19. #pragma alloc_text(PAGEABLE, Lit220StartTimer)
  20. #pragma alloc_text(PAGEABLE, Lit220StopTimer)
  21. static DWORD bTrue = TRUE;
  22. static DWORD bFalse = FALSE;
  23. BOOLEAN
  24. Lit220InputFilter(
  25. IN BYTE SmartcardByte,
  26. IN PSMARTCARD_EXTENSION smartcardExtension
  27. )
  28. /*++
  29. Routine Description:
  30. This routine is processes each byte from the serial port.
  31. Lit220SerialEventCallback call this function when it receives a byte
  32. of data from the serial port. For card insertion/removal it will call the
  33. Lit220NotifyCardChange to process the notificiation.
  34. If an ACK is received it will signal the Lit220SendCommand so it can continue.
  35. After a data block is received it will signal the Lit220SendCommand
  36. to notifiy that the data is ready.
  37. --*/
  38. {
  39. PREADER_EXTENSION readerExtension = smartcardExtension->ReaderExtension;
  40. PDEVICE_EXTENSION deviceExtension = smartcardExtension->OsData->DeviceObject->DeviceExtension;
  41. LONG semState;
  42. BOOLEAN retVal = TRUE;
  43. //
  44. // The first byte of each packet identifies the packet-type
  45. // A packet containing data starts with the packet-type and then
  46. // 2 bytes of packet length.
  47. //
  48. if (++readerExtension->ReceivedByteNo == 1) {
  49. readerExtension->GotLengthB0 = FALSE;
  50. readerExtension->GotLengthB1 = FALSE;
  51. readerExtension->DataByteNo = 0;
  52. switch (SmartcardByte) {
  53. case LIT220_READER_TYPE:
  54. // Prepare for reader type input
  55. readerExtension->GotLengthB0 = TRUE;
  56. readerExtension->GotLengthB1 = TRUE;
  57. readerExtension->DataLength.l.l0 =
  58. LIT220_READER_TYPE_LEN;
  59. break;
  60. case LIT220_READER_STATUS:
  61. // Prepare for reader status input
  62. readerExtension->GotLengthB0 = TRUE;
  63. readerExtension->GotLengthB1 = TRUE;
  64. readerExtension->DataLength.l.l0 =
  65. LIT220_READER_STATUS_LEN;
  66. break;
  67. case LIT220_RECEIVE_BLOCK:
  68. // If a smart card was already inserted in the boot phase
  69. // the reader sends only the ATR but no CARD_IN - msg.
  70. // We fix that missing msg here.
  71. //
  72. if (smartcardExtension->ReaderCapabilities.CurrentState == SCARD_UNKNOWN) {
  73. smartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
  74. }
  75. break;
  76. case LIT220_CARD_IN:
  77. Lit220NotifyCardChange(
  78. smartcardExtension,
  79. TRUE
  80. );
  81. readerExtension->ReceivedByteNo = 0;
  82. break;
  83. case LIT220_CARD_OUT:
  84. Lit220NotifyCardChange(
  85. smartcardExtension,
  86. FALSE
  87. );
  88. readerExtension->ReceivedByteNo = 0;
  89. break;
  90. case LIT220_ACK:
  91. case KBD_ACK: // Also allow kdb_ack for the case for getting keyboard attention
  92. readerExtension->GotNack = FALSE;
  93. readerExtension->ReceivedByteNo = 0;
  94. // Check if anyone needs to be singaled for this event.
  95. // The Lit220SendCommand waits for the ACK signal so it knows
  96. // when it can continue.
  97. if (readerExtension->WaitMask & WAIT_ACK) {
  98. LONG semState;
  99. // Only signal once
  100. readerExtension->WaitMask &= ~WAIT_ACK;
  101. // Signal the AckEvnt
  102. KeSetEvent(
  103. &readerExtension->AckEvnt,
  104. 0,
  105. FALSE
  106. );
  107. }
  108. break;
  109. case LIT220_NACK:
  110. SmartcardDebug(
  111. DEBUG_ERROR,
  112. ("%s!Lit220InteruptService: LIT220_NACK\n",
  113. DRIVER_NAME)
  114. );
  115. Lit220ProcessNack(smartcardExtension);
  116. break;
  117. default:
  118. readerExtension->ReceivedByteNo = 0;
  119. SmartcardDebug(
  120. DEBUG_ERROR,
  121. ("%s!Lit220InteruptService: Invalid PacketType %xh\n",
  122. DRIVER_NAME,
  123. SmartcardByte)
  124. );
  125. // Return false so the rest of this bad buffer
  126. // will not be sent to us.
  127. retVal = FALSE;
  128. // We want to force a NACK so the
  129. // the state of the card being inserted or not
  130. // is re-checked
  131. Lit220ProcessNack(smartcardExtension);
  132. }
  133. return retVal;
  134. }
  135. //
  136. // Get length-byte-0 from reader
  137. //
  138. if (readerExtension->ReceivedByteNo == 2 &&
  139. readerExtension->GotLengthB0 == FALSE) {
  140. readerExtension->DataLength.b.b1 = SmartcardByte;
  141. readerExtension->GotLengthB0 = TRUE;
  142. return TRUE;
  143. }
  144. //
  145. // Get length-byte-1 from reader
  146. //
  147. if (readerExtension->ReceivedByteNo == 3 &&
  148. readerExtension->GotLengthB1 == FALSE) {
  149. readerExtension->DataLength.b.b0 = SmartcardByte;
  150. readerExtension->GotLengthB1 = TRUE;
  151. //
  152. // test if the reader has sent a zero-length block of data
  153. //
  154. if (readerExtension->DataLength.l.l0 == 0) {
  155. readerExtension->ReceivedByteNo = 0;
  156. readerExtension->WaitForATR = FALSE;
  157. SmartcardDebug(
  158. DEBUG_ERROR,
  159. ("%s!SmartcardInterruptService: Zero length block received\n",
  160. DRIVER_NAME)
  161. );
  162. }
  163. if (readerExtension->DataLength.l.l0 >
  164. smartcardExtension->SmartcardReply.BufferSize) {
  165. readerExtension->ReceivedByteNo = 0;
  166. readerExtension->WaitForATR = FALSE;
  167. SmartcardDebug(
  168. DEBUG_ERROR,
  169. ("%s!SmartcardInterruptService: Reply buffer not large enough\n",
  170. DRIVER_NAME)
  171. );
  172. }
  173. return TRUE;
  174. }
  175. //
  176. // store data from reader
  177. //
  178. if ((readerExtension->DataByteNo < readerExtension->DataLength.l.l0) &&
  179. (readerExtension->DataByteNo < smartcardExtension->SmartcardReply.BufferSize))
  180. {
  181. smartcardExtension->SmartcardReply.Buffer[readerExtension->DataByteNo++] =
  182. SmartcardByte;
  183. } else {
  184. SmartcardDebug(
  185. DEBUG_ERROR,
  186. ("%s!SmartcardInterruptService: DataByteNo %X too large buffer %X, %X bytest expected\n",
  187. DRIVER_NAME,
  188. readerExtension->DataByteNo,
  189. smartcardExtension->SmartcardReply.BufferSize,
  190. readerExtension->DataLength.l.l0)
  191. );
  192. }
  193. ASSERT(readerExtension->DataByteNo <= readerExtension->DataLength.l.l0);
  194. //
  195. // Have we received all the bytes in the packet yet?
  196. //
  197. if (readerExtension->DataByteNo == readerExtension->DataLength.l.l0) {
  198. // Stop the input timeout timer
  199. // schedule our remove thread
  200. Lit220ScheduleTimer(
  201. smartcardExtension,
  202. Lit220StopTimer
  203. );
  204. smartcardExtension->SmartcardReply.BufferLength =
  205. readerExtension->DataByteNo;
  206. readerExtension->ReceivedByteNo = 0;
  207. if (readerExtension->WaitForATR) {
  208. //
  209. // Transfer ATR to smartcard-struct
  210. //
  211. smartcardExtension->CardCapabilities.ATR.Length =
  212. (UCHAR) (readerExtension->DataByteNo % (SCARD_ATR_LENGTH + 1));
  213. readerExtension->WaitForATR = FALSE;
  214. if (smartcardExtension->CardCapabilities.ATR.Length >
  215. smartcardExtension->SmartcardReply.BufferLength)
  216. {
  217. SmartcardDebug(
  218. DEBUG_ERROR,
  219. ("%s!SmartcardInterruptService: SmarcardReply buffer too small for ATR\n",
  220. DRIVER_NAME)
  221. );
  222. } else {
  223. RtlCopyMemory(
  224. smartcardExtension->CardCapabilities.ATR.Buffer,
  225. smartcardExtension->SmartcardReply.Buffer,
  226. smartcardExtension->CardCapabilities.ATR.Length
  227. );
  228. SmartcardUpdateCardCapabilities(
  229. smartcardExtension
  230. );
  231. }
  232. }
  233. // Check if anyone needs to be singaled for this event.
  234. // The Lit220SendCommand waits for the DataEvnt signal so it knows
  235. // when the data has been received.
  236. if (readerExtension->WaitMask & WAIT_DATA) {
  237. //
  238. // Do any necessary post proccessing after we have receive the packet
  239. //
  240. if (smartcardExtension->OsData->CurrentIrp != NULL) {
  241. NTSTATUS status = STATUS_SUCCESS;
  242. switch (smartcardExtension->MajorIoControlCode) {
  243. case IOCTL_SMARTCARD_POWER:
  244. if (smartcardExtension->ReaderExtension->GotNack) {
  245. status = STATUS_NO_MEDIA;
  246. break;
  247. }
  248. switch(smartcardExtension->MinorIoControlCode) {
  249. case SCARD_COLD_RESET:
  250. case SCARD_WARM_RESET:
  251. if (smartcardExtension->IoRequest.ReplyBufferLength <
  252. smartcardExtension->CardCapabilities.ATR.Length) {
  253. status = STATUS_BUFFER_TOO_SMALL;
  254. } else {
  255. //
  256. // copy ATR to user buffer
  257. //
  258. if (smartcardExtension->CardCapabilities.ATR.Length <=
  259. sizeof(smartcardExtension->CardCapabilities.ATR.Buffer))
  260. {
  261. RtlCopyMemory(
  262. smartcardExtension->IoRequest.ReplyBuffer,
  263. &smartcardExtension->CardCapabilities.ATR.Buffer,
  264. smartcardExtension->CardCapabilities.ATR.Length
  265. );
  266. //
  267. // length of buffer
  268. //
  269. *(smartcardExtension->IoRequest.Information) =
  270. smartcardExtension->CardCapabilities.ATR.Length;
  271. }
  272. }
  273. break;
  274. case SCARD_POWER_DOWN:
  275. if (smartcardExtension->ReaderCapabilities.CurrentState != SCARD_ABSENT) {
  276. smartcardExtension->ReaderCapabilities.CurrentState =
  277. SCARD_SWALLOWED;
  278. smartcardExtension->CardCapabilities.Protocol.Selected =
  279. SCARD_PROTOCOL_UNDEFINED;
  280. }
  281. break;
  282. }
  283. break;
  284. case IOCTL_SMARTCARD_SET_PROTOCOL:
  285. if (smartcardExtension->ReaderExtension->GotNack) {
  286. smartcardExtension->CardCapabilities.Protocol.Selected =
  287. SCARD_PROTOCOL_UNDEFINED;
  288. status = STATUS_NO_MEDIA;
  289. break;
  290. }
  291. //
  292. // protocol has been changed successfully
  293. //
  294. if (smartcardExtension->ReaderCapabilities.CurrentState != SCARD_ABSENT) {
  295. smartcardExtension->ReaderCapabilities.CurrentState =
  296. SCARD_SPECIFIC;
  297. }
  298. //
  299. // Tell the caller what the current protocol is.
  300. //
  301. *(PULONG) smartcardExtension->IoRequest.ReplyBuffer =
  302. smartcardExtension->CardCapabilities.Protocol.Selected;
  303. *(smartcardExtension->IoRequest.Information) =
  304. sizeof(ULONG);
  305. break;
  306. }
  307. }
  308. // Only signal once
  309. readerExtension->WaitMask &= ~WAIT_DATA;
  310. // Signal the DataEvnt
  311. KeSetEvent(
  312. &readerExtension->DataEvnt,
  313. 0,
  314. FALSE
  315. );
  316. }
  317. }
  318. return TRUE;
  319. }
  320. VOID
  321. Lit220ProcessNack(
  322. PSMARTCARD_EXTENSION SmartcardExtension
  323. )
  324. /*++
  325. Routine Description:
  326. This routine handles everything that needs to be done when we have an error
  327. with the reader. The state of the input filter is reset. All signals that
  328. the Lit220Command function may be waiting on are fired. The flag GotNack is
  329. set which will trigger Lit220Command to resync with the reader (get the last
  330. error and refresh the card inserted state).
  331. --*/
  332. {
  333. PREADER_EXTENSION readerExtension = SmartcardExtension->ReaderExtension;
  334. // Set GotNack so we know something went wrong
  335. readerExtension->GotNack = TRUE;
  336. // Reset the input state of the filter
  337. readerExtension->ReceivedByteNo = 0;
  338. //
  339. // Signal the ACK and data semaphores and set error code
  340. // This will keep the Lit220SendCommand from having to
  341. // wait for a timeout to continue when something goes wrong.
  342. //
  343. if (readerExtension->WaitMask & WAIT_ACK) {
  344. // Signal the AckEvnt
  345. KeSetEvent(
  346. &readerExtension->AckEvnt,
  347. 0,
  348. FALSE
  349. );
  350. }
  351. if (readerExtension->WaitMask & WAIT_DATA) {
  352. // Signal the DataEvnt
  353. KeSetEvent(
  354. &readerExtension->DataEvnt,
  355. 0,
  356. FALSE
  357. );
  358. }
  359. //
  360. // Reset WaitMask since the card has nacked the command
  361. //
  362. readerExtension->WaitMask &= (WAIT_INSERTION | WAIT_REMOVAL);
  363. }
  364. VOID
  365. Lit220NotifyCardChange(
  366. IN PSMARTCARD_EXTENSION smartcardExtension,
  367. IN DWORD CardInserted
  368. )
  369. /*++
  370. Routine Description:
  371. This routine runs at DISPATCH_LEVEL IRQL to finish processing
  372. a card insertion/removal event. It is queued in the smartcard filter
  373. and notifies a caller of an insertion/removal event.
  374. --*/
  375. {
  376. PREADER_EXTENSION readerExtension = smartcardExtension->ReaderExtension;
  377. KIRQL oldOsDataIrql;
  378. if (readerExtension->CardIn == CardInserted) {
  379. return;
  380. }
  381. readerExtension->CardIn = CardInserted;
  382. KeAcquireSpinLock(
  383. &smartcardExtension->OsData->SpinLock,
  384. &oldOsDataIrql
  385. );
  386. if (CardInserted) {
  387. // Set the default state for the new card
  388. smartcardExtension->ReaderCapabilities.CurrentState =
  389. SCARD_SWALLOWED;
  390. smartcardExtension->CardCapabilities.Protocol.Selected =
  391. SCARD_PROTOCOL_UNDEFINED;
  392. } else {
  393. // Reset card state to reflect the card removal
  394. smartcardExtension->ReaderCapabilities.CurrentState =
  395. SCARD_ABSENT;
  396. smartcardExtension->CardCapabilities.Protocol.Selected =
  397. SCARD_PROTOCOL_UNDEFINED;
  398. smartcardExtension->CardCapabilities.ATR.Length = 0;
  399. }
  400. if (readerExtension->WaitMask & WAIT_INSERTION) {
  401. // We only make this notification once
  402. readerExtension->WaitMask &= ~WAIT_INSERTION;
  403. }
  404. Lit220CompleteCardTracking(smartcardExtension);
  405. KeReleaseSpinLock(
  406. &smartcardExtension->OsData->SpinLock,
  407. oldOsDataIrql
  408. );
  409. }
  410. VOID
  411. Lit220CompleteCardTracking(
  412. IN PSMARTCARD_EXTENSION SmartcardExtension
  413. )
  414. {
  415. KIRQL oldIrql;
  416. PIRP notificationIrp;
  417. SmartcardDebug(
  418. DEBUG_TRACE,
  419. ("%s!Lit220CompleteCardTracking: Enter\n",
  420. DRIVER_NAME)
  421. );
  422. IoAcquireCancelSpinLock(&oldIrql);
  423. notificationIrp = InterlockedExchangePointer(
  424. &(SmartcardExtension->OsData->NotificationIrp),
  425. NULL
  426. );
  427. if (notificationIrp) {
  428. IoSetCancelRoutine(
  429. notificationIrp,
  430. NULL
  431. );
  432. }
  433. IoReleaseCancelSpinLock(oldIrql);
  434. if (notificationIrp) {
  435. // finish the request
  436. if (notificationIrp->Cancel) {
  437. notificationIrp->IoStatus.Status = STATUS_CANCELLED;
  438. } else {
  439. notificationIrp->IoStatus.Status = STATUS_SUCCESS;
  440. }
  441. notificationIrp->IoStatus.Information = 0;
  442. IoCompleteRequest(
  443. notificationIrp,
  444. IO_NO_INCREMENT
  445. );
  446. }
  447. }
  448. NTSTATUS
  449. Lit220SerialEventCallback(
  450. IN PDEVICE_OBJECT DeviceObject,
  451. IN PIRP Irp,
  452. IN PSMARTCARD_EXTENSION SmartcardExtension
  453. )
  454. /*++
  455. Routine Description:
  456. This routine is first called as the deferred procedure when a character is received
  457. or when DSR changes its status.
  458. It first calls the serial driver to get the modem status to see if the events was
  459. due to DSR changing (meaning the reader has been removed).
  460. If DSR did not change it then checks the input queue size and reads the characters in
  461. the input queue. It then sends the input characters to the input filter for processing.
  462. Finally it calls the serial driver again to start new cts tracking (starting all over again).
  463. This routine gets continually called back from itself until the driver is ready
  464. to unload (indicated by the WaitMask set to 0).
  465. When the WaitMask is set to 0 it frees this IRP and signals the Lit220WaitForRemoval thread
  466. to close the serial port.
  467. --*/
  468. {
  469. NTSTATUS status;
  470. PIO_STACK_LOCATION irpStack;
  471. DWORD indx;
  472. PDEVICE_EXTENSION deviceExtension = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
  473. SmartcardExtension->ReaderExtension->SerialEventState++;
  474. //
  475. // First check to see we are being unloaded
  476. //
  477. if (SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask == 0) {
  478. SmartcardDebug(
  479. DEBUG_DRIVER,
  480. ("%s!Lit220SerialEventCallback: WAIT MASK 0 UNLOADING !!!!\n",
  481. DRIVER_NAME)
  482. );
  483. SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN;
  484. //
  485. // If the WaitMask is 0 then the driver is about to unload and we've
  486. // been called because the unload function has directed the serial
  487. // driver to complete the outstanding io completion.
  488. //
  489. // schedule our remove thread
  490. IoQueueWorkItem(
  491. deviceExtension->WorkItem,
  492. (PIO_WORKITEM_ROUTINE) Lit220CloseSerialPort,
  493. DelayedWorkQueue,
  494. NULL
  495. );
  496. //
  497. // We don't need the IRP anymore, so free it and tell the
  498. // io subsystem not to touch it anymore by returning the value below
  499. //
  500. IoFreeIrp(Irp);
  501. return STATUS_MORE_PROCESSING_REQUIRED;
  502. }
  503. // Get next stack location for next IRP
  504. irpStack = IoGetNextIrpStackLocation(
  505. SmartcardExtension->ReaderExtension->CardStatus.Irp
  506. );
  507. if (irpStack == NULL) {
  508. // Fatal Error
  509. SmartcardDebug(
  510. DEBUG_ERROR,
  511. ("%s!Lit220SerialEventCallback: Error IoGetNextIrpStackLocation returned NULL - exiting.\n",
  512. DRIVER_NAME)
  513. );
  514. return STATUS_SUCCESS;
  515. }
  516. switch (SmartcardExtension->ReaderExtension->SerialEventState) {
  517. case 1:
  518. //
  519. // First we send a get modem status
  520. //
  521. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  522. irpStack->MinorFunction = 0UL;
  523. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  524. sizeof(SmartcardExtension->ReaderExtension->ModemStatus);
  525. irpStack->Parameters.DeviceIoControl.IoControlCode =
  526. IOCTL_SERIAL_GET_MODEMSTATUS;
  527. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  528. &SmartcardExtension->ReaderExtension->ModemStatus;
  529. break;
  530. case 2:
  531. //
  532. // Check modem status if DSR = 0 then unload driver if not
  533. // then get queuestatus
  534. //
  535. if ((SmartcardExtension->ReaderExtension->ModemStatus & SERIAL_DSR_STATE) == 0) {
  536. // DSR is 0 this means the reader has been removed
  537. SmartcardDebug(
  538. DEBUG_DRIVER,
  539. ("%s!Lit220SerialEventCallback: DSR = 0 signaling to close device\n",
  540. DRIVER_NAME)
  541. );
  542. SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask = 0;
  543. SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN;
  544. // schedule our remove thread
  545. IoQueueWorkItem(
  546. deviceExtension->WorkItem,
  547. (PIO_WORKITEM_ROUTINE) Lit220CloseSerialPort,
  548. DelayedWorkQueue,
  549. NULL
  550. );
  551. //
  552. // We don't need the IRP anymore, so free it and tell the
  553. // io subsystem not to touch it anymore by returning the value below
  554. //
  555. IoFreeIrp(Irp);
  556. return STATUS_MORE_PROCESSING_REQUIRED;
  557. } else {
  558. // Device is not removed - there must be a character ready
  559. // Read the data into our temporary buffer. The temporary buffer
  560. // is large enough to read whatever the reader can send us a one time.
  561. // The character interval timeout will stop the read at the end of whatever
  562. // the reader sends us.
  563. SmartcardExtension->ReaderExtension->SerialStatus.AmountInInQueue =
  564. sizeof(SmartcardExtension->ReaderExtension->TempXferBuf);
  565. // Read the characters
  566. irpStack->MajorFunction = IRP_MJ_READ;
  567. irpStack->Parameters.Read.Length =
  568. sizeof(SmartcardExtension->ReaderExtension->TempXferBuf);
  569. irpStack->MinorFunction = 0UL;
  570. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  571. SmartcardExtension->ReaderExtension->TempXferBuf;
  572. }
  573. break;
  574. case 3:
  575. //
  576. // Send the characers we read to the input filter then setup for read input
  577. // queue again (in case some characters came in while we were processing the
  578. // ones we just read).
  579. //
  580. for (indx = 0; indx < Irp->IoStatus.Information; indx++) {
  581. if (!Lit220InputFilter(
  582. SmartcardExtension->ReaderExtension->TempXferBuf[indx],
  583. SmartcardExtension
  584. ))
  585. {
  586. // An invalid character was received so stop sending the rest of
  587. // the data to the filter because it is probably corrupted.
  588. break;
  589. }
  590. }
  591. // Check if we are in the middle of a block of data
  592. if (SmartcardExtension->ReaderExtension->ReceivedByteNo != 0) {
  593. // Start the timeout timer. If we don't get the rest of this
  594. // data block in a few seconds we will timeout. This prevents
  595. // communication problems between the reader and the PC causing
  596. // locking up a T=0 card for too long.
  597. Lit220ScheduleTimer(
  598. SmartcardExtension,
  599. Lit220StartTimer
  600. );
  601. }
  602. //
  603. // Read done - start all over again with the wait_on_mask
  604. //
  605. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  606. irpStack->MinorFunction = 0UL;
  607. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  608. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask);
  609. irpStack->Parameters.DeviceIoControl.IoControlCode =
  610. IOCTL_SERIAL_WAIT_ON_MASK;
  611. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  612. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask;
  613. // Reset SerialEventState value
  614. SmartcardExtension->ReaderExtension->SerialEventState = 0;
  615. break;
  616. default:
  617. SmartcardDebug(
  618. DEBUG_ERROR,
  619. ("%s!Lit220SerialEventCallback: Error SerialEventState is out of bounds - resetting to 0\n",
  620. DRIVER_NAME)
  621. );
  622. //
  623. // We should never get here, but if we do we should try to recover the
  624. // best we can by setting up for the wait_on_mask.
  625. //
  626. // Reset value
  627. SmartcardExtension->ReaderExtension->SerialEventState = 0;
  628. // Setup for next callback
  629. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  630. irpStack->MinorFunction = 0UL;
  631. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  632. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask);
  633. irpStack->Parameters.DeviceIoControl.IoControlCode =
  634. IOCTL_SERIAL_WAIT_ON_MASK;
  635. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  636. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask;
  637. }
  638. // We always call this same function when we complete a call
  639. IoSetCompletionRoutine(
  640. SmartcardExtension->ReaderExtension->CardStatus.Irp,
  641. Lit220SerialEventCallback,
  642. SmartcardExtension,
  643. TRUE,
  644. TRUE,
  645. TRUE
  646. );
  647. // Call the serial driver
  648. status = IoCallDriver(
  649. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  650. SmartcardExtension->ReaderExtension->CardStatus.Irp
  651. );
  652. // Return STATUS_MORE_PROCESSING_REQUIRED so our IRP stays around
  653. return STATUS_MORE_PROCESSING_REQUIRED;
  654. }
  655. VOID
  656. Lit220ScheduleTimer(
  657. IN PSMARTCARD_EXTENSION SmartcardExtension,
  658. IN PIO_WORKITEM_ROUTINE Routine
  659. )
  660. {
  661. PIO_WORKITEM workItem = IoAllocateWorkItem(
  662. SmartcardExtension->OsData->DeviceObject
  663. );
  664. if (workItem != NULL) {
  665. IoQueueWorkItem(
  666. workItem,
  667. Routine,
  668. CriticalWorkQueue,
  669. workItem
  670. );
  671. }
  672. }
  673. VOID
  674. Lit220StartTimer(
  675. IN PDEVICE_OBJECT DeviceObject,
  676. IN PIO_WORKITEM WorkItem
  677. )
  678. /*++
  679. Routine Description:
  680. This routine starts the timeout timer. The function is executed as a worker
  681. thread so IoStartTimer does not get called at the wrong IRQL.
  682. --*/
  683. {
  684. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  685. PAGED_CODE();
  686. deviceExtension->EntryCount = 0;
  687. IoStartTimer(DeviceObject);
  688. IoFreeWorkItem(WorkItem);
  689. }
  690. VOID
  691. Lit220StopTimer(
  692. IN PDEVICE_OBJECT DeviceObject,
  693. IN PIO_WORKITEM WorkItem
  694. )
  695. /*++
  696. Routine Description:
  697. This routine stops the timeout timer. The function is executed as a worker
  698. thread so IoStopTimer does not get called at the wrong IRQL.
  699. --*/
  700. {
  701. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  702. PAGED_CODE();
  703. IoStopTimer(DeviceObject);
  704. IoFreeWorkItem(WorkItem);
  705. }
  706. VOID
  707. Lit220ReceiveBlockTimeout(
  708. IN PDEVICE_OBJECT DeviceObject,
  709. IN PVOID Context
  710. )
  711. /*++
  712. Routine Description:
  713. This routine is timeout callback. A timeout is setup every time we get an
  714. incomplete block of data. Once we receive the complete block the timeout
  715. will be canceled. The type of timer we use for the timeout gets called
  716. once every second. We want to time out after a few seconds, so we keep track
  717. of how many time we get called and then timeout after we have been called
  718. 5 times.
  719. --*/
  720. {
  721. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  722. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  723. PREADER_EXTENSION readerExtension = smartcardExtension->ReaderExtension;
  724. if (readerExtension->DataByteNo == readerExtension->DataLength.l.l0) {
  725. // Stop the timer we got all the bytes we need
  726. Lit220ScheduleTimer(
  727. smartcardExtension,
  728. Lit220StopTimer
  729. );
  730. return;
  731. }
  732. if (++deviceExtension->EntryCount >= 5) {
  733. SmartcardDebug(
  734. DEBUG_ERROR,
  735. ("%s!Lit220ReceiveBlockTimeout: Communication with reader timed-out\n",
  736. DRIVER_NAME)
  737. );
  738. // Process the timeout
  739. Lit220ProcessNack(smartcardExtension);
  740. // A timeout has occured schedule worker thread to
  741. // stop the timer
  742. Lit220ScheduleTimer(
  743. smartcardExtension,
  744. Lit220StopTimer
  745. );
  746. deviceExtension->EntryCount = 0;
  747. }
  748. }