|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: openclos.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to
12: opening, closing, and cleaning up 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: BOOLEAN
34: SerialMarkOpen(
35: IN PVOID Context
36: );
37:
38: BOOLEAN
39: SerialCheckOpen(
40: IN PVOID Context
41: );
42:
43: typedef struct _SERIAL_CHECK_OPEN {
44: PSERIAL_DEVICE_EXTENSION Extension;
45: NTSTATUS *StatusOfOpen;
46: } SERIAL_CHECK_OPEN,*PSERIAL_CHECK_OPEN;
47:
48: //
49: // Just a bogus little routine to make sure that we
50: // can synch with the ISR.
51: //
52: BOOLEAN
53: SerialNullSynch(
54: IN PVOID Context
55: ) {
56:
57: UNREFERENCED_PARAMETER(Context);
58: return FALSE;
59: }
60:
61: NTSTATUS
62: SerialCreateOpen(
63: IN PDEVICE_OBJECT DeviceObject,
64: IN PIRP Irp
65: )
66:
67: /*++
68:
69: Routine Description:
70:
71: We connect up to the interrupt for the create/open and initialize
72: the structures needed to maintain an open for a device.
73:
74: Arguments:
75:
76: DeviceObject - Pointer to the device object for this device
77:
78: Irp - Pointer to the IRP for the current request
79:
80: Return Value:
81:
82: The function value is the final status of the call
83:
84: --*/
85:
86: {
87:
88: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
89: SERIAL_CHECK_OPEN checkOpen;
90: NTSTATUS localStatus;
91:
92: SerialDump(
93: SERIRPPATH,
94: ("SERIAL: Dispatch entry for: %x\n",Irp)
95: );
96: SerialDump(
97: SERDIAG3,
98: ("SERIAL: In SerialCreateOpen\n")
99: );
100:
101: //
102: // Before we do anything, let's make sure they aren't trying
103: // to create a directory. This is a silly, but what's a driver to do!?
104: //
105:
106: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
107: FILE_DIRECTORY_FILE) {
108:
109: Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
110: Irp->IoStatus.Information = 0;
111:
112: SerialDump(
113: SERIRPPATH,
114: ("SERIAL: Complete Irp: %x\n",Irp)
115: );
116: IoCompleteRequest(
117: Irp,
118: IO_NO_INCREMENT
119: );
120: return STATUS_NOT_A_DIRECTORY;
121:
122: }
123:
124: //
125: // Create a buffer for the RX data when no reads are outstanding.
126: //
127:
128: extension->InterruptReadBuffer = NULL;
129: extension->BufferSize = 0;
130:
131: switch (MmQuerySystemSize()) {
132:
133: case MmLargeSystem: {
134:
135: extension->BufferSize = 4096;
136: extension->InterruptReadBuffer = ExAllocatePool(
137: NonPagedPool,
138: extension->BufferSize
139: );
140:
141: if (extension->InterruptReadBuffer) {
142:
143: break;
144:
145: }
146:
147: }
148:
149: case MmMediumSystem: {
150:
151: extension->BufferSize = 1024;
152: extension->InterruptReadBuffer = ExAllocatePool(
153: NonPagedPool,
154: extension->BufferSize
155: );
156:
157: if (extension->InterruptReadBuffer) {
158:
159: break;
160:
161: }
162:
163: }
164:
165: case MmSmallSystem: {
166:
167: extension->BufferSize = 128;
168: extension->InterruptReadBuffer = ExAllocatePool(
169: NonPagedPool,
170: extension->BufferSize
171: );
172:
173: }
174:
175: }
176:
177: if (!extension->InterruptReadBuffer) {
178:
179: extension->BufferSize = 0;
180: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
181: Irp->IoStatus.Information = 0;
182:
183: SerialDump(
184: SERIRPPATH,
185: ("SERIAL: Complete Irp: %x\n",Irp)
186: );
187: IoCompleteRequest(
188: Irp,
189: IO_NO_INCREMENT
190: );
191: return STATUS_INSUFFICIENT_RESOURCES;
192:
193: }
194:
195: //
196: // On a new open we "flush" the read queue by initializing the
197: // count of characters.
198: //
199:
200: extension->CharsInInterruptBuffer = 0;
201: extension->LastCharSlot = extension->InterruptReadBuffer +
202: (extension->BufferSize - 1);
203:
204: extension->ReadBufferBase = extension->InterruptReadBuffer;
205: extension->CurrentCharSlot = extension->InterruptReadBuffer;
206: extension->FirstReadableChar = extension->InterruptReadBuffer;
207:
208: extension->TotalCharsQueued = 0;
209:
210: //
211: // We set up the default xon/xoff limits.
212: //
213:
214: extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
215: extension->HandFlow.XonLimit = extension->BufferSize >> 1;
216:
217: extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
218: (extension->BufferSize>>4));
219:
220: extension->IrpMaskLocation = NULL;
221: extension->HistoryMask = 0;
222: extension->IsrWaitMask = 0;
223:
224: extension->SendXonChar = FALSE;
225: extension->SendXoffChar = FALSE;
226:
227: //
228: // The escape char replacement must be reset upon every open.
229: //
230:
231: extension->EscapeChar = 0;
232:
233: #if !defined(SERIAL_CRAZY_INTERRUPTS)
234:
235: if (!extension->InterruptShareable) {
236:
237: checkOpen.Extension = extension;
238: checkOpen.StatusOfOpen = &Irp->IoStatus.Status;
239:
240: KeSynchronizeExecution(
241: extension->Interrupt,
242: SerialCheckOpen,
243: &checkOpen
244: );
245:
246: } else {
247:
248: KeSynchronizeExecution(
249: extension->Interrupt,
250: SerialMarkOpen,
251: extension
252: );
253:
254: Irp->IoStatus.Status = STATUS_SUCCESS;
255:
256: }
257: #else
258:
259: //
260: // Synchronize with the ISR and let it know that the device
261: // has been successfully opened.
262: //
263:
264: KeSynchronizeExecution(
265: extension->Interrupt,
266: SerialMarkOpen,
267: extension
268: );
269:
270: Irp->IoStatus.Status = STATUS_SUCCESS;
271: #endif
272:
273: localStatus = Irp->IoStatus.Status;
274: Irp->IoStatus.Information=0L;
275:
276: SerialDump(
277: SERIRPPATH,
278: ("SERIAL: Complete Irp: %x\n",Irp)
279: );
280: IoCompleteRequest(
281: Irp,
282: IO_NO_INCREMENT
283: );
284:
285: return localStatus;
286:
287: }
288:
289: NTSTATUS
290: SerialClose(
291: IN PDEVICE_OBJECT DeviceObject,
292: IN PIRP Irp
293: )
294:
295: /*++
296:
297: Routine Description:
298:
299: We simpley disconnect the interrupt for now.
300:
301: Arguments:
302:
303: DeviceObject - Pointer to the device object for this device
304:
305: Irp - Pointer to the IRP for the current request
306:
307: Return Value:
308:
309: The function value is the final status of the call
310:
311: --*/
312:
313: {
314:
315: //
316: // This "timer value" is used to wait 10 character times
317: // after the hardware is empty before we actually "run down"
318: // all of the flow control/break junk.
319: //
320: LARGE_INTEGER tenCharDelay;
321:
322: //
323: // Holds a character time.
324: //
325: LARGE_INTEGER charTime;
326:
327: //
328: // Just what it says. This is the serial specific device
329: // extension of the device object create for the serial driver.
330: //
331: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
332:
333: SerialDump(
334: SERIRPPATH,
335: ("SERIAL: Dispatch entry for: %x\n",Irp)
336: );
337: SerialDump(
338: SERDIAG3,
339: ("SERIAL: In SerialClose\n")
340: );
341:
342: charTime = RtlLargeIntegerNegate(SerialGetCharTime(extension));
343:
344: //
345: // Synchronize with the ISR to let it know that interrupts are
346: // no longer important.
347: //
348:
349: KeSynchronizeExecution(
350: extension->Interrupt,
351: SerialMarkClose,
352: extension
353: );
354:
355: //
356: // Synchronize with the isr to turn off break if it
357: // is already on.
358: //
359:
360: KeSynchronizeExecution(
361: extension->Interrupt,
362: SerialTurnOffBreak,
363: extension
364: );
365:
366: //
367: // If the driver has automatically transmitted an Xoff in
368: // the context of automatic receive flow control then we
369: // should transmit an Xon.
370: //
371:
372: if (extension->RXHolding & SERIAL_RX_XOFF) {
373:
374: //
375: // Loop until the holding register is empty.
376: //
377:
378: while (!(READ_LINE_STATUS(extension->Controller) &
379: SERIAL_LSR_THRE)) {
380:
381: KeDelayExecutionThread(
382: KernelMode,
383: FALSE,
384: &charTime
385: );
386:
387: }
388:
389: WRITE_TRANSMIT_HOLDING(
390: extension->Controller,
391: extension->SpecialChars.XonChar
392: );
393:
394: }
395:
396: //
397: // Wait until all characters have been emptied out of the hardware.
398: //
399:
400: while ((READ_LINE_STATUS(extension->Controller) &
401: (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
402: (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
403:
404: KeDelayExecutionThread(
405: KernelMode,
406: FALSE,
407: &charTime
408: );
409:
410: }
411:
412: //
413: // The hardware is empty. Delay 10 character times before
414: // shut down all the flow control.
415: //
416:
417: tenCharDelay = RtlExtendedIntegerMultiply(
418: charTime,
419: 10
420: );
421:
422: KeDelayExecutionThread(
423: KernelMode,
424: TRUE,
425: &tenCharDelay
426: );
427:
428: SerialClrDTR(extension);
429:
430: //
431: // We have to be very careful how we clear the RTS line.
432: // Transmit toggling might have been on at some point.
433: //
434: // We know that there is nothing left that could start
435: // out the "polling" execution path. We need to
436: // check the counter that indicates that the execution
437: // path is active. If it is then we loop delaying one
438: // character time. After each delay we check to see if
439: // the counter has gone to zero. When it has we know that
440: // the execution path should be just about finished. We
441: // make sure that we still aren't in the routine that
442: // synchronized execution with the ISR by synchronizing
443: // ourselve with the ISR.
444: //
445:
446: if (extension->CountOfTryingToLowerRTS) {
447:
448: do {
449:
450: KeDelayExecutionThread(
451: KernelMode,
452: FALSE,
453: &charTime
454: );
455:
456: } while (extension->CountOfTryingToLowerRTS);
457:
458: KeSynchronizeExecution(
459: extension->Interrupt,
460: SerialNullSynch,
461: NULL
462: );
463:
464: //
465: // The execution path should no longer exist that
466: // is trying to push down the RTS. Well just
467: // make sure it's down by falling through to
468: // code that forces it down.
469: //
470:
471: }
472:
473: SerialClrRTS(extension);
474:
475: //
476: // Clean out the holding reasons (since we are closed).
477: //
478:
479: extension->RXHolding = 0;
480: extension->TXHolding = 0;
481:
482: //
483: // All is done. The port has been disabled from interrupting
484: // so there is no point in keeping the memory around.
485: //
486:
487: extension->BufferSize = 0;
488: ExFreePool(extension->InterruptReadBuffer);
489: extension->InterruptReadBuffer = NULL;
490:
491: Irp->IoStatus.Status = STATUS_SUCCESS;
492: Irp->IoStatus.Information=0L;
493:
494: SerialDump(
495: SERIRPPATH,
496: ("SERIAL: Complete Irp: %x\n",Irp)
497: );
498: IoCompleteRequest(
499: Irp,
500: IO_NO_INCREMENT
501: );
502:
503: return STATUS_SUCCESS;
504:
505: }
506:
507: BOOLEAN
508: SerialCheckOpen(
509: IN PVOID Context
510: )
511:
512: /*++
513:
514: Routine Description:
515:
516: This routine will traverse the circular doubly linked list
517: of devices that are using the same interrupt object. It will look
518: for other devices that are open. If it doesn't find any
519: it will indicate that it is ok to open this device.
520:
521: If it finds another device open we have two cases:
522:
523: 1) The device we are trying to open is on a multiport card.
524:
525: If the already open device is part of a multiport device
526: this code will indicate it is ok to open. We do this on the
527: theory that the multiport devices are daisy chained
528: and the cards can correctly arbitrate the interrupt
529: line. Note this assumption could be wrong. Somebody
530: could put two non-daisychained multiports on the
531: same interrupt. However, only a total clod would do
532: such a thing, and in my opinion deserves everthing they
533: get.
534:
535: 2) The device we are trying to open is not on a multiport card.
536:
537: We indicate that it is not ok to open.
538:
539: Arguments:
540:
541: Context - This is a structure that contains a pointer to the
542: extension of the device we are trying to open, and
543: a pointer to an NTSTATUS that will indicate whether
544: the device was opened or not.
545:
546: Return Value:
547:
548: This routine always returns FALSE.
549:
550: --*/
551:
552: {
553:
554: PSERIAL_DEVICE_EXTENSION extensionToOpen =
555: ((PSERIAL_CHECK_OPEN)Context)->Extension;
556: NTSTATUS *status = ((PSERIAL_CHECK_OPEN)Context)->StatusOfOpen;
557: PLIST_ENTRY firstEntry = &extensionToOpen->CommonInterruptObject;
558: PLIST_ENTRY currentEntry = firstEntry;
559: PSERIAL_DEVICE_EXTENSION currentExtension;
560:
561: do {
562:
563: currentExtension = CONTAINING_RECORD(
564: currentEntry,
565: SERIAL_DEVICE_EXTENSION,
566: CommonInterruptObject
567: );
568:
569: if (currentExtension->DeviceIsOpened) {
570:
571: break;
572:
573: }
574:
575: currentEntry = currentExtension->CommonInterruptObject.Flink;
576:
577: } while (currentEntry != firstEntry);
578:
579: if (currentEntry == firstEntry) {
580:
581: //
582: // We searched the whole list and found no other opens
583: // mark the status as successful and call the regular
584: // opening routine.
585: //
586:
587: *status = STATUS_SUCCESS;
588: SerialMarkOpen(extensionToOpen);
589:
590: } else {
591:
592: if (!extensionToOpen->PortOnAMultiportCard) {
593:
594: *status = STATUS_SHARED_IRQ_BUSY;
595:
596: } else {
597:
598: if (!currentExtension->PortOnAMultiportCard) {
599:
600: *status = STATUS_SHARED_IRQ_BUSY;
601:
602: } else {
603:
604: *status = STATUS_SUCCESS;
605: SerialMarkOpen(extensionToOpen);
606:
607: }
608:
609: }
610:
611: }
612:
613: return FALSE;
614:
615: }
616:
617: BOOLEAN
618: SerialMarkOpen(
619: IN PVOID Context
620: )
621:
622: /*++
623:
624: Routine Description:
625:
626: This routine merely sets a boolean to true to mark the fact that
627: somebody opened the device and its worthwhile to pay attention
628: to interrupts.
629:
630: Arguments:
631:
632: Context - Really a pointer to the device extension.
633:
634: Return Value:
635:
636: This routine always returns FALSE.
637:
638: --*/
639:
640: {
641:
642: PSERIAL_DEVICE_EXTENSION extension = Context;
643:
644: SerialReset(extension);
645:
646: //
647: // Prepare for the opening by re-enabling interrupts.
648: //
649: // We do this my modifying the OUT2 line in the modem control.
650: // In PC's this bit is "anded" with the interrupt line.
651: //
652: // For the Jensen, we will ALWAYS leave the line high. That's
653: // the way the hardware engineers want it.
654: //
655:
656: WRITE_MODEM_CONTROL(
657: extension->Controller,
658: (UCHAR)(READ_MODEM_CONTROL(extension->Controller) | SERIAL_MCR_OUT2)
659: );
660:
661: extension->DeviceIsOpened = TRUE;
662: extension->ErrorWord = 0;
663:
664: return FALSE;
665:
666: }
667:
668: BOOLEAN
669: SerialMarkClose(
670: IN PVOID Context
671: )
672:
673: /*++
674:
675: Routine Description:
676:
677: This routine merely sets a boolean to false to mark the fact that
678: somebody closed the device and it's no longer worthwhile to pay attention
679: to interrupts.
680:
681: Arguments:
682:
683: Context - Really a pointer to the device extension.
684:
685: Return Value:
686:
687: This routine always returns FALSE.
688:
689: --*/
690:
691: {
692:
693: PSERIAL_DEVICE_EXTENSION extension = Context;
694:
695: //
696: // Prepare for the closing by stopping interrupts.
697: //
698: // We do this by adjusting the OUT2 line in the modem control.
699: // In PC's this bit is "anded" with the interrupt line.
700: //
701: // The line should stay high on the Jensen because that's the
702: // way the hardware engineers did it.
703: //
704:
705: if (!extension->Jensen) {
706:
707: WRITE_MODEM_CONTROL(
708: extension->Controller,
709: (UCHAR)(READ_MODEM_CONTROL(extension->Controller) & ~SERIAL_MCR_OUT2)
710: );
711:
712: }
713:
714: if (extension->FifoPresent) {
715:
716: WRITE_FIFO_CONTROL(
717: extension->Controller,
718: (UCHAR)0
719: );
720:
721: }
722:
723: extension->DeviceIsOpened = FALSE;
724:
725: return FALSE;
726:
727: }
728:
729: NTSTATUS
730: SerialCleanup(
731: IN PDEVICE_OBJECT DeviceObject,
732: IN PIRP Irp
733: )
734:
735: /*++
736:
737: Routine Description:
738:
739: This function is used to kill all longstanding IO operations.
740:
741: Arguments:
742:
743: DeviceObject - Pointer to the device object for this device
744:
745: Irp - Pointer to the IRP for the current request
746:
747: Return Value:
748:
749: The function value is the final status of the call
750:
751: --*/
752:
753: {
754:
755: PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
756: KIRQL oldIrql;
757:
758: SerialDump(
759: SERIRPPATH,
760: ("SERIAL: Dispatch entry for: %x\n",Irp)
761: );
762: //
763: // First kill all the reads and writes.
764: //
765:
766: SerialKillAllReadsOrWrites(
767: DeviceObject,
768: &extension->WriteQueue,
769: &extension->CurrentWriteIrp
770: );
771:
772: SerialKillAllReadsOrWrites(
773: DeviceObject,
774: &extension->ReadQueue,
775: &extension->CurrentReadIrp
776: );
777:
778: //
779: // Next get rid of purges.
780: //
781:
782: SerialKillAllReadsOrWrites(
783: DeviceObject,
784: &extension->PurgeQueue,
785: &extension->CurrentPurgeIrp
786: );
787:
788: //
789: // Get rid of any mask operations.
790: //
791:
792: SerialKillAllReadsOrWrites(
793: DeviceObject,
794: &extension->MaskQueue,
795: &extension->CurrentMaskIrp
796: );
797:
798: //
799: // Now get rid a pending wait mask irp.
800: //
801:
802: IoAcquireCancelSpinLock(&oldIrql);
803:
804: if (extension->CurrentWaitIrp) {
805:
806: PDRIVER_CANCEL cancelRoutine;
807:
808: cancelRoutine = extension->CurrentWaitIrp->CancelRoutine;
809: extension->CurrentWaitIrp->Cancel = TRUE;
810:
811: if (cancelRoutine) {
812:
813: extension->CurrentWaitIrp->CancelIrql = oldIrql;
814: extension->CurrentWaitIrp->CancelRoutine = NULL;
815:
816: cancelRoutine(
817: DeviceObject,
818: extension->CurrentWaitIrp
819: );
820:
821: }
822:
823: } else {
824:
825: IoReleaseCancelSpinLock(oldIrql);
826:
827: }
828:
829: Irp->IoStatus.Status = STATUS_SUCCESS;
830: Irp->IoStatus.Information=0L;
831:
832: SerialDump(
833: SERIRPPATH,
834: ("SERIAL: Complete Irp: %x\n",Irp)
835: );
836: IoCompleteRequest(
837: Irp,
838: IO_NO_INCREMENT
839: );
840:
841: return STATUS_SUCCESS;
842:
843: }
844:
845: LARGE_INTEGER
846: SerialGetCharTime(
847: IN PSERIAL_DEVICE_EXTENSION Extension
848: )
849:
850: /*++
851:
852: Routine Description:
853:
854: This function will return the number of 100 nanosecond intervals
855: there are in one character time (based on the present form
856: of flow control.
857:
858: Arguments:
859:
860: Extension - Just what it says.
861:
862: Return Value:
863:
864: 100 nanosecond intervals in a character time.
865:
866: --*/
867:
868: {
869:
870: ULONG dataSize;
871: ULONG paritySize;
872: ULONG stopSize;
873: ULONG charTime;
874: ULONG bitTime;
875:
876:
877: if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {
878: dataSize = 5;
879: } else if ((Extension->LineControl & SERIAL_DATA_MASK)
880: == SERIAL_6_DATA) {
881: dataSize = 6;
882: } else if ((Extension->LineControl & SERIAL_DATA_MASK)
883: == SERIAL_7_DATA) {
884: dataSize = 7;
885: } else if ((Extension->LineControl & SERIAL_DATA_MASK)
886: == SERIAL_8_DATA) {
887: dataSize = 8;
888: }
889:
890: paritySize = 1;
891: if ((Extension->LineControl & SERIAL_PARITY_MASK)
892: == SERIAL_NONE_PARITY) {
893:
894: paritySize = 0;
895:
896: }
897:
898: if (Extension->LineControl & SERIAL_2_STOP) {
899:
900: //
901: // Even if it is 1.5, for sanities sake were going
902: // to say 2.
903: //
904:
905: stopSize = 2;
906:
907: } else {
908:
909: stopSize = 1;
910:
911: }
912:
913: //
914: // First we calculate the number of 100 nanosecond intervals
915: // are in a single bit time (Approximately).
916: //
917:
918: bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
919: charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
920:
921: return RtlConvertUlongToLargeInteger(charTime);
922:
923: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.