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.

3105 lines
86 KiB

  1. /****************************************************************************/
  2. // tdasync.c
  3. //
  4. // Serial Transport Driver
  5. //
  6. // Copyright (C) 1998-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <ntddk.h>
  9. #include <ntddvdeo.h>
  10. #include <ntddkbd.h>
  11. #include <ntddmou.h>
  12. #include <ntddbeep.h>
  13. #include <ntddser.h>
  14. #include <winstaw.h>
  15. #include <icadd.h>
  16. #include <cdtapi.h>
  17. #include <sdapi.h>
  18. #include <td.h>
  19. #include "tdasync.h"
  20. #include "zwprotos.h"
  21. #ifdef _HYDRA_
  22. // This becomes the device name
  23. PWCHAR ModuleName = L"tdasync";
  24. #endif
  25. /*=============================================================================
  26. == External Functions Defined
  27. =============================================================================*/
  28. NTSTATUS DeviceOpen( PTD, PSD_OPEN );
  29. NTSTATUS DeviceClose( PTD, PSD_CLOSE );
  30. NTSTATUS DeviceCreateEndpoint( PTD, PICA_STACK_ADDRESS, PICA_STACK_ADDRESS );
  31. NTSTATUS DeviceOpenEndpoint( PTD, PVOID, ULONG );
  32. NTSTATUS DeviceCloseEndpoint( PTD );
  33. NTSTATUS DeviceInitializeWrite( PTD, POUTBUF );
  34. NTSTATUS DeviceIoctl( PTD, PSD_IOCTL );
  35. NTSTATUS DeviceConnectionWait( PTD, PVOID, ULONG, PULONG );
  36. NTSTATUS DeviceConnectionSend( PTD );
  37. NTSTATUS DeviceConnectionRequest( PTD, PVOID,
  38. PVOID, ULONG, PULONG );
  39. NTSTATUS DeviceSetParams( PTD );
  40. NTSTATUS DeviceWaitForStatus( PTD );
  41. NTSTATUS DeviceInitializeRead( PTD, PINBUF );
  42. NTSTATUS DeviceSubmitRead( PTD, PINBUF );
  43. NTSTATUS DeviceWaitForRead( PTD );
  44. NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG );
  45. NTSTATUS DeviceCancelIo( PTD );
  46. NTSTATUS DeviceSetLastError( PTD, ULONG );
  47. NTSTATUS DeviceGetLastError( PTD, PICA_STACK_LAST_ERROR );
  48. /*=============================================================================
  49. == Local Functions Defined
  50. =============================================================================*/
  51. BOOLEAN _CheckForConnect( PTD, ULONG, ULONG );
  52. BOOLEAN _CheckForDisconnect( PTD, ULONG, ULONG );
  53. VOID _UpdateAsyncStatus( PTD, PTDASYNC, ULONG, ULONG );
  54. NTSTATUS _SetupComm( PTD, HANDLE, ULONG, ULONG );
  55. NTSTATUS _SetCommTimeouts( PTD, HANDLE, PSERIAL_TIMEOUTS );
  56. NTSTATUS _GetCommModemStatus( PTD, HANDLE, PULONG );
  57. NTSTATUS _GetCommProperties( PTD, HANDLE, PSERIAL_COMMPROP);
  58. NTSTATUS _GetCommState( PTD, HANDLE, PSERIAL_BAUD_RATE, PSERIAL_LINE_CONTROL,
  59. PSERIAL_CHARS, PSERIAL_HANDFLOW );
  60. NTSTATUS _SetCommState( PTD, HANDLE, PSERIAL_BAUD_RATE, PSERIAL_LINE_CONTROL,
  61. PSERIAL_CHARS, PSERIAL_HANDFLOW );
  62. NTSTATUS _ClearCommError( PTD, HANDLE, PSERIAL_STATUS );
  63. NTSTATUS _PurgeComm( PTD, HANDLE, ULONG );
  64. NTSTATUS _WaitCommEvent( PTD, HANDLE, PULONG, PTDIOSTATUS );
  65. NTSTATUS _SetCommMask( PTD, HANDLE, ULONG );
  66. NTSTATUS _IoControl( PTD, HANDLE, ULONG, PVOID, ULONG, PVOID, ULONG, PULONG );
  67. NTSTATUS _OpenDevice( PTD );
  68. NTSTATUS _PrepareDevice( PTD );
  69. NTSTATUS _FillInEndpoint( PTD, PVOID, ULONG, PULONG );
  70. /*=============================================================================
  71. == Functions used
  72. =============================================================================*/
  73. VOID OutBufFree( PTD, POUTBUF );
  74. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  75. VOID MemoryFree( PVOID );
  76. /*******************************************************************************
  77. *
  78. * DeviceOpen
  79. *
  80. * Allocate and initialize private data structures
  81. *
  82. * ENTRY:
  83. * pTd (input)
  84. * Pointer to td data structure
  85. * pSdOpen (output)
  86. * pointer to td open parameter block
  87. *
  88. * EXIT:
  89. * STATUS_SUCCESS - no error
  90. *
  91. ******************************************************************************/
  92. NTSTATUS
  93. DeviceOpen( PTD pTd, PSD_OPEN pSdOpen )
  94. {
  95. PTDASYNC pTdAsync;
  96. PASYNCCONFIG pAsync;
  97. NTSTATUS Status;
  98. /*
  99. * Set protocol driver class
  100. */
  101. pTd->SdClass = SdAsync;
  102. pAsync = &pTd->Params.Async;
  103. TRACE(( pTd->pContext, TC_TD, TT_API1,
  104. "TDASYNC: DeviceOpen entry\n"
  105. ));
  106. /*
  107. * Return size of header and parameters
  108. */
  109. pSdOpen->SdOutBufHeader = 0;
  110. pSdOpen->SdOutBufTrailer = 0;
  111. /*
  112. * Allocate ASYNC TD data structure
  113. */
  114. Status = MemoryAllocate( sizeof(*pTdAsync), &pTdAsync );
  115. if ( !NT_SUCCESS(Status) )
  116. goto badalloc;
  117. pTd->pPrivate = pTdAsync;
  118. TRACE(( pTd->pContext, TC_TD, TT_API1,
  119. "TDASYNC: DeviceOpen, pTd 0x%x, pPrivate 0x%x, &pTd->pPrivate 0x%x\n",
  120. pTd, pTd->pPrivate, &pTd->pPrivate
  121. ));
  122. /*
  123. * Initialize TDASYNC data structure
  124. */
  125. RtlZeroMemory( pTdAsync, sizeof(*pTdAsync) );
  126. /*
  127. * Create event for status wait
  128. */
  129. Status = ZwCreateEvent( &pTdAsync->hStatusEvent,
  130. EVENT_ALL_ACCESS,
  131. NULL,
  132. SynchronizationEvent,
  133. FALSE );
  134. if ( !NT_SUCCESS( Status ) ) {
  135. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  136. "TDASYNC: DeviceOpen, Create StatusEvent failed (0x%x)\n",
  137. Status ));
  138. goto badstatusevent;
  139. }
  140. Status = ObReferenceObjectByHandle( pTdAsync->hStatusEvent,
  141. EVENT_MODIFY_STATE,
  142. NULL,
  143. KernelMode,
  144. (PVOID *) &pTdAsync->pStatusEventObject,
  145. NULL );
  146. if ( !NT_SUCCESS( Status ) ) {
  147. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  148. "TDASYNC: DeviceOpen, Create StatusEventObject failed (0x%x)\n",
  149. Status ));
  150. goto badstatuseventobj;
  151. }
  152. return( STATUS_SUCCESS );
  153. /*=============================================================================
  154. == Error returns
  155. =============================================================================*/
  156. /*
  157. * create of status event object pointer failed
  158. */
  159. badstatuseventobj:
  160. (VOID) ZwClose( pTdAsync->hStatusEvent );
  161. pTdAsync->hStatusEvent = 0;
  162. /*
  163. * create of status event failed
  164. */
  165. badstatusevent:
  166. MemoryFree( pTd->pPrivate );
  167. pTd->pPrivate = NULL;
  168. /*
  169. * allocate failed
  170. */
  171. badalloc:
  172. return( Status );
  173. }
  174. /*******************************************************************************
  175. *
  176. * DeviceClose
  177. *
  178. * Close transport driver
  179. *
  180. * NOTE: this must not close the serial device
  181. *
  182. *
  183. * ENTRY:
  184. * pTd (input)
  185. * Pointer to td data structure
  186. * pSdClose (input)
  187. * pointer to td close parameter block
  188. *
  189. * EXIT:
  190. * STATUS_SUCCESS - no error
  191. *
  192. ******************************************************************************/
  193. NTSTATUS
  194. DeviceClose( PTD pTd, PSD_CLOSE pSdClose )
  195. {
  196. PTDASYNC pTdAsync;
  197. PASYNCCONFIG pAsync;
  198. pTdAsync = (PTDASYNC) pTd->pPrivate;
  199. pAsync = &pTd->Params.Async;
  200. TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceClose entry\n" ));
  201. /*
  202. * If necessary, close the endpoint now.
  203. */
  204. if ( pTdAsync->fCloseEndpoint ) {
  205. DeviceCloseEndpoint( pTd );
  206. }
  207. ObDereferenceObject( pTdAsync->pStatusEventObject );
  208. (VOID) ZwClose( pTdAsync->hStatusEvent );
  209. pTdAsync->pStatusEventObject = NULL;
  210. pTdAsync->hStatusEvent = 0;
  211. return( STATUS_SUCCESS );
  212. }
  213. /*******************************************************************************
  214. *
  215. * DeviceCreateEndpoint
  216. *
  217. * Open and initialize serial device
  218. *
  219. *
  220. * ENTRY:
  221. * pTd (input)
  222. * Pointer to td data structure
  223. * pLocalAddress (input)
  224. * Pointer to local address (not used)
  225. * pReturnedAddress (input)
  226. * Pointer to location to save returned (created) address (not used)
  227. *
  228. * EXIT:
  229. * STATUS_SUCCESS - no error
  230. *
  231. ******************************************************************************/
  232. NTSTATUS
  233. DeviceCreateEndpoint(
  234. PTD pTd,
  235. PICA_STACK_ADDRESS pLocalAddress,
  236. PICA_STACK_ADDRESS pReturnedAddress
  237. )
  238. {
  239. PTDASYNC pTdAsync;
  240. PASYNCCONFIG pAsync;
  241. SERIAL_TIMEOUTS SerialTo;
  242. NTSTATUS Status;
  243. /*
  244. * Get pointer to async parameters
  245. */
  246. pTdAsync = (PTDASYNC) pTd->pPrivate;
  247. pAsync = &pTd->Params.Async;
  248. Status = _OpenDevice( pTd );
  249. if ( !NT_SUCCESS( Status ) ) {
  250. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  251. "TDASYNC: DeviceCreateEndpoint, _OpenDevice failed 0x%x\n",
  252. Status ));
  253. goto badopen;
  254. }
  255. Status = _PrepareDevice( pTd );
  256. if ( !NT_SUCCESS( Status ) ) {
  257. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  258. "TDASYNC: DeviceCreateEndpoint, _PrepareDevice failed 0x%x\n",
  259. Status ));
  260. goto badprepare;
  261. }
  262. /*
  263. * Copy pointers for use by the common TD routines.
  264. */
  265. pTd->pFileObject = pTdAsync->Endpoint.pFileObject;
  266. pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject;
  267. /*
  268. * If DeviceClose is called before a successful ConnectionWait,
  269. * then we must close the endpoint during the DeviceClose.
  270. */
  271. pTdAsync->fCloseEndpoint = TRUE;
  272. return( STATUS_SUCCESS );
  273. /*=============================================================================
  274. == Error returns
  275. =============================================================================*/
  276. /*
  277. * PrepareDevice failed
  278. */
  279. badprepare:
  280. ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent );
  281. pTdAsync->Endpoint.SignalIoStatus.hEvent = NULL;
  282. /*
  283. * open failed
  284. */
  285. badopen:
  286. pTdAsync->Endpoint.hDevice = 0;
  287. return( Status );
  288. }
  289. /*******************************************************************************
  290. *
  291. * DeviceOpenEndpoint
  292. *
  293. * Open an existing endpoint
  294. *
  295. * ENTRY:
  296. * pTd (input)
  297. * Pointer to td data structure
  298. * pEndpoint (input)
  299. * Pointer to endpoint structure
  300. * EndpointLength (input)
  301. * length of endpoint data
  302. *
  303. * EXIT:
  304. * STATUS_SUCCESS - no error
  305. *
  306. ******************************************************************************/
  307. NTSTATUS
  308. DeviceOpenEndpoint(
  309. PTD pTd,
  310. PVOID pEndpoint,
  311. ULONG EndpointLength
  312. )
  313. {
  314. PTDASYNC pTdAsync;
  315. PASYNCCONFIG pAsync;
  316. ULONG Mask;
  317. PTDASYNC_ENDPOINT pEp;
  318. NTSTATUS Status;
  319. pEp = (PTDASYNC_ENDPOINT) pEndpoint;
  320. /*
  321. * Get pointer to async parameters
  322. */
  323. pTdAsync = (PTDASYNC) pTd->pPrivate;
  324. pAsync = &pTd->Params.Async;
  325. TRACE(( pTd->pContext, TC_TD, TT_API2,
  326. "TDASYNC: DeviceOpenEndpoint, old endpoint h 0x%x, f 0x%x, d 0x%x\n",
  327. pEp->hDevice,
  328. pEp->pFileObject,
  329. pEp->pDeviceObject
  330. ));
  331. /*
  332. * copy disconnected Endpoint structure
  333. */
  334. pTdAsync->Endpoint.hDevice = pEp->hDevice;
  335. pTdAsync->Endpoint.pFileObject = pEp->pFileObject;
  336. pTdAsync->Endpoint.pDeviceObject = pEp->pDeviceObject;
  337. pTdAsync->Endpoint.SignalIoStatus.pEventObject =
  338. pEp->SignalIoStatus.pEventObject;
  339. pTdAsync->Endpoint.SignalIoStatus.hEvent =
  340. pEp->SignalIoStatus.hEvent;
  341. /*
  342. * Copy pointers for use by the common TD routines.
  343. */
  344. pTd->pFileObject = pTdAsync->Endpoint.pFileObject;
  345. pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject;
  346. if ( !pAsync->fConnectionDriver ) {
  347. /*
  348. * Set the comm event mask for status changes
  349. */
  350. Mask = EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD;
  351. if ( pAsync->Connect.fEnableBreakDisconnect )
  352. Mask |= EV_BREAK;
  353. Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask );
  354. if ( !NT_SUCCESS( Status ) ) {
  355. goto badsetcomm;
  356. }
  357. }
  358. pTd->pFileObject = pTdAsync->Endpoint.pFileObject;
  359. pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject;
  360. return( STATUS_SUCCESS );
  361. /*=============================================================================
  362. == Error returns
  363. =============================================================================*/
  364. badsetcomm:
  365. return( Status );
  366. }
  367. /*******************************************************************************
  368. *
  369. * DeviceCloseEndpoint
  370. *
  371. * Close Serial device
  372. *
  373. *
  374. * ENTRY:
  375. * pTd (input)
  376. * Pointer to td data structure
  377. *
  378. * EXIT:
  379. * STATUS_SUCCESS - no error
  380. *
  381. ******************************************************************************/
  382. NTSTATUS
  383. DeviceCloseEndpoint( PTD pTd )
  384. {
  385. PTDASYNC pTdAsync;
  386. PASYNCCONFIG pAsync;
  387. pTdAsync = (PTDASYNC) pTd->pPrivate;
  388. pAsync = &pTd->Params.Async;
  389. TRACE(( pTd->pContext, TC_TD, TT_API1,
  390. "TDASYNC: DeviceCloseEndpoint \"%S\"\n",
  391. pTd->Params.Async.DeviceName ));
  392. /*
  393. * Dereference our pointer to the file object,
  394. * and "forget" about the device object pointer as well.
  395. */
  396. if ( pTdAsync->Endpoint.pFileObject ) {
  397. ObDereferenceObject( pTdAsync->Endpoint.pFileObject );
  398. }
  399. pTd->pFileObject = pTdAsync->Endpoint.pFileObject = NULL;
  400. pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject = NULL;
  401. /*
  402. * Close the device handle
  403. */
  404. if ( pTdAsync->Endpoint.hDevice ) {
  405. TRACE(( pTd->pContext, TC_TD, TT_API1,
  406. "TDASYNC: DeviceCloseEndpoint Closing Device handle 0x%x\n",
  407. pTdAsync->Endpoint.hDevice ));
  408. ZwClose( pTdAsync->Endpoint.hDevice );
  409. }
  410. pTdAsync->Endpoint.hDevice = NULL;
  411. /*
  412. * Dereference the SignalIoStatus event
  413. */
  414. if ( pTdAsync->Endpoint.SignalIoStatus.pEventObject ) {
  415. ObDereferenceObject( pTdAsync->Endpoint.SignalIoStatus.pEventObject );
  416. }
  417. pTdAsync->Endpoint.SignalIoStatus.pEventObject = NULL;
  418. /*
  419. * Close the SignalIoStatus event handle
  420. */
  421. if ( pTdAsync->Endpoint.SignalIoStatus.hEvent ) {
  422. (VOID) ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent );
  423. }
  424. pTdAsync->Endpoint.SignalIoStatus.hEvent = 0;
  425. TRACE(( pTd->pContext, TC_TD, TT_API1,
  426. "TDASYNC: DeviceCloseEndpoint success\n"
  427. ));
  428. return( STATUS_SUCCESS );
  429. }
  430. /*******************************************************************************
  431. *
  432. * DeviceInitializeWrite
  433. *
  434. * Initialize a write operation for this device.
  435. *
  436. *
  437. * ENTRY:
  438. * pTd (input)
  439. * Pointer to td data structure
  440. * pOutBuf
  441. * Pointer to the OutBuf for this operation.
  442. *
  443. * EXIT:
  444. * STATUS_SUCCESS - no error
  445. *
  446. ******************************************************************************/
  447. NTSTATUS
  448. DeviceInitializeWrite(
  449. PTD pTd,
  450. POUTBUF pOutBuf
  451. )
  452. {
  453. PIRP Irp;
  454. PIO_STACK_LOCATION _IRPSP;
  455. TRACE(( pTd->pContext, TC_TD, TT_API1,
  456. "TDASYNC: DeviceInitializeWrite Entry\n"
  457. ));
  458. Irp = pOutBuf->pIrp;
  459. _IRPSP = IoGetNextIrpStackLocation( Irp );
  460. /*
  461. * Setup a WRITE IRP
  462. */
  463. _IRPSP->MajorFunction = IRP_MJ_WRITE;
  464. _IRPSP->Parameters.Write.Length = pOutBuf->ByteCount;
  465. ASSERT( Irp->MdlAddress == NULL );
  466. /*
  467. * Determine whether the target device performs direct or buffered I/O.
  468. */
  469. if ( pTd->pDeviceObject->Flags & DO_BUFFERED_IO ) {
  470. /*
  471. * The target device supports buffered I/O operations. Since our
  472. * output buffer is allocated from NonPagedPool memory, we can just
  473. * point the SystemBuffer to the output buffer. No buffer copying
  474. * will be required.
  475. */
  476. Irp->AssociatedIrp.SystemBuffer = pOutBuf->pBuffer;
  477. Irp->UserBuffer = pOutBuf->pBuffer;
  478. Irp->Flags |= IRP_BUFFERED_IO;
  479. } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) {
  480. /*
  481. * The target device supports direct I/O operations.
  482. * Initialize the MDL and point to it from the IRP.
  483. *
  484. * This MDL is allocated for every OUTBUF, and free'd with it.
  485. */
  486. MmInitializeMdl( pOutBuf->pMdl, pOutBuf->pBuffer, pOutBuf->ByteCount );
  487. MmBuildMdlForNonPagedPool( pOutBuf->pMdl );
  488. Irp->MdlAddress = pOutBuf->pMdl;
  489. } else {
  490. /*
  491. * The operation is neither buffered nor direct. Simply pass the
  492. * address of the buffer in the packet to the driver.
  493. */
  494. Irp->UserBuffer = pOutBuf->pBuffer;
  495. }
  496. return( STATUS_SUCCESS );
  497. }
  498. /*******************************************************************************
  499. *
  500. * DeviceIoctl
  501. *
  502. * Query/Set configuration information for the td.
  503. *
  504. * ENTRY:
  505. * pTd (input)
  506. * Pointer to td data structure
  507. * pSdIoctl (input/output)
  508. * Points to the parameter structure SD_IOCTL
  509. *
  510. * EXIT:
  511. * STATUS_SUCCESS - no error
  512. *
  513. ******************************************************************************/
  514. NTSTATUS
  515. DeviceIoctl( PTD pTd, PSD_IOCTL pSdIoctl )
  516. {
  517. NTSTATUS Status;
  518. PTDASYNC pTdAsync;
  519. SERIAL_TIMEOUTS SerialTo;
  520. PICA_STACK_TAPI_ENDPOINT pTe;
  521. pTdAsync = (PTDASYNC) pTd->pPrivate;
  522. TRACE(( pTd->pContext, TC_TD, TT_API2,
  523. "TDASYNC: DeviceIoctl, entry (0x%x)\n", pSdIoctl->IoControlCode ));
  524. switch ( pSdIoctl->IoControlCode ) {
  525. /*
  526. * Special IOCTL called when there is a connection driver
  527. * handling this device (i.e. a TAPI device).
  528. */
  529. case IOCTL_ICA_STACK_CD_CREATE_ENDPOINT :
  530. ASSERT( pSdIoctl->InputBuffer );
  531. ASSERT( pSdIoctl->InputBufferLength ==
  532. sizeof(ICA_STACK_TAPI_ENDPOINT) );
  533. ASSERT(pTd->Params.Async.fConnectionDriver);
  534. pTe = (PICA_STACK_TAPI_ENDPOINT) pSdIoctl->InputBuffer;
  535. /*
  536. * Dup the connection driver's handles
  537. * We do this instead of using the same handle since it
  538. * has been found possible for TAPI to close the device
  539. * handle out from under us BEFORE we process a disconnect.
  540. * Therefore, we dup our own handle here.
  541. */
  542. Status = ZwDuplicateObject( NtCurrentProcess(),
  543. pTe->hDevice,
  544. NtCurrentProcess(),
  545. &pTdAsync->Endpoint.hDevice,
  546. 0,
  547. 0,
  548. DUPLICATE_SAME_ACCESS |
  549. DUPLICATE_SAME_ATTRIBUTES );
  550. if ( !NT_SUCCESS( Status ) ) {
  551. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  552. "TDASYNC: DeviceIoctl, Dup device handle failed 0x%x\n",
  553. Status ));
  554. goto baddup1;
  555. }
  556. Status = ZwDuplicateObject( NtCurrentProcess(),
  557. pTe->hDiscEvent,
  558. NtCurrentProcess(),
  559. &pTdAsync->Endpoint.SignalIoStatus.hEvent,
  560. 0,
  561. 0,
  562. DUPLICATE_SAME_ACCESS |
  563. DUPLICATE_SAME_ATTRIBUTES );
  564. if ( !NT_SUCCESS( Status ) ) {
  565. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  566. "TDASYNC: DeviceIoctl, Dup event handle failed 0x%x\n",
  567. Status ));
  568. goto baddup2;
  569. }
  570. /*
  571. * The application opened the device. One instance of this is a
  572. * modem that has been configured by TAPI. Note, that only the
  573. * handle is provided, all other driver-based initialization is
  574. * still required.
  575. */
  576. TRACE(( pTd->pContext, TC_TD, TT_API2,
  577. "TDASYNC: DeviceIoctl, duping TAPI handle (0x%x -> 0x%x)\n",
  578. pTe->hDevice, pTdAsync->Endpoint.hDevice ));
  579. /*
  580. * Using the supplied handle, prepare this driver and the device.
  581. */
  582. Status = _PrepareDevice( pTd );
  583. if ( !NT_SUCCESS( Status ) ) {
  584. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  585. "TDASYNC: DeviceIoctl, _PrepareDevice failed 0x%x\n",
  586. Status ));
  587. goto badprepare;
  588. }
  589. /*
  590. * Copy pointers for use by the common TD routines.
  591. */
  592. pTd->pFileObject = pTdAsync->Endpoint.pFileObject;
  593. pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject;
  594. _FillInEndpoint( pTd,
  595. pSdIoctl->OutputBuffer,
  596. pSdIoctl->OutputBufferLength,
  597. &pSdIoctl->BytesReturned );
  598. break;
  599. default :
  600. return( STATUS_NOT_SUPPORTED );
  601. }
  602. return( STATUS_SUCCESS );
  603. /*=============================================================================
  604. == Error returns
  605. =============================================================================*/
  606. badprepare:
  607. ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent );
  608. pTdAsync->Endpoint.SignalIoStatus.hEvent = NULL;
  609. baddup2:
  610. ZwClose( pTdAsync->Endpoint.hDevice );
  611. pTdAsync->Endpoint.hDevice = NULL;
  612. baddup1:
  613. return( Status );
  614. }
  615. /*******************************************************************************
  616. *
  617. * DeviceConnectionWait
  618. *
  619. * Wait for serial device to be powered on
  620. * -- (i.e. wait for DSR signal)
  621. *
  622. * NOTE: The endpoint structure is an opaque, variable length data
  623. * structure whose length and contents are determined by the
  624. * transport driver.
  625. *
  626. *
  627. * ENTRY:
  628. * pTd (input)
  629. * Pointer to td data structure
  630. * pEndpoint (output)
  631. * pointer to buffer to return copy of endpoint structure
  632. * Length (input)
  633. * length of endpoint buffer
  634. * pEndpointLength (output)
  635. * pointer to address to return actual length of Endpoint
  636. *
  637. * EXIT:
  638. * STATUS_SUCCESS - no error
  639. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  640. *
  641. ******************************************************************************/
  642. NTSTATUS
  643. DeviceConnectionWait(
  644. PTD pTd,
  645. PVOID pEndpoint,
  646. ULONG Length,
  647. PULONG pEndpointLength
  648. )
  649. {
  650. PTDASYNC pTdAsync;
  651. PASYNCCONFIG pAsync;
  652. ULONG ModemStatus;
  653. ULONG Error;
  654. ULONG Mask;
  655. NTSTATUS Status;
  656. ULONG ActualEndpointLength = sizeof(TDASYNC_ENDPOINT);
  657. PTDASYNC_ENDPOINT pEp = (PTDASYNC_ENDPOINT) pEndpoint;
  658. ASSERT( pEndpoint );
  659. TRACE(( pTd->pContext, TC_TD, TT_API1,
  660. "TDASYNC: DeviceConnectionWait, pTd 0x%x, pPrivate 0x%x\n",
  661. pTd, pTd->pPrivate
  662. ));
  663. _FillInEndpoint( pTd, pEndpoint, Length, pEndpointLength );
  664. /*
  665. * Get pointer to async parameters
  666. */
  667. pTdAsync = (PTDASYNC) pTd->pPrivate;
  668. pAsync = &pTd->Params.Async;
  669. if ( pAsync->fConnectionDriver ) {
  670. /*
  671. * If a connection Driver is handling this connection,
  672. * assume the connection has been established.
  673. */
  674. goto complete;
  675. }
  676. /*
  677. * Set the comm event mask for connect wait
  678. */
  679. Mask = EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD;
  680. if ( pAsync->Connect.Type == Connect_FirstChar )
  681. Mask |= EV_RXCHAR;
  682. if ( pAsync->Connect.fEnableBreakDisconnect )
  683. Mask |= EV_BREAK;
  684. Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask );
  685. if ( !NT_SUCCESS( Status ) ) {
  686. goto badsetcomm;
  687. }
  688. for(;;) {
  689. /*
  690. * Post read for modem signal event
  691. */
  692. if ( !pTdAsync->fCommEventIoctl ) {
  693. TRACE(( pTd->pContext, TC_TD, TT_API2,
  694. "TDASYNC: DeviceConnectionWait, hD 0x%x, hE 0x%x\n",
  695. pEp->hDevice,
  696. pTdAsync->Endpoint.SignalIoStatus.hEvent
  697. ));
  698. pTdAsync->EventMask = 0;
  699. Status = _WaitCommEvent( pTd,
  700. pTdAsync->Endpoint.hDevice,
  701. &pTdAsync->EventMask,
  702. &pTdAsync->Endpoint.SignalIoStatus );
  703. if ( !NT_SUCCESS( Status ) ) {
  704. if ( Status != STATUS_PENDING ) {
  705. goto badwaitcomm;
  706. }
  707. }
  708. pTdAsync->fCommEventIoctl = TRUE;
  709. }
  710. /*
  711. * Get the current modem status
  712. */
  713. Status = _GetCommModemStatus( pTd,
  714. pTdAsync->Endpoint.hDevice,
  715. &ModemStatus );
  716. if ( !NT_SUCCESS( Status ) ) {
  717. goto badstatus;
  718. }
  719. /*
  720. * Update protocol status
  721. */
  722. _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask );
  723. /*
  724. * Check for connect
  725. */
  726. if ( _CheckForConnect( pTd, ModemStatus, pTdAsync->EventMask ) ) {
  727. break;
  728. }
  729. /*
  730. * Wait for modem status to change
  731. */
  732. Status = IcaWaitForSingleObject( pTd->pContext,
  733. pTdAsync->Endpoint.SignalIoStatus.pEventObject,
  734. INFINITE );
  735. pTdAsync->fCommEventIoctl = FALSE;
  736. /*
  737. * Check error code
  738. */
  739. if ( Status != STATUS_WAIT_0 ) {
  740. goto waiterror;
  741. }
  742. } /* forever */
  743. if ( !pAsync->fConnectionDriver ) {
  744. /*
  745. * Update comm event mask
  746. */
  747. if ( pAsync->Connect.Type == Connect_FirstChar ) {
  748. Mask &= ~EV_RXCHAR;
  749. Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask );
  750. if ( !NT_SUCCESS( Status ) ) {
  751. goto badsetcomm;
  752. }
  753. }
  754. }
  755. complete:
  756. /*
  757. * After a successful return from ConnectionWait, we no longer
  758. * have to close the endpoint on a DeviceClose call.
  759. */
  760. pTdAsync->fCloseEndpoint = FALSE;
  761. return( STATUS_SUCCESS );
  762. /*=============================================================================
  763. == Error returns
  764. =============================================================================*/
  765. /*
  766. * wait for object failed
  767. * get comm modem status failed
  768. * wait comm event failed
  769. * set comm mask failed
  770. */
  771. waiterror:
  772. badstatus:
  773. badwaitcomm:
  774. badsetcomm:
  775. return( Status );
  776. }
  777. /*******************************************************************************
  778. *
  779. * DeviceConnectionRequest
  780. *
  781. * Initiate a connection to the specified address
  782. * - this is not supported by the serial transport driver
  783. *
  784. *
  785. * ENTRY:
  786. * pTd (input)
  787. * Pointer to td data structure
  788. * pRemoteAddress (input)
  789. * pointer to remote address to connect to
  790. * pEndpoint (output)
  791. * pointer to buffer to return copy of endpoint structure
  792. * Length (input)
  793. * length of endpoint buffer
  794. * pEndpointLength (output)
  795. * pointer to address to return actual length of Endpoint
  796. *
  797. * EXIT:
  798. * STATUS_SUCCESS - no error
  799. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  800. *
  801. ******************************************************************************/
  802. NTSTATUS
  803. DeviceConnectionRequest(
  804. PTD pTd,
  805. PVOID pRemoteAddress,
  806. PVOID pEndpoint,
  807. ULONG Length,
  808. PULONG pEndpointLength
  809. )
  810. {
  811. return( STATUS_INVALID_DEVICE_REQUEST );
  812. }
  813. /*******************************************************************************
  814. *
  815. * DeviceConnectionSend
  816. *
  817. * Initialize host module data structure
  818. * -- this structure gets sent to the client
  819. *
  820. *
  821. * ENTRY:
  822. * pTd (input)
  823. * Pointer to td data structure
  824. *
  825. * EXIT:
  826. * STATUS_SUCCESS - no error
  827. *
  828. ******************************************************************************/
  829. NTSTATUS
  830. DeviceConnectionSend( PTD pTd )
  831. {
  832. PCLIENTMODULES pClient;
  833. /*
  834. * Get pointer to client structure
  835. */
  836. pClient = pTd->pClient;
  837. /*
  838. * Initialize Td host module structure
  839. */
  840. pClient->TdVersionL = VERSION_HOSTL_TDASYNC;
  841. pClient->TdVersionH = VERSION_HOSTH_TDASYNC;
  842. pClient->TdVersion = VERSION_HOSTH_TDASYNC;
  843. return( STATUS_SUCCESS );
  844. }
  845. /*******************************************************************************
  846. *
  847. * DeviceSetParams
  848. *
  849. * set serial device pararameters
  850. *
  851. * ENTRY:
  852. * pTd (input)
  853. * Pointer to Td data structure
  854. *
  855. * EXIT:
  856. * STATUS_SUCCESS - no error
  857. *
  858. ******************************************************************************/
  859. NTSTATUS
  860. DeviceSetParams( PTD pTd )
  861. {
  862. PTDASYNC pTdAsync;
  863. PASYNCCONFIG pAsync;
  864. PFLOWCONTROLCONFIG pFlow;
  865. NTSTATUS Status;
  866. SERIAL_COMMPROP CommProp;
  867. SERIAL_BAUD_RATE Baud;
  868. SERIAL_LINE_CONTROL LineControl;
  869. SERIAL_CHARS Chars;
  870. SERIAL_HANDFLOW HandFlow;
  871. /*
  872. * Get pointer to async parameters
  873. */
  874. pTdAsync = (PTDASYNC) pTd->pPrivate;
  875. pAsync = &pTd->Params.Async;
  876. /*
  877. * Get current State
  878. */
  879. Status = _GetCommState( pTd,
  880. pTdAsync->Endpoint.hDevice,
  881. &Baud,
  882. &LineControl,
  883. &Chars,
  884. &HandFlow );
  885. if ( !NT_SUCCESS( Status ) ) {
  886. goto badgetstate;
  887. }
  888. /*
  889. * Set defaults
  890. */
  891. if (pAsync->fEnableDsrSensitivity)
  892. HandFlow.ControlHandShake = SERIAL_DSR_SENSITIVITY;
  893. else
  894. HandFlow.ControlHandShake = 0;
  895. HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE;
  896. if ( !pAsync->fConnectionDriver ) {
  897. /*
  898. * Set Communication parameters
  899. */
  900. Baud.BaudRate = pAsync->BaudRate;
  901. LineControl.Parity = (BYTE) pAsync->Parity;
  902. LineControl.StopBits = (BYTE) pAsync->StopBits;
  903. LineControl.WordLength = (BYTE) pAsync->ByteSize;
  904. }
  905. /*
  906. * The following was taken from terminal code
  907. */
  908. /*
  909. * sep92 on low mem rx buffer can be < 1024
  910. * set rx buffer to nice 4096 bytes size
  911. * driver will do its best and set the Rx buffer to this size
  912. * if it fails then dwCurrentRxQueue will be the one we have
  913. * so do getcommprop again to fetch this value, which can
  914. * be used to set xoff and xon lims
  915. */
  916. TRACE(( pTd->pContext, TC_TD, TT_API2,
  917. "TDASYNC: DeviceSetParams Old State: XonLim %u, XoffLim %u\n",
  918. HandFlow.XonLimit, HandFlow.XoffLimit ));
  919. _GetCommProperties( pTd, pTdAsync->Endpoint.hDevice, &CommProp );
  920. TRACE(( pTd->pContext, TC_TD, TT_API2,
  921. "TDASYNC: DeviceSetParams Old Queues: RxQueue %u, TxQueue %u\n",
  922. CommProp.CurrentRxQueue, CommProp.CurrentTxQueue ));
  923. _SetupComm( pTd, pTdAsync->Endpoint.hDevice, 4096, 4096 );
  924. CommProp.CurrentRxQueue = 0; // dirty it so that we
  925. // can use this only if !=0
  926. _GetCommProperties( pTd, pTdAsync->Endpoint.hDevice, &CommProp );
  927. TRACE(( pTd->pContext, TC_TD, TT_API2,
  928. "TDASYNC: DeviceSetParams New Queues: RxQueue %u, TxQueue %u\n",
  929. CommProp.CurrentRxQueue, CommProp.CurrentTxQueue ));
  930. /*
  931. * if for some wierd reason CurrentRxQueue is not
  932. * filled in by the driver, then let xon xoff lims
  933. * be the default which the driver has.
  934. * (CurrentRxQueue was set to 0 before calling Get again)
  935. */
  936. if (CommProp.CurrentRxQueue != 0) {
  937. HandFlow.XonLimit = (LONG)(CommProp.CurrentRxQueue / 4);
  938. HandFlow.XoffLimit = (LONG)(CommProp.CurrentRxQueue / 4);
  939. }
  940. pFlow = &pAsync->FlowControl;
  941. /*
  942. * Initialize default DTR state
  943. */
  944. HandFlow.ControlHandShake &= ~SERIAL_DTR_MASK;
  945. if ( pFlow->fEnableDTR )
  946. HandFlow.ControlHandShake |= SERIAL_DTR_CONTROL;
  947. /*
  948. * Initialize default RTS state
  949. */
  950. HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
  951. if ( pFlow->fEnableRTS )
  952. HandFlow.FlowReplace |= SERIAL_RTS_CONTROL;
  953. /*
  954. * Initialize flow control
  955. */
  956. switch ( pFlow->Type ) {
  957. /*
  958. * Initialize hardware flow control
  959. */
  960. case FlowControl_Hardware :
  961. switch ( pFlow->HardwareReceive ) {
  962. case ReceiveFlowControl_RTS :
  963. HandFlow.FlowReplace =
  964. (HandFlow.FlowReplace & ~SERIAL_RTS_MASK) |
  965. SERIAL_RTS_HANDSHAKE;
  966. break;
  967. case ReceiveFlowControl_DTR :
  968. HandFlow.ControlHandShake =
  969. (HandFlow.ControlHandShake & ~SERIAL_DTR_MASK) |
  970. SERIAL_DTR_HANDSHAKE;
  971. break;
  972. }
  973. switch ( pFlow->HardwareTransmit ) {
  974. case TransmitFlowControl_CTS :
  975. HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
  976. break;
  977. case TransmitFlowControl_DSR :
  978. HandFlow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
  979. break;
  980. }
  981. break;
  982. /*
  983. * Initialize software flow control
  984. */
  985. case FlowControl_Software :
  986. if (pFlow->fEnableSoftwareTx)
  987. HandFlow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
  988. if (pFlow->fEnableSoftwareRx)
  989. HandFlow.FlowReplace |= SERIAL_AUTO_RECEIVE;
  990. Chars.XonChar = (char) pFlow->XonChar;
  991. Chars.XoffChar = (char) pFlow->XoffChar;
  992. break;
  993. case FlowControl_None :
  994. break;
  995. default :
  996. ASSERT( FALSE );
  997. break;
  998. }
  999. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1000. "TDASYNC: DeviceSetParams: baud %u, par %u, stop %u, data %u, dtr %u, rts %u\n",
  1001. Baud.BaudRate, LineControl.Parity, LineControl.StopBits,
  1002. LineControl.WordLength,
  1003. HandFlow.ControlHandShake & SERIAL_DTR_MASK,
  1004. HandFlow.FlowReplace & SERIAL_RTS_MASK ));
  1005. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1006. "TDASYNC: DeviceSetParams: fOutX %u, fInX %u, xon %x, xoff %x, cts %u, dsr %u\n",
  1007. (HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0,
  1008. (HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0,
  1009. Chars.XonChar,
  1010. Chars.XoffChar,
  1011. (HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0,
  1012. (HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0 ));
  1013. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1014. "TDASYNC: DeviceSetParams: XonLimit %u, XoffLimit %u\n",
  1015. HandFlow.XonLimit, HandFlow.XoffLimit ));
  1016. /*
  1017. * Set new State
  1018. */
  1019. Status = _SetCommState( pTd,
  1020. pTdAsync->Endpoint.hDevice,
  1021. &Baud,
  1022. &LineControl,
  1023. &Chars,
  1024. &HandFlow );
  1025. if ( !NT_SUCCESS( Status ) ) {
  1026. goto badsetstate;
  1027. }
  1028. return( STATUS_SUCCESS );
  1029. /*=============================================================================
  1030. == Error returns
  1031. =============================================================================*/
  1032. /*
  1033. * State set failed
  1034. * State query failed
  1035. */
  1036. badsetstate:
  1037. badgetstate:
  1038. return( Status );
  1039. }
  1040. /*******************************************************************************
  1041. *
  1042. * DeviceInitializeRead
  1043. *
  1044. * This routine is called for each read, it also starts the "read" for
  1045. * serial device status changes.
  1046. *
  1047. * ENTRY:
  1048. * pTd (input)
  1049. * Pointer to td data structure
  1050. *
  1051. * EXIT:
  1052. * STATUS_SUCCESS - no error
  1053. *
  1054. ******************************************************************************/
  1055. NTSTATUS
  1056. DeviceInitializeRead(
  1057. PTD pTd,
  1058. PINBUF pInBuf
  1059. )
  1060. {
  1061. PTDASYNC pTdAsync;
  1062. PASYNCCONFIG pAsync;
  1063. NTSTATUS Status;
  1064. ULONG ModemStatus;
  1065. PIRP Irp;
  1066. PIO_STACK_LOCATION _IRPSP;
  1067. pTdAsync = (PTDASYNC) pTd->pPrivate;
  1068. pAsync = &pTd->Params.Async;
  1069. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1070. "TDASYNC: DeviceInitializeRead entry\n"
  1071. ));
  1072. /*
  1073. * Initialize the IRP for a READ
  1074. */
  1075. Irp = pInBuf->pIrp;
  1076. _IRPSP = IoGetNextIrpStackLocation( Irp );
  1077. _IRPSP->Parameters.Read.Length = pTd->InBufHeader + pTd->OutBufLength;
  1078. _IRPSP->MajorFunction = IRP_MJ_READ;
  1079. ASSERT( Irp->MdlAddress == NULL );
  1080. /*
  1081. * Determine whether the target device performs direct or buffered I/O.
  1082. */
  1083. if ( pTd->pDeviceObject->Flags & DO_BUFFERED_IO ) {
  1084. /*
  1085. * The target device supports buffered I/O operations. Since our
  1086. * input buffer is allocated from NonPagedPool memory, we can just
  1087. * point the SystemBuffer to our input buffer. No buffer copying
  1088. * will be required.
  1089. */
  1090. Irp->AssociatedIrp.SystemBuffer = pInBuf->pBuffer;
  1091. Irp->UserBuffer = pInBuf->pBuffer;
  1092. Irp->Flags |= IRP_BUFFERED_IO;
  1093. } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) {
  1094. /*
  1095. * The target device supports direct I/O operations.
  1096. * If we haven't already done so, allocate an MDL large enough
  1097. * to map the input buffer and indicate it is contained in
  1098. * NonPagedPool memory.
  1099. *
  1100. * The MDL is preallocated in the PTD and never freed by the Device leve
  1101. * TD.
  1102. */
  1103. MmInitializeMdl( pInBuf->pMdl, pInBuf->pBuffer, pTd->InBufHeader+pTd->OutBufLength );
  1104. MmBuildMdlForNonPagedPool( pInBuf->pMdl );
  1105. Irp->MdlAddress = pInBuf->pMdl;
  1106. } else {
  1107. /*
  1108. * The operation is neither buffered nor direct. Simply pass the
  1109. * address of the buffer in the packet to the driver.
  1110. */
  1111. Irp->UserBuffer = pInBuf->pBuffer;
  1112. }
  1113. /*
  1114. * If there is not already an Ioctl pending for serial
  1115. * device status, then initiate one now. DeviceWaitForRead
  1116. * uses the event within the SignalIoStatus structure.
  1117. * If a Connection Driver is handling this connection, the connection
  1118. * driver created an event, and passed it down in the Endpoint.
  1119. * The connection driver will take care of the signaling mechanism,
  1120. * so no operations other than waiting on the event are required.
  1121. * NOTE: The connection driver event will only be signaled on
  1122. * Disconnects.
  1123. */
  1124. if ( !pTdAsync->fCommEventIoctl && !pAsync->fConnectionDriver ) {
  1125. /*
  1126. * Get the current modem status
  1127. */
  1128. Status = _GetCommModemStatus( pTd,
  1129. pTdAsync->Endpoint.hDevice,
  1130. &ModemStatus );
  1131. if ( !NT_SUCCESS( Status ) ) {
  1132. goto badgetcomm;
  1133. }
  1134. /*
  1135. * Update protocol status
  1136. */
  1137. _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask );
  1138. /*
  1139. * Check for a disconnect
  1140. */
  1141. if ( _CheckForDisconnect( pTd, ModemStatus, pTdAsync->EventMask )) {
  1142. Status = STATUS_CTX_CLOSE_PENDING;
  1143. goto disconnect;
  1144. }
  1145. pTdAsync->EventMask = 0;
  1146. Status = _WaitCommEvent( pTd,
  1147. pTdAsync->Endpoint.hDevice,
  1148. &pTdAsync->EventMask,
  1149. &pTdAsync->Endpoint.SignalIoStatus );
  1150. if ( !NT_SUCCESS( Status ) ) {
  1151. if ( Status != STATUS_PENDING ) {
  1152. goto badwaitcomm;
  1153. }
  1154. }
  1155. pTdAsync->fCommEventIoctl = TRUE;
  1156. }
  1157. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1158. "TDASYNC: DeviceInitializeRead success\n"
  1159. ));
  1160. return( STATUS_SUCCESS );
  1161. /*=============================================================================
  1162. == Error returns
  1163. =============================================================================*/
  1164. badgetcomm:
  1165. disconnect:
  1166. badwaitcomm:
  1167. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1168. "TDASYNC: DeviceInitializeRead status (0x%x)\n",
  1169. Status
  1170. ));
  1171. return( Status );
  1172. }
  1173. /*******************************************************************************
  1174. *
  1175. * DeviceSubmitRead
  1176. *
  1177. * Submit the read IRP to the driver.
  1178. *
  1179. * ENTRY:
  1180. * pTd (input)
  1181. * Pointer to TD data structure
  1182. *
  1183. * EXIT:
  1184. * STATUS_SUCCESS - no error
  1185. *
  1186. ******************************************************************************/
  1187. NTSTATUS
  1188. DeviceSubmitRead(
  1189. PTD pTd,
  1190. PINBUF pInBuf
  1191. )
  1192. {
  1193. PIRP Irp;
  1194. NTSTATUS Status;
  1195. Irp = pInBuf->pIrp;
  1196. Status = IoCallDriver( pTd->pDeviceObject, Irp );
  1197. return( Status );
  1198. }
  1199. /*******************************************************************************
  1200. *
  1201. * DeviceWaitForRead
  1202. *
  1203. * This routine waits for input data and detects broken connections.
  1204. *
  1205. * ENTRY:
  1206. * pTd (input)
  1207. * Pointer to td data structure
  1208. *
  1209. * EXIT:
  1210. * STATUS_SUCCESS - no error
  1211. * -1 - disconnected
  1212. *
  1213. ******************************************************************************/
  1214. NTSTATUS
  1215. DeviceWaitForRead(
  1216. PTD pTd
  1217. )
  1218. {
  1219. PTDASYNC pTdAsync;
  1220. PASYNCCONFIG pAsync;
  1221. PKEVENT pWait[2];
  1222. ULONG ModemStatus;
  1223. NTSTATUS Status;
  1224. ULONG WaitCount;
  1225. pTdAsync = (PTDASYNC) pTd->pPrivate;
  1226. pAsync = &pTd->Params.Async;
  1227. /*
  1228. * Setup wait for input data, and a communication event
  1229. * if a Connection Driver isn't handling this connection.
  1230. */
  1231. WaitCount = 0;
  1232. pWait[WaitCount++] = &pTd->InputEvent;
  1233. pWait[WaitCount++] = pTdAsync->Endpoint.SignalIoStatus.pEventObject;
  1234. /*
  1235. * Loop until input data or broken connection
  1236. */
  1237. for(;;) {
  1238. TRACE(( pTd->pContext, TC_TD, TT_API1,
  1239. "TDASYNC: DeviceWaitForRead Loop\n"
  1240. ));
  1241. Status = IcaWaitForMultipleObjects( pTd->pContext, WaitCount, pWait,
  1242. WaitAny, INFINITE );
  1243. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1244. "TDASYNC: DeviceWaitForRead: WaitForMultiple status 0x%x\n",
  1245. Status
  1246. ));
  1247. /*
  1248. * Check if input data is available
  1249. */
  1250. if ( Status == STATUS_WAIT_0 ) {
  1251. if ( pAsync->fConnectionDriver ) {
  1252. /*
  1253. * Since the connection driver has control over this port,
  1254. * the event-mask method of waiting for modem signal status
  1255. * changes can't be used, since setting our mask will destroy
  1256. * the one TAPI has established. This makes TAPI very unhappy.
  1257. *
  1258. * Now, you might be thinking - why not just wait for status
  1259. * changes that TAPI has established, and update status then.
  1260. * Well, that's possible, but there's something else which must
  1261. * be considered. When we want to shut down the IOCTL that is
  1262. * waiting for status changes, a change of the event mask is
  1263. * required. Hence, this would alter what TAPI has set.
  1264. */
  1265. /*
  1266. * Get the current modem status
  1267. */
  1268. Status = _GetCommModemStatus( pTd,
  1269. pTdAsync->Endpoint.hDevice,
  1270. &ModemStatus );
  1271. if ( Status != STATUS_SUCCESS ) {
  1272. return( Status );
  1273. }
  1274. /*
  1275. * Update protocol status
  1276. */
  1277. _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask );
  1278. }
  1279. break;
  1280. } else if ( pAsync->fConnectionDriver && Status == STATUS_WAIT_1 ) {
  1281. /*
  1282. * If a Connection Driver is handling this connection, this
  1283. * event was signaled because a disconnect was detected by
  1284. * the connection driver.
  1285. */
  1286. if ( pTd->fCallbackInProgress ) {
  1287. /*
  1288. * During callback the client will disconnect, but
  1289. * in this case we don't want the error going back up
  1290. * the stack.
  1291. */
  1292. continue;
  1293. } else {
  1294. return( STATUS_CTX_CLOSE_PENDING );
  1295. }
  1296. }
  1297. /*
  1298. * If modem status event was not signaled, return error
  1299. */
  1300. if ( Status != STATUS_WAIT_1 ) {
  1301. return( Status );
  1302. }
  1303. pTdAsync->fCommEventIoctl = FALSE;
  1304. /*
  1305. * Get the current modem status
  1306. */
  1307. Status = _GetCommModemStatus( pTd,
  1308. pTdAsync->Endpoint.hDevice,
  1309. &ModemStatus );
  1310. if ( !NT_SUCCESS( Status ) ) {
  1311. return( Status );
  1312. }
  1313. /*
  1314. * Update protocol status
  1315. */
  1316. _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask );
  1317. /*
  1318. * Check for a disconnect
  1319. */
  1320. if ( _CheckForDisconnect( pTd, ModemStatus, pTdAsync->EventMask ) ) {
  1321. return( STATUS_CTX_CLOSE_PENDING );
  1322. }
  1323. /*
  1324. * Signal event wait semaphore
  1325. */
  1326. ZwSetEvent( pTdAsync->hStatusEvent, NULL );
  1327. /*
  1328. * Post another read for a modem signal event
  1329. */
  1330. pTdAsync->EventMask = 0;
  1331. Status = _WaitCommEvent( pTd,
  1332. pTdAsync->Endpoint.hDevice,
  1333. &pTdAsync->EventMask,
  1334. &pTdAsync->Endpoint.SignalIoStatus );
  1335. if ( !NT_SUCCESS( Status ) ) {
  1336. return( Status );
  1337. }
  1338. pTdAsync->fCommEventIoctl = TRUE;
  1339. }
  1340. return( STATUS_SUCCESS );
  1341. }
  1342. /*******************************************************************************
  1343. *
  1344. * DeviceReadComplete
  1345. *
  1346. * Do any read complete processing
  1347. *
  1348. *
  1349. * ENTRY:
  1350. * pTd (input)
  1351. * Pointer to td data structure
  1352. * pBuffer (input)
  1353. * Pointer to input buffer
  1354. * pByteCount (input/output)
  1355. * Pointer to location containing byte count read
  1356. *
  1357. * EXIT:
  1358. * STATUS_SUCCESS - no error
  1359. *
  1360. ******************************************************************************/
  1361. NTSTATUS
  1362. DeviceReadComplete( PTD pTd, PUCHAR pBuffer, PULONG pByteCount )
  1363. {
  1364. return( STATUS_SUCCESS );
  1365. }
  1366. /*******************************************************************************
  1367. *
  1368. * DeviceWaitForStatus
  1369. *
  1370. * This routine waits for RS232 signal status to change
  1371. *
  1372. * ENTRY:
  1373. * pTd (input)
  1374. * Pointer to td data structure
  1375. *
  1376. * EXIT:
  1377. * STATUS_SUCCESS - no error
  1378. *
  1379. ******************************************************************************/
  1380. NTSTATUS
  1381. DeviceWaitForStatus( PTD pTd )
  1382. {
  1383. PTDASYNC pTdAsync;
  1384. NTSTATUS Status;
  1385. pTdAsync = (PTDASYNC) pTd->pPrivate;
  1386. TRACE(( pTd->pContext, TC_TD, TT_API1,
  1387. "TDASYNC: DeviceWaitForStatus: Entry\n"
  1388. ));
  1389. ASSERT(!pTd->Params.Async.fConnectionDriver);
  1390. /*
  1391. * Wait for status to change
  1392. */
  1393. Status = IcaWaitForSingleObject( pTd->pContext,
  1394. pTdAsync->pStatusEventObject,
  1395. INFINITE );
  1396. return( Status );
  1397. }
  1398. /*******************************************************************************
  1399. * DeviceCancelIo
  1400. *
  1401. * cancel all current and future i/o
  1402. ******************************************************************************/
  1403. NTSTATUS DeviceCancelIo(PTD pTd)
  1404. {
  1405. PTDASYNC pTdAsync;
  1406. PASYNCCONFIG pAsync;
  1407. TRACE(( pTd->pContext, TC_TD, TT_API1,
  1408. "TDASYNC: DeviceCancelIo Entry\n" ));
  1409. pTdAsync = (PTDASYNC) pTd->pPrivate;
  1410. pAsync = &pTd->Params.Async;
  1411. /*
  1412. * Signal event wait semaphore
  1413. */
  1414. ZwSetEvent(pTdAsync->hStatusEvent, NULL);
  1415. if (!pAsync->fConnectionDriver) {
  1416. /*
  1417. * Clear comm mask. This will cause the _WaitCommEvent event
  1418. * to be set which will then cause the input thread to wakeup.
  1419. */
  1420. (VOID) _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, 0 );
  1421. }
  1422. /*
  1423. * Cancel all outstanding writes
  1424. */
  1425. (VOID) _PurgeComm( pTd,
  1426. pTdAsync->Endpoint.hDevice,
  1427. SERIAL_PURGE_TXABORT | SERIAL_PURGE_TXCLEAR );
  1428. /*
  1429. * Purge the recieve buffer and any pending read.
  1430. */
  1431. (VOID) _PurgeComm( pTd,
  1432. pTdAsync->Endpoint.hDevice,
  1433. SERIAL_PURGE_RXABORT | SERIAL_PURGE_RXCLEAR );
  1434. return STATUS_SUCCESS;
  1435. }
  1436. /*******************************************************************************
  1437. * DeviceQueryRemoteAddress
  1438. *
  1439. * not supported for Async transport
  1440. ******************************************************************************/
  1441. NTSTATUS
  1442. DeviceQueryRemoteAddress(
  1443. PTD pTd,
  1444. PVOID pIcaEndpoint,
  1445. ULONG EndpointSize,
  1446. PVOID pOutputAddress,
  1447. ULONG OutputAddressSize,
  1448. PULONG BytesReturned)
  1449. {
  1450. //
  1451. // unsupported for Async
  1452. //
  1453. return STATUS_NOT_SUPPORTED;
  1454. }
  1455. /*******************************************************************************
  1456. *
  1457. * DeviceSetLastError
  1458. *
  1459. * save serial error code
  1460. *
  1461. *
  1462. * ENTRY:
  1463. * pTd (input)
  1464. * Pointer to td data structure
  1465. * Error (input)
  1466. * serial error code
  1467. *
  1468. * EXIT:
  1469. * NT error code
  1470. *
  1471. ******************************************************************************/
  1472. NTSTATUS
  1473. DeviceSetLastError( PTD pTd, ULONG Error )
  1474. {
  1475. if ( Error == 0 )
  1476. return( STATUS_SUCCESS );
  1477. pTd->LastError = Error;
  1478. (void) IcaLogError( pTd->pContext,
  1479. Error,
  1480. NULL,
  1481. 0,
  1482. &pTd->Params.Async,
  1483. sizeof(pTd->Params.Async) );
  1484. return( STATUS_CTX_TD_ERROR );
  1485. }
  1486. /*******************************************************************************
  1487. *
  1488. * DeviceGetLastError
  1489. *
  1490. * This routine returns the last serial error code and message
  1491. *
  1492. * ENTRY:
  1493. * pTd (input)
  1494. * Pointer to td data structure
  1495. * pLastError (output)
  1496. * address to return information on last protocol error
  1497. *
  1498. * EXIT:
  1499. * STATUS_SUCCESS - no error
  1500. *
  1501. ******************************************************************************/
  1502. NTSTATUS
  1503. DeviceGetLastError( PTD pTd, PICA_STACK_LAST_ERROR pLastError )
  1504. {
  1505. pLastError->Error = pTd->LastError;
  1506. RtlZeroMemory( pLastError->Message, sizeof(pLastError->Message) );
  1507. return( STATUS_SUCCESS );
  1508. }
  1509. /*******************************************************************************
  1510. *
  1511. * _CheckForConnect
  1512. *
  1513. * check for a connect signal
  1514. *
  1515. * ENTRY:
  1516. * pTd (input)
  1517. * Pointer to td data structure
  1518. * ModemStatus (input)
  1519. * modem status flags (MS_?)
  1520. * EventMask (input)
  1521. * event mask (EV_?)
  1522. *
  1523. * EXIT:
  1524. * TRUE if connected, FALSE otherwise
  1525. *
  1526. ******************************************************************************/
  1527. BOOLEAN
  1528. _CheckForConnect( PTD pTd, ULONG ModemStatus, ULONG EventMask )
  1529. {
  1530. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1531. "TDASYNC: _CheckForConnect: modem 0x%x, event 0x%x, connect 0x%x\n",
  1532. ModemStatus, EventMask, pTd->Params.Async.Connect.Type
  1533. ));
  1534. switch( pTd->Params.Async.Connect.Type ) {
  1535. case Connect_CTS :
  1536. if ( ModemStatus & MS_CTS_ON )
  1537. return( TRUE );
  1538. break;
  1539. case Connect_DSR :
  1540. if ( ModemStatus & MS_DSR_ON )
  1541. return( TRUE );
  1542. break;
  1543. case Connect_RI :
  1544. if ( ModemStatus & MS_RING_ON )
  1545. return( TRUE );
  1546. break;
  1547. case Connect_DCD :
  1548. if ( ModemStatus & MS_RLSD_ON )
  1549. return( TRUE );
  1550. break;
  1551. case Connect_FirstChar :
  1552. if ( EventMask & EV_RXCHAR )
  1553. return( TRUE );
  1554. break;
  1555. case Connect_Perm :
  1556. return( TRUE );
  1557. }
  1558. return( FALSE );
  1559. }
  1560. /*******************************************************************************
  1561. *
  1562. * _CheckForDisconnect
  1563. *
  1564. * check for a disconnect signal
  1565. *
  1566. * ENTRY:
  1567. * pTd (input)
  1568. * Pointer to td data structure
  1569. * ModemStatus (input)
  1570. * modem status flags (MS_?)
  1571. * EventMask (input)
  1572. * event mask (EV_?)
  1573. *
  1574. * EXIT:
  1575. * TRUE if disconnected, FALSE otherwise
  1576. *
  1577. ******************************************************************************/
  1578. BOOLEAN
  1579. _CheckForDisconnect( PTD pTd, ULONG ModemStatus, ULONG EventMask )
  1580. {
  1581. TRACE(( pTd->pContext,
  1582. TC_TD, TT_API2,
  1583. "TDASYNC: _CheckForDisconnect: modem 0x%x, event 0x%x, connect 0x%x\n",
  1584. ModemStatus, EventMask, pTd->Params.Async.Connect.Type
  1585. ));
  1586. switch( pTd->Params.Async.Connect.Type ) {
  1587. case Connect_CTS :
  1588. if ( !(ModemStatus & MS_CTS_ON) )
  1589. return( TRUE );
  1590. break;
  1591. case Connect_DSR :
  1592. if ( !(ModemStatus & MS_DSR_ON) )
  1593. return( TRUE );
  1594. break;
  1595. case Connect_RI :
  1596. if ( !(ModemStatus & MS_RING_ON) )
  1597. return( TRUE );
  1598. break;
  1599. case Connect_DCD :
  1600. if ( !(ModemStatus & MS_RLSD_ON) )
  1601. return( TRUE );
  1602. break;
  1603. case Connect_FirstChar :
  1604. if ( EventMask & EV_BREAK )
  1605. return( TRUE );
  1606. break;
  1607. case Connect_Perm :
  1608. return( FALSE );
  1609. }
  1610. return( FALSE );
  1611. }
  1612. /*******************************************************************************
  1613. *
  1614. * _UpdateAsyncStatus
  1615. *
  1616. * update async signal status
  1617. *
  1618. * ENTRY:
  1619. * pTd (input)
  1620. * Pointer to td data structure
  1621. * pTdAsync (input)
  1622. * Pointer to td async data structure
  1623. * ModemStatus (input)
  1624. * modem status flags (MS_?)
  1625. * EventMask (input)
  1626. * event mask (EV_?)
  1627. *
  1628. * EXIT:
  1629. * nothing
  1630. *
  1631. ******************************************************************************/
  1632. VOID
  1633. _UpdateAsyncStatus(
  1634. PTD pTd,
  1635. PTDASYNC pTdAsync,
  1636. ULONG ModemStatus,
  1637. ULONG EventMask
  1638. )
  1639. {
  1640. PPROTOCOLSTATUS pStatus;
  1641. PFLOWCONTROLCONFIG pFlow;
  1642. SERIAL_STATUS SerialStat;
  1643. pStatus = pTd->pStatus;
  1644. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1645. "TDASYNC: _UpdateAsyncStatus: modem %x, event %x\n",
  1646. ModemStatus, EventMask
  1647. ));
  1648. /*
  1649. * Update modem status
  1650. */
  1651. pStatus->AsyncSignal = ModemStatus;
  1652. /*
  1653. * Or in status of DTR and RTS
  1654. */
  1655. pFlow = &pTd->Params.Async.FlowControl;
  1656. if ( pFlow->fEnableDTR )
  1657. pStatus->AsyncSignal |= MS_DTR_ON;
  1658. if ( pFlow->fEnableRTS )
  1659. pStatus->AsyncSignal |= MS_RTS_ON;
  1660. /*
  1661. * OR in new event mask
  1662. * -- EventMask get cleared when user program reads info
  1663. */
  1664. pStatus->AsyncSignalMask |= EventMask;
  1665. /*
  1666. * Update async error counters
  1667. */
  1668. if ( EventMask & EV_ERR ) {
  1669. (VOID) _ClearCommError( pTd, pTdAsync->Endpoint.hDevice, &SerialStat );
  1670. if ( SerialStat.Errors & SERIAL_ERROR_OVERRUN ) {
  1671. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1672. "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_OVERRUN\n"
  1673. ));
  1674. pStatus->Output.AsyncOverrunError++;
  1675. }
  1676. if ( SerialStat.Errors & SERIAL_ERROR_FRAMING ) {
  1677. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1678. "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_FRAMING\n"
  1679. ));
  1680. pStatus->Input.AsyncFramingError++;
  1681. }
  1682. if ( SerialStat.Errors & SERIAL_ERROR_QUEUEOVERRUN ) {
  1683. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1684. "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_QUEUEOVERRUN\n"
  1685. ));
  1686. pStatus->Input.AsyncOverflowError++;
  1687. }
  1688. if ( SerialStat.Errors & SERIAL_ERROR_PARITY ) {
  1689. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1690. "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_PARITY\n"
  1691. ));
  1692. pStatus->Input.AsyncParityError++;
  1693. }
  1694. }
  1695. }
  1696. /*******************************************************************************
  1697. *
  1698. * _SetCommTimeouts
  1699. *
  1700. * This function establishes the timeout characteristics for all
  1701. * read and write operations on the handle specified by hFile.
  1702. *
  1703. * ENTRY:
  1704. * pTd (input)
  1705. * Pointer to td data structure
  1706. * hFile (input)
  1707. * Specifies the communication device to receive the settings.
  1708. * The CreateFile function returns this value.
  1709. * pTo (input)
  1710. * Points to a structure containing timeout parameters.
  1711. *
  1712. * EXIT:
  1713. * STATUS_SUCCESS - no error
  1714. *
  1715. ******************************************************************************/
  1716. NTSTATUS
  1717. _SetCommTimeouts(
  1718. PTD pTd,
  1719. HANDLE hFile,
  1720. PSERIAL_TIMEOUTS pTo
  1721. )
  1722. {
  1723. NTSTATUS Status;
  1724. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1725. "TDASYNC: _SetCommTimeouts: ReadIntervalTimeout %d\n",
  1726. pTo->ReadIntervalTimeout
  1727. ));
  1728. Status = _IoControl( pTd,
  1729. hFile,
  1730. IOCTL_SERIAL_SET_TIMEOUTS,
  1731. pTo,
  1732. sizeof(*pTo),
  1733. NULL,
  1734. 0,
  1735. NULL );
  1736. return Status;
  1737. }
  1738. /*******************************************************************************
  1739. *
  1740. * _GetCommModemStatus
  1741. * This routine returns the most current value of the modem
  1742. * status register's non-delta values.
  1743. *
  1744. * ENTRY:
  1745. * pTd (input)
  1746. * Pointer to td data structure
  1747. * hFile (input)
  1748. * Specifies the communication device to be examined.
  1749. * pModemStat (output)
  1750. * Points to a ULONG which is to receive the mask of
  1751. * non-delta values in the modem status register.
  1752. *
  1753. * EXIT:
  1754. * STATUS_SUCCESS - no error
  1755. *
  1756. ******************************************************************************/
  1757. NTSTATUS
  1758. _GetCommModemStatus(
  1759. PTD pTd,
  1760. HANDLE hFile,
  1761. PULONG pModemStat
  1762. )
  1763. {
  1764. NTSTATUS Status;
  1765. Status = _IoControl( pTd,
  1766. hFile,
  1767. IOCTL_SERIAL_GET_MODEMSTATUS,
  1768. NULL,
  1769. 0,
  1770. pModemStat,
  1771. sizeof(*pModemStat),
  1772. NULL );
  1773. return Status;
  1774. }
  1775. /*******************************************************************************
  1776. *
  1777. * _WaitCommEvent
  1778. * This function will wait until any of the events occur that were
  1779. * provided in the EvtMask parameter to _SetCommMask. If while waiting
  1780. * the event mask is changed (via another call to SetCommMask), the
  1781. * function will return immediately. The function will fill the EvtMask
  1782. * pointed to by the pEvtMask parameter with the reasons that the
  1783. * wait was satisfied.
  1784. *
  1785. * ENTRY:
  1786. * pTd (input)
  1787. * Pointer to td data structure
  1788. * hFile (input)
  1789. * Specifies the communication device to be waited on.
  1790. * The CreateFile function returns this value.
  1791. * pEvtMask (output)
  1792. * Points to a mask that will receive the reason that
  1793. * the wait was satisfied.
  1794. * pOverLapped (input)
  1795. * An optional overlapped handle.
  1796. *
  1797. * EXIT:
  1798. * STATUS_SUCCESS - no error
  1799. *
  1800. ******************************************************************************/
  1801. NTSTATUS
  1802. _WaitCommEvent(
  1803. PTD pTd,
  1804. HANDLE hFile,
  1805. PULONG pEvtMask,
  1806. PTDIOSTATUS pIoStatus
  1807. )
  1808. {
  1809. NTSTATUS Status;
  1810. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1811. "TDASYNC: _WaitCommEvent: entry\n"
  1812. ));
  1813. ASSERT(!pTd->Params.Async.fConnectionDriver);
  1814. if (ARGUMENT_PRESENT(pIoStatus)) {
  1815. pIoStatus->Internal = (ULONG)STATUS_PENDING;
  1816. Status = ZwDeviceIoControlFile(
  1817. hFile,
  1818. pIoStatus->hEvent,
  1819. NULL,
  1820. NULL,
  1821. (PIO_STATUS_BLOCK)&pIoStatus->Internal,
  1822. IOCTL_SERIAL_WAIT_ON_MASK,
  1823. NULL,
  1824. 0,
  1825. pEvtMask,
  1826. sizeof(*pEvtMask) );
  1827. } else {
  1828. Status = _IoControl( pTd,
  1829. hFile,
  1830. IOCTL_SERIAL_WAIT_ON_MASK,
  1831. NULL,
  1832. 0,
  1833. pEvtMask,
  1834. sizeof(*pEvtMask),
  1835. NULL );
  1836. }
  1837. return( Status );
  1838. }
  1839. /*******************************************************************************
  1840. *
  1841. * _SetupComm
  1842. * The communication device is not initialized until SetupComm is
  1843. * called. This function allocates space for receive and transmit
  1844. * queues. These queues are used by the interrupt-driven transmit/
  1845. * receive software and are internal to the provider.
  1846. *
  1847. * ENTRY:
  1848. * pTd (input)
  1849. * Pointer to td data structure
  1850. * hFile (input)
  1851. * Specifies the communication device to receive the settings.
  1852. * InQueue (input)
  1853. * Specifies the recommended size of the provider's
  1854. * internal receive queue in bytes. This value must be
  1855. * even. A value of -1 indicates that the default should
  1856. * be used.
  1857. * OutQueue (input)
  1858. * Specifies the recommended size of the provider's
  1859. * internal transmit queue in bytes. This value must be
  1860. * even. A value of -1 indicates that the default should be used.
  1861. *
  1862. * EXIT:
  1863. * STATUS_SUCCESS - no error
  1864. *
  1865. ******************************************************************************/
  1866. NTSTATUS
  1867. _SetupComm(
  1868. PTD pTd,
  1869. HANDLE hFile,
  1870. ULONG InQueue,
  1871. ULONG OutQueue
  1872. )
  1873. {
  1874. NTSTATUS Status;
  1875. SERIAL_QUEUE_SIZE NewSizes = {0};
  1876. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1877. "TDASYNC: _SetupComm: InQueue %d, OutQueue %d\n",
  1878. InQueue, OutQueue
  1879. ));
  1880. /*
  1881. * Make sure that the sizes are even.
  1882. */
  1883. if (OutQueue != ((ULONG)-1)) {
  1884. if (((OutQueue/2)*2) != OutQueue) {
  1885. return( STATUS_INVALID_PARAMETER );
  1886. }
  1887. }
  1888. if (InQueue != ((ULONG)-1)) {
  1889. if (((InQueue/2)*2) != InQueue) {
  1890. return( STATUS_INVALID_PARAMETER );
  1891. }
  1892. }
  1893. NewSizes.InSize = InQueue;
  1894. NewSizes.OutSize = OutQueue;
  1895. Status = _IoControl( pTd,
  1896. hFile,
  1897. IOCTL_SERIAL_SET_QUEUE_SIZE,
  1898. &NewSizes,
  1899. sizeof(NewSizes),
  1900. NULL,
  1901. 0,
  1902. NULL );
  1903. return Status;
  1904. }
  1905. /*******************************************************************************
  1906. *
  1907. * _SetCommMask
  1908. *
  1909. * The function enables the event mask of the communication device
  1910. * specified by the hFile parameter. The bits of the EvtMask parameter
  1911. * define which events are to be enabled.
  1912. *
  1913. * ENTRY:
  1914. * pTd (input)
  1915. * Pointer to td data structure
  1916. * hFile (input)
  1917. * Specifies the communication device to receive the settings.
  1918. * EvtMask (input)
  1919. * Specifies which events are to enabled.
  1920. *
  1921. * EXIT:
  1922. * STATUS_SUCCESS - no error
  1923. *
  1924. ******************************************************************************/
  1925. NTSTATUS
  1926. _SetCommMask(
  1927. PTD pTd,
  1928. HANDLE hFile,
  1929. ULONG EvtMask
  1930. )
  1931. {
  1932. ULONG LocalMask = EvtMask;
  1933. NTSTATUS Status;
  1934. TRACE(( pTd->pContext, TC_TD, TT_API2,
  1935. "TDASYNC: _SetCommMask: EventMask 0x%x\n",
  1936. EvtMask
  1937. ));
  1938. /*
  1939. * Make sure that the users mask doesn't contain any values
  1940. * we don't support.
  1941. */
  1942. if (EvtMask & (~(EV_RXCHAR |
  1943. EV_RXFLAG |
  1944. EV_TXEMPTY |
  1945. EV_CTS |
  1946. EV_DSR |
  1947. EV_RLSD |
  1948. EV_BREAK |
  1949. EV_ERR |
  1950. EV_RING |
  1951. EV_PERR |
  1952. EV_RX80FULL |
  1953. EV_EVENT1 |
  1954. EV_EVENT2))) {
  1955. return( STATUS_INVALID_PARAMETER );
  1956. }
  1957. Status = _IoControl( pTd,
  1958. hFile,
  1959. IOCTL_SERIAL_SET_WAIT_MASK,
  1960. &LocalMask,
  1961. sizeof(LocalMask),
  1962. NULL,
  1963. 0,
  1964. NULL );
  1965. return Status;
  1966. }
  1967. /*******************************************************************************
  1968. *
  1969. * _GetCommProperties
  1970. *
  1971. * This function fills the ubffer pointed to by pCommProp with the
  1972. * communications properties associated with the communications device
  1973. * specified by the hFile.
  1974. *
  1975. * ENTRY:
  1976. * pTd (input)
  1977. * Pointer to td data structure
  1978. * hFile (input)
  1979. * Specifies the communication device to be examined.
  1980. * pCommProp (output)
  1981. * Points to the PSERIAL_COMMPROP data structure that is to
  1982. * receive the communications properties structure. This
  1983. * structure defines certain properties of the communications
  1984. * device.
  1985. *
  1986. * EXIT:
  1987. * STATUS_SUCCESS - no error
  1988. *
  1989. ******************************************************************************/
  1990. NTSTATUS
  1991. _GetCommProperties(
  1992. PTD pTd,
  1993. HANDLE hFile,
  1994. PSERIAL_COMMPROP pCommProp
  1995. )
  1996. {
  1997. NTSTATUS Status;
  1998. ULONG bufferLength;
  1999. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2000. "TDASYNC: _GetCommProperties: Entry\n"
  2001. ));
  2002. /*
  2003. * Get the total length of what to pass down. If the
  2004. * application indicates that there is provider specific data
  2005. * (by setting dwProvSpec1 to COMMPROP_INITIAILIZED) then
  2006. * use what's at the start of the commprop.
  2007. */
  2008. bufferLength = sizeof(pCommProp);
  2009. /*
  2010. * Zero out the commprop. This might create an access violation
  2011. * if it isn't big enough. Which is ok, since we would rather
  2012. * get it before we create the sync event.
  2013. */
  2014. RtlZeroMemory(pCommProp, bufferLength);
  2015. Status = _IoControl( pTd,
  2016. hFile,
  2017. IOCTL_SERIAL_GET_PROPERTIES,
  2018. NULL,
  2019. 0,
  2020. pCommProp,
  2021. bufferLength,
  2022. NULL );
  2023. return( Status );
  2024. }
  2025. /*******************************************************************************
  2026. *
  2027. * _GetCommState
  2028. *
  2029. * This function returns the stae of the communication device specified by
  2030. * hFile parameter.
  2031. *
  2032. * ENTRY::
  2033. * pTd (input)
  2034. * Pointer to td data structure
  2035. * hFile (input)
  2036. * Specifies the communication device to be examined.
  2037. * pBuad (output)
  2038. * Pointer to a SERIAL_BAUD_RATE structure
  2039. * pLineControl (output)
  2040. * Pointer to a SERIAL_LINE_CONTROL structure
  2041. * pChars (ouptut)
  2042. * Pointer to a SERIAL_CHARS structure
  2043. * pHandFlow (ouptut)
  2044. * Pointer to a SERIAL_HANDFLOW structure
  2045. *
  2046. * EXIT:
  2047. * STATUS_SUCCESS - no error
  2048. *
  2049. ******************************************************************************/
  2050. NTSTATUS
  2051. _GetCommState(
  2052. PTD pTd,
  2053. HANDLE hFile,
  2054. PSERIAL_BAUD_RATE pBaud,
  2055. PSERIAL_LINE_CONTROL pLineControl,
  2056. PSERIAL_CHARS pChars,
  2057. PSERIAL_HANDFLOW pHandFlow
  2058. )
  2059. {
  2060. NTSTATUS Status;
  2061. if ( ARGUMENT_PRESENT( pBaud ) ) {
  2062. Status = _IoControl( pTd,
  2063. hFile,
  2064. IOCTL_SERIAL_GET_BAUD_RATE,
  2065. NULL,
  2066. 0,
  2067. pBaud,
  2068. sizeof(*pBaud),
  2069. NULL );
  2070. if ( !NT_SUCCESS(Status)) {
  2071. return( Status );
  2072. }
  2073. }
  2074. if ( ARGUMENT_PRESENT( pLineControl ) ) {
  2075. Status = _IoControl( pTd,
  2076. hFile,
  2077. IOCTL_SERIAL_GET_LINE_CONTROL,
  2078. NULL,
  2079. 0,
  2080. pLineControl,
  2081. sizeof(*pLineControl),
  2082. NULL );
  2083. if ( !NT_SUCCESS(Status)) {
  2084. return( Status );
  2085. }
  2086. }
  2087. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2088. "TDASYNC: _GetCommState: Baud 0x%x, Sbits 0x%x, Par 0x%x, WLen 0x%x\n",
  2089. pBaud->BaudRate,
  2090. pLineControl->StopBits,
  2091. pLineControl->Parity,
  2092. pLineControl->WordLength
  2093. ));
  2094. if ( ARGUMENT_PRESENT( pChars ) ) {
  2095. Status = _IoControl( pTd,
  2096. hFile,
  2097. IOCTL_SERIAL_GET_CHARS,
  2098. NULL,
  2099. 0,
  2100. pChars,
  2101. sizeof(*pChars),
  2102. NULL );
  2103. if ( !NT_SUCCESS(Status)) {
  2104. return( Status );
  2105. }
  2106. }
  2107. if ( ARGUMENT_PRESENT( pHandFlow ) ) {
  2108. Status = _IoControl( pTd,
  2109. hFile,
  2110. IOCTL_SERIAL_GET_HANDFLOW,
  2111. NULL,
  2112. 0,
  2113. pHandFlow,
  2114. sizeof(*pHandFlow),
  2115. NULL );
  2116. if ( !NT_SUCCESS(Status)) {
  2117. return( Status );
  2118. }
  2119. }
  2120. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2121. "TDASYNC: _GetCommState: EOF 0x%x,ERR 0x%x,BRK 0x%x,EVT 0x%x,XON 0x%x,XOF 0x%x\n",
  2122. pChars->EofChar,
  2123. pChars->ErrorChar,
  2124. pChars->BreakChar,
  2125. pChars->EventChar,
  2126. pChars->XonChar,
  2127. pChars->XoffChar
  2128. ));
  2129. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2130. "TDASYNC: _GetCommState: CtrlHandS 0x%x,FlwRep 0x%x,XonL 0x%x,XoffL 0x%x\n",
  2131. pHandFlow->ControlHandShake,
  2132. pHandFlow->FlowReplace,
  2133. pHandFlow->XonLimit,
  2134. pHandFlow->XoffLimit
  2135. ));
  2136. return( STATUS_SUCCESS );
  2137. }
  2138. /*******************************************************************************
  2139. *
  2140. * TdSetComState
  2141. *
  2142. * The _SetCommState function sets the communication device specified by
  2143. * hfile parameter. This function reinitializes all hardwae and controls
  2144. * as specified, but does not empty the transmit or receive queues.
  2145. *
  2146. * ENTRY:
  2147. * pTd (input)
  2148. * Pointer to td data structure
  2149. * hFile (input)
  2150. * Specifies the communication device to be examined.
  2151. * pBuad (input)
  2152. * Pointer to a SERIAL_BAUD_RATE structure
  2153. * pLineControl (input)
  2154. * Pointer to a SERIAL_LINE_CONTROL structure
  2155. * pChars (input)
  2156. * Pointer to a SERIAL_CHARS structure
  2157. * pHandFlow (input)
  2158. * Pointer to a SERIAL_HANDFLOW structure
  2159. *
  2160. * EXIT:
  2161. * STATUS_SUCCESS - no error
  2162. *
  2163. ******************************************************************************/
  2164. NTSTATUS
  2165. _SetCommState(
  2166. PTD pTd,
  2167. HANDLE hFile,
  2168. PSERIAL_BAUD_RATE pBaud,
  2169. PSERIAL_LINE_CONTROL pLineControl,
  2170. PSERIAL_CHARS pChars,
  2171. PSERIAL_HANDFLOW pHandFlow
  2172. )
  2173. {
  2174. NTSTATUS Status;
  2175. SERIAL_BAUD_RATE LocalBaud;
  2176. SERIAL_LINE_CONTROL LocalLineControl;
  2177. SERIAL_CHARS LocalChars;
  2178. SERIAL_HANDFLOW LocalHandFlow;
  2179. /*
  2180. * Get the current state before any changes are made, so that
  2181. * in the case of an error, the original state be restored.
  2182. */
  2183. Status = _GetCommState( pTd,
  2184. hFile,
  2185. &LocalBaud,
  2186. &LocalLineControl,
  2187. &LocalChars,
  2188. &LocalHandFlow );
  2189. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2190. "TDASYNC: _SetCommState: Baud 0x%x, Sbits 0x%x, Par 0x%x, WLen 0x%x\n",
  2191. pBaud->BaudRate,
  2192. pLineControl->StopBits,
  2193. pLineControl->Parity,
  2194. pLineControl->WordLength
  2195. ));
  2196. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2197. "TDASYNC: _SetCommState: EOF 0x%x,ERR 0x%x,BRK 0x%x,EVT 0x%x,XON 0x%x,XOF 0x%x\n",
  2198. pChars->EofChar,
  2199. pChars->ErrorChar,
  2200. pChars->BreakChar,
  2201. pChars->EventChar,
  2202. pChars->XonChar,
  2203. pChars->XoffChar
  2204. ));
  2205. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2206. "TDASYNC: _SetCommState: CtrlHandS 0x%x,FlwRep 0x%x,XonL 0x%x,XoffL 0x%x\n",
  2207. pHandFlow->ControlHandShake,
  2208. pHandFlow->FlowReplace,
  2209. pHandFlow->XonLimit,
  2210. pHandFlow->XoffLimit
  2211. ));
  2212. if ( NT_SUCCESS( Status ) ) {
  2213. /*
  2214. * Try to set the baud rate. If we fail here, we just return
  2215. * because we never actually got to set anything.
  2216. */
  2217. Status = _IoControl( pTd,
  2218. hFile,
  2219. IOCTL_SERIAL_SET_BAUD_RATE,
  2220. pBaud,
  2221. sizeof(*pBaud),
  2222. NULL,
  2223. 0,
  2224. NULL );
  2225. if ( !NT_SUCCESS( Status ) )
  2226. goto badsetnorestore;
  2227. Status = _IoControl( pTd,
  2228. hFile,
  2229. IOCTL_SERIAL_SET_LINE_CONTROL,
  2230. pLineControl,
  2231. sizeof(*pLineControl),
  2232. NULL,
  2233. 0,
  2234. NULL );
  2235. if ( !NT_SUCCESS( Status ) )
  2236. goto badset;
  2237. Status = _IoControl( pTd,
  2238. hFile,
  2239. IOCTL_SERIAL_SET_CHARS,
  2240. pChars,
  2241. sizeof(*pChars),
  2242. NULL,
  2243. 0,
  2244. NULL );
  2245. if ( !NT_SUCCESS( Status ) )
  2246. goto badset;
  2247. Status = _IoControl( pTd,
  2248. hFile,
  2249. IOCTL_SERIAL_SET_HANDFLOW,
  2250. pHandFlow,
  2251. sizeof(*pHandFlow),
  2252. NULL,
  2253. 0,
  2254. NULL );
  2255. if ( !NT_SUCCESS( Status ) )
  2256. goto badset;
  2257. return( STATUS_SUCCESS );
  2258. }
  2259. /*
  2260. * Error Encountered, Restore previous state.
  2261. */
  2262. badset:
  2263. _SetCommState( pTd,
  2264. hFile,
  2265. &LocalBaud,
  2266. &LocalLineControl,
  2267. &LocalChars,
  2268. &LocalHandFlow );
  2269. badsetnorestore:
  2270. return( Status );
  2271. }
  2272. /*******************************************************************************
  2273. *
  2274. * _PurgeComm
  2275. *
  2276. * This function is used to purge all characters from the transmit
  2277. * or receive queues of the communication device specified by the
  2278. * hFile parameter. The Flags parameter specifies what function
  2279. * is to be performed.
  2280. *
  2281. * ENTRY:
  2282. * pTd (input)
  2283. * Pointer to td data structure
  2284. * hFile (input)
  2285. * Specifies the communication device to be purged.
  2286. * Flags (input)
  2287. * Bit mask defining actions to be taken.
  2288. *
  2289. * EXIT:
  2290. * STATUS_SUCCESS - no error
  2291. *
  2292. ******************************************************************************/
  2293. NTSTATUS
  2294. _PurgeComm(
  2295. PTD pTd,
  2296. HANDLE hFile,
  2297. ULONG Flags
  2298. )
  2299. {
  2300. NTSTATUS Status;
  2301. Status = _IoControl( pTd,
  2302. hFile,
  2303. IOCTL_SERIAL_PURGE,
  2304. &Flags,
  2305. sizeof(Flags),
  2306. NULL,
  2307. 0,
  2308. NULL );
  2309. return( Status );
  2310. }
  2311. /*******************************************************************************
  2312. *
  2313. *
  2314. * _ClearCommError
  2315. *
  2316. * In case of a communications error, such as a buffer overrun or
  2317. * framing error, the communications software will abort all
  2318. * read and write operations on the communication port. No further
  2319. * read or write operations will be accepted until this function
  2320. * is called.
  2321. *
  2322. * ENTRY:
  2323. * pTd (input)
  2324. * Pointer to td data structure
  2325. * hFile (input)
  2326. * Specifies the communication device to be adjusted.
  2327. * pStat (output)
  2328. * Points to the SERIAL_STATUS structure that is to receive
  2329. * the device status. The structure contains information
  2330. * about the communications device.
  2331. *
  2332. * EXIT:
  2333. * STATUS_SUCCESS - no error
  2334. *
  2335. ******************************************************************************/
  2336. NTSTATUS
  2337. _ClearCommError(
  2338. PTD pTd,
  2339. HANDLE hFile,
  2340. PSERIAL_STATUS pStat
  2341. )
  2342. {
  2343. NTSTATUS Status;
  2344. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2345. "TDASYNC: _ClearCommError: Entry\n"
  2346. ));
  2347. RtlZeroMemory( pStat, sizeof(*pStat) );
  2348. Status = _IoControl( pTd,
  2349. hFile,
  2350. IOCTL_SERIAL_GET_COMMSTATUS,
  2351. NULL,
  2352. 0,
  2353. pStat,
  2354. sizeof(*pStat),
  2355. NULL );
  2356. return( Status );
  2357. }
  2358. /*******************************************************************************
  2359. *
  2360. *
  2361. * _IoControl
  2362. *
  2363. * The _IoControl function performs a specified I/O control function.
  2364. *
  2365. * ENTRY:
  2366. * pTd (input)
  2367. * Pointer to td data structure
  2368. * hFile (input)
  2369. * Supplies the open handle to the file that the overlapped structure.
  2370. * IoControlCode (input)
  2371. * Value of the I/O control command
  2372. * pIn (input)
  2373. * Pointer to the I/O control command's input buffer.
  2374. * InSize (input)
  2375. * Size (in bytes) of input buffer.
  2376. * pOut (output)
  2377. * Pointer to the I/O control command's output buffer.
  2378. * OutSize (input)
  2379. * Size (in bytes) of output buffer.
  2380. * pBytesWritten (output)
  2381. * Size (in bytes) of data actually written to the output buffer.
  2382. *
  2383. * EXIT:
  2384. * STATUS_SUCCESS - no error
  2385. *
  2386. ******************************************************************************/
  2387. NTSTATUS
  2388. _IoControl(
  2389. PTD pTd,
  2390. HANDLE hFile,
  2391. ULONG IoControlCode,
  2392. PVOID pIn,
  2393. ULONG InSize,
  2394. PVOID pOut,
  2395. ULONG OutSize,
  2396. PULONG pBytesWritten
  2397. )
  2398. {
  2399. IO_STATUS_BLOCK Iosb;
  2400. HANDLE hEvent;
  2401. NTSTATUS Status;
  2402. TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _IoControl: Entry\n" ));
  2403. Status = ZwCreateEvent(
  2404. &hEvent,
  2405. EVENT_ALL_ACCESS,
  2406. NULL,
  2407. NotificationEvent,
  2408. FALSE );
  2409. if ( !NT_SUCCESS( Status ) ) {
  2410. return Status;
  2411. }
  2412. Status = ZwDeviceIoControlFile( hFile,
  2413. hEvent,
  2414. NULL,
  2415. NULL,
  2416. &Iosb,
  2417. IoControlCode,
  2418. pIn,
  2419. InSize,
  2420. pOut,
  2421. OutSize );
  2422. if ( Status == STATUS_PENDING ) {
  2423. PKEVENT pEventObject;
  2424. // Operation must complete before return & IoStatusBlock destroyed
  2425. Status = ObReferenceObjectByHandle( hEvent,
  2426. EVENT_MODIFY_STATE,
  2427. NULL,
  2428. KernelMode,
  2429. (PVOID *) &pEventObject,
  2430. NULL );
  2431. if ( NT_SUCCESS( Status ) ) {
  2432. Status = IcaWaitForSingleObject( pTd->pContext,
  2433. pEventObject,
  2434. INFINITE );
  2435. ObDereferenceObject( pEventObject );
  2436. if ( NT_SUCCESS( Status ) ) {
  2437. Status = Iosb.Status;
  2438. }
  2439. }
  2440. }
  2441. if ( ARGUMENT_PRESENT( pBytesWritten ) ) {
  2442. *pBytesWritten = (ULONG)Iosb.Information;
  2443. }
  2444. ZwClose( hEvent );
  2445. return Status;
  2446. }
  2447. /*******************************************************************************
  2448. *
  2449. * _OpenDevice
  2450. *
  2451. * Open the communications device.
  2452. *
  2453. * ENTRY:
  2454. * pTd (input)
  2455. * Pointer to td data structure
  2456. *
  2457. * EXIT:
  2458. * STATUS_SUCCESS - no error
  2459. *
  2460. ******************************************************************************/
  2461. NTSTATUS
  2462. _OpenDevice(
  2463. PTD pTd )
  2464. {
  2465. PTDASYNC pTdAsync;
  2466. PASYNCCONFIG pAsync;
  2467. IO_STATUS_BLOCK ioStatusBlock;
  2468. OBJECT_ATTRIBUTES Obja;
  2469. UNICODE_STRING DeviceName;
  2470. DEVICENAMEW TempDeviceName;
  2471. NTSTATUS Status;
  2472. /*
  2473. * Get pointer to async parameters
  2474. */
  2475. pTdAsync = (PTDASYNC) pTd->pPrivate;
  2476. pAsync = &pTd->Params.Async;
  2477. /*
  2478. * Open device
  2479. */
  2480. wcscpy( TempDeviceName, L"\\DosDevices\\" );
  2481. wcscat( TempDeviceName, pAsync->DeviceName );
  2482. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2483. "TDASYNC: _OpenDevice, Opening \"%S\"\n",
  2484. TempDeviceName ));
  2485. RtlInitUnicodeString( &DeviceName, TempDeviceName);
  2486. InitializeObjectAttributes( &Obja,
  2487. &DeviceName,
  2488. OBJ_CASE_INSENSITIVE,
  2489. NULL,
  2490. NULL );
  2491. Status = ZwOpenFile( &pTdAsync->Endpoint.hDevice,
  2492. GENERIC_READ | GENERIC_WRITE |
  2493. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  2494. &Obja,
  2495. &ioStatusBlock,
  2496. 0, // ShareAccess
  2497. FILE_NON_DIRECTORY_FILE );
  2498. if ( !NT_SUCCESS( Status ) ) {
  2499. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  2500. Status = STATUS_NO_SUCH_DEVICE;
  2501. }
  2502. goto badopen;
  2503. }
  2504. /*
  2505. * Create event for I/O status
  2506. */
  2507. Status = ZwCreateEvent( &pTdAsync->Endpoint.SignalIoStatus.hEvent,
  2508. EVENT_ALL_ACCESS,
  2509. NULL,
  2510. NotificationEvent,
  2511. FALSE );
  2512. if ( !NT_SUCCESS( Status ) ) {
  2513. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2514. "TDASYNC: _OpenDevice, Create SignalEvent failed (0x%x)\n",
  2515. Status ));
  2516. goto badcreateevent;
  2517. }
  2518. TRACE(( pTd->pContext, TC_TD, TT_API2,
  2519. "TDASYNC: _OpenDevice, SignalIoStatus event handle 0x%x\n",
  2520. pTdAsync->Endpoint.SignalIoStatus.hEvent ));
  2521. return( Status );
  2522. /*=============================================================================
  2523. == Error returns
  2524. =============================================================================*/
  2525. /*
  2526. * Create of SignalIoStatus event failed.
  2527. */
  2528. badcreateevent:
  2529. ZwClose( pTdAsync->Endpoint.hDevice );
  2530. pTdAsync->Endpoint.hDevice = NULL;
  2531. /*
  2532. * OpenFile failed
  2533. */
  2534. badopen:
  2535. return( Status );
  2536. }
  2537. /*******************************************************************************
  2538. *
  2539. * _PrepareDevice
  2540. *
  2541. * Prepare the communications device for ICA use.
  2542. *
  2543. * ENTRY:
  2544. * pTd (input)
  2545. * Pointer to td data structure
  2546. *
  2547. * EXIT:
  2548. * STATUS_SUCCESS - no error
  2549. *
  2550. ******************************************************************************/
  2551. NTSTATUS
  2552. _PrepareDevice(
  2553. PTD pTd )
  2554. {
  2555. PTDASYNC pTdAsync;
  2556. PASYNCCONFIG pAsync;
  2557. SERIAL_TIMEOUTS SerialTo;
  2558. NTSTATUS Status;
  2559. /*
  2560. * Get pointer to async parameters
  2561. */
  2562. pTdAsync = (PTDASYNC) pTd->pPrivate;
  2563. pAsync = &pTd->Params.Async;
  2564. /*
  2565. * Obtain a referenced pointer to the file object.
  2566. */
  2567. Status = ObReferenceObjectByHandle (
  2568. pTdAsync->Endpoint.hDevice,
  2569. 0,
  2570. *IoFileObjectType,
  2571. KernelMode,
  2572. (PVOID *)&pTdAsync->Endpoint.pFileObject,
  2573. NULL );
  2574. if ( !NT_SUCCESS( Status ) ) {
  2575. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2576. "TDASYNC: _PrepareDevice, ObReferenceObjectByHandle Device failed (0x%x)\n",
  2577. Status ));
  2578. goto badhandleobj;
  2579. }
  2580. pTdAsync->Endpoint.pDeviceObject = IoGetRelatedDeviceObject(
  2581. pTdAsync->Endpoint.pFileObject);
  2582. /*
  2583. * Obtain a reference pointer to the SignalIoStatus Event
  2584. */
  2585. Status = ObReferenceObjectByHandle( pTdAsync->Endpoint.SignalIoStatus.hEvent,
  2586. EVENT_MODIFY_STATE,
  2587. NULL,
  2588. KernelMode,
  2589. (PVOID *)
  2590. &pTdAsync->Endpoint.SignalIoStatus.pEventObject,
  2591. NULL );
  2592. if ( !NT_SUCCESS( Status ) ) {
  2593. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2594. "TDASYNC: _PrepareDevice, ObReferenceObjectByHandle SignalEventObject failed (0x%x)\n",
  2595. Status ));
  2596. goto badsigeventobj;
  2597. }
  2598. /*
  2599. * Set timeout parameters
  2600. */
  2601. RtlZeroMemory( &SerialTo, sizeof(SerialTo) );
  2602. SerialTo.ReadIntervalTimeout = 1; // msec
  2603. Status = _SetCommTimeouts( pTd, pTdAsync->Endpoint.hDevice, &SerialTo);
  2604. if ( !NT_SUCCESS( Status ) ) {
  2605. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2606. "TDASYNC: _SetCommTimeouts failed 0x%x\n",
  2607. Status ));
  2608. goto badsetmode;
  2609. }
  2610. /*
  2611. * Set communication parameters
  2612. */
  2613. Status = DeviceSetParams( pTd );
  2614. if ( !NT_SUCCESS( Status ) ) {
  2615. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2616. "TDASYNC: DeviceSetParams failed 0x%x\n",
  2617. Status ));
  2618. goto badparams;
  2619. }
  2620. return( STATUS_SUCCESS );
  2621. /*=============================================================================
  2622. == Error returns
  2623. =============================================================================*/
  2624. /*
  2625. * set of communication parameters failed
  2626. * set of timeout mode failed
  2627. */
  2628. badparams:
  2629. badsetmode:
  2630. ObDereferenceObject( pTdAsync->Endpoint.SignalIoStatus.pEventObject );
  2631. pTdAsync->Endpoint.SignalIoStatus.pEventObject = NULL;
  2632. badsigeventobj:
  2633. ObDereferenceObject( pTdAsync->Endpoint.pFileObject );
  2634. pTdAsync->Endpoint.pFileObject = NULL;
  2635. badhandleobj:
  2636. return( Status );
  2637. }
  2638. /*******************************************************************************
  2639. *
  2640. * _FillInEndpoint
  2641. *
  2642. * Fill in the endpoint to be returned via the ioctl's output buffer
  2643. *
  2644. * ENTRY:
  2645. * pTd (input)
  2646. * Pointer to td data structure
  2647. * pEndpoint (output)
  2648. * pointer to buffer to return copy of endpoint structure
  2649. * Length (input)
  2650. * length of endpoint buffer
  2651. * pEndpointLength (output)
  2652. * pointer to address to return actual length of Endpoint
  2653. *
  2654. * EXIT:
  2655. * STATUS_SUCCESS - no error
  2656. * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small
  2657. *
  2658. ******************************************************************************/
  2659. NTSTATUS
  2660. _FillInEndpoint(
  2661. PTD pTd,
  2662. PVOID pEndpoint,
  2663. ULONG Length,
  2664. PULONG pEndpointLength
  2665. )
  2666. {
  2667. PTDASYNC pTdAsync;
  2668. ULONG ActualEndpointLength = sizeof(TDASYNC_ENDPOINT);
  2669. PTDASYNC_ENDPOINT pEp = (PTDASYNC_ENDPOINT) pEndpoint;
  2670. /*
  2671. * Always return actual size of Endpoint.
  2672. */
  2673. if ( ARGUMENT_PRESENT( pEndpointLength ) ) {
  2674. *pEndpointLength = ActualEndpointLength;
  2675. }
  2676. /*
  2677. * Make sure endpoint buffer is large enough
  2678. */
  2679. if ( ARGUMENT_PRESENT( pEndpoint ) && Length < ActualEndpointLength ) {
  2680. TRACE(( pTd->pContext, TC_TD, TT_ERROR,
  2681. "TDASYNC: DeviceConnectionWait, Buffer too small %d, %d req'd\n",
  2682. Length, ActualEndpointLength ));
  2683. return( STATUS_BUFFER_TOO_SMALL );
  2684. }
  2685. /*
  2686. * Get pointer to async parameters
  2687. */
  2688. pTdAsync = (PTDASYNC) pTd->pPrivate;
  2689. /*
  2690. * copy Endpoint structure
  2691. */
  2692. if ( ARGUMENT_PRESENT( pEndpoint ) ) {
  2693. pEp->hDevice = pTdAsync->Endpoint.hDevice;
  2694. pEp->pFileObject = pTdAsync->Endpoint.pFileObject;
  2695. pEp->pDeviceObject = pTdAsync->Endpoint.pDeviceObject;
  2696. pEp->SignalIoStatus.pEventObject =
  2697. pTdAsync->Endpoint.SignalIoStatus.pEventObject;
  2698. pEp->SignalIoStatus.hEvent =
  2699. pTdAsync->Endpoint.SignalIoStatus.hEvent;
  2700. }
  2701. return( STATUS_SUCCESS );
  2702. }