//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: pciidex.c // //-------------------------------------------------------------------------- #include "pciidex.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, DriverEntry) #pragma alloc_text(PAGE, PciIdeXInitialize) #pragma alloc_text(PAGE, PciIdeXAlwaysStatusSuccessIrp) #pragma alloc_text(PAGE, DispatchPnp) #pragma alloc_text(PAGE, DispatchWmi) #pragma alloc_text(PAGE, PassDownToNextDriver) #pragma alloc_text(PAGE, PciIdeInternalDeviceIoControl) #pragma alloc_text(PAGE, PciIdeXGetDeviceParameter) #pragma alloc_text(PAGE, PciIdeXGetDeviceParameterEx) #pragma alloc_text(PAGE, PciIdeXRegQueryRoutine) #pragma alloc_text(PAGE, PciIdeUnload) #pragma alloc_text(PAGE, PciIdeXSyncSendIrp) #pragma alloc_text(NONPAGE, PciIdeXGetBusData) #pragma alloc_text(NONPAGE, PciIdeXSetBusData) #pragma alloc_text(NONPAGE, DispatchPower) #pragma alloc_text(NONPAGE, NoSupportIrp) #pragma alloc_text(NONPAGE, PciIdeBusData) #pragma alloc_text(NONPAGE, PciIdeBusDataCompletionRoutine) #pragma alloc_text(NONPAGE, PciIdeXSyncSendIrpCompletionRoutine) #if DBG #pragma alloc_text(PAGE, PciIdeXSaveDeviceParameter) #endif // DBG #endif // ALLOC_PRAGMA // // get the share code // #include "..\share\util.c" #if DBG ULONG PciIdeDebug = 0; UCHAR DebugBuffer[128 * 6]; VOID PciIdeDebugPrint( ULONG DebugPrintLevel, PCCHAR DebugMessage, ... ) /*++ Routine Description: Debug print for all SCSI drivers Arguments: Debug print level between 0 and 3, with 3 being the most verbose. Return Value: None --*/ { va_list ap; va_start(ap, DebugMessage); if (DebugPrintLevel <= PciIdeDebug) { vsprintf(DebugBuffer, DebugMessage, ap); //DbgPrint(DebugBuffer); #if 1 DbgPrintEx(DPFLTR_PCIIDE_ID, DPFLTR_INFO_LEVEL, DebugBuffer ); #endif } va_end(ap); } // end DebugPrint() #else VOID PciIdeDebugPrint( ULONG DebugPrintLevel, PCCHAR DebugMessage, ... ) { return; } #endif // // PnP Dispatch Table // PDRIVER_DISPATCH FdoPnpDispatchTable[NUM_PNP_MINOR_FUNCTION]; PDRIVER_DISPATCH PdoPnpDispatchTable[NUM_PNP_MINOR_FUNCTION]; // // Po Dispatch Table // PDRIVER_DISPATCH FdoPowerDispatchTable[NUM_POWER_MINOR_FUNCTION]; PDRIVER_DISPATCH PdoPowerDispatchTable[NUM_POWER_MINOR_FUNCTION]; // // Wmi Dispatch Table // PDRIVER_DISPATCH FdoWmiDispatchTable[NUM_WMI_MINOR_FUNCTION]; PDRIVER_DISPATCH PdoWmiDispatchTable[NUM_WMI_MINOR_FUNCTION]; NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { PAGED_CODE(); return STATUS_SUCCESS; } // DriverEntry NTSTATUS PciIdeXInitialize( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath, IN PCONTROLLER_PROPERTIES PciIdeGetControllerProperties, IN ULONG ExtensionSize ) { NTSTATUS status; PDRIVER_EXTENSION driverExtension; PDRIVER_OBJECT_EXTENSION driverObjectExtension; ULONG i; PAGED_CODE(); status = IoAllocateDriverObjectExtension( DriverObject, DRIVER_OBJECT_EXTENSION_ID, sizeof (DRIVER_OBJECT_EXTENSION), &driverObjectExtension ); if (!NT_SUCCESS(status)) { DebugPrint ((0, "PciIde: Unable to create driver extension\n")); return status; } ASSERT (driverObjectExtension); driverObjectExtension->PciIdeGetControllerProperties = PciIdeGetControllerProperties; driverObjectExtension->ExtensionSize = ExtensionSize; // // some entry point init. // DriverObject->DriverUnload = PciIdeUnload; DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = PciIdeInternalDeviceIoControl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi; driverExtension = DriverObject->DriverExtension; driverExtension->AddDevice = ControllerAddDevice; // // FDO PnP Dispatch Table // for (i=0; iIoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } // PciIdeXAlwaysStatusSuccessIrp NTSTATUS DispatchPower( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { 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 ((2, "PciIde: %s %d got %s\n", doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PCHANPDO_EXTENSION) doExtension)->ChannelNumber, IdeDebugPowerIrpName[thisIrpSp->MinorFunction])); switch (thisIrpSp->MinorFunction) { case IRP_MN_WAIT_WAKE: DebugPrint ((2, "IRP_MN_WAIT_WAKE\n")); break; case IRP_MN_POWER_SEQUENCE: DebugPrint ((2, "IRP_MN_POWER_SEQUENCE\n")); break; case IRP_MN_SET_POWER: DebugPrint ((2, "IRP_MN_SET_POWER\n")); break; case IRP_MN_QUERY_POWER: DebugPrint ((2, "IRP_MN_QUERY_POWER\n")); break; default: DebugPrint ((2, "IRP_MN_0x%x\n", thisIrpSp->MinorFunction)); break; } // Should always pass the irp down. It is taken care by the corresponding dispatch // funtion. // if (thisIrpSp->MinorFunction < NUM_POWER_MINOR_FUNCTION) { status = doExtension->PowerDispatchTable[thisIrpSp->MinorFunction] (DeviceObject, Irp); } else { DebugPrint ((1, "ATAPI: Power Dispatch Table too small\n" )); status = doExtension->DefaultDispatch (DeviceObject, Irp); } return status; } // DispatchPower NTSTATUS DispatchPnp( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++ Routine Description: This routine handles all IRP_MJ_PNP_POWER IRPs for this driver. 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; PAGED_CODE(); // // 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 ((2, "PciIde: %s %d got %s\n", doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PCHANPDO_EXTENSION) doExtension)->ChannelNumber, 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; } // DispatchPnp NTSTATUS DispatchWmi( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++ Routine Description: This routine handles all IRP_MJ_SYSTEM_CONTROL (WMI) IRPs for this driver. 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; PAGED_CODE(); // // 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 ((2, "PciIde: %s %d got %s\n", doExtension->AttacheeDeviceObject ? "FDO" : "PDO", doExtension->AttacheeDeviceObject ? 0 : ((PCHANPDO_EXTENSION) doExtension)->ChannelNumber, IdeDebugWmiIrpName[thisIrpSp->MinorFunction])); if (thisIrpSp->MinorFunction < NUM_WMI_MINOR_FUNCTION) { status = doExtension->WmiDispatchTable[thisIrpSp->MinorFunction] (DeviceObject, Irp); } else { DebugPrint ((1, "ATAPI: WMI Dispatch Table too small\n" )); status = doExtension->DefaultDispatch (DeviceObject, Irp); } return status; } // DispatchWmi() NTSTATUS PassDownToNextDriver ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PDEVICE_EXTENSION_HEADER deviceExtensionHeader; NTSTATUS status; PIO_STACK_LOCATION thisIrpSp; PAGED_CODE(); thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); deviceExtensionHeader = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension; ASSERT (deviceExtensionHeader->AttacheeDeviceObject); if (thisIrpSp->MajorFunction == IRP_MJ_POWER) { // // call PoStartNextPowerIrp before completing a power irp // PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation (Irp); status = PoCallDriver (deviceExtensionHeader->AttacheeDeviceObject, Irp); } else { // // Not a power irp // IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (deviceExtensionHeader->AttacheeDeviceObject, Irp); } return status; } // PassDownToNextDriver NTSTATUS StatusSuccessAndPassDownToNextDriver ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PDEVICE_EXTENSION_HEADER deviceExtensionHeader; PAGED_CODE(); IoSkipCurrentIrpStackLocation (Irp); deviceExtensionHeader = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension; Irp->IoStatus.Status = STATUS_SUCCESS; return IoCallDriver (deviceExtensionHeader->AttacheeDeviceObject, Irp); } // PassDownToNextDriver NTSTATUS NoSupportIrp ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp; NTSTATUS status = Irp->IoStatus.Status; thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); // // You should call PoStartNextPowerIrp before completing a power irp // if (thisIrpSp->MajorFunction == IRP_MJ_POWER) { PoStartNextPowerIrp (Irp); } DebugPrint (( 1, "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; } // NoSupportIrp NTSTATUS PciIdeXGetBusData( IN PVOID DeviceExtension, IN PVOID Buffer, IN ULONG ConfigDataOffset, IN ULONG BufferLength ) { PCTRLFDO_EXTENSION fdoExtension = ((PCTRLFDO_EXTENSION) DeviceExtension) - 1; return PciIdeBusData( fdoExtension, Buffer, ConfigDataOffset, BufferLength, TRUE ); } // PciIdeXGetBusData NTSTATUS PciIdeXSetBusData( IN PVOID DeviceExtension, IN PVOID Buffer, IN PVOID DataMask, IN ULONG ConfigDataOffset, IN ULONG BufferLength ) { PCTRLFDO_EXTENSION fdoExtension = ((PCTRLFDO_EXTENSION) DeviceExtension) - 1; NTSTATUS status; PUCHAR pciData; KIRQL currentIrql; pciData = ExAllocatePool (NonPagedPool, BufferLength); if (pciData == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } KeAcquireSpinLock( &fdoExtension->PciConfigDataLock, ¤tIrql); // // get the current values // status = PciIdeBusData( fdoExtension, pciData, ConfigDataOffset, BufferLength, TRUE ); if (NT_SUCCESS(status)) { ULONG i; PUCHAR dataMask = (PUCHAR) DataMask; PUCHAR newData = (PUCHAR) Buffer; for (i=0; iPciConfigDataLock, currentIrql); ExFreePool (pciData); return status; } // PciIdeXSetBusData NTSTATUS PciIdeBusData( IN PCTRLFDO_EXTENSION FdoExtension, IN OUT PVOID Buffer, IN ULONG ConfigDataOffset, IN ULONG BufferLength, IN BOOLEAN ReadConfigData ) { ULONG byteTransferred; PGET_SET_DEVICE_DATA BusDataFunction; if (ReadConfigData) { BusDataFunction = FdoExtension->BusInterface.GetBusData; } else { BusDataFunction = FdoExtension->BusInterface.SetBusData; } // if (!BusDataFunction) { // DebugPrint((0, "PCIIDEX: ERROR: NULL BusDataFunction\n")); // return STATUS_UNSUCCESSFUL; //} byteTransferred = BusDataFunction ( FdoExtension->BusInterface.Context, PCI_WHICHSPACE_CONFIG, Buffer, ConfigDataOffset, BufferLength ); if (byteTransferred != BufferLength) { return STATUS_UNSUCCESSFUL; } else { return STATUS_SUCCESS; } } // PciIdeBusData NTSTATUS PciIdeBusDataCompletionRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) { PIO_STATUS_BLOCK ioStatus = (PIO_STATUS_BLOCK) Context; PKEVENT event; ioStatus->Status = Irp->IoStatus.Status; event = (PKEVENT) ioStatus->Information; KeSetEvent (event, 0, FALSE); IoFreeIrp (Irp); return STATUS_MORE_PROCESSING_REQUIRED; } // PciIdeBusDataCompletionRoutine NTSTATUS PciIdeInternalDeviceIoControl ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PDEVICE_EXTENSION_HEADER DoExtensionHeader; NTSTATUS status; PAGED_CODE(); DoExtensionHeader = DeviceObject->DeviceExtension; if (DoExtensionHeader->AttacheeDeviceObject == NULL) { // // PDO // status = ChannelInternalDeviceIoControl ( DeviceObject, Irp ); } else { // // FDO // status = Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } return status; } // PciIdeInternalDeviceIoControl NTSTATUS PciIdeXRegQueryRoutine ( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) { PVOID *parameterValue = EntryContext; PAGED_CODE(); if (ValueType == REG_MULTI_SZ) { *parameterValue = ExAllocatePool(PagedPool, ValueLength); if (*parameterValue) { RtlMoveMemory(*parameterValue, ValueData, ValueLength); return STATUS_SUCCESS; } } else if (ValueType == REG_DWORD) { PULONG ulongValue; ulongValue = (PULONG) parameterValue; *ulongValue = *((PULONG) ValueData); return STATUS_SUCCESS; } return STATUS_UNSUCCESSFUL; } NTSTATUS PciIdeXGetDeviceParameterEx ( IN PDEVICE_OBJECT DeviceObject, IN PWSTR ParameterName, IN OUT PVOID *ParameterValue ) /*++ Routine Description: retrieve a devnode registry parameter Arguments: FdoExtension - FDO Extension ParameterName - parameter name to look up ParameterValuse - default parameter value Return Value: NT Status --*/ { NTSTATUS status; HANDLE deviceParameterHandle; RTL_QUERY_REGISTRY_TABLE queryTable[2]; ULONG i; ULONG flag; PAGED_CODE(); *ParameterValue = NULL; for (i=0; i<2; i++) { if (i == 0) { flag = PLUGPLAY_REGKEY_DRIVER | PLUGPLAY_REGKEY_CURRENT_HWPROFILE; } else { flag = PLUGPLAY_REGKEY_DRIVER; } // // open the given parameter // status = IoOpenDeviceRegistryKey(DeviceObject, flag, KEY_READ, &deviceParameterHandle); if(!NT_SUCCESS(status)) { continue; } RtlZeroMemory(queryTable, sizeof(queryTable)); queryTable->QueryRoutine = PciIdeXRegQueryRoutine; queryTable->Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; queryTable->Name = ParameterName; queryTable->EntryContext = ParameterValue; queryTable->DefaultType = REG_NONE; queryTable->DefaultData = NULL; queryTable->DefaultLength = 0; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR) deviceParameterHandle, queryTable, NULL, NULL); if (!NT_SUCCESS(status)) { *ParameterValue = NULL; } // // close what we open // ZwClose(deviceParameterHandle); if (NT_SUCCESS(status)) { break; } } return status; } // PciIdeXGetDeviceParameter NTSTATUS PciIdeXGetDeviceParameter ( IN PDEVICE_OBJECT DeviceObject, IN PWSTR ParameterName, IN OUT PULONG ParameterValue ) /*++ Routine Description: retrieve a devnode registry parameter Arguments: FdoExtension - FDO Extension ParameterName - parameter name to look up ParameterValuse - default parameter value Return Value: NT Status --*/ { NTSTATUS status; HANDLE deviceParameterHandle; RTL_QUERY_REGISTRY_TABLE queryTable[2]; ULONG defaultParameterValue; ULONG i; ULONG flag; PAGED_CODE(); for (i=0; i<2; i++) { if (i == 0) { flag = PLUGPLAY_REGKEY_DRIVER | PLUGPLAY_REGKEY_CURRENT_HWPROFILE; } else { flag = PLUGPLAY_REGKEY_DRIVER; } // // open the given parameter // status = IoOpenDeviceRegistryKey(DeviceObject, flag, KEY_READ, &deviceParameterHandle); if(!NT_SUCCESS(status)) { continue; } RtlZeroMemory(queryTable, sizeof(queryTable)); defaultParameterValue = *ParameterValue; queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; queryTable->Name = ParameterName; queryTable->EntryContext = ParameterValue; queryTable->DefaultType = REG_NONE; queryTable->DefaultData = NULL; queryTable->DefaultLength = 0; status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PWSTR) deviceParameterHandle, queryTable, NULL, NULL); if (!NT_SUCCESS(status)) { *ParameterValue = defaultParameterValue; } // // close what we open // ZwClose(deviceParameterHandle); if (NT_SUCCESS(status)) { break; } } return status; } // PciIdeXGetDeviceParameter VOID PciIdeUnload( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: get ready to be unloaded Arguments: DriverObject - the driver being unloaded Return Value: none --*/ { PAGED_CODE(); DebugPrint ((1, "PciIde: unloading...\n")); ASSERT (DriverObject->DeviceObject == NULL); return; } // PciIdeUnload NTSTATUS PciIdeXSyncSendIrp ( 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); PAGED_CODE(); // // Allocate an IRP for below // newIrp = IoAllocateIrp (TargetDeviceObject->StackSize, FALSE); // Get stack size from PDO if (newIrp == NULL) { DebugPrint ((0, "PciIdeXSyncSendIrp: 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, PciIdeXSyncSendIrpCompletionRoutine, &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; } // PciIdeXSyncSendIrp NTSTATUS PciIdeXSyncSendIrpCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PKEVENT event = Context; KeSetEvent( event, EVENT_INCREMENT, FALSE ); return STATUS_MORE_PROCESSING_REQUIRED; } // IdePortSyncSendIrpCompletionRoutine #if DBG NTSTATUS PciIdeXSaveDeviceParameter ( IN PVOID DeviceExtension, IN PWSTR ParameterName, IN ULONG ParameterValue ) /*++ Routine Description: save a devnode registry parameter Arguments: FdoExtension - FDO Extension ParameterName - parameter name to save ParameterValuse - parameter value to save Return Value: NT Status --*/ { NTSTATUS status; HANDLE deviceParameterHandle; PCTRLFDO_EXTENSION fdoExtension = ((PCTRLFDO_EXTENSION) DeviceExtension) - 1; PAGED_CODE(); // // open the given parameter // status = IoOpenDeviceRegistryKey(fdoExtension->AttacheePdo, PLUGPLAY_REGKEY_DRIVER, KEY_WRITE, &deviceParameterHandle); if(!NT_SUCCESS(status)) { DebugPrint((1, "PciIdeXSaveDeviceParameter: IoOpenDeviceRegistryKey() returns 0x%x\n", status)); return status; } // // write the parameter value // status = RtlWriteRegistryValue( RTL_REGISTRY_HANDLE, (PWSTR) deviceParameterHandle, ParameterName, REG_DWORD, &ParameterValue, sizeof (ParameterValue) ); if(!NT_SUCCESS(status)) { DebugPrint((1, "PciIdeXSaveDeviceParameter: RtlWriteRegistryValue() returns 0x%x\n", status)); } // // close what we open // ZwClose(deviceParameterHandle); return status; } // IdePortSaveDeviceParameter #endif // DBG