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.

836 lines
25 KiB

  1. /***************************************************************************
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. READ.C
  5. Abstract:
  6. Routines that perform read functionality
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13. PURPOSE.
  14. Copyright (c) 1998 Microsoft Corporation. All Rights Reserved.
  15. Revision History:
  16. 9/25/98 : created
  17. Authors:
  18. Louis J. Giliberto, Jr.
  19. ****************************************************************************/
  20. #include <wdm.h>
  21. #include <ntddser.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <usb.h>
  25. #include <usbdrivr.h>
  26. #include <usbdlib.h>
  27. #include <usbcomm.h>
  28. #ifdef WMI_SUPPORT
  29. #include <wmilib.h>
  30. #include <wmidata.h>
  31. #include <wmistr.h>
  32. #endif
  33. #include "usbser.h"
  34. #include "utils.h"
  35. #include "debugwdm.h"
  36. //
  37. // PAGEUSBS is keyed off of UsbSer_Read, so UsbSer_Read must
  38. // remain in PAGEUSBS for things to work properly
  39. //
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGEUSBS, UsbSerCancelCurrentRead)
  42. #pragma alloc_text(PAGEUSBS, UsbSer_Read)
  43. #pragma alloc_text(PAGEUSBS, UsbSerStartRead)
  44. #pragma alloc_text(PAGEUSBS, UsbSerGrabReadFromRx)
  45. #pragma alloc_text(PAGEUSBS, UsbSerReadTimeout)
  46. #pragma alloc_text(PAGEUSBS, UsbSerIntervalReadTimeout)
  47. #endif // ALLOC_PRAGMA
  48. /************************************************************************/
  49. /* UsbSer_Read */
  50. /************************************************************************/
  51. /* */
  52. /* Routine Description: */
  53. /* */
  54. /* Process the IRPs sent to this device for Read calls */
  55. /* */
  56. /* Arguments: */
  57. /* */
  58. /* DeviceObject - pointer to a device object */
  59. /* Irp - pointer to an I/O Request Packet */
  60. /* */
  61. /* Return Value: */
  62. /* */
  63. /* NTSTATUS */
  64. /* */
  65. /************************************************************************/
  66. NTSTATUS
  67. UsbSer_Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  68. {
  69. NTSTATUS NtStatus = STATUS_SUCCESS;
  70. PIO_STACK_LOCATION IrpStack;
  71. PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
  72. USBSER_LOCKED_PAGED_CODE();
  73. DEBUG_LOG_PATH("enter UsbSer_Read");
  74. UsbSerSerialDump(USBSERTRACERD, (">UsbSer_Read(%08X)\n", Irp));
  75. // set return values to something known
  76. Irp->IoStatus.Information = 0;
  77. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  78. DEBUG_TRACE2(("Read (%08X)\n", IrpStack->Parameters.Read.Length));
  79. UsbSerSerialDump(USBSERTRACE, ("UsbSer_Read Irp: %08X (%08X)\n", Irp,
  80. IrpStack->Parameters.Read.Length));
  81. // make entry in IRP history table
  82. DEBUG_LOG_IRP_HIST(DeviceObject, Irp, IrpStack->MajorFunction,
  83. Irp->AssociatedIrp.SystemBuffer,
  84. IrpStack->Parameters.Read.Length);
  85. if (IrpStack->Parameters.Read.Length != 0) {
  86. NtStatus = UsbSerStartOrQueue(DeviceExtension, Irp,
  87. &DeviceExtension->ReadQueue,
  88. &DeviceExtension->CurrentReadIrp,
  89. UsbSerStartRead);
  90. } else {
  91. Irp->IoStatus.Status = NtStatus = STATUS_SUCCESS;
  92. Irp->IoStatus.Information = 0;
  93. CompleteIO(DeviceObject, Irp, IrpStack->MajorFunction,
  94. Irp->AssociatedIrp.SystemBuffer,
  95. Irp->IoStatus.Information);
  96. }
  97. // log an error if we got one
  98. DEBUG_LOG_ERROR(NtStatus);
  99. DEBUG_LOG_PATH("exit UsbSer_Read");
  100. DEBUG_TRACE3(("status (%08X)\n", NtStatus));
  101. UsbSerSerialDump(USBSERTRACERD, ("<UsbSer_Read %08X\n", NtStatus));
  102. return NtStatus;
  103. } // UsbSer_Read
  104. NTSTATUS
  105. UsbSerStartRead(IN PDEVICE_EXTENSION PDevExt)
  106. /*++
  107. Routine Description:
  108. This routine processes the active read request by initializing any timers,
  109. doing the initial submission to the read state machine, etc.
  110. Arguments:
  111. PDevExt - Pointer to the device extension for the device to start a read on
  112. Return Value:
  113. NTSTATUS
  114. --*/
  115. {
  116. NTSTATUS firstStatus = STATUS_SUCCESS;
  117. BOOLEAN setFirstStatus = FALSE;
  118. ULONG charsRead;
  119. KIRQL oldIrql;
  120. KIRQL controlIrql;
  121. PIRP newIrp;
  122. PIRP pReadIrp;
  123. ULONG readLen;
  124. ULONG multiplierVal;
  125. ULONG constantVal;
  126. BOOLEAN useTotalTimer;
  127. BOOLEAN returnWithWhatsPresent;
  128. BOOLEAN os2ssreturn;
  129. BOOLEAN crunchDownToOne;
  130. BOOLEAN useIntervalTimer;
  131. SERIAL_TIMEOUTS timeoutsForIrp;
  132. LARGE_INTEGER totalTime;
  133. USBSER_ALWAYS_LOCKED_CODE();
  134. DEBUG_LOG_PATH("Enter UsbSerStartRead");
  135. UsbSerSerialDump(USBSERTRACERD, (">UsbSerStartRead\n"));
  136. do {
  137. pReadIrp = PDevExt->CurrentReadIrp;
  138. readLen = IoGetCurrentIrpStackLocation(pReadIrp)->Parameters.Read.Length;
  139. PDevExt->NumberNeededForRead = readLen;
  140. DEBUG_TRACE3(("Start Reading %08X\n", PDevExt->NumberNeededForRead));
  141. useTotalTimer = FALSE;
  142. returnWithWhatsPresent = FALSE;
  143. os2ssreturn = FALSE;
  144. crunchDownToOne = FALSE;
  145. useIntervalTimer = FALSE;
  146. //
  147. // Always initialize the timer objects so that the
  148. // completion code can tell when it attempts to
  149. // cancel the timers whether the timers had ever
  150. // been Set.
  151. //
  152. ACQUIRE_SPINLOCK(PDevExt, &PDevExt->ControlLock, &controlIrql);
  153. timeoutsForIrp = PDevExt->Timeouts;
  154. PDevExt->CountOnLastRead = 0;
  155. RELEASE_SPINLOCK(PDevExt, &PDevExt->ControlLock, controlIrql);
  156. //
  157. // Calculate the interval timeout for the read
  158. //
  159. if (timeoutsForIrp.ReadIntervalTimeout
  160. && (timeoutsForIrp.ReadIntervalTimeout != MAXULONG)) {
  161. useIntervalTimer = TRUE;
  162. PDevExt->IntervalTime.QuadPart
  163. = UInt32x32To64(timeoutsForIrp.ReadIntervalTimeout, 10000);
  164. if (PDevExt->IntervalTime.QuadPart
  165. >= PDevExt->CutOverAmount.QuadPart) {
  166. PDevExt->IntervalTimeToUse = &PDevExt->LongIntervalAmount;
  167. } else {
  168. PDevExt->IntervalTimeToUse = &PDevExt->ShortIntervalAmount;
  169. }
  170. }
  171. if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {
  172. //
  173. // We need to do special return quickly stuff here.
  174. //
  175. // 1) If both constant and multiplier are
  176. // 0 then we return immediately with whatever
  177. // we've got, even if it was zero.
  178. //
  179. // 2) If constant and multiplier are not MAXULONG
  180. // then return immediately if any characters
  181. // are present, but if nothing is there, then
  182. // use the timeouts as specified.
  183. //
  184. // 3) If multiplier is MAXULONG then do as in
  185. // "2" but return when the first character
  186. // arrives.
  187. //
  188. if (!timeoutsForIrp.ReadTotalTimeoutConstant
  189. && !timeoutsForIrp.ReadTotalTimeoutMultiplier) {
  190. returnWithWhatsPresent = TRUE;
  191. } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
  192. && (timeoutsForIrp.ReadTotalTimeoutMultiplier
  193. != MAXULONG)) {
  194. useTotalTimer = TRUE;
  195. os2ssreturn = TRUE;
  196. multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
  197. constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
  198. } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
  199. && (timeoutsForIrp.ReadTotalTimeoutMultiplier
  200. == MAXULONG)) {
  201. useTotalTimer = TRUE;
  202. os2ssreturn = TRUE;
  203. crunchDownToOne = TRUE;
  204. multiplierVal = 0;
  205. constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
  206. }
  207. } else {
  208. //
  209. // If both the multiplier and the constant are
  210. // zero then don't do any total timeout processing.
  211. //
  212. if (timeoutsForIrp.ReadTotalTimeoutMultiplier
  213. || timeoutsForIrp.ReadTotalTimeoutConstant) {
  214. //
  215. // We have some timer values to calculate
  216. //
  217. useTotalTimer = TRUE;
  218. multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
  219. constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
  220. }
  221. }
  222. if (useTotalTimer) {
  223. totalTime.QuadPart
  224. = ((LONGLONG)(UInt32x32To64(PDevExt->NumberNeededForRead,
  225. multiplierVal) + constantVal)) * -10000;
  226. }
  227. if (PDevExt->CharsInReadBuff) {
  228. charsRead
  229. = GetData(PDevExt, ((PUCHAR)(pReadIrp->AssociatedIrp.SystemBuffer))
  230. + readLen - PDevExt->NumberNeededForRead,
  231. PDevExt->NumberNeededForRead,
  232. &pReadIrp->IoStatus.Information);
  233. } else {
  234. charsRead = 0;
  235. }
  236. //
  237. // See if this read is complete
  238. //
  239. if (returnWithWhatsPresent || (PDevExt->NumberNeededForRead == 0)
  240. || (os2ssreturn && pReadIrp->IoStatus.Information)) {
  241. #if DBG
  242. if (UsbSerSerialDebugLevel & USBSERDUMPRD) {
  243. ULONG i;
  244. ULONG count;
  245. if (PDevExt->CurrentReadIrp->IoStatus.Status == STATUS_SUCCESS) {
  246. count = (ULONG)PDevExt->CurrentReadIrp->IoStatus.Information;
  247. } else {
  248. count = 0;
  249. }
  250. DbgPrint("RD3: A(%08X) G(%08X) I(%08X)\n",
  251. IoGetCurrentIrpStackLocation(PDevExt->CurrentReadIrp)
  252. ->Parameters.Read.Length, count, PDevExt->CurrentReadIrp);
  253. for (i = 0; i < count; i++) {
  254. DbgPrint("%02x ", *(((PUCHAR)PDevExt->CurrentReadIrp
  255. ->AssociatedIrp.SystemBuffer) + i) & 0xFF);
  256. }
  257. if (i == 0) {
  258. DbgPrint("NULL (%08X)\n", PDevExt->CurrentReadIrp
  259. ->IoStatus.Status);
  260. }
  261. DbgPrint("\n\n");
  262. }
  263. #endif
  264. //
  265. // Update the amount of chars left in the ring buffer
  266. //
  267. pReadIrp->IoStatus.Status = STATUS_SUCCESS;
  268. if (!setFirstStatus) {
  269. firstStatus = STATUS_SUCCESS;
  270. setFirstStatus = TRUE;
  271. }
  272. } else {
  273. //
  274. // The irp may be given to the buffering routine
  275. //
  276. USBSER_INIT_REFERENCE(pReadIrp);
  277. ACQUIRE_CANCEL_SPINLOCK(PDevExt, &oldIrql);
  278. //
  279. // Check to see if it needs to be cancelled
  280. //
  281. if (pReadIrp->Cancel) {
  282. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  283. pReadIrp->IoStatus.Status = STATUS_CANCELLED;
  284. pReadIrp->IoStatus.Information = 0;
  285. if (!setFirstStatus) {
  286. setFirstStatus = TRUE;
  287. firstStatus = STATUS_CANCELLED;
  288. }
  289. UsbSerGetNextIrp(&PDevExt->CurrentReadIrp, &PDevExt->ReadQueue,
  290. &newIrp, TRUE, PDevExt);
  291. continue;
  292. } else {
  293. //
  294. // If we are supposed to crunch the read down to
  295. // one character, then update the read length
  296. // in the irp and truncate the number needed for
  297. // read down to one. Note that if we are doing
  298. // this crunching, then the information must be
  299. // zero (or we would have completed above) and
  300. // the number needed for the read must still be
  301. /// equal to the read length.
  302. //
  303. if (crunchDownToOne) {
  304. PDevExt->NumberNeededForRead = 1;
  305. IoGetCurrentIrpStackLocation(pReadIrp)->Parameters.Read.Length
  306. = 1;
  307. }
  308. USBSER_SET_REFERENCE(pReadIrp, USBSER_REF_RXBUFFER);
  309. USBSER_SET_REFERENCE(pReadIrp, USBSER_REF_CANCEL);
  310. if (useTotalTimer) {
  311. USBSER_SET_REFERENCE(pReadIrp, USBSER_REF_TOTAL_TIMER);
  312. KeSetTimer(&PDevExt->ReadRequestTotalTimer, totalTime,
  313. &PDevExt->TotalReadTimeoutDpc);
  314. }
  315. if (useIntervalTimer) {
  316. USBSER_SET_REFERENCE(pReadIrp, USBSER_REF_INT_TIMER);
  317. KeQuerySystemTime(&PDevExt->LastReadTime);
  318. KeSetTimer(&PDevExt->ReadRequestIntervalTimer,
  319. *PDevExt->IntervalTimeToUse,
  320. &PDevExt->IntervalReadTimeoutDpc);
  321. }
  322. //
  323. // Mark IRP as cancellable
  324. //
  325. IoSetCancelRoutine(pReadIrp, UsbSerCancelCurrentRead);
  326. IoMarkIrpPending(pReadIrp);
  327. RELEASE_CANCEL_SPINLOCK(PDevExt, oldIrql);
  328. if (!setFirstStatus) {
  329. firstStatus = STATUS_PENDING;
  330. }
  331. }
  332. DEBUG_LOG_PATH("Exit UsbSerStartRead (1)\n");
  333. UsbSerSerialDump(USBSERTRACERD, ("<UsbSerStartRead (1) %08X\n",
  334. firstStatus));
  335. return firstStatus;
  336. }
  337. UsbSerGetNextIrp(&PDevExt->CurrentReadIrp, &PDevExt->ReadQueue,
  338. &newIrp, TRUE, PDevExt);
  339. } while (newIrp != NULL);
  340. DEBUG_LOG_PATH("Exit UsbSerStartRead (2)\n");
  341. UsbSerSerialDump(USBSERTRACERD, ("<UsbSerStartRead (2) %08X\n",
  342. firstStatus));
  343. return firstStatus;
  344. }
  345. BOOLEAN
  346. UsbSerGrabReadFromRx(IN PVOID Context)
  347. /*++
  348. Routine Description:
  349. This routine is used to grab (if possible) the irp from the
  350. read callback mechanism. If it finds that the rx still owns the irp it
  351. grabs the irp away and also decrements the reference count on the irp since
  352. it no longer belongs to the rx routine.
  353. NOTE: This routine assumes that it is called with the cancel spin
  354. lock and/or control lock held.
  355. Arguments:
  356. Context - Really a pointer to the device extension.
  357. Return Value:
  358. Always false.
  359. --*/
  360. {
  361. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)Context;
  362. USBSER_ALWAYS_LOCKED_CODE();
  363. UsbSerSerialDump(USBSERTRACERD, ("Enter UsbSerGrabReadFromRx\n"));
  364. USBSER_CLEAR_REFERENCE(pDevExt->CurrentReadIrp, USBSER_REF_RXBUFFER);
  365. UsbSerSerialDump(USBSERTRACERD, ("Exit UsbSerGrabReadFromRx\n"));
  366. return FALSE;
  367. }
  368. VOID
  369. UsbSerCancelCurrentRead(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  370. /*++
  371. Routine Description:
  372. This routine is used to cancel the current read.
  373. Arguments:
  374. PDevObj - Pointer to the device object for this device
  375. PIrp - Pointer to the IRP to be canceled.
  376. Return Value:
  377. None.
  378. --*/
  379. {
  380. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  381. USBSER_ALWAYS_LOCKED_CODE();
  382. UsbSerSerialDump(USBSERTRACEOTH, (">UsbSerCancelCurrentRead(%08X)\n",
  383. PIrp));
  384. //
  385. // We set this to indicate to the interval timer
  386. // that the read has encountered a cancel.
  387. //
  388. // Recall that the interval timer dpc can be lurking in some
  389. // DPC queue.
  390. //
  391. pDevExt->CountOnLastRead = SERIAL_COMPLETE_READ_CANCEL;
  392. //
  393. // HACKHACK
  394. //
  395. UsbSerGrabReadFromRx(pDevExt);
  396. UsbSerTryToCompleteCurrent(pDevExt, PIrp->CancelIrql, STATUS_CANCELLED,
  397. &pDevExt->CurrentReadIrp, &pDevExt->ReadQueue,
  398. &pDevExt->ReadRequestIntervalTimer,
  399. &pDevExt->ReadRequestTotalTimer,
  400. UsbSerStartRead, UsbSerGetNextIrp,
  401. USBSER_REF_CANCEL, TRUE);
  402. UsbSerSerialDump(USBSERTRACEOTH, ("<UsbSerCancelCurrentRead\n"));
  403. }
  404. VOID
  405. UsbSerReadTimeout(IN PKDPC PDpc, IN PVOID DeferredContext,
  406. IN PVOID SystemContext1, IN PVOID SystemContext2)
  407. /*++
  408. Routine Description:
  409. This routine is used to complete a read because its total
  410. timer has expired.
  411. Arguments:
  412. PDpc - Not Used.
  413. DeferredContext - Really points to the device extension.
  414. SystemContext1 - Not Used.
  415. SystemContext2 - Not Used.
  416. Return Value:
  417. None.
  418. --*/
  419. {
  420. PDEVICE_EXTENSION pDevExt = DeferredContext;
  421. KIRQL oldIrql;
  422. UNREFERENCED_PARAMETER(SystemContext1);
  423. UNREFERENCED_PARAMETER(SystemContext2);
  424. USBSER_ALWAYS_LOCKED_CODE();
  425. UsbSerSerialDump(USBSERTRACETM, (">UsbSerReadTimeout\n"));
  426. ACQUIRE_CANCEL_SPINLOCK(pDevExt, &oldIrql);
  427. //
  428. // We set this to indicate to the interval timer
  429. // that the read has completed due to total timeout.
  430. //
  431. // Recall that the interval timer dpc can be lurking in some
  432. // DPC queue.
  433. //
  434. pDevExt->CountOnLastRead = SERIAL_COMPLETE_READ_TOTAL;
  435. //
  436. // HACKHACK
  437. //
  438. UsbSerGrabReadFromRx(pDevExt);
  439. UsbSerTryToCompleteCurrent(pDevExt, oldIrql, STATUS_TIMEOUT,
  440. &pDevExt->CurrentReadIrp, &pDevExt->ReadQueue,
  441. &pDevExt->ReadRequestIntervalTimer,
  442. &pDevExt->ReadRequestTotalTimer, UsbSerStartRead,
  443. UsbSerGetNextIrp, USBSER_REF_TOTAL_TIMER, TRUE);
  444. UsbSerSerialDump(USBSERTRACETM, ("<UsbSerReadTimeout\n"));
  445. }
  446. VOID
  447. UsbSerIntervalReadTimeout(IN PKDPC PDpc, IN PVOID DeferredContext,
  448. IN PVOID SystemContext1, IN PVOID SystemContext2)
  449. /*++
  450. Routine Description:
  451. This routine is used timeout the request if the time between
  452. characters exceed the interval time. A global is kept in
  453. the device extension that records the count of characters read
  454. the last the last time this routine was invoked (This dpc
  455. will resubmit the timer if the count has changed). If the
  456. count has not changed then this routine will attempt to complete
  457. the irp. Note the special case of the last count being zero.
  458. The timer isn't really in effect until the first character is
  459. read.
  460. Arguments:
  461. PDpc - Not Used.
  462. DeferredContext - Really points to the device extension.
  463. SystemContext1 - Not Used.
  464. SystemContext2 - Not Used.
  465. Return Value:
  466. None.
  467. --*/
  468. {
  469. PDEVICE_EXTENSION pDevExt = DeferredContext;
  470. KIRQL oldIrql;
  471. KIRQL oldControlIrql;
  472. UNREFERENCED_PARAMETER(SystemContext1);
  473. UNREFERENCED_PARAMETER(SystemContext2);
  474. USBSER_ALWAYS_LOCKED_CODE();
  475. UsbSerSerialDump(USBSERTRACETM, (">UsbSerIntervalReadTimeout "));
  476. ACQUIRE_CANCEL_SPINLOCK(pDevExt, &oldIrql);
  477. if (pDevExt->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) {
  478. UsbSerSerialDump(USBSERTRACETM, ("SERIAL_COMPLETE_READ_TOTAL\n"));
  479. //
  480. // This value is only set by the total
  481. // timer to indicate that it has fired.
  482. // If so, then we should simply try to complete.
  483. //
  484. //
  485. // HACKHACK
  486. //
  487. ACQUIRE_SPINLOCK(pDevExt, &pDevExt->ControlLock, &oldControlIrql);
  488. UsbSerGrabReadFromRx(pDevExt);
  489. pDevExt->CountOnLastRead = 0;
  490. RELEASE_SPINLOCK(pDevExt, &pDevExt->ControlLock, oldControlIrql);
  491. UsbSerTryToCompleteCurrent(pDevExt, oldIrql, STATUS_TIMEOUT,
  492. &pDevExt->CurrentReadIrp, &pDevExt->ReadQueue,
  493. &pDevExt->ReadRequestIntervalTimer,
  494. &pDevExt->ReadRequestTotalTimer,
  495. UsbSerStartRead, UsbSerGetNextIrp,
  496. USBSER_REF_INT_TIMER, TRUE);
  497. } else if (pDevExt->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) {
  498. UsbSerSerialDump(USBSERTRACETM, ("SERIAL_COMPLETE_READ_COMPLETE\n"));
  499. //
  500. // This value is only set by the regular
  501. // completion routine.
  502. //
  503. // If so, then we should simply try to complete.
  504. //
  505. //
  506. // HACKHACK
  507. //
  508. ACQUIRE_SPINLOCK(pDevExt, &pDevExt->ControlLock, &oldControlIrql);
  509. UsbSerGrabReadFromRx(pDevExt);
  510. pDevExt->CountOnLastRead = 0;
  511. RELEASE_SPINLOCK(pDevExt, &pDevExt->ControlLock, oldControlIrql);
  512. UsbSerTryToCompleteCurrent(pDevExt, oldIrql, STATUS_SUCCESS,
  513. &pDevExt->CurrentReadIrp, &pDevExt->ReadQueue,
  514. &pDevExt->ReadRequestIntervalTimer,
  515. &pDevExt->ReadRequestTotalTimer,
  516. UsbSerStartRead, UsbSerGetNextIrp,
  517. USBSER_REF_INT_TIMER, TRUE);
  518. } else if (pDevExt->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) {
  519. UsbSerSerialDump(USBSERTRACETM, ("SERIAL_COMPLETE_READ_CANCEL\n"));
  520. //
  521. // This value is only set by the cancel
  522. // read routine.
  523. //
  524. // If so, then we should simply try to complete.
  525. //
  526. //
  527. // HACKHACK
  528. //
  529. ACQUIRE_SPINLOCK(pDevExt, &pDevExt->ControlLock, &oldControlIrql);
  530. UsbSerGrabReadFromRx(pDevExt);
  531. pDevExt->CountOnLastRead = 0;
  532. RELEASE_SPINLOCK(pDevExt, &pDevExt->ControlLock, oldControlIrql);
  533. UsbSerTryToCompleteCurrent(pDevExt, oldIrql, STATUS_CANCELLED,
  534. &pDevExt->CurrentReadIrp, &pDevExt->ReadQueue,
  535. &pDevExt->ReadRequestIntervalTimer,
  536. &pDevExt->ReadRequestTotalTimer,
  537. UsbSerStartRead, UsbSerGetNextIrp,
  538. USBSER_REF_INT_TIMER, TRUE);
  539. } else if (pDevExt->CountOnLastRead || pDevExt->ReadByIsr) {
  540. //
  541. // Something has happened since we last came here. We
  542. // check to see if the ISR has read in any more characters.
  543. // If it did then we should update the isr's read count
  544. // and resubmit the timer.
  545. //
  546. if (pDevExt->ReadByIsr) {
  547. UsbSerSerialDump(USBSERTRACETM, ("ReadByIsr\n"));
  548. pDevExt->CountOnLastRead = pDevExt->ReadByIsr;
  549. pDevExt->ReadByIsr = 0;
  550. //
  551. // Save off the "last" time something was read.
  552. // As we come back to this routine we will compare
  553. // the current time to the "last" time. If the
  554. // difference is ever larger then the interval
  555. // requested by the user, then time out the request.
  556. //
  557. KeQuerySystemTime(&pDevExt->LastReadTime);
  558. KeSetTimer(&pDevExt->ReadRequestIntervalTimer,
  559. *pDevExt->IntervalTimeToUse,
  560. &pDevExt->IntervalReadTimeoutDpc);
  561. RELEASE_CANCEL_SPINLOCK(pDevExt, oldIrql);
  562. } else {
  563. //
  564. // Take the difference between the current time
  565. // and the last time we had characters and
  566. // see if it is greater then the interval time.
  567. // if it is, then time out the request. Otherwise
  568. // go away again for a while.
  569. //
  570. //
  571. // No characters read in the interval time. Kill
  572. // this read.
  573. //
  574. LARGE_INTEGER currentTime;
  575. UsbSerSerialDump(USBSERTRACETM, ("TIMEOUT\n"));
  576. KeQuerySystemTime(&currentTime);
  577. if ((currentTime.QuadPart - pDevExt->LastReadTime.QuadPart) >=
  578. pDevExt->IntervalTime.QuadPart) {
  579. pDevExt->CountOnLastRead = pDevExt->ReadByIsr = 0;
  580. //
  581. // HACKHACK
  582. //
  583. ACQUIRE_SPINLOCK(pDevExt, &pDevExt->ControlLock, &oldControlIrql);
  584. UsbSerGrabReadFromRx(pDevExt);
  585. RELEASE_SPINLOCK(pDevExt, &pDevExt->ControlLock, oldControlIrql);
  586. UsbSerTryToCompleteCurrent(pDevExt, oldIrql, STATUS_TIMEOUT,
  587. &pDevExt->CurrentReadIrp,
  588. &pDevExt->ReadQueue,
  589. &pDevExt->ReadRequestIntervalTimer,
  590. &pDevExt->ReadRequestTotalTimer,
  591. UsbSerStartRead, UsbSerGetNextIrp,
  592. USBSER_REF_INT_TIMER, TRUE);
  593. } else {
  594. KeSetTimer(&pDevExt->ReadRequestIntervalTimer,
  595. *pDevExt->IntervalTimeToUse,
  596. &pDevExt->IntervalReadTimeoutDpc);
  597. RELEASE_CANCEL_SPINLOCK(pDevExt, oldIrql);
  598. }
  599. }
  600. } else {
  601. //
  602. // Timer doesn't really start until the first character.
  603. // So we should simply resubmit ourselves.
  604. //
  605. UsbSerSerialDump(USBSERTRACETM, ("-\n"));
  606. KeSetTimer(&pDevExt->ReadRequestIntervalTimer,
  607. *pDevExt->IntervalTimeToUse, &pDevExt->IntervalReadTimeoutDpc);
  608. RELEASE_CANCEL_SPINLOCK(pDevExt, oldIrql);
  609. }
  610. UsbSerSerialDump(USBSERTRACETM, ("<UsbSerIntervalReadTimeout\n"));
  611. }
  612.