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.

748 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) SCM Microsystems, 1998 - 1999
  6. //
  7. // File: serialnt.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "drivernt.h"
  11. #include "stc.h"
  12. #include "cbhndlr.h"
  13. #include "drvnt5.h"
  14. const ULONG ConfigTable[] =
  15. {
  16. IOCTL_SERIAL_SET_BAUD_RATE,
  17. IOCTL_SERIAL_SET_LINE_CONTROL,
  18. IOCTL_SERIAL_SET_CHARS,
  19. IOCTL_SERIAL_SET_TIMEOUTS,
  20. IOCTL_SERIAL_SET_HANDFLOW,
  21. #if !defined( __NT4__ )
  22. IOCTL_SERIAL_PURGE,
  23. #endif
  24. IOCTL_SERIAL_SET_BREAK_OFF,
  25. IOCTL_SERIAL_SET_WAIT_MASK,
  26. 0
  27. };
  28. NTSTATUS
  29. IFInitializeInterface(
  30. PREADER_EXTENSION ReaderExtension,
  31. PVOID ConfigData
  32. )
  33. /*++
  34. Routine Description:
  35. Arguments:
  36. Return Value:
  37. --*/
  38. {
  39. NTSTATUS NTStatus = STATUS_SUCCESS;
  40. ULONG OutDataLen;
  41. PVOID OutData;
  42. PULONG ActIoctl;
  43. PSERIAL_PORT_CONFIG SerialPortConfig = (PSERIAL_PORT_CONFIG) ConfigData;
  44. //
  45. // set all parameters defined in config table
  46. //
  47. ActIoctl = (PULONG) ConfigTable;
  48. do
  49. {
  50. switch( *ActIoctl )
  51. {
  52. case IOCTL_SERIAL_SET_BAUD_RATE:
  53. OutData = &SerialPortConfig->BaudRate;
  54. OutDataLen = sizeof( SERIAL_BAUD_RATE );
  55. break;
  56. case IOCTL_SERIAL_SET_LINE_CONTROL:
  57. OutData = &SerialPortConfig->LineControl;
  58. OutDataLen = sizeof( SERIAL_LINE_CONTROL );
  59. break;
  60. case IOCTL_SERIAL_SET_CHARS:
  61. OutData = &SerialPortConfig->SerialChars;
  62. OutDataLen = sizeof( SERIAL_CHARS );
  63. break;
  64. case IOCTL_SERIAL_SET_TIMEOUTS:
  65. OutData = &SerialPortConfig->Timeouts;
  66. OutDataLen = sizeof( SERIAL_TIMEOUTS );
  67. break;
  68. case IOCTL_SERIAL_SET_HANDFLOW:
  69. OutData = &SerialPortConfig->HandFlow;
  70. OutDataLen = sizeof( SERIAL_HANDFLOW );
  71. break;
  72. case IOCTL_SERIAL_SET_WAIT_MASK:
  73. OutData = &SerialPortConfig->WaitMask;
  74. OutDataLen = sizeof( ULONG );
  75. break;
  76. case IOCTL_SERIAL_PURGE:
  77. OutData = &SerialPortConfig->Purge;
  78. OutDataLen = sizeof( ULONG );
  79. break;
  80. case IOCTL_SERIAL_SET_BREAK_OFF:
  81. OutData = NULL;
  82. OutDataLen = 0;
  83. break;
  84. }
  85. NTStatus = IFSerialIoctl(
  86. ReaderExtension,
  87. *ActIoctl,
  88. OutData,
  89. OutDataLen,
  90. NULL,
  91. 0
  92. );
  93. SysDelay(25);
  94. } while( *(++ActIoctl) && ( NTStatus == STATUS_SUCCESS ));
  95. if( NTStatus == STATUS_SUCCESS )
  96. {
  97. // initialize the read thread
  98. NTStatus = IFSerialWaitOnMask( ReaderExtension );
  99. }
  100. return( NTStatus );
  101. }
  102. NTSTATUS
  103. IFWrite(
  104. PREADER_EXTENSION ReaderExtension,
  105. PUCHAR OutData,
  106. ULONG OutDataLen
  107. )
  108. /*++
  109. Routine Description:
  110. Arguments:
  111. Return Value:
  112. --*/
  113. {
  114. NTSTATUS NTStatus = STATUS_INSUFFICIENT_RESOURCES;
  115. IO_STATUS_BLOCK IoStatus;
  116. KEVENT Event;
  117. PIRP Irp;
  118. PIO_STACK_LOCATION IrpStack;
  119. if (KeReadStateEvent(&(ReaderExtension->SerialCloseDone))) {
  120. //
  121. // we have no connection to serial, fail the call
  122. // this could be the case if the reader was removed
  123. // during stand by / hibernation
  124. //
  125. return STATUS_UNSUCCESSFUL;
  126. }
  127. ReaderExtension->Available = 0;
  128. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  129. //
  130. // build irp to be send to serial driver
  131. //
  132. Irp = IoBuildDeviceIoControlRequest(
  133. SERIAL_WRITE,
  134. ReaderExtension->SerialDeviceObject,
  135. OutData,
  136. OutDataLen,
  137. NULL,
  138. 0,
  139. FALSE,
  140. &Event,
  141. &IoStatus
  142. );
  143. if( Irp != NULL )
  144. {
  145. IrpStack = IoGetNextIrpStackLocation( Irp );
  146. IrpStack->MajorFunction = IRP_MJ_WRITE;
  147. IrpStack->Parameters.Write.Length = OutDataLen;
  148. IrpStack->Parameters.Write.ByteOffset.QuadPart = 0;
  149. NTStatus = IoCallDriver( ReaderExtension->SerialDeviceObject, Irp );
  150. if( NTStatus == STATUS_PENDING )
  151. {
  152. KeWaitForSingleObject(
  153. &Event,
  154. Executive,
  155. KernelMode,
  156. FALSE,
  157. NULL
  158. );
  159. NTStatus = IoStatus.Status;
  160. }
  161. }
  162. return( NTStatus );
  163. }
  164. NTSTATUS
  165. IFRead(
  166. PREADER_EXTENSION ReaderExtension,
  167. PUCHAR InData,
  168. ULONG InDataLen
  169. )
  170. /*++
  171. Routine Description:
  172. Arguments:
  173. Return Value:
  174. --*/
  175. {
  176. NTSTATUS NTStatus = STATUS_UNSUCCESSFUL;
  177. KIRQL CurrentIrql;
  178. // acquire spinlock to protect buffer/flag manipulation
  179. KeAcquireSpinLock( &ReaderExtension->ReadSpinLock, &CurrentIrql );
  180. // check if data already available
  181. if( ReaderExtension->Available >= InDataLen )
  182. {
  183. NTStatus = STATUS_SUCCESS;
  184. }
  185. else
  186. {
  187. LARGE_INTEGER Timeout;
  188. // setup read thread
  189. ReaderExtension->Expected = InDataLen;
  190. KeClearEvent( &ReaderExtension->DataAvailable );
  191. KeReleaseSpinLock( &ReaderExtension->ReadSpinLock, CurrentIrql );
  192. // setup wait time (in 100 ns)
  193. Timeout.QuadPart =
  194. (LONGLONG) ReaderExtension->ReadTimeout * -10L * 1000;
  195. NTStatus = KeWaitForSingleObject(
  196. &ReaderExtension->DataAvailable,
  197. Executive,
  198. KernelMode,
  199. FALSE,
  200. &Timeout
  201. );
  202. KeAcquireSpinLock(&ReaderExtension->ReadSpinLock, &CurrentIrql);
  203. // reset the read queue
  204. KeClearEvent(&ReaderExtension->DataAvailable);
  205. }
  206. if( NTStatus == STATUS_SUCCESS )
  207. {
  208. if (ReaderExtension->Available >= InDataLen) {
  209. SysCopyMemory(
  210. InData,
  211. &ReaderExtension->TPDUStack[0],
  212. InDataLen
  213. );
  214. ReaderExtension->Available -= InDataLen;
  215. SysCopyMemory(
  216. &ReaderExtension->TPDUStack[ 0 ],
  217. &ReaderExtension->TPDUStack[ InDataLen ],
  218. ReaderExtension->Available
  219. );
  220. } else {
  221. //
  222. // oops, that should not happen.
  223. // InDataLen should not be bigger than
  224. // the number of bytes available
  225. //
  226. ASSERT(FALSE);
  227. NTStatus = STATUS_IO_TIMEOUT;
  228. }
  229. }
  230. else
  231. {
  232. // ReaderExtension->Available = 0;;
  233. NTStatus = STATUS_IO_TIMEOUT;
  234. }
  235. if( NTStatus != STATUS_SUCCESS )
  236. {
  237. NTStatus = STATUS_IO_TIMEOUT;
  238. }
  239. ReaderExtension->Expected = 0;
  240. KeReleaseSpinLock( &ReaderExtension->ReadSpinLock, CurrentIrql );
  241. return( NTStatus );
  242. }
  243. NTSTATUS
  244. IFSerialIoctl(
  245. PREADER_EXTENSION ReaderExtension,
  246. ULONG IoctlCode,
  247. PVOID OutData,
  248. ULONG OutDataLen,
  249. PVOID InData,
  250. ULONG InDataLen
  251. )
  252. /*++
  253. Routine Description:
  254. Arguments:
  255. Return Value:
  256. --*/
  257. {
  258. NTSTATUS NTStatus = STATUS_INSUFFICIENT_RESOURCES;
  259. IO_STATUS_BLOCK IoStatus;
  260. KEVENT Event;
  261. PIRP Irp;
  262. if (KeReadStateEvent(&(ReaderExtension->SerialCloseDone))) {
  263. //
  264. // we have no connection to serial, fail the call
  265. // this could be the case if the reader was removed
  266. // during stand by / hibernation
  267. //
  268. return STATUS_UNSUCCESSFUL;
  269. }
  270. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  271. //
  272. // build irp to be send to serial driver
  273. //
  274. Irp = IoBuildDeviceIoControlRequest(
  275. IoctlCode,
  276. ReaderExtension->SerialDeviceObject,
  277. OutData,
  278. OutDataLen,
  279. InData,
  280. InDataLen,
  281. FALSE,
  282. &Event,
  283. &IoStatus
  284. );
  285. if( Irp != NULL )
  286. {
  287. NTStatus = IoCallDriver( ReaderExtension->SerialDeviceObject, Irp );
  288. if( NTStatus == STATUS_PENDING )
  289. {
  290. LARGE_INTEGER Timeout;
  291. Timeout.QuadPart =
  292. (LONGLONG) ReaderExtension->ReadTimeout * -10 * 1000;
  293. KeWaitForSingleObject(
  294. &Event,
  295. Executive,
  296. KernelMode,
  297. FALSE,
  298. &Timeout
  299. );
  300. NTStatus = IoStatus.Status;
  301. }
  302. }
  303. return( NTStatus );
  304. }
  305. NTSTATUS
  306. IFSerialRead(
  307. PREADER_EXTENSION ReaderExtension,
  308. PUCHAR InData,
  309. ULONG InDataLen
  310. )
  311. {
  312. NTSTATUS NTStatus = STATUS_INSUFFICIENT_RESOURCES;
  313. IO_STATUS_BLOCK IoStatus;
  314. KEVENT Event;
  315. PIRP Irp;
  316. PIO_STACK_LOCATION IrpStack;
  317. if (KeReadStateEvent(&(ReaderExtension->SerialCloseDone))) {
  318. //
  319. // we have no connection to serial, fail the call
  320. // this could be the case if the reader was removed
  321. // during stand by / hibernation
  322. //
  323. return STATUS_UNSUCCESSFUL;
  324. }
  325. // build irp to be send to serial driver
  326. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  327. Irp = IoBuildDeviceIoControlRequest(
  328. SERIAL_READ,
  329. ReaderExtension->SerialDeviceObject,
  330. NULL,
  331. 0,
  332. InData,
  333. InDataLen,
  334. FALSE,
  335. &Event,
  336. &IoStatus
  337. );
  338. if( Irp != NULL )
  339. {
  340. IrpStack = IoGetNextIrpStackLocation( Irp );
  341. IrpStack->MajorFunction = IRP_MJ_READ;
  342. IrpStack->Parameters.Read.Length = InDataLen;
  343. NTStatus = IoCallDriver( ReaderExtension->SerialDeviceObject, Irp );
  344. if( NTStatus == STATUS_PENDING )
  345. {
  346. KeWaitForSingleObject(
  347. &Event,
  348. Executive,
  349. KernelMode,
  350. FALSE,
  351. NULL
  352. );
  353. NTStatus = IoStatus.Status;
  354. }
  355. }
  356. return( NTStatus );
  357. }
  358. NTSTATUS
  359. IFSerialWaitOnMask( PREADER_EXTENSION ReaderExtension )
  360. /*++
  361. Routine Description:
  362. Arguments:
  363. Return Value:
  364. --*/
  365. {
  366. PIRP irp;
  367. PIO_STACK_LOCATION irpSp;
  368. NTSTATUS NTStatus;
  369. if (KeReadStateEvent(&(ReaderExtension->SerialCloseDone))) {
  370. //
  371. // we have no connection to serial, fail the call
  372. // this could be the case if the reader was removed
  373. // during stand by / hibernation
  374. //
  375. return STATUS_UNSUCCESSFUL;
  376. }
  377. irp = IoAllocateIrp(
  378. (CCHAR) (ReaderExtension->SerialDeviceObject->StackSize + 1),
  379. FALSE
  380. );
  381. ASSERT(irp != NULL);
  382. if (irp == NULL) {
  383. return STATUS_INSUFFICIENT_RESOURCES;
  384. }
  385. irpSp = IoGetNextIrpStackLocation( irp );
  386. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  387. irpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  388. irpSp->Parameters.DeviceIoControl.OutputBufferLength =
  389. sizeof(ReaderExtension->EventMask);
  390. irpSp->Parameters.DeviceIoControl.IoControlCode =
  391. IOCTL_SERIAL_WAIT_ON_MASK;
  392. irp->AssociatedIrp.SystemBuffer = &ReaderExtension->EventMask;
  393. // set completion routine & start io
  394. IoSetCompletionRoutine(
  395. irp,
  396. IFReadThreadCallback,
  397. ReaderExtension,
  398. TRUE,
  399. TRUE,
  400. TRUE
  401. );
  402. NTStatus = IoCallDriver( ReaderExtension->SerialDeviceObject, irp );
  403. return (NTStatus == STATUS_PENDING ? STATUS_SUCCESS : NTStatus);
  404. }
  405. NTSTATUS
  406. IFReadThreadCallback(
  407. PDEVICE_OBJECT DeviceObject,
  408. PIRP Irp,
  409. PREADER_EXTENSION ReaderExtension
  410. )
  411. /*++
  412. Routine Description:
  413. Arguments:
  414. Return Value:
  415. --*/
  416. {
  417. // event_rx?
  418. if( ReaderExtension->EventMask & SERIAL_EV_RXCHAR )
  419. {
  420. IoQueueWorkItem(
  421. ReaderExtension->ReadWorkItem,
  422. (PIO_WORKITEM_ROUTINE) IFReadWorkRoutine,
  423. CriticalWorkQueue,
  424. ReaderExtension
  425. );
  426. }
  427. else
  428. {
  429. SmartcardDebug(
  430. DEBUG_TRACE,
  431. ("SCMSTCS!IFReadThreadCallback: Device removed\n" )
  432. );
  433. ReaderExtension->SmartcardExtension->ReaderCapabilities.CurrentState =
  434. (ULONG) SCARD_UNKNOWN;
  435. // last call: disconnect from the serial driver
  436. IoQueueWorkItem(
  437. ReaderExtension->CloseSerial,
  438. (PIO_WORKITEM_ROUTINE) DrvWaitForDeviceRemoval,
  439. DelayedWorkQueue,
  440. NULL
  441. );
  442. }
  443. IoFreeIrp(Irp);
  444. return STATUS_MORE_PROCESSING_REQUIRED;
  445. }
  446. VOID
  447. IFReadWorkRoutine(
  448. IN PDEVICE_OBJECT DeviceObject,
  449. IN PREADER_EXTENSION ReaderExtension
  450. )
  451. {
  452. NTSTATUS NTStatus = STATUS_SUCCESS;
  453. PIO_STACK_LOCATION IrpStack;
  454. PIRP Irp;
  455. SERIAL_STATUS CommStatus;
  456. PUCHAR IOData;
  457. BOOLEAN purgePort = FALSE;
  458. BOOLEAN bUpdatCardState = FALSE;
  459. USHORT shrtBuf;
  460. ASSERT( ReaderExtension != NULL );
  461. if (ReaderExtension == NULL) {
  462. return;
  463. }
  464. __try {
  465. IOData = &ReaderExtension->IOData[0];
  466. while (NTStatus == STATUS_SUCCESS) {
  467. // read head
  468. NTStatus = IFSerialRead(
  469. ReaderExtension,
  470. &IOData[0],
  471. 3
  472. );
  473. if (NTStatus != STATUS_SUCCESS) {
  474. __leave;
  475. }
  476. if ((IOData[NAD_IDX] & 0x20) != 0x20) {
  477. SmartcardDebug(
  478. DEBUG_ERROR,
  479. ("SCMSTCS!IFReadWorkRoutine: Invalid packet received\n" )
  480. );
  481. purgePort = TRUE;
  482. __leave;
  483. }
  484. if (IOData[LEN_IDX] > STC_BUFFER_SIZE - 4) {
  485. purgePort = TRUE;
  486. __leave;
  487. }
  488. // read tail
  489. NTStatus = IFSerialRead(
  490. ReaderExtension,
  491. &IOData[DATA_IDX],
  492. IOData[LEN_IDX] + 1
  493. );
  494. ASSERT(NTStatus == STATUS_SUCCESS);
  495. if (NTStatus != STATUS_SUCCESS) {
  496. purgePort = TRUE;
  497. __leave;
  498. }
  499. if (IOData[LEN_IDX] == 0) {
  500. purgePort = TRUE;
  501. __leave;
  502. }
  503. // check for card insertion / removal
  504. RtlRetrieveUshort(&shrtBuf, &IOData[DATA_IDX]);
  505. if( ( IOData[NAD_IDX] == STC1_TO_HOST ) &&
  506. ( IOData[LEN_IDX] == 2 ) &&
  507. ( (shrtBuf == SW_INSERTED) ||
  508. (shrtBuf == SW_REMOVED))) {
  509. CBUpdateCardState(
  510. ReaderExtension->SmartcardExtension,
  511. (shrtBuf == SW_INSERTED ? SCARD_PRESENT : SCARD_ABSENT)
  512. );
  513. } else {
  514. KIRQL CurrentIrql;
  515. // acquire spinlock to protect buffer/flag manipulation
  516. KeAcquireSpinLock(
  517. &ReaderExtension->ReadSpinLock,
  518. &CurrentIrql
  519. );
  520. // check size & copy data to TPDU stack
  521. ASSERT(
  522. ReaderExtension->Available+IOData[LEN_IDX] + 4 <
  523. TPDU_STACK_SIZE
  524. );
  525. if (ReaderExtension->Available + IOData[LEN_IDX] + 4 <
  526. TPDU_STACK_SIZE ) {
  527. SysCopyMemory(
  528. &ReaderExtension->TPDUStack[ReaderExtension->Available],
  529. &IOData[ 0 ],
  530. IOData[ LEN_IDX ] + 4
  531. );
  532. ReaderExtension->Available +=
  533. IOData[LEN_IDX] + 4;
  534. if(ReaderExtension->Available >= ReaderExtension->Expected ) {
  535. KeSetEvent(
  536. &ReaderExtension->DataAvailable,
  537. IO_SERIAL_INCREMENT,
  538. FALSE
  539. );
  540. }
  541. }
  542. KeReleaseSpinLock( &ReaderExtension->ReadSpinLock, CurrentIrql );
  543. }
  544. }
  545. }
  546. __finally {
  547. if (purgePort) {
  548. ULONG request;
  549. KIRQL CurrentIrql;
  550. // acquire spinlock to protect buffer/flag manipulation
  551. KeAcquireSpinLock(
  552. &ReaderExtension->ReadSpinLock,
  553. &CurrentIrql
  554. );
  555. ReaderExtension->Available = 0;
  556. KeReleaseSpinLock(
  557. &ReaderExtension->ReadSpinLock,
  558. CurrentIrql
  559. );
  560. // we got an error and need to clean up the port
  561. request = SR_PURGE;
  562. NTStatus = IFSerialIoctl(
  563. ReaderExtension,
  564. IOCTL_SERIAL_PURGE,
  565. &request,
  566. sizeof(request),
  567. NULL,
  568. 0
  569. );
  570. ASSERT(NTStatus == STATUS_SUCCESS);
  571. }
  572. IFSerialWaitOnMask( ReaderExtension );
  573. }
  574. }
  575. UCHAR IFCalcLRC( PUCHAR IOData, ULONG IODataLen )
  576. {
  577. ULONG Idx = 0;
  578. UCHAR CS = 0;
  579. do CS ^= IOData[ Idx ];
  580. while( ++Idx < IODataLen );
  581. return( CS );
  582. }
  583. //---------------------------------------- END OF FILE ----------------------------------------