Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

756 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. KIRQL irql;
  418. // event_rx?
  419. if( ReaderExtension->EventMask & SERIAL_EV_RXCHAR )
  420. {
  421. IoQueueWorkItem(
  422. ReaderExtension->ReadWorkItem,
  423. (PIO_WORKITEM_ROUTINE) IFReadWorkRoutine,
  424. CriticalWorkQueue,
  425. ReaderExtension
  426. );
  427. }
  428. else
  429. {
  430. SmartcardDebug(
  431. DEBUG_TRACE,
  432. ("SCMSTCS!IFReadThreadCallback: Device removed\n" )
  433. );
  434. KeAcquireSpinLock(&ReaderExtension->SmartcardExtension->OsData->SpinLock,
  435. &irql);
  436. ReaderExtension->SmartcardExtension->ReaderCapabilities.CurrentState =
  437. (ULONG) SCARD_UNKNOWN;
  438. KeReleaseSpinLock(&ReaderExtension->SmartcardExtension->OsData->SpinLock,
  439. irql);
  440. // last call: disconnect from the serial driver
  441. IoQueueWorkItem(
  442. ReaderExtension->CloseSerial,
  443. (PIO_WORKITEM_ROUTINE) DrvWaitForDeviceRemoval,
  444. DelayedWorkQueue,
  445. NULL
  446. );
  447. }
  448. IoFreeIrp(Irp);
  449. return STATUS_MORE_PROCESSING_REQUIRED;
  450. }
  451. VOID
  452. IFReadWorkRoutine(
  453. IN PDEVICE_OBJECT DeviceObject,
  454. IN PREADER_EXTENSION ReaderExtension
  455. )
  456. {
  457. NTSTATUS NTStatus = STATUS_SUCCESS;
  458. PIO_STACK_LOCATION IrpStack;
  459. PIRP Irp;
  460. SERIAL_STATUS CommStatus;
  461. PUCHAR IOData;
  462. BOOLEAN purgePort = FALSE;
  463. BOOLEAN bUpdatCardState = FALSE;
  464. USHORT shrtBuf;
  465. ASSERT( ReaderExtension != NULL );
  466. if (ReaderExtension == NULL) {
  467. return;
  468. }
  469. __try {
  470. IOData = &ReaderExtension->IOData[0];
  471. while (NTStatus == STATUS_SUCCESS) {
  472. // read head
  473. NTStatus = IFSerialRead(
  474. ReaderExtension,
  475. &IOData[0],
  476. 3
  477. );
  478. if (NTStatus != STATUS_SUCCESS) {
  479. __leave;
  480. }
  481. if ((IOData[NAD_IDX] & 0x20) != 0x20) {
  482. SmartcardDebug(
  483. DEBUG_ERROR,
  484. ("SCMSTCS!IFReadWorkRoutine: Invalid packet received\n" )
  485. );
  486. purgePort = TRUE;
  487. __leave;
  488. }
  489. if (IOData[LEN_IDX] > STC_BUFFER_SIZE - 4) {
  490. purgePort = TRUE;
  491. __leave;
  492. }
  493. // read tail
  494. NTStatus = IFSerialRead(
  495. ReaderExtension,
  496. &IOData[DATA_IDX],
  497. IOData[LEN_IDX] + 1
  498. );
  499. ASSERT(NTStatus == STATUS_SUCCESS);
  500. if (NTStatus != STATUS_SUCCESS) {
  501. purgePort = TRUE;
  502. __leave;
  503. }
  504. if (IOData[LEN_IDX] == 0) {
  505. purgePort = TRUE;
  506. __leave;
  507. }
  508. // check for card insertion / removal
  509. RtlRetrieveUshort(&shrtBuf, &IOData[DATA_IDX]);
  510. if( ( IOData[NAD_IDX] == STC1_TO_HOST ) &&
  511. ( IOData[LEN_IDX] == 2 ) &&
  512. ( (shrtBuf == SW_INSERTED) ||
  513. (shrtBuf == SW_REMOVED))) {
  514. CBUpdateCardState(
  515. ReaderExtension->SmartcardExtension,
  516. (shrtBuf == SW_INSERTED ? SCARD_PRESENT : SCARD_ABSENT)
  517. );
  518. } else {
  519. KIRQL CurrentIrql;
  520. // acquire spinlock to protect buffer/flag manipulation
  521. KeAcquireSpinLock(
  522. &ReaderExtension->ReadSpinLock,
  523. &CurrentIrql
  524. );
  525. // check size & copy data to TPDU stack
  526. ASSERT(
  527. ReaderExtension->Available+IOData[LEN_IDX] + 4 <
  528. TPDU_STACK_SIZE
  529. );
  530. if (ReaderExtension->Available + IOData[LEN_IDX] + 4 <
  531. TPDU_STACK_SIZE ) {
  532. SysCopyMemory(
  533. &ReaderExtension->TPDUStack[ReaderExtension->Available],
  534. &IOData[ 0 ],
  535. IOData[ LEN_IDX ] + 4
  536. );
  537. ReaderExtension->Available +=
  538. IOData[LEN_IDX] + 4;
  539. if(ReaderExtension->Available >= ReaderExtension->Expected ) {
  540. KeSetEvent(
  541. &ReaderExtension->DataAvailable,
  542. IO_SERIAL_INCREMENT,
  543. FALSE
  544. );
  545. }
  546. }
  547. KeReleaseSpinLock( &ReaderExtension->ReadSpinLock, CurrentIrql );
  548. }
  549. }
  550. }
  551. __finally {
  552. if (purgePort) {
  553. ULONG request;
  554. KIRQL CurrentIrql;
  555. // acquire spinlock to protect buffer/flag manipulation
  556. KeAcquireSpinLock(
  557. &ReaderExtension->ReadSpinLock,
  558. &CurrentIrql
  559. );
  560. ReaderExtension->Available = 0;
  561. KeReleaseSpinLock(
  562. &ReaderExtension->ReadSpinLock,
  563. CurrentIrql
  564. );
  565. // we got an error and need to clean up the port
  566. request = SR_PURGE;
  567. NTStatus = IFSerialIoctl(
  568. ReaderExtension,
  569. IOCTL_SERIAL_PURGE,
  570. &request,
  571. sizeof(request),
  572. NULL,
  573. 0
  574. );
  575. ASSERT(NTStatus == STATUS_SUCCESS);
  576. }
  577. IFSerialWaitOnMask( ReaderExtension );
  578. }
  579. }
  580. UCHAR IFCalcLRC( PUCHAR IOData, ULONG IODataLen )
  581. {
  582. ULONG Idx = 0;
  583. UCHAR CS = 0;
  584. do CS ^= IOData[ Idx ];
  585. while( ++Idx < IODataLen );
  586. return( CS );
  587. }
  588. //---------------------------------------- END OF FILE ----------------------------------------