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

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