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.

1002 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997 SCM Microsystems, Inc.
  3. Module Name:
  4. usbcom.c
  5. Abstract:
  6. Hardware access functions for USB smartcard reader
  7. Environment:
  8. WDM
  9. Revision History:
  10. PP 01/19/1999 1.01
  11. PP 12/18/1998 1.00 Initial Version
  12. --*/
  13. #include "common.h"
  14. #include "stcCmd.h"
  15. #include "usbcom.h"
  16. #include "stcusbnt.h"
  17. #pragma optimize( "", off )
  18. NTSTATUS STCtoNT(
  19. UCHAR ucData[])
  20. /*++
  21. Routine Description:
  22. Error code translation routine
  23. Arguments:
  24. ucData Error code returned by the STC
  25. Return Value:
  26. Corresponding NT error code
  27. --*/
  28. {
  29. USHORT usCode = ucData[0]*0x100 +ucData[1];
  30. NTSTATUS NtStatus;
  31. switch (usCode)
  32. {
  33. case 0x9000:
  34. NtStatus = STATUS_SUCCESS;
  35. break;
  36. case 0x5800:
  37. NtStatus = STATUS_UNSUCCESSFUL;
  38. break;
  39. case 0x2000:
  40. NtStatus = STATUS_UNSUCCESSFUL;
  41. break;
  42. case 0x4000:
  43. NtStatus = STATUS_UNSUCCESSFUL;
  44. break;
  45. case 0x64A1:
  46. NtStatus = STATUS_NO_MEDIA;
  47. break;
  48. case 0x64A0:
  49. NtStatus = STATUS_MEDIA_CHANGED;
  50. break;
  51. case 0x6203:
  52. NtStatus = STATUS_UNSUCCESSFUL;
  53. break;
  54. case 0x6300:
  55. NtStatus = STATUS_UNSUCCESSFUL;
  56. break;
  57. case 0x6500:
  58. NtStatus = STATUS_UNSUCCESSFUL;
  59. break;
  60. case 0x6A00:
  61. NtStatus = STATUS_UNSUCCESSFUL;
  62. break;
  63. case 0x6A80:
  64. NtStatus = STATUS_UNSUCCESSFUL;
  65. break;
  66. default:
  67. NtStatus = STATUS_UNSUCCESSFUL;
  68. break;
  69. }
  70. return(NtStatus);
  71. }
  72. //******************************************************************************
  73. //
  74. // UsbSyncCompletionRoutine()
  75. //
  76. // Completion routine used by UsbCallUSBD.
  77. //
  78. // Signals an Irp completion event and then returns MORE_PROCESSING_REQUIRED
  79. // to stop further completion of the Irp.
  80. //
  81. // If the Irp is one we allocated ourself, DeviceObject is NULL.
  82. //
  83. //******************************************************************************
  84. NTSTATUS
  85. UsbSyncCompletionRoutine (
  86. IN PDEVICE_OBJECT DeviceObject,
  87. IN PIRP Irp,
  88. IN PVOID Context
  89. )
  90. {
  91. PKEVENT kevent;
  92. kevent = (PKEVENT)Context;
  93. KeSetEvent(kevent,
  94. IO_NO_INCREMENT,
  95. FALSE);
  96. return STATUS_MORE_PROCESSING_REQUIRED;
  97. }
  98. //******************************************************************************
  99. //
  100. // UsbCallUSBD()
  101. //
  102. // Synchronously sends a URB down the device stack. Blocks until the request
  103. // completes normally or until the request is timed out and cancelled.
  104. //
  105. // Must be called at IRQL PASSIVE_LEVEL
  106. //
  107. //******************************************************************************
  108. NTSTATUS
  109. UsbCallUSBD (
  110. IN PDEVICE_OBJECT DeviceObject,
  111. IN PURB Urb
  112. )
  113. {
  114. PDEVICE_EXTENSION deviceExtension;
  115. KEVENT localevent;
  116. PIRP irp;
  117. PIO_STACK_LOCATION nextStack;
  118. NTSTATUS ntStatus;
  119. deviceExtension = DeviceObject->DeviceExtension;
  120. // Initialize the event we'll wait on
  121. //
  122. KeInitializeEvent(&localevent,
  123. SynchronizationEvent,
  124. FALSE);
  125. // Allocate the Irp
  126. //
  127. irp = IoAllocateIrp(deviceExtension->AttachedPDO->StackSize,
  128. FALSE);
  129. if (irp == NULL)
  130. {
  131. return STATUS_INSUFFICIENT_RESOURCES;
  132. }
  133. // Set the Irp parameters
  134. //
  135. nextStack = IoGetNextIrpStackLocation(irp);
  136. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  137. nextStack->Parameters.DeviceIoControl.IoControlCode =
  138. IOCTL_INTERNAL_USB_SUBMIT_URB;
  139. nextStack->Parameters.Others.Argument1 = Urb;
  140. // Set the completion routine, which will signal the event
  141. //
  142. IoSetCompletionRoutine(irp,
  143. UsbSyncCompletionRoutine,
  144. &localevent,
  145. TRUE, // InvokeOnSuccess
  146. TRUE, // InvokeOnError
  147. TRUE); // InvokeOnCancel
  148. // Pass the Irp & Urb down the stack
  149. //
  150. ntStatus = IoCallDriver(deviceExtension->AttachedPDO,
  151. irp);
  152. // If the request is pending, block until it completes
  153. //
  154. if (ntStatus == STATUS_PENDING)
  155. {
  156. LARGE_INTEGER timeout;
  157. // We used to wait for 1 second, but that made this timeout longer
  158. // than the polling period of 500ms. So, if this read failed (e.g.,
  159. // because of device or USB failure) and timeout, two more worker items
  160. // would get queued and eventually hundreds of working items would be
  161. // backed up. By reducing this timeout we have a good chance that this
  162. // will finish before the next item is queued. 450ms seems a good value.
  163. //
  164. timeout.QuadPart = -4500000; // 450ms
  165. ntStatus = KeWaitForSingleObject(&localevent,
  166. Executive,
  167. KernelMode,
  168. FALSE,
  169. &timeout);
  170. if (ntStatus == STATUS_TIMEOUT)
  171. {
  172. ntStatus = STATUS_IO_TIMEOUT;
  173. // Cancel the Irp we just sent.
  174. //
  175. IoCancelIrp(irp);
  176. // And wait until the cancel completes
  177. //
  178. KeWaitForSingleObject(&localevent,
  179. Executive,
  180. KernelMode,
  181. FALSE,
  182. NULL);
  183. }
  184. else
  185. {
  186. ntStatus = irp->IoStatus.Status;
  187. }
  188. }
  189. // Done with the Irp, now free it.
  190. //
  191. IoFreeIrp(irp);
  192. return ntStatus;
  193. }
  194. NTSTATUS
  195. UsbSelectInterfaces(
  196. IN PDEVICE_OBJECT DeviceObject,
  197. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
  198. /*++
  199. Routine Description:
  200. Initializes an USB reader with (possibly) multiple interfaces;
  201. This driver only supports one interface (with multiple endpoints).
  202. Arguments:
  203. DeviceObject - pointer to the device object for this instance of the device.
  204. ConfigurationDescriptor - pointer to the USB configuration
  205. descriptor containing the interface and endpoint
  206. descriptors.
  207. Return Value:
  208. NT status code
  209. --*/
  210. {
  211. PDEVICE_EXTENSION DeviceExtension= DeviceObject->DeviceExtension;
  212. NTSTATUS NtStatus;
  213. PURB pUrb = NULL;
  214. USHORT usSize;
  215. ULONG ulNumberOfInterfaces, i;
  216. UCHAR ucNumberOfPipes, ucAlternateSetting, ucMyInterfaceNumber;
  217. PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
  218. PUSBD_INTERFACE_INFORMATION InterfaceObject;
  219. // This driver only supports one interface, we must parse
  220. // the configuration descriptor for the interface
  221. // and remember the pipes.
  222. //
  223. pUrb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &usSize);
  224. if (pUrb)
  225. {
  226. //
  227. // USBD_ParseConfigurationDescriptorEx searches a given configuration
  228. // descriptor and returns a pointer to an interface that matches the
  229. // given search criteria. We only support one interface on this device
  230. //
  231. InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
  232. ConfigurationDescriptor,
  233. ConfigurationDescriptor, //search from start of config descriptro
  234. -1, // interface number not a criteria; we only support one interface
  235. -1, // not interested in alternate setting here either
  236. -1, // interface class not a criteria
  237. -1, // interface subclass not a criteria
  238. -1); // interface protocol not a criteria
  239. ASSERT( InterfaceDescriptor != NULL );
  240. InterfaceObject = &pUrb->UrbSelectConfiguration.Interface;
  241. for (i = 0; i < InterfaceObject->NumberOfPipes; i++)
  242. {
  243. InterfaceObject->Pipes[i].PipeFlags = 0;
  244. }
  245. UsbBuildSelectConfigurationRequest(
  246. pUrb,
  247. usSize,
  248. ConfigurationDescriptor);
  249. NtStatus = UsbCallUSBD(DeviceObject, pUrb);
  250. }
  251. else
  252. {
  253. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  254. }
  255. if(NtStatus == STATUS_SUCCESS)
  256. {
  257. // Save the configuration handle for this device
  258. DeviceExtension->ConfigurationHandle =
  259. pUrb->UrbSelectConfiguration.ConfigurationHandle;
  260. ASSERT(DeviceExtension->Interface == NULL);
  261. DeviceExtension->Interface = ExAllocatePool(
  262. NonPagedPool,
  263. InterfaceObject->Length
  264. );
  265. if (DeviceExtension->Interface)
  266. {
  267. // save a copy of the interface information returned
  268. RtlCopyMemory(
  269. DeviceExtension->Interface,
  270. InterfaceObject,
  271. InterfaceObject->Length);
  272. }
  273. else
  274. {
  275. NtStatus = STATUS_NO_MEMORY;
  276. }
  277. }
  278. if (pUrb)
  279. {
  280. ExFreePool(pUrb);
  281. }
  282. return NtStatus;
  283. }
  284. NTSTATUS
  285. UsbConfigureDevice(
  286. IN PDEVICE_OBJECT DeviceObject)
  287. /*++
  288. Routine Description:
  289. Initializes a given instance of the device on the USB and
  290. selects and saves the configuration.
  291. Arguments:
  292. DeviceObject - pointer to the physical device object for this instance of the device.
  293. Return Value:
  294. NT status code
  295. --*/
  296. {
  297. PDEVICE_EXTENSION DeviceExtension= DeviceObject->DeviceExtension;
  298. NTSTATUS NtStatus;
  299. PURB pUrb = NULL;
  300. ULONG ulSize;
  301. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor = NULL;
  302. __try {
  303. pUrb = ExAllocatePool(
  304. NonPagedPool,
  305. sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST )
  306. );
  307. if( pUrb == NULL)
  308. {
  309. NtStatus = STATUS_NO_MEMORY;
  310. __leave;
  311. }
  312. // When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
  313. // in a call to UsbBuildGetDescriptorRequest(),
  314. // all interface, endpoint, class-specific, and vendor-specific descriptors
  315. // for the configuration also are retrieved.
  316. // The caller must allocate a buffer large enough to hold all of this
  317. // information or the data is truncated without error.
  318. // Therefore the 'siz' set below is just a 'good guess', and we may have to retry
  319. ulSize = sizeof( USB_CONFIGURATION_DESCRIPTOR ) + 16;
  320. // We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
  321. // has a big enough deviceExtension->UsbConfigurationDescriptor buffer not to truncate
  322. while( 1 )
  323. {
  324. ConfigurationDescriptor = ExAllocatePool( NonPagedPool, ulSize );
  325. if(ConfigurationDescriptor == NULL)
  326. {
  327. NtStatus = STATUS_NO_MEMORY;
  328. __leave;
  329. }
  330. UsbBuildGetDescriptorRequest(
  331. pUrb,
  332. sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
  333. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  334. 0,
  335. 0,
  336. ConfigurationDescriptor,
  337. NULL,
  338. ulSize,
  339. NULL );
  340. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  341. // if we got some data see if it was enough.
  342. // NOTE: we may get an error in URB because of buffer overrun
  343. if (pUrb->UrbControlDescriptorRequest.TransferBufferLength == 0 ||
  344. ConfigurationDescriptor->wTotalLength <= ulSize)
  345. {
  346. break;
  347. }
  348. ulSize = ConfigurationDescriptor->wTotalLength;
  349. ExFreePool(ConfigurationDescriptor);
  350. ConfigurationDescriptor = NULL;
  351. }
  352. //
  353. // We have the configuration descriptor for the configuration we want.
  354. // Now we issue the select configuration command to get
  355. // the pipes associated with this configuration.
  356. //
  357. if(NT_SUCCESS(NtStatus))
  358. {
  359. NtStatus = UsbSelectInterfaces(
  360. DeviceObject,
  361. ConfigurationDescriptor);
  362. }
  363. }
  364. __finally {
  365. if( pUrb )
  366. {
  367. ExFreePool( pUrb );
  368. }
  369. if( ConfigurationDescriptor )
  370. {
  371. ExFreePool( ConfigurationDescriptor );
  372. }
  373. }
  374. return NtStatus;
  375. }
  376. NTSTATUS
  377. UsbWriteSTCData(
  378. PREADER_EXTENSION ReaderExtension,
  379. PUCHAR pucData,
  380. ULONG ulSize)
  381. /*++
  382. Routine Description:
  383. Write data in the STC
  384. Arguments:
  385. ReaderExtension Context of the call
  386. APDU Buffer to write
  387. ulAPDULen Length of the buffer to write
  388. Return Value:
  389. --*/
  390. {
  391. NTSTATUS NTStatus = STATUS_SUCCESS;
  392. PUCHAR pucCmd;
  393. UCHAR ucResponse[3];
  394. BOOLEAN resend = TRUE;
  395. LONG Len;
  396. ULONG Index;
  397. LONG refLen = (LONG) ulSize;
  398. ULONG Retries;
  399. pucCmd = ReaderExtension->pExtBuffer;
  400. ReaderExtension->ulReadBufferLen = 0;
  401. // Build the write data command
  402. Len = refLen;
  403. Index = 0;
  404. while (resend == TRUE)
  405. {
  406. if(Len > 62)
  407. {
  408. Len = 62;
  409. resend = TRUE;
  410. }
  411. else
  412. {
  413. resend = FALSE;
  414. }
  415. *pucCmd = 0xA0;
  416. *(pucCmd+1) = (UCHAR) Len;
  417. memcpy( pucCmd + 2, pucData+Index, Len );
  418. Retries = USB_WRITE_RETRIES;
  419. do
  420. {
  421. // Send the Write data command
  422. NTStatus = UsbWrite( ReaderExtension, pucCmd, 2 + Len);
  423. if (NTStatus != STATUS_SUCCESS)
  424. {
  425. SmartcardDebug(
  426. DEBUG_DRIVER,
  427. ("%s!UsbWriteSTCData: write error %X \n",
  428. DRIVER_NAME,
  429. NTStatus)
  430. );
  431. break;
  432. }
  433. // Read the response
  434. NTStatus = UsbRead( ReaderExtension, ucResponse, 3);
  435. if (NTStatus != STATUS_SUCCESS)
  436. {
  437. SmartcardDebug(
  438. DEBUG_DRIVER,
  439. ("%s!UsbWriteSTCData: read error %X \n",
  440. DRIVER_NAME,
  441. NTStatus)
  442. );
  443. break;
  444. }
  445. else
  446. {
  447. // Test if what we read is really a response to a write
  448. if(ucResponse[0] != 0xA0)
  449. {
  450. NTStatus = STCtoNT(ucResponse);
  451. }
  452. }
  453. } while(( NTStatus != STATUS_SUCCESS ) && --Retries );
  454. if( NTStatus != STATUS_SUCCESS )
  455. break;
  456. Index += 62;
  457. Len = refLen - 62;
  458. refLen = refLen - 62;
  459. }
  460. return STATUS_SUCCESS;
  461. }
  462. NTSTATUS
  463. UsbReadSTCData(
  464. PREADER_EXTENSION ReaderExtension,
  465. PUCHAR pucData,
  466. ULONG ulDataLen)
  467. /*++
  468. Routine Description:
  469. Read data from the STC
  470. Arguments:
  471. ReaderExtension Context of the call
  472. ulAPDULen Length of the buffer to write
  473. pucData Output Buffer
  474. Return Value:
  475. --*/
  476. {
  477. NTSTATUS NTStatus = STATUS_SUCCESS;
  478. UCHAR ucCmd[1];
  479. PUCHAR pucResponse;
  480. int i;
  481. ULONG ulLenExpected = ulDataLen;
  482. ULONG Index=0;
  483. BOOLEAN SendReadCommand = TRUE;
  484. LARGE_INTEGER Begin;
  485. LARGE_INTEGER End;
  486. pucResponse = ReaderExtension->pExtBuffer;
  487. KeQuerySystemTime( &Begin );
  488. End = Begin;
  489. End.QuadPart = End.QuadPart + (LONGLONG)10 * 1000 * ReaderExtension->ReadTimeout;
  490. // First let see if we have not already read the data that
  491. // we need
  492. if(ReaderExtension->ulReadBufferLen != 0)
  493. {
  494. if(ReaderExtension->ulReadBufferLen >= ulLenExpected)
  495. {
  496. // all the data that we need are available
  497. memcpy(pucData,ReaderExtension->ucReadBuffer,ulLenExpected);
  498. ReaderExtension->ulReadBufferLen = ReaderExtension->ulReadBufferLen - ulLenExpected;
  499. if(ReaderExtension->ulReadBufferLen != 0)
  500. {
  501. memcpy(
  502. ReaderExtension->ucReadBuffer,
  503. ReaderExtension->ucReadBuffer+ulLenExpected,
  504. ReaderExtension->ulReadBufferLen);
  505. }
  506. SendReadCommand = FALSE;
  507. }
  508. else
  509. {
  510. // all the data that we need are not available
  511. memcpy(pucData,ReaderExtension->ucReadBuffer,ReaderExtension->ulReadBufferLen);
  512. ulLenExpected = ulLenExpected - ReaderExtension->ulReadBufferLen;
  513. Index = ReaderExtension->ulReadBufferLen;
  514. ReaderExtension->ulReadBufferLen = 0;
  515. SendReadCommand = TRUE;
  516. }
  517. }
  518. while( SendReadCommand == TRUE)
  519. {
  520. // Build the Read Register command
  521. ucCmd[0] = 0xE0;
  522. NTStatus = UsbWrite( ReaderExtension, ucCmd, 1);
  523. if (NTStatus != STATUS_SUCCESS)
  524. {
  525. SmartcardDebug(
  526. DEBUG_DRIVER,
  527. ("%s!UsbReadSTCData: write error %X \n",
  528. DRIVER_NAME,
  529. NTStatus)
  530. );
  531. break;
  532. }
  533. NTStatus = UsbRead( ReaderExtension, pucResponse, 64);
  534. if (NTStatus != STATUS_SUCCESS)
  535. {
  536. SmartcardDebug(
  537. DEBUG_DRIVER,
  538. ("%s!UsbReadSTCData: read error %X \n",
  539. DRIVER_NAME,
  540. NTStatus)
  541. );
  542. break;
  543. }
  544. // Test if what we read is really a READ DATA frame
  545. if(*pucResponse != 0xE0)
  546. {
  547. if(*pucResponse == 0x64 && *(pucResponse + 1) == 0xA0)
  548. {
  549. NTStatus = STATUS_NO_MEDIA;
  550. }
  551. else
  552. {
  553. NTStatus = STCtoNT(pucResponse);
  554. }
  555. break;
  556. }
  557. // If there is no data available
  558. if (*(pucResponse + 1) == 0)
  559. {
  560. KeQuerySystemTime( &Begin );
  561. if(RtlLargeIntegerGreaterThan(End, Begin))
  562. {
  563. SendReadCommand = TRUE;
  564. }
  565. else
  566. {
  567. ReaderExtension->ulReadBufferLen = 0;
  568. SmartcardDebug(
  569. DEBUG_DRIVER,
  570. ("%s!UsbReadSTCData: Timeout %X \n",
  571. DRIVER_NAME,
  572. STATUS_IO_TIMEOUT));
  573. NTStatus =STATUS_IO_TIMEOUT;
  574. break;
  575. }
  576. }
  577. if ((ULONG) *(pucResponse+1) < ulLenExpected)
  578. {
  579. memcpy(pucData+Index,pucResponse+2,(ULONG) *(pucResponse+1));
  580. Index = Index + (ULONG) *(pucResponse+1);
  581. ulLenExpected = ulLenExpected - (ULONG) *(pucResponse+1);
  582. SendReadCommand = TRUE;
  583. }
  584. else
  585. {
  586. SendReadCommand = FALSE;
  587. memcpy(pucData+Index,pucResponse+2,ulLenExpected);
  588. if((ULONG) *(pucResponse+1) > ulLenExpected)
  589. {
  590. memcpy(
  591. ReaderExtension->ucReadBuffer,
  592. pucResponse+ulLenExpected+2,
  593. (ULONG) *(pucResponse+1) - ulLenExpected);
  594. ReaderExtension->ulReadBufferLen =
  595. (ULONG) *(pucResponse+1) - ulLenExpected;
  596. }
  597. else
  598. {
  599. ReaderExtension->ulReadBufferLen = 0;
  600. }
  601. }
  602. }
  603. return NTStatus;
  604. }
  605. NTSTATUS
  606. UsbWriteSTCRegister(
  607. PREADER_EXTENSION ReaderExtension,
  608. UCHAR ucAddress,
  609. ULONG ulSize,
  610. PUCHAR pucValue)
  611. /*++
  612. Routine Description:
  613. Arguments:
  614. Return Value:
  615. --*/
  616. {
  617. NTSTATUS NTStatus = STATUS_SUCCESS;
  618. PUCHAR pucCmd;
  619. UCHAR ucResponse[2];
  620. if(ulSize > 16)
  621. {
  622. return STATUS_UNSUCCESSFUL;
  623. }
  624. pucCmd = ReaderExtension->pExtBuffer;
  625. ReaderExtension->ulReadBufferLen = 0;
  626. // Build the write register command
  627. *pucCmd = 0x80 | ucAddress;
  628. *(pucCmd+1) = (UCHAR) ulSize;
  629. memcpy( pucCmd + 2, pucValue, ulSize );
  630. // Send the Write Register command
  631. NTStatus = UsbWrite( ReaderExtension, pucCmd, 2 + ulSize);
  632. if (NTStatus == STATUS_SUCCESS)
  633. {
  634. // Read the acknowledge
  635. NTStatus = UsbRead( ReaderExtension, ucResponse, 2);
  636. if (NTStatus == STATUS_SUCCESS)
  637. {
  638. NTStatus = STCtoNT(ucResponse);
  639. }
  640. }
  641. return NTStatus;
  642. }
  643. NTSTATUS
  644. UsbReadSTCRegister(
  645. PREADER_EXTENSION ReaderExtension,
  646. UCHAR ucAddress,
  647. ULONG ulSize,
  648. PUCHAR pucValue)
  649. /*++
  650. Routine Description:
  651. Arguments:
  652. Return Value:
  653. --*/
  654. {
  655. NTSTATUS NTStatus = STATUS_SUCCESS;
  656. UCHAR ucCmd[2];
  657. PUCHAR pucResponse;
  658. if(ulSize > 16)
  659. {
  660. return STATUS_UNSUCCESSFUL;
  661. }
  662. pucResponse = ReaderExtension->pExtBuffer;
  663. // Build the Read Register command
  664. ucCmd[0] = 0xC0 | ucAddress;
  665. ucCmd[1] = (UCHAR) ulSize;
  666. // Send the Read Register command
  667. NTStatus = UsbWrite( ReaderExtension, ucCmd, 2);
  668. if (NTStatus == STATUS_SUCCESS)
  669. {
  670. // Read the response from the reader
  671. NTStatus = UsbRead(
  672. ReaderExtension,
  673. pucResponse,
  674. 6
  675. );
  676. if (NTStatus == STATUS_SUCCESS)
  677. {
  678. // Test if what we read is really a READ frame
  679. if(*pucResponse == 0x21)
  680. {
  681. if(*(pucResponse + 1) > 4)
  682. {
  683. NTStatus = STATUS_BUFFER_TOO_SMALL;
  684. }
  685. else
  686. {
  687. memcpy(
  688. pucValue,
  689. pucResponse + 2,
  690. (ULONG) *(pucResponse + 1)
  691. );
  692. }
  693. }
  694. else
  695. {
  696. NTStatus = STCtoNT(pucResponse);
  697. }
  698. }
  699. }
  700. return NTStatus;
  701. }
  702. NTSTATUS
  703. UsbGetFirmwareRevision(
  704. PREADER_EXTENSION ReaderExtension)
  705. /*++
  706. Description:
  707. Arguments:
  708. Return Value:
  709. --*/
  710. {
  711. NTSTATUS NTStatus = STATUS_SUCCESS;
  712. UCHAR ucCmd[1];
  713. UCHAR ucResponse[4];
  714. ucCmd[0] = 0xE1;
  715. NTStatus = UsbWrite( ReaderExtension, ucCmd, 2 );
  716. if( NTStatus == STATUS_SUCCESS )
  717. {
  718. ReaderExtension->ReadTimeout = 1000;
  719. NTStatus = UsbRead( ReaderExtension, ucResponse, 4 );
  720. if( NTStatus == STATUS_SUCCESS )
  721. {
  722. ReaderExtension->FirmwareMajor = ucResponse[ 2 ];
  723. ReaderExtension->FirmwareMinor = ucResponse[ 3 ];
  724. }
  725. }
  726. return NTStatus ;
  727. }
  728. NTSTATUS
  729. UsbRead(
  730. PREADER_EXTENSION ReaderExtension,
  731. PUCHAR pData,
  732. ULONG DataLen )
  733. /*++
  734. Description:
  735. Read data on the USB bus
  736. Arguments:
  737. ReaderExtension context of call
  738. pData ptr to data buffer
  739. DataLen length of data buffer
  740. pNBytes number of bytes returned
  741. Return Value:
  742. STATUS_SUCCESS
  743. STATUS_BUFFER_TOO_SMALL
  744. STATUS_UNSUCCESSFUL
  745. --*/
  746. {
  747. NTSTATUS NtStatus = STATUS_SUCCESS;
  748. PURB pUrb;
  749. USBD_INTERFACE_INFORMATION* pInterfaceInfo;
  750. USBD_PIPE_INFORMATION* pPipeInfo;
  751. PDEVICE_OBJECT DeviceObject = ReaderExtension->DeviceObject;
  752. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  753. ULONG ulSize;
  754. pInterfaceInfo = DeviceExtension->Interface;
  755. ASSERT(pInterfaceInfo != NULL);
  756. if (pInterfaceInfo == NULL) {
  757. // The device has likely been disconnected during hibernate / stand by
  758. return STATUS_DEVICE_NOT_CONNECTED;
  759. }
  760. // Read pipe number is 0 on this device
  761. pPipeInfo = &( pInterfaceInfo->Pipes[ 0 ] );
  762. ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  763. pUrb = ReaderExtension->pUrb;
  764. UsbBuildInterruptOrBulkTransferRequest(
  765. pUrb,
  766. (USHORT)ulSize,
  767. pPipeInfo->PipeHandle,
  768. pData,
  769. NULL,
  770. DataLen,
  771. USBD_SHORT_TRANSFER_OK,
  772. NULL);
  773. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  774. return NtStatus;
  775. }
  776. NTSTATUS
  777. UsbWrite(
  778. PREADER_EXTENSION ReaderExtension,
  779. PUCHAR pData,
  780. ULONG DataLen)
  781. /*++
  782. Description:
  783. Write data on the usb port
  784. Arguments:
  785. ReaderExtension context of call
  786. pData ptr to data buffer
  787. DataLen length of data buffer (exclusive LRC!)
  788. Return Value:
  789. return value of
  790. --*/
  791. {
  792. NTSTATUS NtStatus = STATUS_SUCCESS;
  793. PURB pUrb;
  794. USBD_INTERFACE_INFORMATION* pInterfaceInfo;
  795. USBD_PIPE_INFORMATION* pPipeInfo;
  796. PDEVICE_OBJECT DeviceObject = ReaderExtension->DeviceObject;
  797. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  798. ULONG ulSize;
  799. pInterfaceInfo = DeviceExtension->Interface;
  800. ASSERT(pInterfaceInfo != NULL);
  801. if (pInterfaceInfo == NULL) {
  802. // The device has likely been disconnected during hibernate / stand by
  803. return STATUS_DEVICE_NOT_CONNECTED;
  804. }
  805. // Write pipe number is 1 on this device
  806. pPipeInfo = &( pInterfaceInfo->Pipes[ 1 ] );
  807. ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  808. pUrb = ReaderExtension->pUrb;
  809. UsbBuildInterruptOrBulkTransferRequest(
  810. pUrb,
  811. (USHORT)ulSize,
  812. pPipeInfo->PipeHandle,
  813. pData,
  814. NULL,
  815. DataLen,
  816. USBD_SHORT_TRANSFER_OK,
  817. NULL );
  818. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  819. return NtStatus;
  820. }