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.

851 lines
26 KiB

  1. /*************************************************************************
  2. *
  3. * input.c
  4. *
  5. * Common input code for all transport drivers
  6. *
  7. * Copyright 1998, Microsoft
  8. *
  9. *************************************************************************/
  10. /*
  11. * Includes
  12. */
  13. #include <ntddk.h>
  14. #include <ntddvdeo.h>
  15. #include <ntddkbd.h>
  16. #include <ntddmou.h>
  17. #include <ntddbeep.h>
  18. #include <winstaw.h>
  19. #include <icadd.h>
  20. #include <sdapi.h>
  21. #include <td.h>
  22. #if DBG
  23. ULONG
  24. DbgPrint(
  25. PCH Format,
  26. ...
  27. );
  28. #define DBGPRINT(x) DbgPrint x
  29. #if DBGTRACE
  30. #define TRACE0(x) DbgPrint x
  31. #define TRACE1(x) DbgPrint x
  32. #else
  33. #define TRACE0(x)
  34. #define TRACE1(x)
  35. #endif
  36. #else
  37. #define DBGPRINT(x)
  38. #define TRACE0(x)
  39. #define TRACE1(x)
  40. #endif
  41. /*=============================================================================
  42. == External Functions Defined
  43. =============================================================================*/
  44. NTSTATUS TdInputThread( PTD );
  45. /*=============================================================================
  46. == Internal Functions Defined
  47. =============================================================================*/
  48. NTSTATUS _TdInBufAlloc( PTD, PINBUF * );
  49. VOID _TdInBufFree( PTD, PINBUF );
  50. NTSTATUS _TdInitializeRead( PTD, PINBUF );
  51. NTSTATUS _TdReadComplete( PTD, PINBUF );
  52. NTSTATUS _TdReadCompleteRoutine( PDEVICE_OBJECT, PIRP, PVOID );
  53. /*=============================================================================
  54. == Functions used
  55. =============================================================================*/
  56. NTSTATUS DeviceInitializeRead( PTD, PINBUF );
  57. NTSTATUS DeviceWaitForRead( PTD );
  58. NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG );
  59. NTSTATUS StackCancelIo( PTD, PSD_IOCTL );
  60. NTSTATUS NtSetInformationThread( HANDLE, THREADINFOCLASS, PVOID, ULONG );
  61. NTSTATUS DeviceSubmitRead( PTD, PINBUF );
  62. NTSTATUS MemoryAllocate( ULONG, PVOID * );
  63. VOID MemoryFree( PVOID );
  64. /*******************************************************************************
  65. *
  66. * TdInputThread
  67. *
  68. * This private TD thread waits for input data. This thread is created
  69. * when a client connection is established and is terminated when
  70. * StackCancelIo is called.
  71. *
  72. * All received data is sent to the up stream stack driver.
  73. *
  74. *
  75. * ENTRY:
  76. * pTd (input)
  77. * Pointer to TD data structure
  78. *
  79. * EXIT:
  80. * nothing
  81. *
  82. ******************************************************************************/
  83. NTSTATUS
  84. TdInputThread( PTD pTd )
  85. {
  86. ICA_CHANNEL_COMMAND Command;
  87. KPRIORITY Priority;
  88. PFILE_OBJECT pFileObject;
  89. PINBUF pInBuf;
  90. PLIST_ENTRY Head, Next;
  91. KIRQL oldIrql;
  92. ULONG InputByteCount;
  93. int i;
  94. NTSTATUS Status;
  95. TRACE(( pTd->pContext, TC_TD, TT_API2, "TdInputThread (entry)\n" ));
  96. /*
  97. * Check if driver is being closed or endpoint has been closed
  98. */
  99. if ( pTd->fClosing || pTd->pDeviceObject == NULL ) {
  100. TRACE(( pTd->pContext, TC_TD, TT_API2, "TdInputThread (exit) on init\n" ));
  101. return( STATUS_CTX_CLOSE_PENDING );
  102. }
  103. /*
  104. * Set the priority of this thread to lowest realtime (16).
  105. */
  106. Priority = LOW_REALTIME_PRIORITY;
  107. NtSetInformationThread( NtCurrentThread(), ThreadPriority,
  108. &Priority, sizeof(KPRIORITY) );
  109. /*
  110. * Initialize the input wait event
  111. */
  112. KeInitializeEvent( &pTd->InputEvent, NotificationEvent, FALSE );
  113. /*
  114. * Allocate and pre-submit one less than the total number
  115. * of input buffers that we will use. The final buffer will
  116. * be allocated/submitted within the input loop.
  117. */
  118. for ( i = 1; i < pTd->InBufCount; i++ ) {
  119. /*
  120. * Allocate an input buffer
  121. */
  122. Status = _TdInBufAlloc( pTd, &pInBuf );
  123. if ( !NT_SUCCESS( Status ) )
  124. return( Status );
  125. /*
  126. * Initialize the read IRP
  127. */
  128. Status = _TdInitializeRead( pTd, pInBuf );
  129. if ( !NT_SUCCESS(Status) )
  130. return( Status );
  131. /*
  132. * Let the device level code complete the IRP initialization
  133. */
  134. Status = DeviceInitializeRead( pTd, pInBuf );
  135. if ( !NT_SUCCESS(Status) )
  136. return( Status );
  137. /*
  138. * Place the INBUF on the busy list and call the device submit routine.
  139. * (TDI based drivers use receive indications, so we let
  140. * the TD specific code call the driver.)
  141. */
  142. ExInterlockedInsertTailList( &pTd->InBufBusyHead, &pInBuf->Links,
  143. &pTd->InBufListLock );
  144. Status = DeviceSubmitRead( pTd, pInBuf );
  145. }
  146. /*
  147. * Allocate an input buffer
  148. */
  149. Status = _TdInBufAlloc( pTd, &pInBuf );
  150. if ( !NT_SUCCESS( Status ) )
  151. return( Status );
  152. /*
  153. * Reference the file object and keep a local pointer to it.
  154. * This is done so that when the endpoint object gets closed,
  155. * and pTd->pFileObject gets dereferenced and cleared, the file
  156. * object will not get deleted before all of the pending input IRPs
  157. * (which reference the file object) get cancelled.
  158. */
  159. ObReferenceObject( (pFileObject = pTd->pFileObject) );
  160. /*
  161. * Loop reading input data until cancelled or we get an error.
  162. */
  163. for (;;) {
  164. /*
  165. * Initialize the read IRP
  166. */
  167. Status = _TdInitializeRead( pTd, pInBuf );
  168. if ( !NT_SUCCESS(Status) )
  169. break;
  170. /*
  171. * Let the device level code complete the IRP initialization
  172. */
  173. Status = DeviceInitializeRead( pTd, pInBuf );
  174. if ( !NT_SUCCESS(Status) )
  175. break;
  176. /*
  177. * Place the INBUF on the busy list and call the device submit routine.
  178. * (TDI based drivers use receive indications, so we let
  179. * the TD specific code call the driver.)
  180. */
  181. ExInterlockedInsertTailList( &pTd->InBufBusyHead, &pInBuf->Links,
  182. &pTd->InBufListLock );
  183. Status = DeviceSubmitRead( pTd, pInBuf );
  184. /*
  185. * Indicate we no longer have an INBUF referenced
  186. */
  187. pInBuf = NULL;
  188. if ( !NT_SUCCESS(Status) ) {
  189. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TdInputThread: IoCallDriver Status=0x%x\n", Status ));
  190. TRACE0(("TdInputThread: IoCallDriver Status=0x%x, Context 0x%x\n", Status, pTd->pAfd ));
  191. pTd->ReadErrorCount++;
  192. pTd->pStatus->Input.TdErrors++;
  193. if ( pTd->ReadErrorCount >= pTd->ReadErrorThreshold ) {
  194. // Submit failed, set the event since no IRP's are queued
  195. KeSetEvent( &pTd->InputEvent, 1, FALSE );
  196. break;
  197. }
  198. }
  199. /*
  200. * If the INBUF completed list is empty,
  201. * then wait for one to be available.
  202. */
  203. waitforread:
  204. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  205. if ( IsListEmpty( &pTd->InBufDoneHead ) ) {
  206. KeClearEvent( &pTd->InputEvent );
  207. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  208. Status = DeviceWaitForRead( pTd );
  209. /*
  210. * Check for broken connection
  211. */
  212. if ( pTd->fClosing ) {
  213. TRACE(( pTd->pContext, TC_TD, TT_IN1, "TdInputThread: fClosing set\n" ));
  214. TRACE0(("TdInputThread: fClosing set Context 0x%x\n",pTd->pAfd ));
  215. break;
  216. } else if ( Status != STATUS_SUCCESS) {
  217. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TdInputThread: DeviceWaitForRead Status=0x%x\n", Status ));
  218. TRACE0(( "TdInputThread: DeviceWaitForRead Status=0x%x, Context 0x%x\n", Status, pTd->pAfd ));
  219. pTd->ReadErrorCount++;
  220. pTd->pStatus->Input.TdErrors++;
  221. if ( pTd->ReadErrorCount < pTd->ReadErrorThreshold )
  222. goto waitforread;
  223. break;
  224. }
  225. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  226. /*
  227. * Check for broken connection
  228. */
  229. } else if ( pTd->fClosing ) {
  230. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  231. TRACE(( pTd->pContext, TC_TD, TT_IN1, "TdInputThread: fClosing set\n" ));
  232. TRACE0(("TdInputThread: fClosing set Context 0x%x\n",pTd->pAfd ));
  233. break;
  234. }
  235. /*
  236. * If the list is empty as this point, we will just bail.
  237. */
  238. if (!IsListEmpty( &pTd->InBufDoneHead )) {
  239. /*
  240. * Take the first INBUF off the completed list.
  241. */
  242. Head = RemoveHeadList( &pTd->InBufDoneHead );
  243. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  244. pInBuf = CONTAINING_RECORD( Head, INBUF, Links );
  245. /*
  246. * Do any preliminary read complete processing
  247. */
  248. (VOID) _TdReadComplete( pTd, pInBuf );
  249. /*
  250. * Get status from IRP. Note that we allow warning and informational
  251. * status codes as they can also return valid data.
  252. */
  253. Status = pInBuf->pIrp->IoStatus.Status;
  254. InputByteCount = (ULONG)pInBuf->pIrp->IoStatus.Information;
  255. if (NT_ERROR(Status)) {
  256. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TdInputThread: IRP Status=0x%x\n", Status ));
  257. TRACE0(("TdInputThread: IRP Status=0x%x, Context 0x%x\n", Status, pTd->pAfd ));
  258. pTd->ReadErrorCount++;
  259. pTd->pStatus->Input.TdErrors++;
  260. if ( pTd->ReadErrorCount < pTd->ReadErrorThreshold )
  261. continue;
  262. break;
  263. }
  264. if ( Status == STATUS_TIMEOUT )
  265. Status = STATUS_SUCCESS;
  266. /*
  267. * Make sure we got some data
  268. */
  269. TRACE(( pTd->pContext, TC_TD, TT_IN1, "TdInputThread: read cnt=%04u, Status=0x%x\n",
  270. InputByteCount, Status ));
  271. /*
  272. * Check for consecutive zero byte reads
  273. * -- the client may have dropped the connection and ReadFile does
  274. * not always return an error.
  275. * -- some tcp networks return zero byte reads now and then
  276. */
  277. if ( InputByteCount == 0 ) {
  278. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "recv warning: zero byte count\n" ));
  279. TRACE0(("recv warning: zero byte count, Context 0x%x\n",pTd->pAfd ));
  280. if ( ++pTd->ZeroByteReadCount > MAXIMUM_ZERO_BYTE_READS ) {
  281. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "recv failed: %u zero bytes\n", MAXIMUM_ZERO_BYTE_READS ));
  282. TRACE0(("recv failed: %u zero bytes Context 0x%x\n", MAXIMUM_ZERO_BYTE_READS, pTd->pAfd ));
  283. Status = STATUS_CTX_TD_ERROR;
  284. break;
  285. }
  286. continue;
  287. }
  288. /*
  289. * Clear count of consecutive zero byte reads
  290. */
  291. pTd->ZeroByteReadCount = 0;
  292. TRACEBUF(( pTd->pContext, TC_TD, TT_IRAW, pInBuf->pBuffer, InputByteCount ));
  293. /*
  294. * Do device specific read completion processing.
  295. * If the byte count returned is 0, then the device routine
  296. * processed all input data so there is nothing for us to do.
  297. */
  298. Status = DeviceReadComplete( pTd, pInBuf->pBuffer, &InputByteCount );
  299. if ( !NT_SUCCESS(Status) ) {
  300. TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TdInputThread: DeviceReadComplete Status=0x%x\n", Status ));
  301. TRACE0(("TdInputThread: DeviceReadComplete Status=0x%x, Context 0x%x\n", Status, pTd->pAfd ));
  302. pTd->ReadErrorCount++;
  303. pTd->pStatus->Input.TdErrors++;
  304. if ( pTd->ReadErrorCount < pTd->ReadErrorThreshold )
  305. continue;
  306. break;
  307. }
  308. if ( InputByteCount == 0 )
  309. continue;
  310. /*
  311. * Clear count of consecutive read errors
  312. */
  313. pTd->ReadErrorCount = 0;
  314. /*
  315. * Update input byte counter
  316. */
  317. pTd->pStatus->Input.Bytes += (InputByteCount - pTd->InBufHeader);
  318. if ( pTd->PdFlag & PD_FRAME )
  319. pTd->pStatus->Input.Frames++;
  320. /*
  321. * Send input data to upstream stack driver
  322. */
  323. Status = IcaRawInput( pTd->pContext,
  324. NULL,
  325. (pInBuf->pBuffer + pTd->InBufHeader),
  326. (InputByteCount - pTd->InBufHeader) );
  327. if ( !NT_SUCCESS(Status) )
  328. break;
  329. }
  330. else {
  331. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  332. TRACE(( pTd->pContext, TC_TD, TT_IN1, "TdInputThread: InBuf is empty\n" ));
  333. ASSERT(FALSE);
  334. pTd->ReadErrorCount++;
  335. pTd->pStatus->Input.TdErrors++;
  336. if ( pTd->ReadErrorCount < pTd->ReadErrorThreshold )
  337. goto waitforread;
  338. else
  339. break;
  340. }
  341. }
  342. TRACE0(("TdInputThread: Breaking Connection Context 0x%x\n",pTd->pAfd));
  343. /*
  344. * Free current INBUF if we have one
  345. */
  346. if ( pInBuf )
  347. _TdInBufFree( pTd, pInBuf );
  348. /*
  349. * Cancel all i/o
  350. */
  351. (VOID) StackCancelIo( pTd, NULL );
  352. /*
  353. * Wait for pending read (if any) to be cancelled
  354. */
  355. (VOID) IcaWaitForSingleObject( pTd->pContext, &pTd->InputEvent, -1 );
  356. /*
  357. * Free all remaining INBUFs
  358. */
  359. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  360. while ( !IsListEmpty( &pTd->InBufBusyHead ) ||
  361. !IsListEmpty( &pTd->InBufDoneHead ) ) {
  362. if ( !IsListEmpty( &pTd->InBufBusyHead ) ) {
  363. BOOLEAN rc;
  364. Head = RemoveHeadList( &pTd->InBufBusyHead );
  365. Head->Flink = NULL;
  366. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  367. pInBuf = CONTAINING_RECORD( Head, INBUF, Links );
  368. rc = IoCancelIrp( pInBuf->pIrp );
  369. #if DBG
  370. if ( !rc ) {
  371. DbgPrint("TDCOMMON: StackCancelIo: Could not cancel IRP 0x%x\n",pInBuf->pIrp);
  372. }
  373. #endif
  374. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  375. }
  376. if ( IsListEmpty( &pTd->InBufDoneHead ) ) {
  377. KeClearEvent( &pTd->InputEvent );
  378. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  379. Status = DeviceWaitForRead( pTd );
  380. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  381. }
  382. if ( !IsListEmpty( &pTd->InBufDoneHead ) ) {
  383. Head = RemoveHeadList( &pTd->InBufDoneHead );
  384. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  385. pInBuf = CONTAINING_RECORD( Head, INBUF, Links );
  386. _TdInBufFree( pTd, pInBuf );
  387. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  388. }
  389. }
  390. ASSERT( IsListEmpty( &pTd->InBufBusyHead ) );
  391. ASSERT( IsListEmpty( &pTd->InBufDoneHead ) );
  392. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  393. /*
  394. * Release our reference on the underlying file object
  395. */
  396. ObDereferenceObject( pFileObject );
  397. /*
  398. * Report broken connection if no modem callback in progress
  399. */
  400. if ( !pTd->fCallbackInProgress ) {
  401. Command.Header.Command = ICA_COMMAND_BROKEN_CONNECTION;
  402. //
  403. // If it's not an unexpected disconnection then set the reason
  404. // to disconnect. This prevents problems where termsrv resets the
  405. // session if it receives the wrong type of notification.
  406. //
  407. if (pTd->UserBrokenReason == TD_USER_BROKENREASON_UNEXPECTED) {
  408. Command.BrokenConnection.Reason = Broken_Unexpected;
  409. //
  410. // We don't know better so pick server as the source
  411. //
  412. Command.BrokenConnection.Source = BrokenSource_Server;
  413. }
  414. else
  415. {
  416. Command.BrokenConnection.Reason = Broken_Disconnect;
  417. Command.BrokenConnection.Source = BrokenSource_User;
  418. }
  419. (void) IcaChannelInput( pTd->pContext,
  420. Channel_Command,
  421. 0,
  422. NULL,
  423. (PCHAR) &Command,
  424. sizeof(Command) );
  425. }
  426. TRACE(( pTd->pContext, TC_TD, TT_API2, "TdInputThread (exit), Status=0x%x\n", Status ));
  427. TRACE0(("TdInputThread (exit), Status=0x%x, Context 0x%x\n", Status, pTd->pAfd ));
  428. return( Status );
  429. }
  430. /*******************************************************************************
  431. *
  432. * _TdInBufAlloc
  433. *
  434. * Routine to allocate an INBUF and related objects.
  435. *
  436. * ENTRY:
  437. * pTd (input)
  438. * Pointer to TD data structure
  439. *
  440. * EXIT:
  441. * STATUS_SUCCESS - no error
  442. *
  443. ******************************************************************************/
  444. NTSTATUS
  445. _TdInBufAlloc(
  446. PTD pTd,
  447. PINBUF *ppInBuf
  448. )
  449. {
  450. ULONG InBufLength;
  451. ULONG irpSize;
  452. ULONG mdlSize;
  453. ULONG AllocationSize;
  454. KIRQL oldIrql;
  455. PINBUF pInBuf;
  456. NTSTATUS Status;
  457. #define INBUF_STACK_SIZE 4
  458. /*
  459. * Determine size of input buffer
  460. */
  461. InBufLength = pTd->OutBufLength + pTd->InBufHeader;
  462. /*
  463. * Determine the sizes of the various components of an INBUF.
  464. * Note that these are all worst-case calculations--
  465. * actual size of the MDL may be smaller.
  466. */
  467. irpSize = IoSizeOfIrp( INBUF_STACK_SIZE ) + 8;
  468. mdlSize = (ULONG)MmSizeOfMdl( (PVOID)(PAGE_SIZE-1), InBufLength );
  469. /*
  470. * Add up the component sizes of an INBUF to determine
  471. * the total size that is needed to allocate.
  472. */
  473. AllocationSize = (((sizeof(INBUF) + InBufLength +
  474. irpSize + mdlSize) + 3) & ~3);
  475. Status = MemoryAllocate( AllocationSize, &pInBuf );
  476. if ( !NT_SUCCESS( Status ) )
  477. return( STATUS_NO_MEMORY );
  478. /*
  479. * Initialize the IRP pointer and the IRP itself.
  480. */
  481. if ( irpSize ) {
  482. pInBuf->pIrp = (PIRP)(( ((ULONG_PTR)(pInBuf + 1)) + 7) & ~7);
  483. IoInitializeIrp( pInBuf->pIrp, (USHORT)irpSize, INBUF_STACK_SIZE );
  484. }
  485. /*
  486. * Set up the MDL pointer but don't build it yet.
  487. * It will be built by the TD write code if needed.
  488. */
  489. if ( mdlSize ) {
  490. pInBuf->pMdl = (PMDL)((PCHAR)pInBuf->pIrp + irpSize);
  491. }
  492. /*
  493. * Set up the address buffer pointer.
  494. */
  495. pInBuf->pBuffer = (PUCHAR)pInBuf + sizeof(INBUF) + irpSize + mdlSize;
  496. /*
  497. * Initialize the rest of InBuf
  498. */
  499. InitializeListHead( &pInBuf->Links );
  500. pInBuf->MaxByteCount = InBufLength;
  501. pInBuf->ByteCount = 0;
  502. pInBuf->pPrivate = pTd;
  503. /*
  504. * Return buffer to caller
  505. */
  506. #if DBG
  507. DbgPrint( "TdInBufAlloc: pInBuf=0x%x\n", pInBuf );
  508. #endif // DBG
  509. *ppInBuf = pInBuf;
  510. return( STATUS_SUCCESS );
  511. }
  512. /*******************************************************************************
  513. *
  514. * _TdInBufFree
  515. *
  516. * Routine to free an INBUF and related objects.
  517. *
  518. * ENTRY:
  519. * pTd (input)
  520. * Pointer to TD data structure
  521. *
  522. * EXIT:
  523. * STATUS_SUCCESS - no error
  524. *
  525. ******************************************************************************/
  526. VOID
  527. _TdInBufFree(
  528. PTD pTd,
  529. PINBUF pInBuf
  530. )
  531. {
  532. MemoryFree( pInBuf );
  533. }
  534. /*******************************************************************************
  535. *
  536. * _TdInitializeRead
  537. *
  538. * Routine to allocate and initialize the input IRP and related objects.
  539. *
  540. * ENTRY:
  541. * pTd (input)
  542. * Pointer to TD data structure
  543. *
  544. * EXIT:
  545. * STATUS_SUCCESS - no error
  546. *
  547. ******************************************************************************/
  548. NTSTATUS
  549. _TdInitializeRead(
  550. PTD pTd,
  551. PINBUF pInBuf
  552. )
  553. {
  554. PIRP irp = pInBuf->pIrp;
  555. PIO_STACK_LOCATION irpSp;
  556. NTSTATUS Status;
  557. /*
  558. * Check if driver is being closed or endpoint has been closed
  559. */
  560. if ( pTd->fClosing || pTd->pDeviceObject == NULL ) {
  561. TRACE(( pTd->pContext, TC_TD, TT_API2, "_TdInitializeRead: closing\n" ));
  562. return( STATUS_CTX_CLOSE_PENDING );
  563. }
  564. /*
  565. * Set current thread for IoSetHardErrorOrVerifyDevice.
  566. */
  567. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  568. /*
  569. * Get a pointer to the stack location of the first driver which will be
  570. * invoked. This is where the function codes and the parameters are set.
  571. */
  572. irpSp = IoGetNextIrpStackLocation( irp );
  573. /*
  574. * Set the file/device objects and anything not specific to
  575. * the TD. and read parameters.
  576. */
  577. irpSp->FileObject = pTd->pFileObject;
  578. irpSp->DeviceObject = pTd->pDeviceObject;
  579. irp->MdlAddress = NULL;
  580. irp->Flags = IRP_READ_OPERATION;
  581. /*
  582. * Register the I/O completion routine
  583. */
  584. if ( pTd->pSelfDeviceObject ) {
  585. IoSetCompletionRoutineEx( pTd->pSelfDeviceObject, irp, _TdReadCompleteRoutine, pInBuf,
  586. TRUE, TRUE, TRUE );
  587. } else {
  588. IoSetCompletionRoutine( irp, _TdReadCompleteRoutine, pInBuf,
  589. TRUE, TRUE, TRUE );
  590. }
  591. return( STATUS_SUCCESS );
  592. }
  593. /*******************************************************************************
  594. *
  595. * _TdReadCompleteRoutine
  596. *
  597. * This routine is called at DPC level by the lower level device
  598. * driver when an input IRP is completed.
  599. *
  600. * ENTRY:
  601. * DeviceObject (input)
  602. * not used
  603. * pIrp (input)
  604. * pointer to IRP that is complete
  605. * Context (input)
  606. * Context pointer setup when IRP was initialized.
  607. * This is a pointer to the corresponding INBUF.
  608. *
  609. * EXIT:
  610. * STATUS_SUCCESS - no error
  611. *
  612. ******************************************************************************/
  613. NTSTATUS
  614. _TdReadCompleteRoutine(
  615. IN PDEVICE_OBJECT DeviceObject,
  616. IN PIRP Irp,
  617. IN PVOID Context
  618. )
  619. {
  620. KIRQL oldIrql;
  621. PINBUF pInBuf = (PINBUF)Context;
  622. PTD pTd = (PTD)pInBuf->pPrivate;
  623. /*
  624. * Unlink inbuf from busy list and place on completed list
  625. */
  626. ExAcquireSpinLock( &pTd->InBufListLock, &oldIrql );
  627. if ( pInBuf->Links.Flink )
  628. RemoveEntryList( &pInBuf->Links );
  629. InsertTailList( &pTd->InBufDoneHead, &pInBuf->Links );
  630. /*
  631. * Check the auxiliary buffer pointer in the packet and if a buffer was
  632. * allocated, deallocate it now. Note that this buffer must be freed
  633. * here since the pointer is overlayed with the APC that will be used
  634. * to get to the requesting thread's context.
  635. */
  636. if (Irp->Tail.Overlay.AuxiliaryBuffer) {
  637. IcaStackFreePool( Irp->Tail.Overlay.AuxiliaryBuffer );
  638. Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  639. }
  640. //
  641. // Check to see whether any pages need to be unlocked.
  642. //
  643. if (Irp->MdlAddress != NULL) {
  644. PMDL mdl, thisMdl;
  645. //
  646. // Unlock any pages that may be described by MDLs.
  647. //
  648. mdl = Irp->MdlAddress;
  649. while (mdl != NULL) {
  650. thisMdl = mdl;
  651. mdl = mdl->Next;
  652. if (thisMdl == pInBuf->pMdl)
  653. continue;
  654. MmUnlockPages( thisMdl );
  655. IoFreeMdl( thisMdl );
  656. }
  657. }
  658. /*
  659. * Indicate an INBUF was completed
  660. */
  661. KeSetEvent( &pTd->InputEvent, 1, FALSE );
  662. // WARNING!: At this point, we may context switch back to the input thread
  663. // and unload the darn driver!!! This has been temporarily hacked
  664. // for TDPipe by remoing the unload entry point ;-(
  665. ExReleaseSpinLock( &pTd->InBufListLock, oldIrql );
  666. /*
  667. * We return STATUS_MORE_PROCESS_REQUIRED so that no further
  668. * processing for this IRP is done by the I/O completion routine.
  669. */
  670. return( STATUS_MORE_PROCESSING_REQUIRED );
  671. }
  672. /*******************************************************************************
  673. *
  674. * _TdReadComplete
  675. *
  676. * This routine is called at program level after an input IRP
  677. * has been completed.
  678. *
  679. * ENTRY:
  680. * pTd (input)
  681. * Pointer to TD data structure
  682. *
  683. * EXIT:
  684. * STATUS_SUCCESS - no error
  685. *
  686. ******************************************************************************/
  687. NTSTATUS
  688. _TdReadComplete(
  689. IN PTD pTd,
  690. IN PINBUF pInBuf
  691. )
  692. {
  693. PIRP irp = pInBuf->pIrp;
  694. /*
  695. * Handle the buffered I/O case
  696. */
  697. if (irp->Flags & IRP_BUFFERED_IO) {
  698. //
  699. // Copy the data if this was an input operation. Note that no copy
  700. // is performed if the status indicates that a verify operation is
  701. // required, or if the final status was an error-level severity.
  702. //
  703. if (irp->Flags & IRP_INPUT_OPERATION &&
  704. irp->IoStatus.Status != STATUS_VERIFY_REQUIRED &&
  705. !NT_ERROR( irp->IoStatus.Status )) {
  706. //
  707. // Copy the information from the system buffer to the caller's
  708. // buffer. This is done with an exception handler in case
  709. // the operation fails because the caller's address space
  710. // has gone away, or it's protection has been changed while
  711. // the service was executing.
  712. //
  713. try {
  714. RtlCopyMemory( irp->UserBuffer,
  715. irp->AssociatedIrp.SystemBuffer,
  716. irp->IoStatus.Information );
  717. } except(EXCEPTION_EXECUTE_HANDLER) {
  718. //
  719. // An exception occurred while attempting to copy the
  720. // system buffer contents to the caller's buffer. Set
  721. // a new I/O completion status.
  722. //
  723. irp->IoStatus.Status = GetExceptionCode();
  724. }
  725. }
  726. //
  727. // Free the buffer if needed.
  728. //
  729. if (irp->Flags & IRP_DEALLOCATE_BUFFER) {
  730. IcaStackFreePool( irp->AssociatedIrp.SystemBuffer );
  731. }
  732. }
  733. return( STATUS_SUCCESS );
  734. }