/*++ 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 #include #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; iRegistryPath, 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; iModelNumber); 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; jFirmwareRevision); 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); }