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