|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: initunlo.c
8:
9: Abstract:
10:
11: This module contains the code that is very specific to initialization
12: and unload 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: #include "serlog.h"
32:
33:
34: //
35: // This is the actual definition of SerialDebugLevel.
36: // Note that it is only defined if this is a "debug"
37: // build.
38: //
39: #if DBG
40: extern ULONG SerialDebugLevel = 0;
41: #endif
42:
43: static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
44:
45: NTSTATUS
46: DriverEntry(
47: IN PDRIVER_OBJECT DriverObject,
48: IN PUNICODE_STRING RegistryPath
49: );
50:
51: NTSTATUS
52: SerialInitializeController(
53: IN PDRIVER_OBJECT DriverObject,
54: IN PCONFIG_DATA ConfigData,
55: IN BOOLEAN MapInterruptStatus,
56: OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension
57: );
58:
59: BOOLEAN
60: SerialDoesPortExist(
61: IN PSERIAL_DEVICE_EXTENSION Extension,
62: PUNICODE_STRING InsertString,
63: IN ULONG ForceFifo
64: );
65:
66: VOID
67: SerialCleanupMultiPort(
68: PSERIAL_DEVICE_EXTENSION *ExtensionList,
69: ULONG NumberOfDevices
70: );
71:
72: VOID
73: SerialGetConfigInfo(
74: IN PDRIVER_OBJECT DriverObject,
75: IN PUNICODE_STRING RegistryPath,
76: ULONG ForceFifoEnableDefault,
77: ULONG RxFifoDefault,
78: OUT PLIST_ENTRY ConfigList
79: );
80:
81: BOOLEAN
82: SerialPutInConfigList(
83: IN PDRIVER_OBJECT DriverObject,
84: IN OUT PLIST_ENTRY ConfigList,
85: IN PCONFIG_DATA New
86: );
87:
88: BOOLEAN
89: SerialResetSynch(
90: IN PVOID Context
91: );
92:
93: PVOID
94: SerialGetMappedAddress(
95: IN INTERFACE_TYPE BusType,
96: IN ULONG BusNumber,
97: PHYSICAL_ADDRESS IoAddress,
98: ULONG NumberOfBytes,
99: ULONG AddressSpace,
100: PBOOLEAN MappedAddress
101: );
102:
103: VOID
104: SerialSetupExternalNaming(
105: IN PSERIAL_DEVICE_EXTENSION Extension
106: );
107:
108: VOID
109: SerialCleanupExternalNaming(
110: IN PSERIAL_DEVICE_EXTENSION Extension
111: );
112:
113: typedef enum _SERIAL_MEM_COMPARES {
114: AddressesAreEqual,
115: AddressesOverlap,
116: AddressesAreDisjoint
117: } SERIAL_MEM_COMPARES,*PSERIAL_MEM_COMPARES;
118:
119: SERIAL_MEM_COMPARES
120: SerialMemCompare(
121: IN PHYSICAL_ADDRESS A,
122: IN ULONG SpanOfA,
123: IN PHYSICAL_ADDRESS B,
124: IN ULONG SpanOfB
125: );
126:
127: VOID
128: SerialPropagateDeleteSharers(
129: IN PSERIAL_DEVICE_EXTENSION Extension,
130: IN OUT PULONG CountSoFar OPTIONAL,
131: IN PKINTERRUPT Interrupt OPTIONAL
132: );
133:
134: VOID
135: SerialInitializeRootInterrupt(
136: IN PDRIVER_OBJECT DriverObject,
137: IN PCONFIG_DATA ConfigData
138: );
139:
140: NTSTATUS
141: SerialInitializeRootMultiPort(
142: IN PDRIVER_OBJECT DriverObject,
143: IN PCONFIG_DATA ConfigData,
144: OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension
145: );
146:
147: NTSTATUS
148: SerialInitializeOneController(
149: IN PDRIVER_OBJECT DriverObject,
150: IN PCONFIG_DATA ConfigData,
151: IN BOOLEAN MapInterruptStatus,
152: OUT PSERIAL_DEVICE_EXTENSION *Extension
153: );
154:
155: VOID
156: SerialLogError(
157: IN PDRIVER_OBJECT DriverObject,
158: IN PDEVICE_OBJECT DeviceObject OPTIONAL,
159: IN PHYSICAL_ADDRESS P1,
160: IN PHYSICAL_ADDRESS P2,
161: IN ULONG SequenceNumber,
162: IN UCHAR MajorFunctionCode,
163: IN UCHAR RetryCount,
164: IN ULONG UniqueErrorValue,
165: IN NTSTATUS FinalStatus,
166: IN NTSTATUS SpecificIOStatus,
167: IN ULONG LengthOfInsert1,
168: IN PWCHAR Insert1,
169: IN ULONG LengthOfInsert2,
170: IN PWCHAR Insert2
171: );
172:
173: NTSTATUS
174: SerialItemCallBack(
175: IN PVOID Context,
176: IN PUNICODE_STRING PathName,
177: IN INTERFACE_TYPE BusType,
178: IN ULONG BusNumber,
179: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
180: IN CONFIGURATION_TYPE ControllerType,
181: IN ULONG ControllerNumber,
182: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
183: IN CONFIGURATION_TYPE PeripheralType,
184: IN ULONG PeripheralNumber,
185: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
186: );
187:
188: NTSTATUS
189: SerialConfigCallBack(
190: IN PVOID Context,
191: IN PUNICODE_STRING PathName,
192: IN INTERFACE_TYPE BusType,
193: IN ULONG BusNumber,
194: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
195: IN CONFIGURATION_TYPE ControllerType,
196: IN ULONG ControllerNumber,
197: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
198: IN CONFIGURATION_TYPE PeripheralType,
199: IN ULONG PeripheralNumber,
200: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
201: );
202:
203: VOID
204: SerialUnReportResourcesDevice(
205: IN PSERIAL_DEVICE_EXTENSION Extension
206: );
207:
208: VOID
209: SerialReportResourcesDevice(
210: IN PSERIAL_DEVICE_EXTENSION Extension,
211: OUT BOOLEAN *ConflictDetected
212: );
213:
214: //
215: // This is exported from the kernel. It is used to point
216: // to the address that the kernel debugger is using.
217: //
218: extern PUCHAR *KdComPortInUse;
219:
220: #ifdef ALLOC_PRAGMA
221: #pragma alloc_text(init,DriverEntry)
222: #pragma alloc_text(init,SerialInitializeRootInterrupt)
223: #pragma alloc_text(init,SerialInitializeRootMultiPort)
224: #pragma alloc_text(init,SerialInitializeOneController)
225: #pragma alloc_text(init,SerialInitializeController)
226: #pragma alloc_text(init,SerialDoesPortExist)
227: #pragma alloc_text(init,SerialItemCallBack)
228: #pragma alloc_text(init,SerialConfigCallBack)
229: #pragma alloc_text(init,SerialGetConfigInfo)
230: #pragma alloc_text(init,SerialPutInConfigList)
231: #pragma alloc_text(init,SerialGetMappedAddress)
232: #pragma alloc_text(init,SerialSetupExternalNaming)
233: #pragma alloc_text(init,SerialMemCompare)
234: #pragma alloc_text(init,SerialReportResourcesDevice)
235: #endif
236:
237:
238: NTSTATUS
239: DriverEntry(
240: IN PDRIVER_OBJECT DriverObject,
241: IN PUNICODE_STRING RegistryPath
242: )
243:
244: /*++
245:
246: Routine Description:
247:
248: The entry point that the system point calls to initialize
249: any driver.
250:
251: This routine will gather the configuration information,
252: report resource usage, attempt to initialize all serial
253: devices, connect to interrupts for ports. If the above
254: goes reasonably well it will fill in the dispatch points,
255: reset the serial devices and then return to the system.
256:
257: Arguments:
258:
259: DriverObject - Just what it says, really of little use
260: to the driver itself, it is something that the IO system
261: cares more about.
262:
263: PathToRegistry - points to the entry for this driver
264: in the current control set of the registry.
265:
266: Return Value:
267:
268: STATUS_SUCCESS if we could initialize a single device,
269: otherwise STATUS_SERIAL_NO_DEVICE_INITED.
270:
271: --*/
272:
273: {
274:
275: //
276: // Holds status information return by various OS and driver
277: // initialization routines.
278: //
279: NTSTATUS status;
280:
281: //
282: // List head for configuration records.
283: //
284: LIST_ENTRY configList;
285:
286: //
287: // Pointer to a device object in the device object chain
288: // hanging off of the driver object.
289: //
290: PDEVICE_OBJECT currentDevice;
291:
292: //
293: // Holds a pointer to a ulong that the Io system maintains
294: // of the count of serial devices.
295: //
296: PULONG countSoFar;
297:
298: //
299: // We use this to query into the registry as to whether we
300: // should break at driver entry.
301: //
302: RTL_QUERY_REGISTRY_TABLE paramTable[5];
303: ULONG zero = 0;
304: ULONG debugLevel = 0;
305: ULONG shouldBreak = 0;
306: ULONG forceFifoEnableDefault;
307: ULONG rxFIFODefault;
308: ULONG notThereDefault = 1234567;
309: PWCHAR path;
310:
311: //
312: // Since the registry path parameter is a "counted" UNICODE string, it
313: // might not be zero terminated. For a very short time allocate memory
314: // to hold the registry path zero terminated so that we can use it to
315: // delve into the registry.
316: //
317: // NOTE NOTE!!!! This is not an architected way of breaking into
318: // a driver. It happens to work for this driver because the author
319: // likes to do things this way.
320: //
321:
322: if (path = ExAllocatePool(
323: PagedPool,
324: RegistryPath->Length+sizeof(WCHAR)
325: )) {
326:
327: RtlZeroMemory(
328: ¶mTable[0],
329: sizeof(paramTable)
330: );
331: RtlZeroMemory(
332: path,
333: RegistryPath->Length+sizeof(WCHAR)
334: );
335: RtlMoveMemory(
336: path,
337: RegistryPath->Buffer,
338: RegistryPath->Length
339: );
340: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
341: paramTable[0].Name = L"BreakOnEntry";
342: paramTable[0].EntryContext = &shouldBreak;
343: paramTable[0].DefaultType = REG_DWORD;
344: paramTable[0].DefaultData = &zero;
345: paramTable[0].DefaultLength = sizeof(ULONG);
346: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
347: paramTable[1].Name = L"DebugLevel";
348: paramTable[1].EntryContext = &debugLevel;
349: paramTable[1].DefaultType = REG_DWORD;
350: paramTable[1].DefaultData = &zero;
351: paramTable[1].DefaultLength = sizeof(ULONG);
352: paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
353: paramTable[2].Name = L"ForceFifoEnable";
354: paramTable[2].EntryContext = &forceFifoEnableDefault;
355: paramTable[2].DefaultType = REG_DWORD;
356: paramTable[2].DefaultData = ¬ThereDefault;
357: paramTable[2].DefaultLength = sizeof(ULONG);
358: paramTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
359: paramTable[3].Name = L"RxFIFO";
360: paramTable[3].EntryContext = &rxFIFODefault;
361: paramTable[3].DefaultType = REG_DWORD;
362: paramTable[3].DefaultData = ¬ThereDefault;
363: paramTable[3].DefaultLength = sizeof(ULONG);
364:
365: if (!NT_SUCCESS(RtlQueryRegistryValues(
366: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
367: path,
368: ¶mTable[0],
369: NULL,
370: NULL
371: ))) {
372:
373: shouldBreak = 0;
374: debugLevel = 0;
375:
376: }
377:
378: }
379:
380: #if DBG
381: SerialDebugLevel = debugLevel;
382: #endif
383:
384: if (shouldBreak) {
385:
386: DbgBreakPoint();
387:
388: }
389:
390: //
391: // Check to see if there was a forcefifo or an rxfifo size.
392: // If there isn't then write out values so that they could
393: // be adjusted later.
394: //
395:
396: if (forceFifoEnableDefault == notThereDefault) {
397:
398: forceFifoEnableDefault = 1;
399: RtlWriteRegistryValue(
400: RTL_REGISTRY_ABSOLUTE,
401: path,
402: L"ForceFifoEnable",
403: REG_DWORD,
404: &forceFifoEnableDefault,
405: sizeof(ULONG)
406: );
407:
408: }
409:
410: if (rxFIFODefault == notThereDefault) {
411:
412: rxFIFODefault = 8;
413: RtlWriteRegistryValue(
414: RTL_REGISTRY_ABSOLUTE,
415: path,
416: L"RxFIFO",
417: REG_DWORD,
418: &rxFIFODefault,
419: sizeof(ULONG)
420: );
421:
422: }
423:
424:
425:
426: //
427: // We don't need that path anymore.
428: //
429:
430: if (path) {
431:
432: ExFreePool(path);
433:
434: }
435:
436: //
437: // Just dump out how big the extension is.
438: //
439:
440: SerialDump(
441: SERDIAG1,
442: ("SERIAL: The number of bytes in the extension is: %d\n",
443: sizeof(SERIAL_DEVICE_EXTENSION))
444: );
445:
446:
447: countSoFar = &IoGetConfigurationInformation()->SerialCount;
448:
449: SerialGetConfigInfo(
450: DriverObject,
451: RegistryPath,
452: forceFifoEnableDefault,
453: rxFIFODefault,
454: &configList
455: );
456:
457: //
458: // Initialize each item in the list of configuration records.
459: //
460:
461: while (!IsListEmpty(&configList)) {
462:
463: PCONFIG_DATA currentConfig;
464: PLIST_ENTRY head;
465:
466: head = RemoveHeadList(&configList);
467:
468: currentConfig = CONTAINING_RECORD(
469: head,
470: CONFIG_DATA,
471: ConfigList
472: );
473:
474: SerialInitializeRootInterrupt(
475: DriverObject,
476: currentConfig
477: );
478:
479: }
480:
481: //
482: // We've initialized all of the hardware that this driver
483: // will ever know about. All of the hardware that we know
484: // about is set up to NOT interrupt. We now go through
485: // all of the devices and connect an interrupt object for
486: // all.
487: //
488:
489: currentDevice = DriverObject->DeviceObject;
490:
491: while (currentDevice) {
492:
493: PSERIAL_DEVICE_EXTENSION extension = currentDevice->DeviceExtension;
494:
495: //
496: // This loop will only connect the interrupt for the
497: // "root" controller. When we initialize a root controller
498: // we then propagate that interrupt object to all associate
499: // controllers. If a device doesn't already have an interrupt
500: // and it has an isr then we attempt to connect to the
501: // interrupt. Note that if we fail to connect to an interrupt
502: // we will delete all of the associated devices.
503: //
504:
505: if ((!extension->Interrupt) &&
506: (extension->OurIsr)) {
507:
508: SerialDump(
509: SERDIAG5,
510: ("SERIAL: About to connect to interrupt for port %wZ\n"
511: "------- address of extension is %x\n",
512: &extension->DeviceName,extension)
513: );
514: status = IoConnectInterrupt(
515: &extension->Interrupt,
516: extension->OurIsr,
517: extension->OurIsrContext,
518: NULL,
519: extension->Vector,
520: extension->Irql,
521: extension->Irql,
522: extension->InterruptMode,
523: extension->InterruptShareable,
524: extension->ProcessorAffinity,
525: FALSE
526: );
527:
528: if (!NT_SUCCESS(status)) {
529:
530: //
531: // Hmmm, how'd that happen? Somebody either
532: // didn't report their resources, or they
533: // sneaked in since the last time I looked.
534: //
535: // Oh well, delete this device as well as
536: // any of the devices that were hoping to
537: // share this interrupt.
538: //
539:
540: SerialDump(
541: SERERRORS,
542: ("SERIAL: Couldn't connect to interrupt for %wZ\n",
543: &extension->DeviceName)
544: );
545: SerialLogError(
546: extension->DeviceObject->DriverObject,
547: extension->DeviceObject,
548: extension->OriginalController,
549: SerialPhysicalZero,
550: 0,
551: 0,
552: 0,
553: 1,
554: status,
555: SERIAL_UNREPORTED_IRQL_CONFLICT,
556: extension->SymbolicLinkName.Length+sizeof(WCHAR),
557: extension->SymbolicLinkName.Buffer,
558: 0,
559: NULL
560: );
561: SerialPropagateDeleteSharers(
562: extension,
563: NULL,
564: NULL
565: );
566:
567: //
568: // The above call deleted all the associated
569: // device objects. Who knows what the device
570: // list looks like now! Start over from
571: // the beginning of the device list.
572: //
573:
574: currentDevice = DriverObject->DeviceObject;
575:
576: } else {
577:
578: SerialPropagateDeleteSharers(
579: extension,
580: countSoFar,
581: extension->Interrupt
582: );
583:
584: currentDevice = DriverObject->DeviceObject;
585:
586: }
587:
588: } else {
589:
590: //
591: // We've already done this device. We can go on
592: // to the next device.
593: //
594:
595: currentDevice = currentDevice->NextDevice;
596:
597: }
598:
599: }
600:
601: //
602: // Well if we connected to any interrupts then we should
603: // have some device objects. Go through all of the devices
604: // and reset each device.
605: //
606:
607: currentDevice = DriverObject->DeviceObject;
608:
609: while (currentDevice) {
610:
611: PDEVICE_OBJECT nextDevice = currentDevice->NextDevice;
612: PSERIAL_DEVICE_EXTENSION extension = currentDevice->DeviceExtension;
613:
614: //
615: // While the device isn't open, disable all interrupts.
616: //
617:
618: DISABLE_ALL_INTERRUPTS(extension->Controller);
619:
620: if (extension->Jensen) {
621:
622: WRITE_MODEM_CONTROL(
623: extension->Controller,
624: (UCHAR)SERIAL_MCR_OUT2
625: );
626:
627: } else {
628:
629: WRITE_MODEM_CONTROL(
630: extension->Controller,
631: (UCHAR)0
632: );
633:
634: }
635:
636: //
637: // This should set up everything as it should be when
638: // a device is to be opened. We do need to lower the
639: // modem lines, and disable the stupid fifo so that it
640: // will show up if the user boots to dos.
641: //
642:
643: KeSynchronizeExecution(
644: extension->Interrupt,
645: SerialReset,
646: currentDevice->DeviceExtension
647: );
648: KeSynchronizeExecution( //Disables the fifo.
649: extension->Interrupt,
650: SerialMarkClose,
651: currentDevice->DeviceExtension
652: );
653: KeSynchronizeExecution(
654: extension->Interrupt,
655: SerialClrRTS,
656: currentDevice->DeviceExtension
657: );
658: KeSynchronizeExecution(
659: extension->Interrupt,
660: SerialClrDTR,
661: currentDevice->DeviceExtension
662: );
663:
664:
665: currentDevice = nextDevice;
666:
667: }
668:
669: if (DriverObject->DeviceObject) {
670:
671: status = STATUS_SUCCESS;
672:
673: //
674: // Initialize the Driver Object with driver's entry points
675: //
676:
677: DriverObject->DriverUnload = SerialUnload;
678: DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = SerialFlush;
679: DriverObject->MajorFunction[IRP_MJ_WRITE] = SerialWrite;
680: DriverObject->MajorFunction[IRP_MJ_READ] = SerialRead;
681: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SerialIoControl;
682: DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreateOpen;
683: DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
684: DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
685: DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
686: SerialQueryInformationFile;
687: DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
688: SerialSetInformationFile;
689:
690: } else {
691:
692: status = STATUS_SERIAL_NO_DEVICE_INITED;
693:
694: }
695:
696: return status;
697: }
698:
699: VOID
700: SerialPropagateDeleteSharers(
701: IN PSERIAL_DEVICE_EXTENSION Extension,
702: IN OUT PULONG CountSoFar OPTIONAL,
703: IN PKINTERRUPT Interrupt OPTIONAL
704: )
705:
706: /*++
707:
708: Routine Description:
709:
710: This routine will either propagate the interrupt object
711: to all extensions sharing the same interrupt, or it will
712: delete all devices sharing the same interrupt.
713:
714: Arguments:
715:
716: Extension - "Listhead" of all devices sharing the same
717: interrupt.
718:
719: CountSoFar - If interrupt is present and this is present,
720: we will increment the longword pointed to
721: by this pointer for each device extension
722: we stick the interrupt into.
723:
724: If interrupt is *not* present and this
725: pointer *is* present, we will decrement the
726: longword pointed to by this value for
727: each device we delete.
728:
729: If this isn't present, well, then, I guess
730: we won't do anything with it.
731:
732: Interrupt - If this is present, we propagate it to
733: all devices on that want to share the interrupt.
734:
735:
736: Return Value:
737:
738: None.
739:
740: --*/
741:
742: {
743:
744: ASSERT(Extension->OurIsr);
745:
746: SerialDump(
747: SERDIAG3,
748: ("SERIAL: In SerialPropagateDeleteSharers\n"
749: "------- Extension: %x CountSoFar: %d Interrupt: %x\n",
750: Extension,*CountSoFar,Interrupt)
751: );
752:
753: if (Interrupt) {
754:
755: PLIST_ENTRY currentEntry;
756: PLIST_ENTRY firstEntry;
757:
758: SerialDump(
759: SERDIAG5,
760: ("SERIAL: In the report propagate path\n")
761: );
762:
763: //
764: // Were supposed to place the interrupt object
765: // in every associated device object.
766: //
767:
768: currentEntry = &Extension->CommonInterruptObject;
769: firstEntry = currentEntry;
770:
771: do {
772:
773: PSERIAL_DEVICE_EXTENSION currentExtension;
774:
775: currentExtension = CONTAINING_RECORD(
776: currentEntry,
777: SERIAL_DEVICE_EXTENSION,
778: CommonInterruptObject
779: );
780:
781: currentExtension->Interrupt = Interrupt;
782:
783:
784: if (ARGUMENT_PRESENT(CountSoFar)) {
785:
786: *CountSoFar += 1;
787:
788: }
789:
790: currentEntry = currentExtension->CommonInterruptObject.Flink;
791:
792: } while (currentEntry != firstEntry);
793:
794: } else {
795:
796: LIST_ENTRY listHead;
797:
798: //
799: // We are supposed to delete all of the devices
800: // in the linked list.
801: //
802: // First we make a local list head that doesn't
803: // have the current extension as part of the list.
804: //
805: // The we cleanup and delete the "root" device.
806: //
807: // The we traverse all of the associated device
808: // extensions and null out the interrupt object
809: // (this way subsequent cleanup code won't attempt
810: // to disconnect the interrupt object) then we
811: // cleanup and delete the device.
812: //
813:
814: SerialDump(
815: SERDIAG5,
816: ("SERIAL: In the deletion/unreport path\n")
817: );
818:
819: InitializeListHead(&listHead);
820:
821: if (!IsListEmpty(&Extension->CommonInterruptObject)) {
822:
823: PLIST_ENTRY old = Extension->CommonInterruptObject.Flink;
824:
825: RemoveEntryList(&Extension->CommonInterruptObject);
826: InsertTailList(
827: old,
828: &listHead
829: );
830:
831: }
832:
833: if (ARGUMENT_PRESENT(CountSoFar)) {
834:
835: //
836: // An implication of decrementing the
837: // count is that the device has reported
838: // it's resources already. Now unreport
839: // them.
840: //
841:
842: *CountSoFar -= 1;
843: SerialUnReportResourcesDevice(Extension);
844:
845: }
846:
847: SerialCleanupDevice(Extension);
848: IoDeleteDevice(Extension->DeviceObject);
849:
850: while (!IsListEmpty(&listHead)) {
851:
852: PLIST_ENTRY head;
853: PSERIAL_DEVICE_EXTENSION currentExtension;
854:
855: head = RemoveHeadList(&listHead);
856:
857: currentExtension = CONTAINING_RECORD(
858: head,
859: SERIAL_DEVICE_EXTENSION,
860: CommonInterruptObject
861: );
862:
863: currentExtension->Interrupt = NULL;
864:
865: if (ARGUMENT_PRESENT(CountSoFar)) {
866:
867: *CountSoFar -= 1;
868: SerialUnReportResourcesDevice(currentExtension);
869:
870: }
871:
872: SerialCleanupDevice(currentExtension);
873: IoDeleteDevice(currentExtension->DeviceObject);
874:
875: }
876:
877: }
878:
879: }
880:
881: VOID
882: SerialInitializeRootInterrupt(
883: IN PDRIVER_OBJECT DriverObject,
884: IN PCONFIG_DATA ConfigData
885: )
886:
887: /*++
888:
889: Routine Description:
890:
891: This routine attempts to build a list suitable for dispatching
892: to multiple extensions for devices that want to share an interrupt.
893: Note that this includes the degenerate case of a single port who
894: wont be sharing.
895:
896: Arguments:
897:
898: DriverObject - Simply passed on to the controller initialization.
899:
900: ConfigData - Root of a "tree" of configuration records.
901:
902: Return Value:
903:
904: None.
905:
906: --*/
907:
908: {
909:
910: PSERIAL_DEVICE_EXTENSION rootExtension = NULL;
911: PCONFIG_DATA originalConfig = ConfigData;
912: PCONFIG_DATA currentConfig = ConfigData;
913: LIST_ENTRY listHead;
914:
915: SerialDump(
916: SERDIAG3,
917: ("SERIAL: In SerialInitializeRootInterrupt\n")
918: );
919:
920: //
921: // This makes the listhead imbedded in the root config
922: // record a local list head. That list no longer has the
923: // original config record as part of the list.
924: //
925:
926: InitializeListHead(&listHead);
927:
928: if (!IsListEmpty(&ConfigData->SameInterrupt)) {
929:
930: PLIST_ENTRY old = ConfigData->SameInterrupt.Flink;
931:
932: RemoveEntryList(&ConfigData->SameInterrupt);
933: InsertTailList(
934: old,
935: &listHead
936: );
937:
938: }
939:
940: //
941: // If we are on a MicroChannel bus then all the configs can simply
942: // share the interrupt.
943: //
944:
945: if (ConfigData->InterfaceType == MicroChannel) {
946:
947: //
948: // We know that all of the configs on this "chain"
949: // are using the MicroChannel.
950: //
951:
952: while (currentConfig) {
953:
954: if (!IsListEmpty(¤tConfig->SameInterruptStatus)) {
955:
956: //
957: // This is a multiport card, call its intialization.
958: //
959:
960: SerialDump(
961: SERDIAG5,
962: ("SERIAL: Attempting to make %wZ with controller at %x\n"
963: "------- and status at %x a same interrupt root of multiports\n"
964: "------- On a MicroChannel.\n",
965: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart,
966: currentConfig->InterruptStatus.LowPart)
967: );
968: SerialInitializeRootMultiPort(
969: DriverObject,
970: currentConfig,
971: &rootExtension
972: );
973:
974: } else {
975:
976: SerialDump(
977: SERDIAG5,
978: ("SERIAL: Attempting to make %wZ with controller at %x\n"
979: "------- A same interrupt single controller On a MicroChannel.\n",
980: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart)
981: );
982: SerialInitializeOneController(
983: DriverObject,
984: currentConfig,
985: FALSE,
986: &rootExtension
987: );
988:
989: }
990: SerialDump(
991: SERDIAG5,
992: ("SERIAL: It came back with a same interrupt rootExtension of %x\n",
993: rootExtension)
994: );
995:
996: if (!IsListEmpty(&listHead)) {
997:
998: PLIST_ENTRY head;
999:
1000: head = RemoveHeadList(&listHead);
1001:
1002: currentConfig = CONTAINING_RECORD(
1003: head,
1004: CONFIG_DATA,
1005: SameInterrupt
1006: );
1007:
1008: } else {
1009:
1010: currentConfig = NULL;
1011: rootExtension = NULL;
1012:
1013: }
1014:
1015: }
1016:
1017:
1018: } else {
1019:
1020: //
1021: // We have to set up to do "shareing" of interrupt resources.
1022: //
1023:
1024: //
1025: // We first keep trying to initialize one of the
1026: // configs on the chain until one succeeds.
1027: //
1028:
1029: while ((!rootExtension) && currentConfig) {
1030:
1031: NTSTATUS status;
1032:
1033: if (!IsListEmpty(¤tConfig->SameInterruptStatus)) {
1034:
1035: //
1036: // This is a multiport card, call its intialization.
1037: //
1038:
1039: SerialDump(
1040: SERDIAG5,
1041: ("SERIAL: Attempting to make %wZ with controller at %x\n"
1042: "------- and status at %x a same interrupt sharer root controller\n",
1043: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart,
1044: currentConfig->InterruptStatus.LowPart)
1045: );
1046: status = SerialInitializeRootMultiPort(
1047: DriverObject,
1048: currentConfig,
1049: &rootExtension
1050: );
1051:
1052: } else {
1053:
1054: SerialDump(
1055: SERDIAG5,
1056: ("SERIAL: Attempting to make %wZ with controller at %x\n"
1057: "------- A single same interrupt sharer root controller.\n",
1058: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart)
1059: );
1060: status = SerialInitializeOneController(
1061: DriverObject,
1062: currentConfig,
1063: FALSE,
1064: &rootExtension
1065: );
1066:
1067: }
1068:
1069: SerialDump(
1070: SERDIAG5,
1071: ("SERIAL: It came back with a same interrupt rootExtension of %x\n",
1072: rootExtension)
1073: );
1074:
1075: if (!NT_SUCCESS(status)) {
1076:
1077: //
1078: // Well that one didn't work. Try the next one.
1079: //
1080:
1081: if (!IsListEmpty(&listHead)) {
1082:
1083: PLIST_ENTRY head;
1084:
1085: head = RemoveHeadList(&listHead);
1086:
1087: currentConfig = CONTAINING_RECORD(
1088: head,
1089: CONFIG_DATA,
1090: SameInterrupt
1091: );
1092:
1093: } else {
1094:
1095: currentConfig = NULL;
1096: rootExtension = NULL;
1097:
1098: }
1099:
1100: } else {
1101:
1102: //
1103: // We save off the isr to use and the context to the
1104: // isr into the following fields. Unless the
1105: // device is actually sharing the interrupt with
1106: // another "card" this field will not be
1107: // needed.
1108: //
1109:
1110: rootExtension->TopLevelOurIsr = rootExtension->OurIsr;
1111: rootExtension->TopLevelOurIsrContext = rootExtension->OurIsrContext;
1112:
1113: }
1114:
1115:
1116: }
1117:
1118: if (rootExtension) {
1119:
1120: //
1121: // We have a root extension! Now try to
1122: // all intialize all the other configs on this
1123: // interrupt.
1124: //
1125:
1126: ULONG numberOfSharers = 1;
1127:
1128: while (!IsListEmpty(&listHead)) {
1129:
1130: NTSTATUS status;
1131: PLIST_ENTRY head;
1132: PSERIAL_DEVICE_EXTENSION newExtension;
1133:
1134: head = RemoveHeadList(&listHead);
1135:
1136: currentConfig = CONTAINING_RECORD(
1137: head,
1138: CONFIG_DATA,
1139: SameInterrupt
1140: );
1141:
1142: if (!IsListEmpty(¤tConfig->SameInterruptStatus)) {
1143:
1144: //
1145: // This is a multiport card, call its intialization.
1146: //
1147:
1148: SerialDump(
1149: SERDIAG5,
1150: ("SERIAL: Attempting to make %wZ with controller at %x\n"
1151: "------- and status at %x a same interrupt sharer multiports\n",
1152: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart,
1153: currentConfig->InterruptStatus.LowPart)
1154: );
1155: status = SerialInitializeRootMultiPort(
1156: DriverObject,
1157: currentConfig,
1158: &newExtension
1159: );
1160:
1161: } else {
1162:
1163: SerialDump(
1164: SERDIAG5,
1165: ("SERIAL: Attempting to make %wZ with controller at %x\n"
1166: "------- A single same interrupt sharer controller.\n",
1167: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart)
1168: );
1169: status = SerialInitializeOneController(
1170: DriverObject,
1171: currentConfig,
1172: FALSE,
1173: &newExtension
1174: );
1175:
1176: }
1177:
1178: SerialDump(
1179: SERDIAG5,
1180: ("SERIAL: It came back with a same interrupt newExtension of %x\n",
1181: rootExtension)
1182: );
1183:
1184:
1185: if (NT_SUCCESS(status)) {
1186:
1187: PLIST_ENTRY rootTail;
1188: PLIST_ENTRY newTail;
1189:
1190: //
1191: // Propagate the isr routine and context
1192: // up to the sharing list.
1193: //
1194:
1195: newExtension->TopLevelOurIsr = newExtension->OurIsr;
1196: newExtension->TopLevelOurIsrContext = newExtension->OurIsrContext;
1197: newExtension->OurIsr = NULL;
1198: newExtension->OurIsrContext = NULL;
1199:
1200: //
1201: // Append this top level extension onto the list of
1202: // other top level interrupt sharers.
1203: //
1204:
1205: InsertTailList(
1206: &rootExtension->TopLevelSharers,
1207: &newExtension->TopLevelSharers
1208: );
1209:
1210: //
1211: // Link together the lists of extensions that will
1212: // be using the same interrupt object (not necessarily)
1213: // the same "interrupt service routine" (actually dispatchers).
1214: //
1215:
1216: rootTail =
1217: rootExtension->CommonInterruptObject.Blink;
1218: newTail =
1219: newExtension->CommonInterruptObject.Blink;
1220:
1221: rootExtension->CommonInterruptObject.Blink =
1222: newTail;
1223: newExtension->CommonInterruptObject.Blink =
1224: rootTail;
1225: rootTail->Flink =
1226: &newExtension->CommonInterruptObject;
1227: newTail->Flink =
1228: &rootExtension->CommonInterruptObject;
1229:
1230: numberOfSharers++;
1231:
1232: }
1233:
1234: }
1235:
1236: //
1237: // All done initializing the other sharers.
1238: //
1239: // If none of the others actually initialized
1240: // the we simply degenerate into the interrupt
1241: // handling for the root extension. (This requires
1242: // no additional work.)
1243: //
1244:
1245: if (numberOfSharers > 1) {
1246:
1247: //
1248: // Replace the Isr and context for the root
1249: // with the pointer to the "sharer" dispatcher
1250: // and a pointer to the list of share entries
1251: // as context.
1252: //
1253:
1254: SerialDump(
1255: SERDIAG5,
1256: ("SERIAL: We do have more than one sharer for the interrupt.\n"
1257: "------- The controlling extension should be %x\n",
1258: rootExtension)
1259: );
1260: rootExtension->OurIsr = SerialSharerIsr;
1261: rootExtension->OurIsrContext = &rootExtension->TopLevelSharers;
1262:
1263: }
1264:
1265: }
1266:
1267: }
1268:
1269: }
1270:
1271: NTSTATUS
1272: SerialInitializeRootMultiPort(
1273: IN PDRIVER_OBJECT DriverObject,
1274: IN PCONFIG_DATA ConfigData,
1275: OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension
1276: )
1277:
1278: /*++
1279:
1280: Routine Description:
1281:
1282: This routine attempts to initialize all the ports on a
1283: multiport board and to build a structure so that an
1284: isr can dispatch to the particular ports device extension.
1285:
1286: Arguments:
1287:
1288: DriverObject - Simply passed on to the controller initialization
1289: routine.
1290:
1291: ConfigData - A linked list of configuration information for all
1292: the ports on a multiport card.
1293:
1294: DeviceExtension - Will point to the first successfully initialized
1295: port on the multiport card.
1296:
1297: Return Value:
1298:
1299: None.
1300:
1301: --*/
1302:
1303: {
1304:
1305: PSERIAL_DEVICE_EXTENSION rootExtension = NULL;
1306: PCONFIG_DATA originalConfig = ConfigData;
1307: PCONFIG_DATA currentConfig = ConfigData;
1308: ULONG indexed;
1309: ULONG portIndex;
1310: LIST_ENTRY listHead;
1311: NTSTATUS status;
1312:
1313: SerialDump(
1314: SERDIAG3,
1315: ("SERIAL: In SerialInitializeRootMultiPort\n")
1316: );
1317: *DeviceExtension = NULL;
1318:
1319: //
1320: // This makes the listhead imbedded in the root config
1321: // record a local list head. The old head of the list
1322: // (the current config) will no longer be part of the list.
1323: //
1324:
1325: InitializeListHead(&listHead);
1326:
1327: if (!IsListEmpty(&ConfigData->SameInterruptStatus)) {
1328:
1329: PLIST_ENTRY old = ConfigData->SameInterruptStatus.Flink;
1330:
1331: RemoveEntryList(&ConfigData->SameInterruptStatus);
1332: InsertTailList(
1333: old,
1334: &listHead
1335: );
1336:
1337: }
1338:
1339: //
1340: // The indexed field is valid for all ports on the chain.
1341: //
1342:
1343: indexed = ConfigData->Indexed;
1344: SerialDump(
1345: SERDIAG5,
1346: ("SERIAL: This indexed value for this multiport is: %d\n",indexed)
1347: );
1348:
1349: //
1350: // We first keep trying to initialize one of the
1351: // ports on the chain until one succeeds.
1352: //
1353:
1354: while ((!rootExtension) && currentConfig) {
1355:
1356: portIndex = currentConfig->PortIndex;
1357:
1358: SerialDump(
1359: SERDIAG5,
1360: ("SERIAL: Attempting to make %wZ with controller at %x\n"
1361: "------- and status at %x a root of multiports\n",
1362: ¤tConfig->NtNameForPort,currentConfig->Controller.LowPart,
1363: currentConfig->InterruptStatus.LowPart)
1364: );
1365: status = SerialInitializeOneController(
1366: DriverObject,
1367: currentConfig,
1368: TRUE,
1369: &rootExtension
1370: );
1371: SerialDump(
1372: SERDIAG5,
1373: ("SERIAL: Multiport came back with a same interrupt rootExtension of %x\n",
1374: rootExtension)
1375: );
1376:
1377: if (!NT_SUCCESS(status)) {
1378:
1379: //
1380: // Well that one didn't work. Try the next one.
1381: //
1382:
1383: if (!IsListEmpty(&listHead)) {
1384:
1385: PLIST_ENTRY head;
1386:
1387: head = RemoveHeadList(&listHead);
1388:
1389: currentConfig = CONTAINING_RECORD(
1390: head,
1391: CONFIG_DATA,
1392: SameInterruptStatus
1393: );
1394:
1395: } else {
1396:
1397: currentConfig = NULL;
1398: rootExtension = NULL;
1399:
1400: }
1401:
1402: }
1403:
1404: }
1405:
1406: if (rootExtension) {
1407:
1408: //
1409: // Well we have at least one controller. We build a local
1410: // dispatch structure. If we end up being able to
1411: // intialize another port then we will allocate
1412: // the dispatch structure out of pool. If we can't
1413: // intialize anymore ports then this degenerates into a
1414: // single port case.
1415: //
1416:
1417: ULONG numberOfPorts = 1;
1418: SERIAL_MULTIPORT_DISPATCH dispatch;
1419:
1420: rootExtension->PortOnAMultiportCard = TRUE;
1421:
1422: RtlZeroMemory(
1423: &dispatch,
1424: sizeof(SERIAL_MULTIPORT_DISPATCH)
1425: );
1426:
1427: if (!indexed) {
1428:
1429: dispatch.UsablePortMask = 1 << (portIndex-1);
1430:
1431: }
1432:
1433: dispatch.InterruptStatus = rootExtension->InterruptStatus;
1434:
1435: dispatch.Extensions[portIndex-1] = rootExtension;
1436:
1437: while (!IsListEmpty(&listHead)) {
1438:
1439: PLIST_ENTRY head;
1440: PSERIAL_DEVICE_EXTENSION newExtension;
1441:
1442: head = RemoveHeadList(&listHead);
1443:
1444: currentConfig = CONTAINING_RECORD(
1445: head,
1446: CONFIG_DATA,
1447: SameInterruptStatus
1448: );
1449:
1450: portIndex = currentConfig->PortIndex;
1451:
1452: if (NT_SUCCESS(SerialInitializeOneController(
1453: DriverObject,
1454: currentConfig,
1455: FALSE,
1456: &newExtension
1457: ))) {
1458:
1459: numberOfPorts++;
1460: newExtension->PortOnAMultiportCard = TRUE;
1461:
1462: if (!indexed) {
1463:
1464: dispatch.UsablePortMask |= 1 << (portIndex-1);
1465:
1466: }
1467:
1468: dispatch.Extensions[portIndex-1] = newExtension;
1469:
1470: InsertTailList(
1471: &rootExtension->CommonInterruptObject,
1472: &newExtension->CommonInterruptObject
1473: );
1474:
1475: }
1476:
1477: }
1478:
1479: //
1480: // If the number of ports is still one that means we
1481: // couldn't initialize any more extensions. This then
1482: // degenerates into a single port card. Note that there
1483: // is no work to do in that case, it was set up in
1484: // SerialInitializeSingleController.
1485: //
1486:
1487: if (numberOfPorts > 1) {
1488:
1489: //
1490: // Now allocate the dispatch structure out of pool
1491: // since it certain that we will actually use it.
1492: //
1493:
1494: rootExtension->OurIsrContext = ExAllocatePool(
1495: NonPagedPool,
1496: sizeof(SERIAL_MULTIPORT_DISPATCH)
1497: );
1498:
1499: if (!rootExtension->OurIsrContext) {
1500:
1501: //
1502: // Darn! Couldn't allocate the dispatch structure.
1503: //
1504: // Seems as though the safest thing to do in
1505: // this case is to act as though none of the ports
1506: // initialized. Go through and delete all of the
1507: // devices that were initialized.
1508: //
1509: // This should be fairly safe since the initialize controller
1510: // code completely disables the port from interrupting.
1511: //
1512:
1513: ULONG i;
1514:
1515: SerialDump(
1516: SERERRORS,
1517: ("SERIAL: Couldn't allocate memory for %wZ\n"
1518: "------- multiport dispatch structure"
1519: "------- deleting all associated devices",
1520: &rootExtension->DeviceName)
1521: );
1522:
1523: //
1524: // We couldn't allocate memory for it, hopefully
1525: // the logger can make some headway.
1526: //
1527:
1528: SerialLogError(
1529: rootExtension->DeviceObject->DriverObject,
1530: rootExtension->DeviceObject,
1531: rootExtension->OriginalController,
1532: SerialPhysicalZero,
1533: 0,
1534: 0,
1535: 0,
1536: 2,
1537: STATUS_SUCCESS,
1538: SERIAL_INSUFFICIENT_RESOURCES,
1539: 0,
1540: NULL,
1541: 0,
1542: NULL
1543: );
1544:
1545: for (
1546: i = 0;
1547: numberOfPorts;
1548: i++
1549: ) {
1550:
1551: if (dispatch.Extensions[i]) {
1552:
1553: SerialCleanupDevice(dispatch.Extensions[i]);
1554: IoDeleteDevice(
1555: dispatch.Extensions[i]->DeviceObject
1556: );
1557: numberOfPorts--;
1558:
1559: }
1560:
1561: }
1562:
1563: return STATUS_INSUFFICIENT_RESOURCES;
1564:
1565: } else {
1566:
1567: ULONG i;
1568: PSERIAL_MULTIPORT_DISPATCH allocatedDispatch =
1569: rootExtension->OurIsrContext;
1570:
1571: //
1572: // Go throught the list of extensions and NULL
1573: // their pointers to the isr. The only extension
1574: // that will truely have an isr is the root.
1575: //
1576:
1577: allocatedDispatch->UsablePortMask = dispatch.UsablePortMask;
1578: allocatedDispatch->InterruptStatus = dispatch.InterruptStatus;
1579:
1580: for (
1581: i = 0;
1582: i < SERIAL_MAX_PORTS_NONINDEXED;
1583: i++
1584: ) {
1585:
1586: allocatedDispatch->Extensions[i] = dispatch.Extensions[i];
1587:
1588: if (dispatch.Extensions[i]) {
1589: dispatch.Extensions[i]->OurIsr = NULL;
1590: }
1591:
1592: }
1593:
1594: if (indexed) {
1595:
1596: rootExtension->OurIsr = SerialIndexedMultiportIsr;
1597:
1598: } else {
1599:
1600: rootExtension->OurIsr = SerialBitMappedMultiportIsr;
1601:
1602: }
1603:
1604: }
1605:
1606: }
1607:
1608: *DeviceExtension = rootExtension;
1609: return STATUS_SUCCESS;
1610:
1611: } else {
1612:
1613: return STATUS_UNSUCCESSFUL;
1614:
1615: }
1616:
1617: }
1618:
1619: NTSTATUS
1620: SerialInitializeOneController(
1621: IN PDRIVER_OBJECT DriverObject,
1622: IN PCONFIG_DATA ConfigData,
1623: IN BOOLEAN MapInterruptStatus,
1624: OUT PSERIAL_DEVICE_EXTENSION *Extension
1625: )
1626:
1627: /*++
1628:
1629: Routine Description:
1630:
1631: This routine will call the real port initializatio code.
1632: If all was successful, it will save off in the extension
1633: the isr that should be used as well as a pointer to
1634: the extension itself.
1635:
1636: This is the only routine responsible for deleting the
1637: configuration information subsequent to getting it all
1638: from the registry.
1639:
1640: Arguments:
1641:
1642: DriverObject - Simply passed on to the controller initialization
1643: routine.
1644:
1645: ConfigData - Pointer to a record for a single port.
1646:
1647: MapInterruptStatus - Simply passed on to the controller initialization
1648: routine.
1649:
1650: Extension - Points to the device extension of the successfully
1651: initialized controller.
1652:
1653: Return Value:
1654:
1655: Status returned from the controller initialization routine.
1656:
1657: --*/
1658:
1659: {
1660:
1661: NTSTATUS status;
1662:
1663: status = SerialInitializeController(
1664: DriverObject,
1665: ConfigData,
1666: MapInterruptStatus,
1667: Extension
1668: );
1669:
1670: if (NT_SUCCESS(status)) {
1671:
1672: //
1673: // We successfully initialized the single controller.
1674: // Stick the isr routine and the parameter for it
1675: // back into the extension.
1676: //
1677:
1678: (*Extension)->OurIsr = SerialISR;
1679: (*Extension)->OurIsrContext = *Extension;
1680:
1681: } else {
1682:
1683: *Extension = NULL;
1684:
1685: }
1686:
1687: return status;
1688:
1689: }
1690:
1691: NTSTATUS
1692: SerialInitializeController(
1693: IN PDRIVER_OBJECT DriverObject,
1694: IN PCONFIG_DATA ConfigData,
1695: IN BOOLEAN MapInterruptStatus,
1696: OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension
1697: )
1698:
1699: /*++
1700:
1701: Routine Description:
1702:
1703: Really too many things to mention here. In general, it forms
1704: and sets up names, creates the device, initializes kernel
1705: synchronization structures, allocates the typeahead buffer,
1706: sets up defaults, etc.
1707:
1708: Arguments:
1709:
1710: DriverObject - Just used to create the device object.
1711:
1712: ConfigData - Pointer to a record for a single port.
1713:
1714: NOTE: This routine will deallocate the config data.
1715:
1716: MapInterruptStatus - If true, we will attempt to map the
1717: interrupt status register associated
1718: with this port..
1719:
1720: DeviceExtension - Points to the device extension of the successfully
1721: initialized controller.
1722:
1723: Return Value:
1724:
1725: STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
1726: otherwise.
1727:
1728: --*/
1729:
1730: {
1731:
1732: //
1733: // This will hold the string that we need to use to describe
1734: // the name of the device to the IO system.
1735: //
1736: UNICODE_STRING uniNameString;
1737:
1738: //
1739: // Holds the NT Status that is returned from each call to the
1740: // kernel and executive.
1741: //
1742: NTSTATUS status = STATUS_SUCCESS;
1743:
1744: //
1745: // Points to the device object (not the extension) created
1746: // for this device.
1747: //
1748: PDEVICE_OBJECT deviceObject;
1749:
1750: //
1751: // Points to the device extension for the device object
1752: // (see above) created for the device we are initializing.
1753: //
1754: PSERIAL_DEVICE_EXTENSION extension = NULL;
1755:
1756: //
1757: // Indicates that we successfully reported the resources
1758: // used by this device.
1759: //
1760: BOOLEAN reportedResources = FALSE;
1761:
1762: //
1763: // Indicates that a conflict was detected for resources
1764: // used by this device.
1765: //
1766: BOOLEAN conflictDetected = FALSE;
1767:
1768: SerialDump(
1769: SERDIAG1,
1770: ("SERIAL: Initializing for configuration record of %wZ\n",
1771: &ConfigData->NtNameForPort)
1772: );
1773: if ((*KdComPortInUse) ==
1774:
1775: ((PUCHAR)(ConfigData->Controller.LowPart))) {
1776: SerialDump(
1777: SERERRORS,
1778: ("SERIAL: Kernel debugger is using port at address %x\n"
1779: "------ Serial driver will not load port %wZ\n",
1780: *KdComPortInUse,&ConfigData->SymbolicLinkName)
1781: );
1782:
1783: SerialLogError(
1784: DriverObject,
1785: NULL,
1786: ConfigData->Controller,
1787: SerialPhysicalZero,
1788: 0,
1789: 0,
1790: 0,
1791: 3,
1792: STATUS_SUCCESS,
1793: SERIAL_KERNEL_DEBUGGER_ACTIVE,
1794: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
1795: ConfigData->SymbolicLinkName.Buffer,
1796: 0,
1797: NULL
1798: );
1799:
1800: ExFreePool(ConfigData->ObjectDirectory.Buffer);
1801: ExFreePool(ConfigData->NtNameForPort.Buffer);
1802: ExFreePool(ConfigData->SymbolicLinkName.Buffer);
1803: ExFreePool(ConfigData);
1804: return STATUS_INSUFFICIENT_RESOURCES;
1805:
1806: }
1807:
1808: //
1809: // Form a name like \Device\Serial0.
1810: //
1811: // First we allocate space for the name.
1812: //
1813:
1814: RtlInitUnicodeString(
1815: &uniNameString,
1816: NULL
1817: );
1818:
1819: uniNameString.MaximumLength = sizeof(L"\\Device\\") +
1820: ConfigData->NtNameForPort.Length+sizeof(WCHAR);
1821: uniNameString.Buffer = ExAllocatePool(
1822: PagedPool,
1823: uniNameString.MaximumLength
1824: );
1825:
1826: //
1827: // The only reason the above could have failed is if
1828: // there wasn't enough system memory to form the UNICODE
1829: // string.
1830: //
1831:
1832: if (!uniNameString.Buffer) {
1833:
1834: SerialDump(
1835: SERERRORS,
1836: ("SERIAL: Could not form Unicode name string for %wZ\n",
1837: &ConfigData->NtNameForPort)
1838: );
1839: SerialLogError(
1840: DriverObject,
1841: NULL,
1842: ConfigData->Controller,
1843: SerialPhysicalZero,
1844: 0,
1845: 0,
1846: 0,
1847: 4,
1848: STATUS_SUCCESS,
1849: SERIAL_INSUFFICIENT_RESOURCES,
1850: 0,
1851: NULL,
1852: 0,
1853: NULL
1854: );
1855: ExFreePool(ConfigData->ObjectDirectory.Buffer);
1856: ExFreePool(ConfigData->NtNameForPort.Buffer);
1857: ExFreePool(ConfigData->SymbolicLinkName.Buffer);
1858: ExFreePool(ConfigData);
1859: return STATUS_INSUFFICIENT_RESOURCES;
1860:
1861: }
1862:
1863: //
1864: // Actually form the Name.
1865: //
1866:
1867: RtlZeroMemory(
1868: uniNameString.Buffer,
1869: uniNameString.MaximumLength
1870: );
1871:
1872: RtlAppendUnicodeToString(
1873: &uniNameString,
1874: L"\\Device\\"
1875: );
1876:
1877: RtlAppendUnicodeStringToString(
1878: &uniNameString,
1879: &ConfigData->NtNameForPort
1880: );
1881:
1882: //
1883: // Create the device object for this device.
1884: //
1885:
1886: status = IoCreateDevice(
1887: DriverObject,
1888: sizeof(SERIAL_DEVICE_EXTENSION),
1889: &uniNameString,
1890: FILE_DEVICE_SERIAL_PORT,
1891: 0,
1892: TRUE,
1893: &deviceObject
1894: );
1895:
1896: //
1897: // If we couldn't create the device object, then there
1898: // is no point in going on.
1899: //
1900:
1901: if (!NT_SUCCESS(status)) {
1902:
1903: SerialDump(
1904: SERERRORS,
1905: ("SERIAL: Could not create a device for %wZ\n",
1906: &ConfigData->NtNameForPort)
1907: );
1908: SerialLogError(
1909: DriverObject,
1910: NULL,
1911: ConfigData->Controller,
1912: SerialPhysicalZero,
1913: 0,
1914: 0,
1915: 0,
1916: 5,
1917: status,
1918: SERIAL_INSUFFICIENT_RESOURCES,
1919: 0,
1920: NULL,
1921: 0,
1922: NULL
1923: );
1924: ExFreePool(ConfigData->ObjectDirectory.Buffer);
1925: ExFreePool(ConfigData->NtNameForPort.Buffer);
1926: ExFreePool(ConfigData->SymbolicLinkName.Buffer);
1927: ExFreePool(ConfigData);
1928: ExFreePool(uniNameString.Buffer);
1929: return STATUS_INSUFFICIENT_RESOURCES;
1930:
1931: }
1932:
1933: //
1934: // The device object has a pointer to an area of non-paged
1935: // pool allocated for this device. This will be the device
1936: // extension.
1937: //
1938:
1939: extension = deviceObject->DeviceExtension;
1940:
1941: //
1942: // Zero all of the memory associated with the device
1943: // extension.
1944: //
1945:
1946: RtlZeroMemory(
1947: extension,
1948: sizeof(SERIAL_DEVICE_EXTENSION)
1949: );
1950:
1951: //
1952: // Propagate that it is a jensen.
1953: //
1954:
1955: extension->Jensen = ConfigData->Jensen;
1956:
1957: //
1958: // So far, we don't know if this extension will be
1959: // shareing it's interrupt object with any other serial
1960: // port.
1961: //
1962:
1963: InitializeListHead(&extension->TopLevelSharers);
1964: InitializeListHead(&extension->CommonInterruptObject);
1965:
1966: //
1967: // Save off our name.
1968: //
1969:
1970: RtlInitUnicodeString(
1971: &extension->DeviceName,
1972: NULL
1973: );
1974:
1975: extension->DeviceName.Length = uniNameString.Length;
1976: extension->DeviceName.MaximumLength = uniNameString.MaximumLength;
1977: extension->DeviceName.Buffer = uniNameString.Buffer;
1978:
1979: //
1980: // Just initialize the names so that we don't try
1981: // to "clean" them up if we cant intialize the
1982: // controller all the way.
1983: //
1984:
1985: RtlInitUnicodeString(
1986: &extension->ObjectDirectory,
1987: NULL
1988: );
1989: RtlInitUnicodeString(
1990: &extension->NtNameForPort,
1991: NULL
1992: );
1993: RtlInitUnicodeString(
1994: &extension->SymbolicLinkName,
1995: NULL
1996: );
1997:
1998: //
1999: // Initialize the list heads for the read, write, and mask queues.
2000: //
2001: // These lists will hold all of the queued IRP's for the device.
2002: //
2003:
2004: InitializeListHead(&extension->ReadQueue);
2005: InitializeListHead(&extension->WriteQueue);
2006: InitializeListHead(&extension->MaskQueue);
2007: InitializeListHead(&extension->PurgeQueue);
2008:
2009: //
2010: // Initialize the spinlock associated with fields read (& set)
2011: // by IO Control functions.
2012: //
2013:
2014: KeInitializeSpinLock(&extension->ControlLock);
2015:
2016: //
2017: // Initialize the timers used to timeout operations.
2018: //
2019:
2020: KeInitializeTimer(&extension->ReadRequestTotalTimer);
2021: KeInitializeTimer(&extension->ReadRequestIntervalTimer);
2022: KeInitializeTimer(&extension->WriteRequestTotalTimer);
2023: KeInitializeTimer(&extension->ImmediateTotalTimer);
2024: KeInitializeTimer(&extension->XoffCountTimer);
2025: KeInitializeTimer(&extension->LowerRTSTimer);
2026:
2027: //
2028: // Intialialize the dpcs that will be used to complete
2029: // or timeout various IO operations.
2030: //
2031:
2032: KeInitializeDpc(
2033: &extension->CompleteWriteDpc,
2034: SerialCompleteWrite,
2035: extension
2036: );
2037:
2038: KeInitializeDpc(
2039: &extension->CompleteReadDpc,
2040: SerialCompleteRead,
2041: extension
2042: );
2043:
2044: KeInitializeDpc(
2045: &extension->TotalReadTimeoutDpc,
2046: SerialReadTimeout,
2047: extension
2048: );
2049:
2050: KeInitializeDpc(
2051: &extension->IntervalReadTimeoutDpc,
2052: SerialIntervalReadTimeout,
2053: extension
2054: );
2055:
2056: KeInitializeDpc(
2057: &extension->TotalWriteTimeoutDpc,
2058: SerialWriteTimeout,
2059: extension
2060: );
2061:
2062: KeInitializeDpc(
2063: &extension->CommErrorDpc,
2064: SerialCommError,
2065: extension
2066: );
2067:
2068: KeInitializeDpc(
2069: &extension->CompleteImmediateDpc,
2070: SerialCompleteImmediate,
2071: extension
2072: );
2073:
2074: KeInitializeDpc(
2075: &extension->TotalImmediateTimeoutDpc,
2076: SerialTimeoutImmediate,
2077: extension
2078: );
2079:
2080: KeInitializeDpc(
2081: &extension->CommWaitDpc,
2082: SerialCompleteWait,
2083: extension
2084: );
2085:
2086: KeInitializeDpc(
2087: &extension->XoffCountTimeoutDpc,
2088: SerialTimeoutXoff,
2089: extension
2090: );
2091:
2092: KeInitializeDpc(
2093: &extension->XoffCountCompleteDpc,
2094: SerialCompleteXoff,
2095: extension
2096: );
2097:
2098: KeInitializeDpc(
2099: &extension->StartTimerLowerRTSDpc,
2100: SerialStartTimerLowerRTS,
2101: extension
2102: );
2103:
2104: KeInitializeDpc(
2105: &extension->PerhapsLowerRTSDpc,
2106: SerialInvokePerhapsLowerRTS,
2107: extension
2108: );
2109:
2110: if (!((ConfigData->ClockRate == 1843200) ||
2111: (ConfigData->ClockRate == 3072000) ||
2112: (ConfigData->ClockRate == 4233600) ||
2113: (ConfigData->ClockRate == 8000000))) {
2114:
2115: SerialLogError(
2116: extension->DeviceObject->DriverObject,
2117: extension->DeviceObject,
2118: ConfigData->Controller,
2119: SerialPhysicalZero,
2120: 0,
2121: 0,
2122: 0,
2123: 6,
2124: STATUS_SUCCESS,
2125: SERIAL_UNSUPPORTED_CLOCK_RATE,
2126: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
2127: ConfigData->SymbolicLinkName.Buffer,
2128: 0,
2129: NULL
2130: );
2131: SerialDump(
2132: SERERRORS,
2133: ("SERIAL: Invalid clock rate specified for %wZ\n",
2134: &ConfigData->NtNameForPort)
2135: );
2136: status = STATUS_SERIAL_NO_DEVICE_INITED;
2137: goto ExtensionCleanup;
2138:
2139: }
2140:
2141: //
2142: // Save the value of clock input to the part. We use this to calculate
2143: // the divisor latch value. The value is in Hertz.
2144: //
2145:
2146: extension->ClockRate = ConfigData->ClockRate;
2147:
2148: //
2149: // Get a "back pointer" to the device object and specify
2150: // that this driver only supports buffered IO. This basically
2151: // means that the IO system copies the users data to and from
2152: // system supplied buffers.
2153: //
2154:
2155: extension->DeviceObject = deviceObject;
2156: deviceObject->Flags |= DO_BUFFERED_IO;
2157:
2158: //
2159: // Map the memory for the control registers for the serial device
2160: // into virtual memory.
2161: //
2162:
2163: extension->Controller = SerialGetMappedAddress(
2164: ConfigData->InterfaceType,
2165: ConfigData->BusNumber,
2166: ConfigData->Controller,
2167: ConfigData->SpanOfController,
2168: (BOOLEAN)ConfigData->AddressSpace,
2169: &extension->UnMapRegisters
2170: );
2171:
2172:
2173: if (!extension->Controller) {
2174:
2175: SerialLogError(
2176: extension->DeviceObject->DriverObject,
2177: extension->DeviceObject,
2178: ConfigData->Controller,
2179: SerialPhysicalZero,
2180: 0,
2181: 0,
2182: 0,
2183: 7,
2184: STATUS_SUCCESS,
2185: SERIAL_REGISTERS_NOT_MAPPED,
2186: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
2187: ConfigData->SymbolicLinkName.Buffer,
2188: 0,
2189: NULL
2190: );
2191: SerialDump(
2192: SERERRORS,
2193: ("SERIAL: Could not map memory for device registers for %wZ\n",
2194: &ConfigData->NtNameForPort)
2195: );
2196: extension->UnMapRegisters = FALSE;
2197: status = STATUS_NONE_MAPPED;
2198: goto ExtensionCleanup;
2199:
2200: }
2201:
2202: extension->AddressSpace = ConfigData->AddressSpace;
2203: extension->OriginalController = ConfigData->Controller;
2204: extension->SpanOfController = ConfigData->SpanOfController;
2205:
2206: //
2207: // if we were requested to map the interrupt status do so.
2208: //
2209:
2210: if (MapInterruptStatus) {
2211:
2212: extension->InterruptStatus = SerialGetMappedAddress(
2213: ConfigData->InterfaceType,
2214: ConfigData->BusNumber,
2215: ConfigData->InterruptStatus,
2216: ConfigData->SpanOfInterruptStatus,
2217: (BOOLEAN)ConfigData->AddressSpace,
2218: &extension->UnMapStatus
2219: );
2220:
2221:
2222: if (!extension->InterruptStatus) {
2223:
2224: SerialLogError(
2225: extension->DeviceObject->DriverObject,
2226: extension->DeviceObject,
2227: ConfigData->Controller,
2228: SerialPhysicalZero,
2229: 0,
2230: 0,
2231: 0,
2232: 8,
2233: STATUS_SUCCESS,
2234: SERIAL_REGISTERS_NOT_MAPPED,
2235: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
2236: ConfigData->SymbolicLinkName.Buffer,
2237: 0,
2238: NULL
2239: );
2240: SerialDump(
2241: SERERRORS,
2242: ("SERIAL: Could not map memory for interrupt status for %wZ\n",
2243: &ConfigData->NtNameForPort)
2244: );
2245: extension->UnMapRegisters = FALSE;
2246: status = STATUS_NONE_MAPPED;
2247: goto ExtensionCleanup;
2248:
2249: }
2250:
2251: extension->OriginalInterruptStatus = ConfigData->InterruptStatus;
2252: extension->SpanOfInterruptStatus = ConfigData->SpanOfInterruptStatus;
2253:
2254: }
2255:
2256: //
2257: // For now, assume that unless we are on a MicroChannel
2258: // machine the interrupt isn't shareable.
2259: //
2260: // BUG BUG Is there some EISA data out there that will
2261: // BUG BUG tell us whether the card is a true EISA card?
2262: //
2263:
2264: if (ConfigData->InterfaceType == MicroChannel) {
2265:
2266: extension->InterruptShareable = TRUE;
2267:
2268: } else {
2269:
2270: extension->InterruptShareable = FALSE;
2271:
2272: }
2273:
2274: //
2275: // Save off the interface type and the bus number.
2276: //
2277:
2278: extension->InterfaceType = ConfigData->InterfaceType;
2279: extension->BusNumber = ConfigData->BusNumber;
2280:
2281: //
2282: // From the Hal, get the interrupt vector and level.
2283: //
2284:
2285: extension->InterruptMode = ConfigData->InterruptMode;
2286: extension->OriginalIrql = ConfigData->OriginalIrql;
2287: extension->OriginalVector = ConfigData->OriginalVector;
2288: extension->Vector = HalGetInterruptVector(
2289: ConfigData->InterfaceType,
2290: ConfigData->BusNumber,
2291: ConfigData->OriginalIrql,
2292: ConfigData->OriginalVector,
2293: &extension->Irql,
2294: &extension->ProcessorAffinity
2295: );
2296:
2297: //
2298: // Report it's resources. We do this now because we are just
2299: // about to touch the resources for the first time.
2300: //
2301:
2302: SerialReportResourcesDevice(
2303: extension,
2304: &conflictDetected
2305: );
2306:
2307: if (conflictDetected) {
2308:
2309: SerialDump(
2310: SERERRORS,
2311: ("SERIAL: Reporting resources for %wZ with extension %x\n"
2312: "------- detected a conflict\n",
2313: &extension->NtNameForPort,extension)
2314: );
2315: SerialLogError(
2316: extension->DeviceObject->DriverObject,
2317: extension->DeviceObject,
2318: ConfigData->Controller,
2319: SerialPhysicalZero,
2320: 0,
2321: 0,
2322: 0,
2323: 9,
2324: STATUS_SUCCESS,
2325: SERIAL_RESOURCE_CONFLICT,
2326: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
2327: ConfigData->SymbolicLinkName.Buffer,
2328: 0,
2329: NULL
2330: );
2331:
2332: //
2333: // This status won't propagate far.
2334: //
2335:
2336: status = STATUS_INSUFFICIENT_RESOURCES;
2337: goto ExtensionCleanup;
2338:
2339: }
2340:
2341: reportedResources = TRUE;
2342:
2343: //
2344: // Before we test whether the port exists (which will enable the FIFO)
2345: // convert the rx trigger value to what should be used in the register.
2346: //
2347: // If a bogus value was given - crank them down to 1.
2348: //
2349:
2350: switch (ConfigData->RxFIFO) {
2351:
2352: case 1:
2353:
2354: extension->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
2355: break;
2356:
2357: case 4:
2358:
2359: extension->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
2360: break;
2361:
2362: case 8:
2363:
2364: extension->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
2365: break;
2366:
2367: case 14:
2368:
2369: extension->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
2370: break;
2371:
2372: default:
2373:
2374: extension->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
2375: break;
2376:
2377: }
2378:
2379: if (!SerialDoesPortExist(
2380: extension,
2381: &ConfigData->SymbolicLinkName,
2382: ConfigData->ForceFifoEnable
2383: )) {
2384:
2385: //
2386: // We couldn't verify that there was actually a
2387: // port. No need to log an error as the port exist
2388: // code will log exactly why.
2389: //
2390:
2391: SerialDump(
2392: SERERRORS,
2393: ("SERIAL: Does Port exist test failed for %wZ\n",
2394: &ConfigData->NtNameForPort)
2395: );
2396: status = STATUS_NO_SUCH_DEVICE;
2397: goto ExtensionCleanup;
2398:
2399: }
2400:
2401: //
2402: // If the user requested that we disable the port, then
2403: // do it now. Log the fact that the port has been disabled.
2404: //
2405:
2406: if (ConfigData->DisablePort) {
2407:
2408: SerialDump(
2409: SERERRORS,
2410: ("SERIAL: disabled port %wZ as requested in configuration\n",
2411: &ConfigData->NtNameForPort)
2412: );
2413: status = STATUS_NO_SUCH_DEVICE;
2414: SerialLogError(
2415: extension->DeviceObject->DriverObject,
2416: extension->DeviceObject,
2417: ConfigData->Controller,
2418: SerialPhysicalZero,
2419: 0,
2420: 0,
2421: 0,
2422: 57,
2423: STATUS_SUCCESS,
2424: SERIAL_DISABLED_PORT,
2425: ConfigData->SymbolicLinkName.Length+sizeof(WCHAR),
2426: ConfigData->SymbolicLinkName.Buffer,
2427: 0,
2428: NULL
2429: );
2430: goto ExtensionCleanup;
2431:
2432: }
2433:
2434:
2435:
2436: //
2437: // Set up the default device control fields.
2438: // Note that if the values are changed after
2439: // the file is open, they do NOT revert back
2440: // to the old value at file close.
2441: //
2442:
2443: extension->SpecialChars.XonChar = SERIAL_DEF_XON;
2444: extension->SpecialChars.XoffChar = SERIAL_DEF_XOFF;
2445: extension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
2446:
2447: extension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
2448:
2449: //
2450: // Default Line control protocol. 7E1
2451: //
2452: // Seven data bits.
2453: // Even parity.
2454: // 1 Stop bits.
2455: //
2456:
2457: extension->LineControl = SERIAL_7_DATA |
2458: SERIAL_EVEN_PARITY |
2459: SERIAL_NONE_PARITY;
2460:
2461: extension->ValidDataMask = 0x7f;
2462: extension->CurrentBaud = 1200;
2463:
2464:
2465: //
2466: // We set up the default xon/xoff limits.
2467: //
2468:
2469: extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
2470: extension->HandFlow.XonLimit = extension->BufferSize >> 1;
2471:
2472: extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
2473: (extension->BufferSize>>4));
2474:
2475: SerialDump(
2476: SERDIAG1,
2477: ("SERIAL: The default interrupt read buffer size is: %d\n"
2478: "------ The XoffLimit is : %d\n"
2479: "------ The XonLimit is : %d\n"
2480: "------ The pt 8 size is : %d\n",
2481: extension->BufferSize,
2482: extension->HandFlow.XoffLimit,
2483: extension->HandFlow.XonLimit,
2484: extension->BufferSizePt8)
2485: );
2486:
2487: //
2488: // Go through all the "named" baud rates to find out which ones
2489: // can be supported with this port.
2490: //
2491:
2492: extension->SupportedBauds = SERIAL_BAUD_USER;
2493:
2494: {
2495:
2496: SHORT junk;
2497:
2498: if (!NT_ERROR(SerialGetDivisorFromBaud(
2499: extension->ClockRate,
2500: (LONG)75,
2501: &junk
2502: ))) {
2503:
2504: extension->SupportedBauds |= SERIAL_BAUD_075;
2505:
2506: }
2507:
2508: if (!NT_ERROR(SerialGetDivisorFromBaud(
2509: extension->ClockRate,
2510: (LONG)110,
2511: &junk
2512: ))) {
2513:
2514: extension->SupportedBauds |= SERIAL_BAUD_110;
2515:
2516: }
2517:
2518: if (!NT_ERROR(SerialGetDivisorFromBaud(
2519: extension->ClockRate,
2520: (LONG)135,
2521: &junk
2522: ))) {
2523:
2524: extension->SupportedBauds |= SERIAL_BAUD_134_5;
2525:
2526: }
2527:
2528: if (!NT_ERROR(SerialGetDivisorFromBaud(
2529: extension->ClockRate,
2530: (LONG)150,
2531: &junk
2532: ))) {
2533:
2534: extension->SupportedBauds |= SERIAL_BAUD_150;
2535:
2536: }
2537:
2538: if (!NT_ERROR(SerialGetDivisorFromBaud(
2539: extension->ClockRate,
2540: (LONG)300,
2541: &junk
2542: ))) {
2543:
2544: extension->SupportedBauds |= SERIAL_BAUD_300;
2545:
2546: }
2547:
2548: if (!NT_ERROR(SerialGetDivisorFromBaud(
2549: extension->ClockRate,
2550: (LONG)600,
2551: &junk
2552: ))) {
2553:
2554: extension->SupportedBauds |= SERIAL_BAUD_600;
2555:
2556: }
2557:
2558: if (!NT_ERROR(SerialGetDivisorFromBaud(
2559: extension->ClockRate,
2560: (LONG)1200,
2561: &junk
2562: ))) {
2563:
2564: extension->SupportedBauds |= SERIAL_BAUD_1200;
2565:
2566: }
2567:
2568: if (!NT_ERROR(SerialGetDivisorFromBaud(
2569: extension->ClockRate,
2570: (LONG)1800,
2571: &junk
2572: ))) {
2573:
2574: extension->SupportedBauds |= SERIAL_BAUD_1800;
2575:
2576: }
2577:
2578: if (!NT_ERROR(SerialGetDivisorFromBaud(
2579: extension->ClockRate,
2580: (LONG)2400,
2581: &junk
2582: ))) {
2583:
2584: extension->SupportedBauds |= SERIAL_BAUD_2400;
2585:
2586: }
2587:
2588: if (!NT_ERROR(SerialGetDivisorFromBaud(
2589: extension->ClockRate,
2590: (LONG)4800,
2591: &junk
2592: ))) {
2593:
2594: extension->SupportedBauds |= SERIAL_BAUD_4800;
2595:
2596: }
2597:
2598: if (!NT_ERROR(SerialGetDivisorFromBaud(
2599: extension->ClockRate,
2600: (LONG)7200,
2601: &junk
2602: ))) {
2603:
2604: extension->SupportedBauds |= SERIAL_BAUD_7200;
2605:
2606: }
2607:
2608: if (!NT_ERROR(SerialGetDivisorFromBaud(
2609: extension->ClockRate,
2610: (LONG)9600,
2611: &junk
2612: ))) {
2613:
2614: extension->SupportedBauds |= SERIAL_BAUD_9600;
2615:
2616: }
2617:
2618: if (!NT_ERROR(SerialGetDivisorFromBaud(
2619: extension->ClockRate,
2620: (LONG)14400,
2621: &junk
2622: ))) {
2623:
2624: extension->SupportedBauds |= SERIAL_BAUD_14400;
2625:
2626: }
2627:
2628: if (!NT_ERROR(SerialGetDivisorFromBaud(
2629: extension->ClockRate,
2630: (LONG)19200,
2631: &junk
2632: ))) {
2633:
2634: extension->SupportedBauds |= SERIAL_BAUD_19200;
2635:
2636: }
2637:
2638: if (!NT_ERROR(SerialGetDivisorFromBaud(
2639: extension->ClockRate,
2640: (LONG)38400,
2641: &junk
2642: ))) {
2643:
2644: extension->SupportedBauds |= SERIAL_BAUD_38400;
2645:
2646: }
2647:
2648: if (!NT_ERROR(SerialGetDivisorFromBaud(
2649: extension->ClockRate,
2650: (LONG)56000,
2651: &junk
2652: ))) {
2653:
2654: extension->SupportedBauds |= SERIAL_BAUD_56K;
2655:
2656: }
2657: if (!NT_ERROR(SerialGetDivisorFromBaud(
2658: extension->ClockRate,
2659: (LONG)57600,
2660: &junk
2661: ))) {
2662:
2663: extension->SupportedBauds |= SERIAL_BAUD_57600;
2664:
2665: }
2666: if (!NT_ERROR(SerialGetDivisorFromBaud(
2667: extension->ClockRate,
2668: (LONG)115200,
2669: &junk
2670: ))) {
2671:
2672: extension->SupportedBauds |= SERIAL_BAUD_115200;
2673:
2674: }
2675:
2676: if (!NT_ERROR(SerialGetDivisorFromBaud(
2677: extension->ClockRate,
2678: (LONG)128000,
2679: &junk
2680: ))) {
2681:
2682: extension->SupportedBauds |= SERIAL_BAUD_128K;
2683:
2684: }
2685:
2686: }
2687:
2688:
2689: //
2690: // Mark this device as not being opened by anyone. We keep a
2691: // variable around so that spurious interrupts are easily
2692: // dismissed by the ISR.
2693: //
2694:
2695: extension->DeviceIsOpened = FALSE;
2696:
2697: //
2698: // This call will set up the naming necessary for
2699: // external applications to get to the driver. It
2700: // will also set up the device map.
2701: //
2702:
2703:
2704: extension->ObjectDirectory = ConfigData->ObjectDirectory;
2705: extension->NtNameForPort = ConfigData->NtNameForPort;
2706: extension->SymbolicLinkName = ConfigData->SymbolicLinkName;
2707: SerialSetupExternalNaming(extension);
2708:
2709: //
2710: // Store values into the extension for interval timing.
2711: //
2712:
2713: //
2714: // If the interval timer is less than a second then come
2715: // in with a short "polling" loop.
2716: //
2717: // For large (> then 2 seconds) use a 1 second poller.
2718: //
2719:
2720: extension->ShortIntervalAmount.LowPart = 1;
2721: extension->ShortIntervalAmount.HighPart = 0;
2722: extension->ShortIntervalAmount = RtlLargeIntegerNegate(
2723: extension->ShortIntervalAmount
2724: );
2725: extension->LongIntervalAmount.LowPart = 10000000;
2726: extension->LongIntervalAmount.HighPart = 0;
2727: extension->LongIntervalAmount = RtlLargeIntegerNegate(
2728: extension->LongIntervalAmount
2729: );
2730: extension->CutOverAmount.LowPart = 200000000;
2731: extension->CutOverAmount.HighPart = 0;
2732:
2733:
2734: //
2735: // Pass pack the extension to the caller.
2736: //
2737:
2738: *DeviceExtension = extension;
2739:
2740: //
2741: // Common error path cleanup. If the status is
2742: // bad, get rid of the device extension, device object
2743: // and any memory associated with it.
2744: //
2745:
2746: ExtensionCleanup: ;
2747:
2748: ExFreePool(ConfigData);
2749:
2750: if (NT_ERROR(status)) {
2751:
2752: if (extension) {
2753:
2754: if (reportedResources) {
2755:
2756: SerialUnReportResourcesDevice(extension);
2757:
2758: }
2759:
2760: SerialCleanupDevice(extension);
2761: IoDeleteDevice(deviceObject);
2762:
2763: }
2764:
2765: }
2766:
2767: return status;
2768:
2769: }
2770:
2771: BOOLEAN
2772: SerialDoesPortExist(
2773: IN PSERIAL_DEVICE_EXTENSION Extension,
2774: IN PUNICODE_STRING InsertString,
2775: IN ULONG ForceFifo
2776: )
2777:
2778: /*++
2779:
2780: Routine Description:
2781:
2782: This routine examines several of what might be the serial device
2783: registers. It ensures that the bits that should be zero are zero.
2784:
2785: In addition, this routine will determine if the device supports
2786: fifo's. If it does it will enable the fifo's and turn on a boolean
2787: in the extension that indicates the fifo's presence.
2788:
2789: NOTE: If there is indeed a serial port at the address specified
2790: it will absolutely have interrupts inhibited upon return
2791: from this routine.
2792:
2793: NOTE: Since this routine should be called fairly early in
2794: the device driver initialization, the only element
2795: that needs to be filled in is the base register address.
2796:
2797: NOTE: These tests all assume that this code is the only
2798: code that is looking at these ports or this memory.
2799:
2800: This is a not to unreasonable assumption even on
2801: multiprocessor systems.
2802:
2803: Arguments:
2804:
2805: Extension - A pointer to a serial device extension.
2806: InsertString - String to place in an error log entry.
2807: ForceFifo - !0 forces the fifo to be left on if found.
2808:
2809: Return Value:
2810:
2811: Will return true if the port really exists, otherwise it
2812: will return false.
2813:
2814: --*/
2815:
2816: {
2817:
2818:
2819: UCHAR regContents;
2820: BOOLEAN returnValue = TRUE;
2821: UCHAR oldIERContents;
2822: UCHAR oldLCRContents;
2823: USHORT value1;
2824: USHORT value2;
2825: KIRQL oldIrql;
2826:
2827:
2828: //
2829: // Save of the line control.
2830: //
2831:
2832: oldLCRContents = READ_LINE_CONTROL(Extension->Controller);
2833:
2834: //
2835: // Make sure that we are *aren't* accessing the divsior latch.
2836: //
2837:
2838: WRITE_LINE_CONTROL(
2839: Extension->Controller,
2840: (UCHAR)(oldLCRContents & ~SERIAL_LCR_DLAB)
2841: );
2842:
2843: oldIERContents = READ_INTERRUPT_ENABLE(Extension->Controller);
2844:
2845: //
2846: // Go up to power level for a very short time to prevent
2847: // any interrupts from this device from coming in.
2848: //
2849:
2850: KeRaiseIrql(
2851: POWER_LEVEL,
2852: &oldIrql
2853: );
2854:
2855: WRITE_INTERRUPT_ENABLE(
2856: Extension->Controller,
2857: 0x0f
2858: );
2859:
2860: value1 = READ_INTERRUPT_ENABLE(Extension->Controller);
2861: value1 = value1 << 8;
2862: value1 |= READ_RECEIVE_BUFFER(Extension->Controller);
2863:
2864: READ_DIVISOR_LATCH(
2865: Extension->Controller,
2866: &value2
2867: );
2868:
2869: WRITE_LINE_CONTROL(
2870: Extension->Controller,
2871: oldLCRContents
2872: );
2873:
2874: //
2875: // Put the ier back to where it was before. If we are on a
2876: // level sensitive port this should prevent the interrupts
2877: // from coming in. If we are on a latched, we don't care
2878: // cause the interrupts generated will just get dropped.
2879: //
2880:
2881: WRITE_INTERRUPT_ENABLE(
2882: Extension->Controller,
2883: oldIERContents
2884: );
2885:
2886: KeLowerIrql(oldIrql);
2887:
2888: if (value1 == value2) {
2889:
2890: SerialLogError(
2891: Extension->DeviceObject->DriverObject,
2892: Extension->DeviceObject,
2893: Extension->OriginalController,
2894: SerialPhysicalZero,
2895: 0,
2896: 0,
2897: 0,
2898: 62,
2899: STATUS_SUCCESS,
2900: SERIAL_DLAB_INVALID,
2901: InsertString->Length+sizeof(WCHAR),
2902: InsertString->Buffer,
2903: 0,
2904: NULL
2905: );
2906: returnValue = FALSE;
2907: goto AllDone;
2908:
2909: }
2910:
2911: AllDone: ;
2912:
2913:
2914: //
2915: // If we think that there is a serial device then we determine
2916: // if a fifo is present.
2917: //
2918:
2919: if (returnValue) {
2920:
2921: //
2922: // Well, we think it's a serial device. Absolutely
2923: // positively, prevent interrupts from occuring.
2924: //
2925: // We disable all the interrupt enable bits, and
2926: // push down all the lines in the modem control
2927: // We only needed to push down OUT2 which in
2928: // PC's must also be enabled to get an interrupt.
2929: //
2930:
2931: DISABLE_ALL_INTERRUPTS(Extension->Controller);
2932:
2933: if (Extension->Jensen) {
2934:
2935: WRITE_MODEM_CONTROL(
2936: Extension->Controller,
2937: (UCHAR)SERIAL_MCR_OUT2
2938: );
2939:
2940: } else {
2941:
2942: WRITE_MODEM_CONTROL(
2943: Extension->Controller,
2944: (UCHAR)0
2945: );
2946:
2947: }
2948:
2949: //
2950: // See if this is a 16550. We do this by writing to
2951: // what would be the fifo control register with a bit
2952: // pattern that tells the device to enable fifo's.
2953: // We then read the iterrupt Id register to see if the
2954: // bit pattern is present that identifies the 16550.
2955: //
2956:
2957: WRITE_FIFO_CONTROL(
2958: Extension->Controller,
2959: SERIAL_FCR_ENABLE
2960: );
2961:
2962: regContents = READ_INTERRUPT_ID_REG(Extension->Controller);
2963:
2964: if (regContents & SERIAL_IIR_FIFOS_ENABLED) {
2965:
2966: //
2967: // Save off that the device supports fifos.
2968: //
2969:
2970: Extension->FifoPresent = TRUE;
2971:
2972: //
2973: // There are fifos on this card. Set the value of the
2974: // receive fifo to interrupt when 4 characters are present.
2975: //
2976:
2977: WRITE_FIFO_CONTROL(
2978: Extension->Controller,
2979: (UCHAR)(SERIAL_FCR_ENABLE | Extension->RxFifoTrigger |
2980: SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)
2981: );
2982:
2983: }
2984:
2985: if (!ForceFifo) {
2986:
2987: Extension->FifoPresent = FALSE;
2988: WRITE_FIFO_CONTROL(
2989: Extension->Controller,
2990: (UCHAR)0
2991: );
2992:
2993: }
2994:
2995: if (Extension->FifoPresent) {
2996:
2997: SerialLogError(
2998: Extension->DeviceObject->DriverObject,
2999: Extension->DeviceObject,
3000: Extension->OriginalController,
3001: SerialPhysicalZero,
3002: 0,
3003: 0,
3004: 0,
3005: 15,
3006: STATUS_SUCCESS,
3007: SERIAL_FIFO_PRESENT,
3008: InsertString->Length+sizeof(WCHAR),
3009: InsertString->Buffer,
3010: 0,
3011: NULL
3012: );
3013:
3014: SerialDump(
3015: SERDIAG1,
3016: ("SERIAL: Fifo's detected at port address: %x\n",
3017: Extension->Controller)
3018: );
3019:
3020: }
3021:
3022: //
3023: // In case we are dealing with a bitmasked multiportcard,
3024: // that has the mask register enabled, enable all
3025: // interrupts.
3026: //
3027:
3028: if (Extension->InterruptStatus) {
3029:
3030: WRITE_PORT_UCHAR(
3031: Extension->InterruptStatus,
3032: (UCHAR)0xff
3033: );
3034:
3035: }
3036:
3037: }
3038:
3039: return returnValue;
3040:
3041: }
3042:
3043: BOOLEAN
3044: SerialReset(
3045: IN PVOID Context
3046: )
3047:
3048: /*++
3049:
3050: Routine Description:
3051:
3052: This places the hardware in a standard configuration.
3053:
3054: NOTE: This assumes that it is called at interrupt level.
3055:
3056:
3057: Arguments:
3058:
3059: Context - The device extension for serial device
3060: being managed.
3061:
3062: Return Value:
3063:
3064: Always FALSE.
3065:
3066: --*/
3067:
3068: {
3069:
3070: PSERIAL_DEVICE_EXTENSION extension = Context;
3071: UCHAR regContents;
3072: UCHAR oldModemControl;
3073: ULONG i;
3074:
3075: //
3076: // Deal with the out2 bit.
3077: // This will also prevent any interrupts from occuring.
3078: //
3079:
3080: oldModemControl = READ_MODEM_CONTROL(extension->Controller);
3081:
3082: if (extension->Jensen) {
3083:
3084: WRITE_MODEM_CONTROL(
3085: extension->Controller,
3086: (UCHAR)(oldModemControl | SERIAL_MCR_OUT2)
3087: );
3088:
3089: } else {
3090:
3091:
3092: WRITE_MODEM_CONTROL(
3093: extension->Controller,
3094: (UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2)
3095: );
3096:
3097: }
3098:
3099: //
3100: // Reset the fifo's if there are any.
3101: //
3102:
3103: if (extension->FifoPresent) {
3104:
3105: WRITE_FIFO_CONTROL(
3106: extension->Controller,
3107: SERIAL_FCR_ENABLE
3108: );
3109: WRITE_FIFO_CONTROL(
3110: extension->Controller,
3111: (UCHAR)(SERIAL_FCR_ENABLE | extension->RxFifoTrigger |
3112: SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)
3113: );
3114:
3115: }
3116:
3117: //
3118: // Make sure that the line control set up correct.
3119: //
3120: // 1) Make sure that the Divisor latch select is set
3121: // up to select the transmit and receive register.
3122: //
3123: // 2) Make sure that we aren't in a break state.
3124: //
3125:
3126: regContents = READ_LINE_CONTROL(extension->Controller);
3127: regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK);
3128:
3129: WRITE_LINE_CONTROL(
3130: extension->Controller,
3131: regContents
3132: );
3133:
3134: //
3135: // Read the receive buffer until the line status is
3136: // clear. (Actually give up after a 5 reads.)
3137: //
3138:
3139: for (i = 0;
3140: i < 5;
3141: i++
3142: ) {
3143:
3144: READ_RECEIVE_BUFFER(extension->Controller);
3145: if (!(READ_LINE_STATUS(extension->Controller) & 1)) {
3146:
3147: break;
3148:
3149: }
3150:
3151: }
3152:
3153: //
3154: // Read the modem status until the low 4 bits are
3155: // clear. (Actually give up after a 5 reads.)
3156: //
3157:
3158: for (i = 0;
3159: i < 1000;
3160: i++
3161: ) {
3162:
3163: if (!(READ_MODEM_STATUS(extension->Controller) & 0x0f)) {
3164:
3165: break;
3166:
3167: }
3168:
3169: }
3170:
3171: //
3172: // Now we set the line control, modem control, and the
3173: // baud to what they should be.
3174: //
3175:
3176: SerialSetLineControl(extension);
3177:
3178: SerialSetupNewHandFlow(
3179: extension,
3180: &extension->HandFlow
3181: );
3182:
3183: SerialHandleModemUpdate(
3184: extension,
3185: FALSE
3186: );
3187:
3188: {
3189: SHORT appropriateDivisor;
3190: SERIAL_IOCTL_SYNC s;
3191:
3192: SerialGetDivisorFromBaud(
3193: extension->ClockRate,
3194: extension->CurrentBaud,
3195: &appropriateDivisor
3196: );
3197: s.Extension = extension;
3198: s.Data = (PVOID)appropriateDivisor;
3199: SerialSetBaud(&s);
3200: }
3201:
3202: //
3203: // Enable which interrupts we want to receive.
3204: //
3205: // NOTE NOTE: This does not actually let interrupts
3206: // occur. We must still raise the OUT2 bit in the
3207: // modem control register. We will do that on open.
3208: //
3209:
3210: ENABLE_ALL_INTERRUPTS(extension->Controller);
3211:
3212: //
3213: // Read the interrupt id register until the low bit is
3214: // set. (Actually give up after a 5 reads.)
3215: //
3216:
3217: for (i = 0;
3218: i < 5;
3219: i++
3220: ) {
3221:
3222: if (READ_INTERRUPT_ID_REG(extension->Controller) & 0x01) {
3223:
3224: break;
3225:
3226: }
3227:
3228: }
3229:
3230: //
3231: // Now we know that nothing could be transmitting at this point
3232: // so we set the HoldingEmpty indicator.
3233: //
3234:
3235: extension->HoldingEmpty = TRUE;
3236:
3237: return FALSE;
3238: }
3239:
3240: NTSTATUS
3241: SerialGetDivisorFromBaud(
3242: IN ULONG ClockRate,
3243: IN LONG DesiredBaud,
3244: OUT PSHORT AppropriateDivisor
3245: )
3246:
3247: /*++
3248:
3249: Routine Description:
3250:
3251: This routine will determine a divisor based on an unvalidated
3252: baud rate.
3253:
3254: Arguments:
3255:
3256: ClockRate - The clock input to the controller.
3257:
3258: DesiredBaud - The baud rate for whose divisor we seek.
3259:
3260: AppropriateDivisor - Given that the DesiredBaud is valid, the
3261: LONG pointed to by this parameter will be set to the appropriate
3262: value. NOTE: The long is undefined if the DesiredBaud is not
3263: supported.
3264:
3265: Return Value:
3266:
3267: This function will return STATUS_SUCCESS if the baud is supported.
3268: If the value is not supported it will return a status such that
3269: NT_ERROR(Status) == FALSE.
3270:
3271: --*/
3272:
3273: {
3274:
3275: NTSTATUS status = STATUS_SUCCESS;
3276: SHORT calculatedDivisor;
3277: ULONG denominator;
3278: ULONG remainder;
3279:
3280: //
3281: // Allow up to a 1 percent error
3282: //
3283:
3284: ULONG maxRemain18 = 18432;
3285: ULONG maxRemain30 = 30720;
3286: ULONG maxRemain42 = 42336;
3287: ULONG maxRemain80 = 80000;
3288: ULONG maxRemain;
3289:
3290: //
3291: // Reject any non-positive bauds.
3292: //
3293:
3294: denominator = DesiredBaud*(ULONG)16;
3295:
3296: if (DesiredBaud <= 0) {
3297:
3298: *AppropriateDivisor = -1;
3299:
3300: } else if ((LONG)denominator < DesiredBaud) {
3301:
3302: //
3303: // If the desired baud was so huge that it cause the denominator
3304: // calculation to wrap, don't support it.
3305: //
3306:
3307: *AppropriateDivisor = -1;
3308:
3309: } else {
3310:
3311: if (ClockRate == 1843200) {
3312: maxRemain = maxRemain18;
3313: } else if (ClockRate == 3072000) {
3314: maxRemain = maxRemain30;
3315: } else if (ClockRate == 4233600) {
3316: maxRemain = maxRemain42;
3317: } else {
3318: maxRemain = maxRemain80;
3319: }
3320:
3321: calculatedDivisor = (SHORT)(ClockRate / denominator);
3322: remainder = ClockRate % denominator;
3323:
3324: //
3325: // Round up.
3326: //
3327:
3328: if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) {
3329:
3330: calculatedDivisor++;
3331: }
3332:
3333:
3334: //
3335: // Only let the remainder calculations effect us if
3336: // the baud rate is > 9600.
3337: //
3338:
3339: if (DesiredBaud >= 9600) {
3340:
3341: //
3342: // If the remainder is less than the maximum remainder (wrt
3343: // the ClockRate) or the remainder + the maximum remainder is
3344: // greater than or equal to the ClockRate then assume that the
3345: // baud is ok.
3346: //
3347:
3348: if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) {
3349: calculatedDivisor = -1;
3350: }
3351:
3352: }
3353:
3354: //
3355: // Don't support a baud that causes the denominator to
3356: // be larger than the clock.
3357: //
3358:
3359: if (denominator > ClockRate) {
3360:
3361: calculatedDivisor = -1;
3362:
3363: }
3364:
3365: //
3366: // Ok, Now do some special casing so that things can actually continue
3367: // working on all platforms.
3368: //
3369:
3370: if (ClockRate == 1843200) {
3371:
3372: if (DesiredBaud == 56000) {
3373: calculatedDivisor = 2;
3374: }
3375:
3376: } else if (ClockRate == 3072000) {
3377:
3378: if (DesiredBaud == 14400) {
3379: calculatedDivisor = 13;
3380: }
3381:
3382: } else if (ClockRate == 4233600) {
3383:
3384: if (DesiredBaud == 9600) {
3385: calculatedDivisor = 28;
3386: } else if (DesiredBaud == 14400) {
3387: calculatedDivisor = 18;
3388: } else if (DesiredBaud == 19200) {
3389: calculatedDivisor = 14;
3390: } else if (DesiredBaud == 38400) {
3391: calculatedDivisor = 7;
3392: } else if (DesiredBaud == 56000) {
3393: calculatedDivisor = 5;
3394: }
3395:
3396: } else if (ClockRate == 8000000) {
3397:
3398: if (DesiredBaud == 14400) {
3399: calculatedDivisor = 35;
3400: } else if (DesiredBaud == 56000) {
3401: calculatedDivisor = 9;
3402: }
3403:
3404: }
3405:
3406: *AppropriateDivisor = calculatedDivisor;
3407:
3408: }
3409:
3410:
3411: if (*AppropriateDivisor == -1) {
3412:
3413: status = STATUS_INVALID_PARAMETER;
3414:
3415: }
3416:
3417: return status;
3418:
3419: }
3420:
3421: VOID
3422: SerialUnload(
3423: IN PDRIVER_OBJECT DriverObject
3424: )
3425:
3426: /*++
3427:
3428: Routine Description:
3429:
3430: This routine cleans up all of the memory associated with
3431: any of the devices belonging to the driver. It will
3432: loop through the device list.
3433:
3434: Arguments:
3435:
3436: DriverObject - Pointer to the driver object controling all of the
3437: devices.
3438:
3439: Return Value:
3440:
3441: None.
3442:
3443: --*/
3444:
3445: {
3446:
3447: PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
3448:
3449: SerialDump(
3450: SERDIAG3,
3451: ("SERIAL: In SerialUnload\n")
3452: );
3453:
3454: while (currentDevice) {
3455:
3456: PSERIAL_DEVICE_EXTENSION extension = currentDevice->DeviceExtension;
3457:
3458: //
3459: // Look for a device that actually has an isr.
3460: // if we find one then that is a "root" controller.
3461: //
3462:
3463: if (extension->OurIsr) {
3464:
3465: SerialDump(
3466: SERDIAG5,
3467: ("SERIAL: About to do a propagate delete on\n"
3468: "------- extension: %x for port %wZ\n",
3469: extension,&extension->DeviceName)
3470: );
3471: SerialPropagateDeleteSharers(
3472: extension,
3473: &IoGetConfigurationInformation()->SerialCount,
3474: NULL
3475: );
3476:
3477: currentDevice = DriverObject->DeviceObject;
3478:
3479: } else {
3480:
3481: currentDevice = currentDevice->NextDevice;
3482:
3483: }
3484:
3485: }
3486:
3487: }
3488:
3489: VOID
3490: SerialCleanupDevice(
3491: IN PSERIAL_DEVICE_EXTENSION Extension
3492: )
3493:
3494: /*++
3495:
3496: Routine Description:
3497:
3498: This routine will deallocate all of the memory used for
3499: a particular device. It will also disconnect any resources
3500: if need be.
3501:
3502: Arguments:
3503:
3504: Extension - Pointer to the device extension which is getting
3505: rid of all it's resources.
3506:
3507: Return Value:
3508:
3509: None.
3510:
3511: --*/
3512:
3513: {
3514:
3515: SerialDump(
3516: SERDIAG3,
3517: ("SERIAL: in SerialCleanup for extension: %x\n",Extension)
3518: );
3519:
3520: if (Extension) {
3521:
3522: //
3523: // Disconnect the interrupt object first so that some spurious
3524: // interrupt doesn't cause us to dereference some memory we've
3525: // already given up.
3526: //
3527:
3528: if (Extension->Interrupt) {
3529:
3530: SerialDump(
3531: SERDIAG5,
3532: ("SERIAL: Extension has interrupt %x\n",Extension)
3533: );
3534: IoDisconnectInterrupt(Extension->Interrupt);
3535:
3536: }
3537:
3538: KeCancelTimer(&Extension->ReadRequestTotalTimer);
3539: KeCancelTimer(&Extension->ReadRequestIntervalTimer);
3540: KeCancelTimer(&Extension->WriteRequestTotalTimer);
3541: KeCancelTimer(&Extension->ImmediateTotalTimer);
3542: KeCancelTimer(&Extension->XoffCountTimer);
3543: KeCancelTimer(&Extension->LowerRTSTimer);
3544: KeRemoveQueueDpc(&Extension->CompleteWriteDpc);
3545: KeRemoveQueueDpc(&Extension->CompleteReadDpc);
3546: KeRemoveQueueDpc(&Extension->TotalReadTimeoutDpc);
3547: KeRemoveQueueDpc(&Extension->IntervalReadTimeoutDpc);
3548: KeRemoveQueueDpc(&Extension->TotalWriteTimeoutDpc);
3549: KeRemoveQueueDpc(&Extension->CommErrorDpc);
3550: KeRemoveQueueDpc(&Extension->CompleteImmediateDpc);
3551: KeRemoveQueueDpc(&Extension->TotalImmediateTimeoutDpc);
3552: KeRemoveQueueDpc(&Extension->CommWaitDpc);
3553: KeRemoveQueueDpc(&Extension->XoffCountTimeoutDpc);
3554: KeRemoveQueueDpc(&Extension->XoffCountCompleteDpc);
3555: KeRemoveQueueDpc(&Extension->StartTimerLowerRTSDpc);
3556: KeRemoveQueueDpc(&Extension->PerhapsLowerRTSDpc);
3557:
3558: //
3559: // Get rid of all external naming as well as removing
3560: // the device map entry.
3561: //
3562:
3563: SerialCleanupExternalNaming(Extension);
3564:
3565: //
3566: // Delallocate the memory for the various names.
3567: // NOTE: If we have an extension - Then we must
3568: // have a device name stored away. Which is *not*
3569: // true for the other names.
3570: //
3571:
3572: ExFreePool(Extension->DeviceName.Buffer);
3573:
3574: if (Extension->ObjectDirectory.Buffer) {
3575:
3576: ExFreePool(Extension->ObjectDirectory.Buffer);
3577:
3578: }
3579:
3580: if (Extension->NtNameForPort.Buffer) {
3581:
3582: ExFreePool(Extension->NtNameForPort.Buffer);
3583:
3584: }
3585:
3586: if (Extension->SymbolicLinkName.Buffer) {
3587:
3588: ExFreePool(Extension->SymbolicLinkName.Buffer);
3589:
3590: }
3591:
3592: //
3593: // If necessary, unmap the device registers.
3594: //
3595:
3596: if (Extension->UnMapRegisters) {
3597:
3598: MmUnmapIoSpace(
3599: Extension->Controller,
3600: Extension->SpanOfController
3601: );
3602:
3603: }
3604:
3605: if (Extension->UnMapStatus) {
3606:
3607: MmUnmapIoSpace(
3608: Extension->InterruptStatus,
3609: Extension->SpanOfInterruptStatus
3610: );
3611:
3612: }
3613:
3614: }
3615:
3616: }
3617:
3618: NTSTATUS
3619: SerialItemCallBack(
3620: IN PVOID Context,
3621: IN PUNICODE_STRING PathName,
3622: IN INTERFACE_TYPE BusType,
3623: IN ULONG BusNumber,
3624: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
3625: IN CONFIGURATION_TYPE ControllerType,
3626: IN ULONG ControllerNumber,
3627: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
3628: IN CONFIGURATION_TYPE PeripheralType,
3629: IN ULONG PeripheralNumber,
3630: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
3631: )
3632:
3633: /*++
3634:
3635: Routine Description:
3636:
3637: This routine is called to check if a particular item
3638: is present in the registry.
3639:
3640: Arguments:
3641:
3642: Context - Pointer to a boolean.
3643:
3644: PathName - unicode registry path. Not Used.
3645:
3646: BusType - Internal, Isa, ...
3647:
3648: BusNumber - Which bus if we are on a multibus system.
3649:
3650: BusInformation - Configuration information about the bus. Not Used.
3651:
3652: ControllerType - Controller type.
3653:
3654: ControllerNumber - Which controller if there is more than one
3655: controller in the system.
3656:
3657: ControllerInformation - Array of pointers to the three pieces of
3658: registry information.
3659:
3660: PeripheralType - Should be a peripheral.
3661:
3662: PeripheralNumber - Which peripheral - not used..
3663:
3664: PeripheralInformation - Configuration information. Not Used.
3665:
3666: Return Value:
3667:
3668: STATUS_SUCCESS
3669:
3670: --*/
3671:
3672: {
3673:
3674: *((BOOLEAN *)Context) = TRUE;
3675: return STATUS_SUCCESS;
3676: }
3677:
3678: //
3679: // This structure is only used to communicate between the
3680: // code that queries what the firmware found and the code
3681: // that is calling the quering of the firmware data.
3682: //
3683: typedef struct SERIAL_FIRMWARE_DATA {
3684: PDRIVER_OBJECT DriverObject;
3685: ULONG ControllersFound;
3686: ULONG ForceFifoEnableDefault;
3687: ULONG RxFIFODefault;
3688: UNICODE_STRING Directory;
3689: UNICODE_STRING NtNameSuffix;
3690: UNICODE_STRING DirectorySymbolicName;
3691: LIST_ENTRY ConfigList;
3692: } SERIAL_FIRMWARE_DATA,*PSERIAL_FIRMWARE_DATA;
3693:
3694:
3695: NTSTATUS
3696: SerialConfigCallBack(
3697: IN PVOID Context,
3698: IN PUNICODE_STRING PathName,
3699: IN INTERFACE_TYPE BusType,
3700: IN ULONG BusNumber,
3701: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
3702: IN CONFIGURATION_TYPE ControllerType,
3703: IN ULONG ControllerNumber,
3704: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
3705: IN CONFIGURATION_TYPE PeripheralType,
3706: IN ULONG PeripheralNumber,
3707: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
3708: )
3709:
3710: /*++
3711:
3712: Routine Description:
3713:
3714: This routine is used to acquire all of the configuration
3715: information for each serial controller found by the firmware
3716:
3717: Arguments:
3718:
3719: Context - Pointer to the list head of the list of configuration
3720: records that we are building up.
3721:
3722: PathName - unicode registry path. Not Used.
3723:
3724: BusType - Internal, Isa, ...
3725:
3726: BusNumber - Which bus if we are on a multibus system.
3727:
3728: BusInformation - Configuration information about the bus. Not Used.
3729:
3730: ControllerType - Should always be SerialController.
3731:
3732: ControllerNumber - Which controller if there is more than one
3733: controller in the system.
3734:
3735: ControllerInformation - Array of pointers to the three pieces of
3736: registry information.
3737:
3738: PeripheralType - Undefined for this call.
3739:
3740: PeripheralNumber - Undefined for this call.
3741:
3742: PeripheralInformation - Undefined for this call.
3743:
3744: Return Value:
3745:
3746: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
3747: if it couldn't map the base csr or acquire the device object, or
3748: all of the resource information couldn't be acquired.
3749:
3750: --*/
3751:
3752: {
3753:
3754: //
3755: // So we don't have to typecast the context.
3756: //
3757: PSERIAL_FIRMWARE_DATA config = Context;
3758:
3759: //
3760: // Pointer to the configuration stuff for this controller.
3761: //
3762: PCONFIG_DATA controller;
3763:
3764: //
3765: // We use the following two variables to determine if
3766: // we have a pointer peripheral.
3767: //
3768: CONFIGURATION_TYPE pointer = PointerPeripheral;
3769: BOOLEAN foundPointer = FALSE;
3770:
3771: //
3772: // Two booleans to help us determine that we got enough configuration
3773: // data.
3774: //
3775: BOOLEAN foundPort = FALSE;
3776: BOOLEAN foundInterrupt = FALSE;
3777:
3778: //
3779: // Simple iteration variable.
3780: //
3781: ULONG i;
3782:
3783: PCM_FULL_RESOURCE_DESCRIPTOR controllerData;
3784:
3785: ASSERT(ControllerType == SerialController);
3786:
3787: config->ControllersFound++;
3788:
3789: //
3790: // Bail out if some fool wrote a hal and passed me data with no length.
3791: //
3792:
3793: if (!ControllerInformation[IoQueryDeviceConfigurationData]->DataLength) {
3794:
3795: return STATUS_SUCCESS;
3796:
3797: }
3798:
3799: controllerData =
3800: (PCM_FULL_RESOURCE_DESCRIPTOR)
3801: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
3802: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
3803:
3804: //
3805: // First things first. Call up IoQueryDeviceDescription
3806: // again to see if there is a pointer peripheral. If there
3807: // is then we simply ignore this controller.
3808: //
3809:
3810: IoQueryDeviceDescription(
3811: &BusType,
3812: &BusNumber,
3813: &ControllerType,
3814: &ControllerNumber,
3815: &pointer,
3816: NULL,
3817: SerialItemCallBack,
3818: &foundPointer
3819: );
3820:
3821: if (foundPointer) {
3822:
3823: return STATUS_SUCCESS;
3824:
3825: }
3826:
3827: //
3828: // Allocate the memory for the controller config data out of paged pool
3829: // since we will only be accessing it at initialization time.
3830: //
3831:
3832: controller = ExAllocatePool(
3833: PagedPool,
3834: sizeof(CONFIG_DATA)
3835: );
3836:
3837: if (!controller) {
3838:
3839: SerialLogError(
3840: config->DriverObject,
3841: NULL,
3842: SerialPhysicalZero,
3843: SerialPhysicalZero,
3844: 0,
3845: 0,
3846: 0,
3847: 16,
3848: STATUS_SUCCESS,
3849: SERIAL_INSUFFICIENT_RESOURCES,
3850: 0,
3851: NULL,
3852: 0,
3853: NULL
3854: );
3855: SerialDump(
3856: SERERRORS,
3857: ("SERIAL: Couldn't allocate memory for the configuration data\n"
3858: "------ for firmware data\n")
3859: );
3860: return STATUS_INSUFFICIENT_RESOURCES;
3861:
3862: }
3863:
3864: RtlZeroMemory(
3865: controller,
3866: sizeof(CONFIG_DATA)
3867: );
3868: InitializeListHead(&controller->ConfigList);
3869: InitializeListHead(&controller->SameInterrupt);
3870: InitializeListHead(&controller->SameInterruptStatus);
3871:
3872: controller->InterfaceType = BusType;
3873: controller->BusNumber = BusNumber;
3874:
3875: //
3876: // Stick in the default fifo enable an rx trigger for the firmware
3877: // found comm ports.
3878: //
3879:
3880: controller->ForceFifoEnable = config->ForceFifoEnableDefault;
3881: controller->RxFIFO = config->RxFIFODefault;
3882:
3883: //
3884: // We need to get the following information out of the partial
3885: // resource descriptors.
3886: //
3887: // The irql and vector.
3888: //
3889: // The base address and span covered by the serial controllers
3890: // registers.
3891: //
3892: // It is not defined how these appear in the partial resource
3893: // lists, so we will just loop over all of them. If we find
3894: // something we don't recognize, we drop that information on
3895: // the floor. When we have finished going through all the
3896: // partial information, we validate that we got the above
3897: // two.
3898: //
3899: // The other additional piece of data that we seek is the
3900: // baud rate input clock speed. Unless it is specified
3901: // in the device specific portion of the resource list we
3902: // will default it to 1.8432Mhz.
3903: //
3904:
3905: controller->ClockRate = 1843200;
3906: for (
3907: i = 0;
3908: i < controllerData->PartialResourceList.Count;
3909: i++
3910: ) {
3911:
3912: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
3913: &controllerData->PartialResourceList.PartialDescriptors[i];
3914:
3915: switch (partial->Type) {
3916:
3917: case CmResourceTypePort: {
3918:
3919: foundPort = TRUE;
3920:
3921: //
3922: // No matter what the registry says, we
3923: // know how long the register set is.
3924: //
3925:
3926: controller->SpanOfController = SERIAL_REGISTER_SPAN;
3927: controller->Controller = partial->u.Port.Start;
3928: controller->AddressSpace = partial->Flags;
3929:
3930: break;
3931: }
3932: case CmResourceTypeInterrupt: {
3933:
3934: foundInterrupt = TRUE;
3935: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
3936:
3937: controller->InterruptMode = Latched;
3938:
3939: } else {
3940:
3941: controller->InterruptMode = LevelSensitive;
3942:
3943: }
3944:
3945: controller->OriginalIrql = partial->u.Interrupt.Level;
3946: controller->OriginalVector = partial->u.Interrupt.Vector;
3947:
3948: break;
3949:
3950: }
3951: case CmResourceTypeDeviceSpecific: {
3952:
3953: PCM_SERIAL_DEVICE_DATA sDeviceData;
3954:
3955: sDeviceData = (PCM_SERIAL_DEVICE_DATA)(partial + 1);
3956:
3957: controller->ClockRate = sDeviceData->BaudClock;
3958:
3959: break;
3960:
3961: }
3962: default: {
3963:
3964: break;
3965:
3966: }
3967:
3968: }
3969:
3970: }
3971:
3972: if (foundPort && foundInterrupt) {
3973:
3974: WCHAR ntNumberBuffer[100];
3975: WCHAR symbolicNumberBuffer[100];
3976: UNICODE_STRING ntNumberString;
3977: UNICODE_STRING symbolicNumberString;
3978:
3979: ntNumberString.Length = 0;
3980: ntNumberString.MaximumLength = 100;
3981: ntNumberString.Buffer = &ntNumberBuffer[0];
3982:
3983: symbolicNumberString.Length = 0;
3984: symbolicNumberString.MaximumLength = 100;
3985: symbolicNumberString.Buffer = &symbolicNumberBuffer[0];
3986:
3987: //
3988: // Everthing is great so far. We now need to form the
3989: // Nt Names and symbolic link names.
3990: //
3991:
3992: if (!NT_SUCCESS(RtlIntegerToUnicodeString(
3993: config->ControllersFound - 1,
3994: 10,
3995: &ntNumberString
3996: ))) {
3997:
3998: SerialLogError(
3999: config->DriverObject,
4000: NULL,
4001: controller->Controller,
4002: SerialPhysicalZero,
4003: 0,
4004: 0,
4005: 0,
4006: 17,
4007: STATUS_SUCCESS,
4008: SERIAL_INSUFFICIENT_RESOURCES,
4009: 0,
4010: NULL,
4011: 0,
4012: NULL
4013: );
4014: SerialDump(
4015: SERERRORS,
4016: ("SERIAL: Couldn't convert NT controller number to\n"
4017: "------ to unicode for firmware data: %d\n",
4018: config->ControllersFound - 1)
4019: );
4020: //
4021: // Oh well, ignore this controller.
4022: //
4023: ExFreePool(controller);
4024:
4025: } else {
4026:
4027: if (!NT_SUCCESS(RtlIntegerToUnicodeString(
4028: config->ControllersFound,
4029: 10,
4030: &symbolicNumberString
4031: ))) {
4032:
4033: SerialLogError(
4034: config->DriverObject,
4035: NULL,
4036: controller->Controller,
4037: SerialPhysicalZero,
4038: 0,
4039: 0,
4040: 0,
4041: 18,
4042: STATUS_SUCCESS,
4043: SERIAL_INSUFFICIENT_RESOURCES,
4044: 0,
4045: NULL,
4046: 0,
4047: NULL
4048: );
4049: SerialDump(
4050: SERERRORS,
4051: ("SERIAL: Couldn't allocate convert symbolic controller number to\n"
4052: "------ to unicode for firmware data: %d\n",
4053: config->ControllersFound)
4054: );
4055: ExFreePool(controller);
4056:
4057: } else {
4058:
4059: UNICODE_STRING Temp;
4060:
4061: //
4062: // Ok, we have the non-constant portions of the
4063: // names all figured out. Now allocate memory
4064: // for what will be used later.
4065: //
4066:
4067: //
4068: // Save off a copy of the object directory name.
4069: //
4070:
4071: //
4072: // Init the destination.
4073: //
4074: RtlInitUnicodeString(
4075: &controller->ObjectDirectory,
4076: NULL
4077: );
4078:
4079: //
4080: // This will get its length.
4081: //
4082: RtlInitUnicodeString(
4083: &Temp,
4084: DEFAULT_DIRECTORY
4085: );
4086:
4087: //
4088: // Now allocate that much.
4089: //
4090:
4091: controller->ObjectDirectory.Buffer =
4092: ExAllocatePool(
4093: PagedPool,
4094: Temp.Length+sizeof(WCHAR)
4095: );
4096:
4097: if (!controller->ObjectDirectory.Buffer) {
4098:
4099: SerialLogError(
4100: config->DriverObject,
4101: NULL,
4102: controller->Controller,
4103: SerialPhysicalZero,
4104: 0,
4105: 0,
4106: 0,
4107: 19,
4108: STATUS_SUCCESS,
4109: SERIAL_INSUFFICIENT_RESOURCES,
4110: 0,
4111: NULL,
4112: 0,
4113: NULL
4114: );
4115: SerialDump(
4116: SERERRORS,
4117: ("SERIAL: Couldn't allocate memory for object\n"
4118: "------ directory for NT firmware data: %d\n",
4119: config->ControllersFound - 1)
4120: );
4121: ExFreePool(controller);
4122: return STATUS_SUCCESS;
4123:
4124: } else {
4125:
4126: controller->ObjectDirectory.MaximumLength =
4127: Temp.Length+sizeof(WCHAR);
4128:
4129: //
4130: // Zero fill it.
4131: //
4132:
4133: RtlZeroMemory(
4134: controller->ObjectDirectory.Buffer,
4135: controller->ObjectDirectory.MaximumLength
4136: );
4137:
4138: RtlAppendUnicodeStringToString(
4139: &controller->ObjectDirectory,
4140: &Temp
4141: );
4142:
4143: }
4144:
4145: //
4146: // Init the destination.
4147: //
4148: RtlInitUnicodeString(
4149: &controller->NtNameForPort,
4150: NULL
4151: );
4152:
4153: //
4154: // This will get its length.
4155: //
4156: RtlInitUnicodeString(
4157: &Temp,
4158: DEFAULT_NT_SUFFIX
4159: );
4160:
4161: //
4162: // Allocate enough for the suffix and the number.
4163: //
4164:
4165: controller->NtNameForPort.Buffer =
4166: ExAllocatePool(
4167: PagedPool,
4168: Temp.Length +
4169: ntNumberString.Length + sizeof(WCHAR)
4170: );
4171:
4172: if (!controller->NtNameForPort.Buffer) {
4173:
4174: SerialLogError(
4175: config->DriverObject,
4176: NULL,
4177: controller->Controller,
4178: SerialPhysicalZero,
4179: 0,
4180: 0,
4181: 0,
4182: 20,
4183: STATUS_SUCCESS,
4184: SERIAL_INSUFFICIENT_RESOURCES,
4185: 0,
4186: NULL,
4187: 0,
4188: NULL
4189: );
4190: SerialDump(
4191: SERERRORS,
4192: ("SERIAL: Couldn't allocate memory for NT\n"
4193: "------ name for NT firmware data: %d\n",
4194: config->ControllersFound - 1)
4195: );
4196: ExFreePool(controller->ObjectDirectory.Buffer);
4197: ExFreePool(controller);
4198: return STATUS_SUCCESS;
4199:
4200: } else {
4201:
4202: controller->NtNameForPort.MaximumLength =
4203: Temp.Length+ntNumberString.Length+sizeof(WCHAR);
4204:
4205: RtlZeroMemory(
4206: controller->NtNameForPort.Buffer,
4207: controller->NtNameForPort.MaximumLength
4208: );
4209:
4210: RtlAppendUnicodeStringToString(
4211: &controller->NtNameForPort,
4212: &Temp
4213: );
4214:
4215: RtlAppendUnicodeStringToString(
4216: &controller->NtNameForPort,
4217: &ntNumberString
4218: );
4219:
4220: }
4221:
4222: //
4223: // Now form that name that will be used as a
4224: // symbolic link to the actual device name
4225: // we just formed.
4226: //
4227:
4228: RtlInitUnicodeString(
4229: &controller->SymbolicLinkName,
4230: NULL
4231: );
4232:
4233: //
4234: // This will get its length.
4235: //
4236: RtlInitUnicodeString(
4237: &Temp,
4238: DEFAULT_SERIAL_NAME
4239: );
4240:
4241: //
4242: // Allocate enough for the suffix and the number.
4243: //
4244:
4245: controller->SymbolicLinkName.Buffer =
4246: ExAllocatePool(
4247: PagedPool,
4248: Temp.Length +
4249: symbolicNumberString.Length+sizeof(WCHAR)
4250: );
4251:
4252: if (!controller->SymbolicLinkName.Buffer) {
4253:
4254: SerialLogError(
4255: config->DriverObject,
4256: NULL,
4257: controller->Controller,
4258: SerialPhysicalZero,
4259: 0,
4260: 0,
4261: 0,
4262: 21,
4263: STATUS_SUCCESS,
4264: SERIAL_INSUFFICIENT_RESOURCES,
4265: 0,
4266: NULL,
4267: 0,
4268: NULL
4269: );
4270: SerialDump(
4271: SERERRORS,
4272: ("SERIAL: Couldn't allocate memory for symbolic\n"
4273: "------ name for NT firmware data: %d\n",
4274: config->ControllersFound - 1)
4275: );
4276: ExFreePool(controller->ObjectDirectory.Buffer);
4277: ExFreePool(controller->NtNameForPort.Buffer);
4278: ExFreePool(controller);
4279: return STATUS_SUCCESS;
4280:
4281: } else {
4282:
4283: controller->SymbolicLinkName.MaximumLength =
4284: Temp.Length+symbolicNumberString.Length+sizeof(WCHAR);
4285:
4286: RtlZeroMemory(
4287: controller->SymbolicLinkName.Buffer,
4288: controller->SymbolicLinkName.MaximumLength
4289: );
4290:
4291: RtlAppendUnicodeStringToString(
4292: &controller->SymbolicLinkName,
4293: &Temp
4294: );
4295:
4296: RtlAppendUnicodeStringToString(
4297: &controller->SymbolicLinkName,
4298: &symbolicNumberString
4299: );
4300:
4301: }
4302:
4303: InsertTailList(
4304: &config->ConfigList,
4305: &controller->ConfigList
4306: );
4307:
4308: }
4309:
4310: }
4311:
4312: } else {
4313:
4314: SerialLogError(
4315: config->DriverObject,
4316: NULL,
4317: controller->Controller,
4318: SerialPhysicalZero,
4319: 0,
4320: 0,
4321: 0,
4322: 22,
4323: STATUS_SUCCESS,
4324: SERIAL_NOT_ENOUGH_CONFIG_INFO,
4325: 0,
4326: NULL,
4327: 0,
4328: NULL
4329: );
4330: ExFreePool(controller);
4331:
4332: }
4333:
4334: return STATUS_SUCCESS;
4335: }
4336:
4337: VOID
4338: SerialGetConfigInfo(
4339: IN PDRIVER_OBJECT DriverObject,
4340: IN PUNICODE_STRING RegistryPath,
4341: ULONG ForceFifoEnableDefault,
4342: ULONG RxFIFODefault,
4343: OUT PLIST_ENTRY ConfigList
4344: )
4345:
4346: /*++
4347:
4348: Routine Description:
4349:
4350: This routine will "return" a list of configuration
4351: records for the serial ports to initialize.
4352:
4353: It will first query the firmware data. It will then
4354: look for "user" specified comm ports in the registry.
4355: It will place the user specified comm ports in the
4356: the passed in list.
4357:
4358: After it finds all of the user specified port, it will
4359: attempt to add the firmware comm ports into the passed
4360: in lists. The insert in the list code detects conflicts
4361: and rejects a new comm port. In this way we can prevent
4362: firmware found comm ports from overiding information
4363: specified by the "user". Note, this means if the user
4364: specified data is incorrect in its use of the interrupt
4365: (which should *always* be correct from the firmware)
4366: that port likely will not work. But, then, we "trust"
4367: the user.
4368:
4369:
4370: Arguments:
4371:
4372: DriverObject - Not used.
4373:
4374: RegistryPath - Path to this drivers service node in
4375: the current control set.
4376:
4377: ForceFifoEnableDefault - Gotten from the services node.
4378:
4379: RxFifoDefault - Gotten from the services node.
4380:
4381: ConfigList - Listhead (which will be intialized) for a list
4382: of configuration records for ports to control.
4383:
4384: Return Value:
4385:
4386: STATUS_SUCCESS if consistant configuration was found - otherwise.
4387: returns STATUS_SERIAL_NO_DEVICE_INITED.
4388:
4389: --*/
4390:
4391: {
4392:
4393: SERIAL_FIRMWARE_DATA firmware;
4394:
4395: PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
4396:
4397: INTERFACE_TYPE interfaceType;
4398: ULONG defaultInterfaceType;
4399:
4400:
4401: //
4402: // Default values for user data.
4403: //
4404: ULONG maxUlong = MAXULONG;
4405: ULONG zero = 0;
4406: ULONG clockRate = 1843200;
4407: ULONG defaultInterruptMode;
4408: ULONG defaultAddressSpace = CM_RESOURCE_PORT_IO;
4409:
4410: //
4411: // Where user data from the registry will be placed.
4412: //
4413:
4414: PHYSICAL_ADDRESS userPort;
4415: ULONG userVector;
4416: ULONG userLevel;
4417: PHYSICAL_ADDRESS userInterruptStatus;
4418: ULONG userPortIndex;
4419: ULONG userBusNumber;
4420: ULONG userInterfaceType;
4421: ULONG userClockRate;
4422: ULONG userIndexed;
4423: ULONG userAddressSpace;
4424: ULONG userInterruptMode;
4425: ULONG firmwareFound;
4426: ULONG disablePort;
4427: ULONG forceFifoEnable;
4428: ULONG rxFIFO;
4429: UNICODE_STRING userSymbolicLink;
4430:
4431: UNICODE_STRING parametersPath;
4432: OBJECT_ATTRIBUTES parametersAttributes;
4433: HANDLE parametersKey;
4434: PKEY_BASIC_INFORMATION userSubKey = NULL;
4435: ULONG i;
4436:
4437:
4438: RTL_QUERY_REGISTRY_TABLE jensenTable[2] = {0};
4439: UNICODE_STRING jensenData;
4440: UNICODE_STRING jensenValue;
4441: BOOLEAN jensenDetected;
4442: PUCHAR jensenBuffer;
4443:
4444:
4445: if (!(jensenBuffer = ExAllocatePool(
4446: PagedPool,
4447: 512
4448: ))) {
4449:
4450: //
4451: // We couldn't allocate 512 bytes of paged pool. If that's
4452: // so, then it's likely that the least of this machines problem's
4453: // is that it's a Jensen.
4454: //
4455:
4456: jensenDetected = FALSE;
4457:
4458: } else {
4459:
4460: //
4461: // Check to see if this is a Jensen alpha. If we do, then
4462: // well have to change the way we enable and disable interrupts
4463: //
4464:
4465: jensenData.Length = 0;
4466: jensenData.MaximumLength = 512;
4467: jensenData.Buffer = (PWCHAR)&jensenBuffer[0];
4468: RtlInitUnicodeString(
4469: &jensenValue,
4470: L"Jensen"
4471: );
4472: jensenTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
4473: RTL_QUERY_REGISTRY_REQUIRED;
4474: jensenTable[0].Name = L"Identifier";
4475: jensenTable[0].EntryContext = &jensenData;
4476:
4477: if (!NT_SUCCESS(RtlQueryRegistryValues(
4478: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
4479: L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM",
4480: &jensenTable[0],
4481: NULL,
4482: NULL
4483: ))) {
4484:
4485: //
4486: // How odd, no identifer string! We'll it's probably not a jensen.
4487: //
4488:
4489: jensenDetected = FALSE;
4490:
4491: } else {
4492:
4493: //
4494: // Skip past the DEC-XX Portion of the name string.
4495: // Be carful and make sure we have at least that much data.
4496: //
4497:
4498: if (jensenData.Length <= (sizeof(WCHAR)*6)) {
4499:
4500: jensenDetected = FALSE;
4501:
4502: } else {
4503:
4504: jensenData.Length -= (sizeof(WCHAR)*6);
4505: jensenData.MaximumLength -= (sizeof(WCHAR)*6);
4506: jensenData.Buffer = (PWCHAR)&jensenBuffer[sizeof(WCHAR)*6];
4507: jensenDetected = RtlEqualUnicodeString(
4508: &jensenData,
4509: &jensenValue,
4510: FALSE
4511: );
4512:
4513: }
4514:
4515: }
4516:
4517: ExFreePool(jensenBuffer);
4518:
4519: }
4520:
4521: if (jensenDetected) {
4522:
4523: SerialDump(
4524: SERDIAG1,
4525: ("SERIAL: Jensen Detected\n")
4526: );
4527:
4528: }
4529:
4530: InitializeListHead(ConfigList);
4531:
4532: RtlZeroMemory(
4533: &firmware,
4534: sizeof(SERIAL_FIRMWARE_DATA)
4535: );
4536:
4537: firmware.DriverObject = DriverObject;
4538: firmware.ForceFifoEnableDefault = ForceFifoEnableDefault;
4539: firmware.RxFIFODefault = RxFIFODefault;
4540: InitializeListHead(&firmware.ConfigList);
4541: RtlInitUnicodeString(
4542: &firmware.Directory,
4543: DEFAULT_DIRECTORY
4544: );
4545: RtlInitUnicodeString(
4546: &firmware.NtNameSuffix,
4547: DEFAULT_NT_SUFFIX
4548: );
4549: RtlInitUnicodeString(
4550: &firmware.DirectorySymbolicName,
4551: DEFAULT_SERIAL_NAME
4552: );
4553:
4554: //
4555: // First we query the hardware registry for all of
4556: // the firmware defined serial ports. We loop over
4557: // all of the busses.
4558: //
4559:
4560: for (
4561: interfaceType = 0;
4562: interfaceType < MaximumInterfaceType;
4563: interfaceType++
4564: ) {
4565:
4566: CONFIGURATION_TYPE sc = SerialController;
4567:
4568: IoQueryDeviceDescription(
4569: &interfaceType,
4570: NULL,
4571: &sc,
4572: NULL,
4573: NULL,
4574: NULL,
4575: SerialConfigCallBack,
4576: &firmware
4577: );
4578:
4579: }
4580:
4581: //
4582: // Query the registry one more time. This time we
4583: // look for the first bus on the system (that isn't
4584: // the internal bus - we assume that the firmware
4585: // code knows about those ports). We will use that
4586: // as the default bus if no bustype or bus number
4587: // is specified in the "user" configuration records.
4588: //
4589:
4590: defaultInterfaceType = (ULONG)Isa;
4591: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LATCHED;
4592:
4593: for (
4594: interfaceType = 0;
4595: interfaceType < MaximumInterfaceType;
4596: interfaceType++
4597: ) {
4598:
4599: ULONG busZero = 0;
4600: BOOLEAN foundOne = FALSE;
4601:
4602: if (interfaceType != Internal) {
4603:
4604: IoQueryDeviceDescription(
4605: &interfaceType,
4606: &busZero,
4607: NULL,
4608: NULL,
4609: NULL,
4610: NULL,
4611: SerialItemCallBack,
4612: &foundOne
4613: );
4614:
4615: if (foundOne) {
4616:
4617: defaultInterfaceType = (ULONG)interfaceType;
4618: if (defaultInterfaceType == MicroChannel) {
4619:
4620: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
4621:
4622: }
4623:
4624: break;
4625:
4626: }
4627:
4628: }
4629:
4630: }
4631:
4632: //
4633: // Gonna get the user data now. Allocate the
4634: // structures that we will be using throughout
4635: // the search for user data. We will deallocate
4636: // them before we leave this routine.
4637: //
4638:
4639: userSymbolicLink.Buffer = NULL;
4640: parametersPath.Buffer = NULL;
4641:
4642: //
4643: // Allocate the rtl query table. This should have an entry for each value
4644: // we retrieve from the registry as well as a terminating zero entry as
4645: // well the first "goto subkey" entry.
4646: //
4647:
4648: parameters = ExAllocatePool(
4649: PagedPool,
4650: sizeof(RTL_QUERY_REGISTRY_TABLE)*18
4651: );
4652:
4653: if (!parameters) {
4654:
4655: SerialLogError(
4656: DriverObject,
4657: NULL,
4658: SerialPhysicalZero,
4659: SerialPhysicalZero,
4660: 0,
4661: 0,
4662: 0,
4663: 23,
4664: STATUS_SUCCESS,
4665: SERIAL_INSUFFICIENT_RESOURCES,
4666: 0,
4667: NULL,
4668: 0,
4669: NULL
4670: );
4671: SerialDump(
4672: SERERRORS,
4673: ("SERIAL: Couldn't allocate table for rtl query\n"
4674: "------ to parameters for %wZ",
4675: RegistryPath)
4676: );
4677:
4678: goto DoFirmwareAdd;
4679:
4680: }
4681:
4682: RtlZeroMemory(
4683: parameters,
4684: sizeof(RTL_QUERY_REGISTRY_TABLE)*18
4685: );
4686:
4687: //
4688: // Allocate the place where the users symbolic link name
4689: // for the port will go.
4690: //
4691:
4692: //
4693: // We will initially allocate space for 257 wchars.
4694: // we will then set the maximum size to 256
4695: // This way the rtl routine could return a 256
4696: // WCHAR wide string with no null terminator.
4697: // We'll remember that the buffer is one WCHAR
4698: // longer then it says it is so that we can always
4699: // have a NULL terminator at the end.
4700: //
4701:
4702: RtlInitUnicodeString(
4703: &userSymbolicLink,
4704: NULL
4705: );
4706: userSymbolicLink.MaximumLength = sizeof(WCHAR)*256;
4707: userSymbolicLink.Buffer = ExAllocatePool(
4708: PagedPool,
4709: sizeof(WCHAR)*257
4710: );
4711:
4712: if (!userSymbolicLink.Buffer) {
4713:
4714: SerialLogError(
4715: DriverObject,
4716: NULL,
4717: SerialPhysicalZero,
4718: SerialPhysicalZero,
4719: 0,
4720: 0,
4721: 0,
4722: 24,
4723: STATUS_SUCCESS,
4724: SERIAL_INSUFFICIENT_RESOURCES,
4725: 0,
4726: NULL,
4727: 0,
4728: NULL
4729: );
4730: SerialDump(
4731: SERERRORS,
4732: ("SERIAL: Couldn't allocate buffer for the symbolic link\n"
4733: "------ for parameters items in %wZ",
4734: RegistryPath)
4735: );
4736:
4737: goto DoFirmwareAdd;
4738:
4739: }
4740:
4741: //
4742: // Form a path to our drivers Parameters subkey.
4743: //
4744:
4745: RtlInitUnicodeString(
4746: ¶metersPath,
4747: NULL
4748: );
4749:
4750: parametersPath.MaximumLength = RegistryPath->Length +
4751: sizeof(L"\\") +
4752: sizeof(L"Parameters");
4753:
4754: parametersPath.Buffer = ExAllocatePool(
4755: PagedPool,
4756: parametersPath.MaximumLength
4757: );
4758:
4759: if (!parametersPath.Buffer) {
4760:
4761: SerialLogError(
4762: DriverObject,
4763: NULL,
4764: SerialPhysicalZero,
4765: SerialPhysicalZero,
4766: 0,
4767: 0,
4768: 0,
4769: 25,
4770: STATUS_SUCCESS,
4771: SERIAL_INSUFFICIENT_RESOURCES,
4772: 0,
4773: NULL,
4774: 0,
4775: NULL
4776: );
4777: SerialDump(
4778: SERERRORS,
4779: ("SERIAL: Couldn't allocate string for path\n"
4780: "------ to parameters for %wZ",
4781: RegistryPath)
4782: );
4783:
4784: goto DoFirmwareAdd;
4785:
4786: }
4787:
4788: //
4789: // Form the parameters path.
4790: //
4791:
4792: RtlZeroMemory(
4793: parametersPath.Buffer,
4794: parametersPath.MaximumLength
4795: );
4796: RtlAppendUnicodeStringToString(
4797: ¶metersPath,
4798: RegistryPath
4799: );
4800: RtlAppendUnicodeToString(
4801: ¶metersPath,
4802: L"\\"
4803: );
4804: RtlAppendUnicodeToString(
4805: ¶metersPath,
4806: L"Parameters"
4807: );
4808:
4809: userSubKey = ExAllocatePool(
4810: PagedPool,
4811: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*256)
4812: );
4813:
4814: if (!userSubKey) {
4815:
4816: SerialLogError(
4817: DriverObject,
4818: NULL,
4819: SerialPhysicalZero,
4820: SerialPhysicalZero,
4821: 0,
4822: 0,
4823: 0,
4824: 26,
4825: STATUS_SUCCESS,
4826: SERIAL_INSUFFICIENT_RESOURCES,
4827: 0,
4828: NULL,
4829: 0,
4830: NULL
4831: );
4832: SerialDump(
4833: SERERRORS,
4834: ("SERIAL: Couldn't allocate memory basic information\n"
4835: "------ structure to enumerate subkeys for %wZ",
4836: ¶metersPath)
4837: );
4838:
4839: goto DoFirmwareAdd;
4840:
4841: }
4842:
4843: //
4844: // Open the key given by our registry path & Parameters.
4845: //
4846:
4847: InitializeObjectAttributes(
4848: ¶metersAttributes,
4849: ¶metersPath,
4850: OBJ_CASE_INSENSITIVE,
4851: NULL,
4852: NULL
4853: );
4854:
4855: if (!NT_SUCCESS(ZwOpenKey(
4856: ¶metersKey,
4857: MAXIMUM_ALLOWED,
4858: ¶metersAttributes
4859: ))) {
4860:
4861: SerialLogError(
4862: DriverObject,
4863: NULL,
4864: SerialPhysicalZero,
4865: SerialPhysicalZero,
4866: 0,
4867: 0,
4868: 0,
4869: 27,
4870: STATUS_SUCCESS,
4871: SERIAL_NO_PARAMETERS_INFO,
4872: 0,
4873: NULL,
4874: 0,
4875: NULL
4876: );
4877: SerialDump(
4878: SERERRORS,
4879: ("SERIAL: Couldn't open the drivers Parameters key %wZ\n",
4880: RegistryPath)
4881: );
4882: goto DoFirmwareAdd;
4883:
4884: }
4885:
4886: //
4887: // Gather all of the "user specified" information from
4888: // the registry.
4889: //
4890:
4891: parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
4892:
4893: parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
4894: parameters[1].Name = L"PortAddress";
4895: parameters[1].EntryContext = &userPort.LowPart;
4896: parameters[1].DefaultType = REG_DWORD;
4897: parameters[1].DefaultData = &zero;
4898: parameters[1].DefaultLength = sizeof(ULONG);
4899:
4900: parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
4901: parameters[2].Name = L"Interrupt";
4902: parameters[2].EntryContext = &userVector;
4903: parameters[2].DefaultType = REG_DWORD;
4904: parameters[2].DefaultData = &zero;
4905: parameters[2].DefaultLength = sizeof(ULONG);
4906:
4907: parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
4908: parameters[3].Name = firmware.Directory.Buffer;
4909: parameters[3].EntryContext = &userSymbolicLink;
4910: parameters[3].DefaultType = REG_SZ;
4911: parameters[3].DefaultData = L"";
4912: parameters[3].DefaultLength = 0;
4913:
4914: parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
4915: parameters[4].Name = L"InterruptStatus";
4916: parameters[4].EntryContext = &userInterruptStatus.LowPart;
4917: parameters[4].DefaultType = REG_DWORD;
4918: parameters[4].DefaultData = &zero;
4919: parameters[4].DefaultLength = sizeof(ULONG);
4920:
4921: parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
4922: parameters[5].Name = L"PortIndex";
4923: parameters[5].EntryContext = &userPortIndex;
4924: parameters[5].DefaultType = REG_DWORD;
4925: parameters[5].DefaultData = &zero;
4926: parameters[5].DefaultLength = sizeof(ULONG);
4927:
4928: parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
4929: parameters[6].Name = L"BusNumber";
4930: parameters[6].EntryContext = &userBusNumber;
4931: parameters[6].DefaultType = REG_DWORD;
4932: parameters[6].DefaultData = &zero;
4933: parameters[6].DefaultLength = sizeof(ULONG);
4934:
4935: parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
4936: parameters[7].Name = L"BusType";
4937: parameters[7].EntryContext = &userInterfaceType;
4938: parameters[7].DefaultType = REG_DWORD;
4939: parameters[7].DefaultData = &defaultInterfaceType;
4940: parameters[7].DefaultLength = sizeof(ULONG);
4941:
4942: parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
4943: parameters[8].Name = L"ClockRate";
4944: parameters[8].EntryContext = &userClockRate;
4945: parameters[8].DefaultType = REG_DWORD;
4946: parameters[8].DefaultData = &clockRate;
4947: parameters[8].DefaultLength = sizeof(ULONG);
4948:
4949: parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
4950: parameters[9].Name = L"Indexed";
4951: parameters[9].EntryContext = &userIndexed;
4952: parameters[9].DefaultType = REG_DWORD;
4953: parameters[9].DefaultData = &zero;
4954: parameters[9].DefaultLength = sizeof(ULONG);
4955:
4956: parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
4957: parameters[10].Name = L"InterruptMode";
4958: parameters[10].EntryContext = &userInterruptMode;
4959: parameters[10].DefaultType = REG_DWORD;
4960: parameters[10].DefaultData = &defaultInterruptMode;
4961: parameters[10].DefaultLength = sizeof(ULONG);
4962:
4963: parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
4964: parameters[11].Name = L"AddressSpace";
4965: parameters[11].EntryContext = &userAddressSpace;
4966: parameters[11].DefaultType = REG_DWORD;
4967: parameters[11].DefaultData = &defaultAddressSpace;
4968: parameters[11].DefaultLength = sizeof(ULONG);
4969:
4970: parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
4971: parameters[12].Name = L"InterruptLevel";
4972: parameters[12].EntryContext = &userLevel;
4973: parameters[12].DefaultType = REG_DWORD;
4974: parameters[12].DefaultData = &zero;
4975: parameters[12].DefaultLength = sizeof(ULONG);
4976:
4977: parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
4978: parameters[13].Name = L"FirmwareFound";
4979: parameters[13].EntryContext = &firmwareFound;
4980: parameters[13].DefaultType = REG_DWORD;
4981: parameters[13].DefaultData = &zero;
4982: parameters[13].DefaultLength = sizeof(ULONG);
4983:
4984: parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
4985: parameters[14].Name = L"DisablePort";
4986: parameters[14].EntryContext = &disablePort;
4987: parameters[14].DefaultType = REG_DWORD;
4988: parameters[14].DefaultData = &zero;
4989: parameters[14].DefaultLength = sizeof(ULONG);
4990:
4991: parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
4992: parameters[15].Name = L"ForceFifoEnable";
4993: parameters[15].EntryContext = &forceFifoEnable;
4994: parameters[15].DefaultType = REG_DWORD;
4995: parameters[15].DefaultData = &ForceFifoEnableDefault;
4996: parameters[15].DefaultLength = sizeof(ULONG);
4997:
4998: parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
4999: parameters[16].Name = L"RxFIFO";
5000: parameters[16].EntryContext = &rxFIFO;
5001: parameters[16].DefaultType = REG_DWORD;
5002: parameters[16].DefaultData = &RxFIFODefault;
5003: parameters[16].DefaultLength = sizeof(ULONG);
5004:
5005:
5006:
5007: i = 0;
5008: while (TRUE) {
5009:
5010: NTSTATUS status;
5011: ULONG actuallyReturned;
5012:
5013: //
5014: // We lie about the length of the buffer, so that we can
5015: // MAKE SURE that the name it returns can be padded with
5016: // a NULL.
5017: //
5018:
5019: status = ZwEnumerateKey(
5020: parametersKey,
5021: i,
5022: KeyBasicInformation,
5023: userSubKey,
5024: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*255),
5025: &actuallyReturned
5026: );
5027:
5028: if (status == STATUS_NO_MORE_ENTRIES) {
5029:
5030: break;
5031: }
5032:
5033: if (status == STATUS_BUFFER_OVERFLOW) {
5034:
5035: SerialLogError(
5036: DriverObject,
5037: NULL,
5038: SerialPhysicalZero,
5039: SerialPhysicalZero,
5040: 0,
5041: 0,
5042: 0,
5043: 28,
5044: STATUS_SUCCESS,
5045: SERIAL_UNABLE_TO_ACCESS_CONFIG,
5046: 0,
5047: NULL,
5048: 0,
5049: NULL
5050: );
5051: SerialDump(
5052: SERERRORS,
5053: ("SERIAL: Overflowed the enumerate buffer\n"
5054: "------- for subkey #%d of %wZ\n",
5055: i,parametersPath)
5056: );
5057: i++;
5058: continue;
5059:
5060: }
5061:
5062: if (!NT_SUCCESS(status)) {
5063:
5064: SerialLogError(
5065: DriverObject,
5066: NULL,
5067: SerialPhysicalZero,
5068: SerialPhysicalZero,
5069: 0,
5070: 0,
5071: 0,
5072: 29,
5073: status,
5074: SERIAL_UNABLE_TO_ACCESS_CONFIG,
5075: 0,
5076: NULL,
5077: 0,
5078: NULL
5079: );
5080: SerialDump(
5081: SERERRORS,
5082: ("SERIAL: Bad status returned: %x \n"
5083: "------- on enumeration for subkey # %d of %wZ\n",
5084: status,i,parametersPath)
5085: );
5086: i++;
5087: continue;
5088:
5089: }
5090:
5091: //
5092: // Pad the name returned with a null.
5093: //
5094:
5095: RtlZeroMemory(
5096: ((PUCHAR)(&userSubKey->Name[0]))+userSubKey->NameLength,
5097: sizeof(WCHAR)
5098: );
5099:
5100: parameters[0].Name = &userSubKey->Name[0];
5101:
5102: //
5103: // Make sure that the physical addresses start
5104: // out clean.
5105: //
5106: RtlZeroMemory(
5107: &userPort,
5108: sizeof(userPort)
5109: );
5110: RtlZeroMemory(
5111: &userInterruptStatus,
5112: sizeof(userInterruptStatus)
5113: );
5114:
5115: status = RtlQueryRegistryValues(
5116: RTL_REGISTRY_ABSOLUTE,
5117: parametersPath.Buffer,
5118: parameters,
5119: NULL,
5120: NULL
5121: );
5122:
5123: if (NT_SUCCESS(status)) {
5124:
5125: PCONFIG_DATA newConfig;
5126:
5127: //
5128: // Well! Some supposedly valid information was found!
5129: //
5130: // We'll see about that.
5131: //
5132: // Make sure that the interrupt is non zero (which we defaulted
5133: // it to).
5134: //
5135: // Make sure that the portaddress is non zero (which we defaulted
5136: // it to).
5137: //
5138: // Make sure that the DosDevices is not NULL (which we defaulted
5139: // it to).
5140: //
5141: // We need to make sure that if an interrupt status
5142: // was specified, that a port index was also specfied,
5143: // and if so that the port index is <= maximum ports
5144: // on a board.
5145: //
5146: // We should also validate that the bus type and number
5147: // are correct.
5148: //
5149: // We will also validate that the interrupt mode makes
5150: // sense for the bus.
5151: //
5152:
5153: //
5154: // Let's just jam the WCHAR null at the end of the
5155: // user symbolic link. Remember that we left room for
5156: // one when we allocated it's buffer.
5157: //
5158:
5159: RtlZeroMemory(
5160: ((PUCHAR)(&userSymbolicLink.Buffer[0]))+userSymbolicLink.Length,
5161: sizeof(WCHAR)
5162: );
5163:
5164: if (!userPort.LowPart) {
5165:
5166: //
5167: // Ehhhh! Lose Game.
5168: //
5169:
5170: SerialLogError(
5171: DriverObject,
5172: NULL,
5173: userPort,
5174: SerialPhysicalZero,
5175: 0,
5176: 0,
5177: 0,
5178: 58,
5179: STATUS_SUCCESS,
5180: SERIAL_INVALID_USER_CONFIG,
5181: userSubKey->NameLength+sizeof(WCHAR),
5182: &userSubKey->Name[0],
5183: (wcslen(parameters[1].Name)*sizeof(WCHAR))+sizeof(WCHAR),
5184: parameters[1].Name
5185: );
5186: SerialDump(
5187: SERERRORS,
5188: ("SERIAL: Bogus port address %ws\n",
5189: parameters[1].Name)
5190: );
5191: i++;
5192: continue;
5193:
5194: }
5195:
5196: if (!userVector) {
5197:
5198: //
5199: // Ehhhh! Lose Game.
5200: //
5201:
5202: SerialLogError(
5203: DriverObject,
5204: NULL,
5205: userPort,
5206: SerialPhysicalZero,
5207: 0,
5208: 0,
5209: 0,
5210: 59,
5211: STATUS_SUCCESS,
5212: SERIAL_INVALID_USER_CONFIG,
5213: userSubKey->NameLength+sizeof(WCHAR),
5214: &userSubKey->Name[0],
5215: (wcslen(parameters[2].Name)*sizeof(WCHAR))+sizeof(WCHAR),
5216: parameters[2].Name
5217: );
5218: SerialDump(
5219: SERERRORS,
5220: ("SERIAL: Bogus vector %ws\n",
5221: parameters[2].Name)
5222: );
5223: i++;
5224: continue;
5225:
5226: }
5227:
5228: if (!userSymbolicLink.Length) {
5229:
5230: //
5231: // Ehhhh! Lose Game.
5232: //
5233:
5234: SerialLogError(
5235: DriverObject,
5236: NULL,
5237: userPort,
5238: SerialPhysicalZero,
5239: 0,
5240: 0,
5241: 0,
5242: 60,
5243: STATUS_SUCCESS,
5244: SERIAL_INVALID_USER_CONFIG,
5245: userSubKey->NameLength+sizeof(WCHAR),
5246: &userSubKey->Name[0],
5247: (wcslen(parameters[3].Name)*sizeof(WCHAR))+sizeof(WCHAR),
5248: parameters[3].Name
5249: );
5250: SerialDump(
5251: SERERRORS,
5252: ("SERIAL: bogus value for %ws\n",
5253: parameters[3].Name)
5254: );
5255: i++;
5256: continue;
5257:
5258: }
5259:
5260: if (userInterruptStatus.LowPart != 0) {
5261:
5262: if (userPortIndex == MAXULONG) {
5263:
5264: //
5265: // Ehhhh! Lose Game.
5266: //
5267:
5268: SerialLogError(
5269: DriverObject,
5270: NULL,
5271: userPort,
5272: SerialPhysicalZero,
5273: 0,
5274: 0,
5275: 0,
5276: 30,
5277: STATUS_SUCCESS,
5278: SERIAL_INVALID_PORT_INDEX,
5279: userSymbolicLink.Length+sizeof(WCHAR),
5280: userSymbolicLink.Buffer,
5281: 0,
5282: NULL
5283: );
5284: SerialDump(
5285: SERERRORS,
5286: ("SERIAL: Bogus port index %ws\n",
5287: parameters[0].Name)
5288: );
5289: i++;
5290: continue;
5291:
5292: } else if (!userPortIndex) {
5293:
5294: //
5295: // So sorry, you must have a non-zero port index.
5296: //
5297:
5298: SerialLogError(
5299: DriverObject,
5300: NULL,
5301: userPort,
5302: SerialPhysicalZero,
5303: 0,
5304: 0,
5305: 0,
5306: 31,
5307: STATUS_SUCCESS,
5308: SERIAL_INVALID_PORT_INDEX,
5309: userSymbolicLink.Length+sizeof(WCHAR),
5310: userSymbolicLink.Buffer,
5311: 0,
5312: NULL
5313: );
5314: SerialDump(
5315: SERERRORS,
5316: ("SERIAL: Port index must be > 0 for any\n"
5317: "------- port on a multiport card: %ws\n",
5318: parameters[0].Name)
5319: );
5320: i++;
5321: continue;
5322:
5323: } else {
5324:
5325: if (userIndexed) {
5326:
5327: if (userPortIndex > SERIAL_MAX_PORTS_INDEXED) {
5328:
5329: SerialLogError(
5330: DriverObject,
5331: NULL,
5332: userPort,
5333: SerialPhysicalZero,
5334: 0,
5335: 0,
5336: 0,
5337: 32,
5338: STATUS_SUCCESS,
5339: SERIAL_PORT_INDEX_TOO_HIGH,
5340: userSymbolicLink.Length+sizeof(WCHAR),
5341: userSymbolicLink.Buffer,
5342: 0,
5343: NULL
5344: );
5345: SerialDump(
5346: SERERRORS,
5347: ("SERIAL: port index to large %ws\n",
5348: parameters[0].Name)
5349: );
5350: i++;
5351: continue;
5352:
5353: }
5354:
5355: } else {
5356:
5357: if (userPortIndex > SERIAL_MAX_PORTS_NONINDEXED) {
5358:
5359: SerialLogError(
5360: DriverObject,
5361: NULL,
5362: userPort,
5363: SerialPhysicalZero,
5364: 0,
5365: 0,
5366: 0,
5367: 33,
5368: STATUS_SUCCESS,
5369: SERIAL_PORT_INDEX_TOO_HIGH,
5370: userSymbolicLink.Length+sizeof(WCHAR),
5371: userSymbolicLink.Buffer,
5372: 0,
5373: NULL
5374: );
5375: SerialDump(
5376: SERERRORS,
5377: ("SERIAL: port index to large %ws\n",
5378: parameters[0].Name)
5379: );
5380: i++;
5381: continue;
5382:
5383: }
5384:
5385: }
5386:
5387: }
5388:
5389: }
5390:
5391: //
5392: // We don't want to cause the hal to have a bad day,
5393: // so let's check the interface type and bus number.
5394: //
5395: // We only need to check the registry if they aren't
5396: // equal to the defaults.
5397: //
5398:
5399: if ((userBusNumber != 0) ||
5400: (userInterfaceType != defaultInterfaceType)) {
5401:
5402: BOOLEAN foundIt;
5403: if (userInterfaceType >= MaximumInterfaceType) {
5404:
5405: //
5406: // Ehhhh! Lose Game.
5407: //
5408:
5409: SerialLogError(
5410: DriverObject,
5411: NULL,
5412: userPort,
5413: SerialPhysicalZero,
5414: 0,
5415: 0,
5416: 0,
5417: 34,
5418: STATUS_SUCCESS,
5419: SERIAL_UNKNOWN_BUS,
5420: userSymbolicLink.Length+sizeof(WCHAR),
5421: userSymbolicLink.Buffer,
5422: 0,
5423: NULL
5424: );
5425: SerialDump(
5426: SERERRORS,
5427: ("SERIAL: Invalid Bus type %ws\n",
5428: parameters[0].Name)
5429: );
5430: i++;
5431: continue;
5432:
5433: }
5434:
5435: IoQueryDeviceDescription(
5436: (INTERFACE_TYPE *)&userInterfaceType,
5437: &zero,
5438: NULL,
5439: NULL,
5440: NULL,
5441: NULL,
5442: SerialItemCallBack,
5443: &foundIt
5444: );
5445:
5446: if (!foundIt) {
5447:
5448: SerialLogError(
5449: DriverObject,
5450: NULL,
5451: userPort,
5452: SerialPhysicalZero,
5453: 0,
5454: 0,
5455: 0,
5456: 35,
5457: STATUS_SUCCESS,
5458: SERIAL_BUS_NOT_PRESENT,
5459: userSymbolicLink.Length+sizeof(WCHAR),
5460: userSymbolicLink.Buffer,
5461: 0,
5462: NULL
5463: );
5464: SerialDump(
5465: SERERRORS,
5466: ("SERIAL: There aren't that many of those\n"
5467: "------- busses on this system,%ws\n",
5468: parameters[0].Name)
5469: );
5470: i++;
5471: continue;
5472:
5473: }
5474:
5475: }
5476:
5477: if ((userInterfaceType == MicroChannel) &&
5478: (userInterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) {
5479:
5480: SerialLogError(
5481: DriverObject,
5482: NULL,
5483: userPort,
5484: SerialPhysicalZero,
5485: 0,
5486: 0,
5487: 0,
5488: 36,
5489: STATUS_SUCCESS,
5490: SERIAL_BUS_INTERRUPT_CONFLICT,
5491: userSymbolicLink.Length+sizeof(WCHAR),
5492: userSymbolicLink.Buffer,
5493: 0,
5494: NULL
5495: );
5496: SerialDump(
5497: SERERRORS,
5498: ("SERIAL: Latched interrupts and MicroChannel\n"
5499: "------- busses don't mix,%ws\n",
5500: parameters[0].Name)
5501: );
5502: i++;
5503: continue;
5504:
5505: }
5506:
5507: //
5508: // Well ok, I guess we can take the data.
5509: // There be other tests later on to make
5510: // sure it doesn't have any other kinds
5511: // of conflicts.
5512: //
5513:
5514: //
5515: // Allocate the config record.
5516: //
5517:
5518: newConfig = ExAllocatePool(
5519: PagedPool,
5520: sizeof(CONFIG_DATA)
5521: );
5522:
5523: if (!newConfig) {
5524:
5525: SerialLogError(
5526: DriverObject,
5527: NULL,
5528: userPort,
5529: SerialPhysicalZero,
5530: 0,
5531: 0,
5532: 0,
5533: 37,
5534: STATUS_SUCCESS,
5535: SERIAL_INSUFFICIENT_RESOURCES,
5536: 0,
5537: NULL,
5538: 0,
5539: NULL
5540: );
5541: SerialDump(
5542: SERERRORS,
5543: ("SERIAL: Couldn't allocate memory for the\n"
5544: "------ user configuration record\n"
5545: "------ for %ws\n",
5546: parameters[0].Name)
5547: );
5548:
5549: i++;
5550: continue;
5551:
5552: }
5553:
5554: RtlZeroMemory(
5555: newConfig,
5556: sizeof(CONFIG_DATA)
5557: );
5558:
5559: //
5560: // Save off a copy of the object directory name.
5561: //
5562:
5563: //
5564: // Init the destination.
5565: //
5566: RtlInitUnicodeString(
5567: &newConfig->ObjectDirectory,
5568: DEFAULT_DIRECTORY
5569: );
5570: newConfig->ObjectDirectory.MaximumLength += sizeof(WCHAR);
5571:
5572: //
5573: // Now allocate that much.
5574: //
5575:
5576: newConfig->ObjectDirectory.Buffer =
5577: ExAllocatePool(
5578: PagedPool,
5579: newConfig->ObjectDirectory.MaximumLength
5580: );
5581:
5582: if (!newConfig->ObjectDirectory.Buffer) {
5583:
5584: SerialLogError(
5585: DriverObject,
5586: NULL,
5587: userPort,
5588: SerialPhysicalZero,
5589: 0,
5590: 0,
5591: 0,
5592: 38,
5593: STATUS_SUCCESS,
5594: SERIAL_INSUFFICIENT_RESOURCES,
5595: 0,
5596: NULL,
5597: 0,
5598: NULL
5599: );
5600: SerialDump(
5601: SERERRORS,
5602: ("SERIAL: Couldn't allocate memory for object\n"
5603: "------ directory for NT user data for: %ws\n",
5604: parameters[0].Name)
5605: );
5606: ExFreePool(newConfig);
5607: i++;
5608: continue;
5609:
5610: } else {
5611:
5612: //
5613: // Zero fill it.
5614: //
5615:
5616: RtlZeroMemory(
5617: newConfig->ObjectDirectory.Buffer,
5618: newConfig->ObjectDirectory.MaximumLength
5619: );
5620:
5621: newConfig->ObjectDirectory.Length = 0;
5622: RtlAppendUnicodeToString(
5623: &newConfig->ObjectDirectory,
5624: DEFAULT_DIRECTORY
5625: );
5626:
5627: }
5628:
5629: //
5630: // Init the destination.
5631: //
5632: RtlInitUnicodeString(
5633: &newConfig->NtNameForPort,
5634: &userSubKey->Name[0]
5635: );
5636:
5637: //
5638: // Allocate the space for the name.
5639: //
5640:
5641: newConfig->NtNameForPort.Length = 0;
5642: newConfig->NtNameForPort.MaximumLength += sizeof(WCHAR);
5643: newConfig->NtNameForPort.Buffer =
5644: ExAllocatePool(
5645: PagedPool,
5646: newConfig->NtNameForPort.MaximumLength
5647: );
5648:
5649: if (!newConfig->NtNameForPort.Buffer) {
5650:
5651: SerialLogError(
5652: DriverObject,
5653: NULL,
5654: userPort,
5655: SerialPhysicalZero,
5656: 0,
5657: 0,
5658: 0,
5659: 39,
5660: STATUS_SUCCESS,
5661: SERIAL_INSUFFICIENT_RESOURCES,
5662: 0,
5663: NULL,
5664: 0,
5665: NULL
5666: );
5667: SerialDump(
5668: SERERRORS,
5669: ("SERIAL: Couldn't allocate memory for NT\n"
5670: "------ name for NT user data name: %ws\n",
5671: parameters[0].Name)
5672: );
5673: ExFreePool(newConfig->ObjectDirectory.Buffer);
5674: ExFreePool(newConfig);
5675: i++;
5676: continue;
5677:
5678: } else {
5679:
5680: RtlZeroMemory(
5681: newConfig->NtNameForPort.Buffer,
5682: newConfig->NtNameForPort.MaximumLength
5683: );
5684:
5685: RtlAppendUnicodeToString(
5686: &newConfig->NtNameForPort,
5687: &userSubKey->Name[0]
5688: );
5689:
5690: }
5691:
5692: newConfig->SymbolicLinkName = userSymbolicLink;
5693: newConfig->SymbolicLinkName.MaximumLength += sizeof(WCHAR);
5694:
5695: newConfig->SymbolicLinkName.Buffer =
5696: ExAllocatePool(
5697: PagedPool,
5698: newConfig->SymbolicLinkName.MaximumLength
5699: );
5700:
5701: if (!newConfig->SymbolicLinkName.Buffer) {
5702:
5703: SerialLogError(
5704: DriverObject,
5705: NULL,
5706: userPort,
5707: SerialPhysicalZero,
5708: 0,
5709: 0,
5710: 0,
5711: 40,
5712: STATUS_SUCCESS,
5713: SERIAL_INSUFFICIENT_RESOURCES,
5714: 0,
5715: NULL,
5716: 0,
5717: NULL
5718: );
5719: SerialDump(
5720: SERERRORS,
5721: ("SERIAL: Couldn't allocate memory for symbolic\n"
5722: "------ name from user data\n"
5723: "------ %ws\n",
5724: parameters[0].Name)
5725: );
5726: ExFreePool(newConfig->ObjectDirectory.Buffer);
5727: ExFreePool(newConfig->NtNameForPort.Buffer);
5728: ExFreePool(newConfig);
5729: i++;
5730: continue;
5731:
5732: } else {
5733:
5734: RtlZeroMemory(
5735: newConfig->SymbolicLinkName.Buffer,
5736: newConfig->SymbolicLinkName.MaximumLength
5737: );
5738:
5739: newConfig->SymbolicLinkName.Length = 0;
5740: RtlAppendUnicodeStringToString(
5741: &newConfig->SymbolicLinkName,
5742: &userSymbolicLink
5743: );
5744:
5745: }
5746:
5747: InitializeListHead(&newConfig->ConfigList);
5748: InitializeListHead(&newConfig->SameInterrupt);
5749: InitializeListHead(&newConfig->SameInterruptStatus);
5750: newConfig->Controller = userPort;
5751: newConfig->InterruptStatus = userInterruptStatus;
5752: newConfig->SpanOfController = SERIAL_REGISTER_SPAN;
5753: newConfig->SpanOfInterruptStatus = SERIAL_STATUS_LENGTH;
5754: newConfig->PortIndex = userPortIndex;
5755: newConfig->ClockRate = userClockRate;
5756: newConfig->BusNumber = userBusNumber;
5757: newConfig->AddressSpace = userAddressSpace;
5758: newConfig->InterruptMode = userInterruptMode;
5759: newConfig->InterfaceType = userInterfaceType;
5760: newConfig->OriginalVector = userVector;
5761: newConfig->DisablePort = disablePort;
5762: newConfig->ForceFifoEnable = forceFifoEnable;
5763: newConfig->RxFIFO = rxFIFO;
5764: if (!userLevel) {
5765: newConfig->OriginalIrql = userVector;
5766: } else {
5767: newConfig->OriginalIrql = userLevel;
5768: }
5769: newConfig->Indexed = userIndexed;
5770: SerialDump(
5771: SERDIAG1,
5772: ("SERIAL: 'user registry info - userPort: %x\n",
5773: userPort.LowPart)
5774: );
5775: SerialDump(
5776: SERDIAG1,
5777: ("SERIAL: 'user registry info - userInterruptStatus: %x\n",
5778: userInterruptStatus.LowPart)
5779: );
5780: SerialDump(
5781: SERDIAG1,
5782: ("SERIAL: 'user registry info - userPortIndex: %d\n",
5783: userPortIndex)
5784: );
5785: SerialDump(
5786: SERDIAG1,
5787: ("SERIAL: 'user registry info - userClockRate: %d\n",
5788: userClockRate)
5789: );
5790: SerialDump(
5791: SERDIAG1,
5792: ("SERIAL: 'user registry info - userBusNumber: %d\n",
5793: userBusNumber)
5794: );
5795: SerialDump(
5796: SERDIAG1,
5797: ("SERIAL: 'user registry info - userAddressSpace: %d\n",
5798: userAddressSpace)
5799: );
5800: SerialDump(
5801: SERDIAG1,
5802: ("SERIAL: 'user registry info - userInterruptMode: %d\n",
5803: userInterruptMode)
5804: );
5805: SerialDump(
5806: SERDIAG1,
5807: ("SERIAL: 'user registry info - userInterfaceType: %d\n",
5808: userInterfaceType)
5809: );
5810: SerialDump(
5811: SERDIAG1,
5812: ("SERIAL: 'user registry info - userVector: %d\n",
5813: userVector)
5814: );
5815: SerialDump(
5816: SERDIAG1,
5817: ("SERIAL: 'user registry info - userLevel: %d\n",
5818: userLevel)
5819: );
5820: SerialDump(
5821: SERDIAG1,
5822: ("SERIAL: 'user registry info - userIndexed: %d\n",
5823: userIndexed)
5824: );
5825:
5826: if (!SerialPutInConfigList(
5827: DriverObject,
5828: ConfigList,
5829: newConfig
5830: )) {
5831:
5832: //
5833: // Dispose of this configuration record.
5834: //
5835:
5836: SerialDump(
5837: SERERRORS,
5838: ("SERIAL: Conflict detected amoungst user data %ws\n",
5839: parameters[0].Name)
5840: );
5841:
5842: ExFreePool(newConfig->ObjectDirectory.Buffer);
5843: ExFreePool(newConfig->NtNameForPort.Buffer);
5844: ExFreePool(newConfig->SymbolicLinkName.Buffer);
5845: ExFreePool(newConfig);
5846:
5847: }
5848:
5849: i++;
5850:
5851: } else {
5852:
5853: SerialLogError(
5854: DriverObject,
5855: NULL,
5856: SerialPhysicalZero,
5857: SerialPhysicalZero,
5858: 0,
5859: 0,
5860: 0,
5861: 61,
5862: status,
5863: SERIAL_INVALID_USER_CONFIG,
5864: userSubKey->NameLength+sizeof(WCHAR),
5865: &userSubKey->Name[0],
5866: 0,
5867: NULL
5868: );
5869: SerialDump(
5870: SERERRORS,
5871: ("SERIAL: Bad status returned: %x \n"
5872: "------- for the value entries of\n"
5873: "------- %ws\n",
5874: status,parameters[0].Name)
5875: );
5876:
5877: i++;
5878:
5879: }
5880:
5881: }
5882:
5883: ZwClose(parametersKey);
5884:
5885: DoFirmwareAdd:;
5886:
5887: //
5888: // All done with the user specified information. Now try
5889: // to add the firmware specified data to the configuration.
5890: // If a conflict is detected then we simply dispose of that
5891: // firmware collected data.
5892: //
5893:
5894: while (!IsListEmpty(&firmware.ConfigList)) {
5895:
5896: PLIST_ENTRY head;
5897: PCONFIG_DATA firmwareData;
5898:
5899: head = RemoveHeadList(&firmware.ConfigList);
5900:
5901: firmwareData = CONTAINING_RECORD(
5902: head,
5903: CONFIG_DATA,
5904: ConfigList
5905: );
5906:
5907:
5908: firmwareData->Jensen = jensenDetected;
5909:
5910: if (!SerialPutInConfigList(
5911: DriverObject,
5912: ConfigList,
5913: firmwareData
5914: )) {
5915:
5916: //
5917: // Dispose of this configuration record.
5918: //
5919:
5920: SerialLogError(
5921: DriverObject,
5922: NULL,
5923: firmwareData->Controller,
5924: SerialPhysicalZero,
5925: 0,
5926: 0,
5927: 0,
5928: 42,
5929: STATUS_SUCCESS,
5930: SERIAL_USER_OVERRIDE,
5931: firmwareData->SymbolicLinkName.Length+sizeof(WCHAR),
5932: firmwareData->SymbolicLinkName.Buffer,
5933: 0,
5934: NULL
5935: );
5936: SerialDump(
5937: SERERRORS,
5938: ("SERIAL: Conflict detected with user data for firmware port %wZ\n"
5939: "------ User data will overides firmware data\n",
5940: &firmwareData->NtNameForPort)
5941: );
5942: ExFreePool(firmwareData->ObjectDirectory.Buffer);
5943: ExFreePool(firmwareData->NtNameForPort.Buffer);
5944: ExFreePool(firmwareData->SymbolicLinkName.Buffer);
5945: ExFreePool(firmwareData);
5946:
5947: }
5948:
5949: }
5950:
5951: if (userSubKey) {
5952:
5953: ExFreePool(userSubKey);
5954:
5955: }
5956:
5957: if (userSymbolicLink.Buffer) {
5958:
5959: ExFreePool(userSymbolicLink.Buffer);
5960:
5961: }
5962:
5963: if (parametersPath.Buffer) {
5964:
5965: ExFreePool(parametersPath.Buffer);
5966:
5967: }
5968:
5969: if (parameters) {
5970:
5971: ExFreePool(parameters);
5972:
5973: }
5974: }
5975:
5976: BOOLEAN
5977: SerialPutInConfigList(
5978: IN PDRIVER_OBJECT DriverObject,
5979: IN OUT PLIST_ENTRY ConfigList,
5980: IN PCONFIG_DATA New
5981: )
5982:
5983: /*++
5984:
5985: Routine Description:
5986:
5987: Given an interrupt value, port address, interrupt status address,
5988: and an already defined list of configuration records, this routine
5989: will perform a check to make sure that the new record doesn't
5990: conflict with old records. (Note that we also include a port
5991: index, but this has no bearing on validation.)
5992:
5993: If everything checks out it will create a new configuration
5994: record if the new record isn't part of multiport card or
5995: if it is part of a multiport card it will create a configuration
5996: record if the specifiers for that multiport card don't already
5997: exist.
5998:
5999: NOTE: It is assumed throughout this code that no address is
6000: specified as 0.
6001:
6002: We assume nothing is zero because that for interrupt
6003: status that means none was specified.
6004:
6005: Arguments:
6006:
6007: DriverObject - Used to log errors.
6008:
6009: ConfigList - Listhead for a list of configuration records for
6010: ports to control.
6011:
6012: New = Pointer to new configuration record to add.
6013:
6014: Return Value:
6015:
6016: This will return STATUS_SUCCESS this new port information
6017: does not conflict with old port information. Otherwise it
6018: will return STATUS_SERIAL_NO_DEVICE_INITED.
6019:
6020: --*/
6021:
6022: {
6023:
6024: PHYSICAL_ADDRESS serialPhysicalMax;
6025:
6026: serialPhysicalMax.LowPart = (ULONG)~0;
6027: serialPhysicalMax.HighPart = ~0;
6028:
6029: SerialDump(
6030: SERDIAG1,
6031: ("SERIAL: Attempting to add %wZ\n"
6032: "------- to the config list\n"
6033: "------- PortAddress is %x\n"
6034: "------- Interrupt Status is %x\n"
6035: "------- BusNumber is %d\n"
6036: "------- BusType is %d\n"
6037: "------- AddressSpace is %d\n",
6038: &New->NtNameForPort,
6039: New->Controller.LowPart,
6040: New->InterruptStatus.LowPart,
6041: New->BusNumber,
6042: New->InterfaceType,
6043: New->AddressSpace
6044: )
6045: );
6046:
6047: //
6048: // We don't support any boards whose memory wraps around
6049: // the physical address space.
6050: //
6051:
6052: if (SerialMemCompare(
6053: New->Controller,
6054: New->SpanOfController,
6055: serialPhysicalMax,
6056: (ULONG)0
6057: ) != AddressesAreDisjoint) {
6058:
6059: SerialLogError(
6060: DriverObject,
6061: NULL,
6062: New->Controller,
6063: SerialPhysicalZero,
6064: 0,
6065: 0,
6066: 0,
6067: 43,
6068: STATUS_SUCCESS,
6069: SERIAL_DEVICE_TOO_HIGH,
6070: New->SymbolicLinkName.Length+sizeof(WCHAR),
6071: New->SymbolicLinkName.Buffer,
6072: 0,
6073: NULL
6074: );
6075: SerialDump(
6076: SERERRORS,
6077: ("SERIAL: Error in config record for %wZ\n"
6078: "------ registers rap around physical memory\n",
6079: &New->NtNameForPort)
6080: );
6081: return FALSE;
6082:
6083: }
6084:
6085: if (SerialMemCompare(
6086: New->InterruptStatus,
6087: New->SpanOfInterruptStatus,
6088: serialPhysicalMax,
6089: (ULONG)0
6090: ) != AddressesAreDisjoint) {
6091:
6092: SerialLogError(
6093: DriverObject,
6094: NULL,
6095: New->Controller,
6096: SerialPhysicalZero,
6097: 0,
6098: 0,
6099: 0,
6100: 44,
6101: STATUS_SUCCESS,
6102: SERIAL_STATUS_TOO_HIGH,
6103: New->SymbolicLinkName.Length+sizeof(WCHAR),
6104: New->SymbolicLinkName.Buffer,
6105: 0,
6106: NULL
6107: );
6108: SerialDump(
6109: SERERRORS,
6110: ("SERIAL: Error in config record for %wZ\n"
6111: "------ status raps around physical memory\n",
6112: &New->NtNameForPort)
6113: );
6114: return FALSE;
6115:
6116: }
6117:
6118: //
6119: // Make sure that the interrupt status address doesn't
6120: // overlap the controller registers
6121: //
6122:
6123: if (SerialMemCompare(
6124: New->InterruptStatus,
6125: New->SpanOfInterruptStatus,
6126: SerialPhysicalZero,
6127: (ULONG)0
6128: ) != AddressesAreEqual) {
6129:
6130: if (SerialMemCompare(
6131: New->InterruptStatus,
6132: New->SpanOfInterruptStatus,
6133: New->Controller,
6134: New->SpanOfController
6135: ) != AddressesAreDisjoint) {
6136:
6137: SerialLogError(
6138: DriverObject,
6139: NULL,
6140: New->Controller,
6141: New->InterruptStatus,
6142: 0,
6143: 0,
6144: 0,
6145: 45,
6146: STATUS_SUCCESS,
6147: SERIAL_STATUS_CONTROL_CONFLICT,
6148: New->SymbolicLinkName.Length+sizeof(WCHAR),
6149: New->SymbolicLinkName.Buffer,
6150: 0,
6151: NULL
6152: );
6153: SerialDump(
6154: SERERRORS,
6155: ("SERIAL: Error in cofig record for %wZ\n"
6156: "------- Interrupt status overlaps regular registers\n",
6157: &New->NtNameForPort)
6158: );
6159: return FALSE;
6160:
6161: }
6162:
6163: }
6164:
6165: //
6166: // Loop through all of the old configuration records making
6167: // sure that this new record doesn't overlap with any of
6168: // the old records.
6169: //
6170:
6171: if (!IsListEmpty(ConfigList)) {
6172:
6173: PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink;
6174:
6175: do {
6176:
6177: PCONFIG_DATA CurrentSameIntConfig = CONTAINING_RECORD(
6178: CurrentConfigListEntry,
6179: CONFIG_DATA,
6180: ConfigList
6181: );
6182:
6183: //
6184: // We only care about this list if the elements are on the
6185: // same bus as this new entry.
6186: //
6187:
6188: if ((CurrentSameIntConfig->InterfaceType == New->InterfaceType) &&
6189: (CurrentSameIntConfig->AddressSpace == New->AddressSpace) &&
6190: (CurrentSameIntConfig->BusNumber == New->BusNumber)) {
6191:
6192: PLIST_ENTRY RootSameIntListEntry = &CurrentSameIntConfig->SameInterrupt;
6193: PLIST_ENTRY CurrentSameIntListEntry = RootSameIntListEntry;
6194:
6195: do {
6196:
6197: PLIST_ENTRY RootSameStatusListEntry = &CONTAINING_RECORD(
6198: CurrentSameIntListEntry,
6199: CONFIG_DATA,
6200: SameInterrupt
6201: )->SameInterruptStatus;
6202: PLIST_ENTRY CurrentSameStatusListEntry = RootSameStatusListEntry;
6203:
6204: do {
6205:
6206: PCONFIG_DATA OldConfig = CONTAINING_RECORD(
6207: CurrentSameStatusListEntry,
6208: CONFIG_DATA,
6209: SameInterruptStatus
6210: );
6211:
6212: SerialDump(
6213: SERDIAG1,
6214: ("SERIAL: Comparing it to %wZ\n"
6215: "------- already in the config list\n"
6216: "------- PortAddress is %x\n"
6217: "------- Interrupt Status is %x\n"
6218: "------- BusNumber is %d\n"
6219: "------- BusType is %d\n"
6220: "------- AddressSpace is %d\n",
6221: &OldConfig->NtNameForPort,
6222: OldConfig->Controller.LowPart,
6223: OldConfig->InterruptStatus.LowPart,
6224: OldConfig->BusNumber,
6225: OldConfig->InterfaceType,
6226: OldConfig->AddressSpace
6227: )
6228: );
6229:
6230: if (SerialMemCompare(
6231: New->Controller,
6232: New->SpanOfController,
6233: OldConfig->Controller,
6234: OldConfig->SpanOfController
6235: ) != AddressesAreDisjoint) {
6236:
6237: SerialLogError(
6238: DriverObject,
6239: NULL,
6240: New->Controller,
6241: OldConfig->Controller,
6242: 0,
6243: 0,
6244: 0,
6245: 46,
6246: STATUS_SUCCESS,
6247: SERIAL_CONTROL_OVERLAP,
6248: New->SymbolicLinkName.Length+sizeof(WCHAR),
6249: New->SymbolicLinkName.Buffer,
6250: OldConfig->SymbolicLinkName.Length+sizeof(WCHAR),
6251: OldConfig->SymbolicLinkName.Buffer
6252: );
6253: SerialDump(
6254: SERERRORS,
6255: ("SERIAL: Error in config record for %wZ\n"
6256: "------- Register address overlaps with\n"
6257: "------- previous serial device\n",
6258: &New->NtNameForPort)
6259: );
6260: return FALSE;
6261:
6262: }
6263:
6264: //
6265: // If we have an interrupt status, make sure that
6266: // it doesn't overlap with the old controllers
6267: // registers.
6268: //
6269:
6270: if (SerialMemCompare(
6271: New->InterruptStatus,
6272: New->SpanOfInterruptStatus,
6273: SerialPhysicalZero,
6274: (ULONG)0
6275: ) != AddressesAreEqual) {
6276:
6277: if (SerialMemCompare(
6278: New->InterruptStatus,
6279: New->SpanOfInterruptStatus,
6280: OldConfig->Controller,
6281: OldConfig->SpanOfController
6282: ) != AddressesAreDisjoint) {
6283:
6284: SerialLogError(
6285: DriverObject,
6286: NULL,
6287: New->Controller,
6288: OldConfig->Controller,
6289: 0,
6290: 0,
6291: 0,
6292: 47,
6293: STATUS_SUCCESS,
6294: SERIAL_STATUS_OVERLAP,
6295: New->SymbolicLinkName.Length+sizeof(WCHAR),
6296: New->SymbolicLinkName.Buffer,
6297: OldConfig->SymbolicLinkName.Length+sizeof(WCHAR),
6298: OldConfig->SymbolicLinkName.Buffer
6299: );
6300: SerialDump(
6301: SERERRORS,
6302: ("SERIAL: Error in config record for %wZ\n"
6303: "------- status address overlaps with\n"
6304: "------- previous serial device registers\n",
6305: &New->NtNameForPort)
6306: );
6307:
6308: return FALSE;
6309:
6310: }
6311:
6312: //
6313: // If the old configuration record has an interrupt
6314: // status, the addresses should not overlap.
6315: //
6316:
6317: if (SerialMemCompare(
6318: OldConfig->InterruptStatus,
6319: OldConfig->SpanOfInterruptStatus,
6320: SerialPhysicalZero,
6321: (ULONG)0
6322: ) != AddressesAreEqual) {
6323:
6324: if (SerialMemCompare(
6325: New->InterruptStatus,
6326: New->SpanOfInterruptStatus,
6327: OldConfig->InterruptStatus,
6328: OldConfig->SpanOfInterruptStatus
6329: ) == AddressesOverlap) {
6330:
6331: SerialLogError(
6332: DriverObject,
6333: NULL,
6334: New->Controller,
6335: OldConfig->Controller,
6336: 0,
6337: 0,
6338: 0,
6339: 48,
6340: STATUS_SUCCESS,
6341: SERIAL_STATUS_STATUS_OVERLAP,
6342: New->SymbolicLinkName.Length+sizeof(WCHAR),
6343: New->SymbolicLinkName.Buffer,
6344: OldConfig->SymbolicLinkName.Length+sizeof(WCHAR),
6345: OldConfig->SymbolicLinkName.Buffer
6346: );
6347: SerialDump(
6348: SERERRORS,
6349: ("SERIAL: Error in config record for %wZ\n"
6350: "------- status address overlaps with\n"
6351: "------- previous serial status register\n",
6352: &New->NtNameForPort)
6353: );
6354:
6355: return FALSE;
6356:
6357: }
6358:
6359: }
6360:
6361: }
6362:
6363: //
6364: // If the old configuration record has a status
6365: // address make sure that it doesn't overlap with
6366: // the new controllers address. (Interrupt status
6367: // overlap is take care of above.
6368: //
6369:
6370: if (SerialMemCompare(
6371: OldConfig->InterruptStatus,
6372: OldConfig->SpanOfInterruptStatus,
6373: SerialPhysicalZero,
6374: (ULONG)0
6375: ) != AddressesAreEqual) {
6376:
6377: if (SerialMemCompare(
6378: New->Controller,
6379: New->SpanOfController,
6380: OldConfig->InterruptStatus,
6381: OldConfig->SpanOfInterruptStatus
6382: ) == AddressesOverlap) {
6383:
6384: SerialLogError(
6385: DriverObject,
6386: NULL,
6387: New->Controller,
6388: OldConfig->Controller,
6389: 0,
6390: 0,
6391: 0,
6392: 49,
6393: STATUS_SUCCESS,
6394: SERIAL_CONTROL_STATUS_OVERLAP,
6395: New->SymbolicLinkName.Length+sizeof(WCHAR),
6396: New->SymbolicLinkName.Buffer,
6397: OldConfig->SymbolicLinkName.Length+sizeof(WCHAR),
6398: OldConfig->SymbolicLinkName.Buffer
6399: );
6400: SerialDump(
6401: SERERRORS,
6402: ("SERIAL: Error in config record for %wZ\n"
6403: "------- register address overlaps with\n"
6404: "------- previous serial status register\n",
6405: &New->NtNameForPort)
6406: );
6407:
6408: return FALSE;
6409:
6410: }
6411:
6412: }
6413:
6414: CurrentSameStatusListEntry = CurrentSameStatusListEntry->Flink;
6415:
6416: } while (CurrentSameStatusListEntry != RootSameStatusListEntry);
6417:
6418: CurrentSameIntListEntry = CurrentSameIntListEntry->Flink;
6419:
6420: } while (CurrentSameIntListEntry != RootSameIntListEntry);
6421:
6422: }
6423:
6424: CurrentConfigListEntry = CurrentConfigListEntry->Flink;
6425:
6426: } while (CurrentConfigListEntry != ConfigList);
6427: }
6428:
6429: //
6430: // If there is an interrupt status then we
6431: // loop through the config list again to look
6432: // for a config record with the same interrupt
6433: // status (on the same bus).
6434: //
6435:
6436: if ((SerialMemCompare(
6437: New->InterruptStatus,
6438: New->SpanOfInterruptStatus,
6439: SerialPhysicalZero,
6440: (ULONG)0
6441: ) != AddressesAreEqual) &&
6442: !IsListEmpty(ConfigList)) {
6443:
6444: //
6445: // We have an interrupt status. Loop through all
6446: // previous records, look for an existing interrupt status
6447: // the same as the current interrupt status.
6448: //
6449:
6450: PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink;
6451:
6452: do {
6453:
6454: PCONFIG_DATA CurrentSameIntConfig = CONTAINING_RECORD(
6455: CurrentConfigListEntry,
6456: CONFIG_DATA,
6457: ConfigList
6458: );
6459:
6460: //
6461: // We only care about this list if the elements are on the
6462: // same bus as this new entry. (There interrupts must therfore
6463: // also be the on the same bus. We will check that momentarily).
6464: //
6465: // We don't check here for the dissimilar interrupts since that
6466: // could cause us to miss the error of having the same interrupt
6467: // status but different interrupts - which is bizzare.
6468: //
6469:
6470: if ((CurrentSameIntConfig->InterfaceType == New->InterfaceType) &&
6471: (CurrentSameIntConfig->AddressSpace == New->AddressSpace) &&
6472: (CurrentSameIntConfig->BusNumber == New->BusNumber)) {
6473:
6474: PLIST_ENTRY RootSameIntListEntry = &CurrentSameIntConfig->SameInterrupt;
6475: PLIST_ENTRY CurrentSameIntListEntry = RootSameIntListEntry;
6476:
6477: do {
6478:
6479: PLIST_ENTRY RootSameStatusListEntry = &CONTAINING_RECORD(
6480: CurrentSameIntListEntry,
6481: CONFIG_DATA,
6482: SameInterrupt
6483: )->SameInterruptStatus;
6484: PLIST_ENTRY CurrentSameStatusListEntry = RootSameStatusListEntry;
6485:
6486: do {
6487:
6488: PCONFIG_DATA OldConfig = CONTAINING_RECORD(
6489: CurrentSameStatusListEntry,
6490: CONFIG_DATA,
6491: SameInterruptStatus
6492: );
6493:
6494: //
6495: // If the interrupt status
6496: //
6497:
6498: if (SerialMemCompare(
6499: OldConfig->InterruptStatus,
6500: OldConfig->SpanOfInterruptStatus,
6501: New->InterruptStatus,
6502: New->SpanOfInterruptStatus
6503: ) == AddressesAreEqual) {
6504:
6505: //
6506: // Same card. Now make sure that they
6507: // are using the same interrupt parameters.
6508: //
6509:
6510: if ((New->OriginalIrql != OldConfig->OriginalIrql) ||
6511: (New->OriginalVector != OldConfig->OriginalVector)) {
6512:
6513: //
6514: // We won't put this into the configuration
6515: // list.
6516: //
6517:
6518: SerialLogError(
6519: DriverObject,
6520: NULL,
6521: New->Controller,
6522: OldConfig->Controller,
6523: 0,
6524: 0,
6525: 0,
6526: 50,
6527: STATUS_SUCCESS,
6528: SERIAL_MULTI_INTERRUPT_CONFLICT,
6529: New->SymbolicLinkName.Length+sizeof(WCHAR),
6530: New->SymbolicLinkName.Buffer,
6531: OldConfig->SymbolicLinkName.Length+sizeof(WCHAR),
6532: OldConfig->SymbolicLinkName.Buffer
6533: );
6534: SerialDump(
6535: SERERRORS,
6536: ("SERIAL: Configuration error for %wZ\n"
6537: "------- Same multiport - different interrupts\n",
6538: &New->NtNameForPort)
6539: );
6540: return FALSE;
6541:
6542: }
6543:
6544: //
6545: // Place this new record on the SameInterruptStatus
6546: // as the old record.
6547: //
6548:
6549: InitializeListHead(&New->SameInterruptStatus);
6550:
6551: InsertTailList(
6552: &OldConfig->SameInterruptStatus,
6553: &New->SameInterruptStatus
6554: );
6555:
6556: return TRUE;
6557:
6558: }
6559:
6560: CurrentSameStatusListEntry = CurrentSameStatusListEntry->Flink;
6561:
6562: } while (CurrentSameStatusListEntry != RootSameStatusListEntry);
6563:
6564: CurrentSameIntListEntry = CurrentSameIntListEntry->Flink;
6565:
6566: } while (CurrentSameIntListEntry != RootSameIntListEntry);
6567:
6568: }
6569:
6570: CurrentConfigListEntry = CurrentConfigListEntry->Flink;
6571:
6572: } while (CurrentConfigListEntry != ConfigList);
6573:
6574: }
6575:
6576: //
6577: // Go through the list again looking for previous devices
6578: // with the same interrupt.
6579: //
6580:
6581: if (!IsListEmpty(ConfigList)) {
6582:
6583: PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink;
6584:
6585: do {
6586:
6587: PCONFIG_DATA OldConfig = CONTAINING_RECORD(
6588: CurrentConfigListEntry,
6589: CONFIG_DATA,
6590: ConfigList
6591: );
6592:
6593: //
6594: // We only care about interrupts that are on
6595: // the same bus.
6596: //
6597:
6598: if ((OldConfig->InterfaceType == New->InterfaceType) &&
6599: (OldConfig->BusNumber == New->BusNumber)) {
6600:
6601: if ((OldConfig->OriginalIrql == New->OriginalIrql) &&
6602: (OldConfig->OriginalVector == New->OriginalVector)) {
6603:
6604: InsertTailList(
6605: &OldConfig->SameInterrupt,
6606: &New->SameInterrupt
6607: );
6608:
6609: return TRUE;
6610:
6611: }
6612:
6613: }
6614:
6615: CurrentConfigListEntry = CurrentConfigListEntry->Flink;
6616:
6617: } while (CurrentConfigListEntry != ConfigList);
6618:
6619: }
6620:
6621: //
6622: // This port doesn't appear to be sharing with
6623: // anything. Just put it on the config list.
6624: //
6625:
6626: InsertTailList(
6627: ConfigList,
6628: &New->ConfigList
6629: );
6630:
6631: return TRUE;
6632:
6633: }
6634:
6635: PVOID
6636: SerialGetMappedAddress(
6637: IN INTERFACE_TYPE BusType,
6638: IN ULONG BusNumber,
6639: PHYSICAL_ADDRESS IoAddress,
6640: ULONG NumberOfBytes,
6641: ULONG AddressSpace,
6642: PBOOLEAN MappedAddress
6643: )
6644:
6645: /*++
6646:
6647: Routine Description:
6648:
6649: This routine maps an IO address to system address space.
6650:
6651: Arguments:
6652:
6653: BusType - what type of bus - eisa, mca, isa
6654: IoBusNumber - which IO bus (for machines with multiple buses).
6655: IoAddress - base device address to be mapped.
6656: NumberOfBytes - number of bytes for which address is valid.
6657: AddressSpace - Denotes whether the address is in io space or memory.
6658: MappedAddress - indicates whether the address was mapped.
6659: This only has meaning if the address returned
6660: is non-null.
6661:
6662: Return Value:
6663:
6664: Mapped address
6665:
6666: --*/
6667:
6668: {
6669: PHYSICAL_ADDRESS cardAddress;
6670: PVOID address;
6671:
6672: HalTranslateBusAddress(
6673: BusType,
6674: BusNumber,
6675: IoAddress,
6676: &AddressSpace,
6677: &cardAddress
6678: );
6679:
6680: //
6681: // Map the device base address into the virtual address space
6682: // if the address is in memory space.
6683: //
6684:
6685: if (!AddressSpace) {
6686:
6687: address = MmMapIoSpace(
6688: cardAddress,
6689: NumberOfBytes,
6690: FALSE
6691: );
6692:
6693: *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));
6694:
6695:
6696: } else {
6697:
6698: address = (PVOID)cardAddress.LowPart;
6699: *MappedAddress = FALSE;
6700:
6701: }
6702:
6703: return address;
6704:
6705: }
6706:
6707: VOID
6708: SerialSetupExternalNaming(
6709: IN PSERIAL_DEVICE_EXTENSION Extension
6710: )
6711:
6712: /*++
6713:
6714: Routine Description:
6715:
6716: This routine will be used to create a symbolic link
6717: to the driver name in the given object directory.
6718:
6719: It will also create an entry in the device map for
6720: this device - IF we could create the symbolic link.
6721:
6722: Arguments:
6723:
6724: Extension - Pointer to the device extension.
6725:
6726: Return Value:
6727:
6728: None.
6729:
6730: --*/
6731:
6732: {
6733:
6734: UNICODE_STRING fullLinkName;
6735: NTSTATUS status;
6736:
6737: //
6738: // Form the full symbolic link name we wish to create.
6739: //
6740:
6741: RtlInitUnicodeString(
6742: &fullLinkName,
6743: NULL
6744: );
6745:
6746: //
6747: // Allocate some pool for the name.
6748: //
6749:
6750: fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
6751: Extension->ObjectDirectory.Length+
6752: Extension->SymbolicLinkName.Length+
6753: sizeof(WCHAR);
6754:
6755:
6756:
6757: fullLinkName.Buffer = ExAllocatePool(
6758: PagedPool,
6759: fullLinkName.MaximumLength
6760: );
6761:
6762: if (!fullLinkName.Buffer) {
6763:
6764: //
6765: // Couldn't allocate space for the name.
6766: //
6767:
6768: SerialLogError(
6769: Extension->DeviceObject->DriverObject,
6770: Extension->DeviceObject,
6771: Extension->OriginalController,
6772: SerialPhysicalZero,
6773: 0,
6774: 0,
6775: 0,
6776: 51,
6777: STATUS_SUCCESS,
6778: SERIAL_INSUFFICIENT_RESOURCES,
6779: 0,
6780: NULL,
6781: 0,
6782: NULL
6783: );
6784: SerialDump(
6785: SERERRORS,
6786: ("SERIAL: Couldn't allocate space for the symbolic \n"
6787: "------- name for creating the link\n"
6788: "------- for port %wZ\n",
6789: &Extension->DeviceName)
6790: );
6791:
6792: } else {
6793:
6794: RtlZeroMemory(
6795: fullLinkName.Buffer,
6796: fullLinkName.MaximumLength
6797: );
6798:
6799: RtlAppendUnicodeToString(
6800: &fullLinkName,
6801: L"\\"
6802: );
6803:
6804: RtlAppendUnicodeStringToString(
6805: &fullLinkName,
6806: &Extension->ObjectDirectory
6807: );
6808:
6809: RtlAppendUnicodeToString(
6810: &fullLinkName,
6811: L"\\"
6812: );
6813:
6814: RtlAppendUnicodeStringToString(
6815: &fullLinkName,
6816: &Extension->SymbolicLinkName
6817: );
6818:
6819:
6820: status = IoCreateSymbolicLink(
6821: &fullLinkName,
6822: &Extension->DeviceName
6823: );
6824: if (!NT_SUCCESS(status)) {
6825:
6826: //
6827: // Oh well, couldn't create the symbolic link. No point
6828: // in trying to create the device map entry.
6829: //
6830:
6831: SerialLogError(
6832: Extension->DeviceObject->DriverObject,
6833: Extension->DeviceObject,
6834: Extension->OriginalController,
6835: SerialPhysicalZero,
6836: 0,
6837: 0,
6838: 0,
6839: 52,
6840: status,
6841: SERIAL_NO_SYMLINK_CREATED,
6842: Extension->SymbolicLinkName.Length+sizeof(WCHAR),
6843: Extension->SymbolicLinkName.Buffer,
6844: 0,
6845: NULL
6846: );
6847: SerialDump(
6848: SERERRORS,
6849: ("SERIAL: Couldn't create the symbolic link\n"
6850: "------- for port %wZ\n",
6851: &Extension->DeviceName)
6852: );
6853:
6854: } else {
6855:
6856: Extension->CreatedSymbolicLink = TRUE;
6857:
6858: status = RtlWriteRegistryValue(
6859: RTL_REGISTRY_DEVICEMAP,
6860: L"SERIALCOMM",
6861: Extension->NtNameForPort.Buffer,
6862: REG_SZ,
6863: Extension->SymbolicLinkName.Buffer,
6864: Extension->SymbolicLinkName.Length+sizeof(WCHAR)
6865: );
6866:
6867: if (!NT_SUCCESS(status)) {
6868:
6869: SerialLogError(
6870: Extension->DeviceObject->DriverObject,
6871: Extension->DeviceObject,
6872: Extension->OriginalController,
6873: SerialPhysicalZero,
6874: 0,
6875: 0,
6876: 0,
6877: 53,
6878: status,
6879: SERIAL_NO_DEVICE_MAP_CREATED,
6880: Extension->SymbolicLinkName.Length+sizeof(WCHAR),
6881: Extension->SymbolicLinkName.Buffer,
6882: 0,
6883: NULL
6884: );
6885: SerialDump(
6886: SERERRORS,
6887: ("SERIAL: Couldn't create the device map entry\n"
6888: "------- for port %wZ\n",
6889: &Extension->DeviceName)
6890: );
6891:
6892: }
6893:
6894: }
6895:
6896: ExFreePool(fullLinkName.Buffer);
6897:
6898: }
6899:
6900: }
6901:
6902: VOID
6903: SerialCleanupExternalNaming(
6904: IN PSERIAL_DEVICE_EXTENSION Extension
6905: )
6906:
6907: /*++
6908:
6909: Routine Description:
6910:
6911: This routine will be used to delete a symbolic link
6912: to the driver name in the given object directory.
6913:
6914: It will also delete an entry in the device map for
6915: this device if the symbolic link had been created.
6916:
6917: Arguments:
6918:
6919: Extension - Pointer to the device extension.
6920:
6921: Return Value:
6922:
6923: None.
6924:
6925: --*/
6926:
6927: {
6928:
6929: UNICODE_STRING fullLinkName;
6930:
6931: SerialDump(
6932: SERDIAG3,
6933: ("SERIAL: In SerialCleanupExternalNaming for\n"
6934: "------- extension: %x of port %wZ\n",
6935: Extension,&Extension->DeviceName)
6936: );
6937:
6938: //
6939: // We're cleaning up here. One reason we're cleaning up
6940: // is that we couldn't allocate space for the directory
6941: // name or the symbolic link.
6942: //
6943:
6944: if (Extension->ObjectDirectory.Buffer &&
6945: Extension->SymbolicLinkName.Buffer &&
6946: Extension->CreatedSymbolicLink) {
6947:
6948: //
6949: // Form the full symbolic link name we wish to create.
6950: //
6951:
6952: RtlInitUnicodeString(
6953: &fullLinkName,
6954: NULL
6955: );
6956:
6957: //
6958: // Allocate some pool for the name.
6959: //
6960:
6961: fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
6962: Extension->ObjectDirectory.Length+
6963: Extension->SymbolicLinkName.Length+
6964: sizeof(WCHAR);
6965:
6966: fullLinkName.Buffer = ExAllocatePool(
6967: PagedPool,
6968: fullLinkName.MaximumLength
6969: );
6970:
6971: if (!fullLinkName.Buffer) {
6972:
6973: //
6974: // Couldn't allocate space for the name. Just go on
6975: // to the device map stuff.
6976: //
6977:
6978: SerialLogError(
6979: Extension->DeviceObject->DriverObject,
6980: Extension->DeviceObject,
6981: Extension->OriginalController,
6982: SerialPhysicalZero,
6983: 0,
6984: 0,
6985: 0,
6986: 54,
6987: STATUS_SUCCESS,
6988: SERIAL_INSUFFICIENT_RESOURCES,
6989: 0,
6990: NULL,
6991: 0,
6992: NULL
6993: );
6994: SerialDump(
6995: SERERRORS,
6996: ("SERIAL: Couldn't allocate space for the symbolic \n"
6997: "------- name for creating the link\n"
6998: "------- for port %wZ on cleanup\n",
6999: &Extension->DeviceName)
7000: );
7001:
7002: } else {
7003:
7004: RtlZeroMemory(
7005: fullLinkName.Buffer,
7006: fullLinkName.MaximumLength
7007: );
7008:
7009: RtlAppendUnicodeToString(
7010: &fullLinkName,
7011: L"\\"
7012: );
7013:
7014: RtlAppendUnicodeStringToString(
7015: &fullLinkName,
7016: &Extension->ObjectDirectory
7017: );
7018:
7019: RtlAppendUnicodeToString(
7020: &fullLinkName,
7021: L"\\"
7022: );
7023:
7024: RtlAppendUnicodeStringToString(
7025: &fullLinkName,
7026: &Extension->SymbolicLinkName
7027: );
7028:
7029: IoDeleteSymbolicLink(&fullLinkName);
7030:
7031: ExFreePool(fullLinkName.Buffer);
7032:
7033: }
7034:
7035: //
7036: // We're cleaning up here. One reason we're cleaning up
7037: // is that we couldn't allocate space for the NtNameOfPort.
7038: //
7039:
7040: if (Extension->NtNameForPort.Buffer) {
7041:
7042: NTSTATUS status;
7043:
7044: status = RtlDeleteRegistryValue(
7045: RTL_REGISTRY_DEVICEMAP,
7046: L"SERIALCOMM",
7047: Extension->NtNameForPort.Buffer
7048: );
7049:
7050: if (!NT_SUCCESS(status)) {
7051:
7052: SerialLogError(
7053: Extension->DeviceObject->DriverObject,
7054: Extension->DeviceObject,
7055: Extension->OriginalController,
7056: SerialPhysicalZero,
7057: 0,
7058: 0,
7059: 0,
7060: 55,
7061: status,
7062: SERIAL_NO_DEVICE_MAP_DELETED,
7063: Extension->SymbolicLinkName.Length+sizeof(WCHAR),
7064: Extension->SymbolicLinkName.Buffer,
7065: 0,
7066: NULL
7067: );
7068: SerialDump(
7069: SERERRORS,
7070: ("SERIAL: Couldn't delete value entry %wZ\n",
7071: &Extension->DeviceName)
7072: );
7073:
7074: }
7075:
7076: }
7077:
7078: }
7079:
7080: }
7081:
7082: SERIAL_MEM_COMPARES
7083: SerialMemCompare(
7084: IN PHYSICAL_ADDRESS A,
7085: IN ULONG SpanOfA,
7086: IN PHYSICAL_ADDRESS B,
7087: IN ULONG SpanOfB
7088: )
7089:
7090: /*++
7091:
7092: Routine Description:
7093:
7094: Compare two phsical address.
7095:
7096: Arguments:
7097:
7098: A - One half of the comparison.
7099:
7100: SpanOfA - In units of bytes, the span of A.
7101:
7102: B - One half of the comparison.
7103:
7104: SpanOfB - In units of bytes, the span of B.
7105:
7106:
7107: Return Value:
7108:
7109: The result of the comparison.
7110:
7111: --*/
7112:
7113: {
7114:
7115: LARGE_INTEGER a;
7116: LARGE_INTEGER b;
7117:
7118: LARGE_INTEGER lower;
7119: ULONG lowerSpan;
7120: LARGE_INTEGER higher;
7121:
7122: a.LowPart = A.LowPart;
7123: a.HighPart = A.HighPart;
7124: b.LowPart = B.LowPart;
7125: b.HighPart = B.HighPart;
7126:
7127: if (RtlLargeIntegerEqualTo(
7128: a,
7129: b
7130: )) {
7131:
7132: return AddressesAreEqual;
7133:
7134: }
7135:
7136: if (RtlLargeIntegerGreaterThan(
7137: a,
7138: b
7139: )) {
7140:
7141: higher = a;
7142: lower = b;
7143: lowerSpan = SpanOfB;
7144:
7145: } else {
7146:
7147: higher = b;
7148: lower = a;
7149: lowerSpan = SpanOfA;
7150:
7151: }
7152:
7153: if (RtlLargeIntegerGreaterThanOrEqualTo(
7154: RtlLargeIntegerSubtract(
7155: higher,
7156: lower
7157: ),
7158: RtlConvertUlongToLargeInteger(lowerSpan)
7159: )) {
7160:
7161: return AddressesAreDisjoint;
7162:
7163: }
7164:
7165: return AddressesOverlap;
7166:
7167: }
7168:
7169: VOID
7170: SerialLogError(
7171: IN PDRIVER_OBJECT DriverObject,
7172: IN PDEVICE_OBJECT DeviceObject OPTIONAL,
7173: IN PHYSICAL_ADDRESS P1,
7174: IN PHYSICAL_ADDRESS P2,
7175: IN ULONG SequenceNumber,
7176: IN UCHAR MajorFunctionCode,
7177: IN UCHAR RetryCount,
7178: IN ULONG UniqueErrorValue,
7179: IN NTSTATUS FinalStatus,
7180: IN NTSTATUS SpecificIOStatus,
7181: IN ULONG LengthOfInsert1,
7182: IN PWCHAR Insert1,
7183: IN ULONG LengthOfInsert2,
7184: IN PWCHAR Insert2
7185: )
7186:
7187: /*++
7188:
7189: Routine Description:
7190:
7191: This routine allocates an error log entry, copies the supplied data
7192: to it, and requests that it be written to the error log file.
7193:
7194: Arguments:
7195:
7196: DriverObject - A pointer to the driver object for the device.
7197:
7198: DeviceObject - A pointer to the device object associated with the
7199: device that had the error, early in initialization, one may not
7200: yet exist.
7201:
7202: P1,P2 - If phyical addresses for the controller ports involved
7203: with the error are available, put them through as dump data.
7204:
7205: SequenceNumber - A ulong value that is unique to an IRP over the
7206: life of the irp in this driver - 0 generally means an error not
7207: associated with an irp.
7208:
7209: MajorFunctionCode - If there is an error associated with the irp,
7210: this is the major function code of that irp.
7211:
7212: RetryCount - The number of times a particular operation has been
7213: retried.
7214:
7215: UniqueErrorValue - A unique long word that identifies the particular
7216: call to this function.
7217:
7218: FinalStatus - The final status given to the irp that was associated
7219: with this error. If this log entry is being made during one of
7220: the retries this value will be STATUS_SUCCESS.
7221:
7222: SpecificIOStatus - The IO status for a particular error.
7223:
7224: LengthOfInsert1 - The length in bytes (including the terminating NULL)
7225: of the first insertion string.
7226:
7227: Insert1 - The first insertion string.
7228:
7229: LengthOfInsert2 - The length in bytes (including the terminating NULL)
7230: of the second insertion string. NOTE, there must
7231: be a first insertion string for their to be
7232: a second insertion string.
7233:
7234: Insert2 - The second insertion string.
7235:
7236: Return Value:
7237:
7238: None.
7239:
7240: --*/
7241:
7242: {
7243: PIO_ERROR_LOG_PACKET errorLogEntry;
7244:
7245: PVOID objectToUse;
7246: SHORT dumpToAllocate = 0;
7247: PUCHAR ptrToFirstInsert;
7248: PUCHAR ptrToSecondInsert;
7249:
7250:
7251: if (ARGUMENT_PRESENT(DeviceObject)) {
7252:
7253: objectToUse = DeviceObject;
7254:
7255: } else {
7256:
7257: objectToUse = DriverObject;
7258:
7259: }
7260:
7261: if (SerialMemCompare(
7262: P1,
7263: (ULONG)1,
7264: SerialPhysicalZero,
7265: (ULONG)1
7266: ) != AddressesAreEqual) {
7267:
7268: dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
7269:
7270: }
7271:
7272: if (SerialMemCompare(
7273: P2,
7274: (ULONG)1,
7275: SerialPhysicalZero,
7276: (ULONG)1
7277: ) != AddressesAreEqual) {
7278:
7279: dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
7280:
7281: }
7282:
7283: errorLogEntry = IoAllocateErrorLogEntry(
7284: objectToUse,
7285: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
7286: dumpToAllocate + LengthOfInsert1 +
7287: LengthOfInsert2)
7288: );
7289:
7290: if ( errorLogEntry != NULL ) {
7291:
7292: errorLogEntry->ErrorCode = SpecificIOStatus;
7293: errorLogEntry->SequenceNumber = SequenceNumber;
7294: errorLogEntry->MajorFunctionCode = MajorFunctionCode;
7295: errorLogEntry->RetryCount = RetryCount;
7296: errorLogEntry->UniqueErrorValue = UniqueErrorValue;
7297: errorLogEntry->FinalStatus = FinalStatus;
7298: errorLogEntry->DumpDataSize = dumpToAllocate;
7299:
7300: if (dumpToAllocate) {
7301:
7302: RtlCopyMemory(
7303: &errorLogEntry->DumpData[0],
7304: &P1,
7305: sizeof(PHYSICAL_ADDRESS)
7306: );
7307:
7308: if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
7309:
7310: RtlCopyMemory(
7311: ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS),
7312: &P2,
7313: sizeof(PHYSICAL_ADDRESS)
7314: );
7315:
7316: ptrToFirstInsert =
7317: ((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS));
7318:
7319: } else {
7320:
7321: ptrToFirstInsert =
7322: ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS);
7323:
7324:
7325: }
7326:
7327: } else {
7328:
7329: ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
7330:
7331: }
7332:
7333: ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
7334:
7335: if (LengthOfInsert1) {
7336:
7337: errorLogEntry->NumberOfStrings = 1;
7338: errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
7339: (PUCHAR)errorLogEntry);
7340: RtlCopyMemory(
7341: ptrToFirstInsert,
7342: Insert1,
7343: LengthOfInsert1
7344: );
7345:
7346: if (LengthOfInsert2) {
7347:
7348: errorLogEntry->NumberOfStrings = 2;
7349: RtlCopyMemory(
7350: ptrToSecondInsert,
7351: Insert2,
7352: LengthOfInsert2
7353: );
7354:
7355: }
7356:
7357: }
7358:
7359: IoWriteErrorLogEntry(errorLogEntry);
7360:
7361: }
7362:
7363: }
7364:
7365: VOID
7366: SerialUnReportResourcesDevice(
7367: IN PSERIAL_DEVICE_EXTENSION Extension
7368: )
7369:
7370: /*++
7371:
7372: Routine Description:
7373:
7374: This routine *un*reports the resources used for a device that
7375: is "ready" to run. If some conflict was detected, it doesn't
7376: matter, the reources are *un*reported.
7377:
7378: Arguments:
7379:
7380: Extension - The device extension of the device we are *un*reporting
7381: resources for.
7382:
7383: Return Value:
7384:
7385: None.
7386:
7387: --*/
7388:
7389: {
7390:
7391: CM_RESOURCE_LIST resourceList;
7392: ULONG sizeOfResourceList = 0;
7393: UNICODE_STRING className;
7394: BOOLEAN junkBoolean;
7395:
7396: SerialDump(
7397: SERDIAG3,
7398: ("SERIAL: In SerialUnreportResourcesDevice\n"
7399: "------- for extension %x of port %wZ\n",
7400: Extension,&Extension->DeviceName)
7401: );
7402: RtlZeroMemory(
7403: &resourceList,
7404: sizeof(CM_RESOURCE_LIST)
7405: );
7406:
7407: resourceList.Count = 0;
7408:
7409: RtlInitUnicodeString(
7410: &className,
7411: L"LOADED SERIAL DRIVER RESOURCES"
7412: );
7413:
7414: IoReportResourceUsage(
7415: &className,
7416: Extension->DeviceObject->DriverObject,
7417: NULL,
7418: 0,
7419: Extension->DeviceObject,
7420: &resourceList,
7421: sizeof(CM_RESOURCE_LIST),
7422: FALSE,
7423: &junkBoolean
7424: );
7425:
7426: }
7427:
7428: VOID
7429: SerialReportResourcesDevice(
7430: IN PSERIAL_DEVICE_EXTENSION Extension,
7431: OUT BOOLEAN *ConflictDetected
7432: )
7433:
7434: /*++
7435:
7436: Routine Description:
7437:
7438: This routine reports the resources used for a device that
7439: is "ready" to run. If some conflict was detected, it doesn't
7440: matter, the reources are reported.
7441:
7442: Arguments:
7443:
7444: Extension - The device extension of the device we are reporting
7445: resources for.
7446:
7447: ConflictDetected - Pointer to a boolean that we will pass
7448: to the resource reporting code.
7449:
7450: Return Value:
7451:
7452: None.
7453:
7454: --*/
7455:
7456: {
7457:
7458: PCM_RESOURCE_LIST resourceList;
7459: ULONG sizeOfResourceList;
7460: ULONG countOfPartials;
7461: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
7462: UNICODE_STRING className;
7463:
7464: SerialDump(
7465: SERDIAG3,
7466: ("SERIAL: In SerialReportResourcesDevice\n"
7467: "------- for extension %x of port %wZ\n",
7468: Extension,&Extension->DeviceName)
7469: );
7470:
7471: //
7472: // The resource list for a device will consist of
7473: //
7474: // The resource list record itself with a count
7475: // of one for the single "built in" full resource
7476: // descriptor.
7477: //
7478: // The built-in full resource descriptor will contain
7479: // the bus type and busnumber and the built in partial
7480: // resource list.
7481: //
7482: // The built in partial resource list will have at
7483: // least a count of 2:
7484: //
7485: // 1) The interrupt that this device will be
7486: // coming in on.
7487: //
7488: // 2) The base register physical address and it's span.
7489: //
7490: // The built in partial resource list will have a
7491: // count of 3 if it has an interrupt status address
7492: // That interrupt status address will consist of
7493: // the physical address and the span (normally 1).
7494: //
7495:
7496: countOfPartials = Extension->InterruptStatus?3:2;
7497: sizeOfResourceList = sizeof(CM_RESOURCE_LIST) +
7498: (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)*
7499: (countOfPartials-1));
7500:
7501: resourceList = ExAllocatePool(
7502: PagedPool,
7503: sizeOfResourceList
7504: );
7505:
7506: if (!resourceList) {
7507:
7508: //
7509: // Oh well, can't allocate the memory. Act as though
7510: // we succeeded.
7511: //
7512:
7513: SerialLogError(
7514: Extension->DeviceObject->DriverObject,
7515: Extension->DeviceObject,
7516: Extension->OriginalController,
7517: SerialPhysicalZero,
7518: 0,
7519: 0,
7520: 0,
7521: 56,
7522: STATUS_SUCCESS,
7523: SERIAL_INSUFFICIENT_RESOURCES,
7524: 0,
7525: NULL,
7526: 0,
7527: NULL
7528: );
7529: return;
7530:
7531: }
7532:
7533: RtlZeroMemory(
7534: resourceList,
7535: sizeOfResourceList
7536: );
7537:
7538: resourceList->Count = 1;
7539:
7540:
7541: resourceList->List[0].InterfaceType = Extension->InterfaceType;
7542: resourceList->List[0].BusNumber = Extension->BusNumber;
7543: resourceList->List[0].PartialResourceList.Count = countOfPartials;
7544: partial = &resourceList->List[0].PartialResourceList.PartialDescriptors[0];
7545:
7546: //
7547: // Account for the space used by the controller.
7548: //
7549:
7550: partial->Type = CmResourceTypePort;
7551: partial->ShareDisposition = CmResourceShareDeviceExclusive;
7552: partial->Flags = (USHORT)Extension->AddressSpace;
7553: partial->u.Port.Start = Extension->OriginalController;
7554: partial->u.Port.Length = Extension->SpanOfController;
7555:
7556: partial++;
7557:
7558: //
7559: // Report the interrupt information.
7560: //
7561:
7562: partial->Type = CmResourceTypeInterrupt;
7563:
7564: if (Extension->InterruptShareable) {
7565:
7566: partial->ShareDisposition = CmResourceShareShared;
7567:
7568: } else {
7569:
7570: partial->ShareDisposition = CmResourceShareDriverExclusive;
7571:
7572: }
7573:
7574: if (Extension->InterruptMode == Latched) {
7575:
7576: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
7577:
7578: } else {
7579:
7580: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
7581:
7582: }
7583:
7584: partial->u.Interrupt.Vector = Extension->OriginalVector;
7585: partial->u.Interrupt.Level = Extension->OriginalIrql;
7586:
7587: //
7588: // We have an interrupt status register. Report it.
7589: //
7590:
7591: if (countOfPartials == 3) {
7592:
7593: partial++;
7594:
7595: partial->Type = CmResourceTypePort;
7596: partial->ShareDisposition = CmResourceShareDriverExclusive;
7597: partial->Flags = (USHORT)Extension->AddressSpace;
7598: partial->u.Port.Start = Extension->OriginalInterruptStatus;
7599: partial->u.Port.Length = Extension->SpanOfInterruptStatus;
7600:
7601: }
7602:
7603: RtlInitUnicodeString(
7604: &className,
7605: L"LOADED SERIAL DRIVER RESOURCES"
7606: );
7607:
7608: IoReportResourceUsage(
7609: &className,
7610: Extension->DeviceObject->DriverObject,
7611: NULL,
7612: 0,
7613: Extension->DeviceObject,
7614: resourceList,
7615: sizeOfResourceList,
7616: FALSE,
7617: ConflictDetected
7618: );
7619:
7620: ExFreePool(resourceList);
7621:
7622: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.