3760 lines
94 KiB
C
3760 lines
94 KiB
C
/*++
|
||
|
||
Copyright (c) 1991, 1992, 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
initunlo.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code that is very specific to initialization
|
||
and unloading of the parallel driver.
|
||
|
||
Author:
|
||
|
||
Anthony V. Ercolano 1-Aug-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History :
|
||
|
||
--*/
|
||
|
||
#include <stddef.h>
|
||
#include "ntddk.h"
|
||
#include "par.h"
|
||
#include "parlog.h"
|
||
|
||
|
||
//
|
||
// This is the actual definition of ParDebugLevel.
|
||
// Note that it is only defined if this is a "debug"
|
||
// build.
|
||
//
|
||
#if DBG
|
||
extern ULONG ParDebugLevel = 0;
|
||
#endif
|
||
|
||
//
|
||
// Give a timeout of 300 seconds. Some postscript printers will
|
||
// buffer up a lot of commands then proceed to render what they
|
||
// have. The printer will then refuse to accept any characters
|
||
// until it's done with the rendering. This render process can
|
||
// take a while. We'll give it 300 seconds.
|
||
//
|
||
// Note that an application can change this value.
|
||
//
|
||
#define PAR_WRITE_TIMEOUT_VALUE 300
|
||
|
||
static const PHYSICAL_ADDRESS ParPhysicalZero = {0};
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
NTSTATUS
|
||
ParInitializeController(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PCONFIG_DATA ConfigData
|
||
);
|
||
|
||
NTSTATUS
|
||
ParItemCallBack(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
);
|
||
|
||
NTSTATUS
|
||
ParConfigCallBack(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
);
|
||
|
||
VOID
|
||
ParGetConfigInfo(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath,
|
||
OUT PLIST_ENTRY ConfigList
|
||
);
|
||
|
||
BOOLEAN
|
||
ParPutInConfigList(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN OUT PLIST_ENTRY ConfigList,
|
||
IN PCONFIG_DATA New
|
||
);
|
||
|
||
PVOID
|
||
ParGetMappedAddress(
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
PHYSICAL_ADDRESS IoAddress,
|
||
ULONG NumberOfBytes,
|
||
ULONG AddressSpace,
|
||
PBOOLEAN MappedAddress
|
||
);
|
||
|
||
VOID
|
||
ParSetupExternalNaming(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
);
|
||
|
||
VOID
|
||
ParCleanupDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
);
|
||
|
||
VOID
|
||
ParCleanupExternalNaming(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
);
|
||
|
||
typedef enum _PAR_MEM_COMPARES {
|
||
AddressesAreEqual,
|
||
AddressesOverlap,
|
||
AddressesAreDisjoint
|
||
} PAR_MEM_COMPARES,*PPAR_MEM_COMPARES;
|
||
|
||
PAR_MEM_COMPARES
|
||
ParMemCompare(
|
||
IN PHYSICAL_ADDRESS A,
|
||
IN ULONG SpanOfA,
|
||
IN PHYSICAL_ADDRESS B,
|
||
IN ULONG SpanOfB
|
||
);
|
||
|
||
|
||
VOID
|
||
ParUnReportResourcesDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
);
|
||
|
||
VOID
|
||
ParReportResourcesDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension,
|
||
IN BOOLEAN ClaimInterrupt,
|
||
OUT BOOLEAN *ConflictDetected
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(INIT,ParInitializeController)
|
||
#pragma alloc_text(INIT,ParItemCallBack)
|
||
#pragma alloc_text(INIT,ParConfigCallBack)
|
||
#pragma alloc_text(INIT,ParGetConfigInfo)
|
||
#pragma alloc_text(INIT,ParPutInConfigList)
|
||
#pragma alloc_text(INIT,ParGetMappedAddress)
|
||
#pragma alloc_text(INIT,ParSetupExternalNaming)
|
||
#pragma alloc_text(INIT,ParReportResourcesDevice)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The entry point that the system point calls to initialize
|
||
any driver.
|
||
|
||
This path will gather the configuration information,
|
||
attempt to initialize all driver data structures,
|
||
connect to interrupts for ports. If the above
|
||
goes reasonably well it will fill in the dispatch points,
|
||
reset the parallel devices and then return to the system.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Just what it says, really of little use
|
||
to the driver itself, it is something that the IO system
|
||
cares more about.
|
||
|
||
PathToRegistry - points to the entry for this driver
|
||
in the current control set of the registry.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if we could initialize a single device,
|
||
otherwise STATUS_NO_SUCH_DEVICE.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Holds status information return by various OS and driver
|
||
// initialization routines.
|
||
//
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// List head for configuration records.
|
||
//
|
||
LIST_ENTRY configList;
|
||
|
||
//
|
||
// We use this to query into the registry as to whether we
|
||
// should break at driver entry.
|
||
//
|
||
RTL_QUERY_REGISTRY_TABLE paramTable[3];
|
||
ULONG zero = 0;
|
||
ULONG debugLevel = 0;
|
||
ULONG shouldBreak = 0;
|
||
PWCHAR path;
|
||
|
||
//
|
||
// Since the registry path parameter is a "counted" UNICODE string, it
|
||
// might not be zero terminated. For a very short time allocate memory
|
||
// to hold the registry path zero terminated so that we can use it to
|
||
// delve into the registry.
|
||
//
|
||
// NOTE NOTE!!!! This is not an architected way of breaking into
|
||
// a driver. It happens to work for this driver because the author
|
||
// likes to do things this way.
|
||
//
|
||
|
||
if (path = ExAllocatePool(
|
||
PagedPool,
|
||
RegistryPath->Length+sizeof(WCHAR)
|
||
)) {
|
||
|
||
RtlZeroMemory(
|
||
¶mTable[0],
|
||
sizeof(paramTable)
|
||
);
|
||
RtlZeroMemory(
|
||
path,
|
||
RegistryPath->Length+sizeof(WCHAR)
|
||
);
|
||
RtlMoveMemory(
|
||
path,
|
||
RegistryPath->Buffer,
|
||
RegistryPath->Length
|
||
);
|
||
paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
paramTable[0].Name = L"BreakOnEntry";
|
||
paramTable[0].EntryContext = &shouldBreak;
|
||
paramTable[0].DefaultType = REG_DWORD;
|
||
paramTable[0].DefaultData = &zero;
|
||
paramTable[0].DefaultLength = sizeof(ULONG);
|
||
paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
paramTable[1].Name = L"DebugLevel";
|
||
paramTable[1].EntryContext = &debugLevel;
|
||
paramTable[1].DefaultType = REG_DWORD;
|
||
paramTable[1].DefaultData = &zero;
|
||
paramTable[1].DefaultLength = sizeof(ULONG);
|
||
|
||
if (!NT_SUCCESS(RtlQueryRegistryValues(
|
||
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
|
||
path,
|
||
¶mTable[0],
|
||
NULL,
|
||
NULL
|
||
))) {
|
||
|
||
shouldBreak = 0;
|
||
debugLevel = 0;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// We don't need that path anymore.
|
||
//
|
||
|
||
if (path) {
|
||
|
||
ExFreePool(path);
|
||
|
||
}
|
||
|
||
#if DBG
|
||
ParDebugLevel = debugLevel;
|
||
#endif
|
||
|
||
if (shouldBreak) {
|
||
|
||
DbgBreakPoint();
|
||
|
||
}
|
||
|
||
ParGetConfigInfo(
|
||
DriverObject,
|
||
RegistryPath,
|
||
&configList
|
||
);
|
||
|
||
//
|
||
// Initialize each item in the list of configuration records.
|
||
//
|
||
|
||
while (!IsListEmpty(&configList)) {
|
||
|
||
PCONFIG_DATA currentConfig;
|
||
PLIST_ENTRY head;
|
||
|
||
head = RemoveHeadList(&configList);
|
||
|
||
currentConfig = CONTAINING_RECORD(
|
||
head,
|
||
CONFIG_DATA,
|
||
ConfigList
|
||
);
|
||
|
||
ParInitializeController(
|
||
DriverObject,
|
||
currentConfig
|
||
);
|
||
|
||
}
|
||
|
||
if (DriverObject->DeviceObject) {
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Initialize the Driver Object with driver's entry points
|
||
//
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_WRITE] = ParDispatch;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ParDispatch;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = ParCreateOpen;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ParClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ParCleanup;
|
||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] =
|
||
ParQueryInformationFile;
|
||
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] =
|
||
ParSetInformationFile;
|
||
DriverObject->DriverUnload = ParUnload;
|
||
|
||
} else {
|
||
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ParInitializeController(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PCONFIG_DATA ConfigData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Really too many things to mention here. In general, it forms
|
||
and sets up names, creates the device, translates bus relative
|
||
items...
|
||
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Just used to create the device object.
|
||
|
||
ConfigData - Pointer to a record for a single port.
|
||
|
||
NOTE: This routine will deallocate the config data.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
|
||
otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// This will hold the string that we need to use to describe
|
||
// the name of the device to the IO system.
|
||
//
|
||
UNICODE_STRING uniNameString;
|
||
|
||
//
|
||
// Holds the NT Status that is returned from each call to the
|
||
// kernel and executive.
|
||
//
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Points to the device object (not the extension) created
|
||
// for this device.
|
||
//
|
||
PDEVICE_OBJECT deviceObject;
|
||
|
||
//
|
||
// Points to the device extension for the device object
|
||
// (see above) created for the device we are initializing.
|
||
//
|
||
PPAR_DEVICE_EXTENSION extension = NULL;
|
||
|
||
//
|
||
// Passed back from the resource reporting code to indicate
|
||
// whether the requested resources are already being used by
|
||
// another device.
|
||
//
|
||
BOOLEAN conflict;
|
||
|
||
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: Initializing for configuration record of %wZ\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
|
||
//
|
||
// Form a name like \Device\Parallel0.
|
||
//
|
||
// First we allocate space for the name.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&uniNameString,
|
||
NULL
|
||
);
|
||
|
||
uniNameString.MaximumLength = sizeof(L"\\Device\\") +
|
||
ConfigData->NtNameForPort.Length+sizeof(WCHAR);
|
||
uniNameString.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
uniNameString.MaximumLength
|
||
);
|
||
|
||
//
|
||
// The only reason the above could have failed is if
|
||
// there wasn't enough system memory to form the UNICODE
|
||
// string.
|
||
//
|
||
|
||
if (!uniNameString.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ConfigData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
2,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Could not form Unicode name string for %wZ\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
ExFreePool(ConfigData->ObjectDirectory.Buffer);
|
||
ExFreePool(ConfigData->NtNameForPort.Buffer);
|
||
ExFreePool(ConfigData->SymbolicLinkName.Buffer);
|
||
ExFreePool(ConfigData);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// Actually form the Name.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
uniNameString.Buffer,
|
||
uniNameString.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&uniNameString,
|
||
L"\\Device\\"
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&uniNameString,
|
||
&ConfigData->NtNameForPort
|
||
);
|
||
|
||
//
|
||
// Create the device object for this device.
|
||
//
|
||
|
||
status = IoCreateDevice(
|
||
DriverObject,
|
||
sizeof(PAR_DEVICE_EXTENSION),
|
||
&uniNameString,
|
||
FILE_DEVICE_PARALLEL_PORT,
|
||
0,
|
||
TRUE,
|
||
&deviceObject
|
||
);
|
||
|
||
//
|
||
// If we couldn't create the device object, then there
|
||
// is no point in going on.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ConfigData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
3,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Could not create a device for %wZ\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
ExFreePool(ConfigData->ObjectDirectory.Buffer);
|
||
ExFreePool(ConfigData->NtNameForPort.Buffer);
|
||
ExFreePool(ConfigData->SymbolicLinkName.Buffer);
|
||
ExFreePool(ConfigData);
|
||
ExFreePool(uniNameString.Buffer);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// We have created the device, increment the counter in the
|
||
// IO system that keep track. Anyplace that we do an IoDeleteDevice
|
||
// we need to decrement.
|
||
//
|
||
|
||
IoGetConfigurationInformation()->ParallelCount++;
|
||
|
||
//
|
||
// The device object has a pointer to an area of non-paged
|
||
// pool allocated for this device. This will be the device
|
||
// extension.
|
||
//
|
||
|
||
extension = deviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Zero all of the memory associated with the device
|
||
// extension.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
extension,
|
||
sizeof(PAR_DEVICE_EXTENSION)
|
||
);
|
||
|
||
//
|
||
// Save off our name.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&extension->DeviceName,
|
||
NULL
|
||
);
|
||
|
||
extension->DeviceName.Length = uniNameString.Length;
|
||
extension->DeviceName.MaximumLength = uniNameString.MaximumLength;
|
||
extension->DeviceName.Buffer = uniNameString.Buffer;
|
||
|
||
//
|
||
// Just initialize the names so that we don't try
|
||
// to "clean" them up if we cant intialize the
|
||
// controller all the way.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&extension->ObjectDirectory,
|
||
NULL
|
||
);
|
||
RtlInitUnicodeString(
|
||
&extension->NtNameForPort,
|
||
NULL
|
||
);
|
||
RtlInitUnicodeString(
|
||
&extension->SymbolicLinkName,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Get a "back pointer" to the device object and specify
|
||
// that this driver only supports buffered IO. This basically
|
||
// means that the IO system copies the users data to and from
|
||
// system supplied buffers.
|
||
//
|
||
|
||
extension->DeviceObject = deviceObject;
|
||
deviceObject->Flags |= DO_BUFFERED_IO;
|
||
|
||
//
|
||
// Map the memory for the control registers for the parallel device
|
||
// into virtual memory.
|
||
//
|
||
|
||
extension->Controller = ParGetMappedAddress(
|
||
ConfigData->InterfaceType,
|
||
ConfigData->BusNumber,
|
||
ConfigData->Controller,
|
||
ConfigData->SpanOfController,
|
||
(BOOLEAN)ConfigData->AddressSpace,
|
||
&extension->UnMapRegisters
|
||
);
|
||
|
||
if (!extension->Controller) {
|
||
|
||
ParLogError(
|
||
deviceObject->DriverObject,
|
||
deviceObject,
|
||
ConfigData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
4,
|
||
STATUS_SUCCESS,
|
||
PAR_REGISTERS_NOT_MAPPED
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Could not map memory for device registers for %wZ\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
extension->UnMapRegisters = FALSE;
|
||
status = STATUS_NONE_MAPPED;
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
extension->AddressSpace = ConfigData->AddressSpace;
|
||
extension->OriginalController = ConfigData->Controller;
|
||
extension->SpanOfController = ConfigData->SpanOfController;
|
||
|
||
//
|
||
// Save off the interface type and the bus number.
|
||
//
|
||
|
||
extension->InterfaceType = ConfigData->InterfaceType;
|
||
extension->BusNumber = ConfigData->BusNumber;
|
||
|
||
//
|
||
// We now try to claim the ports used by this device.
|
||
//
|
||
|
||
ParReportResourcesDevice(
|
||
extension,
|
||
FALSE,
|
||
&conflict
|
||
);
|
||
|
||
if (conflict) {
|
||
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
ParLogError(
|
||
deviceObject->DriverObject,
|
||
deviceObject,
|
||
ConfigData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
5,
|
||
STATUS_SUCCESS,
|
||
PAR_ADDRESS_CONFLICT
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Could not claim the device registers for %wZ\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
goto ExtensionCleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// If it was requested that the port be disabled, now is the
|
||
// time to do it.
|
||
//
|
||
|
||
if (ConfigData->DisablePort) {
|
||
|
||
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
ParLogError(
|
||
deviceObject->DriverObject,
|
||
deviceObject,
|
||
ConfigData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
40,
|
||
STATUS_SUCCESS,
|
||
PAR_DISABLED_PORT
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Port %wZ disabled as requested\n",
|
||
&ConfigData->NtNameForPort)
|
||
);
|
||
goto ExtensionCleanup;
|
||
}
|
||
|
||
//
|
||
// The call will set up the naming necessary for
|
||
// external applications to get to the driver. It
|
||
// will also set up the device map.
|
||
//
|
||
|
||
extension->ObjectDirectory = ConfigData->ObjectDirectory;
|
||
extension->NtNameForPort = ConfigData->NtNameForPort;
|
||
extension->SymbolicLinkName = ConfigData->SymbolicLinkName;
|
||
ParSetupExternalNaming(extension);
|
||
|
||
extension->Initialized = FALSE;
|
||
extension->TimerStart = PAR_WRITE_TIMEOUT_VALUE;
|
||
InitializeListHead(&extension->WorkQueue);
|
||
|
||
extension->AbsoluteOneSecond.QuadPart = 10*1000*1000;
|
||
extension->OneSecond.QuadPart = -(10*1000*1000);
|
||
|
||
KeInitializeSemaphore(
|
||
&extension->RequestSemaphore,
|
||
0L,
|
||
MAXLONG
|
||
);
|
||
|
||
//
|
||
// Common error path cleanup. If the status is
|
||
// bad, get rid of the device extension, device object
|
||
// and any memory associated with it.
|
||
//
|
||
|
||
ExtensionCleanup: ;
|
||
|
||
ExFreePool(ConfigData);
|
||
|
||
if (NT_ERROR(status)) {
|
||
|
||
if (extension) {
|
||
|
||
ParCleanupDevice(extension);
|
||
IoDeleteDevice(deviceObject);
|
||
IoGetConfigurationInformation()->ParallelCount--;
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ParItemCallBack(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to check if a particular item
|
||
is present in the registry.
|
||
|
||
Arguments:
|
||
|
||
Context - Pointer to a boolean.
|
||
|
||
PathName - unicode registry path. Not Used.
|
||
|
||
BusType - Internal, Isa, ...
|
||
|
||
BusNumber - Which bus if we are on a multibus system.
|
||
|
||
BusInformation - Configuration information about the bus. Not Used.
|
||
|
||
ControllerType - Controller type.
|
||
|
||
ControllerNumber - Which controller if there is more than one
|
||
controller in the system.
|
||
|
||
ControllerInformation - Array of pointers to the three pieces of
|
||
registry information.
|
||
|
||
PeripheralType - Should be a peripheral.
|
||
|
||
PeripheralNumber - Which peripheral - not used..
|
||
|
||
PeripheralInformation - Configuration information. Not Used.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
*((BOOLEAN *)Context) = TRUE;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// This structure is only used to communicate between the
|
||
// code that queries what the firmware found and the code
|
||
// that is calling the quering of the firmware data.
|
||
//
|
||
typedef struct PARALLEL_FIRMWARE_DATA {
|
||
PDRIVER_OBJECT DriverObject;
|
||
ULONG ControllersFound;
|
||
UNICODE_STRING Directory;
|
||
UNICODE_STRING NtNameSuffix;
|
||
UNICODE_STRING DirectorySymbolicName;
|
||
LIST_ENTRY ConfigList;
|
||
} PARALLEL_FIRMWARE_DATA,*PPARALLEL_FIRMWARE_DATA;
|
||
|
||
|
||
NTSTATUS
|
||
ParConfigCallBack(
|
||
IN PVOID Context,
|
||
IN PUNICODE_STRING PathName,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
||
IN CONFIGURATION_TYPE ControllerType,
|
||
IN ULONG ControllerNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
||
IN CONFIGURATION_TYPE PeripheralType,
|
||
IN ULONG PeripheralNumber,
|
||
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to acquire all of the configuration
|
||
information for each parallel controller found by the firmware
|
||
|
||
Arguments:
|
||
|
||
Context - Pointer to the list head of the list of configuration
|
||
records that we are building up.
|
||
|
||
PathName - unicode registry path. Not Used.
|
||
|
||
BusType - Internal, Isa, ...
|
||
|
||
BusNumber - Which bus if we are on a multibus system.
|
||
|
||
BusInformation - Configuration information about the bus. Not Used.
|
||
|
||
ControllerType - Should always be ParallelController.
|
||
|
||
ControllerNumber - Which controller if there is more than one
|
||
controller in the system.
|
||
|
||
ControllerInformation - Array of pointers to the three pieces of
|
||
registry information.
|
||
|
||
PeripheralType - Undefined for this call.
|
||
|
||
PeripheralNumber - Undefined for this call.
|
||
|
||
PeripheralInformation - Undefined for this call.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
|
||
if all of the resource information couldn't be acquired.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// So we don't have to typecast the context.
|
||
//
|
||
PPARALLEL_FIRMWARE_DATA config = Context;
|
||
|
||
//
|
||
// Pointer to the configuration stuff for this controller.
|
||
//
|
||
PCONFIG_DATA controller;
|
||
|
||
//
|
||
// Two booleans to help us determine that we got enough configuration
|
||
// data.
|
||
//
|
||
BOOLEAN foundPort = FALSE;
|
||
BOOLEAN foundInterrupt = FALSE;
|
||
|
||
//
|
||
// Simple iteration variable.
|
||
//
|
||
ULONG i;
|
||
|
||
//
|
||
// Pointer to the configuration "data" portion of the configuration
|
||
// structures in the registry for this device.
|
||
//
|
||
PCM_FULL_RESOURCE_DESCRIPTOR controllerData;
|
||
|
||
ASSERT(ControllerType == ParallelController);
|
||
|
||
config->ControllersFound++;
|
||
|
||
//
|
||
// Bail if some fool wrote a loader.
|
||
//
|
||
|
||
if (!ControllerInformation[IoQueryDeviceConfigurationData]->DataLength) {
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
controllerData =
|
||
(PCM_FULL_RESOURCE_DESCRIPTOR)
|
||
(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
|
||
ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
|
||
//
|
||
// Allocate the memory for the controller config data out of paged pool
|
||
// since we will only be accessing it at initialization time.
|
||
//
|
||
|
||
controller = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(CONFIG_DATA)
|
||
);
|
||
|
||
if (!controller) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
7,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for the configuration data\n"
|
||
"-------- for firmware data\n")
|
||
);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
controller,
|
||
sizeof(CONFIG_DATA)
|
||
);
|
||
InitializeListHead(&controller->ConfigList);
|
||
|
||
controller->InterfaceType = BusType;
|
||
controller->BusNumber = BusNumber;
|
||
|
||
//
|
||
// We need to get the following information out of the partial
|
||
// resource descriptors.
|
||
//
|
||
// The irql and vector.
|
||
//
|
||
// The base address and span covered by the parallel controllers
|
||
// registers.
|
||
//
|
||
// It is not defined how these appear in the partial resource
|
||
// lists, so we will just loop over all of them. If we find
|
||
// something we don't recognize, we drop that information on
|
||
// the floor. When we have finished going through all the
|
||
// partial information, we validate that we got the above
|
||
// two.
|
||
//
|
||
|
||
for (
|
||
i = 0;
|
||
i < controllerData->PartialResourceList.Count;
|
||
i++
|
||
) {
|
||
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
|
||
&controllerData->PartialResourceList.PartialDescriptors[i];
|
||
|
||
switch (partial->Type) {
|
||
|
||
case CmResourceTypePort: {
|
||
|
||
foundPort = TRUE;
|
||
|
||
//
|
||
// No matter what the registry says, we
|
||
// know how long the register set is.
|
||
//
|
||
|
||
controller->SpanOfController = PARALLEL_REGISTER_SPAN;
|
||
controller->Controller = partial->u.Port.Start;
|
||
controller->AddressSpace = partial->Flags;
|
||
|
||
break;
|
||
}
|
||
case CmResourceTypeInterrupt: {
|
||
|
||
foundInterrupt = TRUE;
|
||
if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
|
||
|
||
controller->InterruptMode = Latched;
|
||
|
||
} else {
|
||
|
||
controller->InterruptMode = LevelSensitive;
|
||
|
||
}
|
||
|
||
controller->OriginalIrql = partial->u.Interrupt.Level;
|
||
controller->OriginalVector = partial->u.Interrupt.Vector;
|
||
|
||
break;
|
||
|
||
}
|
||
default: {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (foundPort && foundInterrupt) {
|
||
|
||
//
|
||
// The following are so the we can form the
|
||
// name following the \Device
|
||
// and the default name that will be symbolic
|
||
// linked to the device and the object directory
|
||
// that link will go in.
|
||
//
|
||
|
||
WCHAR ntNumberBuffer[100];
|
||
WCHAR symbolicNumberBuffer[100];
|
||
UNICODE_STRING ntNumberString;
|
||
UNICODE_STRING symbolicNumberString;
|
||
|
||
ntNumberString.Length = 0;
|
||
ntNumberString.MaximumLength = 100;
|
||
ntNumberString.Buffer = &ntNumberBuffer[0];
|
||
|
||
symbolicNumberString.Length = 0;
|
||
symbolicNumberString.MaximumLength = 100;
|
||
symbolicNumberString.Buffer = &symbolicNumberBuffer[0];
|
||
|
||
//
|
||
// Everthing is great so far. We now need to form the
|
||
// Nt Names and symbolic link names.
|
||
//
|
||
|
||
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
|
||
config->ControllersFound - 1,
|
||
10,
|
||
&ntNumberString
|
||
))) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
8,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't convert NT controller number to\n"
|
||
"-------- to unicode for firmware data: %d\n",
|
||
config->ControllersFound - 1)
|
||
);
|
||
//
|
||
// Oh well, ignore this controller.
|
||
//
|
||
ExFreePool(controller);
|
||
|
||
} else {
|
||
|
||
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
|
||
config->ControllersFound,
|
||
10,
|
||
&symbolicNumberString
|
||
))) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
9,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't convert symbolic controller number to\n"
|
||
"-------- to unicode for firmware data: %d\n",
|
||
config->ControllersFound)
|
||
);
|
||
ExFreePool(controller);
|
||
|
||
} else {
|
||
|
||
UNICODE_STRING Temp;
|
||
|
||
//
|
||
// Ok, we have the non-constant portions of the
|
||
// names all figured out. Now allocate memory
|
||
// for what will be used later.
|
||
//
|
||
|
||
//
|
||
// Save off a copy of the object directory name.
|
||
//
|
||
|
||
//
|
||
// Init the destination.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&controller->ObjectDirectory,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// This will get its length.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&Temp,
|
||
DEFAULT_DIRECTORY
|
||
);
|
||
|
||
|
||
//
|
||
// Now allocate that much.
|
||
//
|
||
|
||
controller->ObjectDirectory.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
Temp.Length+sizeof(WCHAR)
|
||
);
|
||
|
||
if (!controller->ObjectDirectory.Buffer) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
10,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for object\n"
|
||
"-------- directory for NT firmware data: %d\n",
|
||
config->ControllersFound - 1)
|
||
);
|
||
ExFreePool(controller);
|
||
return STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
controller->ObjectDirectory.MaximumLength =
|
||
Temp.Length+sizeof(WCHAR);
|
||
|
||
//
|
||
// Zero fill it.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
controller->ObjectDirectory.Buffer,
|
||
controller->ObjectDirectory.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&controller->ObjectDirectory,
|
||
&Temp
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Init the destination.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&controller->NtNameForPort,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// This will get its length.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&Temp,
|
||
DEFAULT_NT_SUFFIX
|
||
);
|
||
|
||
//
|
||
// Allocate enough for the suffix and the number.
|
||
//
|
||
|
||
controller->NtNameForPort.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
Temp.Length +
|
||
ntNumberString.Length + sizeof(WCHAR)
|
||
);
|
||
|
||
if (!controller->NtNameForPort.Buffer) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
11,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for NT\n"
|
||
"-------- name for NT firmware data: %d\n",
|
||
config->ControllersFound - 1)
|
||
);
|
||
ExFreePool(controller->ObjectDirectory.Buffer);
|
||
ExFreePool(controller);
|
||
return STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
controller->NtNameForPort.MaximumLength =
|
||
Temp.Length+ntNumberString.Length+sizeof(WCHAR);
|
||
|
||
RtlZeroMemory(
|
||
controller->NtNameForPort.Buffer,
|
||
controller->NtNameForPort.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&controller->NtNameForPort,
|
||
&Temp
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&controller->NtNameForPort,
|
||
&ntNumberString
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Now form that name that will be used as a
|
||
// symbolic link to the actual device name
|
||
// we just formed.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&controller->SymbolicLinkName,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// This will get its length.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&Temp,
|
||
DEFAULT_PARALLEL_NAME
|
||
);
|
||
|
||
//
|
||
// Allocate enough for the suffix and the number.
|
||
//
|
||
|
||
controller->SymbolicLinkName.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
Temp.Length +
|
||
symbolicNumberString.Length+sizeof(WCHAR)
|
||
);
|
||
|
||
if (!controller->SymbolicLinkName.Buffer) {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
12,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for symbolic\n"
|
||
"-------- name for NT firmware data: %d\n",
|
||
config->ControllersFound - 1)
|
||
);
|
||
ExFreePool(controller->ObjectDirectory.Buffer);
|
||
ExFreePool(controller->NtNameForPort.Buffer);
|
||
ExFreePool(controller);
|
||
return STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
controller->SymbolicLinkName.MaximumLength =
|
||
Temp.Length+symbolicNumberString.Length+sizeof(WCHAR);
|
||
|
||
RtlZeroMemory(
|
||
controller->SymbolicLinkName.Buffer,
|
||
controller->SymbolicLinkName.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&controller->SymbolicLinkName,
|
||
&Temp
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&controller->SymbolicLinkName,
|
||
&symbolicNumberString
|
||
);
|
||
|
||
}
|
||
|
||
InsertTailList(
|
||
&config->ConfigList,
|
||
&controller->ConfigList
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
ParLogError(
|
||
config->DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
13,
|
||
STATUS_SUCCESS,
|
||
PAR_NOT_ENOUGH_CONFIG_INFO
|
||
);
|
||
ExFreePool(controller);
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
ParGetConfigInfo(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath,
|
||
OUT PLIST_ENTRY ConfigList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will "return" a list of configuration
|
||
records for the parallel ports to initialize.
|
||
|
||
It will first query the firmware data. It will then
|
||
look for "user" specified parallel ports in the registry.
|
||
It will place the user specified parallel ports in the
|
||
the passed in list.
|
||
|
||
After it finds all of the user specified ports, it will
|
||
attempt to add the firmware parallel ports into the passed
|
||
in lists. The insert in the list code detects conflicts
|
||
and rejects a new port. In this way we can prevent
|
||
firmware found ports from overiding information
|
||
specified by the "user". Note, this means if the user
|
||
specified data is incorrect in its use of the interrupt
|
||
(which should *always* be correct from the firmware)
|
||
that port likely will not work. But, then, we "trust"
|
||
the user.
|
||
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Not used.
|
||
|
||
RegistryPath - Path to this drivers service node in
|
||
the current control set.
|
||
|
||
ConfigList - Listhead (which will be intialized) for a list
|
||
of configuration records for ports to control.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// A structure that we pass to the firmware query routine
|
||
// as "context". This context will contain the number of
|
||
// ports already found as well as default names and the
|
||
// listhead of the configuration list.
|
||
//
|
||
PARALLEL_FIRMWARE_DATA firmware;
|
||
|
||
//
|
||
// This will point to the structure that is used by RtlQueryRegistryValues
|
||
// to "direct" its search and retrieval of values.
|
||
//
|
||
PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
|
||
|
||
//
|
||
// We'll have to query the registry to determine what kind of
|
||
// bus the system is using. Then when the user specifies the
|
||
// address of a port, the user doesn't have to tell us the
|
||
// the bus type (unless they really want to). When we determine
|
||
// the default bus on the system, we'll know whether the interrupt
|
||
// is latched or level sensitive.
|
||
//
|
||
INTERFACE_TYPE interfaceType;
|
||
ULONG defaultInterfaceType;
|
||
|
||
//
|
||
// Default values for user data.
|
||
//
|
||
ULONG maxUlong = MAXULONG;
|
||
ULONG zero = 0;
|
||
ULONG defaultInterruptMode;
|
||
ULONG defaultAddressSpace = CM_RESOURCE_PORT_IO;
|
||
|
||
//
|
||
// Where user data from the registry will be placed.
|
||
//
|
||
PHYSICAL_ADDRESS userPort;
|
||
ULONG userVector;
|
||
ULONG userLevel;
|
||
ULONG userBusNumber;
|
||
ULONG userInterfaceType;
|
||
ULONG userAddressSpace;
|
||
ULONG userInterruptMode;
|
||
ULONG disablePort;
|
||
UNICODE_STRING userSymbolicLink;
|
||
|
||
UNICODE_STRING parametersPath;
|
||
OBJECT_ATTRIBUTES parametersAttributes;
|
||
HANDLE parametersKey;
|
||
PKEY_BASIC_INFORMATION userSubKey = NULL;
|
||
ULONG i;
|
||
|
||
InitializeListHead(ConfigList);
|
||
|
||
RtlZeroMemory(
|
||
&firmware,
|
||
sizeof(PARALLEL_FIRMWARE_DATA)
|
||
);
|
||
|
||
firmware.DriverObject = DriverObject;
|
||
|
||
//
|
||
// Initialize the controllers found so far with the
|
||
// values in configuration database that the io system
|
||
// maintains
|
||
//
|
||
|
||
firmware.ControllersFound = IoGetConfigurationInformation()->ParallelCount;
|
||
InitializeListHead(&firmware.ConfigList);
|
||
RtlInitUnicodeString(
|
||
&firmware.Directory,
|
||
DEFAULT_DIRECTORY
|
||
);
|
||
RtlInitUnicodeString(
|
||
&firmware.NtNameSuffix,
|
||
DEFAULT_NT_SUFFIX
|
||
);
|
||
RtlInitUnicodeString(
|
||
&firmware.DirectorySymbolicName,
|
||
DEFAULT_PARALLEL_NAME
|
||
);
|
||
|
||
//
|
||
// First we query the hardware registry for all of
|
||
// the firmware defined ports. We loop over all of
|
||
// the busses.
|
||
//
|
||
|
||
for (
|
||
interfaceType = 0;
|
||
interfaceType < MaximumInterfaceType;
|
||
interfaceType++
|
||
) {
|
||
|
||
CONFIGURATION_TYPE sc = ParallelController;
|
||
|
||
IoQueryDeviceDescription(
|
||
&interfaceType,
|
||
NULL,
|
||
&sc,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
ParConfigCallBack,
|
||
&firmware
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Query the registry one more time. This time we
|
||
// look for the first bus on the system (that isn't
|
||
// the internal bus - we assume that the firmware
|
||
// code knows about those ports). We will use that
|
||
// as the default bus if no bustype or bus number
|
||
// is specified in the "user" configuration records.
|
||
//
|
||
|
||
defaultInterfaceType = (ULONG)Isa;
|
||
defaultInterruptMode = CM_RESOURCE_INTERRUPT_LATCHED;
|
||
|
||
for (
|
||
interfaceType = 0;
|
||
interfaceType < MaximumInterfaceType;
|
||
interfaceType++
|
||
) {
|
||
|
||
ULONG busZero = 0;
|
||
BOOLEAN foundOne = FALSE;
|
||
|
||
if (interfaceType != Internal) {
|
||
|
||
IoQueryDeviceDescription(
|
||
&interfaceType,
|
||
&busZero,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
ParItemCallBack,
|
||
&foundOne
|
||
);
|
||
|
||
if (foundOne) {
|
||
|
||
defaultInterfaceType = (ULONG)interfaceType;
|
||
if (defaultInterfaceType == MicroChannel) {
|
||
|
||
defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Gonna get the user data now. Allocate the
|
||
// structures that we will be using throughout
|
||
// the search for user data. We will deallocate
|
||
// them before we leave this routine.
|
||
//
|
||
|
||
userSymbolicLink.Buffer = NULL;
|
||
parametersPath.Buffer = NULL;
|
||
|
||
//
|
||
// Allocate the rtl query table.
|
||
//
|
||
|
||
parameters = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(RTL_QUERY_REGISTRY_TABLE)*15
|
||
);
|
||
|
||
if (!parameters) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
14,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate table for rtl query\n"
|
||
"-------- to parameters for %wZ",
|
||
RegistryPath)
|
||
);
|
||
|
||
goto DoFirmwareAdd;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
parameters,
|
||
sizeof(RTL_QUERY_REGISTRY_TABLE)*15
|
||
);
|
||
|
||
//
|
||
// Allocate the place where the users symbolic link name
|
||
// for the port will go.
|
||
//
|
||
|
||
//
|
||
// We will initially allocate space for 257 wchars.
|
||
// we will then set the maximum size to 256
|
||
// This way the rtl routine could return a 256
|
||
// WCHAR wide string with no null terminator.
|
||
// We'll remember that the buffer is one WCHAR
|
||
// longer then it says it is so that we can always
|
||
// have a NULL terminator at the end.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&userSymbolicLink,
|
||
NULL
|
||
);
|
||
userSymbolicLink.MaximumLength = sizeof(WCHAR)*256;
|
||
userSymbolicLink.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(WCHAR)*257
|
||
);
|
||
|
||
if (!userSymbolicLink.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
15,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate buffer for the symbolic link\n"
|
||
"-------- for parameters items in %wZ",
|
||
RegistryPath)
|
||
);
|
||
|
||
goto DoFirmwareAdd;
|
||
|
||
}
|
||
|
||
//
|
||
// Form a path to our drivers Parameters subkey.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
¶metersPath,
|
||
NULL
|
||
);
|
||
|
||
parametersPath.MaximumLength = RegistryPath->Length +
|
||
sizeof(L"\\") +
|
||
sizeof(L"Parameters");
|
||
|
||
parametersPath.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
parametersPath.MaximumLength
|
||
);
|
||
|
||
if (!parametersPath.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
16,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate string for path\n"
|
||
"-------- to parameters for %wZ",
|
||
RegistryPath)
|
||
);
|
||
|
||
goto DoFirmwareAdd;
|
||
|
||
}
|
||
|
||
//
|
||
// Form the parameters path.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
parametersPath.Buffer,
|
||
parametersPath.MaximumLength
|
||
);
|
||
RtlAppendUnicodeStringToString(
|
||
¶metersPath,
|
||
RegistryPath
|
||
);
|
||
RtlAppendUnicodeToString(
|
||
¶metersPath,
|
||
L"\\"
|
||
);
|
||
RtlAppendUnicodeToString(
|
||
¶metersPath,
|
||
L"Parameters"
|
||
);
|
||
|
||
userSubKey = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*256)
|
||
);
|
||
|
||
if (!userSubKey) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
17,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory basic information\n"
|
||
"-------- structure to enumerate subkeys for %wZ",
|
||
¶metersPath)
|
||
);
|
||
|
||
goto DoFirmwareAdd;
|
||
|
||
}
|
||
|
||
//
|
||
// Open the key given by our registry path & Parameters.
|
||
//
|
||
// Note: The reason we are opening up the key by hand, and
|
||
// then enumerating all of the subkeys is so we don't have
|
||
// to architect what the names of the devices have to be and
|
||
// how many of them there could be. We just try to get
|
||
// as many as there are.
|
||
//
|
||
|
||
InitializeObjectAttributes(
|
||
¶metersAttributes,
|
||
¶metersPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (!NT_SUCCESS(ZwOpenKey(
|
||
¶metersKey,
|
||
MAXIMUM_ALLOWED,
|
||
¶metersAttributes
|
||
))) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
18,
|
||
STATUS_SUCCESS,
|
||
PAR_NO_PARAMETERS_INFO
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't open the drivers Parameters key %wZ\n",
|
||
RegistryPath)
|
||
);
|
||
goto DoFirmwareAdd;
|
||
|
||
}
|
||
|
||
//
|
||
// Gather all of the "user specified" information from
|
||
// the registry.
|
||
//
|
||
|
||
parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
||
|
||
parameters[1].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
||
RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[1].Name = L"PortAddress";
|
||
parameters[1].EntryContext = &userPort.LowPart;
|
||
|
||
parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[2].Name = L"Interrupt";
|
||
parameters[2].EntryContext = &userVector;
|
||
parameters[2].DefaultType = REG_DWORD;
|
||
parameters[2].DefaultData = &maxUlong;
|
||
parameters[2].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[3].Flags = RTL_QUERY_REGISTRY_REQUIRED |
|
||
RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[3].Name = firmware.Directory.Buffer;
|
||
parameters[3].EntryContext = &userSymbolicLink;
|
||
|
||
parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[4].Name = L"BusNumber";
|
||
parameters[4].EntryContext = &userBusNumber;
|
||
parameters[4].DefaultType = REG_DWORD;
|
||
parameters[4].DefaultData = &zero;
|
||
parameters[4].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[5].Name = L"BusType";
|
||
parameters[5].EntryContext = &userInterfaceType;
|
||
parameters[5].DefaultType = REG_DWORD;
|
||
parameters[5].DefaultData = &defaultInterfaceType;
|
||
parameters[5].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[6].Name = L"InterruptMode";
|
||
parameters[6].EntryContext = &userInterruptMode;
|
||
parameters[6].DefaultType = REG_DWORD;
|
||
parameters[6].DefaultData = &defaultInterruptMode;
|
||
parameters[6].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[7].Name = L"AddressSpace";
|
||
parameters[7].EntryContext = &userAddressSpace;
|
||
parameters[7].DefaultType = REG_DWORD;
|
||
parameters[7].DefaultData = &defaultAddressSpace;
|
||
parameters[7].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[8].Name = L"InterruptLevel";
|
||
parameters[8].EntryContext = &userLevel;
|
||
parameters[8].DefaultType = REG_DWORD;
|
||
parameters[8].DefaultData = &zero;
|
||
parameters[8].DefaultLength = sizeof(ULONG);
|
||
|
||
parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parameters[9].Name = L"DisablePort";
|
||
parameters[9].EntryContext = &disablePort;
|
||
parameters[9].DefaultType = REG_DWORD;
|
||
parameters[9].DefaultData = &zero;
|
||
parameters[9].DefaultLength = sizeof(ULONG);
|
||
|
||
i = 0;
|
||
while (TRUE) {
|
||
|
||
NTSTATUS status;
|
||
ULONG actuallyReturned;
|
||
|
||
//
|
||
// We lie about the length of the buffer, so that we can
|
||
// MAKE SURE that the name it returns can be padded with
|
||
// a NULL.
|
||
//
|
||
|
||
status = ZwEnumerateKey(
|
||
parametersKey,
|
||
i,
|
||
KeyBasicInformation,
|
||
userSubKey,
|
||
sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*255),
|
||
&actuallyReturned
|
||
);
|
||
|
||
if (status == STATUS_NO_MORE_ENTRIES) {
|
||
|
||
break;
|
||
}
|
||
|
||
if (status == STATUS_BUFFER_OVERFLOW) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
19,
|
||
STATUS_SUCCESS,
|
||
PAR_UNABLE_TO_ACCESS_CONFIG
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Overflowed the enumerate buffer\n"
|
||
"-------- for subkey #%d of %wZ\n",
|
||
i,parametersPath)
|
||
);
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
20,
|
||
status,
|
||
PAR_UNABLE_TO_ACCESS_CONFIG
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Bad status returned: %x \n"
|
||
"-------- on enumeration for subkey # %d of %wZ\n",
|
||
status,i,parametersPath)
|
||
);
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// Pad the name returned with a null.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
((PUCHAR)(&userSubKey->Name[0]))+userSubKey->NameLength,
|
||
sizeof(WCHAR)
|
||
);
|
||
|
||
parameters[0].Name = &userSubKey->Name[0];
|
||
|
||
//
|
||
// Make sure that the physical addresses start
|
||
// out clean.
|
||
//
|
||
RtlZeroMemory(
|
||
&userPort,
|
||
sizeof(userPort)
|
||
);
|
||
|
||
status = RtlQueryRegistryValues(
|
||
RTL_REGISTRY_ABSOLUTE,
|
||
parametersPath.Buffer,
|
||
parameters,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
PCONFIG_DATA newConfig;
|
||
|
||
//
|
||
// Well! Some supposedly valid information was found!
|
||
//
|
||
// We'll see about that.
|
||
//
|
||
// We don't want to cause the hal to have a bad day,
|
||
// so let's check the interface type and bus number.
|
||
//
|
||
// We only need to check the registry if they aren't
|
||
// equal to the defaults.
|
||
//
|
||
|
||
if ((userBusNumber != 0) ||
|
||
(userInterfaceType != defaultInterfaceType)) {
|
||
|
||
BOOLEAN foundIt = FALSE;
|
||
if (userInterfaceType >= MaximumInterfaceType) {
|
||
|
||
//
|
||
// Ehhhh! Lose Game.
|
||
//
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
21,
|
||
STATUS_SUCCESS,
|
||
PAR_UNKNOWN_BUS
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Invalid Bus type %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
IoQueryDeviceDescription(
|
||
(INTERFACE_TYPE *)&userInterfaceType,
|
||
&userBusNumber,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
ParItemCallBack,
|
||
&foundIt
|
||
);
|
||
|
||
if (!foundIt) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
22,
|
||
STATUS_SUCCESS,
|
||
PAR_BUS_NOT_PRESENT
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: There aren't that many of those\n"
|
||
"-------- busses on this system,%ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ((userInterfaceType == MicroChannel) &&
|
||
(userInterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
23,
|
||
STATUS_SUCCESS,
|
||
PAR_BUS_INTERRUPT_CONFLICT
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Latched interrupts and MicroChannel\n"
|
||
"-------- busses don't mix,%ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// Well ok, I guess we can take the data.
|
||
// There be other tests later on to make
|
||
// sure it doesn't have any other kinds
|
||
// of conflicts.
|
||
//
|
||
|
||
//
|
||
// Allocate the config record.
|
||
//
|
||
|
||
newConfig = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(CONFIG_DATA)
|
||
);
|
||
|
||
if (!newConfig) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
24,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for the\n"
|
||
"-------- user configuration record\n"
|
||
"-------- for %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
|
||
i++;
|
||
continue;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
newConfig,
|
||
sizeof(CONFIG_DATA)
|
||
);
|
||
|
||
//
|
||
// Save off a copy of the object directory name.
|
||
//
|
||
|
||
//
|
||
// Init the destination.
|
||
//
|
||
RtlInitUnicodeString(
|
||
&newConfig->ObjectDirectory,
|
||
DEFAULT_DIRECTORY
|
||
);
|
||
newConfig->ObjectDirectory.MaximumLength += sizeof(WCHAR);
|
||
|
||
//
|
||
// Now allocate that much.
|
||
//
|
||
|
||
newConfig->ObjectDirectory.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
newConfig->ObjectDirectory.MaximumLength
|
||
);
|
||
|
||
if (!newConfig->ObjectDirectory.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
25,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for object\n"
|
||
"-------- directory for NT user data for: %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
ExFreePool(newConfig);
|
||
i++;
|
||
continue;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Zero fill it.
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
newConfig->ObjectDirectory.Buffer,
|
||
newConfig->ObjectDirectory.MaximumLength
|
||
);
|
||
|
||
newConfig->ObjectDirectory.Length = 0;
|
||
RtlAppendUnicodeToString(
|
||
&newConfig->ObjectDirectory,
|
||
DEFAULT_DIRECTORY
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Init the destination.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&newConfig->NtNameForPort,
|
||
&userSubKey->Name[0]
|
||
);
|
||
|
||
//
|
||
// Allocate the space for the name.
|
||
//
|
||
|
||
newConfig->NtNameForPort.Length = 0;
|
||
newConfig->NtNameForPort.MaximumLength += sizeof(WCHAR);
|
||
newConfig->NtNameForPort.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
newConfig->NtNameForPort.MaximumLength
|
||
);
|
||
|
||
if (!newConfig->NtNameForPort.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
26,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for NT\n"
|
||
"-------- name for NT user data name: %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
ExFreePool(newConfig->ObjectDirectory.Buffer);
|
||
ExFreePool(newConfig);
|
||
i++;
|
||
continue;
|
||
|
||
} else {
|
||
|
||
RtlZeroMemory(
|
||
newConfig->NtNameForPort.Buffer,
|
||
newConfig->NtNameForPort.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&newConfig->NtNameForPort,
|
||
&userSubKey->Name[0]
|
||
);
|
||
|
||
}
|
||
|
||
newConfig->SymbolicLinkName = userSymbolicLink;
|
||
newConfig->SymbolicLinkName.MaximumLength += sizeof(WCHAR);
|
||
|
||
newConfig->SymbolicLinkName.Buffer =
|
||
ExAllocatePool(
|
||
PagedPool,
|
||
newConfig->SymbolicLinkName.MaximumLength
|
||
);
|
||
|
||
if (!newConfig->SymbolicLinkName.Buffer) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
userPort,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
27,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate memory for symbolic\n"
|
||
"-------- name from user data\n"
|
||
"-------- %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
ExFreePool(newConfig->ObjectDirectory.Buffer);
|
||
ExFreePool(newConfig->NtNameForPort.Buffer);
|
||
ExFreePool(newConfig);
|
||
i++;
|
||
continue;
|
||
|
||
} else {
|
||
|
||
RtlZeroMemory(
|
||
newConfig->SymbolicLinkName.Buffer,
|
||
newConfig->SymbolicLinkName.MaximumLength
|
||
);
|
||
|
||
newConfig->SymbolicLinkName.Length = 0;
|
||
RtlAppendUnicodeStringToString(
|
||
&newConfig->SymbolicLinkName,
|
||
&userSymbolicLink
|
||
);
|
||
|
||
}
|
||
|
||
InitializeListHead(&newConfig->ConfigList);
|
||
newConfig->Controller = userPort;
|
||
newConfig->SpanOfController = PARALLEL_REGISTER_SPAN;
|
||
newConfig->BusNumber = userBusNumber;
|
||
newConfig->AddressSpace = userAddressSpace;
|
||
newConfig->InterruptMode = userInterruptMode;
|
||
newConfig->InterfaceType = userInterfaceType;
|
||
newConfig->OriginalVector = userVector;
|
||
newConfig->DisablePort = disablePort;
|
||
if (!userLevel) {
|
||
newConfig->OriginalIrql = userVector;
|
||
} else {
|
||
newConfig->OriginalIrql = userLevel;
|
||
}
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userPort: %x\n",
|
||
userPort.LowPart)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userBusNumber: %d\n",
|
||
userBusNumber)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userAddressSpace: %d\n",
|
||
userAddressSpace)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userInterruptMode: %d\n",
|
||
userInterruptMode)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userInterfaceType: %d\n",
|
||
userInterfaceType)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userVector: %d\n",
|
||
userVector)
|
||
);
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: 'user registry info - userLevel: %d\n",
|
||
userLevel)
|
||
);
|
||
|
||
if (!ParPutInConfigList(
|
||
DriverObject,
|
||
ConfigList,
|
||
newConfig
|
||
)) {
|
||
|
||
//
|
||
// Dispose of this configuration record.
|
||
//
|
||
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Conflict detected amoungst user data %ws\n",
|
||
parameters[0].Name)
|
||
);
|
||
|
||
ExFreePool(newConfig->ObjectDirectory.Buffer);
|
||
ExFreePool(newConfig->NtNameForPort.Buffer);
|
||
ExFreePool(newConfig->SymbolicLinkName.Buffer);
|
||
ExFreePool(newConfig);
|
||
|
||
}
|
||
|
||
i++;
|
||
|
||
} else {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
ParPhysicalZero,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
28,
|
||
STATUS_SUCCESS,
|
||
PAR_INVALID_USER_CONFIG
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Bad status returned: %x \n"
|
||
"-------- for the value entries of\n"
|
||
"-------- %ws\n",
|
||
status,parameters[0].Name)
|
||
);
|
||
|
||
i++;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
ZwClose(parametersKey);
|
||
|
||
DoFirmwareAdd:;
|
||
|
||
//
|
||
// All done with the user specified information. Now try
|
||
// to add the firmware specified data to the configuration.
|
||
// If a conflict is detected then we simply dispose of that
|
||
// firmware collected data.
|
||
//
|
||
|
||
while (!IsListEmpty(&firmware.ConfigList)) {
|
||
|
||
PLIST_ENTRY head;
|
||
PCONFIG_DATA firmwareData;
|
||
|
||
head = RemoveHeadList(&firmware.ConfigList);
|
||
|
||
firmwareData = CONTAINING_RECORD(
|
||
head,
|
||
CONFIG_DATA,
|
||
ConfigList
|
||
);
|
||
|
||
if (!ParPutInConfigList(
|
||
DriverObject,
|
||
ConfigList,
|
||
firmwareData
|
||
)) {
|
||
|
||
//
|
||
// Dispose of this configuration record.
|
||
//
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
firmwareData->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
29,
|
||
STATUS_SUCCESS,
|
||
PAR_USER_OVERRIDE
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Conflict detected with user data for firmware port %wZ\n"
|
||
"-------- User data will overides firmware data\n",
|
||
&firmwareData->NtNameForPort)
|
||
);
|
||
ExFreePool(firmwareData->ObjectDirectory.Buffer);
|
||
ExFreePool(firmwareData->NtNameForPort.Buffer);
|
||
ExFreePool(firmwareData->SymbolicLinkName.Buffer);
|
||
ExFreePool(firmwareData);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (userSubKey) {
|
||
|
||
ExFreePool(userSubKey);
|
||
|
||
}
|
||
|
||
if (userSymbolicLink.Buffer) {
|
||
|
||
ExFreePool(userSymbolicLink.Buffer);
|
||
|
||
}
|
||
|
||
if (parametersPath.Buffer) {
|
||
|
||
ExFreePool(parametersPath.Buffer);
|
||
|
||
}
|
||
|
||
if (parameters) {
|
||
|
||
ExFreePool(parameters);
|
||
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
ParPutInConfigList(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN OUT PLIST_ENTRY ConfigList,
|
||
IN PCONFIG_DATA New
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a new config record and a config list, this routine
|
||
will perform a check to make sure that the new record doesn't
|
||
conflict with old records.
|
||
|
||
If everything checks out it will insert the new config record
|
||
into the config list.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - The driver we are attempting to get configuration
|
||
information for.
|
||
|
||
ConfigList - Listhead for a list of configuration records for
|
||
ports to control.
|
||
|
||
New = Pointer to new configuration record to add.
|
||
|
||
Return Value:
|
||
|
||
True if the record was added to the config list, false otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PHYSICAL_ADDRESS parPhysicalMax;
|
||
|
||
parPhysicalMax.LowPart = (ULONG)~0;
|
||
parPhysicalMax.HighPart = ~0;
|
||
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: Attempting to add %wZ\n"
|
||
"-------- to the config list\n"
|
||
"-------- PortAddress is %x\n"
|
||
"-------- BusNumber is %d\n"
|
||
"-------- BusType is %d\n"
|
||
"-------- AddressSpace is %d\n",
|
||
&New->NtNameForPort,
|
||
New->Controller.LowPart,
|
||
New->BusNumber,
|
||
New->InterfaceType,
|
||
New->AddressSpace
|
||
)
|
||
);
|
||
|
||
//
|
||
// We don't support any boards whose memory wraps around
|
||
// the physical address space.
|
||
//
|
||
|
||
if (ParMemCompare(
|
||
New->Controller,
|
||
New->SpanOfController,
|
||
parPhysicalMax,
|
||
(ULONG)0
|
||
) != AddressesAreDisjoint) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
New->Controller,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
30,
|
||
STATUS_SUCCESS,
|
||
PAR_DEVICE_TOO_HIGH
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Error in config record for %wZ\n"
|
||
"-------- registers rap around physical memory\n",
|
||
&New->NtNameForPort)
|
||
);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
//
|
||
// Go through the list looking for previous devices
|
||
// with the same address.
|
||
//
|
||
|
||
if (!IsListEmpty(ConfigList)) {
|
||
|
||
PLIST_ENTRY CurrentConfigListEntry = ConfigList->Flink;
|
||
|
||
do {
|
||
|
||
PCONFIG_DATA OldConfig = CONTAINING_RECORD(
|
||
CurrentConfigListEntry,
|
||
CONFIG_DATA,
|
||
ConfigList
|
||
);
|
||
|
||
//
|
||
// We only care about ports that are on the same bus.
|
||
//
|
||
|
||
if ((OldConfig->InterfaceType == New->InterfaceType) &&
|
||
(OldConfig->BusNumber == New->BusNumber)) {
|
||
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: Comparing it to %wZ\n"
|
||
"-------- already in the config list\n"
|
||
"-------- PortAddress is %x\n"
|
||
"-------- BusNumber is %d\n"
|
||
"-------- BusType is %d\n"
|
||
"-------- AddressSpace is %d\n",
|
||
&OldConfig->NtNameForPort,
|
||
OldConfig->Controller.LowPart,
|
||
OldConfig->BusNumber,
|
||
OldConfig->InterfaceType,
|
||
OldConfig->AddressSpace
|
||
)
|
||
);
|
||
|
||
if (ParMemCompare(
|
||
New->Controller,
|
||
New->SpanOfController,
|
||
OldConfig->Controller,
|
||
OldConfig->SpanOfController
|
||
) != AddressesAreDisjoint) {
|
||
|
||
ParLogError(
|
||
DriverObject,
|
||
NULL,
|
||
New->Controller,
|
||
OldConfig->Controller,
|
||
0,
|
||
0,
|
||
0,
|
||
31,
|
||
STATUS_SUCCESS,
|
||
PAR_CONTROL_OVERLAP
|
||
);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
CurrentConfigListEntry = CurrentConfigListEntry->Flink;
|
||
|
||
} while (CurrentConfigListEntry != ConfigList);
|
||
|
||
}
|
||
|
||
InsertTailList(
|
||
ConfigList,
|
||
&New->ConfigList
|
||
);
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
PVOID
|
||
ParGetMappedAddress(
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
PHYSICAL_ADDRESS IoAddress,
|
||
ULONG NumberOfBytes,
|
||
ULONG AddressSpace,
|
||
PBOOLEAN MappedAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine maps an IO address to system address space.
|
||
|
||
Arguments:
|
||
|
||
BusType - what type of bus - eisa, mca, isa
|
||
IoBusNumber - which IO bus (for machines with multiple buses).
|
||
IoAddress - base device address to be mapped.
|
||
NumberOfBytes - number of bytes for which address is valid.
|
||
AddressSpace - Denotes whether the address is in io space or memory.
|
||
MappedAddress - indicates whether the address was mapped.
|
||
This only has meaning if the address returned
|
||
is non-null.
|
||
|
||
Return Value:
|
||
|
||
Mapped address
|
||
|
||
--*/
|
||
|
||
{
|
||
PHYSICAL_ADDRESS cardAddress;
|
||
PVOID address;
|
||
|
||
HalTranslateBusAddress(
|
||
BusType,
|
||
BusNumber,
|
||
IoAddress,
|
||
&AddressSpace,
|
||
&cardAddress
|
||
);
|
||
|
||
//
|
||
// Map the device base address into the virtual address space
|
||
// if the address is in memory space.
|
||
//
|
||
|
||
if (!AddressSpace) {
|
||
|
||
address = MmMapIoSpace(
|
||
cardAddress,
|
||
NumberOfBytes,
|
||
FALSE
|
||
);
|
||
|
||
*MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));
|
||
|
||
} else {
|
||
|
||
address = (PVOID)cardAddress.LowPart;
|
||
*MappedAddress = FALSE;
|
||
|
||
}
|
||
|
||
return address;
|
||
|
||
}
|
||
|
||
VOID
|
||
ParSetupExternalNaming(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will be used to create a symbolic link
|
||
to the driver name in the given object directory.
|
||
|
||
It will also create an entry in the device map for
|
||
this device if the symbolic link was created.
|
||
|
||
Arguments:
|
||
|
||
Extension - Pointer to the device extension.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNICODE_STRING fullLinkName;
|
||
|
||
//
|
||
// Form the full symbolic link name we wish to create.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&fullLinkName,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Allocate some pool for the name.
|
||
//
|
||
|
||
fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
|
||
Extension->ObjectDirectory.Length+
|
||
Extension->SymbolicLinkName.Length+
|
||
sizeof(WCHAR);
|
||
|
||
|
||
|
||
fullLinkName.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
fullLinkName.MaximumLength
|
||
);
|
||
|
||
if (!fullLinkName.Buffer) {
|
||
|
||
//
|
||
// Couldn't allocate space for the name. Just go on
|
||
// to the device map stuff.
|
||
//
|
||
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
32,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate space for the symbolic \n"
|
||
"-------- name for creating the link\n"
|
||
"-------- for port %wZ\n",
|
||
&Extension->DeviceName)
|
||
);
|
||
|
||
} else {
|
||
|
||
NTSTATUS status;
|
||
RtlZeroMemory(
|
||
fullLinkName.Buffer,
|
||
fullLinkName.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&fullLinkName,
|
||
L"\\"
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&fullLinkName,
|
||
&Extension->ObjectDirectory
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&fullLinkName,
|
||
L"\\"
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&fullLinkName,
|
||
&Extension->SymbolicLinkName
|
||
);
|
||
|
||
status = IoCreateUnprotectedSymbolicLink(
|
||
&fullLinkName,
|
||
&Extension->DeviceName
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Oh well, couldn't create the symbolic link.
|
||
//
|
||
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't create the symbolic link\n"
|
||
"-------- for port %wZ\n",
|
||
&Extension->DeviceName)
|
||
);
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
33,
|
||
status,
|
||
PAR_NO_SYMLINK_CREATED
|
||
);
|
||
|
||
} else {
|
||
|
||
Extension->CreatedSymbolicLink = TRUE;
|
||
|
||
status = RtlWriteRegistryValue(
|
||
RTL_REGISTRY_DEVICEMAP,
|
||
L"PARALLEL PORTS",
|
||
Extension->NtNameForPort.Buffer,
|
||
REG_SZ,
|
||
Extension->SymbolicLinkName.Buffer,
|
||
Extension->SymbolicLinkName.Length+sizeof(WCHAR)
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Oh well, it didn't work. Just go to cleanup.
|
||
//
|
||
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't create the device map entry\n"
|
||
"-------- for port %wZ\n",
|
||
&Extension->DeviceName)
|
||
);
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
34,
|
||
status,
|
||
PAR_NO_DEVICE_MAP_CREATED
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
ExFreePool(fullLinkName.Buffer);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
PAR_MEM_COMPARES
|
||
ParMemCompare(
|
||
IN PHYSICAL_ADDRESS A,
|
||
IN ULONG SpanOfA,
|
||
IN PHYSICAL_ADDRESS B,
|
||
IN ULONG SpanOfB
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare two phsical address.
|
||
|
||
Arguments:
|
||
|
||
A - One half of the comparison.
|
||
|
||
SpanOfA - In units of bytes, the span of A.
|
||
|
||
B - One half of the comparison.
|
||
|
||
SpanOfB - In units of bytes, the span of B.
|
||
|
||
|
||
Return Value:
|
||
|
||
The result of the comparison.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LARGE_INTEGER a;
|
||
LARGE_INTEGER b;
|
||
|
||
LARGE_INTEGER lower;
|
||
ULONG lowerSpan;
|
||
LARGE_INTEGER higher;
|
||
|
||
a.LowPart = A.LowPart;
|
||
a.HighPart = A.HighPart;
|
||
b.LowPart = B.LowPart;
|
||
b.HighPart = B.HighPart;
|
||
|
||
if (a.QuadPart == b.QuadPart) {
|
||
|
||
return AddressesAreEqual;
|
||
|
||
}
|
||
|
||
if (a.QuadPart > b.QuadPart) {
|
||
|
||
higher = a;
|
||
lower = b;
|
||
lowerSpan = SpanOfB;
|
||
|
||
} else {
|
||
|
||
higher = b;
|
||
lower = a;
|
||
lowerSpan = SpanOfA;
|
||
|
||
}
|
||
|
||
if (higher.QuadPart - lower.QuadPart >= lowerSpan) {
|
||
|
||
return AddressesAreDisjoint;
|
||
|
||
}
|
||
|
||
return AddressesOverlap;
|
||
|
||
}
|
||
|
||
VOID
|
||
ParLogError(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PHYSICAL_ADDRESS P1,
|
||
IN PHYSICAL_ADDRESS P2,
|
||
IN ULONG SequenceNumber,
|
||
IN UCHAR MajorFunctionCode,
|
||
IN UCHAR RetryCount,
|
||
IN ULONG UniqueErrorValue,
|
||
IN NTSTATUS FinalStatus,
|
||
IN NTSTATUS SpecificIOStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates an error log entry, copies the supplied data
|
||
to it, and requests that it be written to the error log file.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - A pointer to the driver object for the device.
|
||
|
||
DeviceObject - A pointer to the device object associated with the
|
||
device that had the error, early in initialization, one may not
|
||
yet exist.
|
||
|
||
P1,P2 - If phyical addresses for the controller ports involved
|
||
with the error are available, put them through as dump data.
|
||
|
||
SequenceNumber - A ulong value that is unique to an IRP over the
|
||
life of the irp in this driver - 0 generally means an error not
|
||
associated with an irp.
|
||
|
||
MajorFunctionCode - If there is an error associated with the irp,
|
||
this is the major function code of that irp.
|
||
|
||
RetryCount - The number of times a particular operation has been
|
||
retried.
|
||
|
||
UniqueErrorValue - A unique long word that identifies the particular
|
||
call to this function.
|
||
|
||
FinalStatus - The final status given to the irp that was associated
|
||
with this error. If this log entry is being made during one of
|
||
the retries this value will be STATUS_SUCCESS.
|
||
|
||
SpecificIOStatus - The IO status for a particular error.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_ERROR_LOG_PACKET errorLogEntry;
|
||
|
||
PVOID objectToUse;
|
||
SHORT dumpToAllocate = 0;
|
||
|
||
if (ARGUMENT_PRESENT(DeviceObject)) {
|
||
|
||
objectToUse = DeviceObject;
|
||
|
||
} else {
|
||
|
||
objectToUse = DriverObject;
|
||
|
||
}
|
||
|
||
if (ParMemCompare(
|
||
P1,
|
||
(ULONG)1,
|
||
ParPhysicalZero,
|
||
(ULONG)1
|
||
) != AddressesAreEqual) {
|
||
|
||
dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
|
||
|
||
}
|
||
|
||
if (ParMemCompare(
|
||
P2,
|
||
(ULONG)1,
|
||
ParPhysicalZero,
|
||
(ULONG)1
|
||
) != AddressesAreEqual) {
|
||
|
||
dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
|
||
|
||
}
|
||
|
||
errorLogEntry = IoAllocateErrorLogEntry(
|
||
objectToUse,
|
||
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + dumpToAllocate)
|
||
);
|
||
|
||
if ( errorLogEntry != NULL ) {
|
||
|
||
errorLogEntry->ErrorCode = SpecificIOStatus;
|
||
errorLogEntry->SequenceNumber = SequenceNumber;
|
||
errorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
||
errorLogEntry->RetryCount = RetryCount;
|
||
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
||
errorLogEntry->FinalStatus = FinalStatus;
|
||
errorLogEntry->DumpDataSize = dumpToAllocate;
|
||
|
||
if (dumpToAllocate) {
|
||
|
||
RtlCopyMemory(
|
||
&errorLogEntry->DumpData[0],
|
||
&P1,
|
||
sizeof(PHYSICAL_ADDRESS)
|
||
);
|
||
|
||
if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
|
||
|
||
RtlCopyMemory(
|
||
((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS),
|
||
&P2,
|
||
sizeof(PHYSICAL_ADDRESS)
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
ParReportResourcesDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension,
|
||
IN BOOLEAN ClaimInterrupt,
|
||
OUT BOOLEAN *ConflictDetected
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reports the resources used for a device that
|
||
is "ready" to run. If some conflict was detected, it doesn't
|
||
matter, the reources are reported.
|
||
|
||
Arguments:
|
||
|
||
Extension - The device extension of the device we are reporting
|
||
resources for.
|
||
|
||
ClaimInterrupts - If this was true then we should try to
|
||
claim the interrupt that goes with this
|
||
device
|
||
|
||
ConflictDetected - Pointer to a boolean that we will pass
|
||
to the resource reporting code.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCM_RESOURCE_LIST resourceList;
|
||
ULONG countOfPartials = 1;
|
||
ULONG sizeOfResourceList;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
|
||
UNICODE_STRING className;
|
||
|
||
ParDump(
|
||
PARCONFIG,
|
||
("PARALLEL: In ParReportResourcesDevice\n"
|
||
"-------- for extension %x of port %wZ\n",
|
||
Extension,&Extension->DeviceName)
|
||
);
|
||
|
||
//
|
||
// The resource list for a device will consist of
|
||
//
|
||
// The resource list record itself with a count
|
||
// of one for the single "built in" full resource
|
||
// descriptor.
|
||
//
|
||
// The built-in full resource descriptor will contain
|
||
// the bus type and busnumber and the built in partial
|
||
// resource list.
|
||
//
|
||
// The built in partial resource list will have a count of 1 or 2:
|
||
//
|
||
// 1) The base register physical address and it's span.
|
||
//
|
||
// 2) If the device is using an interrupt then it will
|
||
// report that resource.
|
||
//
|
||
//
|
||
|
||
if (ClaimInterrupt) {
|
||
|
||
countOfPartials = 2;
|
||
|
||
}
|
||
|
||
sizeOfResourceList = sizeof(CM_RESOURCE_LIST) +
|
||
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)*
|
||
(countOfPartials-1));
|
||
|
||
resourceList = ExAllocatePool(
|
||
PagedPool,
|
||
sizeOfResourceList
|
||
);
|
||
|
||
if (!resourceList) {
|
||
|
||
//
|
||
// Oh well, can't allocate the memory. Act as though
|
||
// we succeeded.
|
||
//
|
||
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
35,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
return;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
resourceList,
|
||
sizeOfResourceList
|
||
);
|
||
|
||
resourceList->Count = 1;
|
||
|
||
resourceList->List[0].InterfaceType = Extension->InterfaceType;
|
||
resourceList->List[0].BusNumber = Extension->BusNumber;
|
||
resourceList->List[0].PartialResourceList.Count = countOfPartials;
|
||
partial = &resourceList->List[0].PartialResourceList.PartialDescriptors[0];
|
||
|
||
//
|
||
// Account for the space used by the controller.
|
||
//
|
||
|
||
partial->Type = CmResourceTypePort;
|
||
partial->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
partial->Flags = (USHORT)Extension->AddressSpace;
|
||
partial->u.Port.Start = Extension->OriginalController;
|
||
partial->u.Port.Length = Extension->SpanOfController;
|
||
|
||
partial++;
|
||
|
||
if (ClaimInterrupt) {
|
||
|
||
//
|
||
// Report the interrupt information.
|
||
//
|
||
|
||
partial->Type = CmResourceTypeInterrupt;
|
||
|
||
if (Extension->InterruptShareable) {
|
||
|
||
partial->ShareDisposition = CmResourceShareShared;
|
||
|
||
} else {
|
||
|
||
partial->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
|
||
}
|
||
|
||
if (Extension->InterruptMode == Latched) {
|
||
|
||
partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||
|
||
} else {
|
||
|
||
partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
|
||
}
|
||
|
||
partial->u.Interrupt.Vector = Extension->OriginalVector;
|
||
partial->u.Interrupt.Level = Extension->OriginalIrql;
|
||
|
||
}
|
||
|
||
RtlInitUnicodeString(
|
||
&className,
|
||
L"LOADED PARALLEL DRIVER RESOURCES"
|
||
);
|
||
|
||
IoReportResourceUsage(
|
||
&className,
|
||
Extension->DeviceObject->DriverObject,
|
||
NULL,
|
||
0,
|
||
Extension->DeviceObject,
|
||
resourceList,
|
||
sizeOfResourceList,
|
||
FALSE,
|
||
ConflictDetected
|
||
);
|
||
|
||
ExFreePool(resourceList);
|
||
|
||
}
|
||
|
||
VOID
|
||
ParUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up all of the memory associated with
|
||
any of the devices belonging to the driver. It will
|
||
loop through the device list.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object controling all of the
|
||
devices.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
|
||
|
||
ParDump(
|
||
PARUNLOAD,
|
||
("PARALLEL: In ParUnload\n")
|
||
);
|
||
|
||
while (currentDevice) {
|
||
|
||
ParUnReportResourcesDevice(currentDevice->DeviceExtension);
|
||
ParCleanupDevice(currentDevice->DeviceExtension);
|
||
IoDeleteDevice(currentDevice);
|
||
IoGetConfigurationInformation()->ParallelCount--;
|
||
|
||
currentDevice = DriverObject->DeviceObject;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
ParCleanupDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will deallocate all of the memory used for
|
||
a particular device. It will also disconnect any resources
|
||
if need be.
|
||
|
||
Arguments:
|
||
|
||
Extension - Pointer to the device extension which is getting
|
||
rid of all it's resources.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ParDump(
|
||
PARUNLOAD,
|
||
("PARALLEL: in ParCleanupDevice for extension: %x\n",Extension)
|
||
);
|
||
|
||
if (Extension) {
|
||
|
||
//
|
||
// Get rid of all external naming as well as removing
|
||
// the device map entry.
|
||
//
|
||
|
||
ParCleanupExternalNaming(Extension);
|
||
|
||
//
|
||
// Delallocate the memory for the various names.
|
||
// NOTE: If we have an extension - Then we must
|
||
// have a device name stored away. Which is *not*
|
||
// true for the other names.
|
||
//
|
||
|
||
ExFreePool(Extension->DeviceName.Buffer);
|
||
|
||
if (Extension->ObjectDirectory.Buffer) {
|
||
|
||
ExFreePool(Extension->ObjectDirectory.Buffer);
|
||
|
||
}
|
||
|
||
if (Extension->NtNameForPort.Buffer) {
|
||
|
||
ExFreePool(Extension->NtNameForPort.Buffer);
|
||
|
||
}
|
||
|
||
if (Extension->SymbolicLinkName.Buffer) {
|
||
|
||
ExFreePool(Extension->SymbolicLinkName.Buffer);
|
||
|
||
}
|
||
|
||
//
|
||
// If necessary, unmap the device registers.
|
||
//
|
||
|
||
if (Extension->UnMapRegisters) {
|
||
|
||
MmUnmapIoSpace(
|
||
Extension->Controller,
|
||
Extension->SpanOfController
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
ParCleanupExternalNaming(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will be used to delete a symbolic link
|
||
to the driver name in the given object directory.
|
||
|
||
It will also delete an entry in the device map for
|
||
this device.
|
||
|
||
Arguments:
|
||
|
||
Extension - Pointer to the device extension.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNICODE_STRING fullLinkName;
|
||
|
||
ParDump(
|
||
PARUNLOAD,
|
||
("PARALLEL: In ParCleanupExternalNaming for\n"
|
||
"-------- extension: %x of port %wZ\n",
|
||
Extension,&Extension->DeviceName)
|
||
);
|
||
|
||
//
|
||
// We're cleaning up here. One reason we're cleaning up
|
||
// is that we couldn't allocate space for the directory
|
||
// name or the symbolic link.
|
||
//
|
||
|
||
if (Extension->ObjectDirectory.Buffer &&
|
||
Extension->SymbolicLinkName.Buffer &&
|
||
Extension->CreatedSymbolicLink) {
|
||
|
||
//
|
||
// Form the full symbolic link name we wish to create.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&fullLinkName,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Allocate some pool for the name.
|
||
//
|
||
|
||
fullLinkName.MaximumLength = (sizeof(L"\\")*2) +
|
||
Extension->ObjectDirectory.Length+
|
||
Extension->SymbolicLinkName.Length+
|
||
sizeof(WCHAR);
|
||
|
||
fullLinkName.Buffer = ExAllocatePool(
|
||
PagedPool,
|
||
fullLinkName.MaximumLength
|
||
);
|
||
|
||
if (!fullLinkName.Buffer) {
|
||
|
||
//
|
||
// Couldn't allocate space for the name. Just go on
|
||
// to the device map stuff.
|
||
//
|
||
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
36,
|
||
STATUS_SUCCESS,
|
||
PAR_INSUFFICIENT_RESOURCES
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't allocate space for the symbolic \n"
|
||
"-------- name for creating the link\n"
|
||
"-------- for port %wZ on cleanup\n",
|
||
&Extension->DeviceName)
|
||
);
|
||
|
||
} else {
|
||
|
||
RtlZeroMemory(
|
||
fullLinkName.Buffer,
|
||
fullLinkName.MaximumLength
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&fullLinkName,
|
||
L"\\"
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&fullLinkName,
|
||
&Extension->ObjectDirectory
|
||
);
|
||
|
||
RtlAppendUnicodeToString(
|
||
&fullLinkName,
|
||
L"\\"
|
||
);
|
||
|
||
RtlAppendUnicodeStringToString(
|
||
&fullLinkName,
|
||
&Extension->SymbolicLinkName
|
||
);
|
||
|
||
IoDeleteSymbolicLink(&fullLinkName);
|
||
|
||
ExFreePool(fullLinkName.Buffer);
|
||
|
||
}
|
||
|
||
//
|
||
// We're cleaning up here. One reason we're cleaning up
|
||
// is that we couldn't allocate space for the NtNameOfPort.
|
||
//
|
||
|
||
if (Extension->NtNameForPort.Buffer) {
|
||
|
||
NTSTATUS status;
|
||
|
||
status = RtlDeleteRegistryValue(
|
||
RTL_REGISTRY_DEVICEMAP,
|
||
L"PARALLEL PORTS",
|
||
Extension->NtNameForPort.Buffer
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ParLogError(
|
||
Extension->DeviceObject->DriverObject,
|
||
Extension->DeviceObject,
|
||
Extension->OriginalController,
|
||
ParPhysicalZero,
|
||
0,
|
||
0,
|
||
0,
|
||
37,
|
||
status,
|
||
PAR_NO_DEVICE_MAP_DELETED
|
||
);
|
||
ParDump(
|
||
PARERRORS,
|
||
("PARALLEL: Couldn't delete value entry %wZ\n",
|
||
&Extension->DeviceName)
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
ParUnReportResourcesDevice(
|
||
IN PPAR_DEVICE_EXTENSION Extension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Purge the resources for this particular device.
|
||
|
||
Arguments:
|
||
|
||
Extension - The device extension of the device we are *un*reporting
|
||
resources for.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CM_RESOURCE_LIST resourceList;
|
||
ULONG sizeOfResourceList = 0;
|
||
UNICODE_STRING className;
|
||
BOOLEAN junkBoolean;
|
||
|
||
ParDump(
|
||
PARUNLOAD,
|
||
("PARALLEL: In ParUnreportResourcesDevice\n"
|
||
"-------- for extension %x of port %wZ\n",
|
||
Extension,&Extension->DeviceName)
|
||
);
|
||
RtlZeroMemory(
|
||
&resourceList,
|
||
sizeof(CM_RESOURCE_LIST)
|
||
);
|
||
|
||
resourceList.Count = 0;
|
||
|
||
RtlInitUnicodeString(
|
||
&className,
|
||
L"LOADED PARALLEL DRIVER RESOURCES"
|
||
);
|
||
|
||
IoReportResourceUsage(
|
||
&className,
|
||
Extension->DeviceObject->DriverObject,
|
||
NULL,
|
||
0,
|
||
Extension->DeviceObject,
|
||
&resourceList,
|
||
sizeof(CM_RESOURCE_LIST),
|
||
FALSE,
|
||
&junkBoolean
|
||
);
|
||
|
||
}
|