|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: write.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to write
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:
34: BOOLEAN
35: SerialGiveWriteToIsr(
36: IN PVOID Context
37: );
38:
39: VOID
40: SerialCancelCurrentWrite(
41: PDEVICE_OBJECT DeviceObject,
42: PIRP Irp
43: );
44:
45: BOOLEAN
46: SerialGrabWriteFromIsr(
47: IN PVOID Context
48: );
49:
50: BOOLEAN
51: SerialGrabXoffFromIsr(
52: IN PVOID Context
53: );
54:
55: VOID
56: SerialCancelCurrentXoff(
57: PDEVICE_OBJECT DeviceObject,
58: PIRP Irp
59: );
60:
61: BOOLEAN
62: SerialGiveXoffToIsr(
63: IN PVOID Context
64: );
65:
66:
67:
68: NTSTATUS
69: SerialWrite(
70: IN PDEVICE_OBJECT DeviceObject,
71: IN PIRP Irp
72: )
73:
74: /*++
75:
76: Routine Description:
77:
78: This is the dispatch routine for write. It validates the parameters
79: for the write request and if all is ok then it places the request
80: on the work queue.
81:
82: Arguments:
83:
84: DeviceObject - Pointer to the device object for this device
85:
86: Irp - Pointer to the IRP for the current request
87:
88: Return Value:
89:
90: If the io is zero length then it will return STATUS_SUCCESS,
91: otherwise this routine will return STATUS_PENDING.
92:
93: --*/
94:
95: {
96:
97: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
98:
99: SerialDump(
100: SERIRPPATH,
101: ("SERIAL: Dispatch entry for: %x\n",Irp)
102: );
103: if (SerialCompleteIfError(
104: DeviceObject,
105: Irp
106: ) != STATUS_SUCCESS) {
107:
108: return STATUS_CANCELLED;
109:
110: }
111:
112: Irp->IoStatus.Information = 0L;
113:
114: //
115: // Quick check for a zero length write. If it is zero length
116: // then we are already done!
117: //
118:
119: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length) {
120:
121: //
122: // Well it looks like we actually have to do some
123: // work. Put the write on the queue so that we can
124: // process it when our previous writes are done.
125: //
126:
127: return SerialStartOrQueue(
128: Extension,
129: Irp,
130: &Extension->WriteQueue,
131: &Extension->CurrentWriteIrp,
132: SerialStartWrite
133: );
134:
135: } else {
136:
137: Irp->IoStatus.Status = STATUS_SUCCESS;
138: SerialDump(
139: SERIRPPATH,
140: ("SERIAL: Complete Irp: %x\n",Irp)
141: );
142: IoCompleteRequest(
143: Irp,
144: 0
145: );
146:
147: return STATUS_SUCCESS;
148:
149: }
150:
151: }
152:
153: NTSTATUS
154: SerialStartWrite(
155: IN PSERIAL_DEVICE_EXTENSION Extension
156: )
157:
158: /*++
159:
160: Routine Description:
161:
162: This routine is used to start off any write. It initializes
163: the Iostatus fields of the irp. It will set up any timers
164: that are used to control the write.
165:
166: Arguments:
167:
168: Extension - Points to the serial device extension
169:
170: Return Value:
171:
172: This routine will return STATUS_PENDING for all writes
173: other than those that we find are cancelled.
174:
175: --*/
176:
177: {
178:
179: PIRP NewIrp;
180: KIRQL OldIrql;
181: LARGE_INTEGER TotalTime;
182: BOOLEAN UseATimer;
183: SERIAL_TIMEOUTS Timeouts;
184: BOOLEAN SetFirstStatus = FALSE;
185: NTSTATUS FirstStatus;
186:
187: do {
188:
189: //
190: // If there is an xoff counter then complete it.
191: //
192:
193: IoAcquireCancelSpinLock(&OldIrql);
194:
195: //
196: // We see if there is a actually an Xoff counter irp.
197: //
198: // If there is, we put the write irp back on the head
199: // of the write list. We then kill the xoff counter.
200: // The xoff counter killing code will actually make the
201: // xoff counter back into the current write irp, and
202: // in the course of completing the xoff (which is now
203: // the current write) we will restart this irp.
204: //
205:
206: if (Extension->CurrentXoffIrp) {
207:
208: InsertHeadList(
209: &Extension->WriteQueue,
210: &Extension->CurrentWriteIrp->Tail.Overlay.ListEntry
211: );
212:
213: if (!SetFirstStatus) {
214:
215: IoMarkIrpPending(Extension->CurrentWriteIrp);
216: SetFirstStatus = TRUE;
217: FirstStatus = STATUS_PENDING;
218:
219: }
220:
221: if (SERIAL_REFERENCE_COUNT(Extension->CurrentXoffIrp)) {
222:
223: //
224: // The reference count is non-zero. This implies that
225: // the xoff irp has not made it through the completion
226: // path yet. We will increment the reference count
227: // and attempt to complete it ourseleves.
228: //
229:
230: SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp);
231:
232: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
233:
234: //
235: // The following call will actually release the
236: // cancel spin lock.
237: //
238:
239: SerialTryToCompleteCurrent(
240: Extension,
241: SerialGrabXoffFromIsr,
242: OldIrql,
243: STATUS_SERIAL_MORE_WRITES,
244: &Extension->CurrentWriteIrp,
245: &Extension->WriteQueue,
246: NULL,
247: &Extension->XoffCountTimer,
248: SerialStartWrite,
249: SerialGetNextWrite
250: );
251:
252: return FirstStatus;
253:
254: } else {
255:
256: //
257: // The irp is well on its way to being finished.
258: // We can let the regular completion code do the
259: // work. Just release the spin lock.
260: //
261:
262: IoReleaseCancelSpinLock(OldIrql);
263:
264: return FirstStatus;
265:
266: }
267:
268: } else {
269:
270: IoReleaseCancelSpinLock(OldIrql);
271:
272: }
273:
274: UseATimer = FALSE;
275:
276: //
277: // Calculate the timeout value needed for the
278: // request. Note that the values stored in the
279: // timeout record are in milliseconds. Note that
280: // if the timeout values are zero then we won't start
281: // the timer.
282: //
283:
284: KeAcquireSpinLock(
285: &Extension->ControlLock,
286: &OldIrql
287: );
288:
289: Timeouts = Extension->Timeouts;
290:
291: KeReleaseSpinLock(
292: &Extension->ControlLock,
293: OldIrql
294: );
295:
296: if (Timeouts.WriteTotalTimeoutConstant ||
297: Timeouts.WriteTotalTimeoutMultiplier) {
298:
299: PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(
300: Extension->CurrentWriteIrp
301: );
302: UseATimer = TRUE;
303:
304: //
305: // We have some timer values to calculate.
306: //
307: // Take care, we might have an xoff counter masquerading
308: // as a write.
309: //
310:
311: TotalTime = RtlEnlargedUnsignedMultiply(
312: (IrpSp->MajorFunction == IRP_MJ_WRITE)?
313: (IrpSp->Parameters.Write.Length):
314: (1),
315: Timeouts.WriteTotalTimeoutMultiplier
316: );
317:
318: TotalTime = RtlLargeIntegerAdd(
319: TotalTime,
320: RtlConvertUlongToLargeInteger(
321: Timeouts.WriteTotalTimeoutConstant
322: )
323: );
324:
325: TotalTime = RtlExtendedIntegerMultiply(
326: TotalTime,
327: -10000
328: );
329:
330: }
331:
332: //
333: // The irp may be going to the isr shortly. Now
334: // is a good time to initialize its reference counts.
335: //
336:
337: SERIAL_INIT_REFERENCE(Extension->CurrentWriteIrp);
338:
339: //
340: // We need to see if this irp should be canceled.
341: //
342:
343: IoAcquireCancelSpinLock(&OldIrql);
344: if (Extension->CurrentWriteIrp->Cancel) {
345:
346: IoReleaseCancelSpinLock(OldIrql);
347: Extension->CurrentWriteIrp->IoStatus.Status = STATUS_CANCELLED;
348:
349: if (!SetFirstStatus) {
350:
351: FirstStatus = STATUS_CANCELLED;
352: SetFirstStatus = TRUE;
353:
354: }
355:
356: } else {
357:
358: if (!SetFirstStatus) {
359:
360: //
361: // If we haven't set our first status, then
362: // this is the only irp that could have possibly
363: // not been on the queue. (It could have been
364: // on the queue if this routine is being invoked
365: // from the completion routine.) Since this
366: // irp might never have been on the queue we
367: // should mark it as pending.
368: //
369:
370: IoMarkIrpPending(Extension->CurrentWriteIrp);
371: SetFirstStatus = TRUE;
372: FirstStatus = STATUS_PENDING;
373:
374: }
375:
376: //
377: // We give the irp to to the isr to write out.
378: // We set a cancel routine that knows how to
379: // grab the current write away from the isr.
380: //
381: // Since the cancel routine has an implicit reference
382: // to this irp up the reference count.
383: //
384:
385: IoSetCancelRoutine(
386: Extension->CurrentWriteIrp,
387: SerialCancelCurrentWrite
388: );
389:
390: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
391:
392: if (UseATimer) {
393:
394: KeSetTimer(
395: &Extension->WriteRequestTotalTimer,
396: TotalTime,
397: &Extension->TotalWriteTimeoutDpc
398: );
399:
400: //
401: // This timer now has a reference to the irp.
402: //
403:
404: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
405: }
406:
407: KeSynchronizeExecution(
408: Extension->Interrupt,
409: SerialGiveWriteToIsr,
410: Extension
411: );
412:
413: IoReleaseCancelSpinLock(OldIrql);
414: break;
415:
416: }
417:
418: //
419: // Well the write was canceled before we could start it up.
420: // Try to get another.
421: //
422:
423: SerialGetNextWrite(
424: &Extension->CurrentWriteIrp,
425: &Extension->WriteQueue,
426: &NewIrp,
427: TRUE
428: );
429:
430: } while (NewIrp);
431:
432: return FirstStatus;
433:
434: }
435:
436: VOID
437: SerialGetNextWrite(
438: IN PIRP *CurrentOpIrp,
439: IN PLIST_ENTRY QueueToProcess,
440: IN PIRP *NewIrp,
441: IN BOOLEAN CompleteCurrent
442: )
443:
444: /*++
445:
446: Routine Description:
447:
448: This routine completes the old write as well as getting
449: a pointer to the next write.
450:
451: The reason that we have have pointers to the current write
452: queue as well as the current write irp is so that this
453: routine may be used in the common completion code for
454: read and write.
455:
456: Arguments:
457:
458: CurrentOpIrp - Pointer to the pointer that points to the
459: current write irp.
460:
461: QueueToProcess - Pointer to the write queue.
462:
463: NewIrp - A pointer to a pointer to the irp that will be the
464: current irp. Note that this could end up pointing
465: to a null pointer. This does NOT necessaryly mean
466: that there is no current write. What could occur
467: is that while the cancel lock is held the write
468: queue ended up being empty, but as soon as we release
469: the cancel spin lock a new irp came in from
470: SerialStartWrite.
471:
472: CompleteCurrent - Flag indicates whether the CurrentOpIrp should
473: be completed.
474:
475: Return Value:
476:
477: None.
478:
479: --*/
480:
481: {
482:
483: PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD(
484: QueueToProcess,
485: SERIAL_DEVICE_EXTENSION,
486: WriteQueue
487: );
488:
489: do {
490:
491:
492: //
493: // We could be completing a flush.
494: //
495:
496: if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction
497: == IRP_MJ_WRITE) {
498:
499: KIRQL OldIrql;
500:
501: ASSERT(Extension->TotalCharsQueued >=
502: (IoGetCurrentIrpStackLocation(*CurrentOpIrp)
503: ->Parameters.Write.Length));
504:
505: IoAcquireCancelSpinLock(&OldIrql);
506: Extension->TotalCharsQueued -=
507: IoGetCurrentIrpStackLocation(*CurrentOpIrp)
508: ->Parameters.Write.Length;
509: IoReleaseCancelSpinLock(OldIrql);
510:
511: } else if (IoGetCurrentIrpStackLocation(*CurrentOpIrp)->MajorFunction
512: == IRP_MJ_DEVICE_CONTROL) {
513:
514: KIRQL OldIrql;
515:
516: IoAcquireCancelSpinLock(&OldIrql);
517:
518: //
519: // If CurrentXoffIrp is not equal to null, this
520: // implies that this is the "second" time around
521: // for this irp, which implies that we should really
522: // be completing it this time.
523: //
524:
525: if (Extension->CurrentXoffIrp) {
526:
527: Extension->CurrentXoffIrp = NULL;
528: IoReleaseCancelSpinLock(OldIrql);
529:
530: } else {
531:
532: PIRP Irp = *CurrentOpIrp;
533:
534: PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
535:
536: //
537: // We absolutely shouldn't have a cancel routine
538: // at this point.
539: //
540:
541: ASSERT(!Irp->CancelRoutine);
542:
543: //
544: // This could only be a xoff counter masquerading as
545: // a write irp.
546: //
547:
548: Extension->TotalCharsQueued--;
549:
550: //
551: // Check to see of the xoff irp has been set with success.
552: // This means that the write completed normally. If that
553: // is the case, and it hasn't been set to cancel in the
554: // meanwhile, then go on and make it the CurrentXoffIrp.
555: //
556:
557: if (Irp->IoStatus.Status != STATUS_SUCCESS) {
558:
559: //
560: // Oh well, we can just finish it off.
561: //
562: NOTHING;
563:
564: } else if (Irp->Cancel) {
565:
566: Irp->IoStatus.Status = STATUS_CANCELLED;
567:
568: } else {
569:
570: //
571: // Give it a new cancel routine, and increment the
572: // reference count because the cancel routine has
573: // a reference to it.
574: //
575:
576: IoSetCancelRoutine(
577: Irp,
578: SerialCancelCurrentXoff
579: );
580:
581: SERIAL_INC_REFERENCE(Irp);
582:
583: //
584: // We don't want to complete the current irp now. This
585: // will now get completed by the Xoff counter code.
586: //
587:
588: CompleteCurrent = FALSE;
589:
590: //
591: // Give the counter to the isr.
592: //
593:
594: Extension->CurrentXoffIrp = Irp;
595: KeSynchronizeExecution(
596: Extension->Interrupt,
597: SerialGiveXoffToIsr,
598: Extension
599: );
600:
601: //
602: // Start the timer for the counter and increment
603: // the reference count since the timer has a
604: // reference to the irp.
605: //
606:
607: if (Xc->Timeout) {
608:
609: KeSetTimer(
610: &Extension->XoffCountTimer,
611: RtlLargeIntegerNegate(
612: RtlEnlargedUnsignedMultiply(
613: 10000,
614: Xc->Timeout
615: )
616: ),
617: &Extension->XoffCountTimeoutDpc
618: );
619:
620: SERIAL_INC_REFERENCE(Irp);
621:
622: }
623:
624: }
625:
626: IoReleaseCancelSpinLock(OldIrql);
627:
628: }
629:
630: }
631:
632: //
633: // Note that the following call will (probably) also cause
634: // the current irp to be completed.
635: //
636:
637: SerialGetNextIrp(
638: CurrentOpIrp,
639: QueueToProcess,
640: NewIrp,
641: CompleteCurrent
642: );
643:
644: if (!*NewIrp) {
645:
646: KIRQL OldIrql;
647:
648: IoAcquireCancelSpinLock(&OldIrql);
649: KeSynchronizeExecution(
650: Extension->Interrupt,
651: SerialProcessEmptyTransmit,
652: Extension
653: );
654: IoReleaseCancelSpinLock(OldIrql);
655:
656: break;
657:
658: } else if (IoGetCurrentIrpStackLocation(*NewIrp)->MajorFunction
659: == IRP_MJ_FLUSH_BUFFERS) {
660:
661: //
662: // If we encounter a flush request we just want to get
663: // the next irp and complete the flush.
664: //
665: // Note that if NewIrp is non-null then it is also
666: // equal to CurrentWriteIrp.
667: //
668:
669:
670: ASSERT((*NewIrp) == (*CurrentOpIrp));
671: (*NewIrp)->IoStatus.Status = STATUS_SUCCESS;
672:
673: } else {
674:
675: break;
676:
677: }
678:
679: } while (TRUE);
680:
681: }
682:
683: VOID
684: SerialCompleteWrite(
685: IN PKDPC Dpc,
686: IN PVOID DeferredContext,
687: IN PVOID SystemContext1,
688: IN PVOID SystemContext2
689: )
690:
691: /*++
692:
693: Routine Description:
694:
695: This routine is merely used to complete any write. It
696: assumes that the status and the information fields of
697: the irp are already correctly filled in.
698:
699: Arguments:
700:
701: Dpc - Not Used.
702:
703: DeferredContext - Really points to the device extension.
704:
705: SystemContext1 - Not Used.
706:
707: SystemContext2 - Not Used.
708:
709: Return Value:
710:
711: None.
712:
713: --*/
714:
715: {
716:
717: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
718: KIRQL OldIrql;
719:
720: UNREFERENCED_PARAMETER(Dpc);
721: UNREFERENCED_PARAMETER(SystemContext1);
722: UNREFERENCED_PARAMETER(SystemContext2);
723:
724: IoAcquireCancelSpinLock(&OldIrql);
725:
726: SerialTryToCompleteCurrent(
727: Extension,
728: NULL,
729: OldIrql,
730: STATUS_SUCCESS,
731: &Extension->CurrentWriteIrp,
732: &Extension->WriteQueue,
733: NULL,
734: &Extension->WriteRequestTotalTimer,
735: SerialStartWrite,
736: SerialGetNextWrite
737: );
738:
739: }
740:
741: BOOLEAN
742: SerialProcessEmptyTransmit(
743: IN PVOID Context
744: )
745:
746: /*++
747:
748: Routine Description:
749:
750: This routine is used to determine if conditions are appropriate
751: to satisfy a wait for transmit empty event, and if so to complete
752: the irp that is waiting for that event. It also call the code
753: that checks to see if we should lower the RTS line if we are
754: doing transmit toggling.
755:
756: NOTE: This routine is called by KeSynchronizeExecution.
757:
758: NOTE: This routine assumes that it is called with the cancel
759: spinlock held.
760:
761: Arguments:
762:
763: Context - Really a pointer to the device extension.
764:
765: Return Value:
766:
767: This routine always returns FALSE.
768:
769: --*/
770:
771: {
772:
773: PSERIAL_DEVICE_EXTENSION Extension = Context;
774:
775: if (Extension->IsrWaitMask && (Extension->IsrWaitMask & SERIAL_EV_TXEMPTY) &&
776: Extension->EmptiedTransmit && (!Extension->TransmitImmediate) &&
777: (!Extension->CurrentWriteIrp) && IsListEmpty(&Extension->WriteQueue)) {
778:
779: Extension->HistoryMask |= SERIAL_EV_TXEMPTY;
780: if (Extension->IrpMaskLocation) {
781:
782: *Extension->IrpMaskLocation = Extension->HistoryMask;
783: Extension->IrpMaskLocation = NULL;
784: Extension->HistoryMask = 0;
785:
786: Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
787: KeInsertQueueDpc(
788: &Extension->CommWaitDpc,
789: NULL,
790: NULL
791: );
792:
793: }
794:
795: Extension->CountOfTryingToLowerRTS++;
796: SerialPerhapsLowerRTS(Extension);
797:
798: }
799:
800: return FALSE;
801:
802: }
803:
804: BOOLEAN
805: SerialGiveWriteToIsr(
806: IN PVOID Context
807: )
808:
809: /*++
810:
811: Routine Description:
812:
813: Try to start off the write by slipping it in behind
814: a transmit immediate char, or if that isn't available
815: and the transmit holding register is empty, "tickle"
816: the UART into interrupting with a transmit buffer
817: empty.
818:
819: NOTE: This routine is called by KeSynchronizeExecution.
820:
821: NOTE: This routine assumes that it is called with the
822: cancel spin lock held.
823:
824: Arguments:
825:
826: Context - Really a pointer to the device extension.
827:
828: Return Value:
829:
830: This routine always returns FALSE.
831:
832: --*/
833:
834: {
835:
836: PSERIAL_DEVICE_EXTENSION Extension = Context;
837:
838: //
839: // The current stack location. This contains all of the
840: // information we need to process this particular request.
841: //
842: PIO_STACK_LOCATION IrpSp;
843:
844: IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp);
845:
846: //
847: // We might have a xoff counter request masquerading as a
848: // write. The length of these requests will always be one
849: // and we can get a pointer to the actual character from
850: // the data supplied by the user.
851: //
852:
853: if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
854:
855: Extension->WriteLength = IrpSp->Parameters.Write.Length;
856: Extension->WriteCurrentChar =
857: Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer;
858:
859: } else {
860:
861: Extension->WriteLength = 1;
862: Extension->WriteCurrentChar =
863: ((PUCHAR)Extension->CurrentWriteIrp->AssociatedIrp.SystemBuffer) +
864: FIELD_OFFSET(
865: SERIAL_XOFF_COUNTER,
866: XoffChar
867: );
868:
869: }
870:
871: //
872: // The isr now has a reference to the irp.
873: //
874:
875: SERIAL_INC_REFERENCE(Extension->CurrentWriteIrp);
876:
877: //
878: // Check first to see if an immediate char is transmitting.
879: // If it is then we'll just slip in behind it when its
880: // done.
881: //
882:
883: if (!Extension->TransmitImmediate) {
884:
885: //
886: // If there is no immediate char transmitting then we
887: // will "re-enable" the transmit holding register empty
888: // interrupt. The 8250 family of devices will always
889: // signal a transmit holding register empty interrupt
890: // *ANY* time this bit is set to one. By doing things
891: // this way we can simply use the normal interrupt code
892: // to start off this write.
893: //
894: // We've been keeping track of whether the transmit holding
895: // register is empty so it we only need to do this
896: // if the register is empty.
897: //
898:
899: if (Extension->HoldingEmpty) {
900:
901: DISABLE_ALL_INTERRUPTS(Extension->Controller);
902: ENABLE_ALL_INTERRUPTS(Extension->Controller);
903:
904: }
905:
906: }
907:
908: //
909: // The rts line may already be up from previous writes,
910: // however, it won't take much additional time to turn
911: // on the RTS line if we are doing transmit toggling.
912: //
913:
914: if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
915: SERIAL_TRANSMIT_TOGGLE) {
916:
917: SerialSetRTS(Extension);
918:
919: }
920:
921: return FALSE;
922:
923: }
924:
925: VOID
926: SerialCancelCurrentWrite(
927: PDEVICE_OBJECT DeviceObject,
928: PIRP Irp
929: )
930:
931: /*++
932:
933: Routine Description:
934:
935: This routine is used to cancel the current write.
936:
937: Arguments:
938:
939: DeviceObject - Pointer to the device object for this device
940:
941: Irp - Pointer to the IRP to be canceled.
942:
943: Return Value:
944:
945: None.
946:
947: --*/
948:
949: {
950:
951: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
952:
953: SerialTryToCompleteCurrent(
954: Extension,
955: SerialGrabWriteFromIsr,
956: Irp->CancelIrql,
957: STATUS_CANCELLED,
958: &Extension->CurrentWriteIrp,
959: &Extension->WriteQueue,
960: NULL,
961: &Extension->WriteRequestTotalTimer,
962: SerialStartWrite,
963: SerialGetNextWrite
964: );
965:
966: }
967:
968: VOID
969: SerialWriteTimeout(
970: IN PKDPC Dpc,
971: IN PVOID DeferredContext,
972: IN PVOID SystemContext1,
973: IN PVOID SystemContext2
974: )
975:
976: /*++
977:
978: Routine Description:
979:
980: This routine will try to timeout the current write.
981:
982: Arguments:
983:
984: Dpc - Not Used.
985:
986: DeferredContext - Really points to the device extension.
987:
988: SystemContext1 - Not Used.
989:
990: SystemContext2 - Not Used.
991:
992: Return Value:
993:
994: None.
995:
996: --*/
997:
998: {
999:
1000: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
1001: KIRQL OldIrql;
1002:
1003: UNREFERENCED_PARAMETER(Dpc);
1004: UNREFERENCED_PARAMETER(SystemContext1);
1005: UNREFERENCED_PARAMETER(SystemContext2);
1006:
1007: IoAcquireCancelSpinLock(&OldIrql);
1008:
1009: SerialTryToCompleteCurrent(
1010: Extension,
1011: SerialGrabWriteFromIsr,
1012: OldIrql,
1013: STATUS_TIMEOUT,
1014: &Extension->CurrentWriteIrp,
1015: &Extension->WriteQueue,
1016: NULL,
1017: &Extension->WriteRequestTotalTimer,
1018: SerialStartWrite,
1019: SerialGetNextWrite
1020: );
1021:
1022: }
1023:
1024: BOOLEAN
1025: SerialGrabWriteFromIsr(
1026: IN PVOID Context
1027: )
1028:
1029: /*++
1030:
1031: Routine Description:
1032:
1033:
1034: This routine is used to grab the current irp, which could be timing
1035: out or canceling, from the ISR
1036:
1037: NOTE: This routine is being called from KeSynchronizeExecution.
1038:
1039: NOTE: This routine assumes that the cancel spin lock is held
1040: when this routine is called.
1041:
1042: Arguments:
1043:
1044: Context - Really a pointer to the device extension.
1045:
1046: Return Value:
1047:
1048: Always false.
1049:
1050: --*/
1051:
1052: {
1053:
1054: PSERIAL_DEVICE_EXTENSION Extension = Context;
1055:
1056: //
1057: // Check if the write length is non-zero. If it is non-zero
1058: // then the ISR still owns the irp. We calculate the the number
1059: // of characters written and update the information field of the
1060: // irp with the characters written. We then clear the write length
1061: // the isr sees.
1062: //
1063:
1064: if (Extension->WriteLength) {
1065:
1066: //
1067: // We could have an xoff counter masquerading as a
1068: // write irp. If so, don't update the write length.
1069: //
1070:
1071: if (IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp)
1072: ->MajorFunction == IRP_MJ_WRITE) {
1073:
1074: Extension->CurrentWriteIrp->IoStatus.Information =
1075: IoGetCurrentIrpStackLocation(
1076: Extension->CurrentWriteIrp
1077: )->Parameters.Write.Length -
1078: Extension->WriteLength;
1079:
1080: } else {
1081:
1082: Extension->CurrentWriteIrp->IoStatus.Information = 0;
1083:
1084: }
1085:
1086: //
1087: // Since the isr no longer references this irp, we can
1088: // decrement it's reference count.
1089: //
1090:
1091: SERIAL_DEC_REFERENCE(Extension->CurrentWriteIrp);
1092:
1093: Extension->WriteLength = 0;
1094:
1095: }
1096:
1097: return FALSE;
1098:
1099: }
1100:
1101: BOOLEAN
1102: SerialGrabXoffFromIsr(
1103: IN PVOID Context
1104: )
1105:
1106: /*++
1107:
1108: Routine Description:
1109:
1110: This routine is used to grab an xoff counter irp from the
1111: isr when it is no longer masquerading as a write irp. This
1112: routine is called by the cancel and timeout code for the
1113: xoff counter ioctl.
1114:
1115:
1116: NOTE: This routine is being called from KeSynchronizeExecution.
1117:
1118: NOTE: This routine assumes that the cancel spin lock is held
1119: when this routine is called.
1120:
1121: Arguments:
1122:
1123: Context - Really a pointer to the device extension.
1124:
1125: Return Value:
1126:
1127: Always false.
1128:
1129: --*/
1130:
1131: {
1132:
1133: PSERIAL_DEVICE_EXTENSION Extension = Context;
1134:
1135: if (Extension->CountSinceXoff) {
1136:
1137: //
1138: // This is only non-zero when there actually is a Xoff ioctl
1139: // counting down.
1140: //
1141:
1142: Extension->CountSinceXoff = 0;
1143:
1144: //
1145: // We decrement the count since the isr no longer owns
1146: // the irp.
1147: //
1148:
1149: SERIAL_DEC_REFERENCE(Extension->CurrentXoffIrp);
1150:
1151: }
1152:
1153: return FALSE;
1154:
1155: }
1156:
1157: VOID
1158: SerialCompleteXoff(
1159: IN PKDPC Dpc,
1160: IN PVOID DeferredContext,
1161: IN PVOID SystemContext1,
1162: IN PVOID SystemContext2
1163: )
1164:
1165: /*++
1166:
1167: Routine Description:
1168:
1169: This routine is merely used to truely complete an xoff counter irp. It
1170: assumes that the status and the information fields of the irp are
1171: already correctly filled in.
1172:
1173: Arguments:
1174:
1175: Dpc - Not Used.
1176:
1177: DeferredContext - Really points to the device extension.
1178:
1179: SystemContext1 - Not Used.
1180:
1181: SystemContext2 - Not Used.
1182:
1183: Return Value:
1184:
1185: None.
1186:
1187: --*/
1188:
1189: {
1190:
1191: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
1192: KIRQL OldIrql;
1193:
1194: UNREFERENCED_PARAMETER(Dpc);
1195: UNREFERENCED_PARAMETER(SystemContext1);
1196: UNREFERENCED_PARAMETER(SystemContext2);
1197:
1198: IoAcquireCancelSpinLock(&OldIrql);
1199:
1200: //
1201: // Turn this irp back into the current write irp so
1202: // that it will start of any writes behind it.
1203: //
1204:
1205: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
1206:
1207: SerialTryToCompleteCurrent(
1208: Extension,
1209: NULL,
1210: OldIrql,
1211: STATUS_SUCCESS,
1212: &Extension->CurrentWriteIrp,
1213: &Extension->WriteQueue,
1214: NULL,
1215: &Extension->XoffCountTimer,
1216: SerialStartWrite,
1217: SerialGetNextWrite
1218: );
1219:
1220: }
1221:
1222: VOID
1223: SerialTimeoutXoff(
1224: IN PKDPC Dpc,
1225: IN PVOID DeferredContext,
1226: IN PVOID SystemContext1,
1227: IN PVOID SystemContext2
1228: )
1229:
1230: /*++
1231:
1232: Routine Description:
1233:
1234: This routine is merely used to truely complete an xoff counter irp,
1235: if its timer has run out.
1236:
1237: Arguments:
1238:
1239: Dpc - Not Used.
1240:
1241: DeferredContext - Really points to the device extension.
1242:
1243: SystemContext1 - Not Used.
1244:
1245: SystemContext2 - Not Used.
1246:
1247: Return Value:
1248:
1249: None.
1250:
1251: --*/
1252:
1253: {
1254:
1255: PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
1256: KIRQL OldIrql;
1257:
1258: UNREFERENCED_PARAMETER(Dpc);
1259: UNREFERENCED_PARAMETER(SystemContext1);
1260: UNREFERENCED_PARAMETER(SystemContext2);
1261:
1262: IoAcquireCancelSpinLock(&OldIrql);
1263:
1264: //
1265: // Turn this irp back into the current write irp so
1266: // that it will start of any writes behind it.
1267: //
1268:
1269: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
1270:
1271: SerialTryToCompleteCurrent(
1272: Extension,
1273: SerialGrabXoffFromIsr,
1274: OldIrql,
1275: STATUS_SERIAL_COUNTER_TIMEOUT,
1276: &Extension->CurrentWriteIrp,
1277: &Extension->WriteQueue,
1278: NULL,
1279: &Extension->XoffCountTimer,
1280: SerialStartWrite,
1281: SerialGetNextWrite
1282: );
1283:
1284: }
1285:
1286: VOID
1287: SerialCancelCurrentXoff(
1288: PDEVICE_OBJECT DeviceObject,
1289: PIRP Irp
1290: )
1291:
1292: /*++
1293:
1294: Routine Description:
1295:
1296: This routine is used to cancel the current write.
1297:
1298: Arguments:
1299:
1300: DeviceObject - Pointer to the device object for this device
1301:
1302: Irp - Pointer to the IRP to be canceled.
1303:
1304: Return Value:
1305:
1306: None.
1307:
1308: --*/
1309:
1310: {
1311:
1312: PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
1313:
1314: //
1315: // Turn this irp back into the current write irp so
1316: // that it will start of any writes behind it.
1317: //
1318:
1319: Extension->CurrentWriteIrp = Extension->CurrentXoffIrp;
1320:
1321: SerialTryToCompleteCurrent(
1322: Extension,
1323: SerialGrabXoffFromIsr,
1324: Irp->CancelIrql,
1325: STATUS_CANCELLED,
1326: &Extension->CurrentWriteIrp,
1327: &Extension->WriteQueue,
1328: NULL,
1329: &Extension->XoffCountTimer,
1330: SerialStartWrite,
1331: SerialGetNextWrite
1332: );
1333:
1334: }
1335:
1336: BOOLEAN
1337: SerialGiveXoffToIsr(
1338: IN PVOID Context
1339: )
1340:
1341: /*++
1342:
1343: Routine Description:
1344:
1345:
1346: This routine starts off the xoff counter. It merely
1347: has to set the xoff count and increment the reference
1348: count to denote that the isr has a reference to the irp.
1349:
1350: NOTE: This routine is called by KeSynchronizeExecution.
1351:
1352: NOTE: This routine assumes that it is called with the
1353: cancel spin lock held.
1354:
1355: Arguments:
1356:
1357: Context - Really a pointer to the device extension.
1358:
1359: Return Value:
1360:
1361: This routine always returns FALSE.
1362:
1363: --*/
1364:
1365: {
1366:
1367: PSERIAL_DEVICE_EXTENSION Extension = Context;
1368:
1369: //
1370: // The current stack location. This contains all of the
1371: // information we need to process this particular request.
1372: //
1373: PSERIAL_XOFF_COUNTER Xc =
1374: Extension->CurrentXoffIrp->AssociatedIrp.SystemBuffer;
1375:
1376: Extension->CountSinceXoff = Xc->Counter;
1377:
1378: //
1379: // The isr now has a reference to the irp.
1380: //
1381:
1382: SERIAL_INC_REFERENCE(Extension->CurrentXoffIrp);
1383:
1384: return FALSE;
1385:
1386: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.