//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: util.c // //-------------------------------------------------------------------------- #include "ide.h" #pragma alloc_text(NONPAGE, IdePortChannelEmpty) #pragma alloc_text(PAGE, DigestResourceList) #pragma alloc_text(PAGE, AtapiBuildIoAddress) #pragma alloc_text(PAGE, IdeGetDeviceCapabilities) #pragma alloc_text(NONPAGE, IdePortpWaitOnBusyEx) #pragma alloc_text(PAGE, IdeCreateIdeDirectory) #ifdef DPC_FOR_EMPTY_CHANNEL BOOLEAN IdePortIdentifyDevice( IN PIDE_REGISTERS_1 CmdRegBase, IN PIDE_REGISTERS_2 CtrlRegBase, IN ULONG MaxIdeDevice ) { UCHAR statusByte1; ULONG retryCount=4; BOOLEAN emptyChannel=TRUE; ULONG deviceNumber=0; ULONG i; retryCount = 4; emptyChannel = TRUE; deviceNumber = 0; retryIdentifier: // // Select the master device // SelectIdeDevice(CmdRegBase, deviceNumber, 0); // // write out indentifier to readable and writable io registers // WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE); WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE); // // Check if indentifier can be read back. // if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) || (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) { statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command); DebugPrint((2, "IdePortChannelEmpty: status read back from Master (%x)\n", statusByte1)); if (statusByte1 & IDE_STATUS_BUSY) { i = 0; // // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that // warm boots don't clear. // do { KeStallExecutionProcessor(1000); statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command); DebugPrint((3, "IdePortChannelEmpty: First access to status %x\n", statusByte1)); } while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10); if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) { goto retryIdentifier; } } // // Select slave. // deviceNumber++; SelectIdeDevice(CmdRegBase, deviceNumber, 0); // // write out indentifier to readable and writable io registers // WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE); WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE); // // Check if indentifier can be read back. // if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) || (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) { statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command); DebugPrint((2, "IdePortChannelEmpty: status read back from Slave (%x)\n", statusByte1)); } else { emptyChannel = FALSE; } } else { emptyChannel = FALSE; } deviceNumber++; if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) { goto retryIdentifier; } return emptyChannel; } //IdePortIdentifyDevice ULONG IdePortChannelEmptyQuick ( IN PIDE_REGISTERS_1 CmdRegBase, IN PIDE_REGISTERS_2 CtrlRegBase, IN ULONG MaxIdeDevice, IN PULONG CurrentDevice, IN PULONG moreWait, IN PULONG NoRetry ) { // // try EXECUTE_DIAGNOSTICS. No. // // // statusByte1 needs to be initialized to ff // UCHAR statusByte1=0xff; UCHAR statusByte2; ULONG i; BOOLEAN allStatusBytesAllFs; allStatusBytesAllFs = TRUE; DebugPrint((1, "ChannelEmptyQuick: wait=%d, Device=%d\n", *moreWait, *CurrentDevice)); if (*moreWait) { (*moreWait)--; SelectIdeDevice(CmdRegBase, (*CurrentDevice), 0); IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff); DebugPrint((1, "ATAPI: Status after first retry=%x\n", statusByte1)); if (statusByte1==0xff) { (*CurrentDevice)++; *moreWait=0; } } if (*moreWait && (statusByte1 & IDE_STATUS_BUSY)) { return STATUS_RETRY; } if (!(*NoRetry) && (statusByte1 & IDE_STATUS_BUSY) && ((statusByte1 != 0xfe) && (statusByte1 != 0xff))) { DebugPrint((1, "ATAPI: IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n", statusByte1)); // // channel look hung or busy // // try a hard reset to bring it to idle WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER); // // ATA-2 spec requires a minimum of 5 microsec stall here // KeStallExecutionProcessor (10); WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER); i=*CurrentDevice; SelectIdeDevice(CmdRegBase, i, 0); IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff); if ((statusByte1 & IDE_STATUS_BUSY) && (statusByte1 != 0xff)) { *moreWait=2; //wait for 2 more timer ticks *NoRetry=1; return STATUS_RETRY; } } if (statusByte1 != 0xFF) { allStatusBytesAllFs = FALSE; (*CurrentDevice)++; } for (i=*CurrentDevice; iDriveSelect) != (((i & 0x1) << 4) | 0xA0)) { // // Bad controller. // continue; } } GetStatus(CmdRegBase, statusByte1); DebugPrint((1, "ATAPI:status for device %d after GetStatus=%x\n",i, statusByte1)); if (statusByte1 == 0xff) { continue; } if (statusByte1 == 0xfe) { continue; } IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff); if ((statusByte1 & 0xfe) == 0xfe) { continue; } if (statusByte1 & IDE_STATUS_BUSY) { DebugPrint((1, "ATAPI: Re-init the counts:device=%d, status=%x", i, statusByte1)); *CurrentDevice=i; *moreWait=2; *NoRetry=0; return STATUS_RETRY; } if (statusByte1 != 0xFF) { allStatusBytesAllFs = FALSE; } } if (allStatusBytesAllFs) { // // all status bytes are 0xff, // no controller at this location // return 1; } i=(IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice)) ? 1: 0; return i; }//IdePortChannelEmptyQuick #endif BOOLEAN IdePortChannelEmpty ( IN PIDE_REGISTERS_1 CmdRegBase, IN PIDE_REGISTERS_2 CtrlRegBase, IN ULONG MaxIdeDevice ) /*++ Routine Description: quickly check whether a IDE channel exist at the given io location Arguments: CmdRegBase - command registers CtrlRegBase - control registers MaxIdeDevice - number of max devices Return Value: TRUE - Yes, the channel is empty FALSE - No, the channel is not empty --*/ { UCHAR statusByte1; UCHAR statusByte2; ULONG retryCount; ULONG i; BOOLEAN emptyChannel; ULONG deviceNumber; BOOLEAN allStatusBytesAllFs; allStatusBytesAllFs = TRUE; for (i=0; iDriveSelect) != (((i & 0x1) << 4) | 0xA0)) { // // Bad controller. // continue; } } GetStatus(CmdRegBase, statusByte1); if (statusByte1 == 0xff) { continue; } if (statusByte1 == 0xfe) { continue; } IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff); if ((statusByte1 & IDE_STATUS_BUSY) && ((statusByte1 != 0xfe) && (statusByte1 != 0xff))) { DebugPrint((1, "IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n", statusByte1)); // // channel look hung or busy // // try a hard reset to bring it to idle WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER); // // ATA-2 spec requires a minimum of 5 microsec stall here // KeStallExecutionProcessor (10); WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER); SelectIdeDevice(CmdRegBase, i, 0); IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff); } if (statusByte1 != 0xFF) { allStatusBytesAllFs = FALSE; } } if (allStatusBytesAllFs) { // // all status bytes are 0xff, // no controller at this location // return TRUE; } #ifdef DPC_FOR_EMPTY_CHANNEL return IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice); #endif retryCount = 4; emptyChannel = TRUE; deviceNumber = 0; retryIdentifier: // // Select the master device // SelectIdeDevice(CmdRegBase, deviceNumber, 0); // // write out indentifier to readable and writable io registers // WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE); WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE); // // Check if indentifier can be read back. // if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) || (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) { statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command); DebugPrint((2, "IdePortChannelEmpty: status read back from Master (%x)\n", statusByte1)); if (statusByte1 & IDE_STATUS_BUSY) { i = 0; // // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that // warm boots don't clear. // do { KeStallExecutionProcessor(1000); statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command); DebugPrint((3, "IdePortChannelEmpty: First access to status %x\n", statusByte1)); } while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10); if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) { goto retryIdentifier; } } // // Select slave. // deviceNumber++; SelectIdeDevice(CmdRegBase, deviceNumber, 0); // // write out indentifier to readable and writable io registers // WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE); WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE); // // Check if indentifier can be read back. // if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) || (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) { statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command); DebugPrint((2, "IdePortChannelEmpty: status read back from Slave (%x)\n", statusByte1)); } else { emptyChannel = FALSE; } } else { emptyChannel = FALSE; } deviceNumber++; if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) { goto retryIdentifier; } return emptyChannel; } //IdePortChannelEmpty NTSTATUS DigestResourceList ( IN OUT PIDE_RESOURCE IdeResource, IN PCM_RESOURCE_LIST ResourceList, OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *IrqPartialDescriptors ) { NTSTATUS status; PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList; PCM_PARTIAL_RESOURCE_LIST partialResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors; ULONG resourceListSize; ULONG i; ULONG j; BOOLEAN foundCommandBase; BOOLEAN foundControlBase; BOOLEAN foundIrqLevel; BOOLEAN resourceIsCommandPort; BOOLEAN AtdiskPrimaryClaimed; BOOLEAN AtdiskSecondaryClaimed; PHYSICAL_ADDRESS tranlatedAddress; IDE_REGISTERS_1 baseIoAddress1; ULONG baseIoAddress1Length; fullResourceList = ResourceList->List; resourceListSize = 0; DebugPrint ((5, "IdePort: DigestResourceList()\n")); foundCommandBase = FALSE; foundControlBase = FALSE; foundIrqLevel = FALSE; *IrqPartialDescriptors = NULL; status = STATUS_SUCCESS; AtdiskPrimaryClaimed = FALSE; AtdiskSecondaryClaimed = FALSE; for (i = 0; (i < ResourceList->Count) && NT_SUCCESS(status); i++) { partialResourceList = &(fullResourceList->PartialResourceList); partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors; AtapiBuildIoAddress ((PUCHAR)partialDescriptors[0].u.Port.Start.QuadPart, 0, &baseIoAddress1, NULL, &baseIoAddress1Length, NULL, NULL, NULL); for (j = 0; (j < partialResourceList->Count) && NT_SUCCESS(status); j++) { resourceIsCommandPort = FALSE; if (!Is98LegacyIde(&baseIoAddress1)) { if (((partialDescriptors[j].Type == CmResourceTypePort) || (partialDescriptors[j].Type == CmResourceTypeMemory)) && (partialDescriptors[j].u.Port.Length == baseIoAddress1Length)) { resourceIsCommandPort = TRUE; } } else { if (((partialDescriptors[j].Type == CmResourceTypePort) || (partialDescriptors[j].Type == CmResourceTypeMemory)) && (partialDescriptors[j].u.Port.Start.QuadPart == IDE_NEC98_COMMAND_PORT_ADDRESS)){ resourceIsCommandPort = TRUE; } else if (((partialDescriptors[j].Type == CmResourceTypePort) || (partialDescriptors[j].Type == CmResourceTypeMemory)) && (partialDescriptors[j].u.Port.Start.QuadPart != IDE_NEC98_COMMAND_PORT_ADDRESS) && (partialDescriptors[j].u.Port.Start.QuadPart != (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10C))) { // // This is not the base port address for Legacy ide on NEC98; // continue; } } if (resourceIsCommandPort) { if (foundCommandBase) { // // got this before, just ignore it // // status = STATUS_INVALID_PARAMETER; } else { if (!Is98LegacyIde(&baseIoAddress1)) { if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_PRIMARY_ADDRESS) { AtdiskPrimaryClaimed = TRUE; } else if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_SECONDARY_ADDRESS) { AtdiskSecondaryClaimed = TRUE; } } else { AtdiskPrimaryClaimed = TRUE; AtdiskSecondaryClaimed = TRUE; } if (partialDescriptors[j].Type == CmResourceTypePort) { IdeResource->TranslatedCommandBaseAddress = (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart; IdeResource->CommandBaseAddressSpace = IO_SPACE; } else if (partialDescriptors[j].Type == CmResourceTypeMemory) { IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace( partialDescriptors[j].u.Port.Start, baseIoAddress1Length, FALSE); IdeResource->CommandBaseAddressSpace = MEMORY_SPACE; } else { IdeResource->TranslatedCommandBaseAddress = FALSE; ASSERT (FALSE); } if (IdeResource->TranslatedCommandBaseAddress) { foundCommandBase = TRUE; } else { status = STATUS_INVALID_PARAMETER; } } } else if (((partialDescriptors[j].Type == CmResourceTypePort) || (partialDescriptors[j].Type == CmResourceTypeMemory)) && ((partialDescriptors[j].u.Port.Length == 1) || (partialDescriptors[j].u.Port.Length == 2) || (partialDescriptors[j].u.Port.Length == 4))) { if (foundControlBase) { // // got this before, just ignore it // // status = STATUS_INVALID_PARAMETER; } else { PHYSICAL_ADDRESS p; // // Probably the control block register // p = partialDescriptors[j].u.Port.Start; if (partialDescriptors[j].u.Port.Length == 4) { p.QuadPart += 2; } if (partialDescriptors[j].Type == CmResourceTypePort) { IdeResource->TranslatedControlBaseAddress = (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart; IdeResource->ControlBaseAddressSpace = IO_SPACE; } else if (partialDescriptors[j].Type == CmResourceTypeMemory) { IdeResource->TranslatedControlBaseAddress = MmMapIoSpace( p, 1, FALSE); IdeResource->ControlBaseAddressSpace = MEMORY_SPACE; } else { IdeResource->TranslatedControlBaseAddress = FALSE; ASSERT (FALSE); } if (IdeResource->TranslatedControlBaseAddress) { foundControlBase = TRUE; } else { status = STATUS_INVALID_PARAMETER; } } } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) { if (foundIrqLevel) { // // got this before, just ignore it // // status = STATUS_INVALID_PARAMETER; } else { // // Probably the device IRQ // // // May want to disable device interrupt here // // // Save interrupt level. // IdeResource->InterruptLevel = partialDescriptors[j].u.Interrupt.Level; IdeResource->InterruptMode = partialDescriptors[j].Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive; *IrqPartialDescriptors = partialDescriptors + j; foundIrqLevel = TRUE; } } else if (((partialDescriptors[j].Type == CmResourceTypePort) || (partialDescriptors[j].Type == CmResourceTypeMemory)) && ((partialDescriptors[j].u.Port.Length >= 16) && (partialDescriptors[j].u.Port.Length <= 32)) ) { if (foundControlBase || foundCommandBase) { // // got this before, just ignore it // // status = STATUS_INVALID_PARAMETER; } else { PHYSICAL_ADDRESS ctrlAddr; // // Probably a pcmcia device that has its command and control // registers lumped into one I/O range // // We are guessing the control block register is the second // from the last i/o space. Some standard! // ctrlAddr.QuadPart = partialDescriptors[j].u.Port.Start.QuadPart + partialDescriptors[j].u.Port.Length - 2; if (partialDescriptors[j].Type == CmResourceTypePort) { IdeResource->TranslatedCommandBaseAddress = (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart; IdeResource->CommandBaseAddressSpace = IO_SPACE; IdeResource->TranslatedControlBaseAddress = (PUCHAR)(ULONG_PTR)ctrlAddr.QuadPart; IdeResource->ControlBaseAddressSpace = IO_SPACE; } else if (partialDescriptors[j].Type == CmResourceTypeMemory) { IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace( partialDescriptors[j].u.Port.Start, baseIoAddress1Length, FALSE); IdeResource->CommandBaseAddressSpace = MEMORY_SPACE; IdeResource->TranslatedControlBaseAddress = MmMapIoSpace( ctrlAddr, 1, FALSE); IdeResource->ControlBaseAddressSpace = MEMORY_SPACE; } else { IdeResource->TranslatedCommandBaseAddress = FALSE; IdeResource->TranslatedControlBaseAddress = FALSE; ASSERT (FALSE); } if (IdeResource->TranslatedCommandBaseAddress) { foundCommandBase = TRUE; } else { status = STATUS_INVALID_PARAMETER; } if (IdeResource->TranslatedControlBaseAddress) { foundControlBase = TRUE; } else { status = STATUS_INVALID_PARAMETER; } } } } fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + partialResourceList->Count); } if (foundCommandBase && foundControlBase && NT_SUCCESS(status)) { IdeResource->AtdiskPrimaryClaimed = AtdiskPrimaryClaimed; IdeResource->AtdiskSecondaryClaimed = AtdiskSecondaryClaimed; return STATUS_SUCCESS; } else { DebugPrint((0, "IdePort: pnp manager gave me bad ressources!\n")); if (foundCommandBase && (IdeResource->CommandBaseAddressSpace == MEMORY_SPACE)) { MmUnmapIoSpace ( IdeResource->TranslatedCommandBaseAddress, baseIoAddress1Length ); IdeResource->TranslatedCommandBaseAddress = 0; } if (foundControlBase && (IdeResource->ControlBaseAddressSpace == MEMORY_SPACE)) { MmUnmapIoSpace ( IdeResource->TranslatedControlBaseAddress, 1 ); IdeResource->TranslatedControlBaseAddress = 0; } return STATUS_INVALID_PARAMETER; } } // DigestResourceList VOID AtapiBuildIoAddress ( IN PUCHAR CmdBaseAddress, IN PUCHAR CtrlBaseAddress, OUT PIDE_REGISTERS_1 BaseIoAddress1, OUT PIDE_REGISTERS_2 BaseIoAddress2, OUT PULONG BaseIoAddress1Length, OUT PULONG BaseIoAddress2Length, OUT PULONG MaxIdeDevice, OUT PULONG MaxIdeTargetId ) { PUCHAR baseIoAddress; BOOLEAN LegacyIdeOfNec98; LegacyIdeOfNec98 = FALSE; if (IsNEC_98) { if (CmdBaseAddress == (PUCHAR)IDE_NEC98_COMMAND_PORT_ADDRESS) { LegacyIdeOfNec98 = TRUE; } } if (!LegacyIdeOfNec98) { // // Build command registers. // baseIoAddress = CmdBaseAddress; if (BaseIoAddress1) { BaseIoAddress1->RegistersBaseAddress = baseIoAddress; BaseIoAddress1->Data = (PUSHORT)baseIoAddress; BaseIoAddress1->Error = baseIoAddress + 1; BaseIoAddress1->BlockCount = baseIoAddress + 2; BaseIoAddress1->BlockNumber = baseIoAddress + 3; BaseIoAddress1->CylinderLow = baseIoAddress + 4; BaseIoAddress1->CylinderHigh = baseIoAddress + 5; BaseIoAddress1->DriveSelect = baseIoAddress + 6; BaseIoAddress1->Command = baseIoAddress + 7; } // // Build control registers. // baseIoAddress = CtrlBaseAddress; if (BaseIoAddress2) { BaseIoAddress2->RegistersBaseAddress = baseIoAddress; BaseIoAddress2->DeviceControl = baseIoAddress; BaseIoAddress2->DriveAddress = baseIoAddress + 1; } if (BaseIoAddress1Length) { *BaseIoAddress1Length = 8; } if (BaseIoAddress2Length) { *BaseIoAddress2Length = 1; } if (MaxIdeDevice) { *MaxIdeDevice = MAX_IDE_DEVICE; } if (MaxIdeTargetId) { *MaxIdeTargetId = MAX_IDE_DEVICE; } } else { // // Build command registers. // baseIoAddress = CmdBaseAddress; if (BaseIoAddress1) { BaseIoAddress1->RegistersBaseAddress = baseIoAddress; BaseIoAddress1->Data = (PUSHORT)baseIoAddress; BaseIoAddress1->Error = baseIoAddress + 2; BaseIoAddress1->BlockCount = baseIoAddress + 4; BaseIoAddress1->BlockNumber = baseIoAddress + 6; BaseIoAddress1->CylinderLow = baseIoAddress + 8; BaseIoAddress1->CylinderHigh = baseIoAddress + 10; BaseIoAddress1->DriveSelect = baseIoAddress + 12; BaseIoAddress1->Command = baseIoAddress + 14; } // // Build control registers. // baseIoAddress = CtrlBaseAddress; if (BaseIoAddress2) { BaseIoAddress2->RegistersBaseAddress = baseIoAddress; BaseIoAddress2->DeviceControl = baseIoAddress; BaseIoAddress2->DriveAddress = baseIoAddress + 2; } if (BaseIoAddress1Length) { *BaseIoAddress1Length = 1; } if (BaseIoAddress2Length) { *BaseIoAddress2Length = 1; } if (MaxIdeDevice) { *MaxIdeDevice = MAX_IDE_DEVICE * MAX_IDE_LINE; } if (MaxIdeTargetId) { *MaxIdeTargetId = MAX_IDE_DEVICE * MAX_IDE_LINE; } } return; } // AtapiBuildIoAddress NTSTATUS IdePortpWaitOnBusyEx ( IN PIDE_REGISTERS_1 CmdRegBase, IN OUT PUCHAR Status, IN UCHAR BadStatus #if DBG , IN PCSTR FileName, IN ULONG LineNumber #endif ) { UCHAR status; ULONG sec; ULONG i; for (sec=0; sec<2; sec++) { /**/ /* one second loop */ /**/ for (i=0; i<200000; i++) { GetStatus(CmdRegBase, status); if (status == BadStatus) { break; } else if (status & IDE_STATUS_BUSY) { KeStallExecutionProcessor(5); continue; } else { break; } } if (status == BadStatus) { break; } else if (status & IDE_STATUS_BUSY) { DebugPrint ((1, "ATAPI: after 1 sec wait, device is still busy with 0x%x status = 0x%x\n", CmdRegBase->RegistersBaseAddress, (ULONG) (status))); } else { break; } } *Status = status; if ((status & IDE_STATUS_BUSY) && (status != BadStatus)) { DebugPrint ((0, "WaitOnBusy failed in %s line %u. 0x%x status = 0x%x\n", FileName, LineNumber, CmdRegBase->RegistersBaseAddress, (ULONG) (status))); return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } // IdePortpWaitOnBusyEx static PVOID IdeDirectory = NULL; VOID IdeCreateIdeDirectory( VOID ) { UNICODE_STRING unicodeDirectoryName; OBJECT_ATTRIBUTES objectAttributes; HANDLE directory; NTSTATUS status; PAGED_CODE(); RtlInitUnicodeString( &unicodeDirectoryName, DEVICE_OJBECT_BASE_NAME); InitializeObjectAttributes( &objectAttributes, &unicodeDirectoryName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); status = ZwCreateDirectoryObject(&directory, DIRECTORY_ALL_ACCESS, &objectAttributes); if(NT_SUCCESS(status)) { ObReferenceObjectByHandle(directory, FILE_READ_ATTRIBUTES, NULL, KernelMode, &IdeDirectory, NULL); ZwClose(directory); } return; } NTSTATUS IdeGetDeviceCapabilities( IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_CAPABILITIES DeviceCapabilities ) /*++ Routine Description: This routine sends the get capabilities irp to the given stack Arguments: DeviceObject A device object in the stack whose capabilities we want DeviceCapabilites Where to store the answer Return Value: NTSTATUS --*/ { IO_STATUS_BLOCK ioStatus; KEVENT pnpEvent; NTSTATUS status; PDEVICE_OBJECT targetObject; PIO_STACK_LOCATION irpStack; PIRP pnpIrp; PAGED_CODE(); // // Initialize the capabilities that we will send down // RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) ); DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES); DeviceCapabilities->Version = 1; DeviceCapabilities->Address = -1; DeviceCapabilities->UINumber = -1; // // Initialize the event // KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE ); // // Get the irp that we will send the request to // targetObject = IoGetAttachedDeviceReference( DeviceObject ); // // Build an Irp // pnpIrp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, targetObject, NULL, 0, NULL, &pnpEvent, &ioStatus ); if (pnpIrp == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto IdeGetDeviceCapabilitiesExit; } // // Pnp Irps all begin life as STATUS_NOT_SUPPORTED; // pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; pnpIrp->IoStatus.Information = 0; // // Get the top of stack // irpStack = IoGetNextIrpStackLocation( pnpIrp ); if (irpStack == NULL) { status = STATUS_INVALID_PARAMETER; goto IdeGetDeviceCapabilitiesExit; } // // Set the top of stack // RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) ); irpStack->MajorFunction = IRP_MJ_PNP; irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities; // // Make sure that there are no completion routines set // IoSetCompletionRoutine( pnpIrp, NULL, NULL, FALSE, FALSE, FALSE ); // // Call the driver // status = IoCallDriver( targetObject, pnpIrp ); if (status == STATUS_PENDING) { // // Block until the irp comes back // KeWaitForSingleObject( &pnpEvent, Executive, KernelMode, FALSE, NULL ); status = ioStatus.Status; } IdeGetDeviceCapabilitiesExit: // // Done with reference // ObDereferenceObject( targetObject ); // // Done // return status; }