|
|
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 unloading of the parallel driver.
13:
14: Author:
15:
16: Anthony V. Ercolano 1-Aug-1992
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History :
23:
24: --*/
25:
26: #include <stddef.h>
27: #include "ntddk.h"
28: #include "par.h"
29: #include "parlog.h"
30:
31:
32: //
33: // This is the actual definition of ParDebugLevel.
34: // Note that it is only defined if this is a "debug"
35: // build.
36: //
37: #if DBG
38: extern ULONG ParDebugLevel = 0;
39: #endif
40:
41: //
42: // Give a timeout of 300 seconds. Some postscript printers will
43: // buffer up a lot of commands then proceed to render what they
44: // have. The printer will then refuse to accept any characters
45: // until it's done with the rendering. This render process can
46: // take a while. We'll give it 300 seconds.
47: //
48: // Note that an application can change this value.
49: //
50: #define PAR_WRITE_TIMEOUT_VALUE 300
51:
52: static const PHYSICAL_ADDRESS ParPhysicalZero = {0};
53:
54: NTSTATUS
55: DriverEntry(
56: IN PDRIVER_OBJECT DriverObject,
57: IN PUNICODE_STRING RegistryPath
58: );
59:
60: NTSTATUS
61: ParInitializeController(
62: IN PDRIVER_OBJECT DriverObject,
63: IN PCONFIG_DATA ConfigData
64: );
65:
66: NTSTATUS
67: ParItemCallBack(
68: IN PVOID Context,
69: IN PUNICODE_STRING PathName,
70: IN INTERFACE_TYPE BusType,
71: IN ULONG BusNumber,
72: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
73: IN CONFIGURATION_TYPE ControllerType,
74: IN ULONG ControllerNumber,
75: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
76: IN CONFIGURATION_TYPE PeripheralType,
77: IN ULONG PeripheralNumber,
78: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
79: );
80:
81: NTSTATUS
82: ParConfigCallBack(
83: IN PVOID Context,
84: IN PUNICODE_STRING PathName,
85: IN INTERFACE_TYPE BusType,
86: IN ULONG BusNumber,
87: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
88: IN CONFIGURATION_TYPE ControllerType,
89: IN ULONG ControllerNumber,
90: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
91: IN CONFIGURATION_TYPE PeripheralType,
92: IN ULONG PeripheralNumber,
93: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
94: );
95:
96: VOID
97: ParGetConfigInfo(
98: IN PDRIVER_OBJECT DriverObject,
99: IN PUNICODE_STRING RegistryPath,
100: OUT PLIST_ENTRY ConfigList
101: );
102:
103: BOOLEAN
104: ParPutInConfigList(
105: IN PDRIVER_OBJECT DriverObject,
106: IN OUT PLIST_ENTRY ConfigList,
107: IN PCONFIG_DATA New
108: );
109:
110: PVOID
111: ParGetMappedAddress(
112: IN INTERFACE_TYPE BusType,
113: IN ULONG BusNumber,
114: PHYSICAL_ADDRESS IoAddress,
115: ULONG NumberOfBytes,
116: ULONG AddressSpace,
117: PBOOLEAN MappedAddress
118: );
119:
120: VOID
121: ParSetupExternalNaming(
122: IN PPAR_DEVICE_EXTENSION Extension
123: );
124:
125: VOID
126: ParCleanupDevice(
127: IN PPAR_DEVICE_EXTENSION Extension
128: );
129:
130: VOID
131: ParCleanupExternalNaming(
132: IN PPAR_DEVICE_EXTENSION Extension
133: );
134:
135: typedef enum _PAR_MEM_COMPARES {
136: AddressesAreEqual,
137: AddressesOverlap,
138: AddressesAreDisjoint
139: } PAR_MEM_COMPARES,*PPAR_MEM_COMPARES;
140:
141: PAR_MEM_COMPARES
142: ParMemCompare(
143: IN PHYSICAL_ADDRESS A,
144: IN ULONG SpanOfA,
145: IN PHYSICAL_ADDRESS B,
146: IN ULONG SpanOfB
147: );
148:
149:
150: VOID
151: ParUnReportResourcesDevice(
152: IN PPAR_DEVICE_EXTENSION Extension
153: );
154:
155: VOID
156: ParReportResourcesDevice(
157: IN PPAR_DEVICE_EXTENSION Extension,
158: IN BOOLEAN ClaimInterrupt,
159: OUT BOOLEAN *ConflictDetected
160: );
161:
162: #ifdef ALLOC_PRAGMA
163: #pragma alloc_text(init,DriverEntry)
164: #pragma alloc_text(init,ParInitializeController)
165: #pragma alloc_text(init,ParItemCallBack)
166: #pragma alloc_text(init,ParConfigCallBack)
167: #pragma alloc_text(init,ParGetConfigInfo)
168: #pragma alloc_text(init,ParPutInConfigList)
169: #pragma alloc_text(init,ParGetMappedAddress)
170: #pragma alloc_text(init,ParSetupExternalNaming)
171: #pragma alloc_text(init,ParReportResourcesDevice)
172: #endif
173:
174: NTSTATUS
175: DriverEntry(
176: IN PDRIVER_OBJECT DriverObject,
177: IN PUNICODE_STRING RegistryPath
178: )
179:
180: /*++
181:
182: Routine Description:
183:
184: The entry point that the system point calls to initialize
185: any driver.
186:
187: This path will gather the configuration information,
188: attempt to initialize all driver data structures,
189: connect to interrupts for ports. If the above
190: goes reasonably well it will fill in the dispatch points,
191: reset the parallel devices and then return to the system.
192:
193: Arguments:
194:
195: DriverObject - Just what it says, really of little use
196: to the driver itself, it is something that the IO system
197: cares more about.
198:
199: PathToRegistry - points to the entry for this driver
200: in the current control set of the registry.
201:
202: Return Value:
203:
204: STATUS_SUCCESS if we could initialize a single device,
205: otherwise STATUS_NO_SUCH_DEVICE.
206:
207: --*/
208:
209: {
210:
211: //
212: // Holds status information return by various OS and driver
213: // initialization routines.
214: //
215: NTSTATUS status;
216:
217: //
218: // List head for configuration records.
219: //
220: LIST_ENTRY configList;
221:
222: //
223: // Pointer to a device object in the device object chain
224: // hanging off of the driver object.
225: //
226: PDEVICE_OBJECT currentDevice;
227:
228: //
229: // We use this to query into the registry as to whether we
230: // should break at driver entry.
231: //
232: RTL_QUERY_REGISTRY_TABLE paramTable[3];
233: ULONG zero = 0;
234: ULONG debugLevel = 0;
235: ULONG shouldBreak = 0;
236: PWCHAR path;
237:
238: //
239: // Since the registry path parameter is a "counted" UNICODE string, it
240: // might not be zero terminated. For a very short time allocate memory
241: // to hold the registry path zero terminated so that we can use it to
242: // delve into the registry.
243: //
244: // NOTE NOTE!!!! This is not an architected way of breaking into
245: // a driver. It happens to work for this driver because the author
246: // likes to do things this way.
247: //
248:
249: if (path = ExAllocatePool(
250: PagedPool,
251: RegistryPath->Length+sizeof(WCHAR)
252: )) {
253:
254: RtlZeroMemory(
255: ¶mTable[0],
256: sizeof(paramTable)
257: );
258: RtlZeroMemory(
259: path,
260: RegistryPath->Length+sizeof(WCHAR)
261: );
262: RtlMoveMemory(
263: path,
264: RegistryPath->Buffer,
265: RegistryPath->Length
266: );
267: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
268: paramTable[0].Name = L"BreakOnEntry";
269: paramTable[0].EntryContext = &shouldBreak;
270: paramTable[0].DefaultType = REG_DWORD;
271: paramTable[0].DefaultData = &zero;
272: paramTable[0].DefaultLength = sizeof(ULONG);
273: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
274: paramTable[1].Name = L"DebugLevel";
275: paramTable[1].EntryContext = &debugLevel;
276: paramTable[1].DefaultType = REG_DWORD;
277: paramTable[1].DefaultData = &zero;
278: paramTable[1].DefaultLength = sizeof(ULONG);
279:
280: if (!NT_SUCCESS(RtlQueryRegistryValues(
281: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
282: path,
283: ¶mTable[0],
284: NULL,
285: NULL
286: ))) {
287:
288: shouldBreak = 0;
289: debugLevel = 0;
290:
291: }
292:
293: }
294:
295: //
296: // We don't need that path anymore.
297: //
298:
299: if (path) {
300:
301: ExFreePool(path);
302:
303: }
304:
305: #if DBG
306: ParDebugLevel = debugLevel;
307: #endif
308:
309: if (shouldBreak) {
310:
311: DbgBreakPoint();
312:
313: }
314:
315: ParGetConfigInfo(
316: DriverObject,
317: RegistryPath,
318: &configList
319: );
320:
321: //
322: // Initialize each item in the list of configuration records.
323: //
324:
325: while (!IsListEmpty(&configList)) {
326:
327: PCONFIG_DATA currentConfig;
328: PLIST_ENTRY head;
329:
330: head = RemoveHeadList(&configList);
331:
332: currentConfig = CONTAINING_RECORD(
333: head,
334: CONFIG_DATA,
335: ConfigList
336: );
337:
338: ParInitializeController(
339: DriverObject,
340: currentConfig
341: );
342:
343: }
344:
345: //
346: // We've initialized all of the hardware that this driver
347: // will ever know about. All of the hardware that we know
348: // about is set up to NOT interrupt. We now go through
349: // all of the devices and connect an interrupt object for
350: // all.
351: //
352:
353: currentDevice = DriverObject->DeviceObject;
354:
355: while (currentDevice) {
356:
357: PPAR_DEVICE_EXTENSION extension = currentDevice->DeviceExtension;
358:
359: if (!extension->UsingATimer) {
360:
361: status = IoConnectInterrupt(
362: &extension->Interrupt,
363: ParInterruptServiceRoutine,
364: extension->DeviceObject,
365: NULL,
366: extension->Vector,
367: extension->Irql,
368: extension->Irql,
369: extension->InterruptMode,
370: extension->InterruptShareable,
371: extension->ProcessorAffinity,
372: FALSE
373: );
374:
375: if (!NT_SUCCESS(status)) {
376:
377: BOOLEAN junk;
378:
379: //
380: // Hmmm. Must be a BAD driver out there that isn't claiming
381: // its resources. Just switch this device to running off
382: // the timer. Also, switch the resources to be just the
383: // port.
384: //
385:
386: ParLogError(
387: extension->DeviceObject->DriverObject,
388: extension->DeviceObject,
389: extension->OriginalController,
390: ParPhysicalZero,
391: 0,
392: 0,
393: 0,
394: 1,
395: status,
396: PAR_UNREPORTED_IRQL_CONFLICT
397: );
398: ParReportResourcesDevice(
399: extension,
400: FALSE,
401: &junk
402: );
403: extension->UsingATimer = TRUE;
404:
405: }
406:
407: }
408:
409: currentDevice = currentDevice->NextDevice;
410:
411: }
412:
413: //
414: // We've connected up to the interrupt for everything. Now
415: // we initialize the device. (This could cause an interrupt.)
416: //
417:
418: currentDevice = DriverObject->DeviceObject;
419:
420: while (currentDevice) {
421:
422: IoStartTimer(currentDevice);
423: ParSynchronizeExecution(
424: currentDevice->DeviceExtension,
425: ParInitializeDevice,
426: currentDevice->DeviceExtension
427: );
428: currentDevice = currentDevice->NextDevice;
429:
430: }
431:
432: if (DriverObject->DeviceObject) {
433:
434: status = STATUS_SUCCESS;
435:
436: //
437: // Initialize the Driver Object with driver's entry points
438: //
439:
440: DriverObject->DriverStartIo = ParStartIo;
441: DriverObject->MajorFunction[IRP_MJ_WRITE] = ParDispatch;
442: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ParDispatch;
443: DriverObject->MajorFunction[IRP_MJ_CREATE] = ParDispatch;
444: DriverObject->MajorFunction[IRP_MJ_CLOSE] = ParDispatch;
445: DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
446: ParQueryInformationFile;
447: DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
448: ParSetInformationFile;
449: DriverObject->DriverUnload = ParUnload;
450:
451: } else {
452:
453: status = STATUS_NO_SUCH_DEVICE;
454:
455: }
456:
457: return status;
458: }
459:
460: NTSTATUS
461: ParInitializeController(
462: IN PDRIVER_OBJECT DriverObject,
463: IN PCONFIG_DATA ConfigData
464: )
465:
466: /*++
467:
468: Routine Description:
469:
470: Really too many things to mention here. In general, it forms
471: and sets up names, creates the device, translates bus relative
472: items...
473:
474:
475: Arguments:
476:
477: DriverObject - Just used to create the device object.
478:
479: ConfigData - Pointer to a record for a single port.
480:
481: NOTE: This routine will deallocate the config data.
482:
483: Return Value:
484:
485: STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
486: otherwise.
487:
488: --*/
489:
490: {
491:
492: //
493: // This will hold the string that we need to use to describe
494: // the name of the device to the IO system.
495: //
496: UNICODE_STRING uniNameString;
497:
498: //
499: // Holds the NT Status that is returned from each call to the
500: // kernel and executive.
501: //
502: NTSTATUS status = STATUS_SUCCESS;
503:
504: //
505: // Points to the device object (not the extension) created
506: // for this device.
507: //
508: PDEVICE_OBJECT deviceObject;
509:
510: //
511: // Points to the device extension for the device object
512: // (see above) created for the device we are initializing.
513: //
514: PPAR_DEVICE_EXTENSION extension = NULL;
515:
516: //
517: // Passed back from the resource reporting code to indicate
518: // whether the requested resources are already being used by
519: // another device.
520: //
521: BOOLEAN conflict;
522:
523:
524: ParDump(
525: PARCONFIG,
526: ("PARALLEL: Initializing for configuration record of %wZ\n",
527: &ConfigData->NtNameForPort)
528: );
529:
530: //
531: // Form a name like \Device\Parallel0.
532: //
533: // First we allocate space for the name.
534: //
535:
536: RtlInitUnicodeString(
537: &uniNameString,
538: NULL
539: );
540:
541: uniNameString.MaximumLength = sizeof(L"\\Device\\") +
542: ConfigData->NtNameForPort.Length+sizeof(WCHAR);
543: uniNameString.Buffer = ExAllocatePool(
544: PagedPool,
545: uniNameString.MaximumLength
546: );
547:
548: //
549: // The only reason the above could have failed is if
550: // there wasn't enough system memory to form the UNICODE
551: // string.
552: //
553:
554: if (!uniNameString.Buffer) {
555:
556: ParLogError(
557: DriverObject,
558: NULL,
559: ConfigData->Controller,
560: ParPhysicalZero,
561: 0,
562: 0,
563: 0,
564: 2,
565: STATUS_SUCCESS,
566: PAR_INSUFFICIENT_RESOURCES
567: );
568: ParDump(
569: PARERRORS,
570: ("PARALLEL: Could not form Unicode name string for %wZ\n",
571: &ConfigData->NtNameForPort)
572: );
573: ExFreePool(ConfigData->ObjectDirectory.Buffer);
574: ExFreePool(ConfigData->NtNameForPort.Buffer);
575: ExFreePool(ConfigData->SymbolicLinkName.Buffer);
576: ExFreePool(ConfigData);
577: return STATUS_INSUFFICIENT_RESOURCES;
578:
579: }
580:
581: //
582: // Actually form the Name.
583: //
584:
585: RtlZeroMemory(
586: uniNameString.Buffer,
587: uniNameString.MaximumLength
588: );
589:
590: RtlAppendUnicodeToString(
591: &uniNameString,
592: L"\\Device\\"
593: );
594:
595: RtlAppendUnicodeStringToString(
596: &uniNameString,
597: &ConfigData->NtNameForPort
598: );
599:
600: //
601: // Create the device object for this device.
602: //
603:
604: status = IoCreateDevice(
605: DriverObject,
606: sizeof(PAR_DEVICE_EXTENSION),
607: &uniNameString,
608: FILE_DEVICE_PARALLEL_PORT,
609: 0,
610: TRUE,
611: &deviceObject
612: );
613:
614: //
615: // If we couldn't create the device object, then there
616: // is no point in going on.
617: //
618:
619: if (!NT_SUCCESS(status)) {
620:
621: ParLogError(
622: DriverObject,
623: NULL,
624: ConfigData->Controller,
625: ParPhysicalZero,
626: 0,
627: 0,
628: 0,
629: 3,
630: STATUS_SUCCESS,
631: PAR_INSUFFICIENT_RESOURCES
632: );
633: ParDump(
634: PARERRORS,
635: ("PARALLEL: Could not create a device for %wZ\n",
636: &ConfigData->NtNameForPort)
637: );
638: ExFreePool(ConfigData->ObjectDirectory.Buffer);
639: ExFreePool(ConfigData->NtNameForPort.Buffer);
640: ExFreePool(ConfigData->SymbolicLinkName.Buffer);
641: ExFreePool(ConfigData);
642: ExFreePool(uniNameString.Buffer);
643: return STATUS_INSUFFICIENT_RESOURCES;
644:
645: }
646:
647: //
648: // We have created the device, increment the counter in the
649: // IO system that keep track. Anyplace that we do an IoDeleteDevice
650: // we need to decrement.
651: //
652:
653: IoGetConfigurationInformation()->ParallelCount++;
654:
655: //
656: // The device object has a pointer to an area of non-paged
657: // pool allocated for this device. This will be the device
658: // extension.
659: //
660:
661: extension = deviceObject->DeviceExtension;
662:
663: //
664: // Zero all of the memory associated with the device
665: // extension.
666: //
667:
668: RtlZeroMemory(
669: extension,
670: sizeof(PAR_DEVICE_EXTENSION)
671: );
672:
673: IoInitializeTimer(
674: deviceObject,
675: ParTimerRoutine,
676: NULL
677: );
678: IoInitializeDpcRequest(
679: deviceObject,
680: ParDpcRoutine
681: );
682:
683: //
684: // Save off our name.
685: //
686:
687: RtlInitUnicodeString(
688: &extension->DeviceName,
689: NULL
690: );
691:
692: extension->DeviceName.Length = uniNameString.Length;
693: extension->DeviceName.MaximumLength = uniNameString.MaximumLength;
694: extension->DeviceName.Buffer = uniNameString.Buffer;
695:
696: //
697: // Just initialize the names so that we don't try
698: // to "clean" them up if we cant intialize the
699: // controller all the way.
700: //
701:
702: RtlInitUnicodeString(
703: &extension->ObjectDirectory,
704: NULL
705: );
706: RtlInitUnicodeString(
707: &extension->NtNameForPort,
708: NULL
709: );
710: RtlInitUnicodeString(
711: &extension->SymbolicLinkName,
712: NULL
713: );
714:
715: //
716: // Get a "back pointer" to the device object and specify
717: // that this driver only supports buffered IO. This basically
718: // means that the IO system copies the users data to and from
719: // system supplied buffers.
720: //
721:
722: extension->DeviceObject = deviceObject;
723: deviceObject->Flags |= DO_BUFFERED_IO;
724:
725: //
726: // Map the memory for the control registers for the parallel device
727: // into virtual memory.
728: //
729:
730: extension->Controller = ParGetMappedAddress(
731: ConfigData->InterfaceType,
732: ConfigData->BusNumber,
733: ConfigData->Controller,
734: ConfigData->SpanOfController,
735: (BOOLEAN)ConfigData->AddressSpace,
736: &extension->UnMapRegisters
737: );
738:
739: if (!extension->Controller) {
740:
741: ParLogError(
742: deviceObject->DriverObject,
743: deviceObject,
744: ConfigData->Controller,
745: ParPhysicalZero,
746: 0,
747: 0,
748: 0,
749: 4,
750: STATUS_SUCCESS,
751: PAR_REGISTERS_NOT_MAPPED
752: );
753: ParDump(
754: PARERRORS,
755: ("PARALLEL: Could not map memory for device registers for %wZ\n",
756: &ConfigData->NtNameForPort)
757: );
758: extension->UnMapRegisters = FALSE;
759: status = STATUS_NONE_MAPPED;
760: goto ExtensionCleanup;
761:
762: }
763:
764: extension->AddressSpace = ConfigData->AddressSpace;
765: extension->OriginalController = ConfigData->Controller;
766: extension->SpanOfController = ConfigData->SpanOfController;
767:
768: //
769: // Save off the interface type and the bus number.
770: //
771:
772: extension->InterfaceType = ConfigData->InterfaceType;
773: extension->BusNumber = ConfigData->BusNumber;
774:
775: //
776: // We now try to claim the ports used by this device.
777: //
778: // We only go for the ports first, since we can run this
779: // device without using interrupts (although we prefer
780: // to use the interrupts). If we can't get the
781: // ports then we just cleanup. If we can get the ports
782: // the we try to claim the ports and the interrupt. If
783: // we can't get the interrupt then we'll just run the
784: // port off a timer.
785: //
786: // NOTE NOTE NOTE!!!!!
787: //
788: // Running the port off the timer can ONLY work when we
789: // are ONLY doing output to the port. To support a
790: // BI-DIRECTIONAL port is ****MUCH**** more complicated.
791: //
792: // As an additional note - somebody else could be using
793: // these port addresses and not claimed them, but, there
794: // isn't really much we can do about that.
795: //
796:
797: ParReportResourcesDevice(
798: extension,
799: FALSE,
800: &conflict
801: );
802:
803: if (conflict) {
804:
805: status = STATUS_NO_SUCH_DEVICE;
806: ParLogError(
807: deviceObject->DriverObject,
808: deviceObject,
809: ConfigData->Controller,
810: ParPhysicalZero,
811: 0,
812: 0,
813: 0,
814: 5,
815: STATUS_SUCCESS,
816: PAR_ADDRESS_CONFLICT
817: );
818: ParDump(
819: PARERRORS,
820: ("PARALLEL: Could not claim the device registers for %wZ\n",
821: &ConfigData->NtNameForPort)
822: );
823: goto ExtensionCleanup;
824:
825: }
826:
827: //
828: // The user might not have specified an interrupt. We can
829: // only assume that they wanted to run it off a timer.
830: //
831:
832: if (ConfigData->OriginalVector != MAXULONG) {
833:
834: //
835: // For now, assume that unless we are on a MicroChannel
836: // machine the interrupt isn't shareable.
837: //
838: // BUG BUG Is there some EISA data out there that will
839: // BUG BUG tell us whether the card is a true EISA card?
840: //
841:
842: if (ConfigData->InterfaceType == MicroChannel) {
843:
844: extension->InterruptShareable = TRUE;
845:
846: } else {
847:
848: extension->InterruptShareable = FALSE;
849:
850: }
851: //
852: // From the Hal, get the interrupt vector and level.
853: //
854:
855: extension->InterruptMode = ConfigData->InterruptMode;
856: extension->OriginalIrql = ConfigData->OriginalIrql;
857: extension->OriginalVector = ConfigData->OriginalVector;
858: extension->Vector = HalGetInterruptVector(
859: ConfigData->InterfaceType,
860: ConfigData->BusNumber,
861: ConfigData->OriginalIrql,
862: ConfigData->OriginalVector,
863: &extension->Irql,
864: &extension->ProcessorAffinity
865: );
866:
867: //
868: // Ok, now try for the interrupt.
869: //
870: // NOTE NOTE even if the following call can claim, this doesn't
871: // mean we get to use the interrupt. There might be some BAD
872: // device driver out there that is using that interrupt and
873: // hasn't reported its resources. We won't really find out
874: // until we try to connect to the interrupt.
875: //
876:
877: ParReportResourcesDevice(
878: extension,
879: TRUE,
880: &extension->UsingATimer
881: );
882:
883: if (extension->UsingATimer) {
884:
885: ParLogError(
886: deviceObject->DriverObject,
887: deviceObject,
888: ConfigData->Controller,
889: ParPhysicalZero,
890: 0,
891: 0,
892: 0,
893: 6,
894: STATUS_SUCCESS,
895: PAR_REPORTED_IRQL_CONFLICT
896: );
897:
898: }
899:
900: } else {
901:
902: extension->UsingATimer = TRUE;
903:
904: }
905:
906:
907: //
908: // Setup for using just a timer. We might have to drop down
909: // to this mode if we got an interrupt storm or we never
910: // see the interrupt.
911: //
912:
913: KeInitializeSpinLock(&extension->PollingLock);
914: KeInitializeTimer(&extension->PollingTimer);
915: KeInitializeDpc(
916: &extension->PollingDpc,
917: ParPollingDpcRoutine,
918: extension
919: );
920:
921: //
922: // For now just set the delay amount to 1, this
923: // should get us to the next system timer "tick".
924: //
925:
926: extension->PollingDelayAmount.LowPart = 1;
927: extension->PollingDelayAmount.HighPart = 0;
928: extension->PollingDelayAmount = RtlLargeIntegerNegate(
929: extension->PollingDelayAmount
930: );
931:
932:
933: //
934: // Disable the device from interrupting.
935: //
936:
937: StoreControl(
938: extension->Controller,
939: (UCHAR)PAR_CONTROL_WR_CONTROL
940: );
941: KeStallExecutionProcessor(60);
942:
943: //
944: // If it was requested that the port be disabled, now is the
945: // time to do it.
946: //
947:
948: if (ConfigData->DisablePort) {
949:
950:
951: status = STATUS_NO_SUCH_DEVICE;
952: ParLogError(
953: deviceObject->DriverObject,
954: deviceObject,
955: ConfigData->Controller,
956: ParPhysicalZero,
957: 0,
958: 0,
959: 0,
960: 40,
961: STATUS_SUCCESS,
962: PAR_DISABLED_PORT
963: );
964: ParDump(
965: PARERRORS,
966: ("PARALLEL: Port %wZ disabled as requested\n",
967: &ConfigData->NtNameForPort)
968: );
969: goto ExtensionCleanup;
970: }
971:
972: //
973: // The call will set up the naming necessary for
974: // external applications to get to the driver. It
975: // will also set up the device map.
976: //
977:
978: extension->ObjectDirectory = ConfigData->ObjectDirectory;
979: extension->NtNameForPort = ConfigData->NtNameForPort;
980: extension->SymbolicLinkName = ConfigData->SymbolicLinkName;
981: ParSetupExternalNaming(extension);
982:
983: extension->Initialized = FALSE;
984: extension->CountBuffer = 0;
985: extension->Initializing = FALSE;
986: extension->AutoFeed = FALSE;
987: extension->TimerCount = -1;
988: extension->TimerStart = PAR_WRITE_TIMEOUT_VALUE;
989:
990: //
991: // To get around some hardware bugs associated with the busy
992: // bit being set when it should be, we set up a couple of DPC's
993: // and a timer. See the comments in the interrupt service routine
994: // for details of the problem and the solution.
995: //
996:
997: KeInitializeTimer(&extension->BusyTimer);
998: KeInitializeDpc(
999: &extension->StartBusyTimerDpc,
1000: ParStartBusyTimer,
1001: extension
1002: );
1003: KeInitializeDpc(
1004: &extension->BusyTimerDpc,
1005: ParBusyTimer,
1006: extension
1007: );
1008:
1009: extension->BusyDelayAmount.LowPart = 1;
1010: extension->BusyDelayAmount.HighPart = 0;
1011: extension->BusyDelayAmount = RtlLargeIntegerNegate(
1012: extension->BusyDelayAmount
1013: );
1014:
1015: //
1016: // Common error path cleanup. If the status is
1017: // bad, get rid of the device extension, device object
1018: // and any memory associated with it.
1019: //
1020:
1021: ExtensionCleanup: ;
1022:
1023: ExFreePool(ConfigData);
1024:
1025: if (NT_ERROR(status)) {
1026:
1027: if (extension) {
1028:
1029: ParCleanupDevice(extension);
1030: IoDeleteDevice(deviceObject);
1031: IoGetConfigurationInformation()->ParallelCount--;
1032:
1033:
1034: }
1035:
1036: }
1037:
1038: return status;
1039:
1040: }
1041:
1042: NTSTATUS
1043: ParItemCallBack(
1044: IN PVOID Context,
1045: IN PUNICODE_STRING PathName,
1046: IN INTERFACE_TYPE BusType,
1047: IN ULONG BusNumber,
1048: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1049: IN CONFIGURATION_TYPE ControllerType,
1050: IN ULONG ControllerNumber,
1051: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1052: IN CONFIGURATION_TYPE PeripheralType,
1053: IN ULONG PeripheralNumber,
1054: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1055: )
1056:
1057: /*++
1058:
1059: Routine Description:
1060:
1061: This routine is called to check if a particular item
1062: is present in the registry.
1063:
1064: Arguments:
1065:
1066: Context - Pointer to a boolean.
1067:
1068: PathName - unicode registry path. Not Used.
1069:
1070: BusType - Internal, Isa, ...
1071:
1072: BusNumber - Which bus if we are on a multibus system.
1073:
1074: BusInformation - Configuration information about the bus. Not Used.
1075:
1076: ControllerType - Controller type.
1077:
1078: ControllerNumber - Which controller if there is more than one
1079: controller in the system.
1080:
1081: ControllerInformation - Array of pointers to the three pieces of
1082: registry information.
1083:
1084: PeripheralType - Should be a peripheral.
1085:
1086: PeripheralNumber - Which peripheral - not used..
1087:
1088: PeripheralInformation - Configuration information. Not Used.
1089:
1090: Return Value:
1091:
1092: STATUS_SUCCESS
1093:
1094: --*/
1095:
1096: {
1097:
1098: *((BOOLEAN *)Context) = TRUE;
1099: return STATUS_SUCCESS;
1100: }
1101:
1102: //
1103: // This structure is only used to communicate between the
1104: // code that queries what the firmware found and the code
1105: // that is calling the quering of the firmware data.
1106: //
1107: typedef struct PARALLEL_FIRMWARE_DATA {
1108: PDRIVER_OBJECT DriverObject;
1109: ULONG ControllersFound;
1110: UNICODE_STRING Directory;
1111: UNICODE_STRING NtNameSuffix;
1112: UNICODE_STRING DirectorySymbolicName;
1113: LIST_ENTRY ConfigList;
1114: } PARALLEL_FIRMWARE_DATA,*PPARALLEL_FIRMWARE_DATA;
1115:
1116:
1117: NTSTATUS
1118: ParConfigCallBack(
1119: IN PVOID Context,
1120: IN PUNICODE_STRING PathName,
1121: IN INTERFACE_TYPE BusType,
1122: IN ULONG BusNumber,
1123: IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
1124: IN CONFIGURATION_TYPE ControllerType,
1125: IN ULONG ControllerNumber,
1126: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
1127: IN CONFIGURATION_TYPE PeripheralType,
1128: IN ULONG PeripheralNumber,
1129: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
1130: )
1131:
1132: /*++
1133:
1134: Routine Description:
1135:
1136: This routine is used to acquire all of the configuration
1137: information for each parallel controller found by the firmware
1138:
1139: Arguments:
1140:
1141: Context - Pointer to the list head of the list of configuration
1142: records that we are building up.
1143:
1144: PathName - unicode registry path. Not Used.
1145:
1146: BusType - Internal, Isa, ...
1147:
1148: BusNumber - Which bus if we are on a multibus system.
1149:
1150: BusInformation - Configuration information about the bus. Not Used.
1151:
1152: ControllerType - Should always be ParallelController.
1153:
1154: ControllerNumber - Which controller if there is more than one
1155: controller in the system.
1156:
1157: ControllerInformation - Array of pointers to the three pieces of
1158: registry information.
1159:
1160: PeripheralType - Undefined for this call.
1161:
1162: PeripheralNumber - Undefined for this call.
1163:
1164: PeripheralInformation - Undefined for this call.
1165:
1166: Return Value:
1167:
1168: STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
1169: if all of the resource information couldn't be acquired.
1170:
1171: --*/
1172:
1173: {
1174:
1175: //
1176: // So we don't have to typecast the context.
1177: //
1178: PPARALLEL_FIRMWARE_DATA config = Context;
1179:
1180: //
1181: // Pointer to the configuration stuff for this controller.
1182: //
1183: PCONFIG_DATA controller;
1184:
1185: //
1186: // Two booleans to help us determine that we got enough configuration
1187: // data.
1188: //
1189: BOOLEAN foundPort = FALSE;
1190: BOOLEAN foundInterrupt = FALSE;
1191:
1192: //
1193: // Simple iteration variable.
1194: //
1195: ULONG i;
1196:
1197: //
1198: // Pointer to the configuration "data" portion of the configuration
1199: // structures in the registry for this device.
1200: //
1201: PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
1202: (PCM_FULL_RESOURCE_DESCRIPTOR)
1203: (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
1204: ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
1205:
1206: ASSERT(ControllerType == ParallelController);
1207:
1208: config->ControllersFound++;
1209:
1210: //
1211: // Allocate the memory for the controller config data out of paged pool
1212: // since we will only be accessing it at initialization time.
1213: //
1214:
1215: controller = ExAllocatePool(
1216: PagedPool,
1217: sizeof(CONFIG_DATA)
1218: );
1219:
1220: if (!controller) {
1221:
1222: ParLogError(
1223: config->DriverObject,
1224: NULL,
1225: ParPhysicalZero,
1226: ParPhysicalZero,
1227: 0,
1228: 0,
1229: 0,
1230: 7,
1231: STATUS_SUCCESS,
1232: PAR_INSUFFICIENT_RESOURCES
1233: );
1234: ParDump(
1235: PARERRORS,
1236: ("PARALLEL: Couldn't allocate memory for the configuration data\n"
1237: "-------- for firmware data\n")
1238: );
1239: return STATUS_INSUFFICIENT_RESOURCES;
1240:
1241: }
1242:
1243: RtlZeroMemory(
1244: controller,
1245: sizeof(CONFIG_DATA)
1246: );
1247: InitializeListHead(&controller->ConfigList);
1248:
1249: controller->InterfaceType = BusType;
1250: controller->BusNumber = BusNumber;
1251:
1252: //
1253: // We need to get the following information out of the partial
1254: // resource descriptors.
1255: //
1256: // The irql and vector.
1257: //
1258: // The base address and span covered by the parallel controllers
1259: // registers.
1260: //
1261: // It is not defined how these appear in the partial resource
1262: // lists, so we will just loop over all of them. If we find
1263: // something we don't recognize, we drop that information on
1264: // the floor. When we have finished going through all the
1265: // partial information, we validate that we got the above
1266: // two.
1267: //
1268:
1269: for (
1270: i = 0;
1271: i < controllerData->PartialResourceList.Count;
1272: i++
1273: ) {
1274:
1275: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
1276: &controllerData->PartialResourceList.PartialDescriptors[i];
1277:
1278: switch (partial->Type) {
1279:
1280: case CmResourceTypePort: {
1281:
1282: foundPort = TRUE;
1283:
1284: //
1285: // No matter what the registry says, we
1286: // know how long the register set is.
1287: //
1288:
1289: controller->SpanOfController = PARALLEL_REGISTER_SPAN;
1290: controller->Controller = partial->u.Port.Start;
1291: controller->AddressSpace = partial->Flags;
1292:
1293: break;
1294: }
1295: case CmResourceTypeInterrupt: {
1296:
1297: foundInterrupt = TRUE;
1298: if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
1299:
1300: controller->InterruptMode = Latched;
1301:
1302: } else {
1303:
1304: controller->InterruptMode = LevelSensitive;
1305:
1306: }
1307:
1308: controller->OriginalIrql = partial->u.Interrupt.Level;
1309: controller->OriginalVector = partial->u.Interrupt.Vector;
1310:
1311: break;
1312:
1313: }
1314: default: {
1315:
1316: break;
1317:
1318: }
1319:
1320: }
1321:
1322: }
1323:
1324: if (foundPort && foundInterrupt) {
1325:
1326: //
1327: // The following are so the we can form the
1328: // name following the \Device
1329: // and the default name that will be symbolic
1330: // linked to the device and the object directory
1331: // that link will go in.
1332: //
1333:
1334: WCHAR ntNumberBuffer[100];
1335: WCHAR symbolicNumberBuffer[100];
1336: UNICODE_STRING ntNumberString;
1337: UNICODE_STRING symbolicNumberString;
1338:
1339: ntNumberString.Length = 0;
1340: ntNumberString.MaximumLength = 100;
1341: ntNumberString.Buffer = &ntNumberBuffer[0];
1342:
1343: symbolicNumberString.Length = 0;
1344: symbolicNumberString.MaximumLength = 100;
1345: symbolicNumberString.Buffer = &symbolicNumberBuffer[0];
1346:
1347: //
1348: // Everthing is great so far. We now need to form the
1349: // Nt Names and symbolic link names.
1350: //
1351:
1352: if (!NT_SUCCESS(RtlIntegerToUnicodeString(
1353: config->ControllersFound - 1,
1354: 10,
1355: &ntNumberString
1356: ))) {
1357:
1358: ParLogError(
1359: config->DriverObject,
1360: NULL,
1361: ParPhysicalZero,
1362: ParPhysicalZero,
1363: 0,
1364: 0,
1365: 0,
1366: 8,
1367: STATUS_SUCCESS,
1368: PAR_INSUFFICIENT_RESOURCES
1369: );
1370: ParDump(
1371: PARERRORS,
1372: ("PARALLEL: Couldn't convert NT controller number to\n"
1373: "-------- to unicode for firmware data: %d\n",
1374: config->ControllersFound - 1)
1375: );
1376: //
1377: // Oh well, ignore this controller.
1378: //
1379: ExFreePool(controller);
1380:
1381: } else {
1382:
1383: if (!NT_SUCCESS(RtlIntegerToUnicodeString(
1384: config->ControllersFound,
1385: 10,
1386: &symbolicNumberString
1387: ))) {
1388:
1389: ParLogError(
1390: config->DriverObject,
1391: NULL,
1392: ParPhysicalZero,
1393: ParPhysicalZero,
1394: 0,
1395: 0,
1396: 0,
1397: 9,
1398: STATUS_SUCCESS,
1399: PAR_INSUFFICIENT_RESOURCES
1400: );
1401: ParDump(
1402: PARERRORS,
1403: ("PARALLEL: Couldn't convert symbolic controller number to\n"
1404: "-------- to unicode for firmware data: %d\n",
1405: config->ControllersFound)
1406: );
1407: ExFreePool(controller);
1408:
1409: } else {
1410:
1411: UNICODE_STRING Temp;
1412:
1413: //
1414: // Ok, we have the non-constant portions of the
1415: // names all figured out. Now allocate memory
1416: // for what will be used later.
1417: //
1418:
1419: //
1420: // Save off a copy of the object directory name.
1421: //
1422:
1423: //
1424: // Init the destination.
1425: //
1426: RtlInitUnicodeString(
1427: &controller->ObjectDirectory,
1428: NULL
1429: );
1430:
1431: //
1432: // This will get its length.
1433: //
1434: RtlInitUnicodeString(
1435: &Temp,
1436: DEFAULT_DIRECTORY
1437: );
1438:
1439:
1440: //
1441: // Now allocate that much.
1442: //
1443:
1444: controller->ObjectDirectory.Buffer =
1445: ExAllocatePool(
1446: PagedPool,
1447: Temp.Length+sizeof(WCHAR)
1448: );
1449:
1450: if (!controller->ObjectDirectory.Buffer) {
1451:
1452: ParLogError(
1453: config->DriverObject,
1454: NULL,
1455: ParPhysicalZero,
1456: ParPhysicalZero,
1457: 0,
1458: 0,
1459: 0,
1460: 10,
1461: STATUS_SUCCESS,
1462: PAR_INSUFFICIENT_RESOURCES
1463: );
1464: ParDump(
1465: PARERRORS,
1466: ("PARALLEL: Couldn't allocate memory for object\n"
1467: "-------- directory for NT firmware data: %d\n",
1468: config->ControllersFound - 1)
1469: );
1470: ExFreePool(controller);
1471: return STATUS_SUCCESS;
1472:
1473: } else {
1474:
1475: controller->ObjectDirectory.MaximumLength =
1476: Temp.Length+sizeof(WCHAR);
1477:
1478: //
1479: // Zero fill it.
1480: //
1481:
1482: RtlZeroMemory(
1483: controller->ObjectDirectory.Buffer,
1484: controller->ObjectDirectory.MaximumLength
1485: );
1486:
1487: RtlAppendUnicodeStringToString(
1488: &controller->ObjectDirectory,
1489: &Temp
1490: );
1491:
1492: }
1493:
1494: //
1495: // Init the destination.
1496: //
1497: RtlInitUnicodeString(
1498: &controller->NtNameForPort,
1499: NULL
1500: );
1501:
1502: //
1503: // This will get its length.
1504: //
1505: RtlInitUnicodeString(
1506: &Temp,
1507: DEFAULT_NT_SUFFIX
1508: );
1509:
1510: //
1511: // Allocate enough for the suffix and the number.
1512: //
1513:
1514: controller->NtNameForPort.Buffer =
1515: ExAllocatePool(
1516: PagedPool,
1517: Temp.Length +
1518: ntNumberString.Length + sizeof(WCHAR)
1519: );
1520:
1521: if (!controller->NtNameForPort.Buffer) {
1522:
1523: ParLogError(
1524: config->DriverObject,
1525: NULL,
1526: ParPhysicalZero,
1527: ParPhysicalZero,
1528: 0,
1529: 0,
1530: 0,
1531: 11,
1532: STATUS_SUCCESS,
1533: PAR_INSUFFICIENT_RESOURCES
1534: );
1535: ParDump(
1536: PARERRORS,
1537: ("PARALLEL: Couldn't allocate memory for NT\n"
1538: "-------- name for NT firmware data: %d\n",
1539: config->ControllersFound - 1)
1540: );
1541: ExFreePool(controller->ObjectDirectory.Buffer);
1542: ExFreePool(controller);
1543: return STATUS_SUCCESS;
1544:
1545: } else {
1546:
1547: controller->NtNameForPort.MaximumLength =
1548: Temp.Length+ntNumberString.Length+sizeof(WCHAR);
1549:
1550: RtlZeroMemory(
1551: controller->NtNameForPort.Buffer,
1552: controller->NtNameForPort.MaximumLength
1553: );
1554:
1555: RtlAppendUnicodeStringToString(
1556: &controller->NtNameForPort,
1557: &Temp
1558: );
1559:
1560: RtlAppendUnicodeStringToString(
1561: &controller->NtNameForPort,
1562: &ntNumberString
1563: );
1564:
1565: }
1566:
1567: //
1568: // Now form that name that will be used as a
1569: // symbolic link to the actual device name
1570: // we just formed.
1571: //
1572:
1573: RtlInitUnicodeString(
1574: &controller->SymbolicLinkName,
1575: NULL
1576: );
1577:
1578: //
1579: // This will get its length.
1580: //
1581: RtlInitUnicodeString(
1582: &Temp,
1583: DEFAULT_PARALLEL_NAME
1584: );
1585:
1586: //
1587: // Allocate enough for the suffix and the number.
1588: //
1589:
1590: controller->SymbolicLinkName.Buffer =
1591: ExAllocatePool(
1592: PagedPool,
1593: Temp.Length +
1594: symbolicNumberString.Length+sizeof(WCHAR)
1595: );
1596:
1597: if (!controller->SymbolicLinkName.Buffer) {
1598:
1599: ParLogError(
1600: config->DriverObject,
1601: NULL,
1602: ParPhysicalZero,
1603: ParPhysicalZero,
1604: 0,
1605: 0,
1606: 0,
1607: 12,
1608: STATUS_SUCCESS,
1609: PAR_INSUFFICIENT_RESOURCES
1610: );
1611: ParDump(
1612: PARERRORS,
1613: ("PARALLEL: Couldn't allocate memory for symbolic\n"
1614: "-------- name for NT firmware data: %d\n",
1615: config->ControllersFound - 1)
1616: );
1617: ExFreePool(controller->ObjectDirectory.Buffer);
1618: ExFreePool(controller->NtNameForPort.Buffer);
1619: ExFreePool(controller);
1620: return STATUS_SUCCESS;
1621:
1622: } else {
1623:
1624: controller->SymbolicLinkName.MaximumLength =
1625: Temp.Length+symbolicNumberString.Length+sizeof(WCHAR);
1626:
1627: RtlZeroMemory(
1628: controller->SymbolicLinkName.Buffer,
1629: controller->SymbolicLinkName.MaximumLength
1630: );
1631:
1632: RtlAppendUnicodeStringToString(
1633: &controller->SymbolicLinkName,
1634: &Temp
1635: );
1636:
1637: RtlAppendUnicodeStringToString(
1638: &controller->SymbolicLinkName,
1639: &symbolicNumberString
1640: );
1641:
1642: }
1643:
1644: InsertTailList(
1645: &config->ConfigList,
1646: &controller->ConfigList
1647: );
1648:
1649: }
1650:
1651: }
1652:
1653: } else {
1654:
1655: ParLogError(
1656: config->DriverObject,
1657: NULL,
1658: ParPhysicalZero,
1659: ParPhysicalZero,
1660: 0,
1661: 0,
1662: 0,
1663: 13,
1664: STATUS_SUCCESS,
1665: PAR_NOT_ENOUGH_CONFIG_INFO
1666: );
1667: ExFreePool(controller);
1668:
1669: }
1670:
1671: return STATUS_SUCCESS;
1672: }
1673:
1674: VOID
1675: ParGetConfigInfo(
1676: IN PDRIVER_OBJECT DriverObject,
1677: IN PUNICODE_STRING RegistryPath,
1678: OUT PLIST_ENTRY ConfigList
1679: )
1680:
1681: /*++
1682:
1683: Routine Description:
1684:
1685: This routine will "return" a list of configuration
1686: records for the parallel ports to initialize.
1687:
1688: It will first query the firmware data. It will then
1689: look for "user" specified parallel ports in the registry.
1690: It will place the user specified parallel ports in the
1691: the passed in list.
1692:
1693: After it finds all of the user specified ports, it will
1694: attempt to add the firmware parallel ports into the passed
1695: in lists. The insert in the list code detects conflicts
1696: and rejects a new port. In this way we can prevent
1697: firmware found ports from overiding information
1698: specified by the "user". Note, this means if the user
1699: specified data is incorrect in its use of the interrupt
1700: (which should *always* be correct from the firmware)
1701: that port likely will not work. But, then, we "trust"
1702: the user.
1703:
1704:
1705: Arguments:
1706:
1707: DriverObject - Not used.
1708:
1709: RegistryPath - Path to this drivers service node in
1710: the current control set.
1711:
1712: ConfigList - Listhead (which will be intialized) for a list
1713: of configuration records for ports to control.
1714:
1715: Return Value:
1716:
1717: None.
1718:
1719: --*/
1720:
1721: {
1722:
1723: //
1724: // A structure that we pass to the firmware query routine
1725: // as "context". This context will contain the number of
1726: // ports already found as well as default names and the
1727: // listhead of the configuration list.
1728: //
1729: PARALLEL_FIRMWARE_DATA firmware;
1730:
1731: //
1732: // This will point to the structure that is used by RtlQueryRegistryValues
1733: // to "direct" its search and retrieval of values.
1734: //
1735: PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
1736:
1737: //
1738: // We'll have to query the registry to determine what kind of
1739: // bus the system is using. Then when the user specifies the
1740: // address of a port, the user doesn't have to tell us the
1741: // the bus type (unless they really want to). When we determine
1742: // the default bus on the system, we'll know whether the interrupt
1743: // is latched or level sensitive.
1744: //
1745: INTERFACE_TYPE interfaceType;
1746: ULONG defaultInterfaceType;
1747:
1748: //
1749: // Default values for user data.
1750: //
1751: ULONG maxUlong = MAXULONG;
1752: ULONG zero = 0;
1753: ULONG defaultInterruptMode;
1754: ULONG defaultAddressSpace = CM_RESOURCE_PORT_IO;
1755:
1756: //
1757: // Where user data from the registry will be placed.
1758: //
1759: PHYSICAL_ADDRESS userPort;
1760: ULONG userVector;
1761: ULONG userLevel;
1762: ULONG userBusNumber;
1763: ULONG userInterfaceType;
1764: ULONG userAddressSpace;
1765: ULONG userInterruptMode;
1766: ULONG disablePort;
1767: UNICODE_STRING userSymbolicLink;
1768:
1769: UNICODE_STRING parametersPath;
1770: OBJECT_ATTRIBUTES parametersAttributes;
1771: HANDLE parametersKey;
1772: PKEY_BASIC_INFORMATION userSubKey = NULL;
1773: ULONG i;
1774:
1775: InitializeListHead(ConfigList);
1776:
1777: RtlZeroMemory(
1778: &firmware,
1779: sizeof(PARALLEL_FIRMWARE_DATA)
1780: );
1781:
1782: firmware.DriverObject = DriverObject;
1783:
1784: //
1785: // Initialize the controllers found so far with the
1786: // values in configuration database that the io system
1787: // maintains
1788: //
1789:
1790: firmware.ControllersFound = IoGetConfigurationInformation()->ParallelCount;
1791: InitializeListHead(&firmware.ConfigList);
1792: RtlInitUnicodeString(
1793: &firmware.Directory,
1794: DEFAULT_DIRECTORY
1795: );
1796: RtlInitUnicodeString(
1797: &firmware.NtNameSuffix,
1798: DEFAULT_NT_SUFFIX
1799: );
1800: RtlInitUnicodeString(
1801: &firmware.DirectorySymbolicName,
1802: DEFAULT_PARALLEL_NAME
1803: );
1804:
1805: //
1806: // First we query the hardware registry for all of
1807: // the firmware defined ports. We loop over all of
1808: // the busses.
1809: //
1810:
1811: for (
1812: interfaceType = 0;
1813: interfaceType < MaximumInterfaceType;
1814: interfaceType++
1815: ) {
1816:
1817: CONFIGURATION_TYPE sc = ParallelController;
1818:
1819: IoQueryDeviceDescription(
1820: &interfaceType,
1821: NULL,
1822: &sc,
1823: NULL,
1824: NULL,
1825: NULL,
1826: ParConfigCallBack,
1827: &firmware
1828: );
1829:
1830: }
1831:
1832: //
1833: // Query the registry one more time. This time we
1834: // look for the first bus on the system (that isn't
1835: // the internal bus - we assume that the firmware
1836: // code knows about those ports). We will use that
1837: // as the default bus if no bustype or bus number
1838: // is specified in the "user" configuration records.
1839: //
1840:
1841: defaultInterfaceType = (ULONG)Isa;
1842: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LATCHED;
1843:
1844: for (
1845: interfaceType = 0;
1846: interfaceType < MaximumInterfaceType;
1847: interfaceType++
1848: ) {
1849:
1850: ULONG busZero = 0;
1851: BOOLEAN foundOne = FALSE;
1852:
1853: if (interfaceType != Internal) {
1854:
1855: IoQueryDeviceDescription(
1856: &interfaceType,
1857: &busZero,
1858: NULL,
1859: NULL,
1860: NULL,
1861: NULL,
1862: ParItemCallBack,
1863: &foundOne
1864: );
1865:
1866: if (foundOne) {
1867:
1868: defaultInterfaceType = (ULONG)interfaceType;
1869: if (defaultInterfaceType == MicroChannel) {
1870:
1871: defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1872:
1873: }
1874:
1875: break;
1876:
1877: }
1878:
1879: }
1880:
1881: }
1882:
1883: //
1884: // Gonna get the user data now. Allocate the
1885: // structures that we will be using throughout
1886: // the search for user data. We will deallocate
1887: // them before we leave this routine.
1888: //
1889:
1890: userSymbolicLink.Buffer = NULL;
1891: parametersPath.Buffer = NULL;
1892:
1893: //
1894: // Allocate the rtl query table.
1895: //
1896:
1897: parameters = ExAllocatePool(
1898: PagedPool,
1899: sizeof(RTL_QUERY_REGISTRY_TABLE)*15
1900: );
1901:
1902: if (!parameters) {
1903:
1904: ParLogError(
1905: DriverObject,
1906: NULL,
1907: ParPhysicalZero,
1908: ParPhysicalZero,
1909: 0,
1910: 0,
1911: 0,
1912: 14,
1913: STATUS_SUCCESS,
1914: PAR_INSUFFICIENT_RESOURCES
1915: );
1916: ParDump(
1917: PARERRORS,
1918: ("PARALLEL: Couldn't allocate table for rtl query\n"
1919: "-------- to parameters for %wZ",
1920: RegistryPath)
1921: );
1922:
1923: goto DoFirmwareAdd;
1924:
1925: }
1926:
1927: RtlZeroMemory(
1928: parameters,
1929: sizeof(RTL_QUERY_REGISTRY_TABLE)*15
1930: );
1931:
1932: //
1933: // Allocate the place where the users symbolic link name
1934: // for the port will go.
1935: //
1936:
1937: //
1938: // We will initially allocate space for 257 wchars.
1939: // we will then set the maximum size to 256
1940: // This way the rtl routine could return a 256
1941: // WCHAR wide string with no null terminator.
1942: // We'll remember that the buffer is one WCHAR
1943: // longer then it says it is so that we can always
1944: // have a NULL terminator at the end.
1945: //
1946:
1947: RtlInitUnicodeString(
1948: &userSymbolicLink,
1949: NULL
1950: );
1951: userSymbolicLink.MaximumLength = sizeof(WCHAR)*256;
1952: userSymbolicLink.Buffer = ExAllocatePool(
1953: PagedPool,
1954: sizeof(WCHAR)*257
1955: );
1956:
1957: if (!userSymbolicLink.Buffer) {
1958:
1959: ParLogError(
1960: DriverObject,
1961: NULL,
1962: ParPhysicalZero,
1963: ParPhysicalZero,
1964: 0,
1965: 0,
1966: 0,
1967: 15,
1968: STATUS_SUCCESS,
1969: PAR_INSUFFICIENT_RESOURCES
1970: );
1971: ParDump(
1972: PARERRORS,
1973: ("PARALLEL: Couldn't allocate buffer for the symbolic link\n"
1974: "-------- for parameters items in %wZ",
1975: RegistryPath)
1976: );
1977:
1978: goto DoFirmwareAdd;
1979:
1980: }
1981:
1982: //
1983: // Form a path to our drivers Parameters subkey.
1984: //
1985:
1986: RtlInitUnicodeString(
1987: ¶metersPath,
1988: NULL
1989: );
1990:
1991: parametersPath.MaximumLength = RegistryPath->Length +
1992: sizeof(L"\\") +
1993: sizeof(L"Parameters");
1994:
1995: parametersPath.Buffer = ExAllocatePool(
1996: PagedPool,
1997: parametersPath.MaximumLength
1998: );
1999:
2000: if (!parametersPath.Buffer) {
2001:
2002: ParLogError(
2003: DriverObject,
2004: NULL,
2005: ParPhysicalZero,
2006: ParPhysicalZero,
2007: 0,
2008: 0,
2009: 0,
2010: 16,
2011: STATUS_SUCCESS,
2012: PAR_INSUFFICIENT_RESOURCES
2013: );
2014: ParDump(
2015: PARERRORS,
2016: ("PARALLEL: Couldn't allocate string for path\n"
2017: "-------- to parameters for %wZ",
2018: RegistryPath)
2019: );
2020:
2021: goto DoFirmwareAdd;
2022:
2023: }
2024:
2025: //
2026: // Form the parameters path.
2027: //
2028:
2029: RtlZeroMemory(
2030: parametersPath.Buffer,
2031: parametersPath.MaximumLength
2032: );
2033: RtlAppendUnicodeStringToString(
2034: ¶metersPath,
2035: RegistryPath
2036: );
2037: RtlAppendUnicodeToString(
2038: ¶metersPath,
2039: L"\\"
2040: );
2041: RtlAppendUnicodeToString(
2042: ¶metersPath,
2043: L"Parameters"
2044: );
2045:
2046: userSubKey = ExAllocatePool(
2047: PagedPool,
2048: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*256)
2049: );
2050:
2051: if (!userSubKey) {
2052:
2053: ParLogError(
2054: DriverObject,
2055: NULL,
2056: ParPhysicalZero,
2057: ParPhysicalZero,
2058: 0,
2059: 0,
2060: 0,
2061: 17,
2062: STATUS_SUCCESS,
2063: PAR_INSUFFICIENT_RESOURCES
2064: );
2065: ParDump(
2066: PARERRORS,
2067: ("PARALLEL: Couldn't allocate memory basic information\n"
2068: "-------- structure to enumerate subkeys for %wZ",
2069: ¶metersPath)
2070: );
2071:
2072: goto DoFirmwareAdd;
2073:
2074: }
2075:
2076: //
2077: // Open the key given by our registry path & Parameters.
2078: //
2079: // Note: The reason we are opening up the key by hand, and
2080: // then enumerating all of the subkeys is so we don't have
2081: // to architect what the names of the devices have to be and
2082: // how many of them there could be. We just try to get
2083: // as many as there are.
2084: //
2085:
2086: InitializeObjectAttributes(
2087: ¶metersAttributes,
2088: ¶metersPath,
2089: OBJ_CASE_INSENSITIVE,
2090: NULL,
2091: NULL
2092: );
2093:
2094: if (!NT_SUCCESS(ZwOpenKey(
2095: ¶metersKey,
2096: MAXIMUM_ALLOWED,
2097: ¶metersAttributes
2098: ))) {
2099:
2100: ParLogError(
2101: DriverObject,
2102: NULL,
2103: ParPhysicalZero,
2104: ParPhysicalZero,
2105: 0,
2106: 0,
2107: 0,
2108: 18,
2109: STATUS_SUCCESS,
2110: PAR_NO_PARAMETERS_INFO
2111: );
2112: ParDump(
2113: PARERRORS,
2114: ("PARALLEL: Couldn't open the drivers Parameters key %wZ\n",
2115: RegistryPath)
2116: );
2117: goto DoFirmwareAdd;
2118:
2119: }
2120:
2121: //
2122: // Gather all of the "user specified" information from
2123: // the registry.
2124: //
2125:
2126: parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
2127:
2128: parameters[1].Flags = RTL_QUERY_REGISTRY_REQUIRED |
2129: RTL_QUERY_REGISTRY_DIRECT;
2130: parameters[1].Name = L"PortAddress";
2131: parameters[1].EntryContext = &userPort.LowPart;
2132:
2133: parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
2134: parameters[2].Name = L"Interrupt";
2135: parameters[2].EntryContext = &userVector;
2136: parameters[2].DefaultType = REG_DWORD;
2137: parameters[2].DefaultData = &maxUlong;
2138: parameters[2].DefaultLength = sizeof(ULONG);
2139:
2140: parameters[3].Flags = RTL_QUERY_REGISTRY_REQUIRED |
2141: RTL_QUERY_REGISTRY_DIRECT;
2142: parameters[3].Name = firmware.Directory.Buffer;
2143: parameters[3].EntryContext = &userSymbolicLink;
2144:
2145: parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
2146: parameters[4].Name = L"BusNumber";
2147: parameters[4].EntryContext = &userBusNumber;
2148: parameters[4].DefaultType = REG_DWORD;
2149: parameters[4].DefaultData = &zero;
2150: parameters[4].DefaultLength = sizeof(ULONG);
2151:
2152: parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
2153: parameters[5].Name = L"BusType";
2154: parameters[5].EntryContext = &userInterfaceType;
2155: parameters[5].DefaultType = REG_DWORD;
2156: parameters[5].DefaultData = &defaultInterfaceType;
2157: parameters[5].DefaultLength = sizeof(ULONG);
2158:
2159: parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
2160: parameters[6].Name = L"InterruptMode";
2161: parameters[6].EntryContext = &userInterruptMode;
2162: parameters[6].DefaultType = REG_DWORD;
2163: parameters[6].DefaultData = &defaultInterruptMode;
2164: parameters[6].DefaultLength = sizeof(ULONG);
2165:
2166: parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
2167: parameters[7].Name = L"AddressSpace";
2168: parameters[7].EntryContext = &userAddressSpace;
2169: parameters[7].DefaultType = REG_DWORD;
2170: parameters[7].DefaultData = &defaultAddressSpace;
2171: parameters[7].DefaultLength = sizeof(ULONG);
2172:
2173: parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
2174: parameters[8].Name = L"InterruptLevel";
2175: parameters[8].EntryContext = &userLevel;
2176: parameters[8].DefaultType = REG_DWORD;
2177: parameters[8].DefaultData = &zero;
2178: parameters[8].DefaultLength = sizeof(ULONG);
2179:
2180: parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
2181: parameters[9].Name = L"DisablePort";
2182: parameters[9].EntryContext = &disablePort;
2183: parameters[9].DefaultType = REG_DWORD;
2184: parameters[9].DefaultData = &zero;
2185: parameters[9].DefaultLength = sizeof(ULONG);
2186:
2187: i = 0;
2188: while (TRUE) {
2189:
2190: NTSTATUS status;
2191: ULONG actuallyReturned;
2192:
2193: //
2194: // We lie about the length of the buffer, so that we can
2195: // MAKE SURE that the name it returns can be padded with
2196: // a NULL.
2197: //
2198:
2199: status = ZwEnumerateKey(
2200: parametersKey,
2201: i,
2202: KeyBasicInformation,
2203: userSubKey,
2204: sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*255),
2205: &actuallyReturned
2206: );
2207:
2208: if (status == STATUS_NO_MORE_ENTRIES) {
2209:
2210: break;
2211: }
2212:
2213: if (status == STATUS_BUFFER_OVERFLOW) {
2214:
2215: ParLogError(
2216: DriverObject,
2217: NULL,
2218: ParPhysicalZero,
2219: ParPhysicalZero,
2220: 0,
2221: 0,
2222: 0,
2223: 19,
2224: STATUS_SUCCESS,
2225: PAR_UNABLE_TO_ACCESS_CONFIG
2226: );
2227: ParDump(
2228: PARERRORS,
2229: ("PARALLEL: Overflowed the enumerate buffer\n"
2230: "-------- for subkey #%d of %wZ\n",
2231: i,parametersPath)
2232: );
2233: i++;
2234: continue;
2235:
2236: }
2237:
2238: if (!NT_SUCCESS(status)) {
2239:
2240: ParLogError(
2241: DriverObject,
2242: NULL,
2243: ParPhysicalZero,
2244: ParPhysicalZero,
2245: 0,
2246: 0,
2247: 0,
2248: 20,
2249: status,
2250: PAR_UNABLE_TO_ACCESS_CONFIG
2251: );
2252: ParDump(
2253: PARERRORS,
2254: ("PARALLEL: Bad status returned: %x \n"
2255: "-------- on enumeration for subkey # %d of %wZ\n",
2256: status,i,parametersPath)
2257: );
2258: i++;
2259: continue;
2260:
2261: }
2262:
2263: //
2264: // Pad the name returned with a null.
2265: //
2266:
2267: RtlZeroMemory(
2268: ((PUCHAR)(&userSubKey->Name[0]))+userSubKey->NameLength,
2269: sizeof(WCHAR)
2270: );
2271:
2272: parameters[0].Name = &userSubKey->Name[0];
2273:
2274: //
2275: // Make sure that the physical addresses start
2276: // out clean.
2277: //
2278: RtlZeroMemory(
2279: &userPort,
2280: sizeof(userPort)
2281: );
2282:
2283: status = RtlQueryRegistryValues(
2284: RTL_REGISTRY_ABSOLUTE,
2285: parametersPath.Buffer,
2286: parameters,
2287: NULL,
2288: NULL
2289: );
2290:
2291: if (NT_SUCCESS(status)) {
2292:
2293: PCONFIG_DATA newConfig;
2294:
2295: //
2296: // Well! Some supposedly valid information was found!
2297: //
2298: // We'll see about that.
2299: //
2300: // We don't want to cause the hal to have a bad day,
2301: // so let's check the interface type and bus number.
2302: //
2303: // We only need to check the registry if they aren't
2304: // equal to the defaults.
2305: //
2306:
2307: if ((userBusNumber != 0) ||
2308: (userInterfaceType != defaultInterfaceType)) {
2309:
2310: BOOLEAN foundIt = FALSE;
2311: if (userInterfaceType >= MaximumInterfaceType) {
2312:
2313: //
2314: // Ehhhh! Lose Game.
2315: //
2316:
2317: ParLogError(
2318: DriverObject,
2319: NULL,
2320: userPort,
2321: ParPhysicalZero,
2322: 0,
2323: 0,
2324: 0,
2325: 21,
2326: STATUS_SUCCESS,
2327: PAR_UNKNOWN_BUS
2328: );
2329: ParDump(
2330: PARERRORS,
2331: ("PARALLEL: Invalid Bus type %ws\n",
2332: parameters[0].Name)
2333: );
2334: i++;
2335: continue;
2336:
2337: }
2338:
2339: IoQueryDeviceDescription(
2340: (INTERFACE_TYPE *)&userInterfaceType,
2341: &userBusNumber,
2342: NULL,
2343: NULL,
2344: NULL,
2345: NULL,
2346: ParItemCallBack,
2347: &foundIt
2348: );
2349:
2350: if (!foundIt) {
2351:
2352: ParLogError(
2353: DriverObject,
2354: NULL,
2355: userPort,
2356: ParPhysicalZero,
2357: 0,
2358: 0,
2359: 0,
2360: 22,
2361: STATUS_SUCCESS,
2362: PAR_BUS_NOT_PRESENT
2363: );
2364: ParDump(
2365: PARERRORS,
2366: ("PARALLEL: There aren't that many of those\n"
2367: "-------- busses on this system,%ws\n",
2368: parameters[0].Name)
2369: );
2370: i++;
2371: continue;
2372:
2373: }
2374:
2375: }
2376:
2377: if ((userInterfaceType == MicroChannel) &&
2378: (userInterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) {
2379:
2380: ParLogError(
2381: DriverObject,
2382: NULL,
2383: userPort,
2384: ParPhysicalZero,
2385: 0,
2386: 0,
2387: 0,
2388: 23,
2389: STATUS_SUCCESS,
2390: PAR_BUS_INTERRUPT_CONFLICT
2391: );
2392: ParDump(
2393: PARERRORS,
2394: ("PARALLEL: Latched interrupts and MicroChannel\n"
2395: "-------- busses don't mix,%ws\n",
2396: parameters[0].Name)
2397: );
2398: i++;
2399: continue;
2400:
2401: }
2402:
2403: //
2404: // Well ok, I guess we can take the data.
2405: // There be other tests later on to make
2406: // sure it doesn't have any other kinds
2407: // of conflicts.
2408: //
2409:
2410: //
2411: // Allocate the config record.
2412: //
2413:
2414: newConfig = ExAllocatePool(
2415: PagedPool,
2416: sizeof(CONFIG_DATA)
2417: );
2418:
2419: if (!newConfig) {
2420:
2421: ParLogError(
2422: DriverObject,
2423: NULL,
2424: userPort,
2425: ParPhysicalZero,
2426: 0,
2427: 0,
2428: 0,
2429: 24,
2430: STATUS_SUCCESS,
2431: PAR_INSUFFICIENT_RESOURCES
2432: );
2433: ParDump(
2434: PARERRORS,
2435: ("PARALLEL: Couldn't allocate memory for the\n"
2436: "-------- user configuration record\n"
2437: "-------- for %ws\n",
2438: parameters[0].Name)
2439: );
2440:
2441: i++;
2442: continue;
2443:
2444: }
2445:
2446: RtlZeroMemory(
2447: newConfig,
2448: sizeof(CONFIG_DATA)
2449: );
2450:
2451: //
2452: // Save off a copy of the object directory name.
2453: //
2454:
2455: //
2456: // Init the destination.
2457: //
2458: RtlInitUnicodeString(
2459: &newConfig->ObjectDirectory,
2460: DEFAULT_DIRECTORY
2461: );
2462: newConfig->ObjectDirectory.MaximumLength += sizeof(WCHAR);
2463:
2464: //
2465: // Now allocate that much.
2466: //
2467:
2468: newConfig->ObjectDirectory.Buffer =
2469: ExAllocatePool(
2470: PagedPool,
2471: newConfig->ObjectDirectory.MaximumLength
2472: );
2473:
2474: if (!newConfig->ObjectDirectory.Buffer) {
2475:
2476: ParLogError(
2477: DriverObject,
2478: NULL,
2479: userPort,
2480: ParPhysicalZero,
2481: 0,
2482: 0,
2483: 0,
2484: 25,
2485: STATUS_SUCCESS,
2486: PAR_INSUFFICIENT_RESOURCES
2487: );
2488: ParDump(
2489: PARERRORS,
2490: ("PARALLEL: Couldn't allocate memory for object\n"
2491: "-------- directory for NT user data for: %ws\n",
2492: parameters[0].Name)
2493: );
2494: ExFreePool(newConfig);
2495: i++;
2496: continue;
2497:
2498: } else {
2499:
2500: //
2501: // Zero fill it.
2502: //
2503:
2504: RtlZeroMemory(
2505: newConfig->ObjectDirectory.Buffer,
2506: newConfig->ObjectDirectory.MaximumLength
2507: );
2508:
2509: newConfig->ObjectDirectory.Length = 0;
2510: RtlAppendUnicodeToString(
2511: &newConfig->ObjectDirectory,
2512: DEFAULT_DIRECTORY
2513: );
2514:
2515: }
2516:
2517: //
2518: // Init the destination.
2519: //
2520:
2521: RtlInitUnicodeString(
2522: &newConfig->NtNameForPort,
2523: &userSubKey->Name[0]
2524: );
2525:
2526: //
2527: // Allocate the space for the name.
2528: //
2529:
2530: newConfig->NtNameForPort.Length = 0;
2531: newConfig->NtNameForPort.MaximumLength += sizeof(WCHAR);
2532: newConfig->NtNameForPort.Buffer =
2533: ExAllocatePool(
2534: PagedPool,
2535: newConfig->NtNameForPort.MaximumLength
2536: );
2537:
2538: if (!newConfig->NtNameForPort.Buffer) {
2539:
2540: ParLogError(
2541: DriverObject,
2542: NULL,
2543: userPort,
2544: ParPhysicalZero,
2545: 0,
2546: 0,
2547: 0,
2548: 26,
2549: STATUS_SUCCESS,
2550: PAR_INSUFFICIENT_RESOURCES
2551: );
2552: ParDump(
2553: PARERRORS,
2554: ("PARALLEL: Couldn't allocate memory for NT\n"
2555: "-------- name for NT user data name: %ws\n",
2556: parameters[0].Name)
2557: );
2558: ExFreePool(newConfig->ObjectDirectory.Buffer);
2559: ExFreePool(newConfig);
2560: i++;
2561: continue;
2562:
2563: } else {
2564:
2565: RtlZeroMemory(
2566: newConfig->NtNameForPort.Buffer,
2567: newConfig->NtNameForPort.MaximumLength
2568: );
2569:
2570: RtlAppendUnicodeToString(
2571: &newConfig->NtNameForPort,
2572: &userSubKey->Name[0]
2573: );
2574:
2575: }
2576:
2577: newConfig->SymbolicLinkName = userSymbolicLink;
2578: newConfig->SymbolicLinkName.MaximumLength += sizeof(WCHAR);
2579:
2580: newConfig->SymbolicLinkName.Buffer =
2581: ExAllocatePool(
2582: PagedPool,
2583: newConfig->SymbolicLinkName.MaximumLength
2584: );
2585:
2586: if (!newConfig->SymbolicLinkName.Buffer) {
2587:
2588: ParLogError(
2589: DriverObject,
2590: NULL,
2591: userPort,
2592: ParPhysicalZero,
2593: 0,
2594: 0,
2595: 0,
2596: 27,
2597: STATUS_SUCCESS,
2598: PAR_INSUFFICIENT_RESOURCES
2599: );
2600: ParDump(
2601: PARERRORS,
2602: ("PARALLEL: Couldn't allocate memory for symbolic\n"
2603: "-------- name from user data\n"
2604: "-------- %ws\n",
2605: parameters[0].Name)
2606: );
2607: ExFreePool(newConfig->ObjectDirectory.Buffer);
2608: ExFreePool(newConfig->NtNameForPort.Buffer);
2609: ExFreePool(newConfig);
2610: i++;
2611: continue;
2612:
2613: } else {
2614:
2615: RtlZeroMemory(
2616: newConfig->SymbolicLinkName.Buffer,
2617: newConfig->SymbolicLinkName.MaximumLength
2618: );
2619:
2620: newConfig->SymbolicLinkName.Length = 0;
2621: RtlAppendUnicodeStringToString(
2622: &newConfig->SymbolicLinkName,
2623: &userSymbolicLink
2624: );
2625:
2626: }
2627:
2628: InitializeListHead(&newConfig->ConfigList);
2629: newConfig->Controller = userPort;
2630: newConfig->SpanOfController = PARALLEL_REGISTER_SPAN;
2631: newConfig->BusNumber = userBusNumber;
2632: newConfig->AddressSpace = userAddressSpace;
2633: newConfig->InterruptMode = userInterruptMode;
2634: newConfig->InterfaceType = userInterfaceType;
2635: newConfig->OriginalVector = userVector;
2636: newConfig->DisablePort = disablePort;
2637: if (!userLevel) {
2638: newConfig->OriginalIrql = userVector;
2639: } else {
2640: newConfig->OriginalIrql = userLevel;
2641: }
2642: ParDump(
2643: PARCONFIG,
2644: ("PARALLEL: 'user registry info - userPort: %x\n",
2645: userPort.LowPart)
2646: );
2647: ParDump(
2648: PARCONFIG,
2649: ("PARALLEL: 'user registry info - userBusNumber: %d\n",
2650: userBusNumber)
2651: );
2652: ParDump(
2653: PARCONFIG,
2654: ("PARALLEL: 'user registry info - userAddressSpace: %d\n",
2655: userAddressSpace)
2656: );
2657: ParDump(
2658: PARCONFIG,
2659: ("PARALLEL: 'user registry info - userInterruptMode: %d\n",
2660: userInterruptMode)
2661: );
2662: ParDump(
2663: PARCONFIG,
2664: ("PARALLEL: 'user registry info - userInterfaceType: %d\n",
2665: userInterfaceType)
2666: );
2667: ParDump(
2668: PARCONFIG,
2669: ("PARALLEL: 'user registry info - userVector: %d\n",
2670: userVector)
2671: );
2672: ParDump(
2673: PARCONFIG,
2674: ("PARALLEL: 'user registry info - userLevel: %d\n",
2675: userLevel)
2676: );
2677:
2678: if (!ParPutInConfigList(
2679: DriverObject,
2680: ConfigList,
2681: newConfig
2682: )) {
2683:
2684: //
2685: // Dispose of this configuration record.
2686: //
2687:
2688: ParDump(
2689: PARERRORS,
2690: ("PARALLEL: Conflict detected amoungst user data %ws\n",
2691: parameters[0].Name)
2692: );
2693:
2694: ExFreePool(newConfig->ObjectDirectory.Buffer);
2695: ExFreePool(newConfig->NtNameForPort.Buffer);
2696: ExFreePool(newConfig->SymbolicLinkName.Buffer);
2697: ExFreePool(newConfig);
2698:
2699: }
2700:
2701: i++;
2702:
2703: } else {
2704:
2705: ParLogError(
2706: DriverObject,
2707: NULL,
2708: ParPhysicalZero,
2709: ParPhysicalZero,
2710: 0,
2711: 0,
2712: 0,
2713: 28,
2714: STATUS_SUCCESS,
2715: PAR_INVALID_USER_CONFIG
2716: );
2717: ParDump(
2718: PARERRORS,
2719: ("PARALLEL: Bad status returned: %x \n"
2720: "-------- for the value entries of\n"
2721: "-------- %ws\n",
2722: status,parameters[0].Name)
2723: );
2724:
2725: i++;
2726:
2727: }
2728:
2729: }
2730:
2731: ZwClose(parametersKey);
2732:
2733: DoFirmwareAdd:;
2734:
2735: //
2736: // All done with the user specified information. Now try
2737: // to add the firmware specified data to the configuration.
2738: // If a conflict is detected then we simply dispose of that
2739: // firmware collected data.
2740: //
2741:
2742: while (!IsListEmpty(&firmware.ConfigList)) {
2743:
2744: PLIST_ENTRY head;
2745: PCONFIG_DATA firmwareData;
2746:
2747: head = RemoveHeadList(&firmware.ConfigList);
2748:
2749: firmwareData = CONTAINING_RECORD(
2750: head,
2751: CONFIG_DATA,
2752: ConfigList
2753: );
2754:
2755: if (!ParPutInConfigList(
2756: DriverObject,
2757: ConfigList,
2758: firmwareData
2759: )) {
2760:
2761: //
2762: // Dispose of this configuration record.
2763: //
2764:
2765: ParLogError(
2766: DriverObject,
2767: NULL,
2768: firmwareData->Controller,
2769: ParPhysicalZero,
2770: 0,
2771: 0,
2772: 0,
2773: 29,
2774: STATUS_SUCCESS,
2775: PAR_USER_OVERRIDE
2776: );
2777: ParDump(
2778: PARERRORS,
2779: ("PARALLEL: Conflict detected with user data for firmware port %wZ\n"
2780: "-------- User data will overides firmware data\n",
2781: &firmwareData->NtNameForPort)
2782: );
2783: ExFreePool(firmwareData->ObjectDirectory.Buffer);
2784: ExFreePool(firmwareData->NtNameForPort.Buffer);
2785: ExFreePool(firmwareData->SymbolicLinkName.Buffer);
2786: ExFreePool(firmwareData);
2787:
2788: }
2789:
2790: }
2791:
2792: if (userSubKey) {
2793:
2794: ExFreePool(userSubKey);
2795:
2796: }
2797:
2798: if (userSymbolicLink.Buffer) {
2799:
2800: ExFreePool(userSymbolicLink.Buffer);
2801:
2802: }
2803:
2804: if (parametersPath.Buffer) {
2805:
2806: ExFreePool(parametersPath.Buffer);
2807:
2808: }
2809:
2810: if (parameters) {
2811:
2812: ExFreePool(parameters);
2813:
2814: }
2815: }
2816:
2817: BOOLEAN
2818: ParPutInConfigList(
2819: IN PDRIVER_OBJECT DriverObject,
2820: IN OUT PLIST_ENTRY ConfigList,
2821: IN PCONFIG_DATA New
2822: )
2823:
2824: /*++
2825:
2826: Routine Description:
2827:
2828: Given a new config record and a config list, this routine
2829: will perform a check to make sure that the new record doesn't
2830: conflict with old records.
2831:
2832: If everything checks out it will insert the new config record
2833: into the config list.
2834:
2835: Arguments:
2836:
2837: DriverObject - The driver we are attempting to get configuration
2838: information for.
2839:
2840: ConfigList - Listhead for a list of configuration records for
2841: ports to control.
2842:
2843: New = Pointer to new configuration record to add.
2844:
2845: Return Value:
2846:
2847: True if the record was added to the config list, false otherwise.
2848:
2849: --*/
2850:
2851: {
2852:
2853: PHYSICAL_ADDRESS parPhysicalMax;
2854: PHYSICAL_ADDRESS parPhysicalZero;
2855:
2856: parPhysicalMax.LowPart = (ULONG)~0;
2857: parPhysicalMax.HighPart = ~0;
2858:
2859: ParDump(
2860: PARCONFIG,
2861: ("PARALLEL: Attempting to add %wZ\n"
2862: "-------- to the config list\n"
2863: "-------- PortAddress is %x\n"
2864: "-------- BusNumber is %d\n"
2865: "-------- BusType is %d\n"
2866: "-------- AddressSpace is %d\n",
2867: &New->NtNameForPort,
2868: New->Controller.LowPart,
2869: New->BusNumber,
2870: New->InterfaceType,
2871: New->AddressSpace
2872: )
2873: );
2874:
2875: //
2876: // We don't support any boards whose memory wraps around
2877: // the physical address space.
2878: //
2879:
2880: if (ParMemCompare(
2881: New->Controller,
2882: New->SpanOfController,
2883: parPhysicalMax,
2884: (ULONG)0
2885: ) != AddressesAreDisjoint) {
2886:
2887: ParLogError(
2888: DriverObject,
2889: NULL,
2890: New->Controller,
2891: ParPhysicalZero,
2892: 0,
2893: 0,
2894: 0,
2895: 30,
2896: STATUS_SUCCESS,
2897: PAR_DEVICE_TOO_HIGH
2898: );
2899: ParDump(
2900: PARERRORS,
2901: ("PARALLEL: Error in config record for %wZ\n"
2902: "-------- registers rap around physical memory\n",
2903: &New->NtNameForPort)
2904: );
2905: return FALSE;
2906:
2907: }
2908:
2909: //
2910: // Go through the list looking for previous devices
2911: // with the same address.
2912: //
2913:
2914: if (!IsListEmpty(ConfigList)) {
2915:
2916: PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink;
2917:
2918: do {
2919:
2920: PCONFIG_DATA OldConfig = CONTAINING_RECORD(
2921: CurrentConfigListEntry,
2922: CONFIG_DATA,
2923: ConfigList
2924: );
2925:
2926: //
2927: // We only care about ports that are on the same bus.
2928: //
2929:
2930: if ((OldConfig->InterfaceType == New->InterfaceType) &&
2931: (OldConfig->BusNumber == New->BusNumber)) {
2932:
2933: ParDump(
2934: PARCONFIG,
2935: ("PARALLEL: Comparing it to %wZ\n"
2936: "-------- already in the config list\n"
2937: "-------- PortAddress is %x\n"
2938: "-------- BusNumber is %d\n"
2939: "-------- BusType is %d\n"
2940: "-------- AddressSpace is %d\n",
2941: &OldConfig->NtNameForPort,
2942: OldConfig->Controller.LowPart,
2943: OldConfig->BusNumber,
2944: OldConfig->InterfaceType,
2945: OldConfig->AddressSpace
2946: )
2947: );
2948:
2949: if (ParMemCompare(
2950: New->Controller,
2951: New->SpanOfController,
2952: OldConfig->Controller,
2953: OldConfig->SpanOfController
2954: ) != AddressesAreDisjoint) {
2955:
2956: ParLogError(
2957: DriverObject,
2958: NULL,
2959: New->Controller,
2960: OldConfig->Controller,
2961: 0,
2962: 0,
2963: 0,
2964: 31,
2965: STATUS_SUCCESS,
2966: PAR_CONTROL_OVERLAP
2967: );
2968: return FALSE;
2969:
2970: }
2971:
2972: }
2973:
2974: CurrentConfigListEntry = CurrentConfigListEntry->Flink;
2975:
2976: } while (CurrentConfigListEntry != ConfigList);
2977:
2978: }
2979:
2980: InsertTailList(
2981: ConfigList,
2982: &New->ConfigList
2983: );
2984:
2985: return TRUE;
2986:
2987: }
2988:
2989: PVOID
2990: ParGetMappedAddress(
2991: IN INTERFACE_TYPE BusType,
2992: IN ULONG BusNumber,
2993: PHYSICAL_ADDRESS IoAddress,
2994: ULONG NumberOfBytes,
2995: ULONG AddressSpace,
2996: PBOOLEAN MappedAddress
2997: )
2998:
2999: /*++
3000:
3001: Routine Description:
3002:
3003: This routine maps an IO address to system address space.
3004:
3005: Arguments:
3006:
3007: BusType - what type of bus - eisa, mca, isa
3008: IoBusNumber - which IO bus (for machines with multiple buses).
3009: IoAddress - base device address to be mapped.
3010: NumberOfBytes - number of bytes for which address is valid.
3011: AddressSpace - Denotes whether the address is in io space or memory.
3012: MappedAddress - indicates whether the address was mapped.
3013: This only has meaning if the address returned
3014: is non-null.
3015:
3016: Return Value:
3017:
3018: Mapped address
3019:
3020: --*/
3021:
3022: {
3023: PHYSICAL_ADDRESS cardAddress;
3024: PVOID address;
3025:
3026: HalTranslateBusAddress(
3027: BusType,
3028: BusNumber,
3029: IoAddress,
3030: &AddressSpace,
3031: &cardAddress
3032: );
3033:
3034: //
3035: // Map the device base address into the virtual address space
3036: // if the address is in memory space.
3037: //
3038:
3039: if (!AddressSpace) {
3040:
3041: address = MmMapIoSpace(
3042: cardAddress,
3043: NumberOfBytes,
3044: FALSE
3045: );
3046:
3047: *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));
3048:
3049: } else {
3050:
3051: address = (PVOID)cardAddress.LowPart;
3052: *MappedAddress = FALSE;
3053:
3054: }
3055:
3056: return address;
3057:
3058: }
3059:
3060: VOID
3061: ParSetupExternalNaming(
3062: IN PPAR_DEVICE_EXTENSION Extension
3063: )
3064:
3065: /*++
3066:
3067: Routine Description:
3068:
3069: This routine will be used to create a symbolic link
3070: to the driver name in the given object directory.
3071:
3072: It will also create an entry in the device map for
3073: this device if the symbolic link was created.
3074:
3075: Arguments:
3076:
3077: Extension - Pointer to the device extension.
3078:
3079: Return Value:
3080:
3081: None.
3082:
3083: --*/
3084:
3085: {
3086:
3087: UNICODE_STRING fullLinkName;
3088:
3089: //
3090: // Form the full symbolic link name we wish to create.
3091: //
3092:
3093: RtlInitUnicodeString(
3094: &fullLinkName,
3095: NULL
3096: );
3097:
3098: //
3099: // Allocate some pool for the name.
3100: //
3101:
3102: fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
3103: Extension->ObjectDirectory.Length+
3104: Extension->SymbolicLinkName.Length+
3105: sizeof(WCHAR);
3106:
3107:
3108:
3109: fullLinkName.Buffer = ExAllocatePool(
3110: PagedPool,
3111: fullLinkName.MaximumLength
3112: );
3113:
3114: if (!fullLinkName.Buffer) {
3115:
3116: //
3117: // Couldn't allocate space for the name. Just go on
3118: // to the device map stuff.
3119: //
3120:
3121: ParLogError(
3122: Extension->DeviceObject->DriverObject,
3123: Extension->DeviceObject,
3124: Extension->OriginalController,
3125: ParPhysicalZero,
3126: 0,
3127: 0,
3128: 0,
3129: 32,
3130: STATUS_SUCCESS,
3131: PAR_INSUFFICIENT_RESOURCES
3132: );
3133: ParDump(
3134: PARERRORS,
3135: ("PARALLEL: Couldn't allocate space for the symbolic \n"
3136: "-------- name for creating the link\n"
3137: "-------- for port %wZ\n",
3138: &Extension->DeviceName)
3139: );
3140:
3141: } else {
3142:
3143: NTSTATUS status;
3144: RtlZeroMemory(
3145: fullLinkName.Buffer,
3146: fullLinkName.MaximumLength
3147: );
3148:
3149: RtlAppendUnicodeToString(
3150: &fullLinkName,
3151: L"\\"
3152: );
3153:
3154: RtlAppendUnicodeStringToString(
3155: &fullLinkName,
3156: &Extension->ObjectDirectory
3157: );
3158:
3159: RtlAppendUnicodeToString(
3160: &fullLinkName,
3161: L"\\"
3162: );
3163:
3164: RtlAppendUnicodeStringToString(
3165: &fullLinkName,
3166: &Extension->SymbolicLinkName
3167: );
3168:
3169: status = IoCreateUnprotectedSymbolicLink(
3170: &fullLinkName,
3171: &Extension->DeviceName
3172: );
3173:
3174: if (!NT_SUCCESS(status)) {
3175:
3176: //
3177: // Oh well, couldn't create the symbolic link.
3178: //
3179:
3180: ParDump(
3181: PARERRORS,
3182: ("PARALLEL: Couldn't create the symbolic link\n"
3183: "-------- for port %wZ\n",
3184: &Extension->DeviceName)
3185: );
3186: ParLogError(
3187: Extension->DeviceObject->DriverObject,
3188: Extension->DeviceObject,
3189: Extension->OriginalController,
3190: ParPhysicalZero,
3191: 0,
3192: 0,
3193: 0,
3194: 33,
3195: status,
3196: PAR_NO_SYMLINK_CREATED
3197: );
3198:
3199: } else {
3200:
3201: Extension->CreatedSymbolicLink = TRUE;
3202:
3203: status = RtlWriteRegistryValue(
3204: RTL_REGISTRY_DEVICEMAP,
3205: L"PARALLEL PORTS",
3206: Extension->NtNameForPort.Buffer,
3207: REG_SZ,
3208: Extension->SymbolicLinkName.Buffer,
3209: Extension->SymbolicLinkName.Length+sizeof(WCHAR)
3210: );
3211:
3212: if (!NT_SUCCESS(status)) {
3213:
3214: //
3215: // Oh well, it didn't work. Just go to cleanup.
3216: //
3217:
3218: ParDump(
3219: PARERRORS,
3220: ("PARALLEL: Couldn't create the device map entry\n"
3221: "-------- for port %wZ\n",
3222: &Extension->DeviceName)
3223: );
3224: ParLogError(
3225: Extension->DeviceObject->DriverObject,
3226: Extension->DeviceObject,
3227: Extension->OriginalController,
3228: ParPhysicalZero,
3229: 0,
3230: 0,
3231: 0,
3232: 34,
3233: status,
3234: PAR_NO_DEVICE_MAP_CREATED
3235: );
3236:
3237: }
3238:
3239: }
3240:
3241: ExFreePool(fullLinkName.Buffer);
3242:
3243: }
3244:
3245: }
3246:
3247: PAR_MEM_COMPARES
3248: ParMemCompare(
3249: IN PHYSICAL_ADDRESS A,
3250: IN ULONG SpanOfA,
3251: IN PHYSICAL_ADDRESS B,
3252: IN ULONG SpanOfB
3253: )
3254:
3255: /*++
3256:
3257: Routine Description:
3258:
3259: Compare two phsical address.
3260:
3261: Arguments:
3262:
3263: A - One half of the comparison.
3264:
3265: SpanOfA - In units of bytes, the span of A.
3266:
3267: B - One half of the comparison.
3268:
3269: SpanOfB - In units of bytes, the span of B.
3270:
3271:
3272: Return Value:
3273:
3274: The result of the comparison.
3275:
3276: --*/
3277:
3278: {
3279:
3280: LARGE_INTEGER a;
3281: LARGE_INTEGER b;
3282:
3283: LARGE_INTEGER lower;
3284: ULONG lowerSpan;
3285: LARGE_INTEGER higher;
3286:
3287: a.LowPart = A.LowPart;
3288: a.HighPart = A.HighPart;
3289: b.LowPart = B.LowPart;
3290: b.HighPart = B.HighPart;
3291:
3292: if (RtlLargeIntegerEqualTo(
3293: a,
3294: b
3295: )) {
3296:
3297: return AddressesAreEqual;
3298:
3299: }
3300:
3301: if (RtlLargeIntegerGreaterThan(
3302: a,
3303: b
3304: )) {
3305:
3306: higher = a;
3307: lower = b;
3308: lowerSpan = SpanOfB;
3309:
3310: } else {
3311:
3312: higher = b;
3313: lower = a;
3314: lowerSpan = SpanOfA;
3315:
3316: }
3317:
3318: if (RtlLargeIntegerGreaterThanOrEqualTo(
3319: RtlLargeIntegerSubtract(
3320: higher,
3321: lower
3322: ),
3323: RtlConvertUlongToLargeInteger(lowerSpan)
3324: )) {
3325:
3326: return AddressesAreDisjoint;
3327:
3328: }
3329:
3330: return AddressesOverlap;
3331:
3332: }
3333:
3334: VOID
3335: ParLogError(
3336: IN PDRIVER_OBJECT DriverObject,
3337: IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3338: IN PHYSICAL_ADDRESS P1,
3339: IN PHYSICAL_ADDRESS P2,
3340: IN ULONG SequenceNumber,
3341: IN UCHAR MajorFunctionCode,
3342: IN UCHAR RetryCount,
3343: IN ULONG UniqueErrorValue,
3344: IN NTSTATUS FinalStatus,
3345: IN NTSTATUS SpecificIOStatus
3346: )
3347:
3348: /*++
3349:
3350: Routine Description:
3351:
3352: This routine allocates an error log entry, copies the supplied data
3353: to it, and requests that it be written to the error log file.
3354:
3355: Arguments:
3356:
3357: DriverObject - A pointer to the driver object for the device.
3358:
3359: DeviceObject - A pointer to the device object associated with the
3360: device that had the error, early in initialization, one may not
3361: yet exist.
3362:
3363: P1,P2 - If phyical addresses for the controller ports involved
3364: with the error are available, put them through as dump data.
3365:
3366: SequenceNumber - A ulong value that is unique to an IRP over the
3367: life of the irp in this driver - 0 generally means an error not
3368: associated with an irp.
3369:
3370: MajorFunctionCode - If there is an error associated with the irp,
3371: this is the major function code of that irp.
3372:
3373: RetryCount - The number of times a particular operation has been
3374: retried.
3375:
3376: UniqueErrorValue - A unique long word that identifies the particular
3377: call to this function.
3378:
3379: FinalStatus - The final status given to the irp that was associated
3380: with this error. If this log entry is being made during one of
3381: the retries this value will be STATUS_SUCCESS.
3382:
3383: SpecificIOStatus - The IO status for a particular error.
3384:
3385: Return Value:
3386:
3387: None.
3388:
3389: --*/
3390:
3391: {
3392: PIO_ERROR_LOG_PACKET errorLogEntry;
3393:
3394: PVOID objectToUse;
3395: SHORT dumpToAllocate = 0;
3396:
3397: if (ARGUMENT_PRESENT(DeviceObject)) {
3398:
3399: objectToUse = DeviceObject;
3400:
3401: } else {
3402:
3403: objectToUse = DriverObject;
3404:
3405: }
3406:
3407: if (ParMemCompare(
3408: P1,
3409: (ULONG)1,
3410: ParPhysicalZero,
3411: (ULONG)1
3412: ) != AddressesAreEqual) {
3413:
3414: dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
3415:
3416: }
3417:
3418: if (ParMemCompare(
3419: P2,
3420: (ULONG)1,
3421: ParPhysicalZero,
3422: (ULONG)1
3423: ) != AddressesAreEqual) {
3424:
3425: dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
3426:
3427: }
3428:
3429: errorLogEntry = IoAllocateErrorLogEntry(
3430: objectToUse,
3431: (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate)
3432: );
3433:
3434: if ( errorLogEntry != NULL ) {
3435:
3436: errorLogEntry->ErrorCode = SpecificIOStatus;
3437: errorLogEntry->SequenceNumber = SequenceNumber;
3438: errorLogEntry->MajorFunctionCode = MajorFunctionCode;
3439: errorLogEntry->RetryCount = RetryCount;
3440: errorLogEntry->UniqueErrorValue = UniqueErrorValue;
3441: errorLogEntry->FinalStatus = FinalStatus;
3442: errorLogEntry->DumpDataSize = dumpToAllocate;
3443:
3444: if (dumpToAllocate) {
3445:
3446: RtlCopyMemory(
3447: &errorLogEntry->DumpData[0],
3448: &P1,
3449: sizeof(PHYSICAL_ADDRESS)
3450: );
3451:
3452: if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
3453:
3454: RtlCopyMemory(
3455: ((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS),
3456: &P2,
3457: sizeof(PHYSICAL_ADDRESS)
3458: );
3459:
3460: }
3461:
3462: }
3463:
3464:
3465:
3466: IoWriteErrorLogEntry(errorLogEntry);
3467:
3468: }
3469:
3470: }
3471:
3472: VOID
3473: ParReportResourcesDevice(
3474: IN PPAR_DEVICE_EXTENSION Extension,
3475: IN BOOLEAN ClaimInterrupt,
3476: OUT BOOLEAN *ConflictDetected
3477: )
3478:
3479: /*++
3480:
3481: Routine Description:
3482:
3483: This routine reports the resources used for a device that
3484: is "ready" to run. If some conflict was detected, it doesn't
3485: matter, the reources are reported.
3486:
3487: Arguments:
3488:
3489: Extension - The device extension of the device we are reporting
3490: resources for.
3491:
3492: ClaimInterrupts - If this was true then we should try to
3493: claim the interrupt that goes with this
3494: device
3495:
3496: ConflictDetected - Pointer to a boolean that we will pass
3497: to the resource reporting code.
3498:
3499: Return Value:
3500:
3501: None.
3502:
3503: --*/
3504:
3505: {
3506:
3507: PCM_RESOURCE_LIST resourceList;
3508: ULONG countOfPartials = 1;
3509: ULONG sizeOfResourceList;
3510: PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
3511: UNICODE_STRING className;
3512:
3513: ParDump(
3514: PARCONFIG,
3515: ("PARALLEL: In ParReportResourcesDevice\n"
3516: "-------- for extension %x of port %wZ\n",
3517: Extension,&Extension->DeviceName)
3518: );
3519:
3520: //
3521: // The resource list for a device will consist of
3522: //
3523: // The resource list record itself with a count
3524: // of one for the single "built in" full resource
3525: // descriptor.
3526: //
3527: // The built-in full resource descriptor will contain
3528: // the bus type and busnumber and the built in partial
3529: // resource list.
3530: //
3531: // The built in partial resource list will have a count of 1 or 2:
3532: //
3533: // 1) The base register physical address and it's span.
3534: //
3535: // 2) If the device is using an interrupt then it will
3536: // report that resource.
3537: //
3538: //
3539:
3540: if (ClaimInterrupt) {
3541:
3542: countOfPartials = 2;
3543:
3544: }
3545:
3546: sizeOfResourceList = sizeof(CM_RESOURCE_LIST) +
3547: (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)*
3548: (countOfPartials-1));
3549:
3550: resourceList = ExAllocatePool(
3551: PagedPool,
3552: sizeOfResourceList
3553: );
3554:
3555: if (!resourceList) {
3556:
3557: //
3558: // Oh well, can't allocate the memory. Act as though
3559: // we succeeded.
3560: //
3561:
3562: ParLogError(
3563: Extension->DeviceObject->DriverObject,
3564: Extension->DeviceObject,
3565: Extension->OriginalController,
3566: ParPhysicalZero,
3567: 0,
3568: 0,
3569: 0,
3570: 35,
3571: STATUS_SUCCESS,
3572: PAR_INSUFFICIENT_RESOURCES
3573: );
3574: return;
3575:
3576: }
3577:
3578: RtlZeroMemory(
3579: resourceList,
3580: sizeOfResourceList
3581: );
3582:
3583: resourceList->Count = 1;
3584:
3585: resourceList->List[0].InterfaceType = Extension->InterfaceType;
3586: resourceList->List[0].BusNumber = Extension->BusNumber;
3587: resourceList->List[0].PartialResourceList.Count = countOfPartials;
3588: partial = &resourceList->List[0].PartialResourceList.PartialDescriptors[0];
3589:
3590: //
3591: // Account for the space used by the controller.
3592: //
3593:
3594: partial->Type = CmResourceTypePort;
3595: partial->ShareDisposition = CmResourceShareDeviceExclusive;
3596: partial->Flags = (USHORT)Extension->AddressSpace;
3597: partial->u.Port.Start = Extension->OriginalController;
3598: partial->u.Port.Length = Extension->SpanOfController;
3599:
3600: partial++;
3601:
3602: if (ClaimInterrupt) {
3603:
3604: //
3605: // Report the interrupt information.
3606: //
3607:
3608: partial->Type = CmResourceTypeInterrupt;
3609:
3610: if (Extension->InterruptShareable) {
3611:
3612: partial->ShareDisposition = CmResourceShareShared;
3613:
3614: } else {
3615:
3616: partial->ShareDisposition = CmResourceShareDeviceExclusive;
3617:
3618: }
3619:
3620: if (Extension->InterruptMode == Latched) {
3621:
3622: partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
3623:
3624: } else {
3625:
3626: partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
3627:
3628: }
3629:
3630: partial->u.Interrupt.Vector = Extension->OriginalVector;
3631: partial->u.Interrupt.Level = Extension->OriginalIrql;
3632:
3633: }
3634:
3635: RtlInitUnicodeString(
3636: &className,
3637: L"LOADED PARALLEL DRIVER RESOURCES"
3638: );
3639:
3640: IoReportResourceUsage(
3641: &className,
3642: Extension->DeviceObject->DriverObject,
3643: NULL,
3644: 0,
3645: Extension->DeviceObject,
3646: resourceList,
3647: sizeOfResourceList,
3648: FALSE,
3649: ConflictDetected
3650: );
3651:
3652: ExFreePool(resourceList);
3653:
3654: }
3655:
3656: VOID
3657: ParUnload(
3658: IN PDRIVER_OBJECT DriverObject
3659: )
3660:
3661: /*++
3662:
3663: Routine Description:
3664:
3665: This routine cleans up all of the memory associated with
3666: any of the devices belonging to the driver. It will
3667: loop through the device list.
3668:
3669: Arguments:
3670:
3671: DriverObject - Pointer to the driver object controling all of the
3672: devices.
3673:
3674: Return Value:
3675:
3676: None.
3677:
3678: --*/
3679:
3680: {
3681:
3682: PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
3683:
3684: ParDump(
3685: PARUNLOAD,
3686: ("PARALLEL: In ParUnload\n")
3687: );
3688:
3689: while (currentDevice) {
3690:
3691: //
3692: // Disable the device from interrupting.
3693: //
3694:
3695: StoreControl(
3696: ((PPAR_DEVICE_EXTENSION)currentDevice->DeviceExtension)->Controller,
3697: PAR_CONTROL_WR_CONTROL
3698: );
3699: ParUnReportResourcesDevice(currentDevice->DeviceExtension);
3700: ParCleanupDevice(currentDevice->DeviceExtension);
3701: IoDeleteDevice(currentDevice);
3702: IoGetConfigurationInformation()->ParallelCount--;
3703:
3704: currentDevice = DriverObject->DeviceObject;
3705:
3706: }
3707:
3708: }
3709:
3710: VOID
3711: ParCleanupDevice(
3712: IN PPAR_DEVICE_EXTENSION Extension
3713: )
3714:
3715: /*++
3716:
3717: Routine Description:
3718:
3719: This routine will deallocate all of the memory used for
3720: a particular device. It will also disconnect any resources
3721: if need be.
3722:
3723: Arguments:
3724:
3725: Extension - Pointer to the device extension which is getting
3726: rid of all it's resources.
3727:
3728: Return Value:
3729:
3730: None.
3731:
3732: --*/
3733:
3734: {
3735:
3736: ParDump(
3737: PARUNLOAD,
3738: ("PARALLEL: in ParCleanupDevice for extension: %x\n",Extension)
3739: );
3740:
3741: if (Extension) {
3742:
3743: //
3744: // Stop the timer, we don't need it.
3745: //
3746: IoStopTimer(Extension->DeviceObject);
3747:
3748: //
3749: // Disconnect the interrupt object so that some spurious
3750: // interrupt doesn't cause us to dereference some memory we've
3751: // already given up.
3752: //
3753:
3754: if (!Extension->UsingATimer) {
3755:
3756: if (Extension->Interrupt) {
3757:
3758: ParDump(
3759: PARUNLOAD,
3760: ("PARALLEL: Extension has interrupt %x\n",Extension)
3761: );
3762: IoDisconnectInterrupt(Extension->Interrupt);
3763:
3764: }
3765:
3766: }
3767:
3768: //
3769: // Get rid of all external naming as well as removing
3770: // the device map entry.
3771: //
3772:
3773: ParCleanupExternalNaming(Extension);
3774:
3775: //
3776: // Delallocate the memory for the various names.
3777: // NOTE: If we have an extension - Then we must
3778: // have a device name stored away. Which is *not*
3779: // true for the other names.
3780: //
3781:
3782: ExFreePool(Extension->DeviceName.Buffer);
3783:
3784: if (Extension->ObjectDirectory.Buffer) {
3785:
3786: ExFreePool(Extension->ObjectDirectory.Buffer);
3787:
3788: }
3789:
3790: if (Extension->NtNameForPort.Buffer) {
3791:
3792: ExFreePool(Extension->NtNameForPort.Buffer);
3793:
3794: }
3795:
3796: if (Extension->SymbolicLinkName.Buffer) {
3797:
3798: ExFreePool(Extension->SymbolicLinkName.Buffer);
3799:
3800: }
3801:
3802: //
3803: // If necessary, unmap the device registers.
3804: //
3805:
3806: if (Extension->UnMapRegisters) {
3807:
3808: MmUnmapIoSpace(
3809: Extension->Controller,
3810: Extension->SpanOfController
3811: );
3812:
3813: }
3814:
3815: }
3816:
3817: }
3818:
3819: VOID
3820: ParCleanupExternalNaming(
3821: IN PPAR_DEVICE_EXTENSION Extension
3822: )
3823:
3824: /*++
3825:
3826: Routine Description:
3827:
3828: This routine will be used to delete a symbolic link
3829: to the driver name in the given object directory.
3830:
3831: It will also delete an entry in the device map for
3832: this device.
3833:
3834: Arguments:
3835:
3836: Extension - Pointer to the device extension.
3837:
3838: Return Value:
3839:
3840: None.
3841:
3842: --*/
3843:
3844: {
3845:
3846: UNICODE_STRING fullLinkName;
3847:
3848: ParDump(
3849: PARUNLOAD,
3850: ("PARALLEL: In ParCleanupExternalNaming for\n"
3851: "-------- extension: %x of port %wZ\n",
3852: Extension,&Extension->DeviceName)
3853: );
3854:
3855: //
3856: // We're cleaning up here. One reason we're cleaning up
3857: // is that we couldn't allocate space for the directory
3858: // name or the symbolic link.
3859: //
3860:
3861: if (Extension->ObjectDirectory.Buffer &&
3862: Extension->SymbolicLinkName.Buffer &&
3863: Extension->CreatedSymbolicLink) {
3864:
3865: //
3866: // Form the full symbolic link name we wish to create.
3867: //
3868:
3869: RtlInitUnicodeString(
3870: &fullLinkName,
3871: NULL
3872: );
3873:
3874: //
3875: // Allocate some pool for the name.
3876: //
3877:
3878: fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
3879: Extension->ObjectDirectory.Length+
3880: Extension->SymbolicLinkName.Length+
3881: sizeof(WCHAR);
3882:
3883: fullLinkName.Buffer = ExAllocatePool(
3884: PagedPool,
3885: fullLinkName.MaximumLength
3886: );
3887:
3888: if (!fullLinkName.Buffer) {
3889:
3890: //
3891: // Couldn't allocate space for the name. Just go on
3892: // to the device map stuff.
3893: //
3894:
3895: ParLogError(
3896: Extension->DeviceObject->DriverObject,
3897: Extension->DeviceObject,
3898: Extension->OriginalController,
3899: ParPhysicalZero,
3900: 0,
3901: 0,
3902: 0,
3903: 36,
3904: STATUS_SUCCESS,
3905: PAR_INSUFFICIENT_RESOURCES
3906: );
3907: ParDump(
3908: PARERRORS,
3909: ("PARALLEL: Couldn't allocate space for the symbolic \n"
3910: "-------- name for creating the link\n"
3911: "-------- for port %wZ on cleanup\n",
3912: &Extension->DeviceName)
3913: );
3914:
3915: } else {
3916:
3917: RtlZeroMemory(
3918: fullLinkName.Buffer,
3919: fullLinkName.MaximumLength
3920: );
3921:
3922: RtlAppendUnicodeToString(
3923: &fullLinkName,
3924: L"\\"
3925: );
3926:
3927: RtlAppendUnicodeStringToString(
3928: &fullLinkName,
3929: &Extension->ObjectDirectory
3930: );
3931:
3932: RtlAppendUnicodeToString(
3933: &fullLinkName,
3934: L"\\"
3935: );
3936:
3937: RtlAppendUnicodeStringToString(
3938: &fullLinkName,
3939: &Extension->SymbolicLinkName
3940: );
3941:
3942: IoDeleteSymbolicLink(&fullLinkName);
3943:
3944: ExFreePool(fullLinkName.Buffer);
3945:
3946: }
3947:
3948: //
3949: // We're cleaning up here. One reason we're cleaning up
3950: // is that we couldn't allocate space for the NtNameOfPort.
3951: //
3952:
3953: if (Extension->NtNameForPort.Buffer) {
3954:
3955: NTSTATUS status;
3956:
3957: status = RtlDeleteRegistryValue(
3958: RTL_REGISTRY_DEVICEMAP,
3959: L"PARALLEL PORTS",
3960: Extension->NtNameForPort.Buffer
3961: );
3962:
3963: if (!NT_SUCCESS(status)) {
3964:
3965: ParLogError(
3966: Extension->DeviceObject->DriverObject,
3967: Extension->DeviceObject,
3968: Extension->OriginalController,
3969: ParPhysicalZero,
3970: 0,
3971: 0,
3972: 0,
3973: 37,
3974: status,
3975: PAR_NO_DEVICE_MAP_DELETED
3976: );
3977: ParDump(
3978: PARERRORS,
3979: ("PARALLEL: Couldn't delete value entry %wZ\n",
3980: &Extension->DeviceName)
3981: );
3982:
3983: }
3984:
3985: }
3986:
3987: }
3988:
3989: }
3990:
3991: VOID
3992: ParUnReportResourcesDevice(
3993: IN PPAR_DEVICE_EXTENSION Extension
3994: )
3995:
3996: /*++
3997:
3998: Routine Description:
3999:
4000: Purge the resources for this particular device.
4001:
4002: Arguments:
4003:
4004: Extension - The device extension of the device we are *un*reporting
4005: resources for.
4006:
4007: Return Value:
4008:
4009: None.
4010:
4011: --*/
4012:
4013: {
4014:
4015: CM_RESOURCE_LIST resourceList;
4016: ULONG sizeOfResourceList = 0;
4017: UNICODE_STRING className;
4018: BOOLEAN junkBoolean;
4019:
4020: ParDump(
4021: PARUNLOAD,
4022: ("PARALLEL: In ParUnreportResourcesDevice\n"
4023: "-------- for extension %x of port %wZ\n",
4024: Extension,&Extension->DeviceName)
4025: );
4026: RtlZeroMemory(
4027: &resourceList,
4028: sizeof(CM_RESOURCE_LIST)
4029: );
4030:
4031: resourceList.Count = 0;
4032:
4033: RtlInitUnicodeString(
4034: &className,
4035: L"LOADED PARALLEL DRIVER RESOURCES"
4036: );
4037:
4038: IoReportResourceUsage(
4039: &className,
4040: Extension->DeviceObject->DriverObject,
4041: NULL,
4042: 0,
4043: Extension->DeviceObject,
4044: &resourceList,
4045: sizeof(CM_RESOURCE_LIST),
4046: FALSE,
4047: &junkBoolean
4048: );
4049:
4050: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.