|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: read.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to read
12: operations in the serial driver
13:
14: Author:
15:
16: Anthony V. Ercolano 26-Sep-1991
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History :
23:
24: --*/
25:
26: #include <stddef.h>
27: #include "ntddk.h"
28: #include "ntddser.h"
29: #include "serial.h"
30: #include "serialp.h"
31:
32:
33: VOID
34: SerialCancelCurrentRead(
35: PDEVICE_OBJECT DeviceObject,
36: PIRP Irp
37: );
38:
39: BOOLEAN
40: SerialGrabReadFromIsr(
41: IN PVOID Context
42: );
43:
44: BOOLEAN
45: SerialUpdateReadByIsr(
46: IN PVOID Context
47: );
48:
49: ULONG
50: SerialGetCharsFromIntBuffer(
51: PSERIAL_DEVICE_EXTENSION Extension
52: );
53:
54: BOOLEAN
55: SerialUpdateInterruptBuffer(
56: IN PVOID Context
57: );
58:
59: BOOLEAN
60: SerialUpdateAndSwitchToUser(
61: IN PVOID Context
62: );
63:
64: NTSTATUS
65: SerialResizeBuffer(
66: IN PSERIAL_DEVICE_EXTENSION Extension
67: );
68:
69: ULONG
70: SerialMoveToNewIntBuffer(
71: PSERIAL_DEVICE_EXTENSION Extension,
72: PUCHAR NewBuffer
73: );
74:
75: BOOLEAN
76: SerialUpdateAndSwitchToNew(
77: IN PVOID Context
78: );
79:
80:
81: NTSTATUS
82: SerialRead(
83: IN PDEVICE_OBJECT DeviceObject,
84: IN PIRP Irp
85: )
86:
87: /*++
88:
89: Routine Description:
90:
91: This is the dispatch routine for reading. It validates the parameters
92: for the read request and if all is ok then it places the request
93: on the work queue.
94:
95: Arguments:
96:
97: DeviceObject - Pointer to the device object for this device
98:
99: Irp - Pointer to the IRP for the current request
100:
101: Return Value:
102:
103: If the io is zero length then it will return STATUS_SUCCESS,
104: otherwise this routine will return the status returned by
105: the actual start read routine.
106:
107: --*/
108:
109: {
110:
111: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
112:
113: SerialDump(
114: SERIRPPATH,
115: ("SERIAL: Dispatch entry for: %x\n",Irp)
116: );
117: if (SerialCompleteIfError(
118: DeviceObject,
119: Irp
120: ) != STATUS_SUCCESS) {
121:
122: return STATUS_CANCELLED;
123:
124: }
125:
126: Irp->IoStatus.Information = 0L;
127:
128: //
129: // Quick check for a zero length read. If it is zero length
130: // then we are already done!
131: //
132:
133: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length) {
134:
135: //
136: // Well it looks like we actually have to do some
137: // work. Put the read on the queue so that we can
138: // process it when our previous reads are done.
139: //
140:
141: return SerialStartOrQueue(
142: extension,
143: Irp,
144: &extension->ReadQueue,
145: &extension->CurrentReadIrp,
146: SerialStartRead
147: );
148:
149: } else {
150:
151: Irp->IoStatus.Status = STATUS_SUCCESS;
152: SerialDump(
153: SERIRPPATH,
154: ("SERIAL: Complete Irp: %x\n",Irp)
155: );
156: IoCompleteRequest(
157: Irp,
158: 0
159: );
160:
161: return STATUS_SUCCESS;
162:
163: }
164:
165: }
166:
167: NTSTATUS
168: SerialStartRead(
169: IN PSERIAL_DEVICE_EXTENSION Extension
170: )
171:
172: /*++
173:
174: Routine Description:
175:
176: This routine is used to start off any read. It initializes
177: the Iostatus fields of the irp. It will set up any timers
178: that are used to control the read. It will attempt to complete
179: the read from data already in the interrupt buffer. If the
180: read can be completed quickly it will start off another if
181: necessary.
182:
183: Arguments:
184:
185: Extension - Simply a pointer to the serial device extension.
186:
187: Return Value:
188:
189: This routine will return the status of the first read
190: irp. This is useful in that if we have a read that can
191: complete right away (AND there had been nothing in the
192: queue before it) the read could return SUCCESS and the
193: application won't have to do a wait.
194:
195: --*/
196:
197: {
198:
199: SERIAL_UPDATE_CHAR updateChar;
200:
201: PIRP newIrp;
202: KIRQL oldIrql;
203: KIRQL controlIrql;
204:
205: BOOLEAN returnWithWhatsPresent;
206: BOOLEAN os2ssreturn;
207: BOOLEAN crunchDownToOne;
208: BOOLEAN useTotalTimer;
209: BOOLEAN useIntervalTimer;
210:
211: ULONG multiplierVal;
212: ULONG constantVal;
213:
214: LARGE_INTEGER totalTime;
215:
216: SERIAL_TIMEOUTS timeoutsForIrp;
217:
218: BOOLEAN setFirstStatus = FALSE;
219: NTSTATUS firstStatus;
220:
221:
222: updateChar.Extension = Extension;
223:
224: do {
225:
226: //
227: // Check to see if this is a resize request. If it is
228: // then go to a routine that specializes in that.
229: //
230:
231: if (IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
232: ->MajorFunction != IRP_MJ_READ) {
233:
234: NTSTATUS localStatus = SerialResizeBuffer(Extension);
235:
236: if (!setFirstStatus) {
237:
238: firstStatus = localStatus;
239: setFirstStatus = TRUE;
240:
241: }
242:
243: } else {
244:
245: Extension->NumberNeededForRead =
246: IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
247: ->Parameters.Read.Length;
248:
249: //
250: // Calculate the timeout value needed for the
251: // request. Note that the values stored in the
252: // timeout record are in milliseconds.
253: //
254:
255: useTotalTimer = FALSE;
256: returnWithWhatsPresent = FALSE;
257: os2ssreturn = FALSE;
258: crunchDownToOne = FALSE;
259: useIntervalTimer = FALSE;
260:
261:
262: //
263: // Always initialize the timer objects so that the
264: // completion code can tell when it attempts to
265: // cancel the timers whether the timers had ever
266: // been Set.
267: //
268:
269: KeInitializeTimer(&Extension->ReadRequestTotalTimer);
270: KeInitializeTimer(&Extension->ReadRequestIntervalTimer);
271:
272: //
273: // We get the *current* timeout values to use for timing
274: // this read.
275: //
276:
277: KeAcquireSpinLock(
278: &Extension->ControlLock,
279: &controlIrql
280: );
281:
282: timeoutsForIrp = Extension->Timeouts;
283:
284: KeReleaseSpinLock(
285: &Extension->ControlLock,
286: controlIrql
287: );
288:
289: //
290: // Calculate the interval timeout for the read.
291: //
292:
293: if (timeoutsForIrp.ReadIntervalTimeout &&
294: (timeoutsForIrp.ReadIntervalTimeout !=
295: MAXULONG)) {
296:
297: useIntervalTimer = TRUE;
298:
299: Extension->IntervalTime = RtlEnlargedUnsignedMultiply(
300: timeoutsForIrp.ReadIntervalTimeout,
301: 10000
302: );
303:
304:
305: if (RtlLargeIntegerGreaterThanOrEqualTo(
306: Extension->IntervalTime,
307: Extension->CutOverAmount
308: )) {
309:
310: Extension->IntervalTimeToUse =
311: &Extension->LongIntervalAmount;
312:
313: } else {
314:
315: Extension->IntervalTimeToUse =
316: &Extension->ShortIntervalAmount;
317:
318: }
319:
320: }
321:
322: if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {
323:
324: //
325: // We need to do special return quickly stuff here.
326: //
327: // 1) If both constant and multiplier are
328: // 0 then we return immediately with whatever
329: // we've got, even if it was zero.
330: //
331: // 2) If constant and multiplier are not MAXULONG
332: // then return immediately if any characters
333: // are present, but if nothing is there, then
334: // use the timeouts as specified.
335: //
336: // 3) If multiplier is MAXULONG then do as in
337: // "2" but return when the first character
338: // arrives.
339: //
340:
341: if (!timeoutsForIrp.ReadTotalTimeoutConstant &&
342: !timeoutsForIrp.ReadTotalTimeoutMultiplier) {
343:
344: returnWithWhatsPresent = TRUE;
345:
346: } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
347: &&
348: (timeoutsForIrp.ReadTotalTimeoutMultiplier
349: != MAXULONG)) {
350:
351: useTotalTimer = TRUE;
352: os2ssreturn = TRUE;
353: multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
354: constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
355:
356: } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
357: &&
358: (timeoutsForIrp.ReadTotalTimeoutMultiplier
359: == MAXULONG)) {
360:
361: useTotalTimer = TRUE;
362: os2ssreturn = TRUE;
363: crunchDownToOne = TRUE;
364: multiplierVal = 0;
365: constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
366:
367: }
368:
369: } else {
370:
371: //
372: // If both the multiplier and the constant are
373: // zero then don't do any total timeout processing.
374: //
375:
376: if (timeoutsForIrp.ReadTotalTimeoutMultiplier ||
377: timeoutsForIrp.ReadTotalTimeoutConstant) {
378:
379: //
380: // We have some timer values to calculate.
381: //
382:
383: useTotalTimer = TRUE;
384: multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
385: constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
386:
387: }
388:
389: }
390:
391: if (useTotalTimer) {
392:
393: totalTime = RtlEnlargedUnsignedMultiply(
394: Extension->NumberNeededForRead,
395: multiplierVal
396: );
397:
398: totalTime = RtlLargeIntegerAdd(
399: totalTime,
400: RtlConvertUlongToLargeInteger(
401: constantVal
402: )
403: );
404:
405: totalTime = RtlExtendedIntegerMultiply(
406: totalTime,
407: -10000
408: );
409:
410: }
411:
412:
413: //
414: // We do this copy in the hope of getting most (if not
415: // all) of the characters out of the interrupt buffer.
416: //
417: // Note that we need to protect this operation with a
418: // spinlock since we don't want a purge to hose us.
419: //
420:
421: KeAcquireSpinLock(
422: &Extension->ControlLock,
423: &controlIrql
424: );
425:
426: updateChar.CharsCopied = SerialGetCharsFromIntBuffer(Extension);
427:
428: //
429: // See if we have any cause to return immediately.
430: //
431:
432: if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) ||
433: (os2ssreturn &&
434: Extension->CurrentReadIrp->IoStatus.Information)) {
435:
436: //
437: // We got all we needed for this read.
438: // Update the number of characters in the
439: // interrupt read buffer.
440: //
441:
442: KeSynchronizeExecution(
443: Extension->Interrupt,
444: SerialUpdateInterruptBuffer,
445: &updateChar
446: );
447:
448: KeReleaseSpinLock(
449: &Extension->ControlLock,
450: controlIrql
451: );
452:
453: Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
454: if (!setFirstStatus) {
455:
456: firstStatus = STATUS_SUCCESS;
457: setFirstStatus = TRUE;
458:
459: }
460:
461: } else {
462:
463: //
464: // The irp might go under control of the isr. It
465: // won't hurt to initialize the reference count
466: // right now.
467: //
468:
469: SERIAL_INIT_REFERENCE(Extension->CurrentReadIrp);
470:
471: IoAcquireCancelSpinLock(&oldIrql);
472:
473: //
474: // We need to see if this irp should be canceled.
475: //
476:
477: if (Extension->CurrentReadIrp->Cancel) {
478:
479: IoReleaseCancelSpinLock(oldIrql);
480: KeReleaseSpinLock(
481: &Extension->ControlLock,
482: controlIrql
483: );
484: Extension->CurrentReadIrp->IoStatus.Status =
485: STATUS_CANCELLED;
486: Extension->CurrentReadIrp->IoStatus.Information = 0;
487:
488: if (!setFirstStatus) {
489:
490: firstStatus = STATUS_CANCELLED;
491: setFirstStatus = TRUE;
492:
493: }
494:
495: } else {
496:
497: //
498: // If we are supposed to crunch the read down to
499: // one character, then update the read length
500: // in the irp and truncate the number needed for
501: // read down to one. Note that if we are doing
502: // this crunching, then the information must be
503: // zero (or we would have completed above) and
504: // the number needed for the read must still be
505: // equal to the read length.
506: //
507:
508: if (crunchDownToOne) {
509:
510: ASSERT(
511: (!Extension->CurrentReadIrp->IoStatus.Information)
512: &&
513: (Extension->NumberNeededForRead ==
514: IoGetCurrentIrpStackLocation(
515: Extension->CurrentReadIrp
516: )->Parameters.Read.Length)
517: );
518:
519: Extension->NumberNeededForRead = 1;
520: IoGetCurrentIrpStackLocation(
521: Extension->CurrentReadIrp
522: )->Parameters.Read.Length = 1;
523:
524: }
525:
526: //
527: // We still need to get more characters for this read.
528: // synchronize with the isr so that we can update the
529: // number of characters and if necessary it will have the
530: // isr switch to copying into the users buffer.
531: //
532:
533: KeSynchronizeExecution(
534: Extension->Interrupt,
535: SerialUpdateAndSwitchToUser,
536: &updateChar
537: );
538:
539: if (!updateChar.Completed) {
540:
541: //
542: // The irp still isn't complete. The
543: // completion routines will end up reinvoking
544: // this routine. So we simply leave.
545: //
546: // First thought we should start off the total
547: // timer for the read and increment the reference
548: // count that the total timer has on the current
549: // irp. Note that this is safe, because even if
550: // the io has been satisfied by the isr it can't
551: // complete yet because we still own the cancel
552: // spinlock.
553: //
554:
555: if (useTotalTimer) {
556:
557: SERIAL_INC_REFERENCE(Extension->CurrentReadIrp);
558:
559: KeSetTimer(
560: &Extension->ReadRequestTotalTimer,
561: totalTime,
562: &Extension->TotalReadTimeoutDpc
563: );
564:
565: }
566:
567: if (useIntervalTimer) {
568:
569: SERIAL_INC_REFERENCE(Extension->CurrentReadIrp);
570:
571: KeQuerySystemTime(
572: &Extension->LastReadTime
573: );
574: KeSetTimer(
575: &Extension->ReadRequestIntervalTimer,
576: *Extension->IntervalTimeToUse,
577: &Extension->IntervalReadTimeoutDpc
578: );
579:
580: }
581:
582: IoMarkIrpPending(Extension->CurrentReadIrp);
583: IoReleaseCancelSpinLock(oldIrql);
584: KeReleaseSpinLock(
585: &Extension->ControlLock,
586: controlIrql
587: );
588: if (!setFirstStatus) {
589:
590: firstStatus = STATUS_PENDING;
591:
592: }
593: return firstStatus;
594:
595: } else {
596:
597: IoReleaseCancelSpinLock(oldIrql);
598: KeReleaseSpinLock(
599: &Extension->ControlLock,
600: controlIrql
601: );
602: Extension->CurrentReadIrp->IoStatus.Status =
603: STATUS_SUCCESS;
604:
605: if (!setFirstStatus) {
606:
607: firstStatus = STATUS_SUCCESS;
608: setFirstStatus = TRUE;
609:
610: }
611:
612: }
613:
614: }
615:
616: }
617:
618: }
619:
620: //
621: // Well the operation is complete.
622: //
623:
624: SerialGetNextIrp(
625: &Extension->CurrentReadIrp,
626: &Extension->ReadQueue,
627: &newIrp,
628: TRUE
629: );
630:
631: } while (newIrp);
632:
633: return firstStatus;
634:
635: }
636:
637: VOID
638: SerialCompleteRead(
639: IN PKDPC Dpc,
640: IN PVOID DeferredContext,
641: IN PVOID SystemContext1,
642: IN PVOID SystemContext2
643: )
644:
645: /*++
646:
647: Routine Description:
648:
649: This routine is merely used to complete any read that
650: ended up being used by the Isr. It assumes that the
651: status and the information fields of the irp are already
652: correctly filled in.
653:
654: Arguments:
655:
656: Dpc - Not Used.
657:
658: DeferredContext - Really points to the device extension.
659:
660: SystemContext1 - Not Used.
661:
662: SystemContext2 - Not Used.
663:
664: Return Value:
665:
666: None.
667:
668: --*/
669:
670: {
671:
672: PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
673: KIRQL oldIrql;
674:
675: UNREFERENCED_PARAMETER(Dpc);
676: UNREFERENCED_PARAMETER(SystemContext1);
677: UNREFERENCED_PARAMETER(SystemContext2);
678:
679:
680: IoAcquireCancelSpinLock(&oldIrql);
681:
682: //
683: // We set this to indicate to the interval timer
684: // that the read has completed.
685: //
686: // Recall that the interval timer dpc can be lurking in some
687: // DPC queue.
688: //
689:
690: extension->CountOnLastRead = SERIAL_COMPLETE_READ_COMPLETE;
691:
692: SerialTryToCompleteCurrent(
693: extension,
694: NULL,
695: oldIrql,
696: STATUS_SUCCESS,
697: &extension->CurrentReadIrp,
698: &extension->ReadQueue,
699: &extension->ReadRequestIntervalTimer,
700: &extension->ReadRequestTotalTimer,
701: SerialStartRead,
702: SerialGetNextIrp
703: );
704:
705: }
706:
707: VOID
708: SerialCancelCurrentRead(
709: PDEVICE_OBJECT DeviceObject,
710: PIRP Irp
711: )
712:
713: /*++
714:
715: Routine Description:
716:
717: This routine is used to cancel the current read.
718:
719: Arguments:
720:
721: DeviceObject - Pointer to the device object for this device
722:
723: Irp - Pointer to the IRP to be canceled.
724:
725: Return Value:
726:
727: None.
728:
729: --*/
730:
731: {
732:
733: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
734:
735: //
736: // We set this to indicate to the interval timer
737: // that the read has encountered a cancel.
738: //
739: // Recall that the interval timer dpc can be lurking in some
740: // DPC queue.
741: //
742:
743: extension->CountOnLastRead = SERIAL_COMPLETE_READ_CANCEL;
744:
745: SerialTryToCompleteCurrent(
746: extension,
747: SerialGrabReadFromIsr,
748: Irp->CancelIrql,
749: STATUS_CANCELLED,
750: &extension->CurrentReadIrp,
751: &extension->ReadQueue,
752: &extension->ReadRequestIntervalTimer,
753: &extension->ReadRequestTotalTimer,
754: SerialStartRead,
755: SerialGetNextIrp
756: );
757:
758: }
759:
760: BOOLEAN
761: SerialGrabReadFromIsr(
762: IN PVOID Context
763: )
764:
765: /*++
766:
767: Routine Description:
768:
769: This routine is used to grab (if possible) the irp from the
770: isr. If it finds that the isr still owns the irp it grabs
771: the ipr away (updating the number of characters copied into the
772: users buffer). If it grabs it away it also decrements the
773: reference count on the irp since it no longer belongs to the
774: isr (and the dpc that would complete it).
775:
776: NOTE: This routine assumes that if the current buffer that the
777: ISR is copying characters into is the interrupt buffer then
778: the dpc has already been queued.
779:
780: NOTE: This routine is being called from KeSynchronizeExecution.
781:
782: NOTE: This routine assumes that it is called with the cancel spin
783: lock held.
784:
785: Arguments:
786:
787: Context - Really a pointer to the device extension.
788:
789: Return Value:
790:
791: Always false.
792:
793: --*/
794:
795: {
796:
797: PSERIAL_DEVICE_EXTENSION extension = Context;
798:
799: if (extension->ReadBufferBase !=
800: extension->InterruptReadBuffer) {
801:
802: //
803: // We need to set the information to the number of characters
804: // that the read wanted minus the number of characters that
805: // didn't get read into the interrupt buffer.
806: //
807:
808: extension->CurrentReadIrp->IoStatus.Information =
809: IoGetCurrentIrpStackLocation(
810: extension->CurrentReadIrp
811: )->Parameters.Read.Length -
812: ((extension->LastCharSlot - extension->CurrentCharSlot) + 1);
813:
814: //
815: // Switch back to the interrupt buffer.
816: //
817:
818: extension->ReadBufferBase = extension->InterruptReadBuffer;
819: extension->CurrentCharSlot = extension->InterruptReadBuffer;
820: extension->FirstReadableChar = extension->InterruptReadBuffer;
821: extension->LastCharSlot = extension->InterruptReadBuffer +
822: (extension->BufferSize - 1);
823: extension->CharsInInterruptBuffer = 0;
824:
825: SERIAL_DEC_REFERENCE(extension->CurrentReadIrp);
826:
827: }
828:
829: return FALSE;
830:
831: }
832:
833: VOID
834: SerialReadTimeout(
835: IN PKDPC Dpc,
836: IN PVOID DeferredContext,
837: IN PVOID SystemContext1,
838: IN PVOID SystemContext2
839: )
840:
841: /*++
842:
843: Routine Description:
844:
845: This routine is used to complete a read because its total
846: timer has expired.
847:
848: Arguments:
849:
850: Dpc - Not Used.
851:
852: DeferredContext - Really points to the device extension.
853:
854: SystemContext1 - Not Used.
855:
856: SystemContext2 - Not Used.
857:
858: Return Value:
859:
860: None.
861:
862: --*/
863:
864: {
865:
866: PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
867: KIRQL oldIrql;
868:
869: UNREFERENCED_PARAMETER(Dpc);
870: UNREFERENCED_PARAMETER(SystemContext1);
871: UNREFERENCED_PARAMETER(SystemContext2);
872:
873: IoAcquireCancelSpinLock(&oldIrql);
874:
875: //
876: // We set this to indicate to the interval timer
877: // that the read has completed due to total timeout.
878: //
879: // Recall that the interval timer dpc can be lurking in some
880: // DPC queue.
881: //
882:
883: extension->CountOnLastRead = SERIAL_COMPLETE_READ_TOTAL;
884:
885: SerialTryToCompleteCurrent(
886: extension,
887: SerialGrabReadFromIsr,
888: oldIrql,
889: STATUS_TIMEOUT,
890: &extension->CurrentReadIrp,
891: &extension->ReadQueue,
892: &extension->ReadRequestIntervalTimer,
893: &extension->ReadRequestTotalTimer,
894: SerialStartRead,
895: SerialGetNextIrp
896: );
897:
898: }
899:
900: BOOLEAN
901: SerialUpdateReadByIsr(
902: IN PVOID Context
903: )
904:
905: /*++
906:
907: Routine Description:
908:
909: This routine is used to update the count of characters read
910: by the isr since the last interval timer experation.
911:
912: NOTE: This routine is being called from KeSynchronizeExecution.
913:
914: NOTE: This routine assumes that it is called with the cancel spin
915: lock held.
916:
917: Arguments:
918:
919: Context - Really a pointer to the device extension.
920:
921: Return Value:
922:
923: Always false.
924:
925: --*/
926:
927: {
928:
929: PSERIAL_DEVICE_EXTENSION extension = Context;
930:
931: extension->CountOnLastRead = extension->ReadByIsr;
932: extension->ReadByIsr = 0;
933:
934: return FALSE;
935:
936: }
937:
938: VOID
939: SerialIntervalReadTimeout(
940: IN PKDPC Dpc,
941: IN PVOID DeferredContext,
942: IN PVOID SystemContext1,
943: IN PVOID SystemContext2
944: )
945:
946: /*++
947:
948: Routine Description:
949:
950: This routine is used timeout the request if the time between
951: characters exceed the interval time. A global is kept in
952: the device extension that records the count of characters read
953: the last the last time this routine was invoked (This dpc
954: will resubmit the timer if the count has changed). If the
955: count has not changed then this routine will attempt to complete
956: the irp. Note the special case of the last count being zero.
957: The timer isn't really in effect until the first character is
958: read.
959:
960: Arguments:
961:
962: Dpc - Not Used.
963:
964: DeferredContext - Really points to the device extension.
965:
966: SystemContext1 - Not Used.
967:
968: SystemContext2 - Not Used.
969:
970: Return Value:
971:
972: None.
973:
974: --*/
975:
976: {
977:
978: PSERIAL_DEVICE_EXTENSION extension = DeferredContext;
979: KIRQL oldIrql;
980:
981: UNREFERENCED_PARAMETER(Dpc);
982: UNREFERENCED_PARAMETER(SystemContext1);
983: UNREFERENCED_PARAMETER(SystemContext2);
984:
985: IoAcquireCancelSpinLock(&oldIrql);
986:
987: if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_TOTAL) {
988:
989: //
990: // This value is only set by the total
991: // timer to indicate that it has fired.
992: // If so, then we should simply try to complete.
993: //
994:
995: SerialTryToCompleteCurrent(
996: extension,
997: SerialGrabReadFromIsr,
998: oldIrql,
999: STATUS_TIMEOUT,
1000: &extension->CurrentReadIrp,
1001: &extension->ReadQueue,
1002: &extension->ReadRequestIntervalTimer,
1003: &extension->ReadRequestTotalTimer,
1004: SerialStartRead,
1005: SerialGetNextIrp
1006: );
1007:
1008: } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_COMPLETE) {
1009:
1010: //
1011: // This value is only set by the regular
1012: // completion routine.
1013: //
1014: // If so, then we should simply try to complete.
1015: //
1016:
1017: SerialTryToCompleteCurrent(
1018: extension,
1019: SerialGrabReadFromIsr,
1020: oldIrql,
1021: STATUS_SUCCESS,
1022: &extension->CurrentReadIrp,
1023: &extension->ReadQueue,
1024: &extension->ReadRequestIntervalTimer,
1025: &extension->ReadRequestTotalTimer,
1026: SerialStartRead,
1027: SerialGetNextIrp
1028: );
1029:
1030: } else if (extension->CountOnLastRead == SERIAL_COMPLETE_READ_CANCEL) {
1031:
1032: //
1033: // This value is only set by the cancel
1034: // read routine.
1035: //
1036: // If so, then we should simply try to complete.
1037: //
1038:
1039: SerialTryToCompleteCurrent(
1040: extension,
1041: SerialGrabReadFromIsr,
1042: oldIrql,
1043: STATUS_CANCELLED,
1044: &extension->CurrentReadIrp,
1045: &extension->ReadQueue,
1046: &extension->ReadRequestIntervalTimer,
1047: &extension->ReadRequestTotalTimer,
1048: SerialStartRead,
1049: SerialGetNextIrp
1050: );
1051:
1052: } else if (extension->CountOnLastRead || extension->ReadByIsr) {
1053:
1054: //
1055: // Something has happened since we last came here. We
1056: // check to see if the ISR has read in any more characters.
1057: // If it did then we should update the isr's read count
1058: // and resubmit the timer.
1059: //
1060:
1061: if (extension->ReadByIsr) {
1062:
1063: KeSynchronizeExecution(
1064: extension->Interrupt,
1065: SerialUpdateReadByIsr,
1066: extension
1067: );
1068:
1069: //
1070: // Save off the "last" time something was read.
1071: // As we come back to this routine we will compare
1072: // the current time to the "last" time. If the
1073: // difference is ever larger then the interval
1074: // requested by the user, then time out the request.
1075: //
1076:
1077: KeQuerySystemTime(
1078: &extension->LastReadTime
1079: );
1080:
1081: KeSetTimer(
1082: &extension->ReadRequestIntervalTimer,
1083: *extension->IntervalTimeToUse,
1084: &extension->IntervalReadTimeoutDpc
1085: );
1086:
1087: IoReleaseCancelSpinLock(oldIrql);
1088:
1089: } else {
1090:
1091: //
1092: // Take the difference between the current time
1093: // and the last time we had characters and
1094: // see if it is greater then the interval time.
1095: // if it is, then time out the request. Otherwise
1096: // go away again for a while.
1097: //
1098:
1099: //
1100: // No characters read in the interval time. Kill
1101: // this read.
1102: //
1103:
1104: LARGE_INTEGER currentTime;
1105:
1106: KeQuerySystemTime(
1107: ¤tTime
1108: );
1109:
1110: if (RtlLargeIntegerGreaterThanOrEqualTo(
1111: RtlLargeIntegerSubtract(
1112: currentTime,
1113: extension->LastReadTime
1114: ),
1115: extension->IntervalTime
1116: )) {
1117:
1118: SerialTryToCompleteCurrent(
1119: extension,
1120: SerialGrabReadFromIsr,
1121: oldIrql,
1122: STATUS_TIMEOUT,
1123: &extension->CurrentReadIrp,
1124: &extension->ReadQueue,
1125: &extension->ReadRequestIntervalTimer,
1126: &extension->ReadRequestTotalTimer,
1127: SerialStartRead,
1128: SerialGetNextIrp
1129: );
1130:
1131: } else {
1132:
1133: KeSetTimer(
1134: &extension->ReadRequestIntervalTimer,
1135: *extension->IntervalTimeToUse,
1136: &extension->IntervalReadTimeoutDpc
1137: );
1138: IoReleaseCancelSpinLock(oldIrql);
1139:
1140: }
1141:
1142:
1143: }
1144:
1145: } else {
1146:
1147: //
1148: // Timer doesn't really start until the first character.
1149: // So we should simply resubmit ourselves.
1150: //
1151:
1152: KeSetTimer(
1153: &extension->ReadRequestIntervalTimer,
1154: *extension->IntervalTimeToUse,
1155: &extension->IntervalReadTimeoutDpc
1156: );
1157:
1158: IoReleaseCancelSpinLock(oldIrql);
1159:
1160: }
1161:
1162:
1163: }
1164:
1165: ULONG
1166: SerialGetCharsFromIntBuffer(
1167: PSERIAL_DEVICE_EXTENSION Extension
1168: )
1169:
1170: /*++
1171:
1172: Routine Description:
1173:
1174: This routine is used to copy any characters out of the interrupt
1175: buffer into the users buffer. It will be reading values that
1176: are updated with the ISR but this is safe since this value is
1177: only decremented by synchronization routines. This routine will
1178: return the number of characters copied so some other routine
1179: can call a synchronization routine to update what is seen at
1180: interrupt level.
1181:
1182: Arguments:
1183:
1184: Extension - A pointer to the device extension.
1185:
1186: Return Value:
1187:
1188: The number of characters that were copied into the user
1189: buffer.
1190:
1191: --*/
1192:
1193: {
1194:
1195: //
1196: // This value will be the number of characters that this
1197: // routine returns. It will be the minimum of the number
1198: // of characters currently in the buffer or the number of
1199: // characters required for the read.
1200: //
1201: ULONG numberOfCharsToGet;
1202:
1203: //
1204: // This holds the number of characters between the first
1205: // readable character and - the last character we will read or
1206: // the real physical end of the buffer (not the last readable
1207: // character).
1208: //
1209: ULONG firstTryNumberToGet;
1210:
1211:
1212: //
1213: // The minimum of the number of characters we need and
1214: // the number of characters available
1215: //
1216:
1217: numberOfCharsToGet = Extension->CharsInInterruptBuffer;
1218:
1219: if (numberOfCharsToGet > Extension->NumberNeededForRead) {
1220:
1221: numberOfCharsToGet = Extension->NumberNeededForRead;
1222:
1223: }
1224:
1225: if (numberOfCharsToGet) {
1226:
1227: //
1228: // This will hold the number of characters between the
1229: // first available character and the end of the buffer.
1230: // Note that the buffer could wrap around but for the
1231: // purposes of the first copy we don't care about that.
1232: //
1233:
1234: firstTryNumberToGet = (Extension->LastCharSlot -
1235: Extension->FirstReadableChar) + 1;
1236:
1237: if (firstTryNumberToGet > numberOfCharsToGet) {
1238:
1239: //
1240: // The characters don't wrap. Actually they may wrap but
1241: // we don't care for the purposes of this read since the
1242: // characters we need are available before the wrap.
1243: //
1244:
1245: RtlMoveMemory(
1246: ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
1247: + (IoGetCurrentIrpStackLocation(
1248: Extension->CurrentReadIrp
1249: )->Parameters.Read.Length
1250: - Extension->NumberNeededForRead
1251: ),
1252: Extension->FirstReadableChar,
1253: numberOfCharsToGet
1254: );
1255:
1256: Extension->NumberNeededForRead -= numberOfCharsToGet;
1257:
1258: //
1259: // We now will move the pointer to the first character after
1260: // what we just copied into the users buffer.
1261: //
1262: // We need to check if the stream of readable characters
1263: // is wrapping around to the beginning of the buffer.
1264: //
1265: // Note that we may have just taken the last characters
1266: // at the end of the buffer.
1267: //
1268:
1269: if ((Extension->FirstReadableChar + (numberOfCharsToGet - 1)) ==
1270: Extension->LastCharSlot) {
1271:
1272: Extension->FirstReadableChar = Extension->InterruptReadBuffer;
1273:
1274: } else {
1275:
1276: Extension->FirstReadableChar += numberOfCharsToGet;
1277:
1278: }
1279:
1280: } else {
1281:
1282: //
1283: // The characters do wrap. Get up until the end of the buffer.
1284: //
1285:
1286: RtlMoveMemory(
1287: ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
1288: + (IoGetCurrentIrpStackLocation(
1289: Extension->CurrentReadIrp
1290: )->Parameters.Read.Length
1291: - Extension->NumberNeededForRead
1292: ),
1293: Extension->FirstReadableChar,
1294: firstTryNumberToGet
1295: );
1296:
1297: Extension->NumberNeededForRead -= firstTryNumberToGet;
1298:
1299: //
1300: // Now get the rest of the characters from the beginning of the
1301: // buffer.
1302: //
1303:
1304: RtlMoveMemory(
1305: ((PUCHAR)(Extension->CurrentReadIrp->AssociatedIrp.SystemBuffer))
1306: + (IoGetCurrentIrpStackLocation(
1307: Extension->CurrentReadIrp
1308: )->Parameters.Read.Length
1309: - Extension->NumberNeededForRead
1310: ),
1311: Extension->InterruptReadBuffer,
1312: numberOfCharsToGet - firstTryNumberToGet
1313: );
1314:
1315: Extension->FirstReadableChar = Extension->InterruptReadBuffer +
1316: (numberOfCharsToGet -
1317: firstTryNumberToGet);
1318:
1319: Extension->NumberNeededForRead -= (numberOfCharsToGet -
1320: firstTryNumberToGet);
1321:
1322: }
1323:
1324: }
1325:
1326: Extension->CurrentReadIrp->IoStatus.Information += numberOfCharsToGet;
1327: return numberOfCharsToGet;
1328:
1329: }
1330:
1331: BOOLEAN
1332: SerialUpdateInterruptBuffer(
1333: IN PVOID Context
1334: )
1335:
1336: /*++
1337:
1338: Routine Description:
1339:
1340: This routine is used to update the number of characters that
1341: remain in the interrupt buffer. We need to use this routine
1342: since the count could be updated during the update by execution
1343: of the ISR.
1344:
1345: NOTE: This is called by KeSynchronizeExecution.
1346:
1347: Arguments:
1348:
1349: Context - Points to a structure that contains a pointer to the
1350: device extension and count of the number of characters
1351: that we previously copied into the users buffer. The
1352: structure actually has a third field that we don't
1353: use in this routine.
1354:
1355: Return Value:
1356:
1357: Always FALSE.
1358:
1359: --*/
1360:
1361: {
1362:
1363: PSERIAL_UPDATE_CHAR update = Context;
1364: PSERIAL_DEVICE_EXTENSION extension = update->Extension;
1365:
1366: ASSERT(extension->CharsInInterruptBuffer >= update->CharsCopied);
1367: extension->CharsInInterruptBuffer -= update->CharsCopied;
1368:
1369: //
1370: // Deal with flow control if necessary.
1371: //
1372:
1373: SerialHandleReducedIntBuffer(extension);
1374:
1375:
1376: return FALSE;
1377:
1378: }
1379:
1380: BOOLEAN
1381: SerialUpdateAndSwitchToUser(
1382: IN PVOID Context
1383: )
1384:
1385: /*++
1386:
1387: Routine Description:
1388:
1389: This routine gets the (hopefully) few characters that
1390: remain in the interrupt buffer after the first time we tried
1391: to get them out. If we still don't have enough characters
1392: to satisfy the read it will then we set things up so that the
1393: ISR uses the user buffer copy into.
1394:
1395: This routine is also used to update a count that is maintained
1396: by the ISR to keep track of the number of characters in its buffer.
1397:
1398: NOTE: This is called by KeSynchronizeExecution.
1399:
1400: Arguments:
1401:
1402: Context - Points to a structure that contains a pointer to the
1403: device extension, a count of the number of characters
1404: that we previously copied into the users buffer, and
1405: a boolean that we will set that defines whether we
1406: switched the ISR to copy into the users buffer.
1407:
1408: Return Value:
1409:
1410: Always FALSE.
1411:
1412: --*/
1413:
1414: {
1415:
1416: PSERIAL_UPDATE_CHAR updateChar = Context;
1417: PSERIAL_DEVICE_EXTENSION extension = updateChar->Extension;
1418:
1419: SerialUpdateInterruptBuffer(Context);
1420:
1421: //
1422: // There are more characters to get to satisfy this read.
1423: // Copy any characters that have arrived since we got
1424: // the last batch.
1425: //
1426:
1427: updateChar->CharsCopied = SerialGetCharsFromIntBuffer(extension);
1428:
1429: SerialUpdateInterruptBuffer(Context);
1430:
1431: //
1432: // No more new characters will be "received" until we exit
1433: // this routine. We again check to make sure that we
1434: // haven't satisfied this read, and if we haven't we set things
1435: // up so that the ISR copies into the user buffer.
1436: //
1437:
1438: if (extension->NumberNeededForRead) {
1439:
1440: //
1441: // We shouldn't be switching unless there are no
1442: // characters left.
1443: //
1444:
1445: ASSERT(!extension->CharsInInterruptBuffer);
1446:
1447: //
1448: // We use the following to values to do inteval timing.
1449: //
1450: // CountOnLastRead is mostly used to simply prevent
1451: // the interval timer from timing out before any characters
1452: // are read. (Interval timing should only be effective
1453: // after the first character is read.)
1454: //
1455: // After the first time the interval timer fires and
1456: // characters have be read we will simply update with
1457: // the value of ReadByIsr and then set ReadByIsr to zero.
1458: // (We do that in a synchronization routine.
1459: //
1460: // If the interval timer dpc routine ever encounters
1461: // ReadByIsr == 0 when CountOnLastRead is non-zero it
1462: // will timeout the read.
1463: //
1464: // (Note that we have a special case of CountOnLastRead
1465: // < 0. This is done by the read completion routines other
1466: // than the total timeout dpc to indicate that the total
1467: // timeout has expired.)
1468: //
1469:
1470: extension->CountOnLastRead =
1471: extension->CurrentReadIrp->IoStatus.Information;
1472:
1473: extension->ReadByIsr = 0;
1474:
1475: //
1476: // By compareing the read buffer base address to the
1477: // the base address of the interrupt buffer the ISR
1478: // can determine whether we are using the interrupt
1479: // buffer or the user buffer.
1480: //
1481:
1482: extension->ReadBufferBase =
1483: extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
1484:
1485: //
1486: // The current char slot is after the last copied in
1487: // character. We know there is always room since we
1488: // we wouldn't have gotten here if there wasn't.
1489: //
1490:
1491: extension->CurrentCharSlot = extension->ReadBufferBase +
1492: extension->CurrentReadIrp->IoStatus.Information;
1493:
1494: //
1495: // The last position that a character can go is on the
1496: // last byte of user buffer. While the actual allocated
1497: // buffer space may be bigger, we know that there is at
1498: // least as much as the read length.
1499: //
1500:
1501: extension->LastCharSlot = extension->ReadBufferBase +
1502: (IoGetCurrentIrpStackLocation(
1503: extension->CurrentReadIrp
1504: )->Parameters.Read.Length
1505: - 1);
1506:
1507: //
1508: // Mark the irp as being in a cancelable state.
1509: //
1510:
1511: IoSetCancelRoutine(
1512: extension->CurrentReadIrp,
1513: SerialCancelCurrentRead
1514: );
1515:
1516: //
1517: // Increment the reference count twice.
1518: //
1519: // Once for the Isr owning the irp and once
1520: // because the cancel routine has a reference
1521: // to it.
1522: //
1523:
1524: SERIAL_INC_REFERENCE(extension->CurrentReadIrp);
1525: SERIAL_INC_REFERENCE(extension->CurrentReadIrp);
1526:
1527: updateChar->Completed = FALSE;
1528:
1529: } else {
1530:
1531: updateChar->Completed = TRUE;
1532:
1533: }
1534:
1535: return FALSE;
1536:
1537: }
1538: //
1539: // We use this structure only to communicate to the synchronization
1540: // routine when we are switching to the resized buffer.
1541: //
1542: typedef struct _SERIAL_RESIZE_PARAMS {
1543: PSERIAL_DEVICE_EXTENSION Extension;
1544: PUCHAR OldBuffer;
1545: PUCHAR NewBuffer;
1546: ULONG NewBufferSize;
1547: ULONG NumberMoved;
1548: } SERIAL_RESIZE_PARAMS,*PSERIAL_RESIZE_PARAMS;
1549:
1550: NTSTATUS
1551: SerialResizeBuffer(
1552: IN PSERIAL_DEVICE_EXTENSION Extension
1553: )
1554:
1555: /*++
1556:
1557: Routine Description:
1558:
1559: This routine will process the resize buffer request.
1560: If size requested for the RX buffer is smaller than
1561: the current buffer then we will simply return
1562: STATUS_SUCCESS. (We don't want to make buffers smaller.
1563: If we did that then we all of a sudden have "overrun"
1564: problems to deal with as well as flow control to deal
1565: with - very painful.) We ignore the TX buffer size
1566: request since we don't use a TX buffer.
1567:
1568: Arguments:
1569:
1570: Extension - Pointer to the device extension for the port.
1571:
1572: Return Value:
1573:
1574: STATUS_SUCCESS if everything worked out ok.
1575: STATUS_INSUFFICIENT_RESOURCES if we couldn't allocate the
1576: memory for the buffer.
1577:
1578: --*/
1579:
1580: {
1581:
1582: PSERIAL_QUEUE_SIZE rs = Extension->CurrentReadIrp->AssociatedIrp
1583: .SystemBuffer;
1584: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(
1585: Extension->CurrentReadIrp
1586: );
1587: PVOID newBuffer = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
1588:
1589: irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
1590: Extension->CurrentReadIrp->IoStatus.Information = 0L;
1591: Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
1592:
1593: if (rs->InSize <= Extension->BufferSize) {
1594:
1595: //
1596: // Nothing to do. We don't make buffers smaller. Just
1597: // agree with the user. We must deallocate the memory
1598: // that was already allocated in the ioctl dispatch routine.
1599: //
1600:
1601: ExFreePool(newBuffer);
1602:
1603: } else {
1604:
1605: SERIAL_RESIZE_PARAMS rp;
1606: KIRQL controlIrql;
1607:
1608: //
1609: // Hmmm, looks like we actually have to go
1610: // through with this. We need to move all the
1611: // data that is in the current buffer into this
1612: // new buffer. We'll do this in two steps.
1613: //
1614: // First we go up to dispatch level and try to
1615: // move as much as we can without stopping the
1616: // ISR from running. We go up to dispatch level
1617: // by acquiring the control lock. We do it at
1618: // dispatch using the control lock so that:
1619: //
1620: // 1) We can't be context switched in the middle
1621: // of the move. Our pointers into the buffer
1622: // could be *VERY* stale by the time we got back.
1623: //
1624: // 2) We use the control lock since we don't want
1625: // some pesky purge irp to come along while
1626: // we are trying to move.
1627: //
1628: // After the move, but while we still hold the control
1629: // lock, we synch with the ISR and get those last
1630: // (hopefully) few characters that have come in since
1631: // we started the copy. We switch all of our pointers,
1632: // counters, and such to point to this new buffer. NOTE:
1633: // we need to be careful. If the buffer we were using
1634: // was not the default one created when we initialized
1635: // the device (i.e. it was created via a previous IRP of
1636: // this type), we should deallocate it.
1637: //
1638:
1639: rp.Extension = Extension;
1640: rp.OldBuffer = Extension->InterruptReadBuffer;
1641: rp.NewBuffer = newBuffer;
1642: rp.NewBufferSize = rs->InSize;
1643:
1644: KeAcquireSpinLock(
1645: &Extension->ControlLock,
1646: &controlIrql
1647: );
1648:
1649: rp.NumberMoved = SerialMoveToNewIntBuffer(
1650: Extension,
1651: newBuffer
1652: );
1653:
1654: KeSynchronizeExecution(
1655: Extension->Interrupt,
1656: SerialUpdateAndSwitchToNew,
1657: &rp
1658: );
1659:
1660: KeReleaseSpinLock(
1661: &Extension->ControlLock,
1662: controlIrql
1663: );
1664:
1665: //
1666: // Free up the memory that the old buffer consumed.
1667: //
1668:
1669: ExFreePool(rp.OldBuffer);
1670:
1671: }
1672:
1673: return STATUS_SUCCESS;
1674:
1675: }
1676:
1677: ULONG
1678: SerialMoveToNewIntBuffer(
1679: PSERIAL_DEVICE_EXTENSION Extension,
1680: PUCHAR NewBuffer
1681: )
1682:
1683: /*++
1684:
1685: Routine Description:
1686:
1687: This routine is used to copy any characters out of the interrupt
1688: buffer into the "new" buffer. It will be reading values that
1689: are updated with the ISR but this is safe since this value is
1690: only decremented by synchronization routines. This routine will
1691: return the number of characters copied so some other routine
1692: can call a synchronization routine to update what is seen at
1693: interrupt level.
1694:
1695: Arguments:
1696:
1697: Extension - A pointer to the device extension.
1698: NewBuffer - Where the characters are to be move to.
1699:
1700: Return Value:
1701:
1702: The number of characters that were copied into the user
1703: buffer.
1704:
1705: --*/
1706:
1707: {
1708:
1709: ULONG numberOfCharsMoved = Extension->CharsInInterruptBuffer;
1710:
1711: if (numberOfCharsMoved) {
1712:
1713: //
1714: // This holds the number of characters between the first
1715: // readable character and the last character we will read or
1716: // the real physical end of the buffer (not the last readable
1717: // character).
1718: //
1719: ULONG firstTryNumberToGet = (Extension->LastCharSlot -
1720: Extension->FirstReadableChar) + 1;
1721:
1722: if (firstTryNumberToGet >= numberOfCharsMoved) {
1723:
1724: //
1725: // The characters don't wrap.
1726: //
1727:
1728: RtlMoveMemory(
1729: NewBuffer,
1730: Extension->FirstReadableChar,
1731: numberOfCharsMoved
1732: );
1733:
1734: if ((Extension->FirstReadableChar+(numberOfCharsMoved-1)) ==
1735: Extension->LastCharSlot) {
1736:
1737: Extension->FirstReadableChar = Extension->InterruptReadBuffer;
1738:
1739: } else {
1740:
1741: Extension->FirstReadableChar += numberOfCharsMoved;
1742:
1743: }
1744:
1745: } else {
1746:
1747: //
1748: // The characters do wrap. Get up until the end of the buffer.
1749: //
1750:
1751: RtlMoveMemory(
1752: NewBuffer,
1753: Extension->FirstReadableChar,
1754: firstTryNumberToGet
1755: );
1756:
1757: //
1758: // Now get the rest of the characters from the beginning of the
1759: // buffer.
1760: //
1761:
1762: RtlMoveMemory(
1763: NewBuffer+firstTryNumberToGet,
1764: Extension->InterruptReadBuffer,
1765: numberOfCharsMoved - firstTryNumberToGet
1766: );
1767:
1768: Extension->FirstReadableChar = Extension->InterruptReadBuffer +
1769: numberOfCharsMoved - firstTryNumberToGet;
1770:
1771: }
1772:
1773: }
1774:
1775: return numberOfCharsMoved;
1776:
1777: }
1778:
1779: BOOLEAN
1780: SerialUpdateAndSwitchToNew(
1781: IN PVOID Context
1782: )
1783:
1784: /*++
1785:
1786: Routine Description:
1787:
1788: This routine gets the (hopefully) few characters that
1789: remain in the interrupt buffer after the first time we tried
1790: to get them out.
1791:
1792: NOTE: This is called by KeSynchronizeExecution.
1793:
1794: Arguments:
1795:
1796: Context - Points to a structure that contains a pointer to the
1797: device extension, a pointer to the buffer we are moving
1798: to, and a count of the number of characters
1799: that we previously copied into the new buffer, and the
1800: actual size of the new buffer.
1801:
1802: Return Value:
1803:
1804: Always FALSE.
1805:
1806: --*/
1807:
1808: {
1809:
1810: PSERIAL_RESIZE_PARAMS params = Context;
1811: PSERIAL_DEVICE_EXTENSION extension = params->Extension;
1812: ULONG tempCharsInInterruptBuffer = extension->CharsInInterruptBuffer;
1813:
1814: ASSERT(extension->CharsInInterruptBuffer >= params->NumberMoved);
1815:
1816: //
1817: // We temporarily reduce the chars in interrupt buffer to
1818: // "fool" the move routine. We will restore it after the
1819: // move.
1820: //
1821:
1822: extension->CharsInInterruptBuffer -= params->NumberMoved;
1823:
1824: if (extension->CharsInInterruptBuffer) {
1825:
1826: SerialMoveToNewIntBuffer(
1827: extension,
1828: params->NewBuffer + params->NumberMoved
1829: );
1830:
1831: }
1832:
1833: extension->CharsInInterruptBuffer = tempCharsInInterruptBuffer;
1834:
1835:
1836: extension->LastCharSlot = params->NewBuffer + (params->NewBufferSize - 1);
1837: extension->FirstReadableChar = params->NewBuffer;
1838: extension->ReadBufferBase = params->NewBuffer;
1839: extension->InterruptReadBuffer = params->NewBuffer;
1840: extension->BufferSize = params->NewBufferSize;
1841:
1842: //
1843: // We *KNOW* that the new interrupt buffer is larger than the
1844: // old buffer. We don't need to worry about it being full.
1845: //
1846:
1847: extension->CurrentCharSlot = extension->InterruptReadBuffer +
1848: extension->CharsInInterruptBuffer;
1849:
1850: //
1851: // We set up the default xon/xoff limits.
1852: //
1853:
1854: extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
1855: extension->HandFlow.XonLimit = extension->BufferSize >> 1;
1856:
1857: extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
1858: (extension->BufferSize>>4));
1859:
1860: //
1861: // Since we (essentially) reduced the percentage of the interrupt
1862: // buffer being full, we need to handle any flow control.
1863: //
1864:
1865: SerialHandleReducedIntBuffer(extension);
1866:
1867: return FALSE;
1868:
1869: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.