|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: isr.c
8:
9: Abstract:
10:
11: This module contains the interrupt service routine for the
12: 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: SerialSharerIsr(
36: IN PKINTERRUPT InterruptObject,
37: IN PVOID Context
38: )
39:
40: /*++
41:
42: Routine Description:
43:
44: This is the isr that the system will call if there are any
45: serial devices sharing the same interrupt and they aren't
46: all confined to one multiport card. This routine traverses
47: a linked list structure that contains a pointer to a more
48: refined isr and context that will indicate whether one of
49: the ports on this interrupt actually was interrupting.
50:
51: Arguments:
52:
53: InterruptObject - Points to the interrupt object declared for this
54: device. We *do not* use this parameter.
55:
56: Context - Pointer to a linked list of contextes and isrs.
57: device.
58:
59: Return Value:
60:
61: This function will return TRUE if a serial port using this
62: interrupt was the source of this interrupt, FALSE otherwise.
63:
64: --*/
65:
66: {
67:
68: BOOLEAN servicedAnInterrupt = FALSE;
69: BOOLEAN thisPassServiced;
70: PLIST_ENTRY interruptEntry = Context;
71: PLIST_ENTRY firstInterruptEntry = interruptEntry;
72:
73: do {
74:
75: thisPassServiced = FALSE;
76: do {
77:
78: PSERIAL_DEVICE_EXTENSION extension = CONTAINING_RECORD(
79: interruptEntry,
80: SERIAL_DEVICE_EXTENSION,
81: TopLevelSharers
82: );
83:
84: thisPassServiced |= extension->TopLevelOurIsr(
85: InterruptObject,
86: extension->TopLevelOurIsrContext
87: );
88:
89: servicedAnInterrupt |= thisPassServiced;
90: interruptEntry = interruptEntry->Flink;
91:
92: } while (interruptEntry != firstInterruptEntry);
93:
94: } while (thisPassServiced);
95:
96: return servicedAnInterrupt;
97:
98: }
99:
100: BOOLEAN
101: SerialIndexedMultiportIsr(
102: IN PKINTERRUPT InterruptObject,
103: IN PVOID Context
104: )
105:
106: /*++
107:
108: Routine Description:
109:
110: This routine is used to figure out if a port on a multiport
111: card is the source of an interrupt. If so, this routine
112: uses a dispatch structure to actually call the normal isr
113: to process the interrupt.
114:
115: NOTE: This routine is peculiar to Digiboard interrupt status registers.
116:
117: Arguments:
118:
119: InterruptObject - Points to the interrupt object declared for this
120: device. We *do not* use this parameter.
121:
122: Context - Points to a dispatch structure that contains the
123: device extension of each port on this multiport card.
124:
125: Return Value:
126:
127:
128: This function will return TRUE if a serial port using this
129: interrupt was the source of this interrupt, FALSE otherwise.
130:
131: --*/
132:
133: {
134:
135: BOOLEAN servicedAnInterrupt = FALSE;
136: BOOLEAN thisStatusReadServiced;
137: PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
138: ULONG whichPort;
139: UCHAR statusRegister;
140:
141: do {
142:
143: thisStatusReadServiced = FALSE;
144: statusRegister = READ_PORT_UCHAR(
145: dispatch->InterruptStatus
146: );
147:
148: whichPort = statusRegister & 0x07;
149:
150: //
151: // We test against 0xff, which signals that no port
152: // is interruping. The reason 0xff (rather than 0)
153: // is that that would indicate the 0th (first) port
154: // or the 0th daisy chained card.
155: //
156:
157: if (statusRegister != 0xff) {
158:
159: if (dispatch->Extensions[whichPort]) {
160:
161: thisStatusReadServiced = SerialISR(
162: InterruptObject,
163: dispatch->Extensions[whichPort]
164: );
165:
166: servicedAnInterrupt |= thisStatusReadServiced;
167:
168: }
169:
170: }
171:
172: } while (thisStatusReadServiced);
173:
174: return servicedAnInterrupt;
175:
176: }
177:
178: BOOLEAN
179: SerialBitMappedMultiportIsr(
180: IN PKINTERRUPT InterruptObject,
181: IN PVOID Context
182: )
183:
184: /*++
185:
186: Routine Description:
187:
188: This routine is used to figure out if a port on a multiport
189: card is the source of an interrupt. If so, this routine
190: uses a dispatch structure to actually call the normal isr
191: to process the interrupt.
192:
193: NOTE: This routine is peculiar to status registers that use
194: a bitmask to denote the interrupting port.
195:
196: Arguments:
197:
198: InterruptObject - Points to the interrupt object declared for this
199: device. We *do not* use this parameter.
200:
201: Context - Points to a dispatch structure that contains the
202: device extension of each port on this multiport card.
203:
204: Return Value:
205:
206:
207: This function will return TRUE if a serial port using this
208: interrupt was the source of this interrupt, FALSE otherwise.
209:
210: --*/
211:
212: {
213:
214: BOOLEAN servicedAnInterrupt = FALSE;
215: PSERIAL_MULTIPORT_DISPATCH dispatch = Context;
216: ULONG whichPort;
217: UCHAR statusRegister;
218:
219: do {
220:
221: statusRegister = READ_PORT_UCHAR(
222: dispatch->InterruptStatus
223: );
224: statusRegister &= dispatch->UsablePortMask;
225:
226: if (statusRegister) {
227:
228: if (statusRegister & 0x0f) {
229:
230: if (statusRegister & 0x03) {
231:
232: if (statusRegister & 1) {
233:
234: whichPort = 0;
235:
236: } else {
237:
238: whichPort = 1;
239:
240: }
241:
242: } else {
243:
244: if (statusRegister & 0x04) {
245:
246: whichPort = 2;
247:
248: } else {
249:
250: whichPort = 3;
251:
252: }
253:
254: }
255:
256: } else {
257:
258: if (statusRegister & 0x30) {
259:
260: if (statusRegister & 0x10) {
261:
262: whichPort = 4;
263:
264: } else {
265:
266: whichPort = 5;
267:
268: }
269:
270: } else {
271:
272: if (statusRegister & 0x40) {
273:
274: whichPort = 6;
275:
276: } else {
277:
278: whichPort = 7;
279:
280: }
281:
282: }
283:
284: }
285:
286: if (dispatch->Extensions[whichPort]) {
287:
288: if (SerialISR(
289: InterruptObject,
290: dispatch->Extensions[whichPort]
291: )) {
292:
293: servicedAnInterrupt = TRUE;
294:
295: }
296:
297: }
298:
299: }
300:
301: } while (statusRegister);
302:
303: return servicedAnInterrupt;
304:
305: }
306:
307: BOOLEAN
308: SerialISR(
309: IN PKINTERRUPT InterruptObject,
310: IN PVOID Context
311: )
312:
313: /*++
314:
315: Routine Description:
316:
317: This is the interrupt service routine for the serial port driver.
318: It will determine whether the serial port is the source of this
319: interrupt. If it is, then this routine will do the minimum of
320: processing to quiet the interrupt. It will store any information
321: necessary for later processing.
322:
323: Arguments:
324:
325: InterruptObject - Points to the interrupt object declared for this
326: device. We *do not* use this parameter.
327:
328: Context - This is really a pointer to the device extension for this
329: device.
330:
331: Return Value:
332:
333: This function will return TRUE if the serial port is the source
334: of this interrupt, FALSE otherwise.
335:
336: --*/
337:
338: {
339:
340: //
341: // Holds the information specific to handling this device.
342: //
343: PSERIAL_DEVICE_EXTENSION Extension = Context;
344:
345: //
346: // Holds the contents of the interrupt identification record.
347: // A low bit of zero in this register indicates that there is
348: // an interrupt pending on this device.
349: //
350: UCHAR InterruptIdReg;
351:
352: //
353: // Will hold whether we've serviced any interrupt causes in this
354: // routine.
355: //
356: BOOLEAN ServicedAnInterrupt;
357:
358: UNREFERENCED_PARAMETER(InterruptObject);
359:
360: //
361: // Make sure we have an interrupt pending. If we do then
362: // we need to make sure that the device is open. If the
363: // device isn't open then quiet the device. Note that
364: // if the device isn't opened when we enter this routine
365: // it can't open while we're in it.
366: //
367:
368: InterruptIdReg = READ_INTERRUPT_ID_REG(Extension->Controller);
369:
370: if (InterruptIdReg & SERIAL_IIR_NO_INTERRUPT_PENDING) {
371:
372: ServicedAnInterrupt = FALSE;
373:
374: } else if (!Extension->DeviceIsOpened) {
375:
376: //
377: // We got an interrupt with the device being closed. This
378: // is not unlikely with a serial device. We just quite
379: // keep servicing the causes until it calms down.
380: //
381:
382: ServicedAnInterrupt = TRUE;
383: do {
384:
385: InterruptIdReg &= (~SERIAL_IIR_FIFOS_ENABLED);
386: switch (InterruptIdReg) {
387:
388: case SERIAL_IIR_RLS: {
389:
390: READ_LINE_STATUS(Extension->Controller);
391: break;
392:
393: }
394:
395: case SERIAL_IIR_RDA:
396: case SERIAL_IIR_CTI: {
397:
398:
399: READ_RECEIVE_BUFFER(Extension->Controller);
400: break;
401:
402: }
403:
404: case SERIAL_IIR_THR: {
405:
406: //
407: // Alread clear from reading the iir.
408: //
409: // We want to keep close track of whether
410: // the holding register is empty.
411: //
412:
413: Extension->HoldingEmpty = TRUE;
414: break;
415:
416: }
417:
418: case SERIAL_IIR_MS: {
419:
420: READ_MODEM_STATUS(Extension->Controller);
421: break;
422:
423: }
424:
425: default: {
426:
427: ASSERT(FALSE);
428: break;
429:
430: }
431:
432: }
433:
434: } while (!((InterruptIdReg =
435: READ_INTERRUPT_ID_REG(Extension->Controller))
436: & SERIAL_IIR_NO_INTERRUPT_PENDING));
437: } else {
438:
439: ServicedAnInterrupt = TRUE;
440: do {
441:
442: //
443: // We only care about bits that can denote an interrupt.
444: //
445:
446: InterruptIdReg &= SERIAL_IIR_RLS | SERIAL_IIR_RDA |
447: SERIAL_IIR_CTI | SERIAL_IIR_THR |
448: SERIAL_IIR_MS;
449:
450: //
451: // We have an interrupt. We look for interrupt causes
452: // in priority order. The presence of a higher interrupt
453: // will mask out causes of a lower priority. When we service
454: // and quiet a higher priority interrupt we then need to check
455: // the interrupt causes to see if a new interrupt cause is
456: // present.
457: //
458:
459: switch (InterruptIdReg) {
460:
461: case SERIAL_IIR_RLS: {
462:
463: SerialProcessLSR(Extension);
464:
465: break;
466:
467: }
468:
469: case SERIAL_IIR_RDA:
470: case SERIAL_IIR_CTI:
471:
472: {
473:
474: //
475: // Reading the receive buffer will quiet this interrupt.
476: //
477: // It may also reveal a new interrupt cause.
478: //
479: UCHAR ReceivedChar;
480:
481: do {
482:
483: ReceivedChar =
484: READ_RECEIVE_BUFFER(Extension->Controller);
485:
486: ReceivedChar &= Extension->ValidDataMask;
487:
488: if (!ReceivedChar &&
489: (Extension->HandFlow.FlowReplace &
490: SERIAL_NULL_STRIPPING)) {
491:
492: //
493: // If what we got is a null character
494: // and we're doing null stripping, then
495: // we simply act as if we didn't see it.
496: //
497:
498: goto ReceiveDoLineStatus;
499:
500: }
501:
502: if ((Extension->HandFlow.FlowReplace &
503: SERIAL_AUTO_TRANSMIT) &&
504: ((ReceivedChar ==
505: Extension->SpecialChars.XonChar) ||
506: (ReceivedChar ==
507: Extension->SpecialChars.XoffChar))) {
508:
509: //
510: // No matter what happens this character
511: // will never get seen by the app.
512: //
513:
514: if (ReceivedChar ==
515: Extension->SpecialChars.XoffChar) {
516:
517: Extension->TXHolding |= SERIAL_TX_XOFF;
518:
519: if ((Extension->HandFlow.FlowReplace &
520: SERIAL_RTS_MASK) ==
521: SERIAL_TRANSMIT_TOGGLE) {
522:
523: KeInsertQueueDpc(
524: &Extension->StartTimerLowerRTSDpc,
525: NULL,
526: NULL
527: )?Extension->CountOfTryingToLowerRTS++:0;
528:
529: }
530:
531: } else {
532:
533: if (Extension->TXHolding & SERIAL_TX_XOFF) {
534:
535: //
536: // We've got the xon. Cause the
537: // transmission to restart.
538: //
539: // Prod the transmit.
540: //
541:
542: SerialProdXonXoff(
543: Extension,
544: TRUE
545: );
546:
547: }
548:
549: }
550:
551: goto ReceiveDoLineStatus;
552:
553: }
554:
555: //
556: // Check to see if we should note
557: // the receive character or special
558: // character event.
559: //
560:
561: if (Extension->IsrWaitMask) {
562:
563: if (Extension->IsrWaitMask &
564: SERIAL_EV_RXCHAR) {
565:
566: Extension->HistoryMask |= SERIAL_EV_RXCHAR;
567:
568: }
569:
570: if ((Extension->IsrWaitMask &
571: SERIAL_EV_RXFLAG) &&
572: (Extension->SpecialChars.EventChar ==
573: ReceivedChar)) {
574:
575: Extension->HistoryMask |= SERIAL_EV_RXFLAG;
576:
577: }
578:
579: if (Extension->IrpMaskLocation &&
580: Extension->HistoryMask) {
581:
582: *Extension->IrpMaskLocation =
583: Extension->HistoryMask;
584: Extension->IrpMaskLocation = NULL;
585: Extension->HistoryMask = 0;
586:
587: Extension->CurrentWaitIrp->
588: IoStatus.Information = sizeof(ULONG);
589: KeInsertQueueDpc(
590: &Extension->CommWaitDpc,
591: NULL,
592: NULL
593: );
594:
595: }
596:
597: }
598:
599: SerialPutChar(
600: Extension,
601: ReceivedChar
602: );
603:
604: //
605: // If we're doing line status and modem
606: // status insertion then we need to insert
607: // a zero following the character we just
608: // placed into the buffer to mark that this
609: // was reception of what we are using to
610: // escape.
611: //
612:
613: if (Extension->EscapeChar &&
614: (Extension->EscapeChar ==
615: ReceivedChar)) {
616:
617: SerialPutChar(
618: Extension,
619: SERIAL_LSRMST_ESCAPE
620: );
621:
622: }
623:
624:
625: ReceiveDoLineStatus: ;
626:
627: if (!(SerialProcessLSR(Extension) &
628: SERIAL_LSR_DR)) {
629:
630: //
631: // No more characters, get out of the
632: // loop.
633: //
634:
635: break;
636:
637: }
638:
639: } while (TRUE);
640:
641: break;
642:
643: }
644:
645: case SERIAL_IIR_THR: {
646:
647: Extension->HoldingEmpty = TRUE;
648:
649: if (Extension->WriteLength |
650: Extension->TransmitImmediate |
651: Extension->SendXoffChar |
652: Extension->SendXonChar) {
653:
654: //
655: // Even though all of the characters being
656: // sent haven't all been sent, this variable
657: // will be checked when the transmit queue is
658: // empty. If it is still true and there is a
659: // wait on the transmit queue being empty then
660: // we know we finished transmitting all characters
661: // following the initiation of the wait since
662: // the code that initiates the wait will set
663: // this variable to false.
664: //
665: // One reason it could be false is that
666: // the writes were cancelled before they
667: // actually started, or that the writes
668: // failed due to timeouts. This variable
669: // basically says a character was written
670: // by the isr at some point following the
671: // initiation of the wait.
672: //
673:
674: Extension->EmptiedTransmit = TRUE;
675:
676: //
677: // If we have output flow control based on
678: // the modem status lines, then we have to do
679: // all the modem work before we output each
680: // character. (Otherwise we might miss a
681: // status line change.)
682: //
683:
684: if (Extension->HandFlow.ControlHandShake &
685: SERIAL_OUT_HANDSHAKEMASK) {
686:
687: SerialHandleModemUpdate(
688: Extension,
689: TRUE
690: );
691:
692: }
693:
694: //
695: // We can only send the xon character if
696: // the only reason we are holding is because
697: // of the xoff. (Hardware flow control or
698: // sending break preclude putting a new character
699: // on the wire.)
700: //
701:
702: if (Extension->SendXonChar &&
703: !(Extension->TXHolding & ~SERIAL_TX_XOFF)) {
704:
705: if ((Extension->HandFlow.FlowReplace &
706: SERIAL_RTS_MASK) ==
707: SERIAL_TRANSMIT_TOGGLE) {
708:
709: //
710: // We have to raise if we're sending
711: // this character.
712: //
713:
714: SerialSetRTS(Extension);
715:
716: WRITE_TRANSMIT_HOLDING(
717: Extension->Controller,
718: Extension->SpecialChars.XonChar
719: );
720:
721: KeInsertQueueDpc(
722: &Extension->StartTimerLowerRTSDpc,
723: NULL,
724: NULL
725: )?Extension->CountOfTryingToLowerRTS++:0;
726:
727: } else {
728:
729: WRITE_TRANSMIT_HOLDING(
730: Extension->Controller,
731: Extension->SpecialChars.XonChar
732: );
733:
734: }
735:
736:
737: Extension->SendXonChar = FALSE;
738: Extension->HoldingEmpty = FALSE;
739:
740: //
741: // If we send an xon, by definition we
742: // can't be holding by Xoff.
743: //
744:
745: Extension->TXHolding &= ~SERIAL_TX_XOFF;
746:
747: //
748: // If we are sending an xon char then
749: // by definition we can't be "holding"
750: // up reception by Xoff.
751: //
752:
753: Extension->RXHolding &= ~SERIAL_RX_XOFF;
754:
755: } else if (Extension->SendXoffChar &&
756: !Extension->TXHolding) {
757:
758: if ((Extension->HandFlow.FlowReplace &
759: SERIAL_RTS_MASK) ==
760: SERIAL_TRANSMIT_TOGGLE) {
761:
762: //
763: // We have to raise if we're sending
764: // this character.
765: //
766:
767: SerialSetRTS(Extension);
768:
769: WRITE_TRANSMIT_HOLDING(
770: Extension->Controller,
771: Extension->SpecialChars.XoffChar
772: );
773:
774: KeInsertQueueDpc(
775: &Extension->StartTimerLowerRTSDpc,
776: NULL,
777: NULL
778: )?Extension->CountOfTryingToLowerRTS++:0;
779:
780: } else {
781:
782: WRITE_TRANSMIT_HOLDING(
783: Extension->Controller,
784: Extension->SpecialChars.XoffChar
785: );
786:
787: }
788:
789: //
790: // We can't be sending an Xoff character
791: // if the transmission is already held
792: // up because of Xoff. Therefore, if we
793: // are holding then we can't send the char.
794: //
795:
796: //
797: // If the application has set xoff continue
798: // mode then we don't actually stop sending
799: // characters if we send an xoff to the other
800: // side.
801: //
802:
803: if (!(Extension->HandFlow.FlowReplace &
804: SERIAL_XOFF_CONTINUE)) {
805:
806: Extension->TXHolding |= SERIAL_TX_XOFF;
807:
808: if ((Extension->HandFlow.FlowReplace &
809: SERIAL_RTS_MASK) ==
810: SERIAL_TRANSMIT_TOGGLE) {
811:
812: KeInsertQueueDpc(
813: &Extension->StartTimerLowerRTSDpc,
814: NULL,
815: NULL
816: )?Extension->CountOfTryingToLowerRTS++:0;
817:
818: }
819:
820: }
821:
822: Extension->SendXoffChar = FALSE;
823: Extension->HoldingEmpty = FALSE;
824:
825: //
826: // Even if transmission is being held
827: // up, we should still transmit an immediate
828: // character if all that is holding us
829: // up is xon/xoff (OS/2 rules).
830: //
831:
832: } else if (Extension->TransmitImmediate &&
833: (!Extension->TXHolding ||
834: (Extension->TXHolding == SERIAL_TX_XOFF)
835: )) {
836:
837: Extension->TransmitImmediate = FALSE;
838:
839: if ((Extension->HandFlow.FlowReplace &
840: SERIAL_RTS_MASK) ==
841: SERIAL_TRANSMIT_TOGGLE) {
842:
843: //
844: // We have to raise if we're sending
845: // this character.
846: //
847:
848: SerialSetRTS(Extension);
849:
850: WRITE_TRANSMIT_HOLDING(
851: Extension->Controller,
852: Extension->ImmediateChar
853: );
854:
855: KeInsertQueueDpc(
856: &Extension->StartTimerLowerRTSDpc,
857: NULL,
858: NULL
859: )?Extension->CountOfTryingToLowerRTS++:0;
860:
861: } else {
862:
863: WRITE_TRANSMIT_HOLDING(
864: Extension->Controller,
865: Extension->ImmediateChar
866: );
867:
868: }
869:
870: Extension->HoldingEmpty = FALSE;
871:
872: KeInsertQueueDpc(
873: &Extension->CompleteImmediateDpc,
874: NULL,
875: NULL
876: );
877:
878: } else if (!Extension->TXHolding) {
879:
880: if ((Extension->HandFlow.FlowReplace &
881: SERIAL_RTS_MASK) ==
882: SERIAL_TRANSMIT_TOGGLE) {
883:
884: //
885: // We have to raise if we're sending
886: // this character.
887: //
888:
889: SerialSetRTS(Extension);
890:
891: WRITE_TRANSMIT_HOLDING(
892: Extension->Controller,
893: *(Extension->WriteCurrentChar)
894: );
895:
896: KeInsertQueueDpc(
897: &Extension->StartTimerLowerRTSDpc,
898: NULL,
899: NULL
900: )?Extension->CountOfTryingToLowerRTS++:0;
901:
902: } else {
903:
904: WRITE_TRANSMIT_HOLDING(
905: Extension->Controller,
906: *(Extension->WriteCurrentChar)
907: );
908:
909: }
910:
911: Extension->HoldingEmpty = FALSE;
912: Extension->WriteCurrentChar++;
913: Extension->WriteLength--;
914:
915: if (!Extension->WriteLength) {
916:
917: PIO_STACK_LOCATION IrpSp;
918: //
919: // No More characters left. This
920: // write is complete. Take care
921: // when updating the information field,
922: // we could have an xoff counter masquerading
923: // as a write irp.
924: //
925:
926: IrpSp = IoGetCurrentIrpStackLocation(
927: Extension->CurrentWriteIrp
928: );
929:
930: Extension->CurrentWriteIrp->
931: IoStatus.Information =
932: (IrpSp->MajorFunction == IRP_MJ_WRITE)?
933: (IrpSp->Parameters.Write.Length):
934: (1);
935:
936: KeInsertQueueDpc(
937: &Extension->CompleteWriteDpc,
938: NULL,
939: NULL
940: );
941:
942: }
943:
944: }
945:
946: }
947:
948: break;
949:
950: }
951:
952: case SERIAL_IIR_MS: {
953:
954: SerialHandleModemUpdate(
955: Extension,
956: FALSE
957: );
958:
959: break;
960:
961: }
962:
963: }
964:
965: } while (!((InterruptIdReg =
966: READ_INTERRUPT_ID_REG(Extension->Controller))
967: & SERIAL_IIR_NO_INTERRUPT_PENDING));
968:
969: }
970:
971: return ServicedAnInterrupt;
972:
973: }
974:
975: VOID
976: SerialPutChar(
977: IN PSERIAL_DEVICE_EXTENSION Extension,
978: IN UCHAR CharToPut
979: )
980:
981: /*++
982:
983: Routine Description:
984:
985: This routine, which only runs at device level, takes care of
986: placing a character into the typeahead (receive) buffer.
987:
988: Arguments:
989:
990: Extension - The serial device extension.
991:
992: Return Value:
993:
994: None.
995:
996: --*/
997:
998: {
999:
1000: //
1001: // If we have dsr sensitivity enabled then
1002: // we need to check the modem status register
1003: // to see if it has changed.
1004: //
1005:
1006: if (Extension->HandFlow.ControlHandShake &
1007: SERIAL_DSR_SENSITIVITY) {
1008:
1009: SerialHandleModemUpdate(
1010: Extension,
1011: FALSE
1012: );
1013:
1014: if (Extension->RXHolding & SERIAL_RX_DSR) {
1015:
1016: //
1017: // We simply act as if we haven't
1018: // seen the character if we have dsr
1019: // sensitivity and the dsr line is low.
1020: //
1021:
1022: return;
1023:
1024: }
1025:
1026: }
1027:
1028: //
1029: // If the xoff counter is non-zero then decrement it.
1030: // If the counter then goes to zero, complete that irp.
1031: //
1032:
1033: if (Extension->CountSinceXoff) {
1034:
1035: Extension->CountSinceXoff--;
1036:
1037: if (!Extension->CountSinceXoff) {
1038:
1039: Extension->CurrentXoffIrp->IoStatus.Status = STATUS_SUCCESS;
1040: Extension->CurrentXoffIrp->IoStatus.Information = 0;
1041: KeInsertQueueDpc(
1042: &Extension->XoffCountCompleteDpc,
1043: NULL,
1044: NULL
1045: );
1046:
1047: }
1048:
1049: }
1050:
1051: //
1052: // Check to see if we are copying into the
1053: // users buffer or into the interrupt buffer.
1054: //
1055: // If we are copying into the user buffer
1056: // then we know there is always room for one more.
1057: // (We know this because if there wasn't room
1058: // then that read would have completed and we
1059: // would be using the interrupt buffer.)
1060: //
1061: // If we are copying into the interrupt buffer
1062: // then we will need to check if we have enough
1063: // room.
1064: //
1065:
1066: if (Extension->ReadBufferBase !=
1067: Extension->InterruptReadBuffer) {
1068:
1069: //
1070: // Increment the following value so
1071: // that the interval timer (if one exists
1072: // for this read) can know that a character
1073: // has been read.
1074: //
1075:
1076: Extension->ReadByIsr++;
1077:
1078: //
1079: // We are in the user buffer. Place the
1080: // character into the buffer. See if the
1081: // read is complete.
1082: //
1083:
1084: *Extension->CurrentCharSlot = CharToPut;
1085:
1086: if (Extension->CurrentCharSlot ==
1087: Extension->LastCharSlot) {
1088:
1089: //
1090: // We've filled up the users buffer.
1091: // Switch back to the interrupt buffer
1092: // and send off a DPC to Complete the read.
1093: //
1094: // It is inherent that when we were using
1095: // a user buffer that the interrupt buffer
1096: // was empty.
1097: //
1098:
1099: Extension->ReadBufferBase =
1100: Extension->InterruptReadBuffer;
1101: Extension->CurrentCharSlot =
1102: Extension->InterruptReadBuffer;
1103: Extension->FirstReadableChar =
1104: Extension->InterruptReadBuffer;
1105: Extension->LastCharSlot =
1106: Extension->InterruptReadBuffer +
1107: (Extension->BufferSize - 1);
1108: Extension->CharsInInterruptBuffer = 0;
1109:
1110: Extension->CurrentReadIrp->IoStatus.Information =
1111: IoGetCurrentIrpStackLocation(
1112: Extension->CurrentReadIrp
1113: )->Parameters.Read.Length;
1114:
1115: KeInsertQueueDpc(
1116: &Extension->CompleteReadDpc,
1117: NULL,
1118: NULL
1119: );
1120:
1121: } else {
1122:
1123: //
1124: // Not done with the users read.
1125: //
1126:
1127: Extension->CurrentCharSlot++;
1128:
1129: }
1130:
1131: } else {
1132:
1133: //
1134: // We need to see if we reached our flow
1135: // control threshold. If we have then
1136: // we turn on whatever flow control the
1137: // owner has specified. If no flow
1138: // control was specified, well..., we keep
1139: // trying to receive characters and hope that
1140: // we have enough room. Note that no matter
1141: // what flow control protocol we are using, it
1142: // will not prevent us from reading whatever
1143: // characters are available.
1144: //
1145:
1146: if ((Extension->HandFlow.ControlHandShake
1147: & SERIAL_DTR_MASK) ==
1148: SERIAL_DTR_HANDSHAKE) {
1149:
1150: //
1151: // If we are already doing a
1152: // dtr hold then we don't have
1153: // to do anything else.
1154: //
1155:
1156: if (!(Extension->RXHolding &
1157: SERIAL_RX_DTR)) {
1158:
1159: if ((Extension->BufferSize -
1160: Extension->HandFlow.XoffLimit)
1161: <= (Extension->CharsInInterruptBuffer+1)) {
1162:
1163: Extension->RXHolding |= SERIAL_RX_DTR;
1164:
1165: SerialClrDTR(Extension);
1166:
1167: }
1168:
1169: }
1170:
1171: }
1172:
1173: if ((Extension->HandFlow.FlowReplace
1174: & SERIAL_RTS_MASK) ==
1175: SERIAL_RTS_HANDSHAKE) {
1176:
1177: //
1178: // If we are already doing a
1179: // rts hold then we don't have
1180: // to do anything else.
1181: //
1182:
1183: if (!(Extension->RXHolding &
1184: SERIAL_RX_RTS)) {
1185:
1186: if ((Extension->BufferSize -
1187: Extension->HandFlow.XoffLimit)
1188: <= (Extension->CharsInInterruptBuffer+1)) {
1189:
1190: Extension->RXHolding |= SERIAL_RX_RTS;
1191:
1192: SerialClrRTS(Extension);
1193:
1194: }
1195:
1196: }
1197:
1198: }
1199:
1200: if (Extension->HandFlow.FlowReplace &
1201: SERIAL_AUTO_RECEIVE) {
1202:
1203: //
1204: // If we are already doing a
1205: // xoff hold then we don't have
1206: // to do anything else.
1207: //
1208:
1209: if (!(Extension->RXHolding &
1210: SERIAL_RX_XOFF)) {
1211:
1212: if ((Extension->BufferSize -
1213: Extension->HandFlow.XoffLimit)
1214: <= (Extension->CharsInInterruptBuffer+1)) {
1215:
1216: Extension->RXHolding |= SERIAL_RX_XOFF;
1217:
1218: //
1219: // If necessary cause an
1220: // off to be sent.
1221: //
1222:
1223: SerialProdXonXoff(
1224: Extension,
1225: FALSE
1226: );
1227:
1228: }
1229:
1230: }
1231:
1232: }
1233:
1234: if (Extension->CharsInInterruptBuffer <
1235: Extension->BufferSize) {
1236:
1237: *Extension->CurrentCharSlot = CharToPut;
1238: Extension->CharsInInterruptBuffer++;
1239:
1240: //
1241: // If we've become 80% full on this character
1242: // and this is an interesting event, note it.
1243: //
1244:
1245: if (Extension->CharsInInterruptBuffer ==
1246: Extension->BufferSizePt8) {
1247:
1248: if (Extension->IsrWaitMask &
1249: SERIAL_EV_RX80FULL) {
1250:
1251: Extension->HistoryMask |= SERIAL_EV_RX80FULL;
1252:
1253: if (Extension->IrpMaskLocation) {
1254:
1255: *Extension->IrpMaskLocation =
1256: Extension->HistoryMask;
1257: Extension->IrpMaskLocation = NULL;
1258: Extension->HistoryMask = 0;
1259:
1260: Extension->CurrentWaitIrp->
1261: IoStatus.Information = sizeof(ULONG);
1262: KeInsertQueueDpc(
1263: &Extension->CommWaitDpc,
1264: NULL,
1265: NULL
1266: );
1267:
1268: }
1269:
1270: }
1271:
1272: }
1273:
1274: //
1275: // Point to the next available space
1276: // for a received character. Make sure
1277: // that we wrap around to the beginning
1278: // of the buffer if this last character
1279: // received was placed at the last slot
1280: // in the buffer.
1281: //
1282:
1283: if (Extension->CurrentCharSlot ==
1284: Extension->LastCharSlot) {
1285:
1286: Extension->CurrentCharSlot =
1287: Extension->InterruptReadBuffer;
1288:
1289: } else {
1290:
1291: Extension->CurrentCharSlot++;
1292:
1293: }
1294:
1295: } else {
1296:
1297: //
1298: // We have a new character but no room for it.
1299: //
1300:
1301: Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
1302:
1303: if (Extension->HandFlow.FlowReplace &
1304: SERIAL_ERROR_CHAR) {
1305:
1306: //
1307: // Place the error character into the last
1308: // valid place for a character. Be careful!,
1309: // that place might not be the previous location!
1310: //
1311:
1312: if (Extension->CurrentCharSlot ==
1313: Extension->InterruptReadBuffer) {
1314:
1315: *(Extension->InterruptReadBuffer+
1316: (Extension->BufferSize-1)) =
1317: Extension->SpecialChars.ErrorChar;
1318:
1319: } else {
1320:
1321: *(Extension->CurrentCharSlot-1) =
1322: Extension->SpecialChars.ErrorChar;
1323:
1324: }
1325:
1326: }
1327:
1328: //
1329: // If the application has requested it, abort all reads
1330: // and writes on an error.
1331: //
1332:
1333: if (Extension->HandFlow.ControlHandShake &
1334: SERIAL_ERROR_ABORT) {
1335:
1336: KeInsertQueueDpc(
1337: &Extension->CommErrorDpc,
1338: NULL,
1339: NULL
1340: );
1341:
1342: }
1343:
1344: }
1345:
1346: }
1347:
1348: }
1349:
1350: UCHAR
1351: SerialProcessLSR(
1352: IN PSERIAL_DEVICE_EXTENSION Extension
1353: )
1354:
1355: /*++
1356:
1357: Routine Description:
1358:
1359: This routine, which only runs at device level, reads the
1360: ISR and totally processes everything that might have
1361: changed.
1362:
1363: Arguments:
1364:
1365: Extension - The serial device extension.
1366:
1367: Return Value:
1368:
1369: The value of the line status register.
1370:
1371: --*/
1372:
1373: {
1374:
1375: UCHAR LineStatus = READ_LINE_STATUS(Extension->Controller);
1376:
1377: Extension->HoldingEmpty = !!(LineStatus & SERIAL_LSR_THRE);
1378:
1379: //
1380: // If the line status register is just the fact that
1381: // the trasmit registers are empty or a character is
1382: // received then we want to reread the interrupt
1383: // identification register so that we just pick up that.
1384: //
1385:
1386: if (LineStatus & ~(SERIAL_LSR_THRE | SERIAL_LSR_TEMT
1387: | SERIAL_LSR_DR)) {
1388:
1389: //
1390: // We have some sort of data problem in the receive.
1391: // For any of these errors we may abort all current
1392: // reads and writes.
1393: //
1394: //
1395: // If we are inserting the value of the line status
1396: // into the data stream then we should put the escape
1397: // character in now.
1398: //
1399:
1400: if (Extension->EscapeChar) {
1401:
1402: SerialPutChar(
1403: Extension,
1404: Extension->EscapeChar
1405: );
1406:
1407: SerialPutChar(
1408: Extension,
1409: (UCHAR)((LineStatus & SERIAL_LSR_DR)?
1410: (SERIAL_LSRMST_LSR_DATA):(SERIAL_LSRMST_LSR_NODATA))
1411: );
1412:
1413: SerialPutChar(
1414: Extension,
1415: LineStatus
1416: );
1417:
1418: if (LineStatus & SERIAL_LSR_DR) {
1419:
1420: SerialPutChar(
1421: Extension,
1422: READ_RECEIVE_BUFFER(Extension->Controller)
1423: );
1424:
1425: }
1426:
1427: }
1428:
1429: if (LineStatus & SERIAL_LSR_OE) {
1430:
1431: Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
1432:
1433: if (Extension->HandFlow.FlowReplace &
1434: SERIAL_ERROR_CHAR) {
1435:
1436: SerialPutChar(
1437: Extension,
1438: Extension->SpecialChars.ErrorChar
1439: );
1440:
1441: }
1442:
1443: if (LineStatus & SERIAL_LSR_DR) {
1444:
1445: SerialPutChar(
1446: Extension,
1447: READ_RECEIVE_BUFFER(
1448: Extension->Controller
1449: )
1450: );
1451:
1452: }
1453:
1454: }
1455:
1456: if (LineStatus & SERIAL_LSR_BI) {
1457:
1458: Extension->ErrorWord |= SERIAL_ERROR_BREAK;
1459:
1460: if (Extension->HandFlow.FlowReplace &
1461: SERIAL_BREAK_CHAR) {
1462:
1463: SerialPutChar(
1464: Extension,
1465: Extension->SpecialChars.BreakChar
1466: );
1467:
1468: }
1469:
1470: } else {
1471:
1472: //
1473: // Framing errors only count if they
1474: // occur exclusive of a break being
1475: // received.
1476: //
1477:
1478: if (LineStatus & SERIAL_LSR_PE) {
1479:
1480: Extension->ErrorWord |= SERIAL_ERROR_PARITY;
1481:
1482: if (Extension->HandFlow.FlowReplace &
1483: SERIAL_ERROR_CHAR) {
1484:
1485: SerialPutChar(
1486: Extension,
1487: Extension->SpecialChars.ErrorChar
1488: );
1489:
1490: }
1491:
1492: }
1493:
1494: if (LineStatus & SERIAL_LSR_FE) {
1495:
1496: Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
1497:
1498:
1499: if (Extension->HandFlow.FlowReplace &
1500: SERIAL_ERROR_CHAR) {
1501:
1502: SerialPutChar(
1503: Extension,
1504: Extension->SpecialChars.ErrorChar
1505: );
1506:
1507: }
1508:
1509: }
1510:
1511: }
1512:
1513: //
1514: // If the application has requested it,
1515: // abort all the reads and writes
1516: // on an error.
1517: //
1518:
1519: if (Extension->HandFlow.ControlHandShake &
1520: SERIAL_ERROR_ABORT) {
1521:
1522: KeInsertQueueDpc(
1523: &Extension->CommErrorDpc,
1524: NULL,
1525: NULL
1526: );
1527:
1528: }
1529:
1530: //
1531: // Check to see if we have a wait
1532: // pending on the comm error events. If we
1533: // do then we schedule a dpc to satisfy
1534: // that wait.
1535: //
1536:
1537: if (Extension->IsrWaitMask) {
1538:
1539: if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&
1540: (LineStatus & (SERIAL_LSR_OE |
1541: SERIAL_LSR_PE |
1542: SERIAL_LSR_FE))) {
1543:
1544: Extension->HistoryMask |= SERIAL_EV_ERR;
1545:
1546: }
1547:
1548: if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&
1549: (LineStatus & SERIAL_LSR_BI)) {
1550:
1551: Extension->HistoryMask |= SERIAL_EV_BREAK;
1552:
1553: }
1554:
1555: if (Extension->IrpMaskLocation &&
1556: Extension->HistoryMask) {
1557:
1558: *Extension->IrpMaskLocation =
1559: Extension->HistoryMask;
1560: Extension->IrpMaskLocation = NULL;
1561: Extension->HistoryMask = 0;
1562:
1563: Extension->CurrentWaitIrp->IoStatus.Information =
1564: sizeof(ULONG);
1565: KeInsertQueueDpc(
1566: &Extension->CommWaitDpc,
1567: NULL,
1568: NULL
1569: );
1570:
1571: }
1572:
1573: }
1574:
1575: if (LineStatus & SERIAL_LSR_THRE) {
1576:
1577: //
1578: // There is a hardware bug in some versions
1579: // of the 16450 and 550. If THRE interrupt
1580: // is pending, but a higher interrupt comes
1581: // in it will only return the higher and
1582: // *forget* about the THRE.
1583: //
1584: // A suitable workaround - whenever we
1585: // are *all* done reading line status
1586: // of the device we check to see if the
1587: // transmit holding register is empty. If it is
1588: // AND we are currently transmitting data
1589: // enable the interrupts which should cause
1590: // an interrupt indication which we quiet
1591: // when we read the interrupt id register.
1592: //
1593:
1594: if (Extension->WriteLength |
1595: Extension->TransmitImmediate) {
1596:
1597: DISABLE_ALL_INTERRUPTS(
1598: Extension->Controller
1599: );
1600: ENABLE_ALL_INTERRUPTS(
1601: Extension->Controller
1602: );
1603:
1604: }
1605:
1606: }
1607:
1608: }
1609:
1610: return LineStatus;
1611:
1612: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.