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.

2930 lines
73 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. scrcp8t.c
  5. Abstract:
  6. Author:
  7. Environment:
  8. Kernel mode
  9. Revision History :
  10. Nov. 1997 - 1.0 Release
  11. Jan. 1998 - Fix for vendor defined IOCTLs
  12. CP8SerialIo now write the whole data packet if GT is 0
  13. Support for higher data rates added
  14. --*/
  15. #include <stdio.h>
  16. #include "scrcp8t.h"
  17. //
  18. // We do not need these functions after init anymore
  19. //
  20. #pragma alloc_text(INIT, DriverEntry)
  21. #pragma alloc_text(INIT, CP8AddDevice)
  22. #pragma alloc_text(INIT, CP8CreateDevice)
  23. #pragma alloc_text(INIT, CP8Initialize)
  24. #if DBG
  25. #pragma optimize ("", off)
  26. #endif
  27. NTSTATUS
  28. CP8VendorIoctl(
  29. PSMARTCARD_EXTENSION SmartcardExtension
  30. );
  31. NTSTATUS
  32. DriverEntry(
  33. IN PDRIVER_OBJECT DriverObject,
  34. IN PUNICODE_STRING RegistryPath
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is called at system initialization time to initialize
  39. this driver.
  40. Arguments:
  41. DriverObject - Supplies the driver object.
  42. RegistryPath - Supplies the registry path for this driver.
  43. Return Value:
  44. STATUS_SUCCESS - We could initialize at least one device.
  45. STATUS_NO_SUCH_DEVICE - We could not initialize even one device.
  46. --*/
  47. {
  48. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  49. BOOLEAN detectReader = FALSE;
  50. ULONG i, noOfDevices = 0;
  51. UNICODE_STRING serialPort, parameters, parameterPath;
  52. NTSTATUS status;
  53. WCHAR buffer[128];
  54. SmartcardDebug(
  55. DEBUG_DRIVER,
  56. ("%s!DriverEntry: Enter - %s %s\n",
  57. DRIVER_NAME,
  58. __DATE__,
  59. __TIME__)
  60. )
  61. //
  62. // Initialize the Driver Object with driver's entry points
  63. //
  64. DriverObject->DriverUnload = CP8Unload;
  65. DriverObject->MajorFunction[IRP_MJ_CREATE] = CP8CreateClose;
  66. DriverObject->MajorFunction[IRP_MJ_CLOSE] = CP8CreateClose;
  67. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CP8Cleanup;
  68. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CP8DeviceControl;
  69. RtlZeroMemory(
  70. paramTable,
  71. sizeof(paramTable)
  72. );
  73. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  74. paramTable[0].Name = L"Device0";
  75. paramTable[0].EntryContext = &serialPort;
  76. paramTable[0].DefaultType = REG_SZ;
  77. paramTable[0].DefaultData = &serialPort;
  78. paramTable[0].DefaultLength = 0;
  79. parameterPath.MaximumLength = sizeof(buffer);
  80. parameterPath.Length = 0;
  81. parameterPath.Buffer = buffer;
  82. RtlCopyUnicodeString(
  83. &parameterPath,
  84. RegistryPath
  85. );
  86. RtlInitUnicodeString(
  87. &parameters,
  88. L"\\Parameters"
  89. );
  90. RtlAppendUnicodeStringToString(
  91. &parameterPath,
  92. &parameters
  93. );
  94. //
  95. // We now search the registry for DeviceN value
  96. //
  97. for (i = 0; i < MAXIMUM_SERIAL_READERS; i++) {
  98. UNICODE_STRING serialDeviceName;
  99. RtlInitUnicodeString(
  100. &serialDeviceName,
  101. L"\\Device\\Serial "
  102. );
  103. RtlInitUnicodeString(
  104. &serialPort,
  105. L"COM?"
  106. );
  107. if (detectReader == FALSE) {
  108. //
  109. // create string like DeviceN
  110. //
  111. paramTable[0].Name[6] = L'0' + (WCHAR) i;
  112. //
  113. // now try to find the entry in the registry
  114. //
  115. status = RtlQueryRegistryValues(
  116. RTL_REGISTRY_ABSOLUTE,
  117. parameterPath.Buffer,
  118. &paramTable[0],
  119. NULL,
  120. NULL
  121. );
  122. if (status != STATUS_SUCCESS) {
  123. //
  124. // The entry does no exist in the registry
  125. //
  126. if (i > 0) {
  127. break;
  128. }
  129. //
  130. // we found not even an entry for device0.
  131. // Try to detect readers. We assume now that
  132. // the user has inserted a card into the reader
  133. // Actually we try to detect the card, not the reader
  134. //
  135. detectReader = TRUE;
  136. }
  137. }
  138. if (detectReader) {
  139. serialPort.Buffer[3] = L'1' + (WCHAR) i;
  140. }
  141. //
  142. // create string like \Device\SerialN
  143. //
  144. serialDeviceName.Buffer[14] = serialPort.Buffer[3] - (WCHAR) 1;
  145. //
  146. // Now try to create a device and connect to the serial port
  147. //
  148. status = CP8AddDevice(
  149. DriverObject,
  150. &serialDeviceName
  151. );
  152. if (status == STATUS_SUCCESS) {
  153. //
  154. // We have successfully created a device
  155. //
  156. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  157. PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  158. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  159. //
  160. // Save the serial port number this device is connected to
  161. //
  162. smartcardExtension->ReaderCapabilities.Channel =
  163. serialPort.Buffer[3] - L'0';
  164. if (detectReader) {
  165. //
  166. // We now assume that the user has inserted a smart card
  167. // and we try to get an ATR in order to figure out if there
  168. // is really a reader connected to this port
  169. //
  170. smartcardExtension->IoRequest.ReplyBuffer = NULL;
  171. smartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
  172. status = CP8ReaderPower(smartcardExtension);
  173. if (status == STATUS_SUCCESS) {
  174. //
  175. // create an entry in the registry
  176. //
  177. paramTable[0].Name[6] = L'0' + (WCHAR) noOfDevices;
  178. RtlWriteRegistryValue(
  179. RTL_REGISTRY_ABSOLUTE,
  180. parameterPath.Buffer,
  181. paramTable[0].Name,
  182. REG_SZ,
  183. serialPort.Buffer,
  184. serialPort.Length
  185. );
  186. SmartcardLogError(
  187. DriverObject,
  188. CP8_NEW_DEVICE_ADDED,
  189. &serialPort,
  190. status
  191. );
  192. } else {
  193. //
  194. // We were unable to get an ATR from the card.
  195. // So remove the device again.
  196. //
  197. CP8RemoveDevice(deviceObject);
  198. }
  199. }
  200. if (status == STATUS_SUCCESS) {
  201. noOfDevices++;
  202. }
  203. }
  204. }
  205. if (noOfDevices == 0) {
  206. SmartcardLogError(
  207. DriverObject,
  208. CP8_NO_SUCH_DEVICE,
  209. NULL,
  210. status
  211. );
  212. return STATUS_NO_SUCH_DEVICE;
  213. }
  214. return STATUS_SUCCESS;
  215. }
  216. NTSTATUS
  217. CP8AddDevice(
  218. IN PDRIVER_OBJECT DriverObject,
  219. IN PUNICODE_STRING SerialDeviceName
  220. )
  221. /*++
  222. Routine Description:
  223. This is the add-device routine for the miniport.
  224. Arguments:
  225. DriverObject - a pointer to the driver object for this device
  226. SerialDeviceName - The device name of the serial port to attach to
  227. Return Value:
  228. NT_STATUS
  229. --*/
  230. {
  231. UNICODE_STRING smartcardDeviceName, deviceNo, device;
  232. WCHAR buffer[32];
  233. ULONG i;
  234. NTSTATUS status;
  235. for (i = 0; i < MAXIMUM_SERIAL_READERS; i++) {
  236. //
  237. // Build a device name for the smart card reader
  238. // \Device\BullCP8TN (N is the 0 based device number)
  239. //
  240. smartcardDeviceName.Buffer = buffer;
  241. smartcardDeviceName.MaximumLength = sizeof(buffer);
  242. smartcardDeviceName.Length = 0;
  243. RtlInitUnicodeString(
  244. &device,
  245. L"\\Device\\BullCP8T"
  246. );
  247. RtlCopyUnicodeString(
  248. &smartcardDeviceName,
  249. &device
  250. );
  251. deviceNo.Buffer =
  252. smartcardDeviceName.Buffer +
  253. smartcardDeviceName.Length / sizeof(WCHAR);
  254. deviceNo.MaximumLength = 2 * sizeof(WCHAR);
  255. deviceNo.Length = 0;
  256. RtlIntegerToUnicodeString(
  257. i,
  258. 10,
  259. &deviceNo
  260. );
  261. smartcardDeviceName.Length += deviceNo.Length;
  262. //
  263. // Try to create a device with the just created device name
  264. // It is possible that a smart card device with this name
  265. // already exists from a previous call.
  266. // It is possible to have up to 4 devices in a system
  267. //
  268. status = CP8CreateDevice(
  269. DriverObject,
  270. &smartcardDeviceName,
  271. SerialDeviceName
  272. );
  273. if (status == STATUS_SUCCESS) {
  274. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  275. PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  276. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  277. // this is a list of our supported data rates
  278. static ULONG dataRatesSupported[] = { 9600, 19200 };
  279. //
  280. // Initialize the vendor information
  281. //
  282. strcpy(
  283. deviceExtension->SmartcardExtension.VendorAttr.VendorName.Buffer,
  284. "Bull"
  285. );
  286. deviceExtension->SmartcardExtension.VendorAttr.VendorName.Length =
  287. strlen(deviceExtension->SmartcardExtension.VendorAttr.VendorName.Buffer);
  288. strcpy(
  289. deviceExtension->SmartcardExtension.VendorAttr.IfdType.Buffer,
  290. "CP8 Transac"
  291. );
  292. deviceExtension->SmartcardExtension.VendorAttr.IfdType.Length =
  293. strlen(deviceExtension->SmartcardExtension.VendorAttr.IfdType.Buffer);
  294. smartcardExtension->VendorAttr.UnitNo = i;
  295. //
  296. // Set reader info
  297. //
  298. //
  299. // Clk frequency in KHz encoded as little endian integer
  300. //
  301. smartcardExtension->ReaderCapabilities.CLKFrequency.Default = 3571;
  302. smartcardExtension->ReaderCapabilities.CLKFrequency.Max = 3571;
  303. smartcardExtension->ReaderCapabilities.DataRate.Default = 9600;
  304. smartcardExtension->ReaderCapabilities.DataRate.Max = 19200;
  305. smartcardExtension->ReaderCapabilities.DataRatesSupported.List =
  306. dataRatesSupported;
  307. smartcardExtension->ReaderCapabilities.DataRatesSupported.Entries =
  308. sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
  309. smartcardExtension->ReaderCapabilities.MaxIFSD = 254;
  310. break;
  311. }
  312. if (status != STATUS_OBJECT_NAME_COLLISION) {
  313. //
  314. // The corresponding serial port is already in use
  315. // So don't try to create a smart card device with a different name
  316. //
  317. break;
  318. }
  319. }
  320. return status;
  321. }
  322. NTSTATUS
  323. CP8SerialCallComplete (
  324. IN PDEVICE_OBJECT DeviceObject,
  325. IN PIRP Irp,
  326. IN PKEVENT Event
  327. )
  328. /*++
  329. Routine Description:
  330. Completion routine for an Irp sent to the serial driver.
  331. It sets only an event that we can use to wait for.
  332. --*/
  333. {
  334. UNREFERENCED_PARAMETER (DeviceObject);
  335. Irp->IoStatus.Information = 0;
  336. if (Irp->Cancel) {
  337. Irp->IoStatus.Status = STATUS_CANCELLED;
  338. } else {
  339. Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
  340. }
  341. KeSetEvent (Event, 0, FALSE);
  342. return STATUS_MORE_PROCESSING_REQUIRED;
  343. }
  344. NTSTATUS
  345. CP8CreateDevice(
  346. IN PDRIVER_OBJECT DriverObject,
  347. IN PUNICODE_STRING SmartcardDeviceName,
  348. IN PUNICODE_STRING SerialDeviceName
  349. )
  350. /*++
  351. Routine Description:
  352. This routine creates an object for the physical device specified and
  353. sets up the deviceExtension.
  354. Arguments:
  355. Return Value:
  356. NTSTATUS
  357. --*/
  358. {
  359. PFILE_OBJECT serialFileObject;
  360. PDEVICE_OBJECT deviceObject, serialDeviceObject;
  361. PDEVICE_EXTENSION deviceExtension;
  362. NTSTATUS status = STATUS_SUCCESS;
  363. PIO_STACK_LOCATION irpStack;
  364. IO_STATUS_BLOCK ioStatusBlock;
  365. KEVENT Event;
  366. PIRP irp;
  367. ULONG i;
  368. status = IoGetDeviceObjectPointer(
  369. SerialDeviceName,
  370. FILE_ALL_ACCESS,
  371. &serialFileObject,
  372. &serialDeviceObject
  373. );
  374. if (!NT_SUCCESS(status)) {
  375. UNICODE_STRING comPortNumber;
  376. WCHAR buffer[2];
  377. // Extract the com-port-number
  378. comPortNumber.Buffer = buffer;
  379. comPortNumber.Length = 2;
  380. comPortNumber.MaximumLength = sizeof(buffer);
  381. comPortNumber.Buffer[0] = SerialDeviceName->Buffer[14] + (WCHAR) 1;
  382. // Write an event-log msg that this com port is not available
  383. SmartcardLogError(
  384. DriverObject,
  385. CP8_CANT_CONNECT_TO_SERIAL_PORT,
  386. &comPortNumber,
  387. status
  388. );
  389. return status;
  390. }
  391. status = IoCreateDevice(
  392. DriverObject,
  393. sizeof(DEVICE_EXTENSION),
  394. SmartcardDeviceName,
  395. FILE_DEVICE_SMARTCARD,
  396. 0,
  397. #if DBG
  398. FALSE,
  399. #else
  400. TRUE,
  401. #endif
  402. &deviceObject
  403. );
  404. if (!NT_SUCCESS(status)) {
  405. ObDereferenceObject(
  406. serialFileObject
  407. );
  408. SmartcardLogError(
  409. DriverObject,
  410. CP8_CANT_CREATE_DEVICE,
  411. SmartcardDeviceName,
  412. status
  413. );
  414. return status;
  415. }
  416. deviceExtension = deviceObject->DeviceExtension;
  417. deviceObject->Flags = deviceObject->Flags | DO_BUFFERED_IO;
  418. RtlZeroMemory(
  419. deviceExtension,
  420. sizeof(PDEVICE_EXTENSION)
  421. );
  422. //
  423. // Allocate data struct space for smart card reader
  424. //
  425. deviceExtension->SmartcardExtension.ReaderExtension = ExAllocatePool(
  426. NonPagedPool,
  427. sizeof(READER_EXTENSION)
  428. );
  429. if (deviceExtension->SmartcardExtension.ReaderExtension == NULL) {
  430. SmartcardLogError(
  431. DriverObject,
  432. CP8_NO_MEMORY,
  433. NULL,
  434. 0
  435. );
  436. status = STATUS_INSUFFICIENT_RESOURCES;
  437. }
  438. if (status == STATUS_SUCCESS) {
  439. RtlZeroMemory(
  440. deviceExtension->SmartcardExtension.ReaderExtension,
  441. sizeof(READER_EXTENSION)
  442. );
  443. //
  444. // Write the version of the lib we use to the smartcard extension
  445. //
  446. deviceExtension->SmartcardExtension.Version = SMCLIB_VERSION;
  447. //
  448. // Now let the lib allocate the buffer for data transmission
  449. // We can either tell the lib how big the buffer should be
  450. // by assigning a value to BufferSize or let the lib
  451. // allocate the default size
  452. //
  453. status = SmartcardInitialize(
  454. &deviceExtension->SmartcardExtension
  455. );
  456. }
  457. if (status == STATUS_SUCCESS) {
  458. //
  459. // Set up call back functions
  460. //
  461. deviceExtension->SmartcardExtension.ReaderFunction[RDF_TRANSMIT] =
  462. CP8Transmit;
  463. deviceExtension->SmartcardExtension.ReaderFunction[RDF_SET_PROTOCOL] =
  464. CP8SetProtocol;
  465. deviceExtension->SmartcardExtension.ReaderFunction[RDF_CARD_POWER] =
  466. CP8ReaderPower;
  467. deviceExtension->SmartcardExtension.ReaderFunction[RDF_CARD_TRACKING] =
  468. CP8CardTracking;
  469. deviceExtension->SmartcardExtension.ReaderFunction[RDF_IOCTL_VENDOR] =
  470. CP8VendorIoctl;
  471. //
  472. // Save deviceObject
  473. //
  474. deviceExtension->SmartcardExtension.OsData->DeviceObject =
  475. deviceObject;
  476. //
  477. // Save the deviceObject for the connected serial port
  478. //
  479. deviceExtension->SmartcardExtension.ReaderExtension->ConnectedSerialPort =
  480. serialDeviceObject;
  481. //
  482. // The fileObject is used in the unload function for dereferencing
  483. //
  484. deviceExtension->SmartcardExtension.ReaderExtension->SerialFileObject =
  485. serialFileObject;
  486. //
  487. // Configure serial reader
  488. //
  489. status = CP8Initialize(
  490. &deviceExtension->SmartcardExtension
  491. );
  492. if (NT_SUCCESS(status)) {
  493. //
  494. // Create a symbolic link
  495. //
  496. status = SmartcardCreateLink(
  497. &deviceExtension->SmartcardExtension.ReaderExtension->DosDeviceName,
  498. SmartcardDeviceName
  499. );
  500. }
  501. }
  502. if (status != STATUS_SUCCESS) {
  503. ExFreePool(
  504. deviceExtension->SmartcardExtension.ReaderExtension
  505. );
  506. SmartcardExit(
  507. &deviceExtension->SmartcardExtension
  508. );
  509. IoDeleteDevice(
  510. deviceObject
  511. );
  512. ObDereferenceObject(
  513. serialFileObject
  514. );
  515. } else {
  516. SmartcardDebug(
  517. DEBUG_INFO,
  518. ("%s!CP8CreateDevice: Device %ws created\n",
  519. DRIVER_NAME,
  520. deviceExtension->SmartcardExtension.ReaderExtension->DosDeviceName.Buffer)
  521. );
  522. }
  523. return status;
  524. }
  525. NTSTATUS
  526. CP8Initialize(
  527. IN PSMARTCARD_EXTENSION SmartcardExtension
  528. )
  529. /*++
  530. Routine Description:
  531. This routine reads the default configuraton values for this device.
  532. Arguments:
  533. DriverObject - Pointer to driver object created by system.
  534. Return Value:
  535. none
  536. --*/
  537. {
  538. PREADER_EXTENSION readerExtension = SmartcardExtension->ReaderExtension;
  539. NTSTATUS status;
  540. readerExtension->SerialConfigData.WaitMask = SERIAL_EV_CTS;
  541. readerExtension->SerialConfigData.BaudRate.BaudRate = 9600;
  542. readerExtension->SerialConfigData.LineControl.StopBits = STOP_BITS_2;
  543. readerExtension->SerialConfigData.LineControl.Parity = EVEN_PARITY;
  544. readerExtension->SerialConfigData.LineControl.WordLength = SERIAL_DATABITS_8;
  545. //
  546. // set timeouts
  547. //
  548. readerExtension->SerialConfigData.Timeouts.ReadIntervalTimeout =
  549. READ_INTERVAL_TIMEOUT_DEFAULT;
  550. readerExtension->SerialConfigData.Timeouts.ReadTotalTimeoutConstant =
  551. READ_TOTAL_TIMEOUT_CONSTANT_DEFAULT;
  552. readerExtension->SerialConfigData.Timeouts.ReadTotalTimeoutMultiplier = 0;
  553. //
  554. // set special characters
  555. //
  556. readerExtension->SerialConfigData.SerialChars.ErrorChar = 0;
  557. readerExtension->SerialConfigData.SerialChars.EofChar = 0;
  558. readerExtension->SerialConfigData.SerialChars.EventChar = 0;
  559. readerExtension->SerialConfigData.SerialChars.XonChar = 0;
  560. readerExtension->SerialConfigData.SerialChars.XoffChar = 0;
  561. readerExtension->SerialConfigData.SerialChars.BreakChar = 0xFF;
  562. //
  563. // Set handflow
  564. //
  565. readerExtension->SerialConfigData.HandFlow.XonLimit = 0;
  566. readerExtension->SerialConfigData.HandFlow.XoffLimit = 0;
  567. readerExtension->SerialConfigData.HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE ;
  568. readerExtension->SerialConfigData.HandFlow.ControlHandShake = 0;
  569. //
  570. // Now setup information in our deviceExtension
  571. //
  572. SmartcardExtension->ReaderCapabilities.CurrentState = (ULONG) SCARD_UNKNOWN;
  573. //
  574. // This reader supports T=0 and T=1
  575. //
  576. SmartcardExtension->ReaderCapabilities.SupportedProtocols =
  577. SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
  578. SmartcardExtension->ReaderCapabilities.MechProperties = 0;
  579. status = CP8ConfigureSerialPort(
  580. SmartcardExtension
  581. );
  582. if (status == STATUS_SUCCESS) {
  583. status = CP8InitializeCardTracking(
  584. SmartcardExtension
  585. );
  586. }
  587. return status;
  588. }
  589. NTSTATUS
  590. CP8ConfigureSerialPort(
  591. PSMARTCARD_EXTENSION SmartcardExtension
  592. )
  593. /*++
  594. Routine Description:
  595. This routine will appropriately configure the serial port.
  596. It makes synchronous calls to the serial port.
  597. Arguments:
  598. SmartcardExtension - Pointer to smart card struct
  599. Return Value:
  600. NTSTATUS
  601. --*/
  602. {
  603. PSERIAL_READER_CONFIG configData = &SmartcardExtension->ReaderExtension->SerialConfigData;
  604. NTSTATUS status = STATUS_SUCCESS;
  605. USHORT i;
  606. PUCHAR request = SmartcardExtension->SmartcardRequest.Buffer;
  607. SmartcardExtension->SmartcardRequest.BufferLength = 0;
  608. SmartcardExtension->SmartcardReply.BufferLength =
  609. SmartcardExtension->SmartcardReply.BufferSize;
  610. for (i = 0; NT_SUCCESS(status); i++) {
  611. switch (i) {
  612. case 0:
  613. //
  614. // Set up baudrate for the CP8 reader
  615. //
  616. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  617. IOCTL_SERIAL_SET_BAUD_RATE;
  618. SmartcardExtension->SmartcardRequest.Buffer =
  619. (PUCHAR) &configData->BaudRate;
  620. SmartcardExtension->SmartcardRequest.BufferLength =
  621. sizeof(SERIAL_BAUD_RATE);
  622. break;
  623. case 1:
  624. //
  625. // Set up line control parameters
  626. //
  627. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  628. IOCTL_SERIAL_SET_LINE_CONTROL;
  629. SmartcardExtension->SmartcardRequest.Buffer =
  630. (PUCHAR) &configData->LineControl;
  631. SmartcardExtension->SmartcardRequest.BufferLength =
  632. sizeof(SERIAL_LINE_CONTROL);
  633. break;
  634. case 2:
  635. //
  636. // Set serial special characters
  637. //
  638. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  639. IOCTL_SERIAL_SET_CHARS;
  640. SmartcardExtension->SmartcardRequest.Buffer =
  641. (PUCHAR) &configData->SerialChars;
  642. SmartcardExtension->SmartcardRequest.BufferLength =
  643. sizeof(SERIAL_CHARS);
  644. break;
  645. case 3:
  646. //
  647. // Set up timeouts
  648. //
  649. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  650. IOCTL_SERIAL_SET_TIMEOUTS;
  651. SmartcardExtension->SmartcardRequest.Buffer =
  652. (PUCHAR) &configData->Timeouts;
  653. SmartcardExtension->SmartcardRequest.BufferLength =
  654. sizeof(SERIAL_TIMEOUTS);
  655. break;
  656. case 4:
  657. //
  658. // Set flowcontrol and handshaking
  659. //
  660. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  661. IOCTL_SERIAL_SET_HANDFLOW;
  662. SmartcardExtension->SmartcardRequest.Buffer =
  663. (PUCHAR) &configData->HandFlow;
  664. SmartcardExtension->SmartcardRequest.BufferLength =
  665. sizeof(SERIAL_HANDFLOW);
  666. break;
  667. case 5:
  668. //
  669. // Set break off
  670. //
  671. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  672. IOCTL_SERIAL_SET_BREAK_OFF;
  673. break;
  674. case 6:
  675. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  676. IOCTL_SERIAL_SET_DTR;
  677. break;
  678. case 7:
  679. return STATUS_SUCCESS;
  680. }
  681. status = CP8SerialIo(
  682. SmartcardExtension
  683. );
  684. //
  685. // restore pointer to original request buffer
  686. //
  687. SmartcardExtension->SmartcardRequest.Buffer = request;
  688. }
  689. return status;
  690. }
  691. NTSTATUS
  692. CP8CreateClose(
  693. IN PDEVICE_OBJECT DeviceObject,
  694. IN PIRP Irp
  695. )
  696. /*++
  697. Routine Description:
  698. This routine is called by the I/O system when the device is opened or closed.
  699. Arguments:
  700. DeviceObject - Pointer to device object for this miniport
  701. Irp - IRP involved.
  702. Return Value:
  703. STATUS_SUCCESS.
  704. --*/
  705. {
  706. #if DBG
  707. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  708. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  709. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  710. if (irpStack->MajorFunction == IRP_MJ_CREATE) {
  711. SmartcardDebug(
  712. DEBUG_DRIVER,
  713. ("%s!CP8CreateClose: Device %ws opened\n",
  714. DRIVER_NAME,
  715. smartcardExtension->ReaderExtension->DosDeviceName.Buffer)
  716. );
  717. } else {
  718. SmartcardDebug(
  719. DEBUG_DRIVER,
  720. ("%s!CP8CreateClose: Device %ws closed\n",
  721. DRIVER_NAME,
  722. smartcardExtension->ReaderExtension->DosDeviceName.Buffer)
  723. );
  724. }
  725. #endif
  726. Irp->IoStatus.Information = 0;
  727. Irp->IoStatus.Status = STATUS_SUCCESS;
  728. return STATUS_SUCCESS;
  729. }
  730. NTSTATUS
  731. CP8Cancel(
  732. IN PDEVICE_OBJECT DeviceObject,
  733. IN PIRP Irp
  734. )
  735. /*++
  736. Routine Description:
  737. This routine is called by the I/O system
  738. when the irp should be cancelled
  739. Arguments:
  740. DeviceObject - Pointer to device object for this miniport
  741. Irp - IRP involved.
  742. Return Value:
  743. STATUS_CANCELLED
  744. --*/
  745. {
  746. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  747. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  748. SmartcardDebug(
  749. DEBUG_TRACE,
  750. ("%s!CP8Cancel: Enter\n",
  751. DRIVER_NAME)
  752. );
  753. ASSERT(Irp == smartcardExtension->OsData->NotificationIrp);
  754. smartcardExtension->OsData->NotificationIrp->CancelRoutine = NULL;
  755. smartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0;
  756. smartcardExtension->OsData->NotificationIrp->IoStatus.Status = STATUS_CANCELLED;
  757. IoReleaseCancelSpinLock(
  758. Irp->CancelIrql
  759. );
  760. SmartcardDebug(
  761. DEBUG_DRIVER,
  762. ("%s!CP8Cancel: Completing wait for Irp = %lx\n",
  763. DRIVER_NAME,
  764. smartcardExtension->OsData->NotificationIrp)
  765. );
  766. IoCompleteRequest(
  767. smartcardExtension->OsData->NotificationIrp,
  768. IO_NO_INCREMENT
  769. );
  770. smartcardExtension->OsData->NotificationIrp = NULL;
  771. SmartcardDebug(
  772. DEBUG_TRACE,
  773. ("%s!CP8Cancel: Exit\n",
  774. DRIVER_NAME)
  775. );
  776. return STATUS_CANCELLED;
  777. }
  778. NTSTATUS
  779. CP8Cleanup(
  780. IN PDEVICE_OBJECT DeviceObject,
  781. IN PIRP Irp
  782. )
  783. /*++
  784. Routine Description:
  785. This routine is called by the I/O system when the calling thread terminates
  786. Arguments:
  787. DeviceObject - Pointer to device object for this miniport
  788. Irp - IRP involved.
  789. Return Value:
  790. STATUS_CANCELLED
  791. --*/
  792. {
  793. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  794. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  795. NTSTATUS status = STATUS_SUCCESS;
  796. SmartcardDebug(
  797. DEBUG_TRACE,
  798. ("%s!CP8Cleanup: Enter\n",
  799. DRIVER_NAME)
  800. );
  801. if (smartcardExtension->OsData->NotificationIrp) {
  802. //
  803. // We need to complete the notification irp
  804. //
  805. IoAcquireCancelSpinLock(
  806. &(Irp->CancelIrql)
  807. );
  808. CP8Cancel(
  809. DeviceObject,
  810. smartcardExtension->OsData->NotificationIrp
  811. );
  812. }
  813. SmartcardDebug(
  814. DEBUG_DRIVER,
  815. ("%s!CP8Cleanup: Completing IRP %lx\n",
  816. DRIVER_NAME,
  817. Irp)
  818. );
  819. Irp->IoStatus.Information = 0;
  820. Irp->IoStatus.Status = STATUS_SUCCESS;
  821. IoCompleteRequest(
  822. Irp,
  823. IO_NO_INCREMENT
  824. );
  825. SmartcardDebug(
  826. DEBUG_TRACE,
  827. ("%s!CP8Cleanup: Exit\n",
  828. DRIVER_NAME)
  829. );
  830. return STATUS_SUCCESS;
  831. }
  832. VOID
  833. CP8RemoveDevice(
  834. IN PDEVICE_OBJECT DeviceObject
  835. )
  836. {
  837. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  838. PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
  839. SmartcardDebug(
  840. DEBUG_INFO,
  841. ("%s!CP8RemoveDevice: Unloading device %ws\n",
  842. DRIVER_NAME,
  843. smartcardExtension->ReaderExtension->DosDeviceName.Buffer)
  844. );
  845. //
  846. // Tell the serial driver that we don't need the
  847. // call back (IoCompletion) anymore
  848. //
  849. smartcardExtension->ReaderExtension->SerialConfigData.WaitMask = 0;
  850. *(PULONG) smartcardExtension->SmartcardRequest.Buffer =
  851. smartcardExtension->ReaderExtension->SerialConfigData.WaitMask;
  852. smartcardExtension->SmartcardRequest.BufferLength =
  853. sizeof(ULONG);
  854. smartcardExtension->ReaderExtension->SerialIoControlCode =
  855. IOCTL_SERIAL_SET_WAIT_MASK;
  856. //
  857. // We don't expect to get bytes back
  858. //
  859. smartcardExtension->SmartcardReply.BufferLength = 0;
  860. CP8SerialIo(
  861. smartcardExtension
  862. );
  863. //
  864. // We do not longet need the reference to the serial reader
  865. //
  866. ObDereferenceObject(
  867. smartcardExtension->ReaderExtension->SerialFileObject
  868. );
  869. //
  870. // Delete the symbolic link of the smart card reader
  871. //
  872. IoDeleteSymbolicLink(
  873. &smartcardExtension->ReaderExtension->DosDeviceName
  874. );
  875. //
  876. // Let the lib free the send/receive buffers
  877. //
  878. SmartcardExit(
  879. smartcardExtension
  880. );
  881. //
  882. // Free all allocated buffer
  883. //
  884. ExFreePool(
  885. smartcardExtension->ReaderExtension->DosDeviceName.Buffer
  886. );
  887. ExFreePool(
  888. smartcardExtension->ReaderExtension
  889. );
  890. //
  891. // Delete the device from the system
  892. //
  893. IoDeleteDevice(
  894. DeviceObject
  895. );
  896. }
  897. VOID
  898. CP8Unload(
  899. IN PDRIVER_OBJECT DriverObject
  900. )
  901. /*++
  902. Routine Description:
  903. The driver unload routine. This is called by the I/O system
  904. when the device is unloaded from memory.
  905. Arguments:
  906. DriverObject - Pointer to driver object created by system.
  907. Return Value:
  908. STATUS_SUCCESS.
  909. --*/
  910. {
  911. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  912. NTSTATUS status;
  913. SmartcardDebug(
  914. DEBUG_TRACE,
  915. ("%s!CP8Unload: Enter\n",
  916. DRIVER_NAME)
  917. );
  918. do {
  919. CP8RemoveDevice(deviceObject);
  920. } while(deviceObject = DriverObject->DeviceObject);
  921. SmartcardDebug(
  922. DEBUG_TRACE,
  923. ("%s!CP8Unload: Exit\n",
  924. DRIVER_NAME)
  925. );
  926. }
  927. NTSTATUS
  928. CP8SerialIo(
  929. IN PSMARTCARD_EXTENSION SmartcardExtension
  930. )
  931. /*++
  932. Routine Description:
  933. This routine sends IOCTL's to the serial driver. It waits on for their
  934. completion, and then returns.
  935. Arguments:
  936. Return Value:
  937. NTSTATUS
  938. --*/
  939. {
  940. NTSTATUS status;
  941. ULONG currentByte = 0;
  942. //
  943. // Check if the buffers are large enough
  944. //
  945. ASSERT(SmartcardExtension->SmartcardReply.BufferLength <=
  946. SmartcardExtension->SmartcardReply.BufferSize);
  947. ASSERT(SmartcardExtension->SmartcardRequest.BufferLength <=
  948. SmartcardExtension->SmartcardRequest.BufferSize);
  949. if (SmartcardExtension->SmartcardReply.BufferLength >
  950. SmartcardExtension->SmartcardReply.BufferSize ||
  951. SmartcardExtension->SmartcardRequest.BufferLength >
  952. SmartcardExtension->SmartcardRequest.BufferSize) {
  953. SmartcardLogError(
  954. SmartcardExtension->OsData->DeviceObject,
  955. CP8_BUFFER_TOO_SMALL,
  956. NULL,
  957. 0
  958. );
  959. return STATUS_BUFFER_TOO_SMALL;
  960. }
  961. do {
  962. IO_STATUS_BLOCK ioStatus;
  963. KEVENT event;
  964. PIRP irp;
  965. PIO_STACK_LOCATION irpNextStack;
  966. PUCHAR requestBuffer = NULL;
  967. PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
  968. ULONG requestBufferLength = SmartcardExtension->SmartcardRequest.BufferLength;
  969. ULONG replyBufferLength = SmartcardExtension->SmartcardReply.BufferLength;
  970. KeInitializeEvent(
  971. &event,
  972. NotificationEvent,
  973. FALSE
  974. );
  975. if (SmartcardExtension->ReaderExtension->SerialIoControlCode ==
  976. SMARTCARD_WRITE) {
  977. if (SmartcardExtension->CardCapabilities.GT != 0) {
  978. //
  979. // If the guardtime isn't 0 and we write data to the smart card
  980. // we only write byte by byte, because we have to insert a delay
  981. // between every sent byte
  982. //
  983. requestBufferLength = 1;
  984. }
  985. requestBuffer =
  986. &SmartcardExtension->SmartcardRequest.Buffer[currentByte++];
  987. replyBuffer = NULL;
  988. replyBufferLength = 0;
  989. } else {
  990. requestBuffer =
  991. (requestBufferLength ?
  992. SmartcardExtension->SmartcardRequest.Buffer : NULL);
  993. }
  994. // Build irp to be sent to serial driver
  995. irp = IoBuildDeviceIoControlRequest(
  996. SmartcardExtension->ReaderExtension->SerialIoControlCode,
  997. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  998. requestBuffer,
  999. requestBufferLength,
  1000. replyBuffer,
  1001. replyBufferLength,
  1002. FALSE,
  1003. &event,
  1004. &ioStatus
  1005. );
  1006. ASSERT(irp != NULL);
  1007. if (irp == NULL) {
  1008. return STATUS_INSUFFICIENT_RESOURCES;
  1009. }
  1010. irpNextStack = IoGetNextIrpStackLocation(irp);
  1011. switch (SmartcardExtension->ReaderExtension->SerialIoControlCode) {
  1012. //
  1013. // The serial driver trasfers data from/to irp->AssociatedIrp.SystemBuffer
  1014. //
  1015. case SMARTCARD_WRITE:
  1016. //
  1017. // Since we 'manually' change parameters, the io-manager
  1018. // does not really know if this is an input or an ouput operation
  1019. // unless the reply buffer is 0. We do the assertion here, because
  1020. // if the reply buffer is not NULL, the io-manager will copy
  1021. // data back to the reply buffer.
  1022. //
  1023. ASSERT(replyBuffer == NULL);
  1024. irpNextStack->MajorFunction = IRP_MJ_WRITE;
  1025. irpNextStack->Parameters.Write.Length = requestBufferLength;
  1026. irpNextStack->Parameters.Write.ByteOffset.QuadPart = 0;
  1027. break;
  1028. case SMARTCARD_READ:
  1029. irpNextStack->MajorFunction = IRP_MJ_READ;
  1030. irpNextStack->Parameters.Read.Length = replyBufferLength;
  1031. irpNextStack->Parameters.Read.ByteOffset.QuadPart = 0;
  1032. break;
  1033. }
  1034. status = IoCallDriver(
  1035. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  1036. irp
  1037. );
  1038. if (status == STATUS_PENDING) {
  1039. KeWaitForSingleObject(
  1040. &event,
  1041. Suspended,
  1042. KernelMode,
  1043. FALSE,
  1044. NULL
  1045. );
  1046. status = ioStatus.Status;
  1047. // save the number of bytes received
  1048. SmartcardExtension->SmartcardReply.BufferLength =
  1049. ioStatus.Information;
  1050. }
  1051. // Check if we have to write more bytes to the reader
  1052. if (SmartcardExtension->ReaderExtension->SerialIoControlCode ==
  1053. SMARTCARD_WRITE &&
  1054. SmartcardExtension->CardCapabilities.GT != 0 &&
  1055. currentByte <
  1056. SmartcardExtension->SmartcardRequest.BufferLength) {
  1057. // Now wait the required guard time
  1058. KeStallExecutionProcessor(SmartcardExtension->CardCapabilities.GT);
  1059. status = STATUS_MORE_PROCESSING_REQUIRED;
  1060. }
  1061. } while (status == STATUS_MORE_PROCESSING_REQUIRED);
  1062. return status;
  1063. }
  1064. NTSTATUS
  1065. CP8InitializeCardTracking(
  1066. PSMARTCARD_EXTENSION SmartcardExtension
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. This routine initialized card tracking. It calls the serial driver to
  1071. set a wait mask for CTS tracking. After that it installs a completion
  1072. routine to be called when CTS changes state.
  1073. Arguments:
  1074. SmartcardExtension - Pointer to our smartcard structure
  1075. Return Value:
  1076. NTSTATUS
  1077. --*/
  1078. {
  1079. NTSTATUS status;
  1080. KeInitializeEvent(
  1081. &SmartcardExtension->ReaderExtension->CardStatus.Event,
  1082. NotificationEvent,
  1083. FALSE
  1084. );
  1085. //
  1086. // Send a wait mask to the serial driver.
  1087. // This call only sets the wait mask.
  1088. // We want to be informed when CTS changes its state
  1089. //
  1090. SmartcardExtension->ReaderExtension->CardStatus.Irp = IoBuildDeviceIoControlRequest(
  1091. IOCTL_SERIAL_SET_WAIT_MASK,
  1092. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  1093. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask,
  1094. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask),
  1095. NULL,
  1096. 0,
  1097. FALSE,
  1098. &(SmartcardExtension->ReaderExtension->CardStatus.Event),
  1099. &(SmartcardExtension->ReaderExtension->CardStatus.IoStatus)
  1100. );
  1101. if (SmartcardExtension->ReaderExtension->CardStatus.Irp == NULL) {
  1102. return STATUS_INSUFFICIENT_RESOURCES;
  1103. }
  1104. status = IoCallDriver(
  1105. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  1106. SmartcardExtension->ReaderExtension->CardStatus.Irp,
  1107. );
  1108. if (status == STATUS_SUCCESS) {
  1109. KIRQL oldIrql;
  1110. ULONG ioctlCode = IOCTL_SERIAL_WAIT_ON_MASK | 0x03;
  1111. //
  1112. // Now tell the serial driver that we want to be informed
  1113. // when CTS changes its state.
  1114. // Changing the lowest two bits tells IoBuildDeviceIoControlRequest
  1115. // NOT to allocate a system buffer for the I/O operation.
  1116. // We don't need a system buffer since we use our own buffers.
  1117. //
  1118. SmartcardExtension->ReaderExtension->CardStatus.Irp = IoBuildDeviceIoControlRequest(
  1119. ioctlCode,
  1120. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  1121. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask,
  1122. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask),
  1123. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask,
  1124. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask),
  1125. FALSE,
  1126. &SmartcardExtension->ReaderExtension->CardStatus.Event,
  1127. &SmartcardExtension->ReaderExtension->CardStatus.IoStatus
  1128. );
  1129. if (SmartcardExtension->ReaderExtension->CardStatus.Irp == NULL) {
  1130. return STATUS_INSUFFICIENT_RESOURCES;
  1131. }
  1132. //
  1133. // We simulate a callback now that triggers the card supervision
  1134. //
  1135. CP8SerialCtsChanged(
  1136. SmartcardExtension->OsData->DeviceObject,
  1137. SmartcardExtension->ReaderExtension->CardStatus.Irp,
  1138. SmartcardExtension
  1139. );
  1140. status = STATUS_SUCCESS;
  1141. }
  1142. return status;
  1143. }
  1144. NTSTATUS
  1145. CP8SerialCtsChanged(
  1146. IN PDEVICE_OBJECT DeviceObject,
  1147. IN PIRP Irp,
  1148. IN PSMARTCARD_EXTENSION SmartcardExtension
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This routine is called when CTS changes its status, which means a card was
  1153. inserted or removed.
  1154. Arguments:
  1155. Return Value:
  1156. NTSTATUS
  1157. --*/
  1158. {
  1159. UNREFERENCED_PARAMETER(DeviceObject);
  1160. SmartcardDebug(
  1161. DEBUG_TRACE,
  1162. ("%s!CP8SerialCtsChanged: Enter\n",
  1163. DRIVER_NAME)
  1164. );
  1165. if (SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask) {
  1166. NTSTATUS status;
  1167. //
  1168. // Only inform the user of a card insertion/removal event
  1169. // if this function isn't called due to a power down - power up cycle
  1170. //
  1171. if (SmartcardExtension->ReaderExtension->PowerRequest == FALSE &&
  1172. SmartcardExtension->OsData->NotificationIrp) {
  1173. KIRQL oldIrql;
  1174. //
  1175. // If the user had setup an irp for event tracking complete that irp now
  1176. //
  1177. IoAcquireCancelSpinLock(
  1178. &oldIrql
  1179. );
  1180. IoSetCancelRoutine(
  1181. SmartcardExtension->OsData->NotificationIrp,
  1182. NULL
  1183. );
  1184. IoReleaseCancelSpinLock(
  1185. oldIrql
  1186. );
  1187. SmartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0;
  1188. SmartcardExtension->OsData->NotificationIrp->IoStatus.Status = STATUS_SUCCESS;
  1189. SmartcardDebug(
  1190. DEBUG_DRIVER,
  1191. ("%s!CP8SerialCtsChanged: Completing IRP %lx\n",
  1192. DRIVER_NAME,
  1193. SmartcardExtension->OsData->NotificationIrp);
  1194. );
  1195. IoCompleteRequest(
  1196. SmartcardExtension->OsData->NotificationIrp,
  1197. IO_NO_INCREMENT
  1198. );
  1199. SmartcardExtension->OsData->NotificationIrp = NULL;
  1200. }
  1201. if (SmartcardExtension->ReaderExtension->GetModemStatus) {
  1202. //
  1203. // This function requested the modem status previously.
  1204. // As part of the io-completion, this function is then
  1205. // called again. When we're here we can read the actual
  1206. // modem-status to figure out if the card is in the reader
  1207. //
  1208. PIO_STACK_LOCATION irpStack;
  1209. KIRQL oldIrql;
  1210. KeAcquireSpinLock(
  1211. &SmartcardExtension->ReaderExtension->SpinLock,
  1212. &oldIrql
  1213. );
  1214. if (SmartcardExtension->ReaderExtension->ModemStatus & SERIAL_CTS_STATE) {
  1215. //
  1216. // Card is inserted
  1217. //
  1218. SmartcardExtension->ReaderCapabilities.CurrentState =
  1219. SCARD_SWALLOWED;
  1220. SmartcardExtension->CardCapabilities.Protocol.Selected =
  1221. SCARD_PROTOCOL_UNDEFINED;
  1222. SmartcardDebug(
  1223. DEBUG_DRIVER,
  1224. ("%s!CP8SerialCtsChanged: Smart card inserted\n",
  1225. DRIVER_NAME)
  1226. );
  1227. } else {
  1228. //
  1229. // Card is removed
  1230. //
  1231. SmartcardExtension->CardCapabilities.ATR.Length = 0;
  1232. SmartcardExtension->ReaderCapabilities.CurrentState =
  1233. SCARD_ABSENT;
  1234. SmartcardExtension->CardCapabilities.Protocol.Selected =
  1235. SCARD_PROTOCOL_UNDEFINED;
  1236. SmartcardDebug(
  1237. DEBUG_DRIVER,
  1238. ("%s!CP8SerialCtsChanged: Smart card removed\n",
  1239. DRIVER_NAME)
  1240. );
  1241. }
  1242. KeReleaseSpinLock(
  1243. &SmartcardExtension->ReaderExtension->SpinLock,
  1244. oldIrql
  1245. );
  1246. irpStack = IoGetNextIrpStackLocation(
  1247. SmartcardExtension->ReaderExtension->CardStatus.Irp
  1248. );
  1249. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1250. irpStack->MinorFunction = 0UL;
  1251. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  1252. sizeof(SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask);
  1253. irpStack->Parameters.DeviceIoControl.IoControlCode =
  1254. IOCTL_SERIAL_WAIT_ON_MASK;
  1255. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  1256. &SmartcardExtension->ReaderExtension->SerialConfigData.WaitMask;
  1257. SmartcardExtension->ReaderExtension->GetModemStatus = FALSE;
  1258. SmartcardDebug(
  1259. DEBUG_DRIVER,
  1260. ("%s!CP8SerialCtsChanged: IOCTL_SERIAL_WAIT_ON_MASK\n",
  1261. DRIVER_NAME)
  1262. );
  1263. } else {
  1264. //
  1265. // Setup call for device control to get modem status.
  1266. // The CTS signal tells us if the card is inserted or removed.
  1267. // CTS is high if the card is inserted.
  1268. //
  1269. PIO_STACK_LOCATION irpStack;
  1270. irpStack = IoGetNextIrpStackLocation(
  1271. SmartcardExtension->ReaderExtension->CardStatus.Irp
  1272. );
  1273. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1274. irpStack->MinorFunction = 0UL;
  1275. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  1276. sizeof(SmartcardExtension->ReaderExtension->ModemStatus);
  1277. irpStack->Parameters.DeviceIoControl.IoControlCode =
  1278. IOCTL_SERIAL_GET_MODEMSTATUS;
  1279. SmartcardExtension->ReaderExtension->CardStatus.Irp->AssociatedIrp.SystemBuffer =
  1280. &SmartcardExtension->ReaderExtension->ModemStatus;
  1281. SmartcardExtension->ReaderExtension->GetModemStatus = TRUE;
  1282. SmartcardDebug(
  1283. DEBUG_DRIVER,
  1284. ("%s!CP8SerialCtsChanged: IOCTL_SERIAL_GET_MODEMSTATUS\n",
  1285. DRIVER_NAME)
  1286. );
  1287. }
  1288. IoSetCompletionRoutine(
  1289. SmartcardExtension->ReaderExtension->CardStatus.Irp,
  1290. CP8SerialCtsChanged,
  1291. SmartcardExtension,
  1292. TRUE,
  1293. TRUE,
  1294. TRUE
  1295. );
  1296. status = IoCallDriver(
  1297. SmartcardExtension->ReaderExtension->ConnectedSerialPort,
  1298. SmartcardExtension->ReaderExtension->CardStatus.Irp
  1299. );
  1300. SmartcardDebug(
  1301. DEBUG_TRACE,
  1302. ("%s!CP8SerialCtsChanged: Exit\n",
  1303. DRIVER_NAME)
  1304. );
  1305. return STATUS_MORE_PROCESSING_REQUIRED;
  1306. } else {
  1307. SmartcardDebug(
  1308. DEBUG_TRACE,
  1309. ("%s!CP8SerialCtsChanged: Exit (Release IRP)\n",
  1310. DRIVER_NAME)
  1311. );
  1312. return STATUS_SUCCESS;
  1313. }
  1314. }
  1315. NTSTATUS
  1316. CP8DeviceControl(
  1317. PDEVICE_OBJECT DeviceObject,
  1318. PIRP Irp
  1319. )
  1320. {
  1321. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1322. return SmartcardDeviceControl(
  1323. &(deviceExtension->SmartcardExtension),
  1324. Irp
  1325. );
  1326. }
  1327. static
  1328. ULONG
  1329. NumBitsSet(
  1330. ULONG value
  1331. )
  1332. {
  1333. ULONG i, numBits = 0;
  1334. for (i = 0; i < sizeof(value) * 8; i++) {
  1335. if (value & (1 << i)) {
  1336. numBits ++;
  1337. }
  1338. }
  1339. return numBits;
  1340. }
  1341. NTSTATUS
  1342. CP8ReaderPower(
  1343. PSMARTCARD_EXTENSION SmartcardExtension
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. The smart card lib requires to have this function. It is called
  1348. for certain power requests to the card. We do nothing here, because
  1349. this action is performed in the StartIo function.
  1350. Arguments:
  1351. SmartcardExtension - Pointer to smart card data struct.
  1352. Return Value:
  1353. NTSTATUS
  1354. --*/
  1355. {
  1356. ULONG step, waitTime, TdIndex, numTry = 0, minWaitTime;
  1357. NTSTATUS status = STATUS_SUCCESS;
  1358. PSERIAL_STATUS serialStatus;
  1359. KIRQL oldIrql;
  1360. PSERIAL_READER_CONFIG serialConfigData =
  1361. &SmartcardExtension->ReaderExtension->SerialConfigData;
  1362. SmartcardDebug(
  1363. DEBUG_TRACE,
  1364. ("%s!CP8ReaderPower: Enter (%lx)\n",
  1365. DRIVER_NAME,
  1366. SmartcardExtension->MinorIoControlCode)
  1367. );
  1368. _try {
  1369. serialConfigData->LineControl.Parity = EVEN_PARITY;
  1370. serialConfigData->LineControl.StopBits = STOP_BITS_2;
  1371. serialConfigData->BaudRate.BaudRate =
  1372. SmartcardExtension->ReaderCapabilities.DataRate.Default;
  1373. // we set very short timeouts to get the ATR as fast as possible
  1374. serialConfigData->Timeouts.ReadIntervalTimeout =
  1375. READ_INTERVAL_TIMEOUT_ATR;
  1376. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1377. READ_TOTAL_TIMEOUT_CONSTANT_ATR;
  1378. status = CP8ConfigureSerialPort(SmartcardExtension);
  1379. ASSERT(status == STATUS_SUCCESS);
  1380. if (status != STATUS_SUCCESS) {
  1381. leave;
  1382. }
  1383. status = CP8ConfigureSerialPort(
  1384. SmartcardExtension
  1385. );
  1386. if (status != STATUS_SUCCESS) {
  1387. leave;
  1388. }
  1389. //
  1390. // We don't send data to the reader, so set Number of bytes to send = 0
  1391. //
  1392. SmartcardExtension->SmartcardRequest.BufferLength = 0;
  1393. //
  1394. // Default number of bytes we expect to get back
  1395. //
  1396. SmartcardExtension->SmartcardReply.BufferLength = 0;
  1397. //
  1398. // Since power down triggers the UpdateCardStatus function, we have
  1399. // to inform it that we forced the change of the status and not the user
  1400. // (who might have removed and inserted a card)
  1401. //
  1402. SmartcardExtension->ReaderExtension->PowerRequest = TRUE;
  1403. for (step = 0; NT_SUCCESS(status) ; step++) {
  1404. switch(SmartcardExtension->MinorIoControlCode) {
  1405. case SCARD_WARM_RESET:
  1406. //
  1407. // Skip the power down (clear DTR) - power up (set DTR) sequence
  1408. //
  1409. switch (step) {
  1410. case 0:
  1411. step = 1;
  1412. break;
  1413. case 2:
  1414. step = 3;
  1415. break;
  1416. }
  1417. //
  1418. // No break here !!!
  1419. //
  1420. case SCARD_COLD_RESET:
  1421. //
  1422. // Send a power-down followed by a power-up
  1423. //
  1424. switch (step) {
  1425. case 0:
  1426. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1427. IOCTL_SERIAL_CLR_DTR;
  1428. waitTime = 15000;
  1429. break;
  1430. case 1:
  1431. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1432. IOCTL_SERIAL_CLR_RTS;
  1433. waitTime = 15000;
  1434. break;
  1435. case 2:
  1436. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1437. IOCTL_SERIAL_SET_DTR;
  1438. waitTime = 15000;
  1439. break;
  1440. case 3:
  1441. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1442. IOCTL_SERIAL_PURGE;
  1443. *(PULONG) SmartcardExtension->SmartcardRequest.Buffer =
  1444. SERIAL_PURGE_RXCLEAR;
  1445. SmartcardExtension->SmartcardRequest.BufferLength =
  1446. sizeof(ULONG);
  1447. waitTime = 0;
  1448. break;
  1449. case 4:
  1450. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1451. IOCTL_SERIAL_SET_RTS;
  1452. waitTime = 0;
  1453. break;
  1454. case 5:
  1455. //
  1456. // We now try to get the ATR as fast as possible.
  1457. // Therefor we prev. set a very short read timeout and
  1458. // 'hope' that the card delivered its ATR within this
  1459. // short time. To verify the correctness of the ATR we call
  1460. // SmartcardUpdateCardCapabilities(). If this call returns
  1461. // with STATUS_SUCCESS we know that the ATR is complete.
  1462. // Otherwise we read again and append the new data to the
  1463. // ATR buffer in the CardCapabilities and try again.
  1464. //
  1465. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1466. SMARTCARD_READ;
  1467. SmartcardExtension->SmartcardReply.BufferLength =
  1468. MAXIMUM_ATR_LENGTH -
  1469. SmartcardExtension->CardCapabilities.ATR.Length;
  1470. waitTime = 0;
  1471. break;
  1472. case 6:
  1473. if (SmartcardExtension->SmartcardReply.BufferLength != 0) {
  1474. ASSERT(
  1475. SmartcardExtension->CardCapabilities.ATR.Length +
  1476. SmartcardExtension->SmartcardReply.BufferLength <
  1477. MAXIMUM_ATR_LENGTH
  1478. );
  1479. // we got some ATR bytes.
  1480. RtlCopyMemory(
  1481. SmartcardExtension->CardCapabilities.ATR.Buffer +
  1482. SmartcardExtension->CardCapabilities.ATR.Length,
  1483. SmartcardExtension->SmartcardReply.Buffer,
  1484. SmartcardExtension->SmartcardReply.BufferLength
  1485. );
  1486. SmartcardExtension->CardCapabilities.ATR.Length +=
  1487. (UCHAR) SmartcardExtension->SmartcardReply.BufferLength;
  1488. status = SmartcardUpdateCardCapabilities(
  1489. SmartcardExtension
  1490. );
  1491. }
  1492. if (status != STATUS_SUCCESS && numTry < 100) {
  1493. // ATR is incomplete. Try again to get ATR bytes.
  1494. numTry += 1;
  1495. // continue with step 5
  1496. step = 4;
  1497. status = STATUS_TIMEOUT;
  1498. continue;
  1499. }
  1500. if (status != STATUS_SUCCESS) {
  1501. leave;
  1502. }
  1503. // No break
  1504. case 7:
  1505. KeAcquireSpinLock(
  1506. &SmartcardExtension->OsData->SpinLock,
  1507. &oldIrql
  1508. );
  1509. if (SmartcardExtension->ReaderCapabilities.CurrentState <=
  1510. SCARD_ABSENT) {
  1511. status = STATUS_MEDIA_CHANGED;
  1512. }
  1513. KeReleaseSpinLock(
  1514. &SmartcardExtension->OsData->SpinLock,
  1515. oldIrql
  1516. );
  1517. if (status != STATUS_SUCCESS) {
  1518. leave;
  1519. }
  1520. // Copy ATR to user space
  1521. if (SmartcardExtension->IoRequest.ReplyBuffer) {
  1522. RtlCopyMemory(
  1523. SmartcardExtension->IoRequest.ReplyBuffer,
  1524. SmartcardExtension->CardCapabilities.ATR.Buffer,
  1525. SmartcardExtension->CardCapabilities.ATR.Length
  1526. );
  1527. // Tell user length of ATR
  1528. *SmartcardExtension->IoRequest.Information =
  1529. SmartcardExtension->CardCapabilities.ATR.Length;
  1530. }
  1531. //
  1532. // If the card uses invers convention we need to switch
  1533. // the serial driver to odd paritiy
  1534. //
  1535. if (SmartcardExtension->CardCapabilities.InversConvention) {
  1536. serialConfigData->LineControl.Parity = ODD_PARITY;
  1537. }
  1538. //
  1539. // If the extra guard time is 255 it means that our
  1540. // frame with have to expect from the card has only
  1541. // 1 instead of 2 stop bits
  1542. // 1start bit + 8data bits + 1parity + 1stop == 11 etu
  1543. // see iso 7816-3 6.1.4.4 Extra Guard Time N
  1544. //
  1545. if (SmartcardExtension->CardCapabilities.PtsData.StopBits == 1) {
  1546. serialConfigData->LineControl.StopBits = STOP_BIT_1;
  1547. }
  1548. // depending on the protocol set the timeout values
  1549. if (SmartcardExtension->CardCapabilities.Protocol.Selected &
  1550. SCARD_PROTOCOL_T1) {
  1551. // set timeouts
  1552. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1553. serialConfigData->Timeouts.ReadIntervalTimeout =
  1554. SmartcardExtension->CardCapabilities.T1.CWT / 1000;
  1555. } else if (SmartcardExtension->CardCapabilities.Protocol.Selected &
  1556. SCARD_PROTOCOL_T0) {
  1557. // set timeouts
  1558. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1559. serialConfigData->Timeouts.ReadIntervalTimeout =
  1560. SmartcardExtension->CardCapabilities.T0.WT / 1000;
  1561. }
  1562. // Now make some adjustments depending on the system speed
  1563. minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
  1564. if (serialConfigData->Timeouts.ReadTotalTimeoutConstant <
  1565. minWaitTime) {
  1566. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1567. minWaitTime;
  1568. }
  1569. if (serialConfigData->Timeouts.ReadIntervalTimeout <
  1570. minWaitTime) {
  1571. serialConfigData->Timeouts.ReadIntervalTimeout =
  1572. minWaitTime;
  1573. }
  1574. status = CP8ConfigureSerialPort(SmartcardExtension);
  1575. ASSERT(status == STATUS_SUCCESS);
  1576. leave;
  1577. }
  1578. break;
  1579. case SCARD_POWER_DOWN:
  1580. switch (step) {
  1581. case 0:
  1582. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1583. IOCTL_SERIAL_CLR_DTR;
  1584. waitTime = 15000;
  1585. break;
  1586. case 1:
  1587. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1588. IOCTL_SERIAL_CLR_RTS;
  1589. waitTime = 15000;
  1590. break;
  1591. case 2:
  1592. SmartcardExtension->ReaderExtension->SerialIoControlCode =
  1593. IOCTL_SERIAL_SET_DTR;
  1594. waitTime = 15000;
  1595. break;
  1596. case 3:
  1597. SmartcardExtension->ReaderCapabilities.CurrentState =
  1598. SCARD_SWALLOWED;
  1599. SmartcardExtension->CardCapabilities.Protocol.Selected =
  1600. SCARD_PROTOCOL_UNDEFINED;
  1601. leave;
  1602. }
  1603. break;
  1604. }
  1605. status = CP8SerialIo(SmartcardExtension);
  1606. if (!NT_SUCCESS(status)) {
  1607. leave;
  1608. }
  1609. if (waitTime) {
  1610. LARGE_INTEGER delayPeriod;
  1611. delayPeriod.HighPart = -1;
  1612. delayPeriod.LowPart = waitTime * (-10);
  1613. KeDelayExecutionThread(
  1614. KernelMode,
  1615. FALSE,
  1616. &delayPeriod
  1617. );
  1618. }
  1619. }
  1620. }
  1621. _finally {
  1622. if (status == STATUS_TIMEOUT) {
  1623. status = STATUS_UNRECOGNIZED_MEDIA;
  1624. }
  1625. SmartcardExtension->ReaderExtension->PowerRequest = FALSE;
  1626. }
  1627. SmartcardDebug(
  1628. DEBUG_TRACE,
  1629. ("%s!CP8ReaderPower: Exit (%lxh)\n",
  1630. DRIVER_NAME,
  1631. status)
  1632. );
  1633. return status;
  1634. }
  1635. NTSTATUS
  1636. CP8SetProtocol(
  1637. PSMARTCARD_EXTENSION SmartcardExtension
  1638. )
  1639. /*++
  1640. Routine Description:
  1641. The smart card lib requires to have this function. It is called
  1642. to set a the transmission protocol and parameters. If this function
  1643. is called with a protocol mask (which means the caller doesn't card
  1644. about a particular protocol to be set) we first look if we can
  1645. set T=1 and the T=0
  1646. Arguments:
  1647. SmartcardExtension - Pointer to smart card data struct.
  1648. Return Value:
  1649. NTSTATUS
  1650. --*/
  1651. {
  1652. NTSTATUS status;
  1653. PAGED_CODE();
  1654. SmartcardDebug(
  1655. DEBUG_TRACE,
  1656. ("%s!CP8SetProtocol: Enter\n",
  1657. DRIVER_NAME)
  1658. );
  1659. try {
  1660. PUCHAR ptsRequest = SmartcardExtension->SmartcardRequest.Buffer;
  1661. PUCHAR ptsReply = SmartcardExtension->SmartcardReply.Buffer;
  1662. PSERIAL_READER_CONFIG serialConfigData =
  1663. &SmartcardExtension->ReaderExtension->SerialConfigData;
  1664. ULONG minWaitTime, newProtocol;
  1665. //
  1666. // Check if the card is already in specific state
  1667. // and if the caller wants to have the already selected protocol.
  1668. // We return success if this is the case.
  1669. //
  1670. if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC &&
  1671. (SmartcardExtension->CardCapabilities.Protocol.Selected &
  1672. SmartcardExtension->MinorIoControlCode)) {
  1673. status = STATUS_SUCCESS;
  1674. leave;
  1675. }
  1676. // set normal timeout
  1677. serialConfigData->Timeouts.ReadIntervalTimeout =
  1678. READ_INTERVAL_TIMEOUT_DEFAULT;
  1679. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1680. READ_TOTAL_TIMEOUT_CONSTANT_DEFAULT;
  1681. status = CP8ConfigureSerialPort(SmartcardExtension);
  1682. ASSERT(status == STATUS_SUCCESS);
  1683. if (status != STATUS_SUCCESS) {
  1684. leave;
  1685. }
  1686. //
  1687. // Assemble and send a pts selection
  1688. //
  1689. newProtocol = SmartcardExtension->MinorIoControlCode;
  1690. while(TRUE) {
  1691. // set initial character of PTS
  1692. ptsRequest[0] = 0xff;
  1693. // set the format character
  1694. if (SmartcardExtension->CardCapabilities.Protocol.Supported &
  1695. newProtocol &
  1696. SCARD_PROTOCOL_T1) {
  1697. // select T=1 and indicate that pts1 follows
  1698. ptsRequest[1] = 0x11;
  1699. SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
  1700. } else if (SmartcardExtension->CardCapabilities.Protocol.Supported &
  1701. newProtocol &
  1702. SCARD_PROTOCOL_T0) {
  1703. // select T=0 and indicate that pts1 follows
  1704. ptsRequest[1] = 0x10;
  1705. SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
  1706. } else {
  1707. status = STATUS_INVALID_DEVICE_REQUEST;
  1708. leave;
  1709. }
  1710. // set pts1 which codes Fl and Dl
  1711. ptsRequest[2] =
  1712. SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
  1713. SmartcardExtension->CardCapabilities.PtsData.Dl;
  1714. // set pck (check character)
  1715. ptsRequest[3] = ptsRequest[0] ^ ptsRequest[1] ^ ptsRequest[2];
  1716. SmartcardExtension->SmartcardRequest.BufferLength = 4;
  1717. SmartcardExtension->ReaderExtension->SerialIoControlCode = SMARTCARD_WRITE;
  1718. status = CP8SerialIo(SmartcardExtension);
  1719. if (status != STATUS_SUCCESS) {
  1720. leave;
  1721. }
  1722. // read back the echo of the reader
  1723. SmartcardExtension->SmartcardReply.BufferLength = 4;
  1724. SmartcardExtension->ReaderExtension->SerialIoControlCode = SMARTCARD_READ;
  1725. status = CP8SerialIo(SmartcardExtension);
  1726. if (status != STATUS_SUCCESS) {
  1727. leave;
  1728. }
  1729. // read back the pts data
  1730. status = CP8SerialIo(SmartcardExtension);
  1731. if (status != STATUS_SUCCESS &&
  1732. status != STATUS_TIMEOUT) {
  1733. leave;
  1734. }
  1735. if (status != STATUS_TIMEOUT &&
  1736. memcmp(ptsRequest, ptsReply, 4) == 0) {
  1737. // the card replied correctly to our pts-request
  1738. break;
  1739. }
  1740. if (SmartcardExtension->CardCapabilities.PtsData.Type !=
  1741. PTS_TYPE_DEFAULT) {
  1742. SmartcardDebug(
  1743. DEBUG_TRACE,
  1744. ("%s!CP8SetProtocol: PTS failed. Trying default parameters...\n",
  1745. DRIVER_NAME,
  1746. status)
  1747. );
  1748. //
  1749. // The card did either NOT reply or it replied incorrectly
  1750. // so try default values
  1751. //
  1752. SmartcardExtension->CardCapabilities.PtsData.Type =
  1753. PTS_TYPE_DEFAULT;
  1754. SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
  1755. status = CP8ReaderPower(SmartcardExtension);
  1756. continue;
  1757. }
  1758. // the card failed the pts-request
  1759. status = STATUS_DEVICE_PROTOCOL_ERROR;
  1760. leave;
  1761. }
  1762. //
  1763. // The card replied correctly to the pts request
  1764. // Set the appropriate parameters for the port
  1765. //
  1766. if (SmartcardExtension->CardCapabilities.Protocol.Selected &
  1767. SCARD_PROTOCOL_T1) {
  1768. // set timeouts
  1769. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1770. SmartcardExtension->CardCapabilities.T1.BWT / 1000;
  1771. serialConfigData->Timeouts.ReadIntervalTimeout =
  1772. SmartcardExtension->CardCapabilities.T1.CWT / 1000;
  1773. } else if (SmartcardExtension->CardCapabilities.Protocol.Selected &
  1774. SCARD_PROTOCOL_T0) {
  1775. // set timeouts
  1776. serialConfigData->Timeouts.ReadTotalTimeoutConstant =
  1777. serialConfigData->Timeouts.ReadIntervalTimeout =
  1778. SmartcardExtension->CardCapabilities.T0.WT / 1000;
  1779. }
  1780. // Now make some adjustments depending on the system speed
  1781. minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
  1782. if (serialConfigData->Timeouts.ReadTotalTimeoutConstant < minWaitTime) {
  1783. serialConfigData->Timeouts.ReadTotalTimeoutConstant = minWaitTime;
  1784. }
  1785. if (serialConfigData->Timeouts.ReadIntervalTimeout < minWaitTime) {
  1786. serialConfigData->Timeouts.ReadIntervalTimeout = minWaitTime;
  1787. }
  1788. // Change data rate according to the new settings
  1789. serialConfigData->BaudRate.BaudRate =
  1790. SmartcardExtension->CardCapabilities.PtsData.DataRate;
  1791. status = CP8ConfigureSerialPort(SmartcardExtension);
  1792. ASSERT(status == STATUS_SUCCESS);
  1793. // now indicate that we're in specific mode
  1794. SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
  1795. // return the selected protocol to the caller
  1796. *(PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
  1797. SmartcardExtension->CardCapabilities.Protocol.Selected;
  1798. *SmartcardExtension->IoRequest.Information =
  1799. sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
  1800. }
  1801. finally {
  1802. if (status == STATUS_TIMEOUT) {
  1803. // STATUS_TIMEOUT is not mapped to a Win32 error code
  1804. status = STATUS_IO_TIMEOUT;
  1805. *SmartcardExtension->IoRequest.Information = 0;
  1806. } else if (status != STATUS_SUCCESS) {
  1807. SmartcardExtension->CardCapabilities.Protocol.Selected =
  1808. SCARD_PROTOCOL_UNDEFINED;
  1809. *SmartcardExtension->IoRequest.Information = 0;
  1810. }
  1811. }
  1812. SmartcardDebug(
  1813. DEBUG_TRACE,
  1814. ("%s!CP8SetProtocol: Exit(%lx)\n",
  1815. DRIVER_NAME,
  1816. status)
  1817. );
  1818. return status;
  1819. }
  1820. NTSTATUS
  1821. CP8TransmitT0(
  1822. PSMARTCARD_EXTENSION SmartcardExtension
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. This function performs a T=0 transmission.
  1827. Arguments:
  1828. SmartcardExtension - Pointer to smart card data struct.
  1829. Return Value:
  1830. NTSTATUS
  1831. --*/
  1832. {
  1833. PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer;
  1834. PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
  1835. PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
  1836. PULONG replyLength = &SmartcardExtension->SmartcardReply.BufferLength;
  1837. PULONG serialIoControlCode = &SmartcardExtension->ReaderExtension->SerialIoControlCode;
  1838. ULONG bytesToSend, bytesToRead, currentByte = 0;
  1839. BOOLEAN restartWorkWaitingTime = FALSE;
  1840. NTSTATUS status;
  1841. SmartcardDebug(
  1842. DEBUG_PROTOCOL,
  1843. ("%s!CP8TransmitT0: Enter\n",
  1844. DRIVER_NAME)
  1845. );
  1846. try {
  1847. // Let the lib build a T=0 packet
  1848. status = SmartcardT0Request(
  1849. SmartcardExtension
  1850. );
  1851. if (status != STATUS_SUCCESS)
  1852. leave;
  1853. //
  1854. // The number of bytes we expect from the card
  1855. // is Le + 2 status bytes
  1856. //
  1857. bytesToSend = *requestLength;
  1858. bytesToRead = SmartcardExtension->T0.Le + 2;
  1859. //
  1860. // Send the first 5 bytes to the card
  1861. //
  1862. *requestLength = 5;
  1863. do {
  1864. UCHAR procByte;
  1865. //
  1866. // According to ISO 7816 a procedure byte of
  1867. // 60 should be treated as a request for a one time wait.
  1868. // In this case we do not write anything to the card
  1869. //
  1870. if (restartWorkWaitingTime == FALSE) {
  1871. SmartcardDebug(
  1872. DEBUG_PROTOCOL,
  1873. ("%s!CP8TransmitT0: -> Sending %s (%ld bytes)\n",
  1874. DRIVER_NAME,
  1875. (currentByte == 0 ? "header" : "data"),
  1876. *requestLength)
  1877. );
  1878. //
  1879. // Write to the card
  1880. //
  1881. *serialIoControlCode = SMARTCARD_WRITE;
  1882. SmartcardExtension->SmartcardRequest.Buffer = &requestBuffer[currentByte];
  1883. status = CP8SerialIo(
  1884. SmartcardExtension
  1885. );
  1886. if (status != STATUS_SUCCESS)
  1887. leave;
  1888. //
  1889. // The CP8 echos all sent bytes. We read the echo
  1890. // back into our send buffer
  1891. //
  1892. *serialIoControlCode = SMARTCARD_READ;
  1893. *replyLength = *requestLength;
  1894. SmartcardExtension->SmartcardReply.Buffer = &requestBuffer[currentByte];
  1895. status = CP8SerialIo(
  1896. SmartcardExtension
  1897. );
  1898. if (status != STATUS_SUCCESS)
  1899. leave;
  1900. currentByte += *requestLength;
  1901. bytesToSend -= *requestLength;
  1902. }
  1903. // Read the 'Procedure byte'.
  1904. SmartcardExtension->SmartcardReply.Buffer = &procByte;
  1905. *serialIoControlCode = SMARTCARD_READ;
  1906. *replyLength = 1;
  1907. status = CP8SerialIo(
  1908. SmartcardExtension
  1909. );
  1910. if (status != STATUS_SUCCESS)
  1911. leave;
  1912. restartWorkWaitingTime = FALSE;
  1913. //
  1914. // Check the procedure byte.
  1915. // Please take a look at ISO 7816 Part 3 Section 8.2.2
  1916. //
  1917. if (procByte == requestBuffer[1] ||
  1918. procByte == requestBuffer[1] + 1) {
  1919. SmartcardDebug(
  1920. DEBUG_PROTOCOL,
  1921. ("%s!CP8TransmitT0: <- ACK (send all)\n",
  1922. DRIVER_NAME)
  1923. );
  1924. // All remaining data bytes can be sent at once
  1925. *requestLength = bytesToSend;
  1926. } else if (procByte == (UCHAR) ~requestBuffer[1] ||
  1927. procByte == (UCHAR) ~(requestBuffer[1] + 1)) {
  1928. SmartcardDebug(
  1929. DEBUG_PROTOCOL,
  1930. ("%s!CP8TransmitT0: <- ACK (send single)\n",
  1931. DRIVER_NAME)
  1932. );
  1933. // We can send only one byte
  1934. *requestLength = 1;
  1935. } else if (procByte == 0x60 ||
  1936. SmartcardExtension->CardCapabilities.InversConvention &&
  1937. procByte == 0xf9) {
  1938. //
  1939. // We have to reset the wait time and try again to read
  1940. //
  1941. ULONG TimeRes;
  1942. LARGE_INTEGER delayTime;
  1943. SmartcardDebug(
  1944. DEBUG_PROTOCOL,
  1945. ("%s!CP8TransmitT0: <- NULL (%ldms)\n",
  1946. DRIVER_NAME,
  1947. SmartcardExtension->CardCapabilities.T0.WT / 1000)
  1948. );
  1949. TimeRes = KeQueryTimeIncrement();
  1950. delayTime.HighPart = -1;
  1951. delayTime.LowPart =
  1952. (-1) *
  1953. TimeRes *
  1954. ((SmartcardExtension->CardCapabilities.T0.WT * 10l / TimeRes) + 1);
  1955. KeDelayExecutionThread(
  1956. KernelMode,
  1957. FALSE,
  1958. &delayTime
  1959. );
  1960. //
  1961. // Set flag that we only should read the proc byte
  1962. // without writing data to the card
  1963. //
  1964. restartWorkWaitingTime = TRUE;
  1965. } else {
  1966. //
  1967. // The card returned a status byte.
  1968. // Status bytes are always two bytes long.
  1969. // Store this byte first and then read the next
  1970. //
  1971. replyBuffer[0] = procByte;
  1972. *serialIoControlCode = SMARTCARD_READ;
  1973. *replyLength = 1;
  1974. bytesToSend = 0;
  1975. bytesToRead = 0;
  1976. //
  1977. // Read in the second status byte
  1978. //
  1979. SmartcardExtension->SmartcardReply.Buffer =
  1980. &replyBuffer[1];
  1981. status = CP8SerialIo(
  1982. SmartcardExtension
  1983. );
  1984. SmartcardExtension->SmartcardReply.BufferLength = 2;
  1985. SmartcardDebug(
  1986. DEBUG_PROTOCOL,
  1987. ("%s!CP8TransmitT0: <- SW1=%02x SW2=%02x\n",
  1988. DRIVER_NAME,
  1989. replyBuffer[0],
  1990. replyBuffer[1])
  1991. );
  1992. }
  1993. } while(bytesToSend || restartWorkWaitingTime);
  1994. if (status != STATUS_SUCCESS)
  1995. leave;
  1996. if (bytesToRead != 0) {
  1997. *serialIoControlCode = SMARTCARD_READ;
  1998. *replyLength = bytesToRead;
  1999. SmartcardExtension->SmartcardReply.Buffer =
  2000. replyBuffer;
  2001. status = CP8SerialIo(
  2002. SmartcardExtension
  2003. );
  2004. #if DEBUG
  2005. if (status == STATUS_SUCCESS) {
  2006. SmartcardDebug(
  2007. DEBUG_PROTOCOL,
  2008. ("%s!CP8TransmitT0: <- Data %ld bytes, SW1=%02x SW2=%02x\n",
  2009. DRIVER_NAME,
  2010. bytesToRead,
  2011. replyBuffer[bytesToRead - 2],
  2012. replyBuffer[bytesToRead - 1])
  2013. );
  2014. }
  2015. #endif
  2016. }
  2017. }
  2018. finally {
  2019. // Restore pointers to their original location
  2020. SmartcardExtension->SmartcardRequest.Buffer =
  2021. requestBuffer;
  2022. SmartcardExtension->SmartcardReply.Buffer =
  2023. replyBuffer;
  2024. if (status == STATUS_SUCCESS) {
  2025. status = SmartcardT0Reply(
  2026. SmartcardExtension
  2027. );
  2028. }
  2029. }
  2030. SmartcardDebug(
  2031. DEBUG_PROTOCOL,
  2032. ("%s!CP8TransmitT0: Exit(%lx)\n",
  2033. DRIVER_NAME,
  2034. status)
  2035. );
  2036. return status;
  2037. }
  2038. NTSTATUS
  2039. CP8Transmit(
  2040. PSMARTCARD_EXTENSION SmartcardExtension
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. This function is called by the smart card library whenever a transmission
  2045. is required.
  2046. Arguments:
  2047. SmartcardExtension - Pointer to smart card data struct.
  2048. Return Value:
  2049. NTSTATUS
  2050. --*/
  2051. {
  2052. NTSTATUS status;
  2053. _try {
  2054. do {
  2055. PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer;
  2056. PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer;
  2057. PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength;
  2058. PULONG replyLength = &SmartcardExtension->SmartcardReply.BufferLength;
  2059. PULONG serialIoControlCode = &SmartcardExtension->ReaderExtension->SerialIoControlCode;
  2060. //
  2061. // Tell the lib function how many bytes I need for the prologue
  2062. //
  2063. *requestLength = 0;
  2064. switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
  2065. case SCARD_PROTOCOL_RAW:
  2066. status = SmartcardRawRequest(SmartcardExtension);
  2067. break;
  2068. case SCARD_PROTOCOL_T0:
  2069. //
  2070. // T=0 requires a bit more work.
  2071. // So we do this in a seperate function.
  2072. //
  2073. status = CP8TransmitT0(SmartcardExtension);
  2074. leave;
  2075. case SCARD_PROTOCOL_T1:
  2076. status = SmartcardT1Request(SmartcardExtension);
  2077. break;
  2078. default:
  2079. status = STATUS_INVALID_DEVICE_REQUEST;
  2080. leave;
  2081. }
  2082. if (status != STATUS_SUCCESS) {
  2083. leave;
  2084. }
  2085. //
  2086. // Write the command to the card
  2087. //
  2088. *replyLength = 0;
  2089. *serialIoControlCode = SMARTCARD_WRITE;
  2090. status = CP8SerialIo(SmartcardExtension);
  2091. if (status != STATUS_SUCCESS) {
  2092. leave;
  2093. }
  2094. //
  2095. // The Bull reader always echos the bytes sent, so read that echo back
  2096. //
  2097. *serialIoControlCode = SMARTCARD_READ;
  2098. *replyLength = *requestLength;
  2099. status = CP8SerialIo(SmartcardExtension);
  2100. if (status != STATUS_SUCCESS) {
  2101. leave;
  2102. }
  2103. switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
  2104. case SCARD_PROTOCOL_RAW:
  2105. status = SmartcardRawReply(SmartcardExtension);
  2106. break;
  2107. case SCARD_PROTOCOL_T1:
  2108. //
  2109. // Check if the card requested a waiting time extension
  2110. //
  2111. if (SmartcardExtension->T1.Wtx) {
  2112. LARGE_INTEGER waitTime;
  2113. waitTime.HighPart = -1;
  2114. waitTime.LowPart =
  2115. SmartcardExtension->T1.Wtx *
  2116. SmartcardExtension->CardCapabilities.T1.BWT *
  2117. (-10);
  2118. KeDelayExecutionThread(
  2119. KernelMode,
  2120. FALSE,
  2121. &waitTime
  2122. );
  2123. }
  2124. //
  2125. // Read NAD, PCB and LEN fields
  2126. //
  2127. *replyLength = 3;
  2128. status = CP8SerialIo(SmartcardExtension);
  2129. //
  2130. // Check for timeout first. If the card did not reply
  2131. // we need to send a resend request
  2132. //
  2133. if (status != STATUS_TIMEOUT) {
  2134. if (status != STATUS_SUCCESS) {
  2135. leave;
  2136. }
  2137. //
  2138. // The third byte contains the length of the data in the packet
  2139. // and we additinally want to have the EDC bytes which
  2140. // is one for LRC and 2 for CRC
  2141. //
  2142. *replyLength =
  2143. replyBuffer[2] +
  2144. (SmartcardExtension->CardCapabilities.T1.EDC & 0x01 ? 2 : 1);
  2145. //
  2146. // We want to have the remaining bytes just after the first 3
  2147. //
  2148. SmartcardExtension->SmartcardReply.Buffer += 3;
  2149. status = CP8SerialIo(SmartcardExtension);
  2150. SmartcardExtension->SmartcardReply.Buffer -= 3;
  2151. SmartcardExtension->SmartcardReply.BufferLength += 3;
  2152. if (status != STATUS_SUCCESS && status != STATUS_TIMEOUT) {
  2153. leave;
  2154. }
  2155. }
  2156. if (status == STATUS_TIMEOUT) {
  2157. //
  2158. // Since the card did not reply we set the number of
  2159. // bytes received to 0. This will trigger a resend
  2160. // request
  2161. //
  2162. SmartcardDebug(
  2163. DEBUG_PROTOCOL,
  2164. ("%s!TLP3TransmitT1: Timeout\n",
  2165. DRIVER_NAME)
  2166. );
  2167. SmartcardExtension->SmartcardReply.BufferLength = 0;
  2168. }
  2169. status = SmartcardT1Reply(SmartcardExtension);
  2170. break;
  2171. default:
  2172. status = STATUS_INVALID_DEVICE_REQUEST;
  2173. leave;
  2174. }
  2175. } while (status == STATUS_MORE_PROCESSING_REQUIRED);
  2176. }
  2177. _finally {
  2178. if (status == STATUS_TIMEOUT) {
  2179. // STATUS_TIMEOUT is not mapped to a Win32 error code
  2180. status = STATUS_IO_TIMEOUT;
  2181. }
  2182. }
  2183. return status;
  2184. }
  2185. NTSTATUS
  2186. CP8CardTracking(
  2187. PSMARTCARD_EXTENSION SmartcardExtension
  2188. )
  2189. /*++
  2190. Routine Description:
  2191. The smart card lib requires to have this function. It is called
  2192. to setup event tracking for card insertion and removal events.
  2193. Arguments:
  2194. SmartcardExtension - pointer to the smart card data struct.
  2195. Return Value:
  2196. NTSTATUS
  2197. --*/
  2198. {
  2199. KIRQL oldIrql;
  2200. //
  2201. // Set cancel routine for the notification irp
  2202. //
  2203. IoAcquireCancelSpinLock(
  2204. &oldIrql
  2205. );
  2206. IoSetCancelRoutine(
  2207. SmartcardExtension->OsData->NotificationIrp,
  2208. CP8Cancel
  2209. );
  2210. IoReleaseCancelSpinLock(
  2211. oldIrql
  2212. );
  2213. return STATUS_PENDING;
  2214. }
  2215. NTSTATUS
  2216. CP8VendorIoctl(
  2217. PSMARTCARD_EXTENSION SmartcardExtension
  2218. )
  2219. {
  2220. if (SmartcardExtension->IoRequest.ReplyBuffer != NULL &&
  2221. SmartcardExtension->IoRequest.ReplyBufferLength >= sizeof(ULONG)) {
  2222. *(PULONG) SmartcardExtension->IoRequest.ReplyBuffer = 0xCDAB3412;
  2223. *SmartcardExtension->IoRequest.Information = sizeof(ULONG);
  2224. return STATUS_SUCCESS;
  2225. }
  2226. return STATUS_BUFFER_TOO_SMALL;
  2227. }