|
|
/*++
Copyright (C) 1997-99 Microsoft Corporation
Module Name:
ide.c
Abstract:
This contain DriverEntry and utilities routines
Author:
Joe Dai (joedai)
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "ideport.h"
#include <initguid.h>
#include <idedump.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, IdePortNoSupportIrp)
#pragma alloc_text(PAGE, IdePortPassDownToNextDriver)
#pragma alloc_text(PAGE, IdePortStatusSuccessAndPassDownToNextDriver)
#pragma alloc_text(PAGE, IdePortDispatchPnp)
#pragma alloc_text(PAGE, IdePortDispatchSystemControl)
#pragma alloc_text(PAGE, IdePortOkToDetectLegacy)
#pragma alloc_text(PAGE, IdePortOpenServiceSubKey)
#pragma alloc_text(PAGE, IdePortCloseServiceSubKey)
#pragma alloc_text(PAGE, IdePortParseDeviceParameters)
#pragma alloc_text(PAGE, IdePortGetDeviceTypeString)
#pragma alloc_text(PAGE, IdePortGetCompatibleIdString)
#pragma alloc_text(PAGE, IdePortGetPeripheralIdString)
#pragma alloc_text(PAGE, IdePortUnload)
#pragma alloc_text(PAGE, IdePortSearchDeviceInRegMultiSzList)
#pragma alloc_text(PAGE, IdePortSyncSendIrp)
#pragma alloc_text(PAGE, IdePortInSetup)
#pragma alloc_text(NONPAGE, IdePortDispatchDeviceControl)
#pragma alloc_text(NONPAGE, IdePortAlwaysStatusSuccessIrp)
#pragma alloc_text(NONPAGE, IdePortDispatchPower)
#pragma alloc_text(NONPAGE, IdePortGenericCompletionRoutine)
#endif // ALLOC_PRAGMA
//
// get the share code
//
#include "..\share\util.c"
#if DBG
//
// for performance tuning
//
void _DebugPrintResetTickCount (LARGE_INTEGER * lastTickCount) { KeQueryTickCount(lastTickCount); }
void _DebugPrintTickCount (LARGE_INTEGER * lastTickCount, ULONG limit, PUCHAR filename, ULONG lineNumber) { LARGE_INTEGER tickCount;
KeQueryTickCount(&tickCount); if ((tickCount.QuadPart - lastTickCount->QuadPart) >= limit) { DebugPrint ((1, "File: %s Line %u: CurrentTick = %u (%u ticks since last check)\n", filename, lineNumber, (ULONG) tickCount.QuadPart, (ULONG) (tickCount.QuadPart - lastTickCount->QuadPart))); } *lastTickCount = tickCount; }
#endif //DBG
//
// Globals
//
//
// Po Dispatch Table
//
PDRIVER_DISPATCH FdoPowerDispatchTable[NUM_POWER_MINOR_FUNCTION]; PDRIVER_DISPATCH PdoPowerDispatchTable[NUM_POWER_MINOR_FUNCTION];
IDE_FDO_LIST IdeGlobalFdoList = {-1};
NTSTATUS IdePortNoSupportIrp ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Generic routine to fail unsupported irp
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP to fail.
Return Value:
NT status.
--*/ { NTSTATUS status = Irp->IoStatus.Status; PIO_STACK_LOCATION thisIrpSp;
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
//
// You should call PoStartNextPowerIrp before completing a power irp
//
if (thisIrpSp->MajorFunction == IRP_MJ_POWER) {
PoStartNextPowerIrp (Irp);
}
DebugPrint (( DBG_WARNING, "IdePort: devobj 0x%x failing unsupported Irp (0x%x, 0x%x) with status = %x\n", DeviceObject, thisIrpSp->MajorFunction, thisIrpSp->MinorFunction, status ));
IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status; } // IdePortNoSupportIrp
NTSTATUS IdePortAlwaysStatusSuccessIrp ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp /*++
Routine Description:
Generic routine to STATUS_SUCCESS an irp
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP.
Return Value:
NT status.
--*/ ) { Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } // IdePortAlwaysStatusSuccessIrp
NTSTATUS IdePortPassDownToNextDriver ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Generic routine to pass an irp down to the lower driver
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP.
Return Value:
NT status.
--*/ { PDEVICE_EXTENSION_HEADER doExtension; PIO_STACK_LOCATION thisIrpSp; NTSTATUS status;
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
doExtension = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension;
ASSERT (doExtension->AttacheeDeviceObject);
if (thisIrpSp->MajorFunction == IRP_MJ_POWER) {
//
// call PoStartNextPowerIrp before completing a power irp
//
PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation (Irp); status = PoCallDriver (doExtension->AttacheeDeviceObject, Irp);
} else {
//
// Not a power irp
//
IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (doExtension->AttacheeDeviceObject, Irp); }
return status;
} // IdePortPassDownToNextDriver
NTSTATUS IdePortStatusSuccessAndPassDownToNextDriver ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PAGED_CODE(); Irp->IoStatus.Status = STATUS_SUCCESS; return IdePortPassDownToNextDriver(DeviceObject, Irp); } // IdePortStatusSuccessAndPassDownToNextDriver
NTSTATUS IdePortDispatchDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Dispatch routine for IRP_MJ_DEVICE_CONTROL
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP.
Return Value:
NT status.
--*/ { PDEVICE_EXTENSION_HEADER DoExtensionHeader; NTSTATUS status;
DoExtensionHeader = DeviceObject->DeviceExtension;
if (IS_PDO(DoExtensionHeader)) {
//
// PDO
//
status = DeviceDeviceIoControl ( DeviceObject, Irp );
} else {
//
// FDO
//
status = IdePortDeviceControl ( DeviceObject, Irp ); }
return status; } // IdePortDispatchDeviceControl
NTSTATUS IdePortDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Dispatch routine for IRP_MJ_POWER
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION thisIrpSp; NTSTATUS status; PDEVICE_EXTENSION_HEADER doExtension; BOOLEAN pendingIrp;
//
// Get a pointer to our stack location and take appropriate action based
// on the minor function.
//
thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); doExtension = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension;
DebugPrint ((DBG_POWER, "IdePort: 0x%x %s %d got %s[%d, %d]\n", doExtension->AttacheeDeviceObject ? ((PFDO_EXTENSION) doExtension)->IdeResource.TranslatedCommandBaseAddress : ((PPDO_EXTENSION) doExtension)->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PPDO_EXTENSION) doExtension)->TargetId, IdeDebugPowerIrpName[thisIrpSp->MinorFunction], thisIrpSp->Parameters.Power.Type, thisIrpSp->Parameters.Power.State ));
if (thisIrpSp->MinorFunction < NUM_POWER_MINOR_FUNCTION) {
status = doExtension->PowerDispatchTable[thisIrpSp->MinorFunction] (DeviceObject, Irp); } else {
DebugPrint ((DBG_WARNING, "ATAPI: Power Dispatch Table too small\n" ));
status = doExtension->DefaultDispatch(DeviceObject, Irp); }
return status; } // IdePortDispatchPower
NTSTATUS IdePortDispatchPnp( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Dispatch routine for IRP_MJ_PNP_POWER IRPs
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION thisIrpSp; NTSTATUS status; PDEVICE_EXTENSION_HEADER doExtension;
//
// Get a pointer to our stack location and take appropriate action based
// on the minor function.
//
thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); doExtension = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension;
DebugPrint ((DBG_PNP, "IdePort: 0x%x %s %d got %s\n", doExtension->AttacheeDeviceObject ? ((PFDO_EXTENSION) doExtension)->IdeResource.TranslatedCommandBaseAddress : ((PPDO_EXTENSION) doExtension)->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PPDO_EXTENSION) doExtension)->TargetId, IdeDebugPnpIrpName[thisIrpSp->MinorFunction]));
if (thisIrpSp->MinorFunction < NUM_PNP_MINOR_FUNCTION) {
status = doExtension->PnPDispatchTable[thisIrpSp->MinorFunction] (DeviceObject, Irp);
} else {
if (thisIrpSp->MinorFunction != 0xff) {
ASSERT (!"ATAPI: PnP Dispatch Table too small\n"); }
status = doExtension->DefaultDispatch (DeviceObject, Irp); }
return status; } // IdePortDispatchPnp
NTSTATUS IdePortDispatchSystemControl( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
Dispatch routine for IRP_MJ_SYSTEM_CONTROL (WMI) IRPs
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION thisIrpSp; NTSTATUS status; PDEVICE_EXTENSION_HEADER doExtension;
thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); doExtension = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension;
DebugPrint ((DBG_WMI, "IdePort: 0x%x %s %d got %s\n", doExtension->AttacheeDeviceObject ? ((PFDO_EXTENSION) doExtension)->IdeResource.TranslatedCommandBaseAddress : ((PPDO_EXTENSION) doExtension)->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PPDO_EXTENSION) doExtension)->TargetId, IdeDebugWmiIrpName[thisIrpSp->MinorFunction]));
if (thisIrpSp->MinorFunction < NUM_WMI_MINOR_FUNCTION) {
status = doExtension->WmiDispatchTable[thisIrpSp->MinorFunction] (DeviceObject, Irp);
} else {
DebugPrint((DBG_WARNING, "ATAPI: WMI Dispatch Table too small\n" ));
status = doExtension->DefaultDispatch (DeviceObject, Irp); }
return status; } // IdePortDispatchSystemControl
ULONG DriverEntry( IN OUT PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++
Routine Description:
Entry point to this driver
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP.
Return Value:
NT status.
--*/ { NTSTATUS status; PIDEDRIVER_EXTENSION ideDriverExtension; ULONG i;
#if DBG
//
// checking IDE_COMMAND_BLOCK_WRITE_REGISTERS structure and its macros
//
{ IDE_COMMAND_BLOCK_WRITE_REGISTERS baseIoAddress1; IDE_REGISTERS_2 baseIoAddress2; ULONG baseIoAddress1Length; ULONG baseIoAddress2Length; ULONG maxIdeDevice; ULONG maxIdeTargetId;
AtapiBuildIoAddress (0, 0, (PIDE_REGISTERS_1)&baseIoAddress1, &baseIoAddress2, &baseIoAddress1Length, &baseIoAddress2Length, &maxIdeDevice, &maxIdeTargetId);
ASSERT (ATA_DATA16_REG (&baseIoAddress1) == 0); ASSERT (ATA_ERROR_REG (&baseIoAddress1) == (PUCHAR)1); ASSERT (ATA_SECTOR_COUNT_REG (&baseIoAddress1) == (PUCHAR)2); ASSERT (ATA_SECTOR_NUMBER_REG(&baseIoAddress1) == (PUCHAR)3); ASSERT (ATA_CYLINDER_LOW_REG (&baseIoAddress1) == (PUCHAR)4); ASSERT (ATA_CYLINDER_HIGH_REG(&baseIoAddress1) == (PUCHAR)5); ASSERT (ATA_DRIVE_SELECT_REG (&baseIoAddress1) == (PUCHAR)6); ASSERT (ATA_STATUS_REG (&baseIoAddress1) == (PUCHAR)7);
ASSERT (ATA_FEATURE_REG (&baseIoAddress1) == (PUCHAR)1); ASSERT (ATA_COMMAND_REG (&baseIoAddress1) == (PUCHAR)7);
ASSERT (ATAPI_DATA16_REG (&baseIoAddress1) == 0); ASSERT (ATAPI_ERROR_REG (&baseIoAddress1) == (PUCHAR)1); ASSERT (ATAPI_INTERRUPT_REASON_REG (&baseIoAddress1) == (PUCHAR)2); ASSERT (ATAPI_BYTECOUNT_LOW_REG (&baseIoAddress1) == (PUCHAR)4); ASSERT (ATAPI_BYTECOUNT_HIGH_REG (&baseIoAddress1) == (PUCHAR)5); ASSERT (ATAPI_DRIVE_SELECT_REG (&baseIoAddress1) == (PUCHAR)6); ASSERT (ATAPI_STATUS_REG (&baseIoAddress1) == (PUCHAR)7);
ASSERT (ATAPI_FEATURE_REG (&baseIoAddress1) == (PUCHAR)1); ASSERT (ATAPI_COMMAND_REG (&baseIoAddress1) == (PUCHAR)7);
ASSERT (baseIoAddress1Length == 8); ASSERT (baseIoAddress2Length == 1); ASSERT (maxIdeDevice == 2);
} #endif //DBG
if (!DriverObject) {
//
// We are called by crashdump or po
//
return AtapiCrashDumpDriverEntry (RegistryPath); }
//
// Allocate Driver Object Extension for storing
// the RegistryPath
//
status = IoAllocateDriverObjectExtension( DriverObject, DRIVER_OBJECT_EXTENSION_ID, sizeof (DRIVER_EXTENSION), &ideDriverExtension );
if (!NT_SUCCESS(status)) {
DebugPrint ((0, "IdePort: Unable to create driver extension\n")); return status; }
ASSERT(ideDriverExtension);
RtlZeroMemory ( ideDriverExtension, sizeof (DRIVER_EXTENSION) );
//
// make copy of the RegistryPath
//
ideDriverExtension->RegistryPath.Buffer = ExAllocatePool (NonPagedPool, RegistryPath->Length * sizeof(WCHAR)); if (ideDriverExtension->RegistryPath.Buffer == NULL) {
DebugPrint ((0, "IdePort: Unable to allocate memory for registry path\n"));
return (ULONG) STATUS_INSUFFICIENT_RESOURCES; }
ideDriverExtension->RegistryPath.Length = 0; ideDriverExtension->RegistryPath.MaximumLength = RegistryPath->Length; RtlCopyUnicodeString (&ideDriverExtension->RegistryPath, RegistryPath);
//
// The PnP thing to do
//
DriverObject->DriverExtension->AddDevice = ChannelAddDevice;
//
// Set up the device driver entry points.
//
DriverObject->DriverStartIo = IdePortStartIo; DriverObject->DriverUnload = IdePortUnload; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = IdePortDispatch; DriverObject->MajorFunction[IRP_MJ_SCSI] = IdePortDispatch; DriverObject->MajorFunction[IRP_MJ_CREATE] = IdePortAlwaysStatusSuccessIrp; DriverObject->MajorFunction[IRP_MJ_CLOSE] = IdePortAlwaysStatusSuccessIrp; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IdePortDispatchDeviceControl; DriverObject->MajorFunction[IRP_MJ_POWER] = IdePortDispatchPower; DriverObject->MajorFunction[IRP_MJ_PNP] = IdePortDispatchPnp; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IdePortDispatchSystemControl;
//
// FDO PnP Dispatch Table
//
for (i=0; i<NUM_PNP_MINOR_FUNCTION; i++) {
FdoPnpDispatchTable[i] = IdePortPassDownToNextDriver; } FdoPnpDispatchTable[IRP_MN_START_DEVICE ] = ChannelStartDevice; FdoPnpDispatchTable[IRP_MN_QUERY_REMOVE_DEVICE ] = IdePortStatusSuccessAndPassDownToNextDriver; FdoPnpDispatchTable[IRP_MN_CANCEL_REMOVE_DEVICE ] = IdePortStatusSuccessAndPassDownToNextDriver; FdoPnpDispatchTable[IRP_MN_REMOVE_DEVICE ] = ChannelRemoveDevice; FdoPnpDispatchTable[IRP_MN_QUERY_STOP_DEVICE ] = IdePortStatusSuccessAndPassDownToNextDriver; FdoPnpDispatchTable[IRP_MN_CANCEL_STOP_DEVICE ] = IdePortStatusSuccessAndPassDownToNextDriver; FdoPnpDispatchTable[IRP_MN_STOP_DEVICE ] = ChannelStopDevice; FdoPnpDispatchTable[IRP_MN_QUERY_DEVICE_RELATIONS ] = ChannelQueryDeviceRelations; FdoPnpDispatchTable[IRP_MN_QUERY_ID ] = ChannelQueryId; FdoPnpDispatchTable[IRP_MN_DEVICE_USAGE_NOTIFICATION ] = ChannelUsageNotification; FdoPnpDispatchTable[IRP_MN_FILTER_RESOURCE_REQUIREMENTS] = ChannelFilterResourceRequirements; FdoPnpDispatchTable[IRP_MN_QUERY_PNP_DEVICE_STATE ] = ChannelQueryPnPDeviceState; FdoPnpDispatchTable[IRP_MN_SURPRISE_REMOVAL ] = ChannelSurpriseRemoveDevice;
//
// PDO PnP Dispatch Table
//
for (i=0; i<NUM_PNP_MINOR_FUNCTION; i++) {
PdoPnpDispatchTable[i] = IdePortNoSupportIrp; } PdoPnpDispatchTable[IRP_MN_START_DEVICE ] = DeviceStartDevice; PdoPnpDispatchTable[IRP_MN_QUERY_DEVICE_RELATIONS ] = DeviceQueryDeviceRelations; PdoPnpDispatchTable[IRP_MN_QUERY_REMOVE_DEVICE ] = DeviceQueryStopRemoveDevice; PdoPnpDispatchTable[IRP_MN_REMOVE_DEVICE ] = DeviceRemoveDevice; PdoPnpDispatchTable[IRP_MN_CANCEL_REMOVE_DEVICE ] = IdePortAlwaysStatusSuccessIrp; PdoPnpDispatchTable[IRP_MN_STOP_DEVICE ] = DeviceStopDevice; PdoPnpDispatchTable[IRP_MN_QUERY_STOP_DEVICE ] = DeviceQueryStopRemoveDevice; PdoPnpDispatchTable[IRP_MN_CANCEL_STOP_DEVICE ] = IdePortAlwaysStatusSuccessIrp; PdoPnpDispatchTable[IRP_MN_QUERY_ID ] = DeviceQueryId; PdoPnpDispatchTable[IRP_MN_QUERY_CAPABILITIES ] = DeviceQueryCapabilities; PdoPnpDispatchTable[IRP_MN_QUERY_DEVICE_TEXT ] = DeviceQueryText; PdoPnpDispatchTable[IRP_MN_DEVICE_USAGE_NOTIFICATION ] = DeviceUsageNotification; PdoPnpDispatchTable[IRP_MN_QUERY_PNP_DEVICE_STATE ] = DeviceQueryPnPDeviceState; PdoPnpDispatchTable[IRP_MN_SURPRISE_REMOVAL ] = DeviceRemoveDevice;
//
// FDO Power Dispatch Table
//
for (i=0; i<NUM_POWER_MINOR_FUNCTION; i++) {
FdoPowerDispatchTable[i] = IdePortPassDownToNextDriver; } FdoPowerDispatchTable[IRP_MN_SET_POWER] = IdePortSetFdoPowerState; FdoPowerDispatchTable[IRP_MN_QUERY_POWER] = ChannelQueryPowerState;
//
// PDO Power Dispatch Table
//
for (i=0; i<NUM_POWER_MINOR_FUNCTION; i++) {
PdoPowerDispatchTable[i] = IdePortNoSupportIrp; } PdoPowerDispatchTable[IRP_MN_SET_POWER] = IdePortSetPdoPowerState; PdoPowerDispatchTable[IRP_MN_QUERY_POWER] = DeviceQueryPowerState;
//
// FDO WMI Dispatch Table
//
for (i=0; i<NUM_WMI_MINOR_FUNCTION; i++) {
FdoWmiDispatchTable[i] = IdePortPassDownToNextDriver; }
//
// PDO WMI Dispatch Table
//
for (i=0; i<NUM_WMI_MINOR_FUNCTION; i++) {
#if defined (IDEPORT_WMI_SUPPORT)
PdoWmiDispatchTable[i] = IdePortWmiSystemControl; #else
PdoWmiDispatchTable[i] = IdePortNoSupportIrp; #endif // IDEPORT_WMI_SUPPORT
}
#if defined (IDEPORT_WMI_SUPPORT)
//
// Init WMI related stuff
//
IdePortWmiInit (); #endif // IDEPORT_WMI_SUPPORT
//
// Create device object name directory
//
IdeCreateIdeDirectory();
IdeInitializeFdoList (&IdeGlobalFdoList);
//
// Detect legacy (non-enumerable) IDE devices
//
#if !defined(NO_LEGACY_DRIVERS)
IdePortDetectLegacyController ( DriverObject, RegistryPath ); #endif // NO_LEGACY_DRIVERS
//
// Register a bugcheck handler for ATAPI.
//
PortRegisterBugcheckCallback (&ATAPI_DUMP_ID, AtapiDumpCallback);
return STATUS_SUCCESS; } // DriverEntry
#ifdef DRIVER_PARAMETER_REGISTRY_SUPPORT
HANDLE IdePortOpenServiceSubKey ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING SubKeyPath ) /*++
Routine Description:
Open a registry key
Arguments:
DriverObject - this driver driver object
SubKeyPath - registry key to open
Return Value:
handle to the registry key
--*/ { PIDEDRIVER_EXTENSION ideDriverExtension; OBJECT_ATTRIBUTES objectAttributes; HANDLE serviceKey; HANDLE subServiceKey; NTSTATUS status;
ideDriverExtension = IoGetDriverObjectExtension( DriverObject, DRIVER_OBJECT_EXTENSION_ID );
if (!ideDriverExtension) {
return NULL; }
InitializeObjectAttributes(&objectAttributes, &ideDriverExtension->RegistryPath, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(&serviceKey, KEY_READ, &objectAttributes);
if (!NT_SUCCESS(status)) {
return NULL; }
InitializeObjectAttributes(&objectAttributes, SubKeyPath, OBJ_CASE_INSENSITIVE, serviceKey, (PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(&subServiceKey, KEY_READ, &objectAttributes);
ZwClose(serviceKey);
if (NT_SUCCESS(status)) {
return subServiceKey; } else {
return NULL; } } // IdePortOpenServiceSubKey
VOID IdePortCloseServiceSubKey ( IN HANDLE SubServiceKey ) /*++
Routine Description:
close a registry key handle
Arguments:
SubServiceKey - registry key to close
Return Value:
None
--*/ { ZwClose(SubServiceKey); } // IdePortCloseServiceSubKey
VOID IdePortParseDeviceParameters( IN HANDLE SubServiceKey, IN OUT PCUSTOM_DEVICE_PARAMETER CustomDeviceParameter ) /*++
Routine Description:
This routine parses a device key node and updates the CustomDeviceParameter
Arguments:
SubServiceKey - Supplies an open key to the device node.
CustomDeviceParameter - Supplies the configuration information to be initialized.
Return Value:
None
--*/
{ UCHAR keyValueInformationBuffer[SP_REG_BUFFER_SIZE]; PKEY_VALUE_FULL_INFORMATION keyValueInformation; ULONG length; ULONG index; UNICODE_STRING unicodeString; ANSI_STRING ansiString; NTSTATUS status;
//
// Look at each of the values in the device node.
//
index = 0;
keyValueInformation = (PKEY_VALUE_FULL_INFORMATION) keyValueInformationBuffer;
while (NT_SUCCESS (ZwEnumerateValueKey( SubServiceKey, index, KeyValueFullInformation, keyValueInformation, SP_REG_BUFFER_SIZE, &length))) {
//
// Update the index for the next time around the loop.
//
index++;
//
// Check that the length is reasonable.
//
if (keyValueInformation->Type == REG_DWORD && keyValueInformation->DataLength != sizeof(ULONG)) {
continue; }
//
// Check for a maximum lu number.
//
if (_wcsnicmp(keyValueInformation->Name, L"ScsiDebug", keyValueInformation->NameLength/2) == 0) {
if (keyValueInformation->Type != REG_DWORD) {
DebugPrint((1, "IdeParseDevice: Bad data type for ScsiDebug.\n")); continue; } #if DBG
ScsiDebug = *((PULONG) (keyValueInformationBuffer + keyValueInformation->DataOffset)); #endif
}
//
// Check for driver parameters tranfers.
//
if (_wcsnicmp(keyValueInformation->Name, L"DriverParameters", keyValueInformation->NameLength/2) == 0) {
if (keyValueInformation->DataLength == 0) { continue; }
if (keyValueInformation->Type == REG_SZ) {
//
// This is a unicode string. Convert it to a ANSI string.
// Initialize the strings.
//
unicodeString.Buffer = (PWSTR) ((PCCHAR) keyValueInformation + keyValueInformation->DataOffset); unicodeString.Length = (USHORT) keyValueInformation->DataLength; unicodeString.MaximumLength = (USHORT) keyValueInformation->DataLength;
status = RtlUnicodeStringToAnsiString( &ansiString, &unicodeString, TRUE );
if (NT_SUCCESS(status)) {
CustomDeviceParameter->CommandRegisterBase = AtapiParseArgumentString(ansiString.Buffer, "BaseAddress");
if (CustomDeviceParameter->CommandRegisterBase) {
CustomDeviceParameter->IrqLevel = AtapiParseArgumentString(ansiString.Buffer, "Interrupt"); }
RtlFreeAnsiString (&ansiString); } }
DebugPrint((2, "IdeParseDeviceParameters: Found driver parameter.\n")); } }
return;
} // IdePortParseDeviceParameters
#endif // DRIVER_PARAMETER_REGISTRY_SUPPORT
#pragma data_seg ("PAGEDATA")
//
// device description table
// index by SCSI device type
//
const static IDE_DEVICE_TYPE IdeDeviceType[] = { {"Disk", "GenDisk", "DiskPeripheral" }, {"Sequential", "GenSequential", "TapePeripheral" }, {"Printer", "GenPrinter", "PrinterPeripheral" }, {"Processor", "GenProcessor", "ProcessorPeripheral" }, {"Worm", "GenWorm", "WormPeripheral" }, {"CdRom", "GenCdRom", "CdRomPeripheral" }, {"Scanner", "GenScanner", "ScannerPeripheral" }, {"Optical", "GenOptical", "OpticalDiskPeripheral" }, {"Changer", "GenChanger", "MediumChangerPeripheral" }, {"Net", "GenNet", "CommunicationPeripheral" } }; #pragma data_seg ()
PCSTR IdePortGetDeviceTypeString ( IN ULONG DeviceType ) /*++
Routine Description:
look up SCSI device type string
Arguments:
DeviceType - SCSI device type
Return Value:
device type string
--*/ { if (DeviceType < (sizeof (IdeDeviceType) / sizeof (IDE_DEVICE_TYPE))) {
return IdeDeviceType[DeviceType].DeviceTypeString;
} else {
return NULL; }
} // IdePortGetDeviceTypeString
PCSTR IdePortGetCompatibleIdString ( IN ULONG DeviceType ) /*++
Routine Description:
look up compatible ID string
Arguments:
DeviceType - SCSI device type
Return Value:
compatible ID string
--*/ { if (DeviceType < (sizeof (IdeDeviceType) / sizeof (IDE_DEVICE_TYPE))) {
return IdeDeviceType[DeviceType].CompatibleIdString;
} else {
return NULL; } } // IdePortGetCompatibleIdString
PCSTR IdePortGetPeripheralIdString ( IN ULONG DeviceType ) /*++
Routine Description:
look up peripheral ID string
Arguments:
DeviceType - SCSI device type
Return Value:
Peripheral ID string
--*/ { if (DeviceType < (sizeof (IdeDeviceType) / sizeof (IDE_DEVICE_TYPE))) {
return IdeDeviceType[DeviceType].PeripheralIdString;
} else {
return NULL; } } // IdePortGetPeripheralIdString
VOID IdePortUnload( IN PDRIVER_OBJECT DriverObject )
/*++
Routine Description:
get ready to be unloaded
Arguments:
DriverObject - the driver being unloaded
Return Value:
none
--*/
{ PIDEDRIVER_EXTENSION ideDriverExtension;
DebugPrint ((1, "IdePort: unloading...\n"));
ASSERT (DriverObject->DeviceObject == NULL);
ideDriverExtension = IoGetDriverObjectExtension( DriverObject, DRIVER_OBJECT_EXTENSION_ID ); if ((ideDriverExtension != NULL) && (ideDriverExtension->RegistryPath.Buffer != NULL)) {
ExFreePool (ideDriverExtension->RegistryPath.Buffer); }
//
// Deregister the ATAPI bugcheck callback. NOTE: The function will
// sliently fail if the callback has not yet been registered.
//
PortDeregisterBugcheckCallback (&ATAPI_DUMP_ID);
return; } // IdePortUnload
BOOLEAN IdePortOkToDetectLegacy ( IN PDRIVER_OBJECT DriverObject ) { NTSTATUS status; OBJECT_ATTRIBUTES attributes; HANDLE regHandle; UNICODE_STRING pathRoot; ULONG legacyDetection; RTL_QUERY_REGISTRY_TABLE queryTable[2];
RtlInitUnicodeString (&pathRoot, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Pnp"); InitializeObjectAttributes(&attributes, &pathRoot, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR)NULL ); status = ZwOpenKey(®Handle, KEY_READ, &attributes ); if (NT_SUCCESS(status)) {
ULONG parameterValue = 0;
RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable->QueryRoutine = NULL; queryTable->Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT; queryTable->Name = L"DisableFirmwareMapper"; queryTable->EntryContext = ¶meterValue; queryTable->DefaultType = REG_DWORD; queryTable->DefaultData = ¶meterValue; queryTable->DefaultLength = sizeof (parameterValue);
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR) regHandle, queryTable, NULL, NULL); ZwClose (regHandle);
if (parameterValue) {
//
// Cool. no need to detect legacy controller
//
return FALSE; } }
status = IdePortGetParameterFromServiceSubKey ( DriverObject, LEGACY_DETECTION, REG_DWORD, TRUE, (PVOID) &legacyDetection, 0 ); if (NT_SUCCESS(status)) {
if (legacyDetection) {
legacyDetection = 0;
//
// disable legacy detection for next boot
//
IdePortGetParameterFromServiceSubKey ( DriverObject, LEGACY_DETECTION, REG_DWORD, FALSE, (PVOID) &legacyDetection, sizeof (legacyDetection) );
return TRUE;
} else {
return FALSE; } }
return TRUE; }
BOOLEAN IdePortSearchDeviceInRegMultiSzList ( IN PFDO_EXTENSION FdoExtension, IN PIDENTIFY_DATA IdentifyData, IN PWSTR RegKeyValue ) { PWSTR string; UNICODE_STRING unicodeString;
BOOLEAN foundIt;
NTSTATUS status;
PWSTR regDeviceList;
ANSI_STRING ansiTargetDeviceId; UNICODE_STRING unicodeTargetDeviceId; PUCHAR targetDeviceId; ULONG i; ULONG j;
PAGED_CODE();
ASSERT (IdentifyData); ASSERT (RegKeyValue);
foundIt = FALSE;
status = IdePortGetParameterFromServiceSubKey ( FdoExtension->DriverObject, RegKeyValue, REG_MULTI_SZ, TRUE, ®DeviceList, 0 );
if (NT_SUCCESS(status) && regDeviceList) {
targetDeviceId = ExAllocatePool ( PagedPool, sizeof(IdentifyData->ModelNumber) + sizeof(IdentifyData->FirmwareRevision) + sizeof('\0') );
if (targetDeviceId) {
for (i=0; i<sizeof(IdentifyData->ModelNumber); i+=2) {
targetDeviceId[i + 0] = IdentifyData->ModelNumber[i + 1]; targetDeviceId[i + 1] = IdentifyData->ModelNumber[i + 0];
if (targetDeviceId[i + 0] == '\0') {
targetDeviceId[i + 0] = ' '; } if (targetDeviceId[i + 1] == '\0') {
targetDeviceId[i + 1] = ' '; } } for (j=0; j<sizeof(IdentifyData->FirmwareRevision); j+=2) {
targetDeviceId[i + j + 0] = IdentifyData->FirmwareRevision[j + 1]; targetDeviceId[i + j + 1] = IdentifyData->FirmwareRevision[j + 0];
if (targetDeviceId[i + j + 0] == '\0') {
targetDeviceId[i + j + 0] = ' '; } if (targetDeviceId[i + j + 1] == '\0') {
targetDeviceId[i + j + 1] = ' '; } } targetDeviceId[i + j] = 0;
RtlInitAnsiString( &ansiTargetDeviceId, targetDeviceId );
status = RtlAnsiStringToUnicodeString( &unicodeTargetDeviceId, &ansiTargetDeviceId, TRUE );
if (NT_SUCCESS(status)) {
string = regDeviceList;
DebugPrint ((DBG_REG_SEARCH, "IdePort: searching for %s in list\n", targetDeviceId));
while (string[0]) {
ULONG length;
DebugPrint ((DBG_REG_SEARCH, "IdePort: device list: %ws\n", string));
RtlInitUnicodeString( &unicodeString, string );
//
// compare up to the length of the shorter string
//
if (unicodeTargetDeviceId.Length < unicodeString.Length) {
length = unicodeTargetDeviceId.Length; } else {
length = unicodeString.Length; }
if (length == RtlCompareMemory(unicodeTargetDeviceId.Buffer, unicodeString.Buffer, length)) {
DebugPrint ((DBG_REG_SEARCH, "IdePort: Found a target device on the device list. %ws\n", string)); foundIt = TRUE; break;
} else {
string += (unicodeString.Length / sizeof(WCHAR)) + 1; } }
RtlFreeUnicodeString ( &unicodeTargetDeviceId );
} else {
ASSERT (FALSE); }
ExFreePool(targetDeviceId); }
ExFreePool(regDeviceList); }
return foundIt; }
NTSTATUS IdePortSyncSendIrp ( IN PDEVICE_OBJECT TargetDeviceObject, IN PIO_STACK_LOCATION IrpSp, IN OUT OPTIONAL PIO_STATUS_BLOCK IoStatus ) { PIO_STACK_LOCATION newIrpSp; PIRP newIrp; KEVENT event; NTSTATUS status;
ASSERT (TargetDeviceObject); ASSERT (IrpSp);
//
// Allocate an IRP for below
//
newIrp = IoAllocateIrp (TargetDeviceObject->StackSize, FALSE); // Get stack size from PDO
if (newIrp == NULL) {
DebugPrint ((DBG_ALWAYS, "IdePortSyncSendIrp: Unable to get allocate an irp")); return STATUS_NO_MEMORY; }
newIrpSp = IoGetNextIrpStackLocation(newIrp); RtlMoveMemory (newIrpSp, IrpSp, sizeof (*IrpSp));
if (IoStatus) {
newIrp->IoStatus.Status = IoStatus->Status; } else {
newIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; }
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoSetCompletionRoutine ( newIrp, IdePortGenericCompletionRoutine, &event, TRUE, TRUE, TRUE); status = IoCallDriver (TargetDeviceObject, newIrp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); } status = newIrp->IoStatus.Status;
if (IoStatus) {
*IoStatus = newIrp->IoStatus; }
IoFreeIrp (newIrp); return status; }
NTSTATUS IdePortGenericCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PKEVENT event = Context;
KeSetEvent( event, EVENT_INCREMENT, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED; } // IdePortSyncSendIrpCompletionRoutine
ULONG IdePortSimpleCheckSum ( IN ULONG PartialSum, IN PVOID SourceVa, IN ULONG Length ) /*++
Routine Description:
Computes a checksum for the supplied virtual address and length
This function comes from Dr. Dobbs Journal, May 1992
Arguments:
PartialSum - The previous partial checksum
SourceVa - Starting address
Length - Length, in bytes, of the range
Return Value:
The checksum value
--*/ { PUSHORT Source;
Source = (PUSHORT) SourceVa; Length = Length / 2;
while (Length--) { PartialSum += *Source++; PartialSum = (PartialSum >> 16) + (PartialSum & 0xFFFF); }
return PartialSum; }
BOOLEAN IdePortInSetup( IN PFDO_EXTENSION FdoExtension ) /*++
--*/ { OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING keyName; HANDLE hKey; ULONG systemSetupInProgress = 0; NTSTATUS status; BOOLEAN textmodeSetup = TRUE;
PAGED_CODE();
RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\setupdd");
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(&hKey, KEY_READ, &objectAttributes);
if (!NT_SUCCESS(status)) {
textmodeSetup = FALSE;
} else {
ZwClose(hKey); }
RtlInitUnicodeString(&keyName,L"\\Registry\\Machine\\System\\setup");
InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(&hKey, KEY_READ, &objectAttributes);
if (NT_SUCCESS(status)) {
//
// Query the data for the key value.
//
RTL_QUERY_REGISTRY_TABLE queryTable[2];
systemSetupInProgress = 0;
RtlZeroMemory(queryTable, sizeof(queryTable));
queryTable->QueryRoutine = NULL; queryTable->Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT; queryTable->Name = L"SystemSetupInProgress"; queryTable->EntryContext = &systemSetupInProgress; queryTable->DefaultType = REG_DWORD; queryTable->DefaultData = &systemSetupInProgress; queryTable->DefaultLength = sizeof (systemSetupInProgress);
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR) hKey, queryTable, NULL, NULL);
ZwClose (hKey);
}
return (textmodeSetup || systemSetupInProgress); }
VOID IdeInitializeFdoList( IN PIDE_FDO_LIST FdoList ) /*++
Routine Description:
Initialize IDE's FDO list.
Arguments:
FdoList - Fdo list to initialize.
Return Value:
None.
--*/ { ASSERT (FdoList != NULL);
//
// This allows this function to be called multiple times. NB: This will
// NOT work correctly if we do not synchronize entries to ATAPI's
// DriverEntry routine. This is done for us by IO manager.
//
if (FdoList->Count == -1) { InitializeListHead (&FdoList->List); FdoList->Count = 0; KeInitializeSpinLock (&FdoList->SpinLock); } }
VOID IdeAddToFdoList ( PIDE_FDO_LIST FdoList, PFDO_EXTENSION FdoExtension ) /*++
Routine Description
Adds the FDO to the global list. A new list is allocated (and the old one is freed) every time an Fdo is inserted into the list. Arguments:
FdoList -
FdoExtension - Return Value:
None. --*/ { KIRQL oldIrql;
KeAcquireSpinLock(&FdoList->SpinLock, &oldIrql); InsertTailList(&FdoList->List, &FdoExtension->NextFdoLink); FdoList->Count++; KeReleaseSpinLock(&FdoList->SpinLock, oldIrql); }
VOID IdeRemoveFromFdoList ( PIDE_FDO_LIST FdoList, PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Remove from the IDE FDO list.
Arguments:
FdoList - Supplies the FDO list to remove from.
FdoExtension - Supplies the FDO extension to remove.
Return Value:
None.
--*/ { KIRQL oldIrql;
KeAcquireSpinLock(&FdoList->SpinLock, &oldIrql);
#if DBG
//
// In CHK builds, we verify that the entry is actually in the list
// before removing it.
//
{ PLIST_ENTRY nextEntry; PFDO_EXTENSION fdoExtension = NULL;
for ( nextEntry = FdoList->List.Flink; nextEntry != &FdoList->List; nextEntry = nextEntry->Flink ) {
fdoExtension = CONTAINING_RECORD (nextEntry, FDO_EXTENSION, NextFdoLink); if (fdoExtension == FdoExtension) { break; } }
//
// Verify that we are trying to remove from a list that we're
// actually on.
//
ASSERT(fdoExtension == FdoExtension); } #endif // DBG
FdoList->Count--; RemoveEntryList(&FdoExtension->NextFdoLink); KeReleaseSpinLock(&FdoList->SpinLock, oldIrql); }
|