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.

1047 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. // If the request was not sucessful, delay for 1 second. (Why?)
  193. //
  194. if (ntStatus != STATUS_SUCCESS)
  195. {
  196. SysDelay(1000);
  197. }
  198. return ntStatus;
  199. }
  200. NTSTATUS
  201. UsbSelectInterfaces(
  202. IN PDEVICE_OBJECT DeviceObject,
  203. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
  204. /*++
  205. Routine Description:
  206. Initializes an USB reader with (possibly) multiple interfaces;
  207. This driver only supports one interface (with multiple endpoints).
  208. Arguments:
  209. DeviceObject - pointer to the device object for this instance of the device.
  210. ConfigurationDescriptor - pointer to the USB configuration
  211. descriptor containing the interface and endpoint
  212. descriptors.
  213. Return Value:
  214. NT status code
  215. --*/
  216. {
  217. PDEVICE_EXTENSION DeviceExtension= DeviceObject->DeviceExtension;
  218. NTSTATUS NtStatus;
  219. PURB pUrb = NULL;
  220. USHORT usSize;
  221. ULONG ulNumberOfInterfaces, i;
  222. UCHAR ucNumberOfPipes, ucAlternateSetting, ucMyInterfaceNumber;
  223. PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
  224. PUSBD_INTERFACE_INFORMATION InterfaceObject;
  225. // This driver only supports one interface, we must parse
  226. // the configuration descriptor for the interface
  227. // and remember the pipes.
  228. //
  229. pUrb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &usSize);
  230. if (pUrb)
  231. {
  232. //
  233. // USBD_ParseConfigurationDescriptorEx searches a given configuration
  234. // descriptor and returns a pointer to an interface that matches the
  235. // given search criteria. We only support one interface on this device
  236. //
  237. InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
  238. ConfigurationDescriptor,
  239. ConfigurationDescriptor, //search from start of config descriptro
  240. -1, // interface number not a criteria; we only support one interface
  241. -1, // not interested in alternate setting here either
  242. -1, // interface class not a criteria
  243. -1, // interface subclass not a criteria
  244. -1); // interface protocol not a criteria
  245. ASSERT( InterfaceDescriptor != NULL );
  246. InterfaceObject = &pUrb->UrbSelectConfiguration.Interface;
  247. for (i = 0; i < InterfaceObject->NumberOfPipes; i++)
  248. {
  249. InterfaceObject->Pipes[i].PipeFlags = 0;
  250. }
  251. UsbBuildSelectConfigurationRequest(
  252. pUrb,
  253. usSize,
  254. ConfigurationDescriptor);
  255. NtStatus = UsbCallUSBD(DeviceObject, pUrb);
  256. }
  257. else
  258. {
  259. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  260. }
  261. if(NtStatus == STATUS_SUCCESS)
  262. {
  263. // Save the configuration handle for this device
  264. DeviceExtension->ConfigurationHandle =
  265. pUrb->UrbSelectConfiguration.ConfigurationHandle;
  266. ASSERT(DeviceExtension->Interface == NULL);
  267. DeviceExtension->Interface = ExAllocatePool(
  268. NonPagedPool,
  269. InterfaceObject->Length
  270. );
  271. if (DeviceExtension->Interface)
  272. {
  273. // save a copy of the interface information returned
  274. RtlCopyMemory(
  275. DeviceExtension->Interface,
  276. InterfaceObject,
  277. InterfaceObject->Length);
  278. }
  279. else
  280. {
  281. NtStatus = STATUS_NO_MEMORY;
  282. }
  283. }
  284. if (pUrb)
  285. {
  286. ExFreePool(pUrb);
  287. }
  288. return NtStatus;
  289. }
  290. NTSTATUS
  291. UsbConfigureDevice(
  292. IN PDEVICE_OBJECT DeviceObject)
  293. /*++
  294. Routine Description:
  295. Initializes a given instance of the device on the USB and
  296. selects and saves the configuration.
  297. Arguments:
  298. DeviceObject - pointer to the physical device object for this instance of the device.
  299. Return Value:
  300. NT status code
  301. --*/
  302. {
  303. PDEVICE_EXTENSION DeviceExtension= DeviceObject->DeviceExtension;
  304. NTSTATUS NtStatus;
  305. PURB pUrb = NULL;
  306. ULONG ulSize;
  307. PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor = NULL;
  308. __try {
  309. pUrb = ExAllocatePool(
  310. NonPagedPool,
  311. sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST )
  312. );
  313. if( pUrb == NULL)
  314. {
  315. NtStatus = STATUS_NO_MEMORY;
  316. __leave;
  317. }
  318. // When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
  319. // in a call to UsbBuildGetDescriptorRequest(),
  320. // all interface, endpoint, class-specific, and vendor-specific descriptors
  321. // for the configuration also are retrieved.
  322. // The caller must allocate a buffer large enough to hold all of this
  323. // information or the data is truncated without error.
  324. // Therefore the 'siz' set below is just a 'good guess', and we may have to retry
  325. ulSize = sizeof( USB_CONFIGURATION_DESCRIPTOR ) + 16;
  326. // We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
  327. // has a big enough deviceExtension->UsbConfigurationDescriptor buffer not to truncate
  328. while( 1 )
  329. {
  330. ConfigurationDescriptor = ExAllocatePool( NonPagedPool, ulSize );
  331. if(ConfigurationDescriptor == NULL)
  332. {
  333. NtStatus = STATUS_NO_MEMORY;
  334. __leave;
  335. }
  336. UsbBuildGetDescriptorRequest(
  337. pUrb,
  338. sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
  339. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  340. 0,
  341. 0,
  342. ConfigurationDescriptor,
  343. NULL,
  344. ulSize,
  345. NULL );
  346. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  347. // if we got some data see if it was enough.
  348. // NOTE: we may get an error in URB because of buffer overrun
  349. if (pUrb->UrbControlDescriptorRequest.TransferBufferLength == 0 ||
  350. ConfigurationDescriptor->wTotalLength <= ulSize)
  351. {
  352. break;
  353. }
  354. ulSize = ConfigurationDescriptor->wTotalLength;
  355. ExFreePool(ConfigurationDescriptor);
  356. ConfigurationDescriptor = NULL;
  357. }
  358. //
  359. // We have the configuration descriptor for the configuration we want.
  360. // Now we issue the select configuration command to get
  361. // the pipes associated with this configuration.
  362. //
  363. if(NT_SUCCESS(NtStatus))
  364. {
  365. NtStatus = UsbSelectInterfaces(
  366. DeviceObject,
  367. ConfigurationDescriptor);
  368. }
  369. }
  370. __finally {
  371. if( pUrb )
  372. {
  373. ExFreePool( pUrb );
  374. }
  375. if( ConfigurationDescriptor )
  376. {
  377. ExFreePool( ConfigurationDescriptor );
  378. }
  379. }
  380. return NtStatus;
  381. }
  382. NTSTATUS
  383. UsbWriteSTCData(
  384. PREADER_EXTENSION ReaderExtension,
  385. PUCHAR pucData,
  386. ULONG ulSize)
  387. /*++
  388. Routine Description:
  389. Write data in the STC
  390. Arguments:
  391. ReaderExtension Context of the call
  392. APDU Buffer to write
  393. ulAPDULen Length of the buffer to write
  394. Return Value:
  395. --*/
  396. {
  397. NTSTATUS NTStatus = STATUS_SUCCESS;
  398. PUCHAR pucCmd;
  399. UCHAR ucResponse[3];
  400. BOOLEAN resend = TRUE;
  401. LONG Len;
  402. ULONG Index;
  403. LONG refLen = (LONG) ulSize;
  404. ULONG Retries;
  405. pucCmd = ExAllocatePool( NonPagedPool, MIN_BUFFER_SIZE);
  406. if(pucCmd == NULL)
  407. {
  408. return STATUS_NO_MEMORY;
  409. }
  410. ReaderExtension->ulReadBufferLen = 0;
  411. // Build the write data command
  412. Len = refLen;
  413. Index = 0;
  414. while (resend == TRUE)
  415. {
  416. if(Len > 62)
  417. {
  418. Len = 62;
  419. resend = TRUE;
  420. }
  421. else
  422. {
  423. resend = FALSE;
  424. }
  425. *pucCmd = 0xA0;
  426. *(pucCmd+1) = (UCHAR) Len;
  427. memcpy( pucCmd + 2, pucData+Index, Len );
  428. Retries = USB_WRITE_RETRIES;
  429. do
  430. {
  431. // Send the Write data command
  432. NTStatus = UsbWrite( ReaderExtension, pucCmd, 2 + Len);
  433. if (NTStatus != STATUS_SUCCESS)
  434. {
  435. SmartcardDebug(
  436. DEBUG_DRIVER,
  437. ("%s!UsbWriteSTCData: write error %X \n",
  438. DRIVER_NAME,
  439. NTStatus)
  440. );
  441. break;
  442. }
  443. // Read the response
  444. NTStatus = UsbRead( ReaderExtension, ucResponse, 3);
  445. if (NTStatus != STATUS_SUCCESS)
  446. {
  447. SmartcardDebug(
  448. DEBUG_DRIVER,
  449. ("%s!UsbWriteSTCData: read error %X \n",
  450. DRIVER_NAME,
  451. NTStatus)
  452. );
  453. break;
  454. }
  455. else
  456. {
  457. // Test if what we read is really a response to a write
  458. if(ucResponse[0] != 0xA0)
  459. {
  460. NTStatus = STCtoNT(ucResponse);
  461. }
  462. }
  463. } while(( NTStatus != STATUS_SUCCESS ) && --Retries );
  464. if( NTStatus != STATUS_SUCCESS )
  465. break;
  466. Index += 62;
  467. Len = refLen - 62;
  468. refLen = refLen - 62;
  469. }
  470. ExFreePool( pucCmd );
  471. return STATUS_SUCCESS;
  472. }
  473. NTSTATUS
  474. UsbReadSTCData(
  475. PREADER_EXTENSION ReaderExtension,
  476. PUCHAR pucData,
  477. ULONG ulDataLen)
  478. /*++
  479. Routine Description:
  480. Read data from the STC
  481. Arguments:
  482. ReaderExtension Context of the call
  483. ulAPDULen Length of the buffer to write
  484. pucData Output Buffer
  485. Return Value:
  486. --*/
  487. {
  488. NTSTATUS NTStatus = STATUS_SUCCESS;
  489. UCHAR ucCmd[1];
  490. PUCHAR pucResponse;
  491. int i;
  492. ULONG ulLenExpected = ulDataLen;
  493. ULONG Index=0;
  494. BOOLEAN SendReadCommand = TRUE;
  495. LARGE_INTEGER Begin;
  496. LARGE_INTEGER End;
  497. pucResponse = ExAllocatePool( NonPagedPool, MIN_BUFFER_SIZE);
  498. if(pucResponse == NULL)
  499. {
  500. return STATUS_NO_MEMORY;
  501. }
  502. KeQuerySystemTime( &Begin );
  503. End = Begin;
  504. End.QuadPart = End.QuadPart + (LONGLONG)10 * 1000 * ReaderExtension->ReadTimeout;
  505. // First let see if we have not already read the data that
  506. // we need
  507. if(ReaderExtension->ulReadBufferLen != 0)
  508. {
  509. if(ReaderExtension->ulReadBufferLen >= ulLenExpected)
  510. {
  511. // all the data that we need are available
  512. memcpy(pucData,ReaderExtension->ucReadBuffer,ulLenExpected);
  513. ReaderExtension->ulReadBufferLen = ReaderExtension->ulReadBufferLen - ulLenExpected;
  514. if(ReaderExtension->ulReadBufferLen != 0)
  515. {
  516. memcpy(
  517. ReaderExtension->ucReadBuffer,
  518. ReaderExtension->ucReadBuffer+ulLenExpected,
  519. ReaderExtension->ulReadBufferLen);
  520. }
  521. SendReadCommand = FALSE;
  522. }
  523. else
  524. {
  525. // all the data that we need are not available
  526. memcpy(pucData,ReaderExtension->ucReadBuffer,ReaderExtension->ulReadBufferLen);
  527. ulLenExpected = ulLenExpected - ReaderExtension->ulReadBufferLen;
  528. Index = ReaderExtension->ulReadBufferLen;
  529. ReaderExtension->ulReadBufferLen = 0;
  530. SendReadCommand = TRUE;
  531. }
  532. }
  533. while( SendReadCommand == TRUE)
  534. {
  535. // Build the Read Register command
  536. ucCmd[0] = 0xE0;
  537. NTStatus = UsbWrite( ReaderExtension, ucCmd, 1);
  538. if (NTStatus != STATUS_SUCCESS)
  539. {
  540. SmartcardDebug(
  541. DEBUG_DRIVER,
  542. ("%s!UsbReadSTCData: write error %X \n",
  543. DRIVER_NAME,
  544. NTStatus)
  545. );
  546. break;
  547. }
  548. NTStatus = UsbRead( ReaderExtension, pucResponse, 64);
  549. if (NTStatus != STATUS_SUCCESS)
  550. {
  551. SmartcardDebug(
  552. DEBUG_DRIVER,
  553. ("%s!UsbReadSTCData: read error %X \n",
  554. DRIVER_NAME,
  555. NTStatus)
  556. );
  557. break;
  558. }
  559. // Test if what we read is really a READ DATA frame
  560. if(*pucResponse != 0xE0)
  561. {
  562. if(*pucResponse == 0x64 && *(pucResponse + 1) == 0xA0)
  563. {
  564. NTStatus = STATUS_NO_MEDIA;
  565. }
  566. else
  567. {
  568. NTStatus = STCtoNT(pucResponse);
  569. }
  570. break;
  571. }
  572. // If there is no data available
  573. if (*(pucResponse + 1) == 0)
  574. {
  575. KeQuerySystemTime( &Begin );
  576. if(RtlLargeIntegerGreaterThan(End, Begin))
  577. {
  578. SendReadCommand = TRUE;
  579. }
  580. else
  581. {
  582. ReaderExtension->ulReadBufferLen = 0;
  583. SmartcardDebug(
  584. DEBUG_DRIVER,
  585. ("%s!UsbReadSTCData: Timeout %X \n",
  586. DRIVER_NAME,
  587. STATUS_IO_TIMEOUT));
  588. NTStatus =STATUS_IO_TIMEOUT;
  589. break;
  590. }
  591. }
  592. if ((ULONG) *(pucResponse+1) < ulLenExpected)
  593. {
  594. memcpy(pucData+Index,pucResponse+2,(ULONG) *(pucResponse+1));
  595. Index = Index + (ULONG) *(pucResponse+1);
  596. ulLenExpected = ulLenExpected - (ULONG) *(pucResponse+1);
  597. SendReadCommand = TRUE;
  598. }
  599. else
  600. {
  601. SendReadCommand = FALSE;
  602. memcpy(pucData+Index,pucResponse+2,ulLenExpected);
  603. if((ULONG) *(pucResponse+1) > ulLenExpected)
  604. {
  605. memcpy(
  606. ReaderExtension->ucReadBuffer,
  607. pucResponse+ulLenExpected+2,
  608. (ULONG) *(pucResponse+1) - ulLenExpected);
  609. ReaderExtension->ulReadBufferLen =
  610. (ULONG) *(pucResponse+1) - ulLenExpected;
  611. }
  612. else
  613. {
  614. ReaderExtension->ulReadBufferLen = 0;
  615. }
  616. }
  617. }
  618. ExFreePool( pucResponse );
  619. return NTStatus;
  620. }
  621. NTSTATUS
  622. UsbWriteSTCRegister(
  623. PREADER_EXTENSION ReaderExtension,
  624. UCHAR ucAddress,
  625. ULONG ulSize,
  626. PUCHAR pucValue)
  627. /*++
  628. Routine Description:
  629. Arguments:
  630. Return Value:
  631. --*/
  632. {
  633. NTSTATUS NTStatus = STATUS_SUCCESS;
  634. PUCHAR pucCmd;
  635. UCHAR ucResponse[2];
  636. if(ulSize > 16)
  637. {
  638. return STATUS_UNSUCCESSFUL;
  639. }
  640. pucCmd = ExAllocatePool( NonPagedPool, MAX_READ_REGISTER_BUFFER_SIZE);
  641. if(pucCmd == NULL)
  642. {
  643. return STATUS_NO_MEMORY;
  644. }
  645. ReaderExtension->ulReadBufferLen = 0;
  646. // Build the write register command
  647. *pucCmd = 0x80 | ucAddress;
  648. *(pucCmd+1) = (UCHAR) ulSize;
  649. memcpy( pucCmd + 2, pucValue, ulSize );
  650. // Send the Write Register command
  651. NTStatus = UsbWrite( ReaderExtension, pucCmd, 2 + ulSize);
  652. if (NTStatus == STATUS_SUCCESS)
  653. {
  654. // Read the acknowledge
  655. NTStatus = UsbRead( ReaderExtension, ucResponse, 2);
  656. if (NTStatus == STATUS_SUCCESS)
  657. {
  658. NTStatus = STCtoNT(ucResponse);
  659. }
  660. }
  661. ExFreePool( pucCmd );
  662. return NTStatus;
  663. }
  664. NTSTATUS
  665. UsbReadSTCRegister(
  666. PREADER_EXTENSION ReaderExtension,
  667. UCHAR ucAddress,
  668. ULONG ulSize,
  669. PUCHAR pucValue)
  670. /*++
  671. Routine Description:
  672. Arguments:
  673. Return Value:
  674. --*/
  675. {
  676. NTSTATUS NTStatus = STATUS_SUCCESS;
  677. UCHAR ucCmd[2];
  678. PUCHAR pucResponse;
  679. if(ulSize > 16)
  680. {
  681. return STATUS_UNSUCCESSFUL;
  682. }
  683. pucResponse = ExAllocatePool(
  684. NonPagedPool,
  685. MAX_READ_REGISTER_BUFFER_SIZE
  686. );
  687. if(pucResponse == NULL)
  688. {
  689. return STATUS_NO_MEMORY;
  690. }
  691. // Build the Read Register command
  692. ucCmd[0] = 0xC0 | ucAddress;
  693. ucCmd[1] = (UCHAR) ulSize;
  694. // Send the Read Register command
  695. NTStatus = UsbWrite( ReaderExtension, ucCmd, 2);
  696. if (NTStatus == STATUS_SUCCESS)
  697. {
  698. // Read the response from the reader
  699. NTStatus = UsbRead(
  700. ReaderExtension,
  701. pucResponse,
  702. 6
  703. );
  704. if (NTStatus == STATUS_SUCCESS)
  705. {
  706. // Test if what we read is really a READ frame
  707. if(*pucResponse == 0x21)
  708. {
  709. if(*(pucResponse + 1) > 16)
  710. {
  711. NTStatus = STATUS_BUFFER_TOO_SMALL;
  712. }
  713. else
  714. {
  715. memcpy(
  716. pucValue,
  717. pucResponse + 2,
  718. (ULONG) *(pucResponse + 1)
  719. );
  720. }
  721. }
  722. else
  723. {
  724. NTStatus = STCtoNT(pucResponse);
  725. }
  726. }
  727. }
  728. ExFreePool( pucResponse );
  729. return NTStatus;
  730. }
  731. NTSTATUS
  732. UsbGetFirmwareRevision(
  733. PREADER_EXTENSION ReaderExtension)
  734. /*++
  735. Description:
  736. Arguments:
  737. Return Value:
  738. --*/
  739. {
  740. NTSTATUS NTStatus = STATUS_SUCCESS;
  741. UCHAR ucCmd[1];
  742. UCHAR ucResponse[4];
  743. ucCmd[0] = 0xE1;
  744. NTStatus = UsbWrite( ReaderExtension, ucCmd, 2 );
  745. if( NTStatus == STATUS_SUCCESS )
  746. {
  747. ReaderExtension->ReadTimeout = 1000;
  748. NTStatus = UsbRead( ReaderExtension, ucResponse, 4 );
  749. if( NTStatus == STATUS_SUCCESS )
  750. {
  751. ReaderExtension->FirmwareMajor = ucResponse[ 2 ];
  752. ReaderExtension->FirmwareMinor = ucResponse[ 3 ];
  753. }
  754. }
  755. return NTStatus ;
  756. }
  757. NTSTATUS
  758. UsbRead(
  759. PREADER_EXTENSION ReaderExtension,
  760. PUCHAR pData,
  761. ULONG DataLen )
  762. /*++
  763. Description:
  764. Read data on the USB bus
  765. Arguments:
  766. ReaderExtension context of call
  767. pData ptr to data buffer
  768. DataLen length of data buffer
  769. pNBytes number of bytes returned
  770. Return Value:
  771. STATUS_SUCCESS
  772. STATUS_BUFFER_TOO_SMALL
  773. STATUS_UNSUCCESSFUL
  774. --*/
  775. {
  776. NTSTATUS NtStatus = STATUS_SUCCESS;
  777. PURB pUrb;
  778. USBD_INTERFACE_INFORMATION* pInterfaceInfo;
  779. USBD_PIPE_INFORMATION* pPipeInfo;
  780. PDEVICE_OBJECT DeviceObject = ReaderExtension->DeviceObject;
  781. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  782. ULONG ulSize;
  783. pInterfaceInfo = DeviceExtension->Interface;
  784. ASSERT(pInterfaceInfo != NULL);
  785. if (pInterfaceInfo == NULL) {
  786. // The device has likely been disconnected during hibernate / stand by
  787. return STATUS_DEVICE_NOT_CONNECTED;
  788. }
  789. // Read pipe number is 0 on this device
  790. pPipeInfo = &( pInterfaceInfo->Pipes[ 0 ] );
  791. ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  792. pUrb = ExAllocatePool( NonPagedPool, ulSize );
  793. if(pUrb == NULL)
  794. {
  795. return STATUS_NO_MEMORY;
  796. }
  797. else
  798. {
  799. UsbBuildInterruptOrBulkTransferRequest(
  800. pUrb,
  801. (USHORT)ulSize,
  802. pPipeInfo->PipeHandle,
  803. pData,
  804. NULL,
  805. DataLen,
  806. USBD_SHORT_TRANSFER_OK,
  807. NULL
  808. );
  809. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  810. ExFreePool( pUrb );
  811. }
  812. return NtStatus;
  813. }
  814. NTSTATUS
  815. UsbWrite(
  816. PREADER_EXTENSION ReaderExtension,
  817. PUCHAR pData,
  818. ULONG DataLen)
  819. /*++
  820. Description:
  821. Write data on the usb port
  822. Arguments:
  823. ReaderExtension context of call
  824. pData ptr to data buffer
  825. DataLen length of data buffer (exclusive LRC!)
  826. Return Value:
  827. return value of
  828. --*/
  829. {
  830. NTSTATUS NtStatus = STATUS_SUCCESS;
  831. PURB pUrb;
  832. USBD_INTERFACE_INFORMATION* pInterfaceInfo;
  833. USBD_PIPE_INFORMATION* pPipeInfo;
  834. PDEVICE_OBJECT DeviceObject = ReaderExtension->DeviceObject;
  835. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  836. ULONG ulSize;
  837. pInterfaceInfo = DeviceExtension->Interface;
  838. ASSERT(pInterfaceInfo != NULL);
  839. if (pInterfaceInfo == NULL) {
  840. // The device has likely been disconnected during hibernate / stand by
  841. return STATUS_DEVICE_NOT_CONNECTED;
  842. }
  843. // Write pipe number is 1 on this device
  844. pPipeInfo = &( pInterfaceInfo->Pipes[ 1 ] );
  845. ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  846. pUrb = ExAllocatePool( NonPagedPool, ulSize );
  847. if(pUrb == NULL)
  848. {
  849. NtStatus = STATUS_NO_MEMORY;
  850. }
  851. else
  852. {
  853. UsbBuildInterruptOrBulkTransferRequest(
  854. pUrb,
  855. (USHORT)ulSize,
  856. pPipeInfo->PipeHandle,
  857. pData,
  858. NULL,
  859. DataLen,
  860. USBD_SHORT_TRANSFER_OK,
  861. NULL );
  862. NtStatus = UsbCallUSBD( DeviceObject, pUrb );
  863. ExFreePool( pUrb );
  864. }
  865. return NtStatus;
  866. }