mirror of
https://github.com/reactos/reactos.git
synced 2026-05-25 08:39:58 +08:00
[PCIIDEX] Add DMA support
CORE-17256
This commit is contained in:
committed by
Carl J. Bialorucki
parent
5418987cb8
commit
ae2827f481
17
drivers/storage/ide/legide/CMakeLists.txt
Normal file
17
drivers/storage/ide/legide/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
add_library(legide MODULE legide.c legide.rc)
|
||||
set_module_type(legide kernelmodedriver)
|
||||
|
||||
if(MSVC)
|
||||
# Required for NT5.x pciidex.sys
|
||||
target_link_options(legide PRIVATE /SECTION:.rsrc,!D)
|
||||
else()
|
||||
add_custom_command(
|
||||
TARGET legide POST_BUILD
|
||||
COMMAND native-pefixup --section:.rsrc,!D $<TARGET_FILE:legide>
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_importlibs(legide pciidex ntoskrnl hal)
|
||||
add_cd_file(TARGET legide DESTINATION reactos/system32/drivers NO_CAB FOR all)
|
||||
add_registry_inf(legide_reg.inf)
|
||||
850
drivers/storage/ide/legide/legide.c
Normal file
850
drivers/storage/ide/legide/legide.c
Normal file
@@ -0,0 +1,850 @@
|
||||
/*
|
||||
* PROJECT: Legacy PATA Bus Enumerator Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Main file
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This driver detects non-PnP PATA controllers in the system.
|
||||
* The legacy PATA device detection should be done after PCI bus enumeration,
|
||||
* therefore this logic is implemented in a separate kernel-mode driver.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <ide.h>
|
||||
#include <ata.h>
|
||||
#include <scsi.h>
|
||||
#include <reactos/drivers/ata/ata_shared.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define ATAPORT_TAG 'PedI'
|
||||
|
||||
#define IDE_DRIVE_SELECT 0xA0
|
||||
|
||||
#define ATA_READ(Port) READ_PORT_UCHAR((Port))
|
||||
#define ATA_WRITE(Port, Value) WRITE_PORT_UCHAR((Port), (Value))
|
||||
#define ATA_IO_WAIT() KeStallExecutionProcessor(1)
|
||||
|
||||
#define ATA_TIME_BUSY_SELECT 3000 // 30 ms
|
||||
#define ATA_TIME_BUSY_IDENTIFY 500000 // 5 s
|
||||
#define ATA_TIME_DRQ_CLEAR 1000 // 10 ms
|
||||
#define ATA_TIME_RESET_SELECT 200000 // 2 s
|
||||
#define ATA_TIME_BUSY_RESET 1000000 // 10 s
|
||||
|
||||
typedef struct _ATA_LEGACY_CHANNEL
|
||||
{
|
||||
ULONG IoBase;
|
||||
ULONG Irq;
|
||||
} ATA_LEGACY_CHANNEL, *PATA_LEGACY_CHANNEL;
|
||||
|
||||
CODE_SEG("INIT")
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
UCHAR
|
||||
AtaWait(
|
||||
_In_ PIDE_REGISTERS Registers,
|
||||
_In_range_(>, 0) ULONG Timeout,
|
||||
_In_ UCHAR Mask,
|
||||
_In_ UCHAR Value)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < Timeout; ++i)
|
||||
{
|
||||
IdeStatus = ATA_READ(Registers->Status);
|
||||
if ((IdeStatus & Mask) == Value)
|
||||
break;
|
||||
|
||||
if (IdeStatus == 0xFF)
|
||||
break;
|
||||
|
||||
KeStallExecutionProcessor(10);
|
||||
}
|
||||
|
||||
return IdeStatus;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
VOID
|
||||
AtaLegacyFetchIdentifyData(
|
||||
_In_ PIDE_REGISTERS Registers)
|
||||
{
|
||||
USHORT Buffer[256];
|
||||
|
||||
READ_PORT_BUFFER_USHORT((PUSHORT)Registers->Data, Buffer, RTL_NUMBER_OF(Buffer));
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyIdentifyDevice(
|
||||
_In_ PIDE_REGISTERS Registers,
|
||||
_In_ ULONG DeviceNumber,
|
||||
_In_ UCHAR Command)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
|
||||
/* Select the device */
|
||||
ATA_WRITE(Registers->Device, ((DeviceNumber << 4) | IDE_DRIVE_SELECT));
|
||||
ATA_IO_WAIT();
|
||||
IdeStatus = AtaWait(Registers, ATA_TIME_BUSY_SELECT, IDE_STATUS_BUSY, 0);
|
||||
if (IdeStatus & IDE_STATUS_BUSY)
|
||||
{
|
||||
DPRINT("Timeout, status 0x%02x\n", IdeStatus);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ATA_WRITE(Registers->Features, 0);
|
||||
ATA_WRITE(Registers->SectorCount, 0);
|
||||
ATA_WRITE(Registers->LbaLow, 0);
|
||||
ATA_WRITE(Registers->LbaMid, 0);
|
||||
ATA_WRITE(Registers->LbaHigh, 0);
|
||||
ATA_WRITE(Registers->Command, Command);
|
||||
|
||||
/* Need to wait for a valid status */
|
||||
ATA_IO_WAIT();
|
||||
|
||||
/* Now wait for busy to clear */
|
||||
IdeStatus = AtaWait(Registers, ATA_TIME_BUSY_IDENTIFY, IDE_STATUS_BUSY, 0);
|
||||
if (IdeStatus & IDE_STATUS_BUSY)
|
||||
{
|
||||
DPRINT("Timeout, status 0x%02x\n", IdeStatus);
|
||||
return FALSE;
|
||||
}
|
||||
if (IdeStatus & ((IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT)))
|
||||
{
|
||||
DPRINT("Command 0x%02x aborted, status 0x%02x, error 0x%02x\n",
|
||||
Command,
|
||||
IdeStatus,
|
||||
ATA_READ(Registers->Error));
|
||||
return FALSE;
|
||||
}
|
||||
if (!(IdeStatus & IDE_STATUS_DRQ))
|
||||
{
|
||||
DPRINT1("DRQ not set, status 0x%02x\n", IdeStatus);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Complete the data transfer */
|
||||
AtaLegacyFetchIdentifyData(Registers);
|
||||
|
||||
/* All data has been transferred, wait for DRQ to clear */
|
||||
IdeStatus = AtaWait(Registers,
|
||||
ATA_TIME_DRQ_CLEAR,
|
||||
IDE_STATUS_BUSY | IDE_STATUS_DRQ,
|
||||
0);
|
||||
if (IdeStatus & (IDE_STATUS_BUSY | IDE_STATUS_DRQ))
|
||||
{
|
||||
DPRINT1("DRQ not cleared, status 0x%02x\n", IdeStatus);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyPerformSoftwareReset(
|
||||
_In_ PIDE_REGISTERS Registers,
|
||||
_In_ ULONG DeviceNumber)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
ULONG i;
|
||||
|
||||
/* Perform a software reset */
|
||||
ATA_WRITE(Registers->Control, IDE_DC_RESET_CONTROLLER);
|
||||
KeStallExecutionProcessor(20);
|
||||
ATA_WRITE(Registers->Control, IDE_DC_DISABLE_INTERRUPTS);
|
||||
KeStallExecutionProcessor(20);
|
||||
|
||||
/* The reset will cause the master device to be selected */
|
||||
if ((DeviceNumber & 1) != 0)
|
||||
{
|
||||
for (i = ATA_TIME_RESET_SELECT; i > 0; i--)
|
||||
{
|
||||
/* Select the device again */
|
||||
ATA_WRITE(Registers->Device, ((DeviceNumber << 4) | IDE_DRIVE_SELECT));
|
||||
ATA_IO_WAIT();
|
||||
|
||||
/* Check whether the selection was successful */
|
||||
ATA_WRITE(Registers->ByteCountLow, 0xAA);
|
||||
ATA_WRITE(Registers->ByteCountLow, 0x55);
|
||||
ATA_WRITE(Registers->ByteCountLow, 0xAA);
|
||||
if (ATA_READ(Registers->ByteCountLow) == 0xAA)
|
||||
break;
|
||||
|
||||
KeStallExecutionProcessor(10);
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
DPRINT("Selection timeout\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now wait for busy to clear */
|
||||
IdeStatus = AtaWait(Registers, ATA_TIME_BUSY_RESET, IDE_STATUS_BUSY, 0);
|
||||
if (IdeStatus & IDE_STATUS_BUSY)
|
||||
{
|
||||
DPRINT1("Timeout, status 0x%02x\n", IdeStatus);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyFindAtaDevice(
|
||||
_In_ PIDE_REGISTERS Registers,
|
||||
_In_ ULONG DeviceNumber)
|
||||
{
|
||||
UCHAR IdeStatus, SignatureLow, SignatureHigh;
|
||||
|
||||
/* Select the device */
|
||||
ATA_WRITE(Registers->Device, ((DeviceNumber << 4) | IDE_DRIVE_SELECT));
|
||||
ATA_IO_WAIT();
|
||||
|
||||
/* Do a quick check first */
|
||||
IdeStatus = ATA_READ(Registers->Status);
|
||||
if (IdeStatus == 0xFF || IdeStatus == 0x7F)
|
||||
return FALSE;
|
||||
|
||||
/* Look at controller */
|
||||
ATA_WRITE(Registers->ByteCountLow, 0x55);
|
||||
ATA_WRITE(Registers->ByteCountLow, 0xAA);
|
||||
ATA_WRITE(Registers->ByteCountLow, 0x55);
|
||||
if (ATA_READ(Registers->ByteCountLow) != 0x55)
|
||||
return FALSE;
|
||||
ATA_WRITE(Registers->ByteCountHigh, 0xAA);
|
||||
ATA_WRITE(Registers->ByteCountHigh, 0x55);
|
||||
ATA_WRITE(Registers->ByteCountHigh, 0xAA);
|
||||
if (ATA_READ(Registers->ByteCountHigh) != 0xAA)
|
||||
return FALSE;
|
||||
|
||||
/* Wait for busy to clear */
|
||||
IdeStatus = AtaWait(Registers, ATA_TIME_BUSY_SELECT, IDE_STATUS_BUSY, 0);
|
||||
if (IdeStatus & IDE_STATUS_BUSY)
|
||||
{
|
||||
DPRINT1("Device is busy, attempting to recover %02x\n", IdeStatus);
|
||||
|
||||
if (!AtaLegacyPerformSoftwareReset(Registers, DeviceNumber))
|
||||
{
|
||||
DPRINT1("Failed to reset device %02x\n", ATA_READ(Registers->Status));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for ATA */
|
||||
if (AtaLegacyIdentifyDevice(Registers, DeviceNumber, IDE_COMMAND_IDENTIFY))
|
||||
return TRUE;
|
||||
|
||||
SignatureLow = ATA_READ(Registers->SignatureLow);
|
||||
SignatureHigh = ATA_READ(Registers->SignatureHigh);
|
||||
|
||||
DPRINT("SL = 0x%02x, SH = 0x%02x\n", SignatureLow, SignatureHigh);
|
||||
|
||||
/* Check for ATAPI */
|
||||
if (SignatureLow == 0x14 && SignatureHigh == 0xEB)
|
||||
return TRUE;
|
||||
|
||||
/*
|
||||
* ATAPI devices abort the IDENTIFY command and return an ATAPI signature
|
||||
* in the task file registers. However the NEC CDR-260 drive doesn't return
|
||||
* the correct signature, but instead shows up with zeroes.
|
||||
* This drive also reports an ATA signature after device reset.
|
||||
* To overcome this behavior, we try the ATAPI IDENTIFY command.
|
||||
* It should be successfully completed or failed (aborted or time-out).
|
||||
*/
|
||||
return AtaLegacyIdentifyDevice(Registers, DeviceNumber, IDE_COMMAND_ATAPI_IDENTIFY);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyChannelPresent(
|
||||
_In_ PIDE_REGISTERS Registers)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
/* Check for the PC-98 on-board IDE interface */
|
||||
if (IsNEC_98)
|
||||
return (ATA_READ((PUCHAR)0x432) != 0xFF);
|
||||
|
||||
/*
|
||||
* The only reliable way to detect the legacy IDE channel
|
||||
* is to check for devices attached to the bus.
|
||||
*/
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
if (AtaLegacyFindAtaDevice(Registers, i))
|
||||
{
|
||||
DPRINT("Found IDE device\n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
VOID
|
||||
AtaLegacyMakePortResource(
|
||||
_Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ ULONG IoBase,
|
||||
_In_ ULONG Length)
|
||||
{
|
||||
Descriptor->Type = CmResourceTypePort;
|
||||
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
|
||||
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
||||
Descriptor->u.Port.Start.u.LowPart = IoBase;
|
||||
Descriptor->u.Port.Length = Length;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
VOID
|
||||
AtaLegacyMakeInterruptResource(
|
||||
_Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||||
_In_ ULONG Level)
|
||||
{
|
||||
Descriptor->Type = CmResourceTypeInterrupt;
|
||||
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
|
||||
Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||||
Descriptor->u.Interrupt.Level = Level;
|
||||
Descriptor->u.Interrupt.Vector = Level;
|
||||
Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyChannelBuildResources(
|
||||
_In_ PATA_LEGACY_CHANNEL LegacyChannel,
|
||||
_Inout_ PCM_RESOURCE_LIST ResourceList)
|
||||
{
|
||||
PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
||||
ULONG i;
|
||||
|
||||
Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
|
||||
|
||||
if (IsNEC_98)
|
||||
{
|
||||
if (ConfigInfo->AtDiskPrimaryAddressClaimed || ConfigInfo->AtDiskSecondaryAddressClaimed)
|
||||
return FALSE;
|
||||
|
||||
#define CHANNEL_PC98_RESOURCE_COUNT 12
|
||||
/*
|
||||
* Make a resource list for the internal IDE interface:
|
||||
*
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:640, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:74C, Len 1
|
||||
* [ShareDisposition 1, Flags 1] INT: Lev 9 Vec 9 Aff FFFFFFFF
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:642, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:644, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:646, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:648, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:64A, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:64C, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:64E, Len 1
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:432, Len 2
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:435, Len 1
|
||||
*/
|
||||
AtaLegacyMakePortResource(Descriptor++, 0x640, 1);
|
||||
AtaLegacyMakePortResource(Descriptor++, 0x74C, 1);
|
||||
AtaLegacyMakeInterruptResource(Descriptor++, 9);
|
||||
for (i = 0; i < 7; ++i)
|
||||
{
|
||||
AtaLegacyMakePortResource(Descriptor++, 0x642 + i * 2, 1);
|
||||
}
|
||||
AtaLegacyMakePortResource(Descriptor++, 0x432, 2);
|
||||
AtaLegacyMakePortResource(Descriptor++, 0x435, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LegacyChannel->IoBase == 0x1F0 && ConfigInfo->AtDiskPrimaryAddressClaimed)
|
||||
return FALSE;
|
||||
|
||||
if (LegacyChannel->IoBase == 0x170 && ConfigInfo->AtDiskSecondaryAddressClaimed)
|
||||
return FALSE;
|
||||
|
||||
#define CHANNEL_PCAT_RESOURCE_COUNT 3
|
||||
/*
|
||||
* For example, the following resource list is created for the primary IDE channel:
|
||||
*
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:1F0, Len 8
|
||||
* [ShareDisposition 1, Flags 11] IO: Start 0:3F6, Len 1
|
||||
* [ShareDisposition 1, Flags 1] INT: Lev A Vec A Aff FFFFFFFF
|
||||
*/
|
||||
AtaLegacyMakePortResource(Descriptor++, LegacyChannel->IoBase, 8);
|
||||
AtaLegacyMakePortResource(Descriptor++, LegacyChannel->IoBase + 0x206, 1);
|
||||
AtaLegacyMakeInterruptResource(Descriptor++, LegacyChannel->Irq);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
VOID
|
||||
AtaLegacyChannelTranslateResources(
|
||||
_Inout_ PCM_RESOURCE_LIST ResourceList,
|
||||
_In_ PUCHAR CommandPortBase,
|
||||
_In_ PUCHAR ControlPortBase)
|
||||
{
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
||||
KIRQL Irql;
|
||||
|
||||
Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
|
||||
|
||||
/* Move on to the interrupt descriptor */
|
||||
if (IsNEC_98)
|
||||
{
|
||||
Descriptor += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Descriptor->u.Port.Start.QuadPart = (ULONG_PTR)CommandPortBase;
|
||||
++Descriptor;
|
||||
|
||||
Descriptor->u.Port.Start.QuadPart = (ULONG_PTR)ControlPortBase;
|
||||
++Descriptor;
|
||||
}
|
||||
ASSERT(Descriptor->Type == CmResourceTypeInterrupt);
|
||||
|
||||
Descriptor->u.Interrupt.Vector = HalGetInterruptVector(Isa,
|
||||
0,
|
||||
Descriptor->u.Interrupt.Level,
|
||||
Descriptor->u.Interrupt.Vector,
|
||||
&Irql,
|
||||
&Descriptor->u.Interrupt.Affinity);
|
||||
Descriptor->u.Interrupt.Level = Irql;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
PVOID
|
||||
AtaLegacyTranslateBusAddress(
|
||||
_In_ ULONG Address,
|
||||
_In_ ULONG NumberOfBytes,
|
||||
_Out_ PBOOLEAN IsAddressMmio)
|
||||
{
|
||||
ULONG AddressSpace;
|
||||
BOOLEAN Success;
|
||||
PHYSICAL_ADDRESS BusAddress, TranslatedAddress;
|
||||
|
||||
BusAddress.QuadPart = Address;
|
||||
AddressSpace = 1; // I/O space
|
||||
Success = HalTranslateBusAddress(Isa, 0, BusAddress, &AddressSpace, &TranslatedAddress);
|
||||
if (!Success)
|
||||
return NULL;
|
||||
|
||||
/* I/O space */
|
||||
if (AddressSpace != 0)
|
||||
{
|
||||
*IsAddressMmio = FALSE;
|
||||
return (PVOID)(ULONG_PTR)TranslatedAddress.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
*IsAddressMmio = TRUE;
|
||||
return MmMapIoSpace(TranslatedAddress, NumberOfBytes, MmNonCached);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyClaimHardwareResources(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PCM_RESOURCE_LIST ResourceList,
|
||||
_In_ ULONG ResourceListSize)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
BOOLEAN ConflictDetected;
|
||||
|
||||
Status = IoReportResourceForDetection(DriverObject,
|
||||
ResourceList,
|
||||
ResourceListSize,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
&ConflictDetected);
|
||||
/* HACK: We really need to fix a number of resource bugs in the kernel */
|
||||
if (IsNEC_98)
|
||||
return TRUE;
|
||||
|
||||
if (!NT_SUCCESS(Status) || ConflictDetected)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
VOID
|
||||
AtaLegacyReleaseHardwareResources(
|
||||
_In_ PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
BOOLEAN Dummy;
|
||||
|
||||
IoReportResourceForDetection(DriverObject, NULL, 0, NULL, NULL, 0, &Dummy);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyDetectChannel(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PPCIIDEX_LEGACY_CONTROLLER_INTERFACE ControllerInferface,
|
||||
_In_ PATA_LEGACY_CHANNEL LegacyChannel,
|
||||
_In_ PCM_RESOURCE_LIST ResourceList,
|
||||
_In_ ULONG ResourceListSize)
|
||||
{
|
||||
BOOLEAN IsAddressMmio[2];
|
||||
PDEVICE_OBJECT PhysicalDeviceObject;
|
||||
PVOID ControllerContext;
|
||||
IDE_REGISTERS Registers;
|
||||
NTSTATUS Status;
|
||||
ULONG Spare;
|
||||
|
||||
DPRINT("IDE Channel IO %lx, Irq %lu\n", LegacyChannel->IoBase, LegacyChannel->Irq);
|
||||
|
||||
if (!AtaLegacyChannelBuildResources(LegacyChannel, ResourceList))
|
||||
{
|
||||
DPRINT("Failed to build the resource list\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!AtaLegacyClaimHardwareResources(DriverObject, ResourceList, ResourceListSize))
|
||||
{
|
||||
DPRINT("Failed to claim resources\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
IsAddressMmio[0] = FALSE;
|
||||
IsAddressMmio[1] = FALSE;
|
||||
|
||||
if (IsNEC_98)
|
||||
{
|
||||
/* No translation required for the C-Bus I/O space */
|
||||
Registers.Data = (PVOID)0x640;
|
||||
Registers.Control = (PVOID)0x74C;
|
||||
|
||||
Spare = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Registers.Data = AtaLegacyTranslateBusAddress(LegacyChannel->IoBase,
|
||||
8,
|
||||
&IsAddressMmio[0]);
|
||||
if (!Registers.Data)
|
||||
{
|
||||
DPRINT("Failed to map command port\n");
|
||||
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto ReleaseResources;
|
||||
}
|
||||
|
||||
Registers.Control = AtaLegacyTranslateBusAddress(LegacyChannel->IoBase + 0x206,
|
||||
1,
|
||||
&IsAddressMmio[1]);
|
||||
if (!Registers.Control)
|
||||
{
|
||||
DPRINT("Failed to map control port\n");
|
||||
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto ReleaseResources;
|
||||
}
|
||||
|
||||
Spare = 1;
|
||||
}
|
||||
Registers.Error = (PVOID)((ULONG_PTR)Registers.Data + 1 * Spare);
|
||||
Registers.SectorCount = (PVOID)((ULONG_PTR)Registers.Data + 2 * Spare);
|
||||
Registers.LbaLow = (PVOID)((ULONG_PTR)Registers.Data + 3 * Spare);
|
||||
Registers.LbaMid = (PVOID)((ULONG_PTR)Registers.Data + 4 * Spare);
|
||||
Registers.LbaHigh = (PVOID)((ULONG_PTR)Registers.Data + 5 * Spare);
|
||||
Registers.Device = (PVOID)((ULONG_PTR)Registers.Data + 6 * Spare);
|
||||
Registers.Status = (PVOID)((ULONG_PTR)Registers.Data + 7 * Spare);
|
||||
|
||||
if (!AtaLegacyChannelPresent(&Registers))
|
||||
{
|
||||
DPRINT("No IDE devices found\n");
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
ReleaseResources:
|
||||
AtaLegacyReleaseHardwareResources(DriverObject);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto Cleanup;
|
||||
|
||||
PhysicalDeviceObject = NULL;
|
||||
Status = IoReportDetectedDevice(DriverObject,
|
||||
InterfaceTypeUndefined,
|
||||
(ULONG)-1,
|
||||
(ULONG)-1,
|
||||
ResourceList,
|
||||
NULL,
|
||||
0,
|
||||
&PhysicalDeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("IoReportDetectedDevice() failed with status 0x%lx\n", Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (ControllerInferface->Version != PCIIDEX_INTERFACE_VERSION)
|
||||
{
|
||||
/* ReactOS-specific: Retrieve the interface for legacy device detection */
|
||||
Status = PciIdeXInitialize(DriverObject,
|
||||
NULL,
|
||||
(PVOID)ControllerInferface,
|
||||
PCIIDEX_GET_CONTROLLER_INTERFACE_SIGNATURE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to register the legacy channel 0x%lx, status 0x%lx\n",
|
||||
LegacyChannel->IoBase, Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (ControllerInferface->Version != PCIIDEX_INTERFACE_VERSION)
|
||||
{
|
||||
DPRINT1("Unknown interface version 0x%lx\n", ControllerInferface->Version);
|
||||
Status = STATUS_REVISION_MISMATCH;
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
Status = ControllerInferface->AddDevice(DriverObject, PhysicalDeviceObject, &ControllerContext);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to add the legacy channel 0x%lx, status 0x%lx\n",
|
||||
LegacyChannel->IoBase, Status);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
AtaLegacyChannelTranslateResources(ResourceList, Registers.Data, Registers.Control);
|
||||
|
||||
Status = ControllerInferface->StartDevice(ControllerContext, ResourceList);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to start the legacy channel 0x%lx, status 0x%lx\n",
|
||||
LegacyChannel->IoBase, Status);
|
||||
|
||||
ControllerInferface->RemoveDevice(ControllerContext);
|
||||
}
|
||||
|
||||
Cleanup:
|
||||
if (IsAddressMmio[0] && Registers.Data)
|
||||
{
|
||||
MmUnmapIoSpace(Registers.Data, 8);
|
||||
}
|
||||
|
||||
if (IsAddressMmio[1] && Registers.Control)
|
||||
{
|
||||
MmUnmapIoSpace(Registers.Control, 1);
|
||||
}
|
||||
|
||||
return NT_SUCCESS(Status);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
NTSTATUS
|
||||
AtaOpenRegistryKey(
|
||||
_Out_ PHANDLE KeyHandle,
|
||||
_In_ HANDLE RootKey,
|
||||
_In_ PUNICODE_STRING KeyName)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
KeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
RootKey,
|
||||
NULL);
|
||||
return ZwOpenKey(KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("INIT")
|
||||
BOOLEAN
|
||||
AtaLegacyShouldDetectChannels(
|
||||
_In_ PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG KeyValue;
|
||||
BOOLEAN PerformDetection;
|
||||
HANDLE SoftKeyHandle, ParamsKeyHandle;
|
||||
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
||||
UNICODE_STRING ParametersKeyName = RTL_CONSTANT_STRING(L"Parameters");
|
||||
static const WCHAR MapperKeyPath[] =
|
||||
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Pnp";
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Read the firmware mapper key. If the firmware mapper is disabled,
|
||||
* it is the responsibility of PnP drivers (ACPI, PCI, and others)
|
||||
* to detect and enumerate IDE channels.
|
||||
*/
|
||||
KeyValue = 0;
|
||||
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
||||
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||||
QueryTable[0].Name = L"DisableFirmwareMapper";
|
||||
QueryTable[0].EntryContext = &KeyValue;
|
||||
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, MapperKeyPath, QueryTable, NULL, NULL);
|
||||
if (NT_SUCCESS(Status) && (KeyValue != 0))
|
||||
{
|
||||
DPRINT("Skipping legacy detection on a PnP system\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Open the driver's software key */
|
||||
Status = AtaOpenRegistryKey(&SoftKeyHandle, NULL, RegistryPath);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to open the '%wZ' key, status 0x%lx\n", RegistryPath, Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Open the 'Parameters' key */
|
||||
Status = AtaOpenRegistryKey(&ParamsKeyHandle, SoftKeyHandle, &ParametersKeyName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to open the 'Parameters' key, status 0x%lx\n", Status);
|
||||
|
||||
ZwClose(SoftKeyHandle);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check whether it is the first time we detect IDE channels */
|
||||
KeyValue = 0;
|
||||
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
||||
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
||||
QueryTable[0].Name = L"LegacyDetection";
|
||||
QueryTable[0].EntryContext = &KeyValue;
|
||||
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
||||
(PWSTR)ParamsKeyHandle,
|
||||
QueryTable,
|
||||
NULL,
|
||||
NULL);
|
||||
PerformDetection = (KeyValue != 0);
|
||||
|
||||
/* Do not detect devices again on subsequent boots after driver installation */
|
||||
if (PerformDetection)
|
||||
{
|
||||
KeyValue = 0;
|
||||
RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
|
||||
(PWSTR)ParamsKeyHandle,
|
||||
L"LegacyDetection",
|
||||
REG_DWORD,
|
||||
&KeyValue,
|
||||
sizeof(KeyValue));
|
||||
}
|
||||
|
||||
ZwClose(ParamsKeyHandle);
|
||||
ZwClose(SoftKeyHandle);
|
||||
|
||||
return PerformDetection;
|
||||
}
|
||||
|
||||
CODE_SEG("INIT")
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DriverEntry(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
PCIIDEX_LEGACY_CONTROLLER_INTERFACE ControllerInferface = { 0 };
|
||||
ATA_LEGACY_CHANNEL LegacyChannel[4 + 1] = { 0 };
|
||||
PCM_RESOURCE_LIST ResourceList;
|
||||
ULONG i, ListSize, ResourceCount;
|
||||
NTSTATUS Status;
|
||||
|
||||
if (!AtaLegacyShouldDetectChannels(RegistryPath))
|
||||
return STATUS_CANCELLED;
|
||||
|
||||
if (IsNEC_98)
|
||||
{
|
||||
/* Internal IDE interface */
|
||||
LegacyChannel[0].IoBase = 0x640;
|
||||
LegacyChannel[0].Irq = 9;
|
||||
|
||||
ResourceCount = CHANNEL_PC98_RESOURCE_COUNT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Primary IDE channel */
|
||||
LegacyChannel[0].IoBase = 0x1F0;
|
||||
LegacyChannel[0].Irq = 14;
|
||||
|
||||
/* Secondary IDE channel */
|
||||
LegacyChannel[1].IoBase = 0x170;
|
||||
LegacyChannel[1].Irq = 15;
|
||||
|
||||
/* Tertiary IDE channel */
|
||||
LegacyChannel[2].IoBase = 0x1E8;
|
||||
LegacyChannel[2].Irq = 11;
|
||||
|
||||
/* Quaternary IDE channel */
|
||||
LegacyChannel[3].IoBase = 0x168;
|
||||
LegacyChannel[3].Irq = 10;
|
||||
|
||||
ResourceCount = CHANNEL_PCAT_RESOURCE_COUNT;
|
||||
}
|
||||
|
||||
ListSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors) +
|
||||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * ResourceCount;
|
||||
|
||||
ResourceList = ExAllocatePoolZero(PagedPool, ListSize, ATAPORT_TAG);
|
||||
if (!ResourceList)
|
||||
{
|
||||
DPRINT1("Failed to allocate the resource list\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
ResourceList->Count = 1;
|
||||
ResourceList->List[0].InterfaceType = Isa;
|
||||
ResourceList->List[0].BusNumber = 0;
|
||||
ResourceList->List[0].PartialResourceList.Version = 1;
|
||||
ResourceList->List[0].PartialResourceList.Revision = 1;
|
||||
ResourceList->List[0].PartialResourceList.Count = ResourceCount;
|
||||
|
||||
Status = STATUS_NOT_FOUND;
|
||||
|
||||
for (i = 0; LegacyChannel[i].IoBase != 0; ++i)
|
||||
{
|
||||
if (AtaLegacyDetectChannel(DriverObject,
|
||||
&ControllerInferface,
|
||||
&LegacyChannel[i],
|
||||
ResourceList,
|
||||
ListSize))
|
||||
{
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(ResourceList, ATAPORT_TAG);
|
||||
return Status;
|
||||
}
|
||||
5
drivers/storage/ide/legide/legide.rc
Normal file
5
drivers/storage/ide/legide/legide.rc
Normal file
@@ -0,0 +1,5 @@
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "Legacy PATA Bus Enumerator Driver"
|
||||
#define REACTOS_STR_INTERNAL_NAME "legide"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "legide.sys"
|
||||
#include <reactos/version.rc>
|
||||
9
drivers/storage/ide/legide/legide_reg.inf
Normal file
9
drivers/storage/ide/legide/legide_reg.inf
Normal file
@@ -0,0 +1,9 @@
|
||||
; Legacy PATA Bus Enumerator Driver
|
||||
[AddReg]
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","ErrorControl",0x00010001,0x00000003
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","Group",0x00000000,"SCSI Miniport"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","ImagePath",0x00020000,"system32\drivers\legide.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","Start",0x00010001,0x00000000
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","Type",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide","Tag",0x00010001,0x00000021
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\legide\Parameters","LegacyDetection",0x00010001,0x00000001
|
||||
@@ -3,7 +3,7 @@
|
||||
* PROJECT: PCI IDE bus driver
|
||||
* FILE: drivers/storage/pciide/pciide.c
|
||||
* PURPOSE: Main file
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
||||
*/
|
||||
|
||||
#include "pciide.h"
|
||||
@@ -16,34 +16,8 @@ PciIdeChannelEnabled(
|
||||
IN PVOID DeviceExtension,
|
||||
IN ULONG Channel)
|
||||
{
|
||||
PCI_COMMON_CONFIG PciConfig;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("PciIdeChannelEnabled(%p, %lu)\n", DeviceExtension, Channel);
|
||||
|
||||
Status = PciIdeXGetBusData(
|
||||
DeviceExtension,
|
||||
&PciConfig,
|
||||
0,
|
||||
PCI_COMMON_HDR_LENGTH);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("PciIdeXGetBusData() failed with status 0x%08lx\n", Status);
|
||||
return ChannelStateUnknown;
|
||||
}
|
||||
|
||||
if (PCI_CONFIGURATION_TYPE(&PciConfig) != PCI_DEVICE_TYPE)
|
||||
{
|
||||
DPRINT("Wrong PCI card type. Disabling IDE channel #%lu\n", Channel);
|
||||
return ChannelDisabled;
|
||||
}
|
||||
|
||||
if (PciConfig.BaseClass != PCI_CLASS_MASS_STORAGE_CTLR || PciConfig.SubClass != PCI_SUBCLASS_MSC_IDE_CTLR)
|
||||
{
|
||||
DPRINT("Wrong PCI card base class/sub class. Disabling IDE channel #%lu\n", Channel);
|
||||
return ChannelDisabled;
|
||||
}
|
||||
|
||||
return ChannelStateUnknown;
|
||||
}
|
||||
|
||||
@@ -51,24 +25,9 @@ BOOLEAN NTAPI
|
||||
PciIdeSyncAccessRequired(
|
||||
IN PVOID DeviceExtension)
|
||||
{
|
||||
DPRINT1("PciIdeSyncAccessRequired %p\n", DeviceExtension);
|
||||
DPRINT("PciIdeSyncAccessRequired %p\n", DeviceExtension);
|
||||
|
||||
return FALSE; /* FIXME */
|
||||
}
|
||||
|
||||
NTSTATUS NTAPI
|
||||
PciIdeTransferModeSelect(
|
||||
IN PVOID DeviceExtension,
|
||||
IN PPCIIDE_TRANSFER_MODE_SELECT XferMode)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
DPRINT1("PciIdeTransferModeSelect(%p %p)\n", DeviceExtension, XferMode);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; i++)
|
||||
XferMode->DevicePresent[i] = FALSE; /* FIXME */
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ULONG NTAPI
|
||||
@@ -88,27 +47,40 @@ PciIdeGetControllerProperties(
|
||||
IN PVOID DeviceExtension,
|
||||
OUT PIDE_CONTROLLER_PROPERTIES ControllerProperties)
|
||||
{
|
||||
ULONG SupportedMode;
|
||||
USHORT PciCommand;
|
||||
|
||||
if (ControllerProperties->Size != sizeof(IDE_CONTROLLER_PROPERTIES))
|
||||
return STATUS_REVISION_MISMATCH;
|
||||
|
||||
ControllerProperties->PciIdeChannelEnabled = PciIdeChannelEnabled;
|
||||
ControllerProperties->PciIdeSyncAccessRequired = PciIdeSyncAccessRequired;
|
||||
ControllerProperties->PciIdeTransferModeSelect = PciIdeTransferModeSelect;
|
||||
ControllerProperties->IgnoreActiveBitForAtaDevice = FALSE;
|
||||
ControllerProperties->AlwaysClearBusMasterInterrupt = TRUE;
|
||||
ControllerProperties->PciIdeUseDma = PciIdeUseDma;
|
||||
ControllerProperties->AlignmentRequirement = 1;
|
||||
ControllerProperties->DefaultPIO = 0; /* FIXME */
|
||||
ControllerProperties->PciIdeUdmaModesSupported = NULL; /* optional */
|
||||
|
||||
PciIdeXGetBusData(DeviceExtension,
|
||||
&PciCommand,
|
||||
FIELD_OFFSET(PCI_COMMON_HEADER, Command),
|
||||
sizeof(PciCommand));
|
||||
if (!(PciCommand & PCI_ENABLE_BUS_MASTER))
|
||||
{
|
||||
SupportedMode = PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4;
|
||||
}
|
||||
else
|
||||
{
|
||||
SupportedMode = PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4 |
|
||||
SWDMA_MODE0 | SWDMA_MODE1 | SWDMA_MODE2 |
|
||||
MWDMA_MODE0 | MWDMA_MODE1 | MWDMA_MODE2 |
|
||||
UDMA_MODE0 | UDMA_MODE1 | UDMA_MODE2 |
|
||||
UDMA_MODE3 | UDMA_MODE4 | UDMA_MODE5 | UDMA_MODE6;
|
||||
}
|
||||
|
||||
ControllerProperties->SupportedTransferMode[0][0] =
|
||||
ControllerProperties->SupportedTransferMode[0][1] =
|
||||
ControllerProperties->SupportedTransferMode[1][0] =
|
||||
ControllerProperties->SupportedTransferMode[1][1] =
|
||||
PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4 |
|
||||
SWDMA_MODE0 | SWDMA_MODE1 | SWDMA_MODE2 |
|
||||
MWDMA_MODE0 | MWDMA_MODE1 | MWDMA_MODE2 |
|
||||
UDMA_MODE0 | UDMA_MODE1 | UDMA_MODE2 | UDMA_MODE3 | UDMA_MODE4;
|
||||
ControllerProperties->SupportedTransferMode[1][1] = SupportedMode;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,36 @@
|
||||
spec2def(pciidex.sys pciidex.spec ADD_IMPORTLIB)
|
||||
|
||||
list(APPEND SOURCE
|
||||
chipset/ahci_generic.c
|
||||
chipset/ahci_hw.c
|
||||
chipset/ahci_io.c
|
||||
chipset/amd.c
|
||||
chipset/ati.c
|
||||
chipset/cmd.c
|
||||
chipset/intel.c
|
||||
chipset/pata_generic.c
|
||||
chipset/pata_hw.c
|
||||
chipset/pata_io.c
|
||||
chipset/pctech.c
|
||||
chipset/sil680.c
|
||||
chipset/svw_pata.c
|
||||
chipset/svw_sata.c
|
||||
chipset/toshiba.c
|
||||
chipset/via.c
|
||||
acpi.c
|
||||
ahci.h
|
||||
debug.h
|
||||
fdo.c
|
||||
miniport.c
|
||||
pciidex.c
|
||||
pciidex.h
|
||||
pdo.c
|
||||
power.c
|
||||
pciidex.h)
|
||||
power.c)
|
||||
|
||||
if(ARCH STREQUAL "i386")
|
||||
add_definitions(-DATA_DETECT_LEGACY_DEVICES)
|
||||
list(APPEND SOURCE chipset/pata_legacy.c)
|
||||
endif()
|
||||
|
||||
add_library(pciidex MODULE
|
||||
${SOURCE}
|
||||
|
||||
337
drivers/storage/ide/pciidex/acpi.c
Normal file
337
drivers/storage/ide/pciidex/acpi.c
Normal file
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: ACPI interface with SATA ports, IDE controllers and drives
|
||||
* COPYRIGHT: Copyright 2026 <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
#include <acpiioct.h>
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
static
|
||||
NTSTATUS
|
||||
AtaAcpiEvaluateObject(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
|
||||
_In_ ULONG InputBufferLength,
|
||||
_Out_writes_bytes_opt_(OutputBufferLength) PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,
|
||||
_In_ ULONG OutputBufferLength)
|
||||
{
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
PDEVICE_OBJECT TopDeviceObject;
|
||||
|
||||
/* Get the ACPI bus filter device for this DO */
|
||||
TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
|
||||
|
||||
/*
|
||||
* We could be called at DISPATCH_LEVEL,
|
||||
* so use IoAllocateIrp() rather going through IoBuildDeviceIoControlRequest().
|
||||
*/
|
||||
Irp = IoAllocateIrp(TopDeviceObject->StackSize, 0);
|
||||
if (!Irp)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto Exit;
|
||||
}
|
||||
Irp->AssociatedIrp.SystemBuffer = InputBuffer;
|
||||
Irp->UserBuffer = OutputBuffer;
|
||||
Irp->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
|
||||
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
/*
|
||||
* Submit an asynchronous evaluation request.
|
||||
* Note that _STM should be evaluated while the device queue has been paused,
|
||||
* so we must not cause *any* page faults and use IOCTL_ACPI_EVAL_METHOD.
|
||||
* AtaAcpiEvaluateObject() also has to be non-pageable.
|
||||
*/
|
||||
IoStack = IoGetNextIrpStackLocation(Irp);
|
||||
IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
||||
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ASYNC_EVAL_METHOD;
|
||||
IoStack->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
|
||||
IoStack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
IoSetCompletionRoutine(Irp,
|
||||
PciIdeXPdoCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE);
|
||||
|
||||
Status = IoCallDriver(TopDeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
RtlCopyMemory(OutputBuffer, InputBuffer, min(Irp->IoStatus.Information, OutputBufferLength));
|
||||
|
||||
if (OutputBuffer && NT_SUCCESS(Status))
|
||||
{
|
||||
ASSERT(OutputBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
|
||||
|
||||
if ((OutputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) ||
|
||||
(OutputBuffer->Count == 0))
|
||||
{
|
||||
ERR("Invalid ACPI output buffer\n");
|
||||
|
||||
Status = STATUS_ACPI_INVALID_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
ObDereferenceObject(TopDeviceObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
AtaAcpiGetTimingMode(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Out_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode)
|
||||
{
|
||||
UCHAR Buffer[FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode))];
|
||||
ACPI_EVAL_INPUT_BUFFER InputBuffer;
|
||||
NTSTATUS Status;
|
||||
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
|
||||
|
||||
RtlZeroMemory(Buffer, sizeof(Buffer));
|
||||
|
||||
InputBuffer.MethodNameAsUlong = 'MTG_'; // _GTM
|
||||
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||||
|
||||
/* Evaluate the _GTM method */
|
||||
Status = AtaAcpiEvaluateObject(DeviceObject,
|
||||
&InputBuffer,
|
||||
sizeof(InputBuffer),
|
||||
OutputBuffer,
|
||||
sizeof(Buffer));
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ASSERT(Status != STATUS_BUFFER_OVERFLOW);
|
||||
|
||||
TRACE("Failed to evaluate the _GTM method, status 0x%lx\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (OutputBuffer->Argument[0].DataLength < sizeof(*TimingMode))
|
||||
{
|
||||
ERR("Buffer too small, size %u/%u\n",
|
||||
OutputBuffer->Argument[0].DataLength, sizeof(*TimingMode));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (OutputBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER)
|
||||
{
|
||||
ERR("Unexpected method type %u\n", OutputBuffer->Argument[0].Type);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlCopyMemory(TimingMode, OutputBuffer->Argument[0].Data, sizeof(*TimingMode));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
AtaAcpiSetTimingMode(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode,
|
||||
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock1,
|
||||
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock2)
|
||||
{
|
||||
PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
|
||||
PACPI_METHOD_ARGUMENT Argument;
|
||||
NTSTATUS Status;
|
||||
ULONG InputSize;
|
||||
|
||||
InputSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode)) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock1)) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock2));
|
||||
|
||||
InputBuffer = ExAllocatePoolUninitialized(NonPagedPool, InputSize, TAG_PCIIDEX);
|
||||
if (!InputBuffer)
|
||||
{
|
||||
ERR("Failed to allocate memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
InputBuffer->MethodNameAsUlong = 'MTS_'; // _STM
|
||||
InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
|
||||
InputBuffer->ArgumentCount = 3;
|
||||
InputBuffer->Size = InputSize;
|
||||
|
||||
/* Argument 1: The channel timing information block */
|
||||
Argument = InputBuffer->Argument;
|
||||
ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, TimingMode, sizeof(*TimingMode));
|
||||
|
||||
/* Argument 2: The ATA drive ID block */
|
||||
Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
|
||||
Argument->Type = ACPI_METHOD_ARGUMENT_BUFFER;
|
||||
Argument->DataLength = sizeof(*IdBlock1);
|
||||
if (IdBlock1)
|
||||
RtlCopyMemory(Argument->Data, IdBlock1, sizeof(*IdBlock1));
|
||||
else
|
||||
RtlZeroMemory(Argument->Data, sizeof(*IdBlock1));
|
||||
|
||||
/* Argument 3: The ATA drive ID block */
|
||||
Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
|
||||
Argument->Type = ACPI_METHOD_ARGUMENT_BUFFER;
|
||||
Argument->DataLength = sizeof(*IdBlock2);
|
||||
if (IdBlock2)
|
||||
RtlCopyMemory(Argument->Data, IdBlock2, sizeof(*IdBlock2));
|
||||
else
|
||||
RtlZeroMemory(Argument->Data, sizeof(*IdBlock2));
|
||||
|
||||
/* Evaluate the _STM method */
|
||||
Status = AtaAcpiEvaluateObject(DeviceObject, InputBuffer, InputSize, NULL, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
INFO("Failed to set transfer timings, status 0x%lx\n", Status);
|
||||
else
|
||||
ERR("Failed to set transfer timings, status 0x%lx\n", Status);
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(InputBuffer, TAG_PCIIDEX);
|
||||
return Status;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
PVOID
|
||||
AtaAcpiGetTaskFile(
|
||||
_In_ PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
ACPI_EVAL_INPUT_BUFFER InputBuffer;
|
||||
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
|
||||
ULONG RetryCount, OutputSize;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
/*
|
||||
* We invoke this routine within the PnP START handler only,
|
||||
* and thus specify that the code is in a pageable section.
|
||||
*/
|
||||
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
|
||||
|
||||
InputBuffer.MethodNameAsUlong = 'FTG_'; // _GTF
|
||||
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||||
|
||||
/*
|
||||
* The output buffer must be large enough to hold the list of ATA commands to the drive.
|
||||
* We assume that 10 commands is the common case.
|
||||
*/
|
||||
OutputSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ATA_ACPI_TASK_FILE) * 10);
|
||||
|
||||
for (RetryCount = 0; RetryCount < 2; ++RetryCount)
|
||||
{
|
||||
OutputBuffer = ExAllocatePoolZero(NonPagedPool, OutputSize, TAG_PCIIDEX);
|
||||
if (!OutputBuffer)
|
||||
{
|
||||
ERR("Failed to allocate memory of size %lu\n", OutputSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Evaluate the _GTF method */
|
||||
Status = AtaAcpiEvaluateObject(DeviceObject,
|
||||
&InputBuffer,
|
||||
sizeof(InputBuffer),
|
||||
OutputBuffer,
|
||||
OutputSize);
|
||||
|
||||
/* Increase the allocation size if it's too small */
|
||||
if (Status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
OutputSize = OutputBuffer->Length;
|
||||
|
||||
ExFreePoolWithTag(OutputBuffer, TAG_PCIIDEX);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
goto Cleanup;
|
||||
|
||||
if (OutputBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER)
|
||||
{
|
||||
ERR("Unexpected method type %u\n", OutputBuffer->Argument[0].Type);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (OutputBuffer->Argument[0].DataLength % sizeof(ATA_ACPI_TASK_FILE))
|
||||
{
|
||||
ERR("Incorrect command stream length %u\n", OutputBuffer->Argument[0].DataLength);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
if (OutputBuffer->Argument[0].DataLength == 0)
|
||||
{
|
||||
WARN("Empty command list\n");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
return OutputBuffer;
|
||||
|
||||
Cleanup:
|
||||
ExFreePoolWithTag(OutputBuffer, TAG_PCIIDEX);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
AtaAcpiSetDeviceData(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIDENTIFY_DEVICE_DATA IdBlock)
|
||||
{
|
||||
PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
|
||||
PACPI_METHOD_ARGUMENT Argument;
|
||||
NTSTATUS Status;
|
||||
ULONG InputSize;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
|
||||
|
||||
InputSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
|
||||
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock));
|
||||
|
||||
InputBuffer = ExAllocatePoolUninitialized(NonPagedPool, InputSize, TAG_PCIIDEX);
|
||||
if (!InputBuffer)
|
||||
{
|
||||
ERR("Failed to allocate memory\n");
|
||||
return;
|
||||
}
|
||||
InputBuffer->MethodNameAsUlong = 'DDS_'; // _SDD
|
||||
InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
|
||||
InputBuffer->ArgumentCount = 1;
|
||||
InputBuffer->Size = InputSize;
|
||||
|
||||
/* Argument 1: The ATA drive ID block */
|
||||
Argument = InputBuffer->Argument;
|
||||
ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, IdBlock, sizeof(*IdBlock));
|
||||
|
||||
/* Evaluate the _SDD method */
|
||||
Status = AtaAcpiEvaluateObject(DeviceObject, InputBuffer, InputSize, NULL, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
TRACE("Failed to set device data, status 0x%lx\n", Status);
|
||||
else
|
||||
WARN("Failed to set device data, status 0x%lx\n", Status);
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(InputBuffer, TAG_PCIIDEX);
|
||||
}
|
||||
563
drivers/storage/ide/pciidex/ahci.h
Normal file
563
drivers/storage/ide/pciidex/ahci.h
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: AHCI header file
|
||||
* COPYRIGHT: Copyright 2026 <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define AHCI_MAX_PORTS 32
|
||||
#define AHCI_MAX_PORT_DEVICES 1
|
||||
#define AHCI_MAX_PMP_DEVICES 15
|
||||
#define AHCI_MAX_COMMAND_SLOTS 32
|
||||
|
||||
#define AHCI_MAX_PRDT_ENTRIES 0x000FFFFF // 65535
|
||||
#define AHCI_MAX_PRD_LENGTH 0x003FFFFF // 4MB
|
||||
|
||||
#define AHCI_PMP_CONTROL_PORT 15
|
||||
|
||||
#define AHCI_COMMAND_TABLE_ALIGNMENT 128
|
||||
#define AHCI_RECEIVED_FIS_ALIGNMENT 256
|
||||
#define AHCI_COMMAND_LIST_ALIGNMENT 1024
|
||||
#define AHCI_RECEIVED_FIS_FBS_ALIGNMENT 4096
|
||||
|
||||
#define AHCI_FBS_RECEIVE_AREA_SIZE 4096
|
||||
|
||||
#define AHCI_DELAY_1_SECOND (1000 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_CR_START_STOP (500 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_FR_START_STOP (500 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_DET_PRESENCE (40 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_DET_STABLE (200 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_READY_DRIVE (10000 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_PMP_READY_DRIVE (400 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_PMP_DET_PRESENSE (100 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_PMP_DET_STABLE (300 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_CLO_CLEAR (10 / PORT_TIMER_TICK_MS)
|
||||
#define AHCI_DELAY_INTERFACE_CHANGE (10 / PORT_TIMER_TICK_MS)
|
||||
|
||||
#define AHCI_FIS_REGISTER_HOST_TO_DEVICE 0x27
|
||||
#define AHCI_FIS_REGISTER_DEVICE_TO_HOST 0x34
|
||||
#define AHCI_FIS_DMA_ACTIVATE_DEVICE_TO_HOST 0x39
|
||||
#define AHCI_FIS_DMA_SETUP 0x41
|
||||
#define AHCI_FIS_DATA 0x46
|
||||
#define AHCI_FIS_BIST_ACTIVATE 0x58
|
||||
#define AHCI_FIS_PIO_SETUP_DEVICE_TO_HOST 0x5F
|
||||
#define AHCI_FIS_SET_DEVICE_BITS_DEVICE_TO_HOST 0xA1
|
||||
|
||||
#define IDE_COMMAND_READ_PORT_MULTIPLIER 0xE4
|
||||
#define IDE_COMMAND_WRITE_PORT_MULTIPLIER 0xE8
|
||||
|
||||
typedef enum _SATA_SCR_REGISTER
|
||||
{
|
||||
ATA_SSTATUS = 0,
|
||||
ATA_SERROR = 1,
|
||||
ATA_SCONTROL = 2,
|
||||
ATA_SACTIVE = 3,
|
||||
ATA_SNOTIFICATION = 4,
|
||||
} SATA_SCR_REGISTER;
|
||||
|
||||
#define AHCI_INTERNAL_SLOT 0
|
||||
|
||||
/**
|
||||
* Port Multiplier Registers
|
||||
*/
|
||||
typedef enum _AHCI_PORT_MULTIPLIER_REGISTER
|
||||
{
|
||||
PmpProductId = 0,
|
||||
PmpRevisionInfo = 1,
|
||||
PmpPortInfo = 2,
|
||||
PmpErrorInfo = 32,
|
||||
PmpErrorControl = 33,
|
||||
PmpPhyEventCounterControl = 34,
|
||||
PmpCapabilities = 64,
|
||||
PmpFeaturesEnabled = 96,
|
||||
#define AHCI_PMP_BIST 0x00000001
|
||||
#define AHCI_PMP_PMREQ 0x00000002
|
||||
#define AHCI_PMP_SSC 0x00000004
|
||||
#define AHCI_PMP_SNTF 0x00000008
|
||||
} AHCI_PORT_MULTIPLIER_REGISTER;
|
||||
|
||||
typedef enum _AHCI_HOST_BUS_ADAPTER_REGISTER
|
||||
{
|
||||
HbaCapabilities = 0x00,
|
||||
HbaGlobalControl = 0x04,
|
||||
HbaInterruptStatus = 0x08,
|
||||
HbaPortBitmap = 0x0C,
|
||||
HbaAhciVersion = 0x10,
|
||||
HbaCoalescingControl = 0x14,
|
||||
HbaCoalescingPorts = 0x18,
|
||||
HbaEnclosureManagementLocation = 0x1C,
|
||||
HbaEnclosureManagementControl = 0x20,
|
||||
HbaCapabilitiesEx = 0x24,
|
||||
HbaBiosHandoffControl = 0x28,
|
||||
} AHCI_HOST_BUS_ADAPTER_REGISTER;
|
||||
|
||||
typedef enum _AHCI_PORT_REGISTER
|
||||
{
|
||||
PxCommandListBaseLow = 0x00,
|
||||
PxCommandListBaseHigh = 0x04,
|
||||
PxFisBaseLow = 0x08,
|
||||
PxFisBaseHigh = 0x0C,
|
||||
PxInterruptStatus = 0x10,
|
||||
PxInterruptEnable = 0x14,
|
||||
PxCmdStatus = 0x18,
|
||||
PxTaskFileData = 0x20,
|
||||
PxSignature = 0x24,
|
||||
PxSataStatus = 0x28,
|
||||
PxSataControl = 0x2C,
|
||||
PxSataError = 0x30,
|
||||
PxSataActive = 0x34,
|
||||
PxCommandIssue = 0x38,
|
||||
PxSataNotification = 0x3C,
|
||||
PxFisSwitchingControl = 0x40,
|
||||
PxDeviceSleep = 0x44,
|
||||
} AHCI_PORT_REGISTER;
|
||||
|
||||
/*
|
||||
* Interrupt Status/Enable Register
|
||||
*/
|
||||
#define AHCI_PXIRQ_DHRS 0x00000001
|
||||
#define AHCI_PXIRQ_PSS 0x00000002
|
||||
#define AHCI_PXIRQ_DSS 0x00000004
|
||||
#define AHCI_PXIRQ_SDBS 0x00000008
|
||||
#define AHCI_PXIRQ_UFS 0x00000010
|
||||
#define AHCI_PXIRQ_DPS 0x00000020
|
||||
#define AHCI_PXIRQ_PCS 0x00000040
|
||||
#define AHCI_PXIRQ_DMPS 0x00000080
|
||||
#define AHCI_PXIRQ_RSV1 0x003FFF00
|
||||
#define AHCI_PXIRQ_PRCS 0x00400000
|
||||
#define AHCI_PXIRQ_IPMS 0x00800000
|
||||
#define AHCI_PXIRQ_OFS 0x01000000
|
||||
#define AHCI_PXIRQ_RSV2 0x02000000
|
||||
#define AHCI_PXIRQ_INFS 0x04000000
|
||||
#define AHCI_PXIRQ_IFS 0x08000000
|
||||
#define AHCI_PXIRQ_HBDS 0x10000000
|
||||
#define AHCI_PXIRQ_HBFS 0x20000000
|
||||
#define AHCI_PXIRQ_TFES 0x40000000
|
||||
#define AHCI_PXIRQ_CPDS 0x80000000
|
||||
|
||||
#define AHCI_PXIRQ_FATAL_ERROR \
|
||||
(AHCI_PXIRQ_TFES | AHCI_PXIRQ_IFS | AHCI_PXIRQ_HBDS | AHCI_PXIRQ_HBFS)
|
||||
|
||||
#define AHCI_PXIRQ_PORT_STATUS \
|
||||
(AHCI_PXIRQ_PCS | AHCI_PXIRQ_PRCS | AHCI_PXIRQ_DMPS)
|
||||
|
||||
/*
|
||||
* Command and Status Register
|
||||
*/
|
||||
#define AHCI_PXCMD_ST 0x00000001
|
||||
#define AHCI_PXCMD_SUD 0x00000002
|
||||
#define AHCI_PXCMD_POD 0x00000004
|
||||
#define AHCI_PXCMD_CLO 0x00000008
|
||||
#define AHCI_PXCMD_FRE 0x00000010
|
||||
#define AHCI_PXCMD_RSV 0x000000E0
|
||||
#define AHCI_PXCMD_CCS_MASK 0x00001F00
|
||||
#define AHCI_PXCMD_MPSS 0x00002000
|
||||
#define AHCI_PXCMD_FR 0x00004000
|
||||
#define AHCI_PXCMD_CR 0x00008000
|
||||
#define AHCI_PXCMD_CPS 0x00010000
|
||||
#define AHCI_PXCMD_PMA 0x00020000
|
||||
#define AHCI_PXCMD_HPCP 0x00040000
|
||||
#define AHCI_PXCMD_MPSP 0x00080000
|
||||
#define AHCI_PXCMD_CPD 0x00100000
|
||||
#define AHCI_PXCMD_ESP 0x00200000
|
||||
#define AHCI_PXCMD_FBSCP 0x00400000
|
||||
#define AHCI_PXCMD_APSTE 0x00800000
|
||||
#define AHCI_PXCMD_ATAPI 0x01000000
|
||||
#define AHCI_PXCMD_DLAE 0x02000000
|
||||
#define AHCI_PXCMD_ALPE 0x04000000
|
||||
#define AHCI_PXCMD_ASP 0x08000000
|
||||
#define AHCI_PXCMD_ICC_MASK 0xF0000000
|
||||
|
||||
#define AHCI_PXCMD_ICC_IDLE 0x00000000
|
||||
#define AHCI_PXCMD_ICC_ACTIVE 0x10000000
|
||||
#define AHCI_PXCMD_ICC_PARTIAL 0x20000000
|
||||
#define AHCI_PXCMD_ICC_SLUMBER 0x60000000
|
||||
#define AHCI_PXCMD_ICC_DEVSLEEP 0x80000000
|
||||
|
||||
#define AHCI_PXCMD_ICC_DEVSLEEP 0x80000000
|
||||
|
||||
#define AHCI_PXCMD_CCS_SHIFT 8
|
||||
|
||||
#define AHCI_PXCMD_CCS(Value) (((Value) & AHCI_PXCMD_CCS_MASK) >> AHCI_PXCMD_CCS_SHIFT)
|
||||
|
||||
/*
|
||||
* Task File Data Register
|
||||
*/
|
||||
#define AHCI_PXTFD_STATUS_MASK 0x000000FF
|
||||
#define AHCI_PXTFD_ERROR_MASK 0x0000FF00
|
||||
|
||||
#define AHCI_PXTFD_ERROR_SHIFT 8
|
||||
|
||||
/*
|
||||
* Signature Register
|
||||
*/
|
||||
#define AHCI_PXSIG_INVALID 0xFFFFFFFF
|
||||
#define AHCI_PXSIG_ATAPI 0xEB140101
|
||||
#define AHCI_PXSIG_PMP 0x96690101
|
||||
|
||||
/*
|
||||
* Some PATA ATAPI devices (NEC CDR-C251) do not update the Sector Count and LBA Low registers.
|
||||
* Just to be safe, the contents of these registers is also ignored for AHCI devices.
|
||||
*/
|
||||
#define AHCI_PXSIG_MASK 0xFFFF0000
|
||||
|
||||
/*
|
||||
* Serial ATA Status Register
|
||||
*/
|
||||
#define AHCI_PXSSTS_DET_MASK 0x0000000F
|
||||
#define AHCI_PXSSTS_SPD_MASK 0x000000F0
|
||||
#define AHCI_PXSSTS_IPM_MASK 0x00000F00
|
||||
|
||||
#define AHCI_PXSSTS_DET_NO_DEVICE 0x00000000
|
||||
#define AHCI_PXSSTS_DET_PHY_NOT_READY 0x00000001
|
||||
#define AHCI_PXSSTS_DET_PHY_OK 0x00000003
|
||||
#define AHCI_PXSSTS_DET_PHY_OFFLINE 0x00000004
|
||||
|
||||
#define AHCI_PXSSTS_SPD_UNKNOWN 0x00000000
|
||||
#define AHCI_PXSSTS_SPD_SATA1 0x00000010
|
||||
#define AHCI_PXSSTS_SPD_SATA2 0x00000020
|
||||
#define AHCI_PXSSTS_SPD_SATA3 0x00000030
|
||||
|
||||
#define AHCI_PXSSTS_IPM_NO_DEVICE 0x00000000
|
||||
#define AHCI_PXSSTS_IPM_ACTIVE 0x00000100
|
||||
#define AHCI_PXSSTS_IPM_PARTIAL 0x00000200
|
||||
#define AHCI_PXSSTS_IPM_SLUMBER 0x00000600
|
||||
#define AHCI_PXSSTS_IPM_DEVSLEEP 0x00000800
|
||||
|
||||
/*
|
||||
* Serial ATA Control Register
|
||||
*/
|
||||
#define AHCI_PXCTL_DET_MASK 0x0000000F
|
||||
#define AHCI_PXCTL_SPD_MASK 0x000000F0
|
||||
#define AHCI_PXCTL_IPM_MASK 0x00000F00
|
||||
|
||||
#define AHCI_PXCTL_DET_IDLE 0x00000000
|
||||
#define AHCI_PXCTL_DET_RESET 0x00000001
|
||||
#define AHCI_PXCTL_DET_DISABLE_SATA 0x00000004
|
||||
|
||||
#define AHCI_PXCTL_SPD_LIMIT_NONE 0x00000000
|
||||
#define AHCI_PXCTL_SPD_LIMIT_SATA1 0x00000010
|
||||
#define AHCI_PXCTL_SPD_LIMIT_SATA2 0x00000020
|
||||
#define AHCI_PXCTL_SPD_LIMIT_SATA3 0x00000030
|
||||
|
||||
#define AHCI_PXCTL_SPD_LIMIT_LEVEL 0x00000010
|
||||
|
||||
#define AHCI_PXCTL_IPM_DISABLE_NONE 0x00000000
|
||||
#define AHCI_PXCTL_IPM_DISABLE_PARTIAL 0x00000100
|
||||
#define AHCI_PXCTL_IPM_DISABLE_SLUMBER 0x00000200
|
||||
#define AHCI_PXCTL_IPM_DISABLE_DEVSLEEP 0x00000400
|
||||
|
||||
#define AHCI_PXCTL_IPM_DISABLE_ALL 0x00000700
|
||||
|
||||
/*
|
||||
* FIS-based Switching Control Register
|
||||
*/
|
||||
#define AHCI_FBS_ENABLE 0x00000001
|
||||
#define AHCI_FBS_DEV_ERROR_CLEAR 0x00000002
|
||||
#define AHCI_FBS_SINGLE_DEV_ERROR 0x00000004
|
||||
#define AHCI_FBS_ISSUE_MASK 0x00000F00
|
||||
#define AHCI_FBS_ACTIVE_DEV_OPT_MASK 0x0000F000
|
||||
#define AHCI_FBS_DEV_WITH_ERROR_MASK 0x000F0000
|
||||
|
||||
#define AHCI_FBS_ISSUE_SHIFT 8
|
||||
|
||||
/*
|
||||
* Device Sleep Register
|
||||
*/
|
||||
#define AHCI_PXDEVSLP_ADSE 0x00000001
|
||||
#define AHCI_PXDEVSLP_DSP 0x00000002
|
||||
#define AHCI_PXDEVSLP_DETO_MASK 0x000003FC
|
||||
#define AHCI_PXDEVSLP_MDAT_MASK 0x00007C00
|
||||
#define AHCI_PXDEVSLP_DITO_MASK 0x01FF8000
|
||||
#define AHCI_PXDEVSLP_DM_MASK 0x1E000000
|
||||
|
||||
#define AHCI_PORT_INTERRUPT_MASK \
|
||||
(AHCI_PXIRQ_DHRS | \
|
||||
AHCI_PXIRQ_PSS | \
|
||||
AHCI_PXIRQ_DSS | \
|
||||
AHCI_PXIRQ_SDBS | \
|
||||
AHCI_PXIRQ_UFS | \
|
||||
AHCI_PXIRQ_DPS | \
|
||||
AHCI_PXIRQ_PCS | \
|
||||
AHCI_PXIRQ_DMPS | \
|
||||
AHCI_PXIRQ_PRCS | \
|
||||
AHCI_PXIRQ_IPMS | \
|
||||
AHCI_PXIRQ_OFS | \
|
||||
AHCI_PXIRQ_INFS | \
|
||||
AHCI_PXIRQ_IFS | \
|
||||
AHCI_PXIRQ_HBDS | \
|
||||
AHCI_PXIRQ_HBFS | \
|
||||
AHCI_PXIRQ_TFES | \
|
||||
AHCI_PXIRQ_CPDS)
|
||||
|
||||
/*
|
||||
* AHCI Version Register
|
||||
*/
|
||||
#define AHCI_VERSION_0_95 0x00000905
|
||||
#define AHCI_VERSION_1_0 0x00010000
|
||||
#define AHCI_VERSION_1_2 0x00010200
|
||||
#define AHCI_VERSION_1_3_0 0x00010300
|
||||
#define AHCI_VERSION_1_3_1 0x00010301
|
||||
|
||||
/*
|
||||
* Global HBA Control Register
|
||||
*/
|
||||
#define AHCI_GHC_HR 0x00000001
|
||||
#define AHCI_GHC_IE 0x00000002
|
||||
#define AHCI_GHC_MRSM 0x00000004
|
||||
#define AHCI_GHC_AE 0x80000000
|
||||
|
||||
/*
|
||||
* HBA Capabilities Register
|
||||
*/
|
||||
#define AHCI_CAP_NP 0x0000001F
|
||||
#define AHCI_CAP_SXS 0x00000020
|
||||
#define AHCI_CAP_EMS 0x00000040
|
||||
#define AHCI_CAP_CCCS 0x00000080
|
||||
#define AHCI_CAP_NCS 0x00001F00
|
||||
#define AHCI_CAP_PSC 0x00002000
|
||||
#define AHCI_CAP_SSC 0x00004000
|
||||
#define AHCI_CAP_PMD 0x00008000
|
||||
#define AHCI_CAP_FBSS 0x00010000
|
||||
#define AHCI_CAP_SPM 0x00020000
|
||||
#define AHCI_CAP_SAM 0x00040000
|
||||
#define AHCI_CAP_RSV 0x00080000
|
||||
#define AHCI_CAP_ISS 0x00F00000
|
||||
#define AHCI_CAP_SCLO 0x01000000
|
||||
#define AHCI_CAP_SAL 0x02000000
|
||||
#define AHCI_CAP_SALP 0x04000000
|
||||
#define AHCI_CAP_SSS 0x08000000
|
||||
#define AHCI_CAP_SMPS 0x10000000
|
||||
#define AHCI_CAP_SSNTF 0x20000000
|
||||
#define AHCI_CAP_SNCQ 0x40000000
|
||||
#define AHCI_CAP_S64A 0x80000000
|
||||
|
||||
/*
|
||||
* HBA Capabilities Extended Register
|
||||
*/
|
||||
#define AHCI_CAP2_BOH 0x00000001
|
||||
#define AHCI_CAP2_NVMP 0x00000002
|
||||
#define AHCI_CAP2_APST 0x00000004
|
||||
#define AHCI_CAP2_SDS 0x00000008
|
||||
#define AHCI_CAP2_SADM 0x00000010
|
||||
#define AHCI_CAP2_DESO 0x00000020
|
||||
|
||||
#define AHCI_BOHC_BIOS_SEMAPHORE 0x00000001
|
||||
#define AHCI_BOHC_OS_SEMAPHORE 0x00000002
|
||||
#define AHCI_BOHC_SMI_ON_OS_OWNERSHIP_CHANGE 0x00000004
|
||||
#define AHCI_BOHC_OS_OWNERSHIP_CHANGE 0x00000008
|
||||
#define AHCI_BOHC_BIOS_BUSY 0x00000010
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
typedef struct _AHCI_FIS_HOST_TO_DEVICE
|
||||
{
|
||||
UCHAR Type; // 0x27
|
||||
|
||||
UCHAR Flags;
|
||||
#define UPDATE_COMMAND 0x80
|
||||
#define PMP_NUMBER 0x0F
|
||||
|
||||
UCHAR Command;
|
||||
UCHAR Features;
|
||||
UCHAR LbaLow;
|
||||
UCHAR LbaMid;
|
||||
UCHAR LbaHigh;
|
||||
UCHAR Device;
|
||||
UCHAR LbaLowEx;
|
||||
UCHAR LbaMidEx;
|
||||
UCHAR LbaHighEx;
|
||||
UCHAR FeaturesEx;
|
||||
UCHAR SectorCount;
|
||||
UCHAR SectorCountEx;
|
||||
UCHAR Icc;
|
||||
UCHAR Control;
|
||||
ULONG Auxiliary;
|
||||
} AHCI_FIS_HOST_TO_DEVICE, *PAHCI_FIS_HOST_TO_DEVICE;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_FIS_HOST_TO_DEVICE) == 20);
|
||||
|
||||
typedef struct _AHCI_FIS_PIO_SETUP
|
||||
{
|
||||
UCHAR Type; // 0x5F
|
||||
|
||||
UCHAR Flags;
|
||||
|
||||
UCHAR Status;
|
||||
UCHAR Error;
|
||||
UCHAR LbaLow;
|
||||
UCHAR LbaMid;
|
||||
UCHAR LbaHigh;
|
||||
UCHAR Device;
|
||||
UCHAR LbaLowEx;
|
||||
UCHAR LbaMidEx;
|
||||
UCHAR LbaHighEx;
|
||||
UCHAR Reserved;
|
||||
UCHAR SectorCount;
|
||||
UCHAR SectorCountEx;
|
||||
UCHAR Reserved1;
|
||||
UCHAR EStatus;
|
||||
USHORT TransferCount;
|
||||
USHORT Reserved2;
|
||||
} AHCI_FIS_PIO_SETUP, *PAHCI_FIS_PIO_SETUP;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_FIS_PIO_SETUP) == 20);
|
||||
|
||||
typedef struct _AHCI_FIS_DEVICE_TO_HOST
|
||||
{
|
||||
UCHAR Type; // 0x34
|
||||
|
||||
UCHAR Flags;
|
||||
|
||||
UCHAR Status;
|
||||
UCHAR Error;
|
||||
UCHAR LbaLow;
|
||||
UCHAR LbaMid;
|
||||
UCHAR LbaHigh;
|
||||
UCHAR Device;
|
||||
UCHAR LbaLowEx;
|
||||
UCHAR LbaMidEx;
|
||||
UCHAR LbaHighEx;
|
||||
UCHAR Reserved;
|
||||
UCHAR SectorCount;
|
||||
UCHAR SectorCountEx;
|
||||
UCHAR Reserved1;
|
||||
UCHAR Reserved2;
|
||||
ULONG Reserved3;
|
||||
} AHCI_FIS_DEVICE_TO_HOST, *PAHCI_FIS_DEVICE_TO_HOST;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_FIS_DEVICE_TO_HOST) == 20);
|
||||
|
||||
typedef struct _AHCI_FIS_SET_DEVICE_BITS
|
||||
{
|
||||
UCHAR Type; // 0xA1
|
||||
|
||||
UCHAR Flags;
|
||||
|
||||
UCHAR Status;
|
||||
UCHAR Error;
|
||||
ULONG Reserved;
|
||||
} AHCI_FIS_SET_DEVICE_BITS, *PAHCI_FIS_SET_DEVICE_BITS;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_FIS_SET_DEVICE_BITS) == 8);
|
||||
|
||||
typedef struct _AHCI_RECEIVED_FIS
|
||||
{
|
||||
UCHAR DmaSetupFis[0x1C];
|
||||
ULONG Reserved;
|
||||
|
||||
AHCI_FIS_PIO_SETUP PioSetupFis;
|
||||
ULONG Reserved2[3];
|
||||
|
||||
AHCI_FIS_DEVICE_TO_HOST DeviceToHostFis;
|
||||
ULONG Reserved3;
|
||||
|
||||
AHCI_FIS_SET_DEVICE_BITS SetDeviceBitsFis;
|
||||
|
||||
UCHAR UnknownFis[0x40];
|
||||
|
||||
UCHAR Reserved4[0x60];
|
||||
} AHCI_RECEIVED_FIS, *PAHCI_RECEIVED_FIS;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_RECEIVED_FIS) == 256);
|
||||
|
||||
typedef struct _AHCI_COMMAND_HEADER
|
||||
{
|
||||
ULONG Control;
|
||||
#define AHCI_COMMAND_HEADER_COMMAND_FIS_LENGTH 0x0000001F
|
||||
#define AHCI_COMMAND_HEADER_ATAPI 0x00000020
|
||||
#define AHCI_COMMAND_HEADER_WRITE 0x00000040
|
||||
#define AHCI_COMMAND_HEADER_PREFETCHABLE 0x00000080
|
||||
#define AHCI_COMMAND_HEADER_RESET 0x00000100
|
||||
#define AHCI_COMMAND_HEADER_BIST 0x00000200
|
||||
#define AHCI_COMMAND_HEADER_CLEAR_BUSY_UPON_OK 0x00000400
|
||||
#define AHCI_COMMAND_HEADER_PMP 0x0000F000
|
||||
#define AHCI_COMMAND_HEADER_PRDT_LENGTH 0xFFFF0000
|
||||
|
||||
#define AHCI_COMMAND_HEADER_PRDT_LENGTH_SHIFT 16
|
||||
#define AHCI_COMMAND_HEADER_PMP_SHIFT 12
|
||||
|
||||
ULONG PrdByteCount;
|
||||
ULONG CommandTableBaseLow;
|
||||
ULONG CommandTableBaseHigh;
|
||||
ULONG Reserved[4];
|
||||
} AHCI_COMMAND_HEADER, *PAHCI_COMMAND_HEADER;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_COMMAND_HEADER) == 32);
|
||||
|
||||
typedef struct _AHCI_COMMAND_LIST
|
||||
{
|
||||
AHCI_COMMAND_HEADER CommandHeader[ANYSIZE_ARRAY];
|
||||
} AHCI_COMMAND_LIST, *PAHCI_COMMAND_LIST;
|
||||
|
||||
typedef struct _AHCI_PRD_TABLE_ENTRY
|
||||
{
|
||||
ULONG DataBaseLow;
|
||||
ULONG DataBaseHigh;
|
||||
ULONG Reserved;
|
||||
|
||||
ULONG ByteCount;
|
||||
#define AHCI_PRD_INTERRUPT_ON_COMPLETION 0x80000000
|
||||
|
||||
} AHCI_PRD_TABLE_ENTRY, *PAHCI_PRD_TABLE_ENTRY;
|
||||
|
||||
C_ASSERT(sizeof(AHCI_PRD_TABLE_ENTRY) == 16);
|
||||
|
||||
typedef struct _AHCI_COMMAND_TABLE
|
||||
{
|
||||
union
|
||||
{
|
||||
AHCI_FIS_HOST_TO_DEVICE HostToDeviceFis;
|
||||
UCHAR CommandFis[64];
|
||||
};
|
||||
UCHAR AtapiCommand[16];
|
||||
UCHAR Reserved[48];
|
||||
AHCI_PRD_TABLE_ENTRY PrdTable[ANYSIZE_ARRAY];
|
||||
} AHCI_COMMAND_TABLE, *PAHCI_COMMAND_TABLE;
|
||||
|
||||
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, PrdTable) == 128);
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
#define AHCI_PORT_BASE(HbaIoBase, PortNumber) \
|
||||
(PULONG)((ULONG_PTR)(HbaIoBase) + (PortNumber) * 0x80 + 0x100)
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
AHCI_HBA_READ(
|
||||
_In_ PVOID HbaIoBase,
|
||||
_In_ AHCI_HOST_BUS_ADAPTER_REGISTER Register)
|
||||
{
|
||||
return READ_REGISTER_ULONG((PULONG)((ULONG_PTR)HbaIoBase + Register));
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
AHCI_HBA_WRITE(
|
||||
_In_ PVOID HbaIoBase,
|
||||
_In_ AHCI_HOST_BUS_ADAPTER_REGISTER Register,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
WRITE_REGISTER_ULONG((PULONG)((ULONG_PTR)HbaIoBase + Register), Value);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
AHCI_PORT_READ(
|
||||
_In_ PVOID PortIoBase,
|
||||
_In_ AHCI_PORT_REGISTER Register)
|
||||
{
|
||||
return READ_REGISTER_ULONG((PULONG)((ULONG_PTR)PortIoBase + Register));
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
AHCI_PORT_WRITE(
|
||||
_In_ PVOID PortIoBase,
|
||||
_In_ AHCI_PORT_REGISTER Register,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
WRITE_REGISTER_ULONG((PULONG)((ULONG_PTR)PortIoBase + Register), Value);
|
||||
}
|
||||
752
drivers/storage/ide/pciidex/chipset/ahci_generic.c
Normal file
752
drivers/storage/ide/pciidex/chipset/ahci_generic.c
Normal file
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: AHCI controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const struct
|
||||
{
|
||||
USHORT VendorID;
|
||||
USHORT DeviceID;
|
||||
} AhciControllerList[] =
|
||||
{
|
||||
{ PCI_VEN_NVIDIA, 0x0550 },
|
||||
{ PCI_VEN_NVIDIA, 0x0584 },
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AtaAhciAllocateMemory(
|
||||
_In_ PVOID ChannelContext)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
PDMA_OPERATIONS DmaOperations = ChanData->DmaAdapter->DmaOperations;
|
||||
ULONG i, j, SlotNumber, CommandSlots, BlockSize;
|
||||
ULONG CommandListSize, CommandTableLength, CommandTablesPerPage;
|
||||
PVOID Buffer;
|
||||
ULONG_PTR BufferVa;
|
||||
ULONG64 BufferPa;
|
||||
PHYSICAL_ADDRESS PhysicalAddress;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* The maximum size of the command list is 1024 bytes */
|
||||
CommandSlots = ChanData->Controller->QueueDepth;
|
||||
CommandListSize = FIELD_OFFSET(AHCI_COMMAND_LIST, CommandHeader[CommandSlots]);
|
||||
BlockSize = CommandListSize + (AHCI_COMMAND_LIST_ALIGNMENT - 1);
|
||||
|
||||
/* Add the receive area structure (256 bytes) */
|
||||
if (!(ChanData->ChanInfo & CHANNEL_FLAG_HAS_FBS))
|
||||
{
|
||||
BlockSize += sizeof(AHCI_RECEIVED_FIS);
|
||||
|
||||
/* The command list is 1024-byte aligned, which saves us some bytes of allocation size */
|
||||
BlockSize += ALIGN_UP_BY(CommandListSize, AHCI_RECEIVED_FIS_ALIGNMENT) - CommandListSize;
|
||||
}
|
||||
|
||||
Buffer = DmaOperations->AllocateCommonBuffer(ChanData->DmaAdapter,
|
||||
BlockSize,
|
||||
&PhysicalAddress,
|
||||
TRUE); // Cached
|
||||
if (!Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlZeroMemory(Buffer, BlockSize);
|
||||
|
||||
ChanData->Mem.CommandListSize = BlockSize;
|
||||
ChanData->Mem.CommandListOriginal = Buffer;
|
||||
ChanData->Mem.CommandListPhysOriginal.QuadPart = PhysicalAddress.QuadPart;
|
||||
|
||||
BufferVa = (ULONG_PTR)Buffer;
|
||||
BufferPa = PhysicalAddress.QuadPart;
|
||||
|
||||
/* Command list */
|
||||
BufferVa = ALIGN_UP_BY(BufferVa, AHCI_COMMAND_LIST_ALIGNMENT);
|
||||
BufferPa = ALIGN_UP_BY(BufferPa, AHCI_COMMAND_LIST_ALIGNMENT);
|
||||
ChanData->CommandList = (PVOID)BufferVa;
|
||||
ChanData->Mem.CommandListPhys = BufferPa;
|
||||
BufferVa += CommandListSize;
|
||||
BufferPa += CommandListSize;
|
||||
|
||||
/* Alignment requirement */
|
||||
ASSERT((ULONG_PTR)ChanData->Mem.CommandListPhys % AHCI_COMMAND_LIST_ALIGNMENT == 0);
|
||||
|
||||
/* Received FIS structure */
|
||||
if (!(ChanData->ChanInfo & CHANNEL_FLAG_HAS_FBS))
|
||||
{
|
||||
BufferVa = ALIGN_UP_BY(BufferVa, AHCI_RECEIVED_FIS_ALIGNMENT);
|
||||
BufferPa = ALIGN_UP_BY(BufferPa, AHCI_RECEIVED_FIS_ALIGNMENT);
|
||||
ChanData->ReceivedFis = (PVOID)BufferVa;
|
||||
ChanData->Mem.ReceivedFisPhys = BufferPa;
|
||||
BufferVa += sizeof(AHCI_RECEIVED_FIS);
|
||||
BufferPa += sizeof(AHCI_RECEIVED_FIS);
|
||||
|
||||
/* Alignment requirement */
|
||||
ASSERT((ULONG_PTR)ChanData->Mem.ReceivedFisPhys % AHCI_RECEIVED_FIS_ALIGNMENT == 0);
|
||||
}
|
||||
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_HAS_FBS)
|
||||
{
|
||||
/* The FBS receive area is 4kB, allocate a page which is also 4kB-aligned */
|
||||
BlockSize = PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* Some other architectures, like ia64, use a different page size,
|
||||
* that is a multiple of 4096.
|
||||
*/
|
||||
C_ASSERT(PAGE_SIZE % AHCI_RECEIVED_FIS_FBS_ALIGNMENT == 0);
|
||||
|
||||
Buffer = DmaOperations->AllocateCommonBuffer(ChanData->DmaAdapter,
|
||||
BlockSize,
|
||||
&PhysicalAddress,
|
||||
TRUE);
|
||||
if (!Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlZeroMemory(Buffer, BlockSize);
|
||||
|
||||
ChanData->Mem.ReceivedFisOriginal = Buffer;
|
||||
ChanData->Mem.ReceivedFisPhysOriginal.QuadPart = PhysicalAddress.QuadPart;
|
||||
|
||||
BufferVa = (ULONG_PTR)Buffer;
|
||||
BufferPa = PhysicalAddress.QuadPart;
|
||||
|
||||
ChanData->ReceivedFis = (PVOID)BufferVa;
|
||||
ChanData->Mem.ReceivedFisPhys = BufferPa;
|
||||
|
||||
/* Alignment requirement */
|
||||
ASSERT(BufferPa % AHCI_RECEIVED_FIS_FBS_ALIGNMENT == 0);
|
||||
}
|
||||
|
||||
/* 32-bit DMA */
|
||||
if (!(ChanData->ChanInfo & CHANNEL_FLAG_64_BIT_DMA))
|
||||
{
|
||||
ASSERT((ULONG)(ChanData->Mem.CommandListPhys >> 32) == 0);
|
||||
ASSERT((ULONG)(ChanData->Mem.ReceivedFisPhys >> 32) == 0);
|
||||
}
|
||||
|
||||
CommandTableLength = FIELD_OFFSET(AHCI_COMMAND_TABLE, PrdTable[ChanData->MaximumPhysicalPages]);
|
||||
|
||||
ASSERT(ChanData->MaximumPhysicalPages != 0 &&
|
||||
ChanData->MaximumPhysicalPages <= AHCI_MAX_PRDT_ENTRIES);
|
||||
|
||||
/*
|
||||
* See ATA_MAX_TRANSFER_LENGTH, currently the MaximumPhysicalPages is restricted to
|
||||
* a maximum of (0x20000 / PAGE_SIZE) + 1 = 33 pages.
|
||||
* Each command table will require us 128 + 16 * 33 + (128 - 1) = 783 bytes of shared memory.
|
||||
*/
|
||||
ASSERT(PAGE_SIZE > (CommandTableLength + (AHCI_COMMAND_TABLE_ALIGNMENT - 1)));
|
||||
|
||||
/* Allocate one-page chunks to avoid having a large chunk of contiguous memory */
|
||||
CommandTablesPerPage = PAGE_SIZE / (CommandTableLength + (AHCI_COMMAND_TABLE_ALIGNMENT - 1));
|
||||
|
||||
/* Command tables allocation loop */
|
||||
SlotNumber = 0;
|
||||
i = CommandSlots;
|
||||
while (i > 0)
|
||||
{
|
||||
ULONG TableCount;
|
||||
|
||||
TableCount = min(i, CommandTablesPerPage);
|
||||
BlockSize = (CommandTableLength + (AHCI_COMMAND_TABLE_ALIGNMENT - 1)) * TableCount;
|
||||
|
||||
/* Allocate a chunk of memory */
|
||||
Buffer = DmaOperations->AllocateCommonBuffer(ChanData->DmaAdapter,
|
||||
BlockSize,
|
||||
&PhysicalAddress,
|
||||
TRUE);
|
||||
if (!Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlZeroMemory(Buffer, BlockSize);
|
||||
|
||||
ChanData->Mem.CommandTableOriginal[SlotNumber] = Buffer;
|
||||
ChanData->Mem.CommandTablePhysOriginal[SlotNumber].QuadPart = PhysicalAddress.QuadPart;
|
||||
ChanData->Mem.CommandTableSize[SlotNumber] = BlockSize;
|
||||
|
||||
BufferVa = (ULONG_PTR)Buffer;
|
||||
BufferPa = PhysicalAddress.QuadPart;
|
||||
|
||||
/* Split the allocation into command tables */
|
||||
for (j = 0; j < TableCount; ++j)
|
||||
{
|
||||
PAHCI_COMMAND_HEADER CommandHeader;
|
||||
|
||||
BufferVa = ALIGN_UP_BY(BufferVa, AHCI_COMMAND_TABLE_ALIGNMENT);
|
||||
BufferPa = ALIGN_UP_BY(BufferPa, AHCI_COMMAND_TABLE_ALIGNMENT);
|
||||
|
||||
/* Alignment requirement */
|
||||
ASSERT(BufferPa % AHCI_COMMAND_TABLE_ALIGNMENT == 0);
|
||||
|
||||
/* 32-bit DMA */
|
||||
if (!(ChanData->ChanInfo & CHANNEL_FLAG_64_BIT_DMA))
|
||||
{
|
||||
ASSERT((ULONG)(BufferPa >> 32) == 0);
|
||||
}
|
||||
|
||||
ChanData->CommandTable[SlotNumber] = (PAHCI_COMMAND_TABLE)BufferVa;
|
||||
|
||||
CommandHeader = &ChanData->CommandList->CommandHeader[SlotNumber];
|
||||
CommandHeader->CommandTableBaseLow = (ULONG)BufferPa;
|
||||
CommandHeader->CommandTableBaseHigh = (ULONG)(BufferPa >> 32);
|
||||
|
||||
++SlotNumber;
|
||||
BufferVa += CommandTableLength;
|
||||
BufferPa += CommandTableLength;
|
||||
}
|
||||
|
||||
i -= TableCount;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
AtaAhciFreeMemory(
|
||||
_In_ PVOID ChannelContext)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
PDMA_ADAPTER DmaAdapter = ChanData->DmaAdapter;
|
||||
PDMA_OPERATIONS DmaOperations = ChanData->DmaAdapter->DmaOperations;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (ChanData->Mem.CommandListOriginal)
|
||||
{
|
||||
DmaOperations->FreeCommonBuffer(DmaAdapter,
|
||||
ChanData->Mem.CommandListSize,
|
||||
ChanData->Mem.CommandListPhysOriginal,
|
||||
ChanData->Mem.CommandListOriginal,
|
||||
TRUE); // Cached
|
||||
ChanData->Mem.CommandListOriginal = NULL;
|
||||
}
|
||||
|
||||
if (ChanData->Mem.ReceivedFisOriginal)
|
||||
{
|
||||
DmaOperations->FreeCommonBuffer(DmaAdapter,
|
||||
PAGE_SIZE,
|
||||
ChanData->Mem.ReceivedFisPhysOriginal,
|
||||
ChanData->Mem.ReceivedFisOriginal,
|
||||
TRUE);
|
||||
ChanData->Mem.ReceivedFisOriginal = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < AHCI_MAX_COMMAND_SLOTS; ++i)
|
||||
{
|
||||
if (ChanData->Mem.CommandTableOriginal[i])
|
||||
{
|
||||
DmaOperations->FreeCommonBuffer(DmaAdapter,
|
||||
ChanData->Mem.CommandTableSize[i],
|
||||
ChanData->Mem.CommandTablePhysOriginal[i],
|
||||
ChanData->Mem.CommandTableOriginal[i],
|
||||
TRUE);
|
||||
ChanData->Mem.CommandTableOriginal[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DBG
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
AtaAhciIsVbox(VOID)
|
||||
{
|
||||
UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_HEADER, DeviceID)];
|
||||
PPCI_COMMON_HEADER PciData = (PPCI_COMMON_HEADER)Buffer; // Partial PCI header
|
||||
ULONG BytesRead;
|
||||
PCI_SLOT_NUMBER Slot;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Slot.u.AsULONG = 0;
|
||||
Slot.u.bits.DeviceNumber = 4;
|
||||
Slot.u.bits.FunctionNumber = 0;
|
||||
|
||||
BytesRead = HalGetBusDataByOffset(PCIConfiguration,
|
||||
0,
|
||||
Slot.u.AsULONG,
|
||||
&Buffer,
|
||||
FIELD_OFFSET(PCI_COMMON_HEADER, VendorID),
|
||||
sizeof(Buffer));
|
||||
return (BytesRead == sizeof(Buffer)) &&
|
||||
(PciData->VendorID == 0x80EE) &&
|
||||
(PciData->DeviceID == 0xCAFE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
AtaAhciHbaRequestOsOwnership(
|
||||
_In_ PVOID IoBase)
|
||||
{
|
||||
ULONG i, Control;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Control = AHCI_HBA_READ(IoBase, HbaBiosHandoffControl);
|
||||
if (Control & AHCI_BOHC_OS_SEMAPHORE)
|
||||
return;
|
||||
|
||||
INFO("HBA ownership change\n");
|
||||
|
||||
AHCI_HBA_WRITE(IoBase, HbaBiosHandoffControl, Control | AHCI_BOHC_OS_SEMAPHORE);
|
||||
|
||||
/* Wait up to 2 seconds */
|
||||
for (i = 0; i < 200000; ++i)
|
||||
{
|
||||
Control = AHCI_HBA_READ(IoBase, HbaBiosHandoffControl);
|
||||
|
||||
if (!(Control & (AHCI_BOHC_BIOS_BUSY | AHCI_BOHC_BIOS_SEMAPHORE)))
|
||||
return;
|
||||
|
||||
KeStallExecutionProcessor(10);
|
||||
}
|
||||
|
||||
WARN("Unable to acquire the OS semaphore %08lx\n", Control);
|
||||
}
|
||||
|
||||
/**
|
||||
* See eSATA paper
|
||||
* http://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/eSATA.docx
|
||||
*/
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
AtaAhciIsPortRemovable(
|
||||
_In_ ULONG AhciCapabilities,
|
||||
_In_ ULONG CmdStatus)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (CmdStatus & AHCI_PXCMD_HPCP)
|
||||
return TRUE;
|
||||
|
||||
if ((AhciCapabilities & AHCI_CAP_SXS) && (CmdStatus & AHCI_PXCMD_ESP))
|
||||
return TRUE;
|
||||
|
||||
if ((AhciCapabilities & AHCI_CAP_SMPS) && (CmdStatus & AHCI_PXCMD_MPSP))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AtaAhciCreateChannelData(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->MaxChannels != 0);
|
||||
|
||||
ChanData = ExAllocatePoolZero(NonPagedPool,
|
||||
sizeof(*ChanData) * Controller->MaxChannels,
|
||||
TAG_PCIIDEX);
|
||||
if (!ChanData)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
Controller->ChanDataBlock = ChanData;
|
||||
|
||||
for (i = 0; i < AHCI_MAX_PORTS; ++i)
|
||||
{
|
||||
ULONG CmdStatus;
|
||||
|
||||
if (!(Controller->ChannelBitmap & (1 << i)))
|
||||
continue;
|
||||
|
||||
Controller->Channels[i] = ChanData;
|
||||
|
||||
ChanData->Channel = i;
|
||||
ChanData->Controller = Controller;
|
||||
|
||||
ChanData->AllocateMemory = AtaAhciAllocateMemory;
|
||||
ChanData->FreeMemory = AtaAhciFreeMemory;
|
||||
ChanData->EnableInterrupts = AtaAhciEnableInterrupts;
|
||||
ChanData->PreparePrdTable = AtaAhciPreparePrdTable;
|
||||
ChanData->PrepareIo = AtaAhciPrepareIo;
|
||||
ChanData->StartIo = AtaAhciStartIo;
|
||||
ChanData->SetTransferMode = SataSetTransferMode;
|
||||
ChanData->TransferModeSupported = SATA_ALL;
|
||||
|
||||
ChanData->IoBase = AHCI_PORT_BASE(Controller->IoBase, i);
|
||||
|
||||
ChanData->EnableInterrupts(ChanData, FALSE);
|
||||
|
||||
/* Begin the process of stopping the command list DMA engine for later initialization */
|
||||
CmdStatus = AHCI_PORT_READ(ChanData->IoBase, PxCmdStatus);
|
||||
if (CmdStatus & AHCI_PXCMD_ST)
|
||||
{
|
||||
CmdStatus &= ~AHCI_PXCMD_ST;
|
||||
AHCI_PORT_WRITE(ChanData->IoBase, PxCmdStatus, CmdStatus);
|
||||
}
|
||||
|
||||
/* The AHCI HBA can only perform DMA I/O and PIO is not supported */
|
||||
ChanData->ChanInfo = CHANNEL_FLAG_PIO_VIA_DMA;
|
||||
|
||||
if (Controller->AhciCapabilities & AHCI_CAP_S64A)
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_64_BIT_DMA;
|
||||
|
||||
if (Controller->AhciCapabilities & AHCI_CAP_SNCQ)
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_HAS_NCQ;
|
||||
|
||||
/* Check for the FIS-based switching feature support */
|
||||
if ((Controller->AhciCapabilities & AHCI_CAP_SPM) &&
|
||||
(Controller->AhciCapabilities & AHCI_CAP_FBSS) &&
|
||||
(CmdStatus & AHCI_PXCMD_FBSCP))
|
||||
{
|
||||
INFO("CH %lu: FBS supported\n", ChanData->Channel);
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_HAS_FBS;
|
||||
}
|
||||
|
||||
if (AtaAhciIsPortRemovable(Controller->AhciCapabilities, CmdStatus))
|
||||
{
|
||||
INFO("CH %lu: Port is external\n", ChanData->Channel);
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_IS_EXTERNAL;
|
||||
}
|
||||
|
||||
++ChanData;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
PVOID
|
||||
AtaAhciGetAbar(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
PVOID Abar;
|
||||
ULONG i, Index;
|
||||
PCIIDEX_PAGED_DATA static const struct
|
||||
{
|
||||
USHORT VendorID;
|
||||
USHORT DeviceID;
|
||||
ULONG Index;
|
||||
} AbarLocations[] =
|
||||
{
|
||||
{ PCI_VEN_CAVIUM, 0xA01C, 0 },
|
||||
};
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Default index */
|
||||
Index = 5;
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(AbarLocations); ++i)
|
||||
{
|
||||
if ((Controller->Pci.VendorID == AbarLocations[i].VendorID) &&
|
||||
(Controller->Pci.DeviceID == AbarLocations[i].DeviceID))
|
||||
{
|
||||
Index = AbarLocations[i].Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Controller->AccessRange[Index].Flags & RANGE_IS_MEMORY))
|
||||
return NULL;
|
||||
|
||||
Abar = AtaCtrlPciMapBar(Controller, Index, 0);
|
||||
if (!Abar)
|
||||
return NULL;
|
||||
|
||||
return Abar;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AtaAhciAttachChannel(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN Attach)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (Attach)
|
||||
{
|
||||
/* We do enable interrupts in the QBR handler */
|
||||
}
|
||||
else
|
||||
{
|
||||
AtaChanEnableInterruptsSync(ChanData, FALSE);
|
||||
AtaAhciStopDma(ChanData);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciHbaStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
ULONG GlobalControl;
|
||||
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
if (!(GlobalControl & AHCI_GHC_AE))
|
||||
{
|
||||
/* Set AE on power up */
|
||||
GlobalControl |= AHCI_GHC_AE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
}
|
||||
|
||||
/* Clear HBA interrupts */
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaInterruptStatus, 0xFFFFFFFF);
|
||||
|
||||
/* Enable interrupts */
|
||||
GlobalControl |= AHCI_GHC_IE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciHbaStop(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
ULONG GlobalControl;
|
||||
KIRQL OldIrql;
|
||||
|
||||
/* Failed to connect interrupt */
|
||||
if (!Controller->InterruptObject)
|
||||
return;
|
||||
|
||||
OldIrql = KeAcquireInterruptSpinLock(Controller->InterruptObject);
|
||||
|
||||
/* Disable interrupts */
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
GlobalControl &= ~AHCI_GHC_IE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
|
||||
/* Clear HBA interrupts */
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaInterruptStatus, 0xFFFFFFFF);
|
||||
|
||||
KeReleaseInterruptSpinLock(Controller->InterruptObject, OldIrql);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
AtaAhciHbaFreeResouces(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (Controller->InterruptObject)
|
||||
{
|
||||
IoDisconnectInterrupt(Controller->InterruptObject);
|
||||
Controller->InterruptObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
AhciControllerIsSubClassCheckNeeded(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (Controller->Pci.VendorID == PCI_VEN_INTEL)
|
||||
{
|
||||
/* IDE or AHCI */
|
||||
if ((Controller->Pci.DeviceID == 0x2652) || (Controller->Pci.DeviceID == 0x2653))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* IDE, RAID, or AHCI */
|
||||
if ((Controller->Pci.VendorID == PCI_VEN_VIA) && (Controller->Pci.DeviceID == 0x3349))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
AhciMatchController(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Some controllers share the same PCI ID between AHCI and IDE/RAID modes */
|
||||
if (AhciControllerIsSubClassCheckNeeded(Controller))
|
||||
{
|
||||
if (Controller->Pci.SubClass != PCI_SUBCLASS_MSC_AHCI_CTLR)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match the controller through the PCI ID.
|
||||
* We do not want to check the PCI subclass code because of
|
||||
* some AHCI controllers that support AHCI even in IDE emulation mode.
|
||||
* For example, nVidia 10DE:0550 uses the same PCI ID between AHCI and IDE modes,
|
||||
* but BAR5 will always be available and AHCI can be enabled by setting GHC.AE to 1.
|
||||
*/
|
||||
for (i = 0; i < RTL_NUMBER_OF(AhciControllerList); ++i)
|
||||
{
|
||||
if ((Controller->Pci.VendorID == AhciControllerList[i].VendorID) &&
|
||||
(Controller->Pci.DeviceID == AhciControllerList[i].DeviceID))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for generic PCI AHCI controller */
|
||||
if ((Controller->Pci.BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
|
||||
(Controller->Pci.SubClass == PCI_SUBCLASS_MSC_AHCI_CTLR))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AhciGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc = &Controller->InterruptDesc;
|
||||
ULONG i, GlobalControl;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!AhciMatchController(Controller))
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
if (Controller->InterruptDesc.Type != CmResourceTypeInterrupt)
|
||||
{
|
||||
ERR("No interrupt resource\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
Controller->IoBase = AtaAhciGetAbar(Controller);
|
||||
if (!Controller->IoBase)
|
||||
return STATUS_NO_MATCH; // Try IDE/RAID
|
||||
|
||||
Controller->Flags = CTRL_FLAG_IS_AHCI | CTRL_FLAG_SATA_HBA_ACPI;
|
||||
Controller->Start = AtaAhciHbaStart;
|
||||
Controller->Stop = AtaAhciHbaStop;
|
||||
Controller->FreeResources = AtaAhciHbaFreeResouces;
|
||||
Controller->AttachChannel = AtaAhciAttachChannel;
|
||||
|
||||
/* Set AE before accessing other AHCI registers */
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
GlobalControl |= AHCI_GHC_AE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
|
||||
Controller->AhciCapabilities = AHCI_HBA_READ(Controller->IoBase, HbaCapabilities);
|
||||
Controller->ChannelBitmap = AHCI_HBA_READ(Controller->IoBase, HbaPortBitmap);
|
||||
Controller->MaxChannels = CountSetBits(Controller->ChannelBitmap);
|
||||
if (Controller->MaxChannels == 0)
|
||||
{
|
||||
ASSERT(Controller->MaxChannels == 0);
|
||||
return STATUS_DEVICE_HARDWARE_ERROR;
|
||||
}
|
||||
|
||||
Controller->AhciVersion = AHCI_HBA_READ(Controller->IoBase, HbaAhciVersion);
|
||||
if (Controller->AhciVersion >= AHCI_VERSION_1_2)
|
||||
{
|
||||
Controller->AhciCapabilitiesEx = AHCI_HBA_READ(Controller->IoBase, HbaCapabilitiesEx);
|
||||
|
||||
if (Controller->AhciCapabilitiesEx & AHCI_CAP2_BOH)
|
||||
AtaAhciHbaRequestOsOwnership(Controller->IoBase);
|
||||
}
|
||||
|
||||
/* Reset the HBA into a consistent state */
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
GlobalControl |= AHCI_GHC_HR;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
|
||||
/* HBA reset may take up to 1 second */
|
||||
for (i = 100000; i > 0; i--)
|
||||
{
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
if (!(GlobalControl & AHCI_GHC_HR))
|
||||
break;
|
||||
|
||||
KeStallExecutionProcessor(10);
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
ERR("HBA reset failed %08lx\n", GlobalControl);
|
||||
return STATUS_IO_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Re-enable AE */
|
||||
GlobalControl |= AHCI_GHC_AE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
|
||||
/* Disable interrupts */
|
||||
GlobalControl = AHCI_HBA_READ(Controller->IoBase, HbaGlobalControl);
|
||||
if (GlobalControl & AHCI_GHC_IE)
|
||||
{
|
||||
GlobalControl &= ~AHCI_GHC_IE;
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaGlobalControl, GlobalControl);
|
||||
}
|
||||
|
||||
#if DBG
|
||||
/* On virtual machines, this will allow us to test the PMP support code */
|
||||
if (AtaAhciIsVbox())
|
||||
Controller->AhciCapabilities |= AHCI_CAP_SPM;
|
||||
#endif
|
||||
|
||||
Status = AtaAhciCreateChannelData(Controller);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
Controller->QueueDepth = ((Controller->AhciCapabilities & AHCI_CAP_NCS) >> 8) + 1;
|
||||
|
||||
INFO("%04X:%04X.%02X: Ver %08lX, PI %08lX, CAP %08lX, CAP2 %08lX\n",
|
||||
Controller->Pci.VendorID,
|
||||
Controller->Pci.DeviceID,
|
||||
Controller->Pci.RevisionID,
|
||||
Controller->AhciVersion,
|
||||
Controller->ChannelBitmap,
|
||||
Controller->AhciCapabilities,
|
||||
Controller->AhciCapabilitiesEx);
|
||||
|
||||
/* Clear HBA interrupts */
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaInterruptStatus, 0xFFFFFFFF);
|
||||
|
||||
Status = IoConnectInterrupt(&Controller->InterruptObject,
|
||||
AtaAhciHbaIsr,
|
||||
Controller,
|
||||
NULL,
|
||||
InterruptDesc->u.Interrupt.Vector,
|
||||
InterruptDesc->u.Interrupt.Level,
|
||||
InterruptDesc->u.Interrupt.Level,
|
||||
(InterruptDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
|
||||
? Latched : LevelSensitive,
|
||||
(InterruptDesc->ShareDisposition == CmResourceShareShared),
|
||||
InterruptDesc->u.Interrupt.Affinity,
|
||||
FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("Could not connect to interrupt %lu, status 0x%lx\n",
|
||||
InterruptDesc->u.Interrupt.Vector, Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
1579
drivers/storage/ide/pciidex/chipset/ahci_hw.c
Normal file
1579
drivers/storage/ide/pciidex/chipset/ahci_hw.c
Normal file
File diff suppressed because it is too large
Load Diff
429
drivers/storage/ide/pciidex/chipset/ahci_io.c
Normal file
429
drivers/storage/ide/pciidex/chipset/ahci_io.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: AHCI I/O request handling
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciBeginHostToDeviceFis(
|
||||
_In_ ATA_DEVICE_REQUEST* __restrict Request,
|
||||
_Out_ AHCI_FIS_HOST_TO_DEVICE* __restrict Fis)
|
||||
{
|
||||
RtlZeroMemory(Fis, sizeof(*Fis));
|
||||
|
||||
Fis->Type = AHCI_FIS_REGISTER_HOST_TO_DEVICE;
|
||||
Fis->Flags = UPDATE_COMMAND | DEV_NUMBER(Request->Device);
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_SET_DEVICE_REGISTER)
|
||||
Fis->Device = Request->TaskFile.DriveSelect;
|
||||
else
|
||||
Fis->Device = IDE_DRIVE_SELECT;
|
||||
|
||||
Fis->Control = IDE_DC_ALWAYS;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciBuildPacketCommandFis(
|
||||
_In_ ATA_DEVICE_REQUEST* __restrict Request,
|
||||
_Out_ AHCI_FIS_HOST_TO_DEVICE* __restrict Fis)
|
||||
{
|
||||
Fis->Command = IDE_COMMAND_ATAPI_PACKET;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_DMA)
|
||||
{
|
||||
/* DMA transfer */
|
||||
if ((Request->Device->TransportFlags & DEVICE_NEED_DMA_DIRECTION) &&
|
||||
(Request->Flags & REQUEST_FLAG_DATA_IN))
|
||||
{
|
||||
/* Some SATA-to-PATA bridges require the DMADIR bit to be set */
|
||||
Fis->Features = IDE_FEATURE_DMA | IDE_FEATURE_DMADIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Fis->Features = IDE_FEATURE_DMA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USHORT ByteCount;
|
||||
|
||||
/* PIO transfer */
|
||||
ByteCount = min(Request->DataTransferLength, ATAPI_MAX_DRQ_DATA_BLOCK);
|
||||
Fis->LbaMid = (UCHAR)ByteCount;
|
||||
Fis->LbaHigh = ByteCount >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciBuildAtaCommandFis(
|
||||
_In_ ATA_DEVICE_REQUEST* __restrict Request,
|
||||
_Out_ AHCI_FIS_HOST_TO_DEVICE* __restrict Fis)
|
||||
{
|
||||
PATA_TASKFILE TaskFile = &Request->TaskFile;
|
||||
|
||||
Fis->Command = TaskFile->Command;
|
||||
Fis->Features = TaskFile->Feature;
|
||||
Fis->LbaLow = TaskFile->LowLba;
|
||||
Fis->LbaMid = TaskFile->MidLba;
|
||||
Fis->LbaHigh = TaskFile->HighLba;
|
||||
Fis->SectorCount = TaskFile->SectorCount;
|
||||
|
||||
/* Unique queue tag */
|
||||
if (Request->Flags & REQUEST_FLAG_NCQ)
|
||||
Fis->SectorCount |= Request->Slot << 3;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_LBA48)
|
||||
{
|
||||
Fis->LbaLowEx = TaskFile->LowLbaEx;
|
||||
Fis->LbaMidEx = TaskFile->MidLbaEx;
|
||||
Fis->LbaHighEx = TaskFile->HighLbaEx;
|
||||
Fis->FeaturesEx = TaskFile->FeatureEx;
|
||||
Fis->SectorCountEx = TaskFile->SectorCountEx;
|
||||
}
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_SET_ICC_FIELD)
|
||||
Fis->Icc = TaskFile->Icc;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_SET_AUXILIARY_FIELD)
|
||||
Fis->Auxiliary = TaskFile->Auxiliary;
|
||||
}
|
||||
|
||||
/** Copy the CDB bytes (12 or 16 bytes) */
|
||||
static
|
||||
VOID
|
||||
AtaAhciTransferACMDRegion(
|
||||
_In_ VOID* __restrict Destination,
|
||||
_In_ VOID* __restrict Source,
|
||||
_In_ ATA_IO_CONTEXT_COMMON* __restrict Device)
|
||||
{
|
||||
/* Both addresses are 8-byte aligned */
|
||||
#if defined(_WIN64)
|
||||
PULONG64 Dest = Destination, Src = Source;
|
||||
|
||||
*Dest++ = *Src++;
|
||||
|
||||
if ((Device->CdbSize & (sizeof(ULONG64) - 1)) == 0)
|
||||
*Dest = *Src;
|
||||
else
|
||||
*(PULONG)Dest = *(PULONG)Src;
|
||||
#else
|
||||
PULONG Dest = Destination, Src = Source;
|
||||
|
||||
*Dest++ = *Src++;
|
||||
*Dest++ = *Src++;
|
||||
*Dest++ = *Src++;
|
||||
|
||||
if ((Device->CdbSize & (sizeof(ULONG64) - 1)) == 0)
|
||||
*Dest = *Src;
|
||||
#endif
|
||||
}
|
||||
C_ASSERT(FIELD_OFFSET(ATA_DEVICE_REQUEST, Cdb) % sizeof(ULONG64) == 0);
|
||||
C_ASSERT(FIELD_OFFSET(AHCI_COMMAND_TABLE, AtapiCommand) % sizeof(ULONG64) == 0);
|
||||
|
||||
BOOLEAN
|
||||
AtaAhciStartIo(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
PULONG IoBase = ChanData->IoBase;
|
||||
ULONG IssueSlot;
|
||||
|
||||
IssueSlot = 1 << Request->Slot;
|
||||
|
||||
ChanData->ActiveSlotsBitmap |= IssueSlot;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_NCQ)
|
||||
{
|
||||
ChanData->ActiveQueuedSlotsBitmap |= IssueSlot;
|
||||
AHCI_PORT_WRITE(IoBase, PxSataActive, IssueSlot);
|
||||
}
|
||||
|
||||
if ((ChanData->ChanInfo & CHANNEL_FLAG_FBS_ENABLED) &&
|
||||
(ChanData->LastFbsDeviceNumber != DEV_NUMBER(Request->Device)))
|
||||
{
|
||||
ULONG Control;
|
||||
|
||||
ChanData->LastFbsDeviceNumber = DEV_NUMBER(Request->Device);
|
||||
|
||||
Control = AHCI_FBS_ENABLE;
|
||||
Control |= DEV_NUMBER(Request->Device) << AHCI_FBS_ISSUE_SHIFT;
|
||||
AHCI_PORT_WRITE(IoBase, PxFisSwitchingControl, Control);
|
||||
}
|
||||
|
||||
AHCI_PORT_WRITE(IoBase, PxCommandIssue, IssueSlot);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
AtaAhciPrepareIo(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
PAHCI_COMMAND_TABLE CommandTable;
|
||||
PAHCI_COMMAND_HEADER CommandHeader;
|
||||
PAHCI_FIS_HOST_TO_DEVICE Fis;
|
||||
ULONG Control;
|
||||
|
||||
Control = sizeof(*Fis) / sizeof(ULONG);
|
||||
Control |= DEV_NUMBER(Request->Device) << AHCI_COMMAND_HEADER_PMP_SHIFT;
|
||||
|
||||
if (Request->Flags & (REQUEST_FLAG_DATA_IN | REQUEST_FLAG_DATA_OUT))
|
||||
{
|
||||
ASSERT(Request->Flags & REQUEST_FLAG_HAS_SG_LIST);
|
||||
|
||||
Control |= Request->SgList->NumberOfElements << AHCI_COMMAND_HEADER_PRDT_LENGTH_SHIFT;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_DATA_OUT)
|
||||
{
|
||||
Control |= AHCI_COMMAND_HEADER_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
CommandTable = ChanData->CommandTable[Request->Slot];
|
||||
|
||||
Fis = &CommandTable->HostToDeviceFis;
|
||||
|
||||
AtaAhciBeginHostToDeviceFis(Request, Fis);
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_PACKET_COMMAND)
|
||||
{
|
||||
AtaAhciBuildPacketCommandFis(Request, Fis);
|
||||
AtaAhciTransferACMDRegion(CommandTable->AtapiCommand,
|
||||
Request->Cdb,
|
||||
Request->Device);
|
||||
|
||||
Control |= AHCI_COMMAND_HEADER_ATAPI;
|
||||
}
|
||||
else
|
||||
{
|
||||
AtaAhciBuildAtaCommandFis(Request, Fis);
|
||||
}
|
||||
|
||||
CommandHeader = &ChanData->CommandList->CommandHeader[Request->Slot];
|
||||
CommandHeader->Control = Control;
|
||||
CommandHeader->PrdByteCount = 0;
|
||||
|
||||
KeFlushIoBuffers(Request->Mdl, !!(Request->Flags & REQUEST_FLAG_DATA_IN), TRUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
AtaAhciPreparePrdTable(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request,
|
||||
_In_ SCATTER_GATHER_LIST* __restrict SgList)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
PAHCI_PRD_TABLE_ENTRY PrdTableEntry;
|
||||
ULONG i;
|
||||
#if DBG
|
||||
BOOLEAN Is64BitDma = !!(ChanData->Controller->AhciCapabilities & AHCI_CAP_S64A);
|
||||
#endif
|
||||
|
||||
ASSUME(SgList->NumberOfElements > 0);
|
||||
ASSERT(SgList->NumberOfElements < AHCI_MAX_PRDT_ENTRIES);
|
||||
|
||||
PrdTableEntry = ChanData->CommandTable[Request->Slot]->PrdTable;
|
||||
|
||||
for (i = 0; i < SgList->NumberOfElements; ++i)
|
||||
{
|
||||
ASSERT(SgList->Elements[i].Length != 0);
|
||||
ASSERT(SgList->Elements[i].Length < AHCI_MAX_PRD_LENGTH);
|
||||
ASSERT((SgList->Elements[i].Length & ATA_MIN_BUFFER_ALIGNMENT) == 0);
|
||||
ASSERT(Is64BitDma || (SgList->Elements[i].Address.HighPart == 0));
|
||||
ASSERT(i < ChanData->MaximumPhysicalPages);
|
||||
|
||||
PrdTableEntry->DataBaseLow = SgList->Elements[i].Address.LowPart;
|
||||
PrdTableEntry->DataBaseHigh = SgList->Elements[i].Address.HighPart;
|
||||
PrdTableEntry->ByteCount = SgList->Elements[i].Length - 1;
|
||||
|
||||
++PrdTableEntry;
|
||||
}
|
||||
|
||||
/* Enable IRQ on last entry */
|
||||
--PrdTableEntry;
|
||||
PrdTableEntry->ByteCount |= AHCI_PRD_INTERRUPT_ON_COMPLETION;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
AtaAhciAllocateSlot(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request,
|
||||
_In_ BOOLEAN Allocate)
|
||||
{
|
||||
PCHANNEL_DATA_AHCI ChanData = ChannelContext;
|
||||
|
||||
if (Allocate)
|
||||
{
|
||||
/*
|
||||
* We cannot issue commands to more than one device behind the Port Multiplier
|
||||
* that supports only command-based switching.
|
||||
*/
|
||||
if ((ChanData->ChanInfo & CHANNEL_FLAG_IS_PMP) &&
|
||||
!(ChanData->ChanInfo & CHANNEL_FLAG_FBS_ENABLED))
|
||||
{
|
||||
if ((ChanData->LastPmpDeviceNumber != 0xFF) &&
|
||||
(ChanData->LastPmpDeviceNumber != DEV_NUMBER(Request->Device)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ChanData->LastPmpDeviceNumber = DEV_NUMBER(Request->Device);
|
||||
|
||||
Request->Flags |= REQUEST_FLAG_DEVICE_EXCLUSIVE_ACCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Request->Flags & REQUEST_FLAG_DEVICE_EXCLUSIVE_ACCESS)
|
||||
{
|
||||
ChanData->LastPmpDeviceNumber = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciPortCompleteCommands(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData,
|
||||
_In_ ULONG CommandsCompleted)
|
||||
{
|
||||
ULONG Slot;
|
||||
|
||||
while (_BitScanForward(&Slot, CommandsCompleted) != 0)
|
||||
{
|
||||
PATA_DEVICE_REQUEST Request;
|
||||
UCHAR SrbStatus;
|
||||
|
||||
CommandsCompleted &= ~(1 << Slot);
|
||||
|
||||
Request = ChanData->Slots[Slot];
|
||||
ASSERT(Request);
|
||||
ASSERT(Request->Slot == Slot);
|
||||
|
||||
SrbStatus = SRB_STATUS_SUCCESS;
|
||||
|
||||
if (!(Request->Flags & REQUEST_FLAG_NCQ) &&
|
||||
Request->Flags & (REQUEST_FLAG_DATA_IN | REQUEST_FLAG_DATA_OUT))
|
||||
{
|
||||
PAHCI_COMMAND_HEADER CommandHeader = &ChanData->CommandList->CommandHeader[Slot];
|
||||
|
||||
/* This indicates a residual underrun */
|
||||
if (CommandHeader->PrdByteCount < Request->DataTransferLength)
|
||||
{
|
||||
Request->DataTransferLength = CommandHeader->PrdByteCount;
|
||||
SrbStatus = SRB_STATUS_DATA_OVERRUN;
|
||||
}
|
||||
}
|
||||
Request->SrbStatus = SrbStatus;
|
||||
|
||||
/* Save the latest copy of the task file registers */
|
||||
if (Request->Flags & REQUEST_FLAG_SAVE_TASK_FILE)
|
||||
{
|
||||
AtaAhciSaveTaskFile(ChanData, Request, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaAhciPortHandleInterrupt(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData)
|
||||
{
|
||||
ULONG InterruptStatus, CommandsIssued, CommandsCompleted;
|
||||
AHCI_PORT_REGISTER CommandRegister;
|
||||
|
||||
/* Clear all pending events */
|
||||
InterruptStatus = AHCI_PORT_READ(ChanData->IoBase, PxInterruptStatus);
|
||||
AHCI_PORT_WRITE(ChanData->IoBase, PxInterruptStatus, InterruptStatus);
|
||||
|
||||
TRACE("CH %lu: Intr %08lx\n", ChanData->Channel, InterruptStatus);
|
||||
|
||||
/* Clear interface errors */
|
||||
AHCI_PORT_WRITE(ChanData->IoBase, PxSataError,
|
||||
AHCI_PORT_READ(ChanData->IoBase, PxSataError));
|
||||
|
||||
/* Determine commands that have completed */
|
||||
if (ChanData->ActiveQueuedSlotsBitmap != 0)
|
||||
CommandRegister = PxSataActive;
|
||||
else
|
||||
CommandRegister = PxCommandIssue;
|
||||
CommandsIssued = AHCI_PORT_READ(ChanData->IoBase, CommandRegister);
|
||||
CommandsCompleted = ~CommandsIssued & ChanData->ActiveSlotsBitmap;
|
||||
|
||||
/* Complete processed commands */
|
||||
if (CommandsCompleted != 0)
|
||||
{
|
||||
ChanData->ActiveSlotsBitmap &= ~CommandsCompleted;
|
||||
ChanData->ActiveQueuedSlotsBitmap &= ~CommandsCompleted;
|
||||
|
||||
AtaAhciPortCompleteCommands(ChanData, CommandsCompleted);
|
||||
ChanData->PortNotification(AtaRequestComplete, ChanData->PortContext, CommandsCompleted);
|
||||
}
|
||||
|
||||
/* Asynchronous notification received */
|
||||
if (InterruptStatus & AHCI_PXIRQ_SDBS)
|
||||
{
|
||||
ULONG Message = AHCI_PORT_READ(ChanData->IoBase, PxSataNotification);
|
||||
|
||||
if (Message != 0)
|
||||
{
|
||||
AHCI_PORT_WRITE(ChanData->IoBase, PxSataNotification, Message);
|
||||
|
||||
WARN("CH %lu: Notification %08lx arrived\n", ChanData->Channel, Message);
|
||||
|
||||
ChanData->PortNotification(AtaAsyncNotificationDetected, ChanData->PortContext, 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle various errors and link change events */
|
||||
if (InterruptStatus & AHCI_PXIRQ_PORT_STATUS)
|
||||
{
|
||||
AtaAhciHandlePortStateChange(ChanData, InterruptStatus);
|
||||
}
|
||||
|
||||
if (InterruptStatus & AHCI_PXIRQ_FATAL_ERROR)
|
||||
{
|
||||
AtaAhciHandleFatalError(ChanData);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
AtaAhciHbaIsr(
|
||||
_In_ PKINTERRUPT Interrupt,
|
||||
_In_ PVOID Context)
|
||||
{
|
||||
PATA_CONTROLLER Controller = Context;
|
||||
ULONG Port, InterruptStatus, PortInterruptBitmap;
|
||||
|
||||
InterruptStatus = AHCI_HBA_READ(Controller->IoBase, HbaInterruptStatus);
|
||||
if (InterruptStatus == 0)
|
||||
return FALSE;
|
||||
|
||||
PortInterruptBitmap = InterruptStatus & Controller->ChannelBitmap;
|
||||
while (_BitScanForward(&Port, PortInterruptBitmap) != 0)
|
||||
{
|
||||
PortInterruptBitmap &= ~(1 << Port);
|
||||
|
||||
AtaAhciPortHandleInterrupt(Controller->Channels[Port]);
|
||||
}
|
||||
|
||||
/* Clear pending HBA interrupts */
|
||||
AHCI_HBA_WRITE(Controller->IoBase, HbaInterruptStatus, InterruptStatus);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
430
drivers/storage/ide/pciidex/chipset/amd.c
Normal file
430
drivers/storage/ide/pciidex/chipset/amd.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: AMD ATA controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_AMD_756 0x7409
|
||||
#define PCI_DEV_AMD_766 0x7411
|
||||
#define PCI_DEV_AMD_768 0x7441
|
||||
#define PCI_DEV_AMD_8111 0x7469
|
||||
#define PCI_DEV_AMD_CS5536 0x2092
|
||||
#define PCI_DEV_AMD_CS5536_2 0x209A
|
||||
|
||||
#define PCI_DEV_NFORCE_IDE 0x01BC
|
||||
#define PCI_DEV_NFORCE2_IDE 0x0065
|
||||
#define PCI_DEV_NFORCE2_IDE_2 0x0085
|
||||
#define PCI_DEV_NFORCE3_IDE 0x00D5
|
||||
#define PCI_DEV_NFORCE3_IDE_2 0x00E5
|
||||
#define PCI_DEV_CK804_IDE 0x0053
|
||||
#define PCI_DEV_MCP04_IDE 0x0035
|
||||
#define PCI_DEV_MCP51_IDE 0x0265
|
||||
#define PCI_DEV_MCP55_IDE 0x036E
|
||||
#define PCI_DEV_MCP61_IDE 0x03EC
|
||||
#define PCI_DEV_MCP65_IDE 0x0448
|
||||
#define PCI_DEV_MCP67_IDE 0x0560
|
||||
#define PCI_DEV_MCP73_IDE 0x056C
|
||||
#define PCI_DEV_MCP77_IDE 0x0759
|
||||
|
||||
#define PCI_DEV_NFORCE2_SATA 0x008E
|
||||
#define PCI_DEV_NFORCE3_SATA 0x00E3
|
||||
#define PCI_DEV_NFORCE3_SATA_2 0x00EE
|
||||
#define PCI_DEV_CK804_SATA 0x0054
|
||||
#define PCI_DEV_CK804_SATA_2 0x0055
|
||||
#define PCI_DEV_MCP04_SATA 0x0036
|
||||
#define PCI_DEV_MCP04_SATA_2 0x003E
|
||||
#define PCI_DEV_MCP51_SATA 0x0266
|
||||
#define PCI_DEV_MCP51_SATA_2 0x0267
|
||||
#define PCI_DEV_MCP55_SATA 0x037E
|
||||
#define PCI_DEV_MCP55_SATA_2 0x037F
|
||||
#define PCI_DEV_MCP61_SATA 0x03E7
|
||||
#define PCI_DEV_MCP61_SATA_2 0x03F6
|
||||
#define PCI_DEV_MCP61_SATA_3 0x03F7
|
||||
#define PCI_DEV_MCP89_SATA 0x0D85
|
||||
|
||||
#define PCI_SUBSYSTEM_AMD_SERENADE 0x36C0
|
||||
|
||||
#define AMD_CONFIG_BASE 0x40
|
||||
#define NV_CONFIG_BASE 0x50
|
||||
|
||||
#define AMD_PCI_CLOCK 30000
|
||||
|
||||
#define AMD_REG_CONFIG_PREFETCH(IoBase) ((IoBase) + 0x01)
|
||||
#define AMD_REG_CONFIG_CR(IoBase) ((IoBase) + 0x02)
|
||||
#define AMD_REG_TIMING_CTRL(IoBase) ((IoBase) + 0x08)
|
||||
#define AMD_REG_ADDRESS_SETUP(IoBase) ((IoBase) + 0x0C)
|
||||
#define AMD_REG_UDMA(IoBase, Channel) ((IoBase) + 0x10 + (2 - ((Channel) * 2)))
|
||||
|
||||
#define AMD_CONFIG_PREFETCH(Channel) (0xC0 >> ((Channel) * 2))
|
||||
#define AMD_CONFIG_CR(Channel) (0x03 << ((Channel) * 2))
|
||||
|
||||
#define AMD_UDMA_TIME(x) (x)
|
||||
#define AMD_UDMA_EN 0xC0
|
||||
|
||||
#define AMD_UDMA_CTRL(Drive, Value) ((Value) << ((1 - (Drive)) * 8))
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const struct
|
||||
{
|
||||
USHORT VendorID;
|
||||
USHORT DeviceID;
|
||||
USHORT Flags;
|
||||
#define HW_FLAGS_UDMA4 0x0001
|
||||
#define HW_FLAGS_UDMA5 0x0002
|
||||
#define HW_FLAGS_CHECK_SYSBOARD 0x0004
|
||||
#define HW_FLAGS_NO_PREFETCH 0x0008
|
||||
#define HW_FLAGS_SATA 0x0010
|
||||
} AmdControllerList[] =
|
||||
{
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_756, HW_FLAGS_UDMA4 },
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_766, HW_FLAGS_UDMA5 | HW_FLAGS_NO_PREFETCH },
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_768, HW_FLAGS_UDMA5 },
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_8111, HW_FLAGS_CHECK_SYSBOARD },
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_CS5536, HW_FLAGS_UDMA5 },
|
||||
{ PCI_VEN_AMD, PCI_DEV_AMD_CS5536_2, HW_FLAGS_UDMA5 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE_IDE, HW_FLAGS_UDMA5 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE2_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE2_IDE_2, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE3_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE3_IDE_2, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_CK804_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP04_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP51_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP55_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP61_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP65_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP67_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP73_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP77_IDE, 0 },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE2_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE3_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_NFORCE3_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_CK804_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_CK804_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP04_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP04_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP51_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP51_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP55_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP55_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP61_SATA, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP61_SATA_2, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP61_SATA_3, HW_FLAGS_SATA },
|
||||
{ PCI_VEN_NVIDIA, PCI_DEV_MCP89_SATA, HW_FLAGS_SATA },
|
||||
};
|
||||
|
||||
static const UCHAR AmdUdmaSettings[] =
|
||||
{
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(2), // 0
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(1), // 1
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(0), // 2
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(4), // 3
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(5), // 4
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(6), // 5
|
||||
AMD_UDMA_EN | AMD_UDMA_TIME(7), // 6
|
||||
};
|
||||
|
||||
static const ULONG AmdTimingControlShift[MAX_IDE_CHANNEL][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ 24, 16 }, // Pri
|
||||
{ 8, 0 }, // Sec
|
||||
};
|
||||
static const ULONG AmdAddressSetupShift[MAX_IDE_CHANNEL][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ 6, 4 }, // Pri
|
||||
{ 2, 0 }, // Sec
|
||||
};
|
||||
static const ULONG AmdPortTimShift[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
24, // Pri
|
||||
16 // Sec
|
||||
};
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const ATA_PCI_ENABLE_BITS AmdEnableBits[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
{ AMD_CONFIG_BASE, 0x02, 0x02 },
|
||||
{ AMD_CONFIG_BASE, 0x01, 0x01 },
|
||||
};
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const ATA_PCI_ENABLE_BITS NvEnableBits[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
{ NV_CONFIG_BASE, 0x02, 0x02 },
|
||||
{ NV_CONFIG_BASE, 0x01, 0x01 },
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
ULONG
|
||||
AmdGetPciConfigIoBase(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
if (Controller->Pci.VendorID == PCI_VEN_AMD)
|
||||
return AMD_CONFIG_BASE;
|
||||
|
||||
return NV_CONFIG_BASE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AmdEnablePostedWriteBuffer(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList,
|
||||
_In_ ULONG IoBase)
|
||||
{
|
||||
UCHAR ConfigReg;
|
||||
ULONG i;
|
||||
|
||||
ConfigReg = PciRead8(Controller, AMD_REG_CONFIG_PREFETCH(IoBase));
|
||||
if (ChanData->HwFlags & HW_FLAGS_NO_PREFETCH)
|
||||
{
|
||||
/* Errata: IDE Read / Write Prefetch Hangs PCI Bus */
|
||||
ConfigReg &= ~(AMD_CONFIG_PREFETCH(0) | AMD_CONFIG_PREFETCH(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigReg |= AMD_CONFIG_PREFETCH(Channel);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
|
||||
if (Device && !Device->IsFixedDisk)
|
||||
{
|
||||
ConfigReg &= ~AMD_CONFIG_PREFETCH(Channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
PciWrite8(Controller, AMD_REG_CONFIG_PREFETCH(IoBase), ConfigReg);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AmdSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[Channel];
|
||||
const ULONG IoBase = AmdGetPciConfigIoBase(Controller);
|
||||
ATA_TIMING DeviceTimings[MAX_IDE_DEVICE];
|
||||
ULONG i, DriveTimReg, PortTimReg, UdmaTimReg;
|
||||
|
||||
AtaSelectTimings(DeviceList, DeviceTimings, AMD_PCI_CLOCK, SHARED_CMD_TIMINGS);
|
||||
|
||||
DriveTimReg = PciRead32(Controller, AMD_REG_TIMING_CTRL(IoBase));
|
||||
PortTimReg = PciRead32(Controller, AMD_REG_ADDRESS_SETUP(IoBase));
|
||||
UdmaTimReg = PciRead32(Controller, AMD_REG_UDMA(IoBase, 1));
|
||||
|
||||
INFO("CH %lu: Config (before)\n"
|
||||
"DRV %08lX\n"
|
||||
"PORT %08lX\n"
|
||||
"UDMA %08lX\n"
|
||||
"CFG %08lX\n",
|
||||
Channel, DriveTimReg, PortTimReg, UdmaTimReg, PciRead32(Controller, IoBase));
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
PATA_TIMING Timing = &DeviceTimings[i];
|
||||
ULONG Value;
|
||||
|
||||
/* UDMA timings */
|
||||
if (Device && (Device->DmaMode >= UDMA_MODE(0)))
|
||||
{
|
||||
Value = AmdUdmaSettings[Device->DmaMode - UDMA_MODE(0)];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set "Slow UDMA mode 0" by default */
|
||||
if (Controller->Pci.VendorID == PCI_VEN_AMD)
|
||||
Value = AMD_UDMA_TIME(3);
|
||||
else
|
||||
Value = 0;
|
||||
}
|
||||
UdmaTimReg &= ~(0xFF << AmdTimingControlShift[Channel][i]);
|
||||
UdmaTimReg |= Value << AmdTimingControlShift[Channel][i];
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
/* PIO and DMA timings */
|
||||
ViaClampTimings(Timing);
|
||||
|
||||
Value = Timing->AddressSetup;
|
||||
PortTimReg &= ~(0x03 << AmdAddressSetupShift[Channel][i]);
|
||||
PortTimReg |= Value << AmdAddressSetupShift[Channel][i];
|
||||
|
||||
Value = (Timing->CmdActive << 4) | Timing->CmdRecovery;
|
||||
PortTimReg &= ~(0xFF << AmdPortTimShift[Channel]);
|
||||
PortTimReg |= Value << AmdPortTimShift[Channel];
|
||||
|
||||
Value = (Timing->DataActive << 4) | Timing->DataRecovery;
|
||||
DriveTimReg &= ~(0xFF << AmdTimingControlShift[Channel][i]);
|
||||
DriveTimReg |= Value << AmdTimingControlShift[Channel][i];
|
||||
}
|
||||
|
||||
AmdEnablePostedWriteBuffer(Controller, ChanData, Channel, DeviceList, IoBase);
|
||||
|
||||
PciWrite32(Controller, AMD_REG_TIMING_CTRL(IoBase), DriveTimReg);
|
||||
PciWrite32(Controller, AMD_REG_ADDRESS_SETUP(IoBase), PortTimReg);
|
||||
PciWrite32(Controller, AMD_REG_UDMA(IoBase, 1), UdmaTimReg);
|
||||
|
||||
INFO("CH %lu: Config (after)\n"
|
||||
"DRV %08lX\n"
|
||||
"PORT %08lX\n"
|
||||
"UDMA %08lX\n"
|
||||
"CFG %08lX\n",
|
||||
Channel, DriveTimReg, PortTimReg, UdmaTimReg, PciRead32(Controller, IoBase));
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AmdControllerStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
UCHAR ConfigReg;
|
||||
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_AMD);
|
||||
|
||||
/* Initialize controller before issuing the identify command */
|
||||
ConfigReg = PciRead8(Controller, AMD_REG_CONFIG_PREFETCH(AMD_CONFIG_BASE));
|
||||
ConfigReg &= ~(AMD_CONFIG_PREFETCH(0) | AMD_CONFIG_PREFETCH(1));
|
||||
PciWrite8(Controller, AMD_REG_CONFIG_PREFETCH(AMD_CONFIG_BASE), ConfigReg);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CODE_SEG("PAGE")
|
||||
NvHasUdmaCable(
|
||||
_In_ USHORT UdmaTimReg,
|
||||
_In_ ULONG Drive)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* UDMA was disabled by BIOS */
|
||||
if ((AMD_UDMA_CTRL(Drive, UdmaTimReg) & AMD_UDMA_EN) != AMD_UDMA_EN)
|
||||
return FALSE;
|
||||
|
||||
/* Check clock settings, see if UDMA3 or higher mode is active */
|
||||
return !!((AMD_UDMA_CTRL(Drive, UdmaTimReg) & 0x7) & AMD_UDMA_TIME(4));
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AmdGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i, HwFlags, SupportedMode;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_AMD || Controller->Pci.VendorID == PCI_VEN_NVIDIA);
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(AmdControllerList); ++i)
|
||||
{
|
||||
HwFlags = AmdControllerList[i].Flags;
|
||||
|
||||
if ((Controller->Pci.VendorID == AmdControllerList[i].VendorID) &&
|
||||
(Controller->Pci.DeviceID == AmdControllerList[i].DeviceID))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == RTL_NUMBER_OF(AmdControllerList))
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
if (HwFlags & HW_FLAGS_SATA)
|
||||
{
|
||||
SupportedMode = SATA_ALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_ALL;
|
||||
|
||||
if (HwFlags & HW_FLAGS_CHECK_SYSBOARD)
|
||||
{
|
||||
if (Controller->Pci.SubSystemID == PCI_SUBSYSTEM_AMD_SERENADE)
|
||||
SupportedMode &= ~UDMA_MODE6;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HwFlags & HW_FLAGS_UDMA5)
|
||||
SupportedMode &= ~UDMA_MODE6;
|
||||
else if (HwFlags & HW_FLAGS_UDMA4)
|
||||
SupportedMode &= ~UDMA_MODES(5, 6);
|
||||
}
|
||||
|
||||
if (Controller->Pci.VendorID == PCI_VEN_AMD)
|
||||
{
|
||||
Controller->ChannelEnableBits = AmdEnableBits;
|
||||
Controller->Start = AmdControllerStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
Controller->ChannelEnableBits = NvEnableBits;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->HwFlags = HwFlags;
|
||||
ChanData->TransferModeSupported = SupportedMode;
|
||||
|
||||
if (HwFlags & HW_FLAGS_SATA)
|
||||
{
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_NO_SLAVE;
|
||||
ChanData->SetTransferMode = SataSetTransferMode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChanData->SetTransferMode = AmdSetTransferMode;
|
||||
|
||||
/* Check for 80-conductor cable */
|
||||
if (Controller->Pci.VendorID == PCI_VEN_AMD)
|
||||
{
|
||||
UCHAR ConfigReg = PciRead8(Controller, AMD_REG_CONFIG_CR(AMD_CONFIG_BASE));
|
||||
|
||||
if (!(ConfigReg & AMD_REG_CONFIG_CR(i)))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", i);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USHORT UdmaTimReg = PciRead16(Controller, AMD_REG_UDMA(NV_CONFIG_BASE, i));
|
||||
|
||||
if (!NvHasUdmaCable(UdmaTimReg, 0) && !NvHasUdmaCable(UdmaTimReg, 1))
|
||||
{
|
||||
INFO("CH %lu: BIOS hasn't selected mode faster than UDMA 2, "
|
||||
"assume 40-conductor cable\n",
|
||||
ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
83
drivers/storage/ide/pciidex/chipset/ati.c
Normal file
83
drivers/storage/ide/pciidex/chipset/ati.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
|
||||
* PURPOSE: ATI ATA controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from the FreeBSD ata-ati driver
|
||||
* Copyright (c) 1998-2008 Søren Schmidt <sos@FreeBSD.org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_IXP200_IDE 0x4349
|
||||
#define PCI_DEV_IXP300_IDE 0x4369
|
||||
#define PCI_DEV_IXP400_IDE 0x4376
|
||||
#define PCI_DEV_IXP600_IDE 0x438C
|
||||
#define PCI_DEV_IXP700_IDE 0x439C
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const ATA_PCI_ENABLE_BITS AtiEnableBits[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
{ 0x48, 0x01, 0x00 },
|
||||
{ 0x48, 0x08, 0x00 },
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AtiGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_ATI);
|
||||
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_IXP200_IDE &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_IXP300_IDE &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_IXP400_IDE &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_IXP600_IDE &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_IXP700_IDE)
|
||||
{
|
||||
return STATUS_NO_MATCH;
|
||||
}
|
||||
|
||||
Controller->ChannelEnableBits = AtiEnableBits;
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_IXP600_IDE)
|
||||
Controller->MaxChannels = 1;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->SetTransferMode = SvwSetTransferMode;
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_IXP200_IDE)
|
||||
ChanData->TransferModeSupported &= ~UDMA_MODE5;
|
||||
|
||||
if (!SvwHasUdmaCable(Controller, i))
|
||||
{
|
||||
INFO("CH %lu: BIOS hasn't selected mode faster than UDMA 2, "
|
||||
"assume 40-conductor cable\n",
|
||||
ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
577
drivers/storage/ide/pciidex/chipset/cmd.c
Normal file
577
drivers/storage/ide/pciidex/chipset/cmd.c
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: CMD PCI IDE controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* The CMD-640 does not support 32-bit PCI configuration space writes.
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_PCI0640 0x0640
|
||||
#define PCI_DEV_PCI0643 0x0643
|
||||
#define PCI_DEV_PCI0646 0x0646
|
||||
#define PCI_DEV_PCI0648 0x0648
|
||||
#define PCI_DEV_CMD0649 0x0649
|
||||
|
||||
#define HW_FLAGS_PRIMARY_ENABLED 0x0001
|
||||
#define HW_FLAGS_HAS_UDMA_REG 0x0002
|
||||
#define HW_FLAGS_NEED_PIO_FIX 0x0004
|
||||
#define HW_FLAGS_NO_PREFETCH 0x0008
|
||||
|
||||
#define CMD_PCI_CLOCK 30000
|
||||
|
||||
#define CMD_REG_CFR 0x50
|
||||
#define CMD_REG_CNTRL 0x51
|
||||
#define CMD_REG_CMDTIM 0x52
|
||||
#define CMD_REG_ARTTIM0 0x53
|
||||
#define CMD_REG_DRWTIM0 0x54
|
||||
#define CMD_REG_ARTTIM1 0x55
|
||||
#define CMD_REG_DRWTIM1 0x56
|
||||
#define CMD_REG_ARTTIM23 0x57
|
||||
#define CMD_REG_DRWTIM2 0x58
|
||||
#define CMD_REG_DRWTIM23 0x58 // 640 only
|
||||
#define CMD_REG_DRWTIM3 0x5B
|
||||
#define CMD_REG_MRDMODE 0x71
|
||||
#define CMD_REG_BMIDECSR 0x79
|
||||
#define CMD_REG_UDIDETCR(Channel) (((Channel) == 0) ? 0x73 : 0x7B)
|
||||
|
||||
#define CMD_CFR_INTR(Channel) (((Channel) == 0) ? 0x04 : 0x10)
|
||||
|
||||
#define CMD_CNTRL_CHAN_EN(Channel) (0x04 << (Channel))
|
||||
|
||||
#define CMD_ARTTIM_ART_MASK 0xC0
|
||||
|
||||
#define CMD_MRDMODE_READ_MULTIPLE 0x01
|
||||
#define CMD_MRDMODE_INTR(Channel) (0x04 << (Channel))
|
||||
#define CMD_MRDMODE_INTR_CH0_BLOCK 0x10
|
||||
#define CMD_MRDMODE_INTR_CH1_BLOCK 0x20
|
||||
|
||||
#define CMD_BMIDECSR_CR(Channel) (0x01 << (Channel))
|
||||
|
||||
#define CMD_UDIDETCR_CLEAR(Drive) (((Drive) == 0) ? 0x35 : 0xCA)
|
||||
#define CMD_UDIDETCR_EN(Drive) (0x01 << (Drive))
|
||||
|
||||
typedef struct _CMD_HW_EXTENSION
|
||||
{
|
||||
ATATIM CmdActive[MAX_IDE_CHANNEL * MAX_IDE_DEVICE];
|
||||
ATATIM CmdRecovery[MAX_IDE_CHANNEL * MAX_IDE_DEVICE];
|
||||
} CMD_HW_EXTENSION, *PCMD_HW_EXTENSION;
|
||||
|
||||
static const UCHAR CmdPrefetchDisable[MAX_IDE_CHANNEL][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ 0x40, 0x80 }, // Pri
|
||||
{ 0x04, 0x08 } // Sec
|
||||
};
|
||||
|
||||
static const ULONG CmdPrefetchRegs[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
// Pri Sec
|
||||
CMD_REG_CNTRL, CMD_REG_ARTTIM23
|
||||
};
|
||||
|
||||
static const ULONG CmdDrwTimRegs[MAX_IDE_CHANNEL][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ CMD_REG_DRWTIM0, CMD_REG_DRWTIM1 }, // Pri
|
||||
{ CMD_REG_DRWTIM2, CMD_REG_DRWTIM3 } // Sec
|
||||
};
|
||||
|
||||
static const ULONG CmdArtTimRegs[MAX_IDE_CHANNEL][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ CMD_REG_ARTTIM0, CMD_REG_ARTTIM1 }, // Pri
|
||||
{ CMD_REG_ARTTIM23, CMD_REG_ARTTIM23 } // Sec
|
||||
};
|
||||
|
||||
static const UCHAR CmdArtTimings[] =
|
||||
{
|
||||
0x40, // 0
|
||||
0x40, // 1
|
||||
0x40, // 2
|
||||
0x80, // 3
|
||||
0x00, // 4
|
||||
0xC0 // 5
|
||||
};
|
||||
|
||||
static const UCHAR CmdUdmaTimings[6][MAX_IDE_DEVICE] =
|
||||
{
|
||||
// M S
|
||||
{ 0x31, 0xC2 }, // 0
|
||||
{ 0x21, 0x82 }, // 1
|
||||
{ 0x11, 0x42 }, // 2
|
||||
{ 0x25, 0x8A }, // 3
|
||||
{ 0x15, 0x4A }, // 4
|
||||
{ 0x05, 0x0A } // 5
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
CmdFixRecoveryTiming(
|
||||
_In_ PCHANNEL_DEVICE_CONFIG Device,
|
||||
_Inout_ PATA_TIMING Timing,
|
||||
_In_ ATATIM CycleTimeClocks,
|
||||
_In_ ATATIM CmdActiveClocks,
|
||||
_In_ ATATIM CmdRecoveryClocks,
|
||||
_In_ ATATIM DataActiveClocks,
|
||||
_In_ ATATIM DataRecoveryClocks)
|
||||
{
|
||||
if (((Timing->DataActive + Timing->DataRecovery) > CycleTimeClocks) || // Cycle time not met
|
||||
(Device->DmaMode == MWDMA_MODE(0))) // Data active time not met
|
||||
{
|
||||
if (Timing->CmdActive < CmdActiveClocks)
|
||||
Timing->CmdActive = CmdActiveClocks;
|
||||
if (Timing->CmdRecovery < CmdRecoveryClocks)
|
||||
Timing->CmdRecovery = CmdRecoveryClocks;
|
||||
|
||||
if (Timing->DataActive < DataActiveClocks)
|
||||
Timing->DataActive = DataActiveClocks;
|
||||
if (Timing->DataRecovery < DataRecoveryClocks)
|
||||
Timing->DataRecovery = DataRecoveryClocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use recommended values */
|
||||
Timing->CmdActive = CmdActiveClocks;
|
||||
Timing->CmdRecovery = CmdRecoveryClocks;
|
||||
Timing->DataActive = DataActiveClocks;
|
||||
Timing->DataRecovery = DataRecoveryClocks;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CmdDerateTimings(
|
||||
_In_ PCHANNEL_DEVICE_CONFIG Device,
|
||||
_Inout_ PATA_TIMING Timing)
|
||||
{
|
||||
/* Make the timings run slower to address the PCI Bus Hang errata */
|
||||
switch (Device->PioMode)
|
||||
{
|
||||
case PIO_MODE(0):
|
||||
{
|
||||
/*
|
||||
* 600ns is minimum in PIO mode 0, but program the chip to 570ns.
|
||||
* 480 + 90 = 570
|
||||
*/
|
||||
CmdFixRecoveryTiming(Device, Timing, 20, 16, 3, 16, 3);
|
||||
break;
|
||||
}
|
||||
case PIO_MODE(1):
|
||||
{
|
||||
/* 300 + 90 = 390 */
|
||||
CmdFixRecoveryTiming(Device, Timing, 13, 10, 3, 10, 3);
|
||||
break;
|
||||
}
|
||||
case PIO_MODE(2):
|
||||
{
|
||||
/*
|
||||
* Cmd 300 + 90 = 390
|
||||
* Data 150 + 90 = 240
|
||||
*/
|
||||
CmdFixRecoveryTiming(Device, Timing, 8, 10, 3, 5, 3);
|
||||
break;
|
||||
}
|
||||
|
||||
/* PIO 3 & 4 unaffected by the errata */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
UCHAR
|
||||
CmdPackTimings(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ATATIM Active,
|
||||
_In_ ATATIM Recovery)
|
||||
{
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_PCI0640)
|
||||
{
|
||||
if (Active >= 16)
|
||||
Active = 0;
|
||||
else if (Active < 2)
|
||||
Active = 2;
|
||||
|
||||
if (Controller->Pci.RevisionID > 1)
|
||||
{
|
||||
/* 640B */
|
||||
if (Recovery >= 17)
|
||||
Recovery = 0;
|
||||
else if (Recovery > 2)
|
||||
--Recovery;
|
||||
else
|
||||
Recovery = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 640A */
|
||||
if (Recovery >= 16)
|
||||
Recovery = 0;
|
||||
else if (Recovery < 2)
|
||||
Recovery = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Active >= 16)
|
||||
Active = 0;
|
||||
|
||||
if (Recovery >= 16)
|
||||
Recovery = 0;
|
||||
else if (Recovery > 1)
|
||||
--Recovery;
|
||||
else
|
||||
Recovery = 15;
|
||||
}
|
||||
|
||||
return (Active << 4) | Recovery;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CmdSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[Channel];
|
||||
PCMD_HW_EXTENSION HwExt = Controller->HwExt;
|
||||
ATA_TIMING DeviceTimings[MAX_IDE_DEVICE];
|
||||
ULONG i, TimingFlags;
|
||||
UCHAR Value;
|
||||
|
||||
/* Some timings are shared between both drives drives on the secondary channel */
|
||||
TimingFlags = 0;
|
||||
if (Channel != 0)
|
||||
{
|
||||
TimingFlags |= SHARED_ADDR_TIMINGS;
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_PCI0640)
|
||||
TimingFlags |= SHARED_DATA_TIMINGS;
|
||||
}
|
||||
AtaSelectTimings(DeviceList, DeviceTimings, CMD_PCI_CLOCK, TimingFlags);
|
||||
|
||||
/* Enable or disable prefetch mode */
|
||||
Value = PciRead8(Controller, CmdPrefetchRegs[Channel]);
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
if ((ChanData->HwFlags & HW_FLAGS_NO_PREFETCH) || !Device->IsFixedDisk)
|
||||
Value |= CmdPrefetchDisable[Channel][i];
|
||||
else
|
||||
Value &= ~CmdPrefetchDisable[Channel][i];
|
||||
}
|
||||
PciWrite8(Controller, CmdPrefetchRegs[Channel], Value);
|
||||
|
||||
/* Program timing settings */
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
PATA_TIMING Timing = &DeviceTimings[i];
|
||||
UCHAR UdmaTimReg;
|
||||
ULONG Register;
|
||||
|
||||
/* UDMA timings */
|
||||
if (ChanData->HwFlags & HW_FLAGS_HAS_UDMA_REG)
|
||||
{
|
||||
UdmaTimReg = PciRead8(Controller, CMD_REG_UDIDETCR(Channel));
|
||||
if (Device && (Device->DmaMode >= UDMA_MODE(0)))
|
||||
{
|
||||
UdmaTimReg &= ~CMD_UDIDETCR_CLEAR(i);
|
||||
UdmaTimReg |= CmdUdmaTimings[Device->DmaMode - UDMA_MODE(0)][i];
|
||||
}
|
||||
else
|
||||
{
|
||||
UdmaTimReg &= ~CMD_UDIDETCR_EN(i);
|
||||
}
|
||||
PciWrite8(Controller, CMD_REG_UDIDETCR(Channel), UdmaTimReg);
|
||||
}
|
||||
|
||||
if (!Device)
|
||||
{
|
||||
HwExt->CmdActive[i + Channel * MAX_IDE_DEVICE] = 0;
|
||||
HwExt->CmdRecovery[i + Channel * MAX_IDE_DEVICE] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ChanData->HwFlags & HW_FLAGS_NEED_PIO_FIX)
|
||||
CmdDerateTimings(Device, Timing);
|
||||
|
||||
/* 8-bit timings */
|
||||
HwExt->CmdActive[i + Channel * MAX_IDE_DEVICE] = Timing->CmdActive;
|
||||
HwExt->CmdRecovery[i + Channel * MAX_IDE_DEVICE] = Timing->CmdRecovery;
|
||||
|
||||
/* Address setup timing */
|
||||
if (Timing->AddressSetup > RTL_NUMBER_OF(CmdArtTimings) - 1)
|
||||
Timing->AddressSetup = RTL_NUMBER_OF(CmdArtTimings) - 1;
|
||||
Value = PciRead8(Controller, CmdArtTimRegs[Channel][i]);
|
||||
Value &= ~CMD_ARTTIM_ART_MASK;
|
||||
Value |= CmdArtTimings[Timing->AddressSetup];
|
||||
PciWrite8(Controller, CmdArtTimRegs[Channel][i], Value);
|
||||
|
||||
/* 16-bit timings */
|
||||
Value = CmdPackTimings(Controller, Timing->DataActive, Timing->DataRecovery);
|
||||
if ((Controller->Pci.DeviceID == PCI_DEV_PCI0640) && (Channel != 0))
|
||||
Register = CMD_REG_DRWTIM23;
|
||||
else
|
||||
Register = CmdDrwTimRegs[Channel][i];
|
||||
PciWrite8(Controller, Register, Value);
|
||||
}
|
||||
|
||||
/* 8-bit timings are shared between both the primary and secondary channels */
|
||||
for (i = 0; i < MAX_IDE_CHANNEL * MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
if (HwExt->CmdActive[i] > DeviceTimings[0].CmdActive)
|
||||
DeviceTimings[0].CmdActive = HwExt->CmdActive[i];
|
||||
|
||||
if (HwExt->CmdRecovery[i] > DeviceTimings[0].CmdRecovery)
|
||||
DeviceTimings[0].CmdRecovery = HwExt->CmdRecovery[i];
|
||||
}
|
||||
if ((DeviceTimings[0].CmdActive != 0) || (DeviceTimings[0].CmdRecovery != 0))
|
||||
{
|
||||
Value = CmdPackTimings(Controller,
|
||||
DeviceTimings[0].CmdActive,
|
||||
DeviceTimings[0].CmdRecovery);
|
||||
PciWrite8(Controller, CMD_REG_CMDTIM, Value);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
IDE_CHANNEL_STATE
|
||||
CmdChannelEnabledTest(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[Channel];
|
||||
UCHAR Control;
|
||||
|
||||
/* Some controllers lack the primary channel enable bit */
|
||||
if ((Channel == 0) && (ChanData->HwFlags & HW_FLAGS_PRIMARY_ENABLED))
|
||||
return ChannelEnabled;
|
||||
|
||||
Control = PciRead8(Controller, CMD_REG_CNTRL);
|
||||
if (Control & CMD_CNTRL_CHAN_EN(Channel))
|
||||
return ChannelEnabled;
|
||||
|
||||
return ChannelDisabled;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CmdCheckInterruptMrdMode(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
UCHAR Control, InterruptMask;
|
||||
|
||||
if (ChanData->Regs.Dma)
|
||||
Control = ATA_READ(ChanData->Regs.Dma + 1, ChanData, MRES_DMA);
|
||||
else
|
||||
Control = PciRead8(Controller, CMD_REG_MRDMODE);
|
||||
|
||||
InterruptMask = CMD_MRDMODE_INTR(ChanData->Channel);
|
||||
if (!(Control & InterruptMask))
|
||||
return FALSE;
|
||||
|
||||
Control &= ~(CMD_MRDMODE_INTR(0) | CMD_MRDMODE_INTR(1));
|
||||
Control |= InterruptMask;
|
||||
/* Make sure we do not clear the write-only bits */
|
||||
Control |= CMD_MRDMODE_READ_MULTIPLE;
|
||||
|
||||
/* Clear the interrupt */
|
||||
if (ChanData->Regs.Dma)
|
||||
ATA_WRITE(ChanData->Regs.Dma + 1, Control, ChanData, MRES_DMA);
|
||||
else
|
||||
PciWrite8(Controller, CMD_REG_MRDMODE, Control);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CmdCheckInterruptPci(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
UCHAR Status, InterruptMask;
|
||||
ULONG Register;
|
||||
|
||||
InterruptMask = CMD_CFR_INTR(ChanData->Channel);
|
||||
Register = (ChanData->Channel == 0) ? CMD_REG_CFR : CMD_REG_ARTTIM23;
|
||||
|
||||
/* Read CFR or REG_ARTTIM23 to clear the interrupt */
|
||||
Status = PciRead8(Controller, Register);
|
||||
return !!(Status & InterruptMask);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
CmdControllerStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
ULONG i;
|
||||
UCHAR Control;
|
||||
|
||||
/*
|
||||
* Initialize the controller to compatible PIO timings.
|
||||
* We dynamically adjust these timings depending on attached devices.
|
||||
*/
|
||||
PciWrite8(Controller, CMD_REG_CMDTIM, 0);
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_PCI0640)
|
||||
{
|
||||
/*
|
||||
* Errata: Disable the Read-Ahead Mode.
|
||||
* https://www.mindprod.com/jgloss/eideflaw.html
|
||||
*/
|
||||
for (i = 0; i < RTL_NUMBER_OF(CmdPrefetchRegs); ++i)
|
||||
{
|
||||
Control = PciRead8(Controller, CmdPrefetchRegs[i]);
|
||||
Control |= CmdPrefetchDisable[i][0] | CmdPrefetchDisable[i][1];
|
||||
PciWrite8(Controller, CmdPrefetchRegs[i], Control);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Control = PciRead8(Controller, CMD_REG_MRDMODE);
|
||||
Control &= ~(CMD_MRDMODE_INTR_CH0_BLOCK | CMD_MRDMODE_INTR_CH1_BLOCK);
|
||||
Control |= CMD_MRDMODE_READ_MULTIPLE;
|
||||
PciWrite8(Controller, CMD_REG_MRDMODE, Control);
|
||||
}
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
CmdGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i, SupportedMode, HwFlags = 0;
|
||||
PCHANNEL_CHECK_INTERRUPT CheckInterrupt = CmdCheckInterruptPci;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_CMD);
|
||||
|
||||
switch (Controller->Pci.DeviceID)
|
||||
{
|
||||
case PCI_DEV_PCI0640:
|
||||
/*
|
||||
* Errata: The CMD-640 has one set of task file registers per controller
|
||||
* and thus the two channels cannot be used simultaneously.
|
||||
* https://www.mindprod.com/jgloss/eideflaw.html
|
||||
*/
|
||||
Controller->Flags |= CTRL_FLAG_IS_SIMPLEX;
|
||||
|
||||
SupportedMode = PIO_ALL;
|
||||
HwFlags |= HW_FLAGS_PRIMARY_ENABLED | HW_FLAGS_NO_PREFETCH;
|
||||
break;
|
||||
|
||||
case PCI_DEV_PCI0643:
|
||||
SupportedMode = PIO_ALL | SWDMA_ALL | MWDMA_ALL;
|
||||
|
||||
if (Controller->Pci.RevisionID < 6)
|
||||
HwFlags |= HW_FLAGS_PRIMARY_ENABLED;
|
||||
break;
|
||||
|
||||
case PCI_DEV_PCI0646:
|
||||
SupportedMode = PIO_ALL | SWDMA_ALL | MWDMA_ALL;
|
||||
HwFlags |= HW_FLAGS_HAS_UDMA_REG;
|
||||
|
||||
if (Controller->Pci.RevisionID < 3)
|
||||
HwFlags |= HW_FLAGS_PRIMARY_ENABLED;
|
||||
else
|
||||
CheckInterrupt = CmdCheckInterruptMrdMode;
|
||||
|
||||
if (Controller->Pci.RevisionID == 5 || Controller->Pci.RevisionID == 6)
|
||||
{
|
||||
/*
|
||||
* Early 646U2 revisions can support UDMA2 only at a PCI bus speed of 33MHz.
|
||||
* When it runs at 25 MHz or 30 MHZ, the transfer speed must be limited to UDMA1.
|
||||
*/
|
||||
SupportedMode |= UDMA_MODES(0, 1);
|
||||
}
|
||||
else if (Controller->Pci.RevisionID > 6)
|
||||
{
|
||||
SupportedMode |= UDMA_MODES(0, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI_DEV_PCI0648:
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
|
||||
/* Prefetch bits have different meaning on this controller */
|
||||
HwFlags |= HW_FLAGS_HAS_UDMA_REG | HW_FLAGS_NO_PREFETCH;
|
||||
CheckInterrupt = CmdCheckInterruptMrdMode;
|
||||
break;
|
||||
|
||||
case PCI_DEV_CMD0649:
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
HwFlags |= HW_FLAGS_HAS_UDMA_REG;
|
||||
|
||||
if (Controller->Pci.RevisionID == 2)
|
||||
HwFlags |= HW_FLAGS_NEED_PIO_FIX;
|
||||
|
||||
CheckInterrupt = CmdCheckInterruptMrdMode;
|
||||
break;
|
||||
|
||||
default:
|
||||
return STATUS_NO_MATCH;
|
||||
}
|
||||
|
||||
Controller->Start = CmdControllerStart;
|
||||
|
||||
Controller->Flags |= CTRL_FLAG_USE_TEST_FUNCTION;
|
||||
Controller->ChannelEnabledTest = CmdChannelEnabledTest;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
Controller->HwExt = ExAllocatePoolZero(NonPagedPool, sizeof(CMD_HW_EXTENSION), TAG_PCIIDEX);
|
||||
if (!Controller->HwExt)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->HwFlags = HwFlags;
|
||||
ChanData->CheckInterrupt = CheckInterrupt;
|
||||
ChanData->SetTransferMode = CmdSetTransferMode;
|
||||
ChanData->TransferModeSupported = SupportedMode;
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_PCI0640)
|
||||
{
|
||||
ChanData->ChanInfo &= ~CHANNEL_FLAG_IO32;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for 80-conductor cable */
|
||||
if (ChanData->TransferModeSupported & UDMA_80C_ALL)
|
||||
{
|
||||
UCHAR BmControl = PciRead8(Controller, CMD_REG_BMIDECSR);
|
||||
if (!(BmControl & CMD_BMIDECSR_CR(i)))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
1048
drivers/storage/ide/pciidex/chipset/intel.c
Normal file
1048
drivers/storage/ide/pciidex/chipset/intel.c
Normal file
File diff suppressed because it is too large
Load Diff
1244
drivers/storage/ide/pciidex/chipset/pata_generic.c
Normal file
1244
drivers/storage/ide/pciidex/chipset/pata_generic.c
Normal file
File diff suppressed because it is too large
Load Diff
259
drivers/storage/ide/pciidex/chipset/pata_hw.c
Normal file
259
drivers/storage/ide/pciidex/chipset/pata_hw.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: PATA hardware support
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
PataIsDevicePresent(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ ULONG DeviceNumber)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
|
||||
/* Select the device */
|
||||
ATA_SELECT_DEVICE(ChanData, DeviceNumber, IDE_DRIVE_SELECT | ((DeviceNumber & 1) << 4));
|
||||
|
||||
/* Do a quick check first */
|
||||
IdeStatus = ChanData->ReadStatus(ChanData);
|
||||
INFO("CH %lu: Device %lu status %02x\n", ChanData->Channel, DeviceNumber, IdeStatus);
|
||||
if (IdeStatus == 0xFF || IdeStatus == 0x7F)
|
||||
return FALSE;
|
||||
|
||||
/* Look at controller */
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
|
||||
if (ATA_READ(ChanData->Regs.ByteCountLow, ChanData, MRES_TF) != 0x55)
|
||||
return FALSE;
|
||||
ATA_WRITE(ChanData->Regs.ByteCountHigh, 0xAA, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountHigh, 0x55, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountHigh, 0xAA, ChanData, MRES_TF);
|
||||
if (ATA_READ(ChanData->Regs.ByteCountHigh, ChanData, MRES_TF) != 0xAA)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
PataIssueSoftwareReset(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
ATA_WRITE(ChanData->Regs.Control, IDE_DC_RESET_CONTROLLER | IDE_DC_ALWAYS,
|
||||
ChanData, MRES_CTRL);
|
||||
KeStallExecutionProcessor(20);
|
||||
ATA_WRITE(ChanData->Regs.Control, IDE_DC_DISABLE_INTERRUPTS | IDE_DC_ALWAYS,
|
||||
ChanData, MRES_CTRL);
|
||||
KeStallExecutionProcessor(20);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
PataDrainDeviceBuffer(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
ULONG i;
|
||||
USHORT LocalBuffer;
|
||||
|
||||
/* Try to clear the DRQ indication */
|
||||
for (i = 0; i < ATA_MAX_TRANSFER_LENGTH / sizeof(USHORT); ++i)
|
||||
{
|
||||
UCHAR IdeStatus = ChanData->ReadStatus(ChanData);
|
||||
|
||||
if (!(IdeStatus & IDE_STATUS_DRQ))
|
||||
break;
|
||||
|
||||
ATA_READ_BLOCK_16((PUSHORT)ChanData->Regs.Data,
|
||||
&LocalBuffer,
|
||||
1,
|
||||
ChanData,
|
||||
MRES_TF);
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
INFO("CH %lu: Total drained %lu bytes\n", ChanData->Channel, i * sizeof(USHORT));
|
||||
}
|
||||
|
||||
ULONG
|
||||
PataChannelGetMaximumDeviceCount(
|
||||
_In_ PVOID ChannelContext)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = ChannelContext;
|
||||
|
||||
#if defined(_M_IX86)
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
|
||||
return 4;
|
||||
#endif
|
||||
|
||||
return (ChanData->ChanInfo & CHANNEL_FLAG_NO_SLAVE) ? 1 : 2;
|
||||
}
|
||||
|
||||
VOID
|
||||
PataResetChannel(
|
||||
_In_ PVOID ChannelContext)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = ChannelContext;
|
||||
ULONG i, DeviceNumber, DeviceCount, DeviceBitmap = 0;
|
||||
|
||||
ChanData->IsPollingActive = FALSE;
|
||||
|
||||
#if defined(_M_IX86)
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
|
||||
ChanData->LastAtaBankId = 0xFF;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reset the start/stop bus master bit, also needed on some chips to recover,
|
||||
* see for example Intel 82371AB/EB/MB Specification Update 297738-017 #10.
|
||||
*/
|
||||
if (ChanData->Regs.Dma != NULL)
|
||||
PciIdeDmaStop(ChanData);
|
||||
|
||||
PataDrainDeviceBuffer(ChanData);
|
||||
|
||||
DeviceCount = PataChannelGetMaximumDeviceCount(ChanData);
|
||||
for (DeviceNumber = 0; DeviceNumber < DeviceCount; ++DeviceNumber)
|
||||
{
|
||||
if (PataIsDevicePresent(ChanData, DeviceNumber))
|
||||
DeviceBitmap |= 1 << DeviceNumber;
|
||||
}
|
||||
/* Restore the device selection */
|
||||
ATA_SELECT_DEVICE(ChanData, 0, IDE_DRIVE_SELECT);
|
||||
|
||||
WARN("CH %lu: Resetting IDE channel, devices map 0x%lx\n", ChanData->Channel, DeviceBitmap);
|
||||
|
||||
#if defined(_M_IX86)
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
|
||||
{
|
||||
/* Reset the secondary IDE channel if present */
|
||||
if (DeviceBitmap & ((1 << 2) | (1 << 3)))
|
||||
{
|
||||
WRITE_PORT_UCHAR((PUCHAR)PC98_ATA_BANK, 1);
|
||||
PataIssueSoftwareReset(ChanData);
|
||||
}
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)PC98_ATA_BANK, 0);
|
||||
ChanData->LastAtaBankId = 0xFF;
|
||||
}
|
||||
#endif
|
||||
PataIssueSoftwareReset(ChanData);
|
||||
|
||||
for (DeviceNumber = 0; DeviceNumber < DeviceCount; ++DeviceNumber)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
|
||||
/* The reset will cause the master device to be selected */
|
||||
if ((DeviceNumber % 2) != 0)
|
||||
{
|
||||
/* Always check BSY for the master device regardless of its presence */
|
||||
if (!(DeviceBitmap & (1 << DeviceNumber)))
|
||||
continue;
|
||||
|
||||
for (i = ATA_TIME_RESET_SELECT; i > 0; i--)
|
||||
{
|
||||
/* Select the device again */
|
||||
ATA_SELECT_DEVICE(ChanData,
|
||||
DeviceNumber,
|
||||
IDE_DRIVE_SELECT | ((DeviceNumber & 1) << 4));
|
||||
|
||||
/* Check whether the selection was successful */
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0x55, ChanData, MRES_TF);
|
||||
ATA_WRITE(ChanData->Regs.ByteCountLow, 0xAA, ChanData, MRES_TF);
|
||||
if (ATA_READ(ChanData->Regs.ByteCountLow, ChanData, MRES_TF) == 0xAA)
|
||||
break;
|
||||
|
||||
AtaSleep();
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
ERR("CH %lu: Device %lu selection timeout %02x\n",
|
||||
ChanData->Channel, DeviceNumber, ChanData->ReadStatus(ChanData));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now wait for busy to clear */
|
||||
for (i = 0; i < ATA_TIME_BUSY_RESET; ++i)
|
||||
{
|
||||
IdeStatus = ChanData->ReadStatus(ChanData);
|
||||
if (IdeStatus == 0xFF)
|
||||
break;
|
||||
|
||||
if (!(IdeStatus & IDE_STATUS_BUSY))
|
||||
break;
|
||||
|
||||
AtaSleep();
|
||||
}
|
||||
|
||||
if (IdeStatus & IDE_STATUS_BUSY)
|
||||
{
|
||||
ERR("CH %lu: Failed to reset device %lu, status %02x\n",
|
||||
ChanData->Channel, DeviceNumber, IdeStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO("CH %lu: Device %lu online with status %02x\n",
|
||||
ChanData->Channel, DeviceNumber, IdeStatus);
|
||||
}
|
||||
}
|
||||
|
||||
AtaChanEnableInterruptsSync(ChanData, TRUE);
|
||||
}
|
||||
|
||||
ATA_CONNECTION_STATUS
|
||||
PataIdentifyDevice(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ ULONG DeviceNumber)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = ChannelContext;
|
||||
UCHAR IdeStatus;
|
||||
|
||||
if (!PataIsDevicePresent(ChanData, DeviceNumber))
|
||||
return CONN_STATUS_NO_DEVICE;
|
||||
|
||||
/* Wait for busy to clear */
|
||||
IdeStatus = ATA_WAIT(ChanData, ATA_TIME_BUSY_SELECT, IDE_STATUS_BUSY, 0);
|
||||
if (IdeStatus & (IDE_STATUS_BUSY | IDE_STATUS_DRQ))
|
||||
{
|
||||
/*
|
||||
* This status indicates that the previous command hasn't been completed
|
||||
* and the device is left in an unexpected state.
|
||||
* A device reset is required to recover.
|
||||
*/
|
||||
WARN("CH %lu: Device %lu is busy %02x\n", ChanData->Channel, DeviceNumber, IdeStatus);
|
||||
return CONN_STATUS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Also we do not check the device signature,
|
||||
* because early ATAPI drives (NEC CDR-260, and some other devices)
|
||||
* report an ATA signature.
|
||||
*/
|
||||
return CONN_STATUS_DEV_UNKNOWN;
|
||||
}
|
||||
|
||||
ULONG
|
||||
PataEnumerateChannel(
|
||||
_In_ PVOID ChannelContext)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = ChannelContext;
|
||||
|
||||
/*
|
||||
* By default, we do not issue the software reset to detect the device signature,
|
||||
* since attached devices may reset their current transfer mode.
|
||||
* We need to know what transfer mode is actually set by BIOS in order to
|
||||
* select any transfer mode correctly by our generic PATA chipset driver
|
||||
* (PciIdeAcpiSetTransferMode() or PciIdeBiosSetTransferMode()).
|
||||
*/
|
||||
return PataChannelGetMaximumDeviceCount(ChanData);
|
||||
}
|
||||
1218
drivers/storage/ide/pciidex/chipset/pata_io.c
Normal file
1218
drivers/storage/ide/pciidex/chipset/pata_io.c
Normal file
File diff suppressed because it is too large
Load Diff
60
drivers/storage/ide/pciidex/chipset/pata_legacy.c
Normal file
60
drivers/storage/ide/pciidex/chipset/pata_legacy.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Legacy (non-PnP) IDE controllers support
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller,
|
||||
_In_ PCM_RESOURCE_LIST ResourcesTranslated)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Flags & CTRL_FLAG_NON_PNP);
|
||||
|
||||
Controller->MaxChannels = 1;
|
||||
Controller->ChannelBitmap = 0x1;
|
||||
Controller->Flags &= ~CTRL_FLAG_NATIVE_PCI;
|
||||
Controller->Flags |= CTRL_FLAG_MANUAL_RES;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
ChanData = Controller->Channels[0];
|
||||
ChanData->ChanInfo &= ~CHANNEL_FLAG_IO32;
|
||||
ChanData->TransferModeSupported = PIO_ALL;
|
||||
|
||||
Status = PciIdeParseResources(ChanData, ResourcesTranslated);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
#if defined(_M_IX86)
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_CBUS)
|
||||
{
|
||||
UCHAR Value, Result;
|
||||
|
||||
/* Check whether the 32-bit data port can be enabled on the southbridge */
|
||||
Value = READ_PORT_UCHAR((PUCHAR)PC98_ATA_BANK);
|
||||
WRITE_PORT_UCHAR((PUCHAR)PC98_ATA_BANK, Value ^ PC98_ATA_BANK_32BIT_PORT);
|
||||
Result = READ_PORT_UCHAR((PUCHAR)PC98_ATA_BANK);
|
||||
if ((Result ^ Value) & PC98_ATA_BANK_32BIT_PORT)
|
||||
{
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_IO32;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
67
drivers/storage/ide/pciidex/chipset/pctech.c
Normal file
67
drivers/storage/ide/pciidex/chipset/pctech.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: PC-Tech RZ1000 PCI IDE controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_RZ1000 0x1000
|
||||
#define PCI_DEV_RZ1001 0x1001
|
||||
|
||||
#define REG_CONFIG 0x40
|
||||
#define CONFIG_PREFETCH 0x2000
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
/*
|
||||
* Errata: Disable the Read-Ahead Mode.
|
||||
* https://web.archive.org/web/19961222024423/http://www.intel.com/procs/support/rz1000/rztech.htm
|
||||
* https://web.archive.org/web/20250324132451/https://www.mindprod.com/jgloss/eideflaw.html
|
||||
*/
|
||||
static
|
||||
VOID
|
||||
PcTechControllerStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
USHORT ConfigReg;
|
||||
|
||||
ConfigReg = PciRead16(Controller, REG_CONFIG);
|
||||
ConfigReg &= ~CONFIG_PREFETCH;
|
||||
PciWrite16(Controller, REG_CONFIG, ConfigReg);
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PcTechGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_PC_TECH);
|
||||
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_RZ1000 && Controller->Pci.DeviceID != PCI_DEV_RZ1001)
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
Controller->Start = PcTechControllerStart;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->ChanInfo &= ~CHANNEL_FLAG_IO32;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
249
drivers/storage/ide/pciidex/chipset/sil680.c
Normal file
249
drivers/storage/ide/pciidex/chipset/sil680.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Silicon Image 0680 PCI IDE controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_SIL0680 0x0680
|
||||
|
||||
#define SIL_REG_XFER_MODE(Channel) (0x80 + ((Channel) << 2))
|
||||
#define SIL_REG_SYS_CFG 0x8A
|
||||
#define SIL_REG_CFG(Channel) (0xA0 + ((Channel) << 4))
|
||||
#define SIL_REG_STATUS(Channel) (0xA1 + ((Channel) << 4))
|
||||
#define SIL_REG_TF_TIM(Channel) (0xA2 + ((Channel) << 4))
|
||||
#define SIL_REG_PIO_TIMING(Channel, Drive) (0xA4 + ((Channel) << 4) + ((Drive) << 1))
|
||||
#define SIL_REG_DMA_TIMING(Channel, Drive) (0xA8 + ((Channel) << 4) + ((Drive) << 1))
|
||||
#define SIL_REG_UDMA_TIMING(Channel, Drive) (0xAC + ((Channel) << 4) + ((Drive) << 1))
|
||||
|
||||
#define SIL_CFG_CABLE_80 0x00000001
|
||||
#define SIL_CFG_MONITOR_IORDY 0x00000200
|
||||
#define SIL_STATUS_INTR 0x08
|
||||
|
||||
#define SIL_CLK_MASK 0x30
|
||||
#define SIL_CLK_100MHZ 0x00
|
||||
#define SIL_CLK_133MHZ 0x10
|
||||
#define SIL_CLK_X2 0x20
|
||||
#define SIL_CLK_DISABLED 0x30
|
||||
|
||||
static const USHORT Sil680TaskFileTimings[] =
|
||||
{
|
||||
0x328A, // 0
|
||||
0x2283, // 1
|
||||
0x1281, // 2
|
||||
0x10C3, // 3
|
||||
0x10C1 // 4
|
||||
};
|
||||
|
||||
static const USHORT Sil680PioTimings[] =
|
||||
{
|
||||
0x328A, // 0
|
||||
0x2283, // 1
|
||||
0x1104, // 2
|
||||
0x10C3, // 3
|
||||
0x10C1 // 4
|
||||
};
|
||||
|
||||
static const USHORT Sil680MwDmaTimings[] =
|
||||
{
|
||||
0x2208, // 0
|
||||
0x10C2, // 1
|
||||
0x10C1, // 2
|
||||
};
|
||||
|
||||
static const UCHAR Sil680UdmaTimings[2][7] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6
|
||||
{ 0x0B, 0x07, 0x05, 0x04, 0x02, 0x01 }, // 100MHz
|
||||
{ 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, // 133MHz
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
Sil680SetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
ULONG i, SlowestPioMode, Config;
|
||||
UCHAR ModeReg;
|
||||
BOOLEAN MonitorIoReady = FALSE;
|
||||
|
||||
INFO("CH %lu: Config (before)\n"
|
||||
"MODE %08lX\n"
|
||||
"CFG %08lX\n"
|
||||
"PIO %08lX\n"
|
||||
"DMA %08lX\n"
|
||||
"UDMA %08lX\n",
|
||||
Channel,
|
||||
PciRead32(Controller, SIL_REG_XFER_MODE(Channel)),
|
||||
PciRead32(Controller, SIL_REG_CFG(Channel)),
|
||||
PciRead32(Controller, SIL_REG_PIO_TIMING(Channel, 0)),
|
||||
PciRead32(Controller, SIL_REG_DMA_TIMING(Channel, 0)),
|
||||
PciRead32(Controller, SIL_REG_UDMA_TIMING(Channel, 0)));
|
||||
|
||||
SlowestPioMode = UDMA_MODE(0);
|
||||
ModeReg = PciRead8(Controller, SIL_REG_XFER_MODE(Channel));
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
UCHAR XferMode, SysConfig;
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
/* PIO timings */
|
||||
SlowestPioMode = min(SlowestPioMode, Device->PioMode);
|
||||
PciWrite16(Controller, SIL_REG_PIO_TIMING(Channel, i), Sil680PioTimings[Device->PioMode]);
|
||||
|
||||
if (Device->PioMode >= PIO_MODE(3))
|
||||
MonitorIoReady = TRUE;
|
||||
|
||||
if (Device->DmaMode >= UDMA_MODE(0))
|
||||
{
|
||||
SysConfig = PciRead8(Controller, SIL_REG_SYS_CFG);
|
||||
|
||||
/* Try to enable the 133MHz IDE clock */
|
||||
if ((SysConfig & SIL_CLK_MASK) == SIL_CLK_100MHZ)
|
||||
{
|
||||
PciWrite8(Controller, SIL_REG_SYS_CFG, SysConfig | SIL_CLK_133MHZ);
|
||||
|
||||
SysConfig = PciRead8(Controller, SIL_REG_SYS_CFG);
|
||||
}
|
||||
|
||||
/* If we are unable to do so, skip UDMA6 selection */
|
||||
if ((Device->DmaMode == UDMA_MODE(6)) &&
|
||||
(SysConfig & SIL_CLK_MASK) == SIL_CLK_100MHZ)
|
||||
{
|
||||
ULONG SupportedModes = Device->SupportedModes & ~(PIO_ALL | UDMA_MODE6);
|
||||
|
||||
if (!_BitScanReverse(&Device->DmaMode, SupportedModes))
|
||||
Device->DmaMode = PIO_MODE(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* UDMA timings */
|
||||
if (Device->DmaMode >= UDMA_MODE(0))
|
||||
{
|
||||
ULONG ClockIndex = ((SysConfig & SIL_CLK_MASK) == SIL_CLK_100MHZ) ? 0 : 1;
|
||||
USHORT UdmaTim;
|
||||
|
||||
XferMode = 3;
|
||||
|
||||
UdmaTim = PciRead16(Controller, SIL_REG_UDMA_TIMING(Channel, i));
|
||||
UdmaTim &= ~0x003F;
|
||||
UdmaTim |= Sil680UdmaTimings[ClockIndex][Device->DmaMode - UDMA_MODE(0)];
|
||||
PciWrite16(Controller, SIL_REG_UDMA_TIMING(Channel, i), UdmaTim);
|
||||
}
|
||||
/* DMA timings */
|
||||
else if (Device->DmaMode != PIO_MODE(0))
|
||||
{
|
||||
ULONG ModeIndex = Device->DmaMode - MWDMA_MODE(0);
|
||||
|
||||
XferMode = 2;
|
||||
|
||||
PciWrite16(Controller, SIL_REG_DMA_TIMING(Channel, i), Sil680MwDmaTimings[ModeIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Device->IoReadySupported)
|
||||
XferMode = 1;
|
||||
else
|
||||
XferMode = 0;
|
||||
}
|
||||
|
||||
ModeReg &= ~(0x03 << (i * 4));
|
||||
ModeReg |= XferMode << (i * 4);
|
||||
}
|
||||
|
||||
/* Transfer mode */
|
||||
PciWrite8(Controller, SIL_REG_XFER_MODE(Channel), ModeReg);
|
||||
|
||||
Config = PciRead32(Controller, SIL_REG_CFG(Channel));
|
||||
if (MonitorIoReady)
|
||||
Config |= SIL_CFG_MONITOR_IORDY;
|
||||
else
|
||||
Config &= ~SIL_CFG_MONITOR_IORDY;
|
||||
|
||||
/* Task file timings */
|
||||
if (SlowestPioMode != UDMA_MODE(0))
|
||||
{
|
||||
Config &= ~0xFFFF0000;
|
||||
Config |= Sil680TaskFileTimings[SlowestPioMode] << 16;
|
||||
}
|
||||
|
||||
PciWrite32(Controller, SIL_REG_CFG(Channel), Config);
|
||||
|
||||
INFO("CH %lu: Config (after)\n"
|
||||
"MODE %08lX\n"
|
||||
"CFG %08lX\n"
|
||||
"PIO %08lX\n"
|
||||
"DMA %08lX\n"
|
||||
"UDMA %08lX\n",
|
||||
Channel,
|
||||
PciRead32(Controller, SIL_REG_XFER_MODE(Channel)),
|
||||
Config,
|
||||
PciRead32(Controller, SIL_REG_PIO_TIMING(Channel, 0)),
|
||||
PciRead32(Controller, SIL_REG_DMA_TIMING(Channel, 0)),
|
||||
PciRead32(Controller, SIL_REG_UDMA_TIMING(Channel, 0)));
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
Sil680CheckInterrupt(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
UCHAR Status;
|
||||
|
||||
Status = PciRead8(Controller, SIL_REG_STATUS(ChanData->Channel));
|
||||
return !!(Status & SIL_STATUS_INTR);
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
Sil680GetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_CMD);
|
||||
|
||||
if (Controller->Pci.VendorID != PCI_DEV_SIL0680)
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
UCHAR Config;
|
||||
|
||||
ChanData->CheckInterrupt = Sil680CheckInterrupt;
|
||||
ChanData->SetTransferMode = Sil680SetTransferMode;
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 6);
|
||||
|
||||
/* Check for 80-conductor cable */
|
||||
Config = PciRead8(Controller, SIL_REG_CFG(i));
|
||||
if (!(Config & SIL_CFG_CABLE_80))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
361
drivers/storage/ide/pciidex/chipset/svw_pata.c
Normal file
361
drivers/storage/ide/pciidex/chipset/svw_pata.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
|
||||
* PURPOSE: ServerWorks/Broadcom ATA controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from the FreeBSD ata-serverworks driver
|
||||
* Copyright (c) 1998-2008 Søren Schmidt <sos@FreeBSD.org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_OSB4_IDE 0x0211
|
||||
#define PCI_DEV_CSB5_IDE 0x0212
|
||||
#define PCI_DEV_CSB6_IDE 0x0213
|
||||
#define PCI_DEV_CSB6_IDE_THIRD 0x0217
|
||||
#define PCI_DEV_HT1000_IDE 0x0214
|
||||
|
||||
#define PCI_DEV_OSB4_BRIDGE 0x0210
|
||||
|
||||
#define SVW_REG_PIO_TIMING 0x40
|
||||
#define SVW_REG_DMA_TIMING 0x44
|
||||
#define SVW_REG_PIO_MODE 0x4A // CSB5 and later
|
||||
#define SVW_REG_UDMA_ENABLE 0x54
|
||||
#define SVW_REG_UDMA_MODE 0x56
|
||||
#define SVW_REG_UDMA_CONTROL 0x5A // Absent on ATI
|
||||
|
||||
#define SVW_UDMA_CTRL_MODE_MASK 0x03
|
||||
#define SVW_UDMA_CTRL_DISABLE 0x40
|
||||
|
||||
#define SVW_UDMA_CTRL_MODE_UDMA4 0x02
|
||||
#define SVW_UDMA_CTRL_MODE_UDMA5 0x03
|
||||
|
||||
static const struct
|
||||
{
|
||||
UCHAR Value;
|
||||
ULONG CycleTime;
|
||||
} SvwPioTimings[] =
|
||||
{
|
||||
{ 0x5D, 600 }, // 0
|
||||
{ 0x47, 390 }, // 1
|
||||
{ 0x34, 270 }, // 2
|
||||
{ 0x22, 180 }, // 3
|
||||
{ 0x20, 120 }, // 4
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
UCHAR Value;
|
||||
ULONG CycleTime;
|
||||
} SvwMwDmaTimings[] =
|
||||
{
|
||||
{ 0x77, 480 }, // 0
|
||||
{ 0x21, 150 }, // 1
|
||||
{ 0x20, 120 }, // 2
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
SvwChooseDeviceSpeed(
|
||||
_In_ ULONG Channel,
|
||||
_In_ PCHANNEL_DEVICE_CONFIG Device)
|
||||
{
|
||||
ULONG Mode;
|
||||
|
||||
/* PIO speed */
|
||||
for (Mode = Device->PioMode; Mode > PIO_MODE(0); Mode--)
|
||||
{
|
||||
if (!(Device->SupportedModes & (1 << Mode)))
|
||||
continue;
|
||||
|
||||
if (SvwPioTimings[Mode].CycleTime >= Device->MinPioCycleTime)
|
||||
break;
|
||||
}
|
||||
if (Mode != Device->PioMode)
|
||||
INFO("CH %lu: Downgrade PIO speed from %lu to %lu\n", Channel, Device->PioMode, Mode);
|
||||
Device->PioMode = Mode;
|
||||
|
||||
/* UDMA works independently of any PIO mode */
|
||||
if (Device->DmaMode == PIO_MODE(0) || Device->DmaMode >= UDMA_MODE(0))
|
||||
return;
|
||||
|
||||
/* DMA speed */
|
||||
for (Mode = Device->DmaMode; Mode > PIO_MODE(0); Mode--)
|
||||
{
|
||||
if (!(Device->SupportedModes & ~PIO_ALL & (1 << Mode)))
|
||||
continue;
|
||||
|
||||
ASSERT((1 << Mode) & MWDMA_ALL);
|
||||
|
||||
if (SvwMwDmaTimings[Mode - MWDMA_MODE(0)].CycleTime >= Device->MinMwDmaCycleTime)
|
||||
break;
|
||||
}
|
||||
if (Mode != Device->DmaMode)
|
||||
{
|
||||
if (Mode == PIO_MODE(0))
|
||||
WARN("CH %lu: Too slow device '%s', disabling DMA\n", Channel, Device->FriendlyName);
|
||||
else
|
||||
INFO("CH %lu: Downgrade DMA speed from %lu to %lu\n", Channel, Device->DmaMode, Mode);
|
||||
}
|
||||
Device->DmaMode = Mode;
|
||||
}
|
||||
|
||||
VOID
|
||||
SvwSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
USHORT PioModeReg, UdmaModeReg;
|
||||
UCHAR UdmaEnableReg;
|
||||
ULONG i, PioTimReg, DmaTimReg;
|
||||
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_OSB4_IDE)
|
||||
PioModeReg = PciRead16(Controller, SVW_REG_PIO_MODE);
|
||||
else
|
||||
PioModeReg = 0;
|
||||
|
||||
PioTimReg = PciRead32(Controller, SVW_REG_PIO_TIMING);
|
||||
DmaTimReg = PciRead32(Controller, SVW_REG_DMA_TIMING);
|
||||
UdmaEnableReg = PciRead8(Controller, SVW_REG_UDMA_ENABLE);
|
||||
UdmaModeReg = PciRead16(Controller, SVW_REG_UDMA_MODE);
|
||||
|
||||
INFO("CH %lu: Config (before)\n"
|
||||
"DMA Timing %08lX\n"
|
||||
"PIO Timing %08lX\n"
|
||||
"PIO Mode %04X\n"
|
||||
"UDMA Mode %04X\n",
|
||||
"UDMA Enable %02X\n",
|
||||
Channel,
|
||||
DmaTimReg,
|
||||
PioTimReg,
|
||||
PioModeReg,
|
||||
UdmaModeReg,
|
||||
UdmaEnableReg);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
const ULONG DeviceIndex = (Channel << 1) + i; // 0 1 2 3
|
||||
const ULONG Shift = (DeviceIndex ^ 1) << 3; // 8 0 24 16
|
||||
|
||||
UdmaModeReg &= ~(0x0F << (DeviceIndex << 2));
|
||||
UdmaEnableReg &= ~(0x01 << DeviceIndex);
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
/* Make sure that the selected PIO and DMA speeds match the cycle time */
|
||||
SvwChooseDeviceSpeed(Channel, Device);
|
||||
|
||||
/* UDMA timings */
|
||||
if (Device->DmaMode >= UDMA_MODE(0))
|
||||
{
|
||||
ULONG ModeIndex = Device->DmaMode - UDMA_MODE(0);
|
||||
|
||||
UdmaModeReg |= ModeIndex << (DeviceIndex << 2);
|
||||
UdmaEnableReg |= 1 << DeviceIndex;
|
||||
|
||||
DmaTimReg &= ~(0xFF << Shift);
|
||||
DmaTimReg |= SvwMwDmaTimings[2].Value << Shift;
|
||||
}
|
||||
/* DMA timings */
|
||||
else if (Device->DmaMode != PIO_MODE(0))
|
||||
{
|
||||
ULONG ModeIndex = Device->DmaMode - MWDMA_MODE(0);
|
||||
|
||||
DmaTimReg &= ~(0xFF << Shift);
|
||||
DmaTimReg |= SvwMwDmaTimings[ModeIndex].Value << Shift;
|
||||
}
|
||||
|
||||
/* PIO timings */
|
||||
PioModeReg &= ~(0x0F << (DeviceIndex << 2));
|
||||
PioModeReg |= Device->PioMode << (DeviceIndex << 2);
|
||||
|
||||
PioTimReg &= ~(0xFF << Shift);
|
||||
PioTimReg |= SvwPioTimings[Device->PioMode].Value << Shift;
|
||||
}
|
||||
|
||||
PciWrite32(Controller, SVW_REG_PIO_TIMING, PioTimReg);
|
||||
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_OSB4_IDE)
|
||||
PciWrite16(Controller, SVW_REG_PIO_MODE, PioModeReg);
|
||||
|
||||
PciWrite32(Controller, SVW_REG_DMA_TIMING, DmaTimReg);
|
||||
PciWrite16(Controller, SVW_REG_UDMA_MODE, UdmaModeReg);
|
||||
PciWrite8(Controller, SVW_REG_UDMA_ENABLE, UdmaEnableReg);
|
||||
|
||||
INFO("CH %lu: Config (after)\n"
|
||||
"DMA Timing %08lX\n"
|
||||
"PIO Timing %08lX\n"
|
||||
"PIO Mode %04X\n"
|
||||
"UDMA Mode %04X\n",
|
||||
"UDMA Enable %02X\n",
|
||||
Channel,
|
||||
DmaTimReg,
|
||||
PioTimReg,
|
||||
PioModeReg,
|
||||
UdmaModeReg,
|
||||
UdmaEnableReg);
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
SvwHasUdmaCable(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel)
|
||||
{
|
||||
UCHAR UdmaModeReg;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
UdmaModeReg = PciRead8(Controller, SVW_REG_UDMA_MODE + Channel);
|
||||
|
||||
/* Check mode settings, see if UDMA3 or higher mode is active */
|
||||
return ((UdmaModeReg & 0x07) > 2) || ((UdmaModeReg & 0x70) > 0x20);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SvwOsb4PciBridgeInit(
|
||||
_In_ PVOID Context,
|
||||
_In_ ULONG BusNumber,
|
||||
_In_ PCI_SLOT_NUMBER PciSlot,
|
||||
_In_ PPCI_COMMON_HEADER PciConfig)
|
||||
{
|
||||
ULONG Value;
|
||||
|
||||
UNREFERENCED_PARAMETER(Context);
|
||||
|
||||
if (PciConfig->VendorID != PCI_VEN_SERVERWORKS ||
|
||||
PciConfig->DeviceID != PCI_DEV_OSB4_BRIDGE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HalGetBusDataByOffset(PCIConfiguration,
|
||||
BusNumber,
|
||||
PciSlot.u.AsULONG,
|
||||
&Value,
|
||||
0x64,
|
||||
sizeof(Value));
|
||||
Value &= ~0x00002000; // Disable 600ns interrupt mask
|
||||
Value |= 0x00004000; // Enable UDMA/33 support
|
||||
HalSetBusDataByOffset(PCIConfiguration,
|
||||
BusNumber,
|
||||
PciSlot.u.AsULONG,
|
||||
&Value,
|
||||
0x64,
|
||||
sizeof(Value));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SvwPataControllerStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_OSB4_IDE)
|
||||
{
|
||||
PciFindDevice(SvwOsb4PciBridgeInit, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
PCHANNEL_DATA_COMMON ChanData = Controller->Channels[0];
|
||||
UCHAR UdmaCtrlReg = PciRead8(Controller, SVW_REG_UDMA_CONTROL);
|
||||
|
||||
UdmaCtrlReg &= ~(SVW_UDMA_CTRL_DISABLE | SVW_UDMA_CTRL_MODE_MASK);
|
||||
if (ChanData->TransferModeSupported & UDMA_MODE5)
|
||||
UdmaCtrlReg |= SVW_UDMA_CTRL_MODE_UDMA5;
|
||||
else
|
||||
UdmaCtrlReg |= SVW_UDMA_CTRL_MODE_UDMA4;
|
||||
|
||||
PciWrite8(Controller, SVW_REG_UDMA_CONTROL, UdmaCtrlReg);
|
||||
}
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
SvwPataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i, SupportedMode;
|
||||
BOOLEAN No64KDma = FALSE;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_SERVERWORKS);
|
||||
|
||||
switch (Controller->Pci.DeviceID)
|
||||
{
|
||||
case PCI_DEV_OSB4_IDE:
|
||||
/* UDMA is supported but its use is discouraged */
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL;
|
||||
|
||||
No64KDma = TRUE;
|
||||
break;
|
||||
|
||||
case PCI_DEV_CSB5_IDE:
|
||||
if (Controller->Pci.RevisionID < 0x92)
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
|
||||
else
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
Controller->Flags |= CTRL_FLAG_DMA_INTERRUPT;
|
||||
break;
|
||||
|
||||
case PCI_DEV_CSB6_IDE_THIRD:
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
|
||||
Controller->MaxChannels = 1;
|
||||
break;
|
||||
|
||||
case PCI_DEV_CSB6_IDE:
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
break;
|
||||
|
||||
case PCI_DEV_HT1000_IDE:
|
||||
SupportedMode = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
Controller->MaxChannels = 1;
|
||||
No64KDma = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return STATUS_NO_MATCH;
|
||||
}
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
Controller->Start = SvwPataControllerStart;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
if (No64KDma)
|
||||
ChanData->MaximumTransferLength = PCIIDE_PRD_LIMIT - 0x4000;
|
||||
|
||||
ChanData->SetTransferMode = SvwSetTransferMode;
|
||||
ChanData->TransferModeSupported = SupportedMode;
|
||||
|
||||
/* Check for 80-conductor cable */
|
||||
if ((ChanData->TransferModeSupported & UDMA_80C_ALL) && !SvwHasUdmaCable(Controller, i))
|
||||
{
|
||||
INFO("CH %lu: BIOS hasn't selected mode faster than UDMA 2, "
|
||||
"assume 40-conductor cable\n",
|
||||
ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
289
drivers/storage/ide/pciidex/chipset/svw_sata.c
Normal file
289
drivers/storage/ide/pciidex/chipset/svw_sata.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
|
||||
* PURPOSE: ServerWorks/Broadcom SATA controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from the FreeBSD ata-serverworks driver
|
||||
* Copyright (c) 1998-2008 Søren Schmidt <sos@FreeBSD.org>
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_K2_SATA 0x0240
|
||||
#define PCI_DEV_BCM5770_SATA 0x0241
|
||||
#define PCI_DEV_BCM5770R_SATA 0x0242
|
||||
#define PCI_DEV_HT1000_SATA 0x024A
|
||||
#define PCI_DEV_HT1000_SATA_2 0x024B
|
||||
#define PCI_DEV_HT1100_SATA 0x0410
|
||||
#define PCI_DEV_HT1100_SATA_2 0x0411
|
||||
|
||||
#define SVW_SATA_PORT_BASE_OFFSET 0x100
|
||||
#define SVW_SATA_PORT_CONTROL_OFFSET 0x20
|
||||
#define SVW_SATA_PORT_DMA_OFFSET 0x30
|
||||
#define SVW_SATA_PORT_SCR_OFFSET 0x40
|
||||
#define SVW_SATA_PORT_TF_STRIDE 4
|
||||
|
||||
#define HW_FLAGS_8_PORTS 0x01
|
||||
#define HW_FLAGS_NO_ATAPI_DMA 0x02
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const struct
|
||||
{
|
||||
USHORT DeviceID;
|
||||
USHORT Flags;
|
||||
} SvwSataControllerList[] =
|
||||
{
|
||||
{ PCI_DEV_K2_SATA, HW_FLAGS_NO_ATAPI_DMA },
|
||||
{ PCI_DEV_BCM5770_SATA, HW_FLAGS_NO_ATAPI_DMA | HW_FLAGS_8_PORTS },
|
||||
{ PCI_DEV_BCM5770R_SATA, HW_FLAGS_NO_ATAPI_DMA },
|
||||
{ PCI_DEV_HT1000_SATA, HW_FLAGS_NO_ATAPI_DMA },
|
||||
{ PCI_DEV_HT1000_SATA_2, HW_FLAGS_NO_ATAPI_DMA },
|
||||
{ PCI_DEV_HT1100_SATA, 0 },
|
||||
{ PCI_DEV_HT1100_SATA_2, 0 },
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SvwSataScrRead(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ PULONG Result)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PortNumber);
|
||||
|
||||
if (Register > ATA_SCONTROL)
|
||||
return FALSE;
|
||||
|
||||
*Result = READ_REGISTER_ULONG((PULONG)(ChanData->Regs.Scr + (Register * 4)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SvwSataScrWrite(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PortNumber);
|
||||
|
||||
if (Register > ATA_SCONTROL)
|
||||
return FALSE;
|
||||
|
||||
WRITE_REGISTER_ULONG((PULONG)(ChanData->Regs.Scr + (Register * 4)), Value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
ULONG
|
||||
SvwSataGetIoBarIndex(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
return (Controller->Pci.DeviceID == PCI_DEV_HT1100_SATA) ? 3 : 5;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SvwSataCheckInterrupt(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
PUCHAR IoBase = Controller->AccessRange[SvwSataGetIoBarIndex(Controller)].IoBase;
|
||||
ULONG InterruptStatus;
|
||||
|
||||
InterruptStatus = READ_REGISTER_ULONG((PULONG)(IoBase + 0x1F80));
|
||||
return !!(InterruptStatus & (1 << ChanData->Channel));
|
||||
}
|
||||
|
||||
static
|
||||
UCHAR
|
||||
SvwSataReadStatus(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData)
|
||||
{
|
||||
/*
|
||||
* The SATA hardware expects 32-bit reads on the status register
|
||||
* to get it latched propertly.
|
||||
*/
|
||||
return READ_REGISTER_ULONG((PULONG)ChanData->Regs.Status);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SvwSataLoadTaskFile(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ PATA_DEVICE_REQUEST Request)
|
||||
{
|
||||
USHORT Features, SectorCount, LbaLow, LbaMid, LbaHigh;
|
||||
|
||||
Features = Request->TaskFile.Feature;
|
||||
SectorCount = Request->TaskFile.SectorCount;
|
||||
LbaLow = Request->TaskFile.LowLba;
|
||||
LbaMid = Request->TaskFile.MidLba;
|
||||
LbaHigh = Request->TaskFile.HighLba;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_LBA48)
|
||||
{
|
||||
Features |= (USHORT)Request->TaskFile.FeatureEx << 8;
|
||||
SectorCount |= (USHORT)Request->TaskFile.SectorCountEx << 8;
|
||||
LbaLow |= (USHORT)Request->TaskFile.LowLbaEx << 8;
|
||||
LbaMid |= (USHORT)Request->TaskFile.MidLbaEx << 8;
|
||||
LbaHigh |= (USHORT)Request->TaskFile.HighLbaEx << 8;
|
||||
}
|
||||
|
||||
/* The SATA hardware needs 16-bit accesses for the second byte of FIFO */
|
||||
WRITE_REGISTER_USHORT((PUSHORT)ChanData->Regs.Features, Features);
|
||||
WRITE_REGISTER_USHORT((PUSHORT)ChanData->Regs.SectorCount, SectorCount);
|
||||
WRITE_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaLow, LbaLow);
|
||||
WRITE_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaMid, LbaMid);
|
||||
WRITE_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaHigh, LbaHigh);
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_SET_DEVICE_REGISTER)
|
||||
WRITE_REGISTER_UCHAR(ChanData->Regs.Device, Request->TaskFile.DriveSelect);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SvwSataSaveTaskFile(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_Inout_ PATA_DEVICE_REQUEST Request)
|
||||
{
|
||||
PATA_TASKFILE TaskFile = &Request->Output;
|
||||
USHORT Error, SectorCount, LbaLow, LbaMid, LbaHigh;
|
||||
|
||||
TaskFile->DriveSelect = READ_REGISTER_UCHAR(ChanData->Regs.Device);
|
||||
TaskFile->Command = READ_REGISTER_UCHAR(ChanData->Regs.Command);
|
||||
|
||||
Error = READ_REGISTER_USHORT((PUSHORT)ChanData->Regs.Error);
|
||||
SectorCount = READ_REGISTER_USHORT((PUSHORT)ChanData->Regs.SectorCount);
|
||||
LbaLow = READ_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaLow);
|
||||
LbaMid = READ_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaMid);
|
||||
LbaHigh = READ_REGISTER_USHORT((PUSHORT)ChanData->Regs.LbaHigh);
|
||||
|
||||
TaskFile->Error = Error & 0xFF;
|
||||
TaskFile->SectorCount = SectorCount & 0xFF;
|
||||
TaskFile->LowLba = LbaLow & 0xFF;
|
||||
TaskFile->MidLba = LbaMid & 0xFF;
|
||||
TaskFile->HighLba = LbaHigh & 0xFF;
|
||||
|
||||
if (Request->Flags & REQUEST_FLAG_LBA48)
|
||||
{
|
||||
TaskFile->FeatureEx = Error >> 8;
|
||||
TaskFile->SectorCountEx = SectorCount >> 8;
|
||||
TaskFile->LowLbaEx = LbaLow >> 8;
|
||||
TaskFile->MidLbaEx = LbaMid >> 8;
|
||||
TaskFile->HighLbaEx = LbaHigh >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
SvwSataParseResources(
|
||||
_Inout_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ PUCHAR IoBase,
|
||||
_In_ ULONG PortIndex)
|
||||
{
|
||||
PUCHAR ChanBase = IoBase + (PortIndex * SVW_SATA_PORT_BASE_OFFSET);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_MRES_TF | CHANNEL_FLAG_MRES_CTRL | CHANNEL_FLAG_MRES_DMA;
|
||||
|
||||
ChanData->Regs.Dma = ChanBase + SVW_SATA_PORT_DMA_OFFSET;
|
||||
ChanData->Regs.Scr = ChanBase + SVW_SATA_PORT_SCR_OFFSET;
|
||||
|
||||
PciIdeInitTaskFileIoResources(ChanData,
|
||||
(ULONG_PTR)ChanBase,
|
||||
(ULONG_PTR)ChanBase + SVW_SATA_PORT_CONTROL_OFFSET,
|
||||
SVW_SATA_PORT_TF_STRIDE);
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
SvwSataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i, HwFlags;
|
||||
PUCHAR IoBase;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_SERVERWORKS);
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(SvwSataControllerList); ++i)
|
||||
{
|
||||
HwFlags = SvwSataControllerList[i].Flags;
|
||||
|
||||
if (Controller->Pci.DeviceID == SvwSataControllerList[i].DeviceID)
|
||||
break;
|
||||
}
|
||||
if (i == RTL_NUMBER_OF(SvwSataControllerList))
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
if (HwFlags & HW_FLAGS_8_PORTS)
|
||||
Controller->MaxChannels = 8;
|
||||
else
|
||||
Controller->MaxChannels = 4;
|
||||
|
||||
Controller->Flags |= CTRL_FLAG_MANUAL_RES;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
IoBase = AtaCtrlPciMapBar(Controller, SvwSataGetIoBarIndex(Controller), 0);
|
||||
if (!IoBase)
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
|
||||
/*
|
||||
* Errata: Set SICR registers to turn off waiting for a status message
|
||||
* before sending FIS, fixes some issues with Seagate hard drives.
|
||||
*/
|
||||
WRITE_REGISTER_ULONG((PULONG)(IoBase + 0x80),
|
||||
READ_REGISTER_ULONG((PULONG)(IoBase + 0x80)) & ~0x00040000);
|
||||
|
||||
/* Clear interrupts */
|
||||
WRITE_REGISTER_ULONG((PULONG)(IoBase + 0x44), 0xFFFFFFFF);
|
||||
WRITE_REGISTER_ULONG((PULONG)(IoBase + 0x88), 0);
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->TransferModeSupported = SATA_ALL;
|
||||
ChanData->SetTransferMode = SataSetTransferMode;
|
||||
|
||||
if (HwFlags & HW_FLAGS_NO_ATAPI_DMA)
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_NO_ATAPI_DMA;
|
||||
|
||||
/*
|
||||
* Errata: Enable the DMA engine before sending the drive command
|
||||
* to avoid data corruption.
|
||||
*/
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_DMA_BEFORE_CMD;
|
||||
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_NO_SLAVE;
|
||||
ChanData->ReadStatus = SvwSataReadStatus;
|
||||
ChanData->LoadTaskFile = SvwSataLoadTaskFile;
|
||||
ChanData->SaveTaskFile = SvwSataSaveTaskFile;
|
||||
ChanData->CheckInterrupt = SvwSataCheckInterrupt;
|
||||
ChanData->ScrRead = SvwSataScrRead;
|
||||
ChanData->ScrWrite = SvwSataScrWrite;
|
||||
|
||||
SvwSataParseResources(ChanData, IoBase, i);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
134
drivers/storage/ide/pciidex/chipset/toshiba.c
Normal file
134
drivers/storage/ide/pciidex/chipset/toshiba.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
|
||||
* PURPOSE: Toshiba PCI IDE controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from the NetBSD toshide driver
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_PICCOLO_1 0x0101
|
||||
#define PCI_DEV_PICCOLO_2 0x0102
|
||||
#define PCI_DEV_PICCOLO_3 0x0103
|
||||
#define PCI_DEV_PICCOLO_5 0x0105
|
||||
|
||||
#define PICCOLO_REG_PIO_TIMING 0x50
|
||||
#define PICCOLO_REG_DMA_TIMING 0x5C
|
||||
|
||||
#define PICCOLO_PIO_MASK 0xFFFFE088
|
||||
#define PICCOLO_DMA_MASK 0xFFFFE088
|
||||
#define PICCOLO_UDMA_MASK 0x78FFE088
|
||||
|
||||
static const ULONG PiccoloPioTimings[] =
|
||||
{
|
||||
0x0566, // Mode 0
|
||||
0x0433, // Mode 1
|
||||
0x0311, // Mode 2
|
||||
0x0201, // Mode 3
|
||||
0x0200 // Mode 4
|
||||
};
|
||||
|
||||
static const ULONG PiccoloMwDmaTimings[] =
|
||||
{
|
||||
0x0655, // Mode 0
|
||||
0x0200, // Mode 1
|
||||
0x0200, // Mode 2
|
||||
};
|
||||
|
||||
static const ULONG PiccoloUdmaTimings[] =
|
||||
{
|
||||
0x84000222, // Mode 0
|
||||
0x83000111, // Mode 1
|
||||
0x82000000, // Mode 2
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
ToshibaSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
UNREFERENCED_PARAMETER(Channel);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
ULONG TimingReg;
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
TimingReg = PciRead32(Controller, PICCOLO_REG_PIO_TIMING);
|
||||
TimingReg &= PICCOLO_PIO_MASK;
|
||||
TimingReg |= PiccoloPioTimings[Device->PioMode];
|
||||
PciWrite32(Controller, PICCOLO_REG_PIO_TIMING, TimingReg);
|
||||
|
||||
if (Device->DmaMode != PIO_MODE(0))
|
||||
{
|
||||
TimingReg = PciRead32(Controller, PICCOLO_REG_DMA_TIMING);
|
||||
|
||||
if (Device->DmaMode >= UDMA_MODE(0))
|
||||
{
|
||||
TimingReg &= PICCOLO_UDMA_MASK;
|
||||
TimingReg |= PiccoloUdmaTimings[Device->DmaMode - UDMA_MODE(0)];
|
||||
}
|
||||
else
|
||||
{
|
||||
TimingReg &= PICCOLO_DMA_MASK;
|
||||
TimingReg |= PiccoloMwDmaTimings[Device->DmaMode - MWDMA_MODE(0)];
|
||||
}
|
||||
|
||||
PciWrite32(Controller, PICCOLO_REG_DMA_TIMING, TimingReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ToshibaGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_TOSHIBA);
|
||||
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_PICCOLO_1 &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_PICCOLO_2 &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_PICCOLO_3 &&
|
||||
Controller->Pci.DeviceID != PCI_DEV_PICCOLO_5)
|
||||
{
|
||||
return STATUS_NO_MATCH;
|
||||
}
|
||||
|
||||
Controller->MaxChannels = 1;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 2);
|
||||
ChanData->SetTransferMode = ToshibaSetTransferMode;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
899
drivers/storage/ide/pciidex/chipset/via.c
Normal file
899
drivers/storage/ide/pciidex/chipset/via.c
Normal file
@@ -0,0 +1,899 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: BSD-2-Clause (https://spdx.org/licenses/BSD-2-Clause)
|
||||
* PURPOSE: VIA ATA controller minidriver
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some code taken from the NetBSD viaide driver
|
||||
* Copyright (c) 1999, 2000, 2001 Manuel Bouyer
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define PCI_DEV_VT82C576M_IDE 0x1571
|
||||
#define PCI_DEV_VT82C586A_IDE 0x0571
|
||||
#define PCI_DEV_VT6410_IDE_RAID 0x3164
|
||||
#define PCI_DEV_VT6415_IDE 0x0415
|
||||
#define PCI_DEV_VT6420_IDE 0x4149
|
||||
#define PCI_DEV_VT6421A_RAID 0x3249
|
||||
#define PCI_DEV_CX700M2_IDE_SATA 0x5324
|
||||
#define PCI_DEV_CX700M2_IDE_SATA_RAID 0x0581
|
||||
#define PCI_DEV_VX855_IDE 0xC409
|
||||
|
||||
#define PCI_DEV_VT8237_SATA 0x3149
|
||||
#define PCI_DEV_VT8237A_SATA 0x0591
|
||||
#define PCI_DEV_VT8237A_SATA_2 0x5337
|
||||
#define PCI_DEV_VT8237S_SATA 0x5372
|
||||
#define PCI_DEV_VT8237S_SATA_RAID 0x7372
|
||||
#define PCI_DEV_VT8251_SATA_AHCI 0x3349
|
||||
#define PCI_DEV_VT8251_SATA_2 0x5287
|
||||
#define PCI_DEV_VT8261_SATA 0x9000
|
||||
#define PCI_DEV_VT8261_SATA_RAID 0x9040
|
||||
#define PCI_DEV_VX900_SATA 0x9001
|
||||
#define PCI_DEV_VX900_SATA_RAID 0x9041
|
||||
|
||||
#define PCI_DEV_BRIDGE_VT82C586 0x0586
|
||||
#define PCI_DEV_BRIDGE_VT82C596A 0x0596
|
||||
#define PCI_DEV_BRIDGE_VT82C686A 0x0686
|
||||
#define PCI_DEV_BRIDGE_VT8231 0x8231
|
||||
#define PCI_DEV_BRIDGE_VT8233 0x3074
|
||||
#define PCI_DEV_BRIDGE_VT8233A 0x3147
|
||||
#define PCI_DEV_BRIDGE_VT8233C 0x3109
|
||||
#define PCI_DEV_BRIDGE_VT8235 0x3177
|
||||
#define PCI_DEV_BRIDGE_VT8237 0x3227
|
||||
#define PCI_DEV_BRIDGE_VT8237A 0x3337
|
||||
#define PCI_DEV_BRIDGE_VT8237S 0x3372
|
||||
#define PCI_DEV_BRIDGE_VT8251 0x3287
|
||||
#define PCI_DEV_BRIDGE_VT8261 0x3402
|
||||
|
||||
#define HW_FLAGS_TYPE_MASK 0x000F
|
||||
#define HW_FLAGS_CHECK_BRIDGE 0x0010
|
||||
#define HW_FLAGS_HAS_UDMA_CLOCK 0x0020
|
||||
#define HW_FLAGS_SINGLE_CHAN 0x0040
|
||||
#define HW_FLAGS_SINGLE_PORT 0x0080
|
||||
#define HW_FLAGS_PCI_SCR 0x0100
|
||||
|
||||
#define TYPE_33 0
|
||||
#define TYPE_66 1
|
||||
#define TYPE_100 2
|
||||
#define TYPE_133 3
|
||||
#define TYPE_MWDMA 4
|
||||
#define TYPE_SATA 5
|
||||
|
||||
#define GET_TYPE(Flags) ((Flags) & HW_FLAGS_TYPE_MASK)
|
||||
|
||||
#define VIA_PCI_CLOCK 30000
|
||||
|
||||
#define VIA_REG_ENABLE_CTRL 0x40
|
||||
#define VIA_REG_DRIVE_TIMING 0x48
|
||||
#define VIA_REG_PORT_TIMING(Channel) (0x4F - (Channel))
|
||||
#define VIA_REG_ADDRESS_SETUP 0x4C
|
||||
#define VIA_REG_UDMA_CTRL 0x50
|
||||
#define VIA_REG_SSTATUS 0xA0
|
||||
#define VIA_REG_SCONTROL 0xA4
|
||||
#define VIA_REG_SERROR 0xA8
|
||||
#define VIA_REG_SERROR_VT8237 0xB0
|
||||
|
||||
#define VIA_UDMA_CLOCK_UDMA66 0x08
|
||||
#define VIA_UDMA_CABLE_BITS 0x10
|
||||
#define VIA_UDMA_CLEAR_MASK 0xEF // Save the cable bits
|
||||
|
||||
#define VIA_UDMA_CLOCK_ENABLED(Reg32, Channel) \
|
||||
(((Reg32) & (0x00080000 >> ((Channel) * 16))) != 0)
|
||||
|
||||
#define VIA_UDMA_CABLE_PRESENT(Reg32, Channel) \
|
||||
(((Reg32) & (0x10100000 >> ((Channel) * 16))) != 0)
|
||||
|
||||
#define VIA_SINGLE_CHAN_UDMA_CABLE_PRESENT(Controller) \
|
||||
((PciRead16(Controller, 0x50) & 0x1010) != 0)
|
||||
|
||||
/* Note that the cable bits are inverted */
|
||||
#define VT6421A_UDMA_CABLE_PRESENT(Controller) \
|
||||
((PciRead16(Controller, 0xB2) & 0x1010) == 0)
|
||||
|
||||
#define VIA_REG_SATA_PORT_MAP 0x49
|
||||
|
||||
#define VT6421A_REG_SATA_CTRL 0x52 // Also for VT8237
|
||||
#define VT6421A_REG_TIMING_CTRL(Drive) (0xAB - (Drive))
|
||||
#define VT6421A_REG_UDMA_CTRL(Drive) (0xB3 - (Drive))
|
||||
|
||||
#define VT6421A_UDMA_SLOW 0x0F
|
||||
#define VT6421A_FIFO_WATERMARK_64DW 0x04
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const struct
|
||||
{
|
||||
USHORT DeviceID;
|
||||
USHORT Flags;
|
||||
} ViaControllerList[] =
|
||||
{
|
||||
{ PCI_DEV_VT82C576M_IDE, TYPE_MWDMA },
|
||||
{ PCI_DEV_VT82C586A_IDE, HW_FLAGS_CHECK_BRIDGE },
|
||||
{ PCI_DEV_VT6410_IDE_RAID, TYPE_133 },
|
||||
{ PCI_DEV_VT6415_IDE, TYPE_133 | HW_FLAGS_SINGLE_CHAN },
|
||||
{ PCI_DEV_VT6420_IDE, TYPE_133 | HW_FLAGS_SINGLE_CHAN },
|
||||
{ PCI_DEV_VX855_IDE, TYPE_133 | HW_FLAGS_SINGLE_CHAN },
|
||||
{ PCI_DEV_VT8237_SATA, TYPE_SATA | HW_FLAGS_SINGLE_PORT },
|
||||
{ PCI_DEV_VT8237A_SATA, TYPE_SATA | HW_FLAGS_SINGLE_PORT },
|
||||
{ PCI_DEV_VT8237A_SATA_2, TYPE_SATA | HW_FLAGS_SINGLE_PORT },
|
||||
{ PCI_DEV_VT8237S_SATA, TYPE_SATA | HW_FLAGS_SINGLE_PORT },
|
||||
{ PCI_DEV_VT8237S_SATA_RAID, TYPE_SATA | HW_FLAGS_SINGLE_PORT | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VT8251_SATA_AHCI, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VT8251_SATA_2, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VT8261_SATA, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VT8261_SATA_RAID, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VX900_SATA, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
{ PCI_DEV_VX900_SATA_RAID, TYPE_SATA | HW_FLAGS_PCI_SCR },
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
UCHAR DefaultValue;
|
||||
UCHAR Data[7];
|
||||
} ViaUdmaTimings[] =
|
||||
{
|
||||
// UDMA 0 1 2 3 4 5 6
|
||||
{ 0x03, { 0xE2, 0xE1, 0xE0 } }, // TYPE_33
|
||||
{ 0x03, { 0xE6, 0xE4, 0xE2, 0xE1, 0xE0 } }, // TYPE_66
|
||||
{ 0x07, { 0xEA, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0 } }, // TYPE_100
|
||||
{ 0x07, { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0 } }, // TYPE_133
|
||||
};
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const ATA_PCI_ENABLE_BITS ViaPataEnableBits[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
{ 0x40, 0x02, 0x02 },
|
||||
{ 0x40, 0x01, 0x01 },
|
||||
};
|
||||
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const ATA_PCI_ENABLE_BITS ViaCx700EnableBits[MAX_IDE_CHANNEL] =
|
||||
{
|
||||
{ 0x40, 0x02, 0x02 },
|
||||
{ 0xC0, 0x01, 0x01 },
|
||||
};
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
ViaClampTimings(
|
||||
_Inout_ PATA_TIMING Timing)
|
||||
{
|
||||
Timing->AddressSetup = CLAMP_TIMING(Timing->AddressSetup, 1, 4) - 1;
|
||||
Timing->CmdRecovery = CLAMP_TIMING(Timing->CmdRecovery, 1, 16) - 1;
|
||||
Timing->CmdActive = CLAMP_TIMING(Timing->CmdActive, 1, 16) - 1;
|
||||
Timing->DataRecovery = CLAMP_TIMING(Timing->DataRecovery, 1, 16) - 1;
|
||||
Timing->DataActive = CLAMP_TIMING(Timing->DataActive, 1, 16) - 1;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
ViaSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[Channel];
|
||||
ATA_TIMING DeviceTimings[MAX_IDE_DEVICE];
|
||||
ULONG i;
|
||||
ULONG DriveTimReg, UdmaTimReg;
|
||||
UCHAR PortTimReg;
|
||||
|
||||
AtaSelectTimings(DeviceList, DeviceTimings, VIA_PCI_CLOCK, SHARED_CMD_TIMINGS);
|
||||
|
||||
INFO("CH %lu: Config (before)\n"
|
||||
"DRV %08lX\n"
|
||||
"PORT %08lX\n"
|
||||
"UDMA %08lX\n"
|
||||
"CFG %08lX\n",
|
||||
Channel,
|
||||
PciRead32(Controller, 0x48),
|
||||
PciRead32(Controller, 0x4C),
|
||||
PciRead32(Controller, 0x50),
|
||||
PciRead32(Controller, 0x40));
|
||||
|
||||
DriveTimReg = PciRead32(Controller, VIA_REG_DRIVE_TIMING);
|
||||
PortTimReg = PciRead8(Controller, VIA_REG_PORT_TIMING(Channel));
|
||||
|
||||
if (GET_TYPE(ChanData->HwFlags) != TYPE_MWDMA)
|
||||
UdmaTimReg = PciRead32(Controller, VIA_REG_UDMA_CTRL);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
PATA_TIMING Timing = &DeviceTimings[i];
|
||||
const ULONG DeviceIndex = (Channel << 1) + i; // 0 1 2 3
|
||||
const ULONG Shift = (3 - DeviceIndex) << 3; // 24 16 8 0
|
||||
ULONG Value;
|
||||
|
||||
/* UDMA timings */
|
||||
if (GET_TYPE(ChanData->HwFlags) != TYPE_MWDMA)
|
||||
{
|
||||
if (Device && (Device->DmaMode >= UDMA_MODE(0)))
|
||||
{
|
||||
ULONG ModeIndex = Device->DmaMode - UDMA_MODE(0);
|
||||
Value = ViaUdmaTimings[GET_TYPE(ChanData->HwFlags)].Data[ModeIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = ViaUdmaTimings[GET_TYPE(ChanData->HwFlags)].DefaultValue;
|
||||
}
|
||||
|
||||
/* Turn on the 66MHz UDMA clock */
|
||||
if ((i != 0) && (GET_TYPE(ChanData->HwFlags) == TYPE_66))
|
||||
Value |= VIA_UDMA_CLOCK_UDMA66;
|
||||
|
||||
UdmaTimReg &= ~(VIA_UDMA_CLEAR_MASK << Shift);
|
||||
UdmaTimReg |= Value << Shift;
|
||||
}
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
/* PIO and DMA timings */
|
||||
ViaClampTimings(Timing);
|
||||
|
||||
Value = (Timing->DataActive << 4) | Timing->DataRecovery;
|
||||
DriveTimReg &= ~(0xFF << Shift);
|
||||
DriveTimReg |= Value << Shift;
|
||||
|
||||
PortTimReg = (Timing->CmdActive << 4) | Timing->CmdRecovery;
|
||||
}
|
||||
|
||||
PciWrite8(Controller, VIA_REG_PORT_TIMING(Channel), PortTimReg);
|
||||
PciWrite32(Controller, VIA_REG_DRIVE_TIMING, DriveTimReg);
|
||||
|
||||
if (GET_TYPE(ChanData->HwFlags) != TYPE_MWDMA)
|
||||
PciWrite32(Controller, VIA_REG_UDMA_CTRL, UdmaTimReg);
|
||||
|
||||
INFO("CH %lu: Config (after)\n"
|
||||
"DRV %08lX\n"
|
||||
"PORT %08lX\n"
|
||||
"UDMA %08lX\n"
|
||||
"CFG %08lX\n",
|
||||
Channel,
|
||||
PciRead32(Controller, 0x48),
|
||||
PciRead32(Controller, 0x4C),
|
||||
PciRead32(Controller, 0x50),
|
||||
PciRead32(Controller, 0x40));
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
ViaSataSetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
UCHAR SataControl = PciRead8(Controller, VT6421A_REG_SATA_CTRL);
|
||||
ULONG i;
|
||||
|
||||
if (!(SataControl & VT6421A_FIFO_WATERMARK_64DW))
|
||||
{
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
/* Fix freezes with Western Digital drives. See CORE-5897 for more details */
|
||||
if (_strnicmp(Device->FriendlyName, "WD", 2) == 0)
|
||||
{
|
||||
/* This will slow down I/O performance */
|
||||
WARN("Enabling workaround for the '%s' drive\n", Device->FriendlyName);
|
||||
SataControl |= VT6421A_FIFO_WATERMARK_64DW;
|
||||
PciWrite8(Controller, VT6421A_REG_SATA_CTRL, SataControl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SataSetTransferMode(Controller, Channel, DeviceList);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
Via6421SetTransferMode(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList)
|
||||
{
|
||||
ATA_TIMING DeviceTimings[MAX_IDE_DEVICE];
|
||||
ULONG i;
|
||||
|
||||
UNREFERENCED_PARAMETER(Channel);
|
||||
|
||||
AtaSelectTimings(DeviceList, DeviceTimings, VIA_PCI_CLOCK, SHARED_CMD_TIMINGS);
|
||||
|
||||
for (i = 0; i < MAX_IDE_DEVICE; ++i)
|
||||
{
|
||||
PCHANNEL_DEVICE_CONFIG Device = DeviceList[i];
|
||||
PATA_TIMING Timing = &DeviceTimings[i];
|
||||
UCHAR UdmaTimReg;
|
||||
|
||||
/* UDMA timings */
|
||||
UdmaTimReg = PciRead8(Controller, VT6421A_REG_UDMA_CTRL(i));
|
||||
UdmaTimReg &= VIA_UDMA_CABLE_BITS;
|
||||
if (Device && (Device->DmaMode >= UDMA_MODE(0)))
|
||||
UdmaTimReg |= ViaUdmaTimings[TYPE_133].Data[Device->DmaMode - UDMA_MODE(0)];
|
||||
else
|
||||
UdmaTimReg |= VT6421A_UDMA_SLOW;
|
||||
PciWrite8(Controller, VT6421A_REG_UDMA_CTRL(i), UdmaTimReg);
|
||||
|
||||
if (!Device)
|
||||
continue;
|
||||
|
||||
ViaClampTimings(Timing);
|
||||
|
||||
/* PIO timings */
|
||||
PciWrite8(Controller,
|
||||
VT6421A_REG_TIMING_CTRL(i),
|
||||
(Timing->DataActive << 4) | Timing->DataRecovery);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
ULONG
|
||||
ViaGetSerrOffset(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
if ((Controller->Pci.DeviceID == PCI_DEV_VT8237S_SATA_RAID))
|
||||
return VIA_REG_SERROR_VT8237;
|
||||
|
||||
return VIA_REG_SERROR;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
ViaScrReadPci(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ PULONG Result)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
ULONG Value, Offset = 2 * ChanData->Channel + PortNumber;
|
||||
UCHAR Reg;
|
||||
|
||||
switch (Register)
|
||||
{
|
||||
case ATA_SSTATUS:
|
||||
{
|
||||
Reg = PciRead8(Controller, VIA_REG_SSTATUS + Offset);
|
||||
|
||||
Value = Reg & 0x03;
|
||||
|
||||
if (Reg & 0x04)
|
||||
Value |= AHCI_PXSSTS_IPM_PARTIAL;
|
||||
else if (Reg & 0x08)
|
||||
Value |= AHCI_PXSSTS_IPM_SLUMBER;
|
||||
else
|
||||
Value |= AHCI_PXSSTS_IPM_ACTIVE;
|
||||
|
||||
if (Reg & 0x10)
|
||||
Value |= AHCI_PXSSTS_SPD_SATA2;
|
||||
else
|
||||
Value |= AHCI_PXSSTS_SPD_SATA1;
|
||||
break;
|
||||
}
|
||||
case ATA_SERROR:
|
||||
{
|
||||
Value = PciRead32(Controller, ViaGetSerrOffset(Controller) + Offset * 4);
|
||||
break;
|
||||
}
|
||||
case ATA_SCONTROL:
|
||||
{
|
||||
Value = 0;
|
||||
Reg = PciRead8(Controller, VIA_REG_SCONTROL + Offset);
|
||||
if (Reg & 0x01)
|
||||
Value |= AHCI_PXCTL_DET_RESET;
|
||||
if (Reg & 0x02)
|
||||
Value |= AHCI_PXCTL_DET_DISABLE_SATA;
|
||||
if (Reg & 0x04)
|
||||
Value |= AHCI_PXCTL_IPM_DISABLE_PARTIAL;
|
||||
if (Reg & 0x08)
|
||||
Value |= AHCI_PXCTL_IPM_DISABLE_SLUMBER;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*Result = Value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
ViaScrWritePci(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
PATA_CONTROLLER Controller = ChanData->Controller;
|
||||
ULONG Offset = 2 * ChanData->Channel + PortNumber;
|
||||
|
||||
switch (Register)
|
||||
{
|
||||
case ATA_SERROR:
|
||||
{
|
||||
PciWrite32(Controller, ViaGetSerrOffset(Controller) + Offset * 4, Value);
|
||||
break;
|
||||
}
|
||||
case ATA_SCONTROL:
|
||||
{
|
||||
UCHAR Val = 0;
|
||||
if (Value & AHCI_PXCTL_DET_RESET)
|
||||
Val |= 0x01;
|
||||
if (Value & AHCI_PXCTL_DET_DISABLE_SATA)
|
||||
Val |= 0x02;
|
||||
if (Value & AHCI_PXCTL_IPM_DISABLE_PARTIAL)
|
||||
Val |= 0x04;
|
||||
if (Value & AHCI_PXCTL_IPM_DISABLE_SLUMBER)
|
||||
Val |= 0x08;
|
||||
|
||||
PciWrite8(Controller, VIA_REG_SCONTROL + Offset, Val);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
ViaScrReadIoPort(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ PULONG Result)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PortNumber);
|
||||
|
||||
if (Register > ATA_SCONTROL)
|
||||
return FALSE;
|
||||
|
||||
*Result = READ_PORT_ULONG((PULONG)(ChanData->Regs.Scr + (Register * 4)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
ViaScrWriteIoPort(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(PortNumber);
|
||||
|
||||
if (Register > ATA_SCONTROL)
|
||||
return FALSE;
|
||||
|
||||
WRITE_PORT_ULONG((PULONG)(ChanData->Regs.Scr + (Register * 4)), Value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
Via6421ParseResources(
|
||||
_Inout_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ ULONG PortIndex)
|
||||
{
|
||||
PUCHAR CommandPortBase, ControlPortBase, DmaBase, ScrBase;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* [BAR 0]: I/O ports at E150 [size=16] Channel 0
|
||||
* [BAR 1]: I/O ports at E140 [size=16] Channel 1
|
||||
* [BAR 2]: I/O ports at E130 [size=16] Channel 2
|
||||
* [BAR 3]: I/O ports at E120 [size=16]
|
||||
* [BAR 4]: I/O ports at E100 [size=32] BM DMA
|
||||
* [BAR 5]: I/O ports at E000 [size=256] SATA PHY (minimum size = 128)
|
||||
*/
|
||||
|
||||
CommandPortBase = AtaCtrlPciMapBar(ChanData->Controller, PortIndex, 16);
|
||||
if (!CommandPortBase)
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
|
||||
DmaBase = AtaCtrlPciMapBar(ChanData->Controller, 4, 32);
|
||||
if (!DmaBase)
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
|
||||
ScrBase = AtaCtrlPciMapBar(ChanData->Controller, 5, 128);
|
||||
if (!ScrBase)
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
|
||||
ChanData->Regs.Dma = DmaBase + (PortIndex * 8);
|
||||
ChanData->Regs.Scr = ScrBase + (PortIndex * 64);
|
||||
|
||||
ControlPortBase = CommandPortBase + PCIIDE_COMMAND_IO_RANGE_LENGTH;
|
||||
|
||||
PciIdeInitTaskFileIoResources(ChanData,
|
||||
(ULONG_PTR)CommandPortBase,
|
||||
(ULONG_PTR)ControlPortBase + PCIIDE_CONTROL_IO_BAR_OFFSET,
|
||||
1);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
Via6421GetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Channel 0: SATA port #0 (M only)
|
||||
* Channel 1: SATA port #1 (M only)
|
||||
* Channel 2: PATA channel
|
||||
*/
|
||||
Controller->MaxChannels = 3;
|
||||
Controller->Flags |= CTRL_FLAG_MANUAL_RES;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
if (i == 2)
|
||||
{
|
||||
/* No MWDMA support */
|
||||
ChanData->TransferModeSupported = PIO_ALL | UDMA_ALL;
|
||||
ChanData->SetTransferMode = Via6421SetTransferMode;
|
||||
|
||||
if (!VT6421A_UDMA_CABLE_PRESENT(Controller))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_NO_SLAVE;
|
||||
ChanData->SetTransferMode = ViaSataSetTransferMode;
|
||||
ChanData->TransferModeSupported = SATA_ALL;
|
||||
ChanData->ScrRead = ViaScrReadIoPort;
|
||||
ChanData->ScrWrite = ViaScrWriteIoPort;
|
||||
}
|
||||
|
||||
Status = Via6421ParseResources(ChanData, i);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ViaCx700GetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
Controller->ChannelEnableBits = ViaCx700EnableBits;
|
||||
|
||||
/*
|
||||
* Channel 0: 2 SATA ports (M/S emulation)
|
||||
* Channel 1: PATA channel
|
||||
*/
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
ChanData->SetTransferMode = SataSetTransferMode;
|
||||
ChanData->TransferModeSupported = SATA_ALL;
|
||||
ChanData->ScrRead = ViaScrReadPci;
|
||||
ChanData->ScrWrite = ViaScrWritePci;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChanData->HwFlags |= TYPE_133;
|
||||
ChanData->SetTransferMode = ViaSetTransferMode;
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_ALL;
|
||||
|
||||
if (!VIA_SINGLE_CHAN_UDMA_CABLE_PRESENT(Controller))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
Via6410ControllerStart(
|
||||
_In_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
UCHAR Value;
|
||||
|
||||
/*
|
||||
* Enable the primary and secondary IDE channels.
|
||||
*
|
||||
* The VT6410 can be either a controller soldered onto the motherboard
|
||||
* or added on an external PCI card. These PCI cards usually come
|
||||
* without an option ROM on their own and have these bits set to 0s by default.
|
||||
*/
|
||||
Value = PciRead8(Controller, VIA_REG_ENABLE_CTRL);
|
||||
Value |= 0x03;
|
||||
PciWrite8(Controller, VIA_REG_ENABLE_CTRL, Value);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
ViaQuerySouthBridgeInformation(
|
||||
_In_ PVOID Context,
|
||||
_In_ ULONG BusNumber,
|
||||
_In_ PCI_SLOT_NUMBER PciSlot,
|
||||
_In_ PPCI_COMMON_HEADER PciConfig)
|
||||
{
|
||||
PULONG HwFlags = Context;
|
||||
ULONG i;
|
||||
PCIIDEX_PAGED_DATA
|
||||
static const struct
|
||||
{
|
||||
USHORT DeviceID;
|
||||
UCHAR MinimumRevisionID;
|
||||
UCHAR Flags;
|
||||
} ViaBridgeList[] =
|
||||
{
|
||||
{ PCI_DEV_BRIDGE_VT82C586, 0x20, TYPE_33 },
|
||||
{ PCI_DEV_BRIDGE_VT82C586, 0, TYPE_MWDMA },
|
||||
{ PCI_DEV_BRIDGE_VT82C596A, 0x10, TYPE_66 | HW_FLAGS_HAS_UDMA_CLOCK },
|
||||
{ PCI_DEV_BRIDGE_VT82C596A, 0, TYPE_33 },
|
||||
{ PCI_DEV_BRIDGE_VT82C686A, 0x40, TYPE_100 },
|
||||
{ PCI_DEV_BRIDGE_VT82C686A, 0, TYPE_66 | HW_FLAGS_HAS_UDMA_CLOCK },
|
||||
{ PCI_DEV_BRIDGE_VT8231, 0, TYPE_100 },
|
||||
{ PCI_DEV_BRIDGE_VT8233, 0, TYPE_100 },
|
||||
{ PCI_DEV_BRIDGE_VT8233A, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8233C, 0, TYPE_100 },
|
||||
{ PCI_DEV_BRIDGE_VT8235, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8237, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8237A, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8237S, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8251, 0, TYPE_133 },
|
||||
{ PCI_DEV_BRIDGE_VT8261, 0, TYPE_133 },
|
||||
};
|
||||
|
||||
UNREFERENCED_PARAMETER(BusNumber);
|
||||
UNREFERENCED_PARAMETER(PciSlot);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (PciConfig->VendorID != PCI_VEN_VIA)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(ViaBridgeList); ++i)
|
||||
{
|
||||
if ((PciConfig->DeviceID == ViaBridgeList[i].DeviceID) &&
|
||||
(PciConfig->RevisionID >= ViaBridgeList[i].MinimumRevisionID))
|
||||
{
|
||||
INFO("Found %04X:%04X.%02X VIA bridge\n",
|
||||
PciConfig->VendorID, PciConfig->DeviceID, PciConfig->RevisionID);
|
||||
|
||||
*HwFlags = ViaBridgeList[i].Flags;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ViaPataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG HwFlags)
|
||||
{
|
||||
ULONG i, UdmaTimReg;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Look for a PCI-ISA bridge to see what features are available.
|
||||
* Early VIA PATA controllers share the same PCI device ID
|
||||
* but have very different capabilities.
|
||||
*/
|
||||
if (HwFlags & HW_FLAGS_CHECK_BRIDGE)
|
||||
{
|
||||
if (!PciFindDevice(ViaQuerySouthBridgeInformation, &HwFlags))
|
||||
{
|
||||
ERR("Unable to find the VIA bridge\n");
|
||||
ASSERT(FALSE);
|
||||
return STATUS_NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_VT6410_IDE_RAID)
|
||||
Controller->Start = Via6410ControllerStart;
|
||||
|
||||
/* The VT6415 has no channel enable bits */
|
||||
if (Controller->Pci.DeviceID != PCI_DEV_VT6415_IDE)
|
||||
Controller->ChannelEnableBits = ViaPataEnableBits;
|
||||
|
||||
if (GET_TYPE(HwFlags) != TYPE_MWDMA)
|
||||
UdmaTimReg = PciRead32(Controller, VIA_REG_UDMA_CTRL);
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->HwFlags = HwFlags;
|
||||
ChanData->SetTransferMode = ViaSetTransferMode;
|
||||
|
||||
switch (GET_TYPE(ChanData->HwFlags))
|
||||
{
|
||||
case TYPE_MWDMA:
|
||||
{
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL;
|
||||
break;
|
||||
}
|
||||
case TYPE_33:
|
||||
{
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 2);
|
||||
break;
|
||||
}
|
||||
case TYPE_66:
|
||||
{
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 4);
|
||||
|
||||
/* Check to see if the BIOS has enabled the 66MHz UDMA clock for us */
|
||||
if (!VIA_UDMA_CLOCK_ENABLED(UdmaTimReg, i))
|
||||
{
|
||||
/* It seems that the clock can also be disabled due to hardware errata */
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable "
|
||||
"or this chip is ATA/33 capable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
|
||||
/* Use timing table based on a 33MHz UDMA clock */
|
||||
ChanData->HwFlags &= ~HW_FLAGS_TYPE_MASK;
|
||||
ChanData->HwFlags |= TYPE_33;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_100:
|
||||
{
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 5);
|
||||
|
||||
if (!VIA_UDMA_CABLE_PRESENT(UdmaTimReg, i))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_133:
|
||||
{
|
||||
ChanData->TransferModeSupported = PIO_ALL | MWDMA_ALL | UDMA_MODES(0, 6);
|
||||
|
||||
if (!VIA_UDMA_CABLE_PRESENT(UdmaTimReg, i))
|
||||
{
|
||||
INFO("CH %lu: BIOS detected 40-conductor cable\n", ChanData->Channel);
|
||||
ChanData->TransferModeSupported &= ~UDMA_80C_ALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(FALSE);
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ViaSataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG HwFlags)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
INFO("Port map: %02X\n", PciRead8(Controller, VIA_REG_SATA_PORT_MAP));
|
||||
|
||||
for (i = 0; i < Controller->MaxChannels; ++i)
|
||||
{
|
||||
PCHANNEL_DATA_PATA ChanData = Controller->Channels[i];
|
||||
|
||||
ChanData->HwFlags = HwFlags;
|
||||
ChanData->TransferModeSupported = SATA_ALL;
|
||||
ChanData->SetTransferMode = SataSetTransferMode;
|
||||
|
||||
if (HwFlags & HW_FLAGS_SINGLE_PORT)
|
||||
ChanData->ChanInfo |= CHANNEL_FLAG_NO_SLAVE;
|
||||
|
||||
if (HwFlags & HW_FLAGS_PCI_SCR)
|
||||
{
|
||||
ChanData->ScrRead = ViaScrReadPci;
|
||||
ChanData->ScrWrite = ViaScrWritePci;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ViaGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG i, HwFlags;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(Controller->Pci.VendorID == PCI_VEN_VIA);
|
||||
|
||||
if (Controller->Pci.DeviceID == PCI_DEV_VT6421A_RAID)
|
||||
{
|
||||
return Via6421GetControllerProperties(Controller);
|
||||
}
|
||||
else if ((Controller->Pci.DeviceID == PCI_DEV_CX700M2_IDE_SATA) ||
|
||||
(Controller->Pci.DeviceID == PCI_DEV_CX700M2_IDE_SATA_RAID))
|
||||
{
|
||||
return ViaCx700GetControllerProperties(Controller);
|
||||
}
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(ViaControllerList); ++i)
|
||||
{
|
||||
HwFlags = ViaControllerList[i].Flags;
|
||||
|
||||
if (Controller->Pci.DeviceID == ViaControllerList[i].DeviceID)
|
||||
break;
|
||||
}
|
||||
if (i == RTL_NUMBER_OF(ViaControllerList))
|
||||
return STATUS_NO_MATCH;
|
||||
|
||||
if (HwFlags & HW_FLAGS_SINGLE_CHAN)
|
||||
Controller->MaxChannels = 1;
|
||||
|
||||
Status = PciIdeCreateChannelData(Controller, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
if (GET_TYPE(HwFlags) == TYPE_SATA)
|
||||
return ViaSataGetControllerProperties(Controller, HwFlags);
|
||||
|
||||
return ViaPataGetControllerProperties(Controller, HwFlags);
|
||||
}
|
||||
95
drivers/storage/ide/pciidex/debug.h
Normal file
95
drivers/storage/ide/pciidex/debug.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Debug support header file
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __RELFILE__
|
||||
#define __RELFILE__ __FILE__
|
||||
#endif
|
||||
|
||||
#if DBG
|
||||
|
||||
// #define DEBUG_TRACE
|
||||
// #define DEBUG_INFO
|
||||
#define DEBUG_WARN
|
||||
#define DEBUG_ERR
|
||||
|
||||
#ifdef DEBUG_TRACE
|
||||
#define TRACE(fmt, ...) \
|
||||
do { \
|
||||
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
|
||||
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define TRACE __noop
|
||||
#else
|
||||
#define TRACE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_INFO
|
||||
#define INFO(fmt, ...) \
|
||||
do { \
|
||||
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
|
||||
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define INFO __noop
|
||||
#else
|
||||
#define INFO(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_WARN
|
||||
#define WARN(fmt, ...) \
|
||||
do { \
|
||||
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
|
||||
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define WARN __noop
|
||||
#else
|
||||
#define WARN(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ERR
|
||||
#define ERR(fmt, ...) \
|
||||
do { \
|
||||
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
|
||||
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#define ERR __noop
|
||||
#else
|
||||
#define ERR(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define TRACE __noop
|
||||
#define INFO __noop
|
||||
#define WARN __noop
|
||||
#define ERR __noop
|
||||
#else
|
||||
#define TRACE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#define INFO(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#define WARN(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#define ERR(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,42 +7,9 @@
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/** @brief Global debugging level. Valid values are between 0 (Error) and 3 (Trace). */
|
||||
ULONG PciIdeDebug = 0;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXStartMiniport(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension)
|
||||
{
|
||||
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (FdoExtension->MiniportStarted)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
DPRINT("Starting miniport\n");
|
||||
|
||||
DriverExtension = IoGetDriverObjectExtension(FdoExtension->DriverObject,
|
||||
FdoExtension->DriverObject);
|
||||
ASSERT(DriverExtension);
|
||||
|
||||
FdoExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
|
||||
FdoExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
|
||||
Status = DriverExtension->HwGetControllerProperties(FdoExtension->MiniControllerExtension,
|
||||
&FdoExtension->Properties);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
FdoExtension->MiniportStarted = TRUE;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
IDE_CHANNEL_STATE
|
||||
PciIdeXChannelState(
|
||||
@@ -95,21 +62,21 @@ PciIdeXGetBusData(
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
||||
PFDO_DEVICE_EXTENSION FdoExt;
|
||||
PATA_CONTROLLER Controller;
|
||||
ULONG BytesRead;
|
||||
|
||||
DPRINT("PciIdeXGetBusData(%p %p 0x%lx 0x%lx)\n",
|
||||
DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
||||
INFO("PciIdeXGetBusData(%p %p 0x%lx 0x%lx)\n",
|
||||
DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
||||
|
||||
FdoExtension = CONTAINING_RECORD(DeviceExtension,
|
||||
FDO_DEVICE_EXTENSION,
|
||||
MiniControllerExtension);
|
||||
FdoExt = CONTAINING_RECORD(DeviceExtension, FDO_DEVICE_EXTENSION, MiniControllerExtension);
|
||||
Controller = &FdoExt->Controller;
|
||||
|
||||
BytesRead = (*FdoExtension->BusInterface.GetBusData)(FdoExtension->BusInterface.Context,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
Buffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
BytesRead = Controller->GetBusData(Controller->BusInterfaceContext,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
Buffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
if (BytesRead != BufferLength)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
@@ -126,24 +93,38 @@ PciIdeXSetBusData(
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
||||
PFDO_DEVICE_EXTENSION FdoExt;
|
||||
PATA_CONTROLLER Controller;
|
||||
UCHAR LocalBuffer[4];
|
||||
ULONG i, BytesWritten;
|
||||
PUCHAR CurrentBuffer;
|
||||
KIRQL OldIrql;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("PciIdeXSetBusData(%p %p %p 0x%lx 0x%lx)\n",
|
||||
DeviceExtension, Buffer, DataMask, ConfigDataOffset, BufferLength);
|
||||
INFO("PciIdeXSetBusData(%p %p %p 0x%lx 0x%lx)\n",
|
||||
DeviceExtension, Buffer, DataMask, ConfigDataOffset, BufferLength);
|
||||
|
||||
CurrentBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferLength, TAG_PCIIDEX);
|
||||
if (!CurrentBuffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
/* Optimize the common case (4-byte PCI access) */
|
||||
if (BufferLength <= sizeof(LocalBuffer))
|
||||
{
|
||||
CurrentBuffer = LocalBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentBuffer = ExAllocatePoolUninitialized(NonPagedPool, BufferLength, TAG_PCIIDEX);
|
||||
if (!CurrentBuffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
FdoExtension = CONTAINING_RECORD(DeviceExtension,
|
||||
FDO_DEVICE_EXTENSION,
|
||||
MiniControllerExtension);
|
||||
FdoExt = CONTAINING_RECORD(DeviceExtension, FDO_DEVICE_EXTENSION, MiniControllerExtension);
|
||||
Controller = &FdoExt->Controller;
|
||||
|
||||
KeAcquireSpinLock(&FdoExtension->BusDataLock, &OldIrql);
|
||||
/*
|
||||
* This spinlock protects the PCI configuration space against concurrent modifications.
|
||||
* For example, the PIIX register SIDETIM (0x44) is a byte-sized register
|
||||
* and controls both of the IDE channels.
|
||||
*/
|
||||
KeAcquireSpinLock(&Controller->Lock, &OldIrql);
|
||||
|
||||
Status = PciIdeXGetBusData(DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
||||
if (!NT_SUCCESS(Status))
|
||||
@@ -155,19 +136,40 @@ PciIdeXSetBusData(
|
||||
(((PUCHAR)DataMask)[i] & ((PUCHAR)Buffer)[i]);
|
||||
}
|
||||
|
||||
BytesWritten = (*FdoExtension->BusInterface.SetBusData)(FdoExtension->BusInterface.Context,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
CurrentBuffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
BytesWritten = Controller->SetBusData(Controller->BusInterfaceContext,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
CurrentBuffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
if (BytesWritten != BufferLength)
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
else
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
Cleanup:
|
||||
KeReleaseSpinLock(&FdoExtension->BusDataLock, OldIrql);
|
||||
KeReleaseSpinLock(&Controller->Lock, OldIrql);
|
||||
|
||||
ExFreePoolWithTag(CurrentBuffer, TAG_PCIIDEX);
|
||||
if (CurrentBuffer != LocalBuffer)
|
||||
ExFreePoolWithTag(CurrentBuffer, TAG_PCIIDEX);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PciIdexGetBusLocation(
|
||||
_In_ PVOID DeviceExtension,
|
||||
_Out_ PULONG BusLocation)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION FdoExt;
|
||||
ULONG Length;
|
||||
NTSTATUS Status;
|
||||
|
||||
FdoExt = CONTAINING_RECORD(DeviceExtension, FDO_DEVICE_EXTENSION, MiniControllerExtension);
|
||||
|
||||
Status = IoGetDeviceProperty(FdoExt->Pdo,
|
||||
DevicePropertyAddress,
|
||||
sizeof(*BusLocation),
|
||||
BusLocation,
|
||||
&Length);
|
||||
return Status;
|
||||
}
|
||||
|
||||
323
drivers/storage/ide/pciidex/pata.h
Normal file
323
drivers/storage/ide/pciidex/pata.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* PROJECT: ReactOS ATA Bus Driver
|
||||
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: PATA definitions
|
||||
* COPYRIGHT: Copyright 2026 <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PCI_VEN_ATI 0x1002
|
||||
#define PCI_VEN_AMD 0x1022
|
||||
#define PCI_VEN_NVIDIA 0x10DE
|
||||
#define PCI_VEN_PC_TECH 0x1042
|
||||
#define PCI_VEN_CMD 0x1095
|
||||
#define PCI_VEN_VIA 0x1106
|
||||
#define PCI_VEN_SERVERWORKS 0x1166
|
||||
#define PCI_VEN_TOSHIBA 0x1179
|
||||
#define PCI_VEN_CAVIUM 0x177D
|
||||
#define PCI_VEN_INTEL 0x8086
|
||||
|
||||
/** Master/Slave devices */
|
||||
#define CHANNEL_PCAT_MAX_DEVICES 2
|
||||
|
||||
/** Master/Slave devices for Bank 0 and Bank 1 */
|
||||
#define CHANNEL_PC98_MAX_DEVICES 4
|
||||
|
||||
/** PC-98 ATA bank register */
|
||||
#define PC98_ATA_BANK 0x432
|
||||
#define PC98_ATA_BANK_32BIT_PORT 0x08
|
||||
|
||||
/** Delay of 400ns */
|
||||
#define ATA_IO_WAIT() KeStallExecutionProcessor(1)
|
||||
|
||||
#define NUM_TO_BITMAP(num) (0xFFFFFFFF >> (RTL_BITS_OF(ULONG) - (num)))
|
||||
|
||||
/** Supported transfer modes by SATA devices */
|
||||
#define SATA_ALL \
|
||||
(PIO_ALL | MWDMA_ALL | UDMA_ALL)
|
||||
|
||||
/** UDMA modes that require the presence of an 80-conductor ATA cable */
|
||||
#define UDMA_80C_ALL \
|
||||
(UDMA_MODE3 | UDMA_MODE4 | UDMA_MODE5 | UDMA_MODE6)
|
||||
|
||||
/** Used to specify a range of MWDMA modes */
|
||||
#define MWDMA_MODES(MinMode, MaxMode) \
|
||||
(NUM_TO_BITMAP(MWDMA_MODE((MaxMode) + 1)) & ~NUM_TO_BITMAP(MWDMA_MODE(MinMode)))
|
||||
|
||||
/** Used to specify a range of UDMA modes */
|
||||
#define UDMA_MODES(MinMode, MaxMode) \
|
||||
(NUM_TO_BITMAP(UDMA_MODE((MaxMode) + 1)) & ~NUM_TO_BITMAP(UDMA_MODE(MinMode)))
|
||||
|
||||
#define IDE_DC_ALWAYS 0x08
|
||||
#define IDE_DRIVE_SELECT 0xA0
|
||||
|
||||
#define IDE_HIGH_ORDER_BYTE 0x80
|
||||
|
||||
#define IDE_FEATURE_PIO 0x00
|
||||
#define IDE_FEATURE_DMA 0x01
|
||||
#define IDE_FEATURE_DMADIR 0x04
|
||||
|
||||
/**
|
||||
* If a larger transfer is attempted, the 16-bit ByteCount register might overflow.
|
||||
* In this case we round down the length to the closest multiple of 2.
|
||||
*/
|
||||
#define ATAPI_MAX_DRQ_DATA_BLOCK 0xFFFE
|
||||
|
||||
/**
|
||||
* Legacy ranges and interrupts
|
||||
*/
|
||||
/*@{*/
|
||||
#define PCIIDE_LEGACY_RESOURCE_COUNT 3
|
||||
#define PCIIDE_LEGACY_COMMAND_IO_RANGE_LENGTH 8
|
||||
#define PCIIDE_LEGACY_CONTROL_IO_RANGE_LENGTH 1
|
||||
#define PCIIDE_LEGACY_PRIMARY_COMMAND_BASE 0x1F0
|
||||
#define PCIIDE_LEGACY_PRIMARY_CONTROL_BASE 0x3F6
|
||||
#define PCIIDE_LEGACY_PRIMARY_IRQ 14
|
||||
#define PCIIDE_LEGACY_SECONDARY_COMMAND_BASE 0x170
|
||||
#define PCIIDE_LEGACY_SECONDARY_CONTROL_BASE 0x376
|
||||
#define PCIIDE_LEGACY_SECONDARY_IRQ 15
|
||||
/*@}*/
|
||||
|
||||
#define PCIIDE_COMMAND_IO_RANGE_LENGTH 8
|
||||
#define PCIIDE_CONTROL_IO_RANGE_LENGTH 4
|
||||
#define PCIIDE_CONTROL_IO_BAR_OFFSET 2
|
||||
#define PCIIDE_DMA_IO_BAR 4
|
||||
#define PCIIDE_DMA_IO_RANGE_LENGTH 16
|
||||
|
||||
/** Offset from base address */
|
||||
#define PCIIDE_DMA_SECONDARY_CHANNEL_OFFSET 8
|
||||
|
||||
/**
|
||||
* Programming Interface Register
|
||||
*/
|
||||
/*@{*/
|
||||
#define PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE 0x01
|
||||
#define PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE_CAPABLE 0x02
|
||||
#define PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE 0x04
|
||||
#define PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE_CAPABLE 0x08
|
||||
#define PCIIDE_PROGIF_DMA_CAPABLE 0x80
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* IDE Bus Master I/O Registers
|
||||
*/
|
||||
/*@{*/
|
||||
#define PCIIDE_DMA_COMMAND 0
|
||||
#define PCIIDE_DMA_STATUS 2
|
||||
#define PCIIDE_DMA_PRDT_PHYSICAL_ADDRESS 4
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* IDE Bus Master Command Register
|
||||
*/
|
||||
/*@{*/
|
||||
#define PCIIDE_DMA_COMMAND_STOP 0x00
|
||||
#define PCIIDE_DMA_COMMAND_START 0x01
|
||||
#define PCIIDE_DMA_COMMAND_READ_FROM_SYSTEM_MEMORY 0x00
|
||||
#define PCIIDE_DMA_COMMAND_WRITE_TO_SYSTEM_MEMORY 0x08
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* IDE Bus Master Status Register
|
||||
*/
|
||||
/*@{*/
|
||||
#define PCIIDE_DMA_STATUS_ACTIVE 0x01
|
||||
#define PCIIDE_DMA_STATUS_ERROR 0x02
|
||||
#define PCIIDE_DMA_STATUS_INTERRUPT 0x04
|
||||
#define PCIIDE_DMA_STATUS_RESERVED1 0x08
|
||||
#define PCIIDE_DMA_STATUS_RESERVED2 0x10
|
||||
#define PCIIDE_DMA_STATUS_DRIVE0_DMA_CAPABLE 0x20
|
||||
#define PCIIDE_DMA_STATUS_DRIVE1_DMA_CAPABLE 0x40
|
||||
#define PCIIDE_DMA_STATUS_SIMPLEX 0x80
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* ATAPI Interrupt Status
|
||||
*/
|
||||
/*@{*/
|
||||
/** Command or Data */
|
||||
#define ATAPI_INT_REASON_COD 0x01
|
||||
|
||||
/** Read direction */
|
||||
#define ATAPI_INT_REASON_IO 0x02
|
||||
|
||||
/** Bus release */
|
||||
#define ATAPI_INT_REASON_RELEASE 0x04
|
||||
|
||||
/** Command Tag for the command */
|
||||
#define ATAPI_INT_REASON_TAG 0xF8
|
||||
|
||||
#define ATAPI_INT_REASON_MASK (ATAPI_INT_REASON_IO | ATAPI_INT_REASON_COD)
|
||||
|
||||
/** Status - Register contains Completion Status (NEC CDR-260) */
|
||||
#define ATAPI_INT_REASON_STATUS_NEC 0x00
|
||||
|
||||
/** Status - Register contains Completion Status */
|
||||
#define ATAPI_INT_REASON_STATUS (ATAPI_INT_REASON_IO | ATAPI_INT_REASON_COD)
|
||||
|
||||
/** Data From Host - Receive command parameter data from the host */
|
||||
#define ATAPI_INT_REASON_DATA_OUT IDE_STATUS_DRQ
|
||||
|
||||
/** CDB - Ready for Command Packet */
|
||||
#define ATAPI_INT_REASON_AWAIT_CDB (IDE_STATUS_DRQ | ATAPI_INT_REASON_COD)
|
||||
|
||||
/** Data To Host - Send command parameter data to the host */
|
||||
#define ATAPI_INT_REASON_DATA_IN (ATAPI_INT_REASON_IO | IDE_STATUS_DRQ)
|
||||
/*@}*/
|
||||
|
||||
#define ATA_TIME_BUSY_SELECT 3000 ///< 30 ms
|
||||
#define ATA_TIME_BUSY_NORMAL 50000 ///< 500 ms
|
||||
#define ATA_TIME_BUSY_POLL 5 ///< 50 us
|
||||
#define ATA_TIME_DRQ_CLEAR 1000 ///< 10 ms
|
||||
#define ATA_TIME_PHASE_CHANGE 100 ///< 1 ms
|
||||
|
||||
/* We keep the value as small as possible, since large timeout can break our error handling */
|
||||
#define ATA_TIME_DRQ_ASSERT 15 ///< 150 us
|
||||
|
||||
#define ATA_TIME_RESET_SELECT (2000 / PORT_TIMER_TICK_MS) ///< 2 s
|
||||
#define ATA_TIME_BUSY_RESET (10000 / PORT_TIMER_TICK_MS) ///< 10 s
|
||||
|
||||
#define CMD_FLAG_NONE 0x00000000
|
||||
#define CMD_FLAG_TRANSFER_MASK 0x00000003
|
||||
#define CMD_FLAG_AWAIT_CDB 0x00000004
|
||||
#define CMD_FLAG_DATA_IN 0x00000040
|
||||
#define CMD_FLAG_DATA_OUT 0x00000080
|
||||
#define CMD_FLAG_AWAIT_INTERRUPT 0x80000000
|
||||
|
||||
#define CMD_FLAG_ATAPI_PIO_TRANSFER 0x00000001
|
||||
#define CMD_FLAG_ATA_PIO_TRANSFER 0x00000002
|
||||
#define CMD_FLAG_DMA_TRANSFER 0x00000003
|
||||
|
||||
/** The IDE interface has one slot per channel */
|
||||
#define PATA_CHANNEL_SLOT 0
|
||||
#define PATA_CHANNEL_QUEUE_DEPTH 1
|
||||
|
||||
C_ASSERT(CMD_FLAG_DMA_TRANSFER == (CMD_FLAG_ATAPI_PIO_TRANSFER | CMD_FLAG_ATA_PIO_TRANSFER));
|
||||
C_ASSERT(CMD_FLAG_DATA_IN == REQUEST_FLAG_DATA_IN);
|
||||
C_ASSERT(CMD_FLAG_DATA_OUT == REQUEST_FLAG_DATA_OUT);
|
||||
C_ASSERT(CMD_FLAG_AWAIT_INTERRUPT == REQUEST_FLAG_POLL);
|
||||
|
||||
#include <pshpack1.h>
|
||||
/**
|
||||
* Physical Region Descriptor Table Entry
|
||||
*/
|
||||
typedef struct _PCIIDE_PRD_TABLE_ENTRY
|
||||
{
|
||||
ULONG Address;
|
||||
ULONG Length; //!< 0 means 0x10000 bytes
|
||||
#define PCIIDE_PRD_LENGTH_MASK 0xFFFF
|
||||
#define PCIIDE_PRD_END_OF_TABLE 0x80000000
|
||||
} PCIIDE_PRD_TABLE_ENTRY, *PPCIIDE_PRD_TABLE_ENTRY;
|
||||
#include <poppack.h>
|
||||
|
||||
/** 64 kB boundary */
|
||||
#define PCIIDE_PRD_LIMIT 0x10000
|
||||
|
||||
typedef USHORT ATATIM;
|
||||
|
||||
typedef struct _ATA_TIMING
|
||||
{
|
||||
ATATIM AddressSetup; // t1
|
||||
/* Register transfers (8-bit) */
|
||||
ATATIM CmdActive; // t2
|
||||
ATATIM CmdRecovery; // t2i
|
||||
/* PIO data transfers (16-bit) */
|
||||
ATATIM DataActive; // t2
|
||||
ATATIM DataRecovery; // t2i
|
||||
} ATA_TIMING, *PATA_TIMING;
|
||||
|
||||
#define SHARED_CMD_TIMINGS 0x00000001
|
||||
#define SHARED_DATA_TIMINGS 0x00000002
|
||||
#define SHARED_ADDR_TIMINGS 0x00000004
|
||||
|
||||
FORCEINLINE
|
||||
ATATIM
|
||||
CLAMP_TIMING(
|
||||
_In_ ATATIM Value,
|
||||
_In_ ATATIM Minimum,
|
||||
_In_ ATATIM Maximum)
|
||||
{
|
||||
if (Value < Minimum)
|
||||
return Minimum;
|
||||
if (Value > Maximum)
|
||||
return Maximum;
|
||||
return Value;
|
||||
}
|
||||
|
||||
#define ATA_READ_BLOCK_16(Port, Buffer, Count, Ctx, MmioFlag) \
|
||||
AtaReadBlock16(Port, Buffer, Count, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_WRITE_BLOCK_16(Port, Buffer, Count, Ctx, MmioFlag) \
|
||||
AtaWriteBlock16(Port, Buffer, Count, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_READ_BLOCK_32(Port, Buffer, Count, Ctx, MmioFlag) \
|
||||
AtaReadBlock32(Port, Buffer, Count, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_WRITE_BLOCK_32(Port, Buffer, Count, Ctx, MmioFlag) \
|
||||
AtaWriteBlock32(Port, Buffer, Count, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_READ(Port, Ctx, MmioFlag) \
|
||||
AtaReadPortUchar(Port, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_WRITE(Port, Value, Ctx, MmioFlag) \
|
||||
AtaWritePortUchar(Port, Value, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
#define ATA_WRITE_ULONG(Port, Value, Ctx, MmioFlag) \
|
||||
AtaWritePortUlong(Port, Value, (Ctx)->ChanInfo & CHANNEL_FLAG_##MmioFlag)
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
ATA_SELECT_DEVICE(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ UCHAR DeviceNumber,
|
||||
_In_ UCHAR DeviceSelect)
|
||||
{
|
||||
#if defined(_M_IX86)
|
||||
/* NEC extension to allow 4 drives per channel */
|
||||
if ((ChanData->ChanInfo & CHANNEL_FLAG_CBUS) &&
|
||||
(ChanData->LastAtaBankId != DeviceNumber))
|
||||
{
|
||||
UCHAR AtaBank;
|
||||
|
||||
ChanData->LastAtaBankId = DeviceNumber;
|
||||
|
||||
/* The 0x432 port is used to select the primary (0) or secondary (1) IDE channel */
|
||||
AtaBank = DeviceNumber >> 1;
|
||||
|
||||
if (ChanData->ChanInfo & CHANNEL_FLAG_IO32)
|
||||
AtaBank |= PC98_ATA_BANK_32BIT_PORT;
|
||||
|
||||
WRITE_PORT_UCHAR((PUCHAR)PC98_ATA_BANK, AtaBank);
|
||||
}
|
||||
#endif
|
||||
|
||||
ATA_WRITE(ChanData->Regs.Device, DeviceSelect, ChanData, MRES_TF);
|
||||
ATA_IO_WAIT();
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
UCHAR
|
||||
ATA_WAIT(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_range_(>, 0) ULONG Timeout,
|
||||
_In_ UCHAR Mask,
|
||||
_In_ UCHAR Value)
|
||||
{
|
||||
UCHAR IdeStatus;
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < Timeout; ++i)
|
||||
{
|
||||
IdeStatus = ChanData->ReadStatus(ChanData);
|
||||
if ((IdeStatus & Mask) == Value)
|
||||
break;
|
||||
|
||||
if (IdeStatus == 0xFF)
|
||||
break;
|
||||
|
||||
KeStallExecutionProcessor(10);
|
||||
}
|
||||
|
||||
return IdeStatus;
|
||||
}
|
||||
@@ -7,11 +7,110 @@
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
ULONG PciIdeControllerNumber = 0;
|
||||
|
||||
BOOLEAN
|
||||
PciFindDevice(
|
||||
_In_ __callback PATA_PCI_MATCH_FN MatchFunction,
|
||||
_In_ PVOID Context)
|
||||
{
|
||||
ULONG BusNumber, DeviceNumber, FunctionNumber;
|
||||
|
||||
for (BusNumber = 0; BusNumber < 0xFF; ++BusNumber)
|
||||
{
|
||||
for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; ++DeviceNumber)
|
||||
{
|
||||
for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; ++FunctionNumber)
|
||||
{
|
||||
UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_HEADER, RevisionID)];
|
||||
PPCI_COMMON_HEADER PciConfig = (PPCI_COMMON_HEADER)Buffer; // Partial PCI header
|
||||
PCI_SLOT_NUMBER PciSlot;
|
||||
ULONG BytesRead;
|
||||
|
||||
PciSlot.u.AsULONG = 0;
|
||||
PciSlot.u.bits.DeviceNumber = DeviceNumber;
|
||||
PciSlot.u.bits.FunctionNumber = FunctionNumber;
|
||||
|
||||
BytesRead = HalGetBusDataByOffset(PCIConfiguration,
|
||||
BusNumber,
|
||||
PciSlot.u.AsULONG,
|
||||
&Buffer,
|
||||
0,
|
||||
sizeof(Buffer));
|
||||
if (BytesRead != sizeof(Buffer) ||
|
||||
PciConfig->VendorID == PCI_INVALID_VENDORID ||
|
||||
PciConfig->VendorID == 0)
|
||||
{
|
||||
if (FunctionNumber == 0)
|
||||
{
|
||||
/* This slot has no single- or a multi-function device */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Continue scanning the functions */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (MatchFunction(Context, BusNumber, PciSlot, PciConfig))
|
||||
return TRUE;
|
||||
|
||||
if (!PCI_MULTIFUNCTION_DEVICE(PciConfig))
|
||||
{
|
||||
/* The device is a single function device */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
PciRead(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_Out_writes_bytes_all_(BufferLength) PVOID Buffer,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength)
|
||||
{
|
||||
Controller->GetBusData(Controller->BusInterfaceContext,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
Buffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
}
|
||||
|
||||
VOID
|
||||
PciWrite(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_reads_bytes_(BufferLength) PVOID Buffer,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength)
|
||||
{
|
||||
Controller->SetBusData(Controller->BusInterfaceContext,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
Buffer,
|
||||
ConfigDataOffset,
|
||||
BufferLength);
|
||||
}
|
||||
|
||||
VOID
|
||||
AtaSleep(VOID)
|
||||
{
|
||||
KTIMER Timer;
|
||||
LARGE_INTEGER DueTime;
|
||||
|
||||
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
||||
|
||||
DueTime.QuadPart = PORT_TIMER_TICK_MS * -10000LL;
|
||||
|
||||
KeInitializeTimer(&Timer);
|
||||
KeSetTimer(&Timer, DueTime, 0);
|
||||
KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
@@ -28,7 +127,7 @@ PciIdeXDispatchWmi(
|
||||
PFDO_DEVICE_EXTENSION FdoExtension = DeviceObject->DeviceExtension;
|
||||
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
Status = IoCallDriver(FdoExtension->Ldo, Irp);
|
||||
Status = IoCallDriver(FdoExtension->Common.LowerDeviceObject, Irp);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -52,13 +151,156 @@ PciIdeXUnload(
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpRepeatRequest(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp,
|
||||
_In_opt_ PDEVICE_CAPABILITIES DeviceCapabilities)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION FdoExt = CommonExt->FdoExt;
|
||||
PDEVICE_OBJECT TopDeviceObject;
|
||||
PIO_STACK_LOCATION IoStack, SubStack;
|
||||
PIRP SubIrp;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(!IS_FDO(CommonExt));
|
||||
|
||||
TopDeviceObject = IoGetAttachedDeviceReference(FdoExt->Self);
|
||||
|
||||
SubIrp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
|
||||
if (!SubIrp)
|
||||
{
|
||||
ObDereferenceObject(TopDeviceObject);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
SubStack = IoGetNextIrpStackLocation(SubIrp);
|
||||
RtlCopyMemory(SubStack, IoStack, sizeof(*SubStack));
|
||||
|
||||
if (DeviceCapabilities)
|
||||
SubStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
|
||||
|
||||
IoSetCompletionRoutine(SubIrp,
|
||||
PciIdeXPdoCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE);
|
||||
|
||||
SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
Status = IoCallDriver(TopDeviceObject, SubIrp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
}
|
||||
|
||||
ObDereferenceObject(TopDeviceObject);
|
||||
|
||||
Status = SubIrp->IoStatus.Status;
|
||||
IoFreeIrp(SubIrp);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpQueryDeviceUsageNotification(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
NTSTATUS Status;
|
||||
volatile LONG* Counter;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!IS_FDO(CommonExt))
|
||||
{
|
||||
Status = PciIdeXPnpRepeatRequest(CommonExt, Irp, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!NT_VERIFY(IoForwardIrpSynchronously(CommonExt->LowerDeviceObject, Irp)))
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
switch (IoStack->Parameters.UsageNotification.Type)
|
||||
{
|
||||
case DeviceUsageTypePaging:
|
||||
Counter = &CommonExt->PageFiles;
|
||||
break;
|
||||
|
||||
case DeviceUsageTypeHibernation:
|
||||
Counter = &CommonExt->HibernateFiles;
|
||||
break;
|
||||
|
||||
case DeviceUsageTypeDumpFile:
|
||||
Counter = &CommonExt->DumpFiles;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Status;
|
||||
}
|
||||
|
||||
IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
|
||||
|
||||
if (!IS_FDO(CommonExt))
|
||||
IoInvalidateDeviceState(CommonExt->Self);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpQueryPnpDeviceState(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (CommonExt->PageFiles || CommonExt->HibernateFiles || CommonExt->DumpFiles)
|
||||
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
||||
|
||||
if (IS_FDO(CommonExt))
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PciIdeXPdoCompletionRoutine(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIRP Irp,
|
||||
_In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
if (Irp->PendingReturned)
|
||||
KeSetEvent(Context, IO_NO_INCREMENT, FALSE);
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXQueryInterface(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
||||
PciIdeXPnpQueryInterface(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ const GUID* Guid,
|
||||
_Out_ PVOID Interface,
|
||||
_In_ ULONG Version,
|
||||
_In_ ULONG Size)
|
||||
{
|
||||
KEVENT Event;
|
||||
@@ -72,7 +314,7 @@ PciIdeXQueryInterface(
|
||||
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
||||
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
||||
FdoExtension->Ldo,
|
||||
CommonExt->LowerDeviceObject,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
@@ -87,12 +329,12 @@ PciIdeXQueryInterface(
|
||||
Stack = IoGetNextIrpStackLocation(Irp);
|
||||
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||||
Stack->Parameters.QueryInterface.InterfaceType = Guid;
|
||||
Stack->Parameters.QueryInterface.Version = 1;
|
||||
Stack->Parameters.QueryInterface.Version = Version;
|
||||
Stack->Parameters.QueryInterface.Size = Size;
|
||||
Stack->Parameters.QueryInterface.Interface = Interface;
|
||||
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||||
|
||||
Status = IoCallDriver(FdoExtension->Ldo, Irp);
|
||||
Status = IoCallDriver(CommonExt->LowerDeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
@@ -105,86 +347,40 @@ PciIdeXQueryInterface(
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXGetConfigurationInfo(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension)
|
||||
{
|
||||
UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_HEADER, BaseClass)];
|
||||
PPCI_COMMON_HEADER PciConfig = (PPCI_COMMON_HEADER)Buffer;
|
||||
ULONG BytesRead;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
BytesRead = (*FdoExtension->BusInterface.GetBusData)(FdoExtension->BusInterface.Context,
|
||||
PCI_WHICHSPACE_CONFIG,
|
||||
Buffer,
|
||||
0,
|
||||
sizeof(Buffer));
|
||||
if (BytesRead != sizeof(Buffer))
|
||||
return STATUS_IO_DEVICE_ERROR;
|
||||
|
||||
FdoExtension->VendorId = PciConfig->VendorID;
|
||||
FdoExtension->DeviceId = PciConfig->DeviceID;
|
||||
|
||||
if (PciConfig->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR)
|
||||
{
|
||||
if (PciConfig->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)
|
||||
{
|
||||
/* Both IDE channels in native mode */
|
||||
FdoExtension->InNativeMode =
|
||||
(PciConfig->ProgIf & PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE) &&
|
||||
(PciConfig->ProgIf & PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE);
|
||||
}
|
||||
else if (PciConfig->SubClass == PCI_SUBCLASS_MSC_RAID_CTLR)
|
||||
{
|
||||
FdoExtension->InNativeMode = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Controller %04x:%04x, Interface byte 0x%02x, Native mode %d\n",
|
||||
FdoExtension->VendorId,
|
||||
FdoExtension->DeviceId,
|
||||
PciConfig->ProgIf,
|
||||
FdoExtension->InNativeMode);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PciIdeXAddDevice(
|
||||
PciIdeXAddDeviceEx(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
|
||||
_In_ PDEVICE_OBJECT PhysicalDeviceObject,
|
||||
_Out_ PVOID *ControllerContext)
|
||||
{
|
||||
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
||||
ULONG DeviceExtensionSize;
|
||||
PDEVICE_OBJECT Fdo;
|
||||
UNICODE_STRING DeviceName;
|
||||
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde999")];
|
||||
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde99999")];
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
Status = RtlStringCbPrintfW(DeviceNameBuffer,
|
||||
sizeof(DeviceNameBuffer),
|
||||
L"\\Device\\Ide\\PciIde%u",
|
||||
L"\\Device\\Ide\\PciIde%lu",
|
||||
PciIdeControllerNumber);
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
||||
|
||||
DPRINT("%s(%p, %p) '%wZ'\n", __FUNCTION__, DriverObject, PhysicalDeviceObject, &DeviceName);
|
||||
INFO("%s(%p, %p, %p) '%wZ'\n",
|
||||
__FUNCTION__, DriverObject, PhysicalDeviceObject, ControllerContext, &DeviceName);
|
||||
|
||||
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
|
||||
ASSERT(DriverExtension);
|
||||
|
||||
Status = RtlULongAdd(DriverExtension->MiniControllerExtensionSize,
|
||||
sizeof(FDO_DEVICE_EXTENSION),
|
||||
sizeof(*FdoExtension),
|
||||
&DeviceExtensionSize);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Invalid miniport extension size %lx\n",
|
||||
DriverExtension->MiniControllerExtensionSize);
|
||||
ERR("Invalid miniport extension size %lx\n", DriverExtension->MiniControllerExtensionSize);
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -197,61 +393,90 @@ PciIdeXAddDevice(
|
||||
&Fdo);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create FDO 0x%lx\n", Status);
|
||||
ERR("Failed to create FDO 0x%lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
FdoExtension = Fdo->DeviceExtension;
|
||||
|
||||
RtlZeroMemory(FdoExtension, sizeof(FDO_DEVICE_EXTENSION));
|
||||
FdoExtension->Common.IsFDO = TRUE;
|
||||
RtlZeroMemory(FdoExtension, sizeof(*FdoExtension));
|
||||
FdoExtension->Common.Flags = DO_IS_FDO;
|
||||
FdoExtension->Common.Self = Fdo;
|
||||
IoInitializeRemoveLock(&FdoExtension->Common.RemoveLock, TAG_PCIIDEX, 0, 0);
|
||||
|
||||
FdoExtension->DriverObject = DriverObject;
|
||||
FdoExtension->Pdo = PhysicalDeviceObject;
|
||||
FdoExtension->ControllerNumber = PciIdeControllerNumber++;
|
||||
|
||||
KeInitializeSpinLock(&FdoExtension->BusDataLock);
|
||||
ExInitializeFastMutex(&FdoExtension->DeviceSyncMutex);
|
||||
ExInitializeFastMutex(&FdoExtension->PdoListSyncMutex);
|
||||
InitializeListHead(&FdoExtension->PdoListHead);
|
||||
|
||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo, PhysicalDeviceObject, &FdoExtension->Ldo);
|
||||
KeInitializeSpinLock(&FdoExtension->Controller.Lock);
|
||||
|
||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo,
|
||||
PhysicalDeviceObject,
|
||||
&FdoExtension->Common.LowerDeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Failed to attach FDO 0x%lx\n", Status);
|
||||
ERR("Failed to attach FDO 0x%lx\n", Status);
|
||||
goto Failure;
|
||||
}
|
||||
|
||||
/* DMA buffers alignment */
|
||||
Fdo->AlignmentRequirement = max(FdoExtension->Ldo->AlignmentRequirement, FILE_WORD_ALIGNMENT);
|
||||
Fdo->AlignmentRequirement = FdoExtension->Common.LowerDeviceObject->AlignmentRequirement;
|
||||
Fdo->AlignmentRequirement = max(Fdo->AlignmentRequirement, ATA_MIN_BUFFER_ALIGNMENT);
|
||||
|
||||
Status = PciIdeXQueryInterface(FdoExtension,
|
||||
&GUID_BUS_INTERFACE_STANDARD,
|
||||
&FdoExtension->BusInterface,
|
||||
sizeof(BUS_INTERFACE_STANDARD));
|
||||
if (!NT_SUCCESS(Status))
|
||||
#if defined(ATA_DETECT_LEGACY_DEVICES)
|
||||
if (ControllerContext)
|
||||
{
|
||||
DPRINT1("No bus interface 0x%lx\n", Status);
|
||||
goto Failure;
|
||||
FdoExtension->Controller.Flags |= CTRL_FLAG_NON_PNP;
|
||||
*ControllerContext = FdoExtension;
|
||||
}
|
||||
|
||||
Status = PciIdeXGetConfigurationInfo(FdoExtension);
|
||||
if (!NT_SUCCESS(Status))
|
||||
else
|
||||
#endif
|
||||
{
|
||||
DPRINT1("Unable to retrieve the configuration info %lx\n", Status);
|
||||
goto Failure;
|
||||
BUS_INTERFACE_STANDARD BusInterface;
|
||||
|
||||
Status = PciIdeXPnpQueryInterface(&FdoExtension->Common,
|
||||
&GUID_BUS_INTERFACE_STANDARD,
|
||||
&BusInterface,
|
||||
PCI_BUS_INTERFACE_STANDARD_VERSION,
|
||||
sizeof(BusInterface));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ERR("No PCI bus interface 0x%lx\n", Status);
|
||||
goto Failure;
|
||||
}
|
||||
|
||||
FdoExtension->Controller.BusInterfaceContext = BusInterface.Context;
|
||||
FdoExtension->Controller.SetBusData = BusInterface.SetBusData;
|
||||
FdoExtension->Controller.GetBusData = BusInterface.GetBusData;
|
||||
}
|
||||
|
||||
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
Failure:
|
||||
if (FdoExtension->Ldo)
|
||||
IoDetachDevice(FdoExtension->Ldo);
|
||||
if (FdoExtension->Common.LowerDeviceObject)
|
||||
IoDetachDevice(FdoExtension->Common.LowerDeviceObject);
|
||||
|
||||
IoDeleteDevice(Fdo);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PciIdeXAddDevice(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
return PciIdeXAddDeviceEx(DriverObject, PhysicalDeviceObject, NULL);
|
||||
}
|
||||
|
||||
static
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
@@ -297,17 +522,35 @@ PciIdeXInitialize(
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT("PciIdeXInitialize(%p '%wZ' %p 0x%lx)\n",
|
||||
DriverObject, RegistryPath, HwGetControllerProperties, ExtensionSize);
|
||||
INFO("PciIdeXInitialize(%p '%wZ' %p 0x%lx)\n",
|
||||
DriverObject, RegistryPath, HwGetControllerProperties, ExtensionSize);
|
||||
|
||||
/* ReactOS-specific: Check for our legacy detection magic */
|
||||
if (ExtensionSize == PCIIDEX_GET_CONTROLLER_INTERFACE_SIGNATURE)
|
||||
{
|
||||
#if defined(ATA_DETECT_LEGACY_DEVICES)
|
||||
PPCIIDEX_LEGACY_CONTROLLER_INTERFACE ControllerInferface;
|
||||
|
||||
ControllerInferface = (PVOID)HwGetControllerProperties;
|
||||
ControllerInferface->Version = PCIIDEX_INTERFACE_VERSION;
|
||||
ControllerInferface->AddDevice = PciIdeXAddDeviceEx;
|
||||
ControllerInferface->StartDevice = PciIdeXFdoStartDevice;
|
||||
ControllerInferface->RemoveDevice = PciIdeXFdoRemoveDevice;
|
||||
|
||||
ExtensionSize = 0;
|
||||
#else
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status = IoAllocateDriverObjectExtension(DriverObject,
|
||||
DriverObject,
|
||||
sizeof(PCIIDEX_DRIVER_EXTENSION),
|
||||
sizeof(*DriverExtension),
|
||||
(PVOID*)&DriverExtension);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
RtlZeroMemory(DriverExtension, sizeof(PCIIDEX_DRIVER_EXTENSION));
|
||||
RtlZeroMemory(DriverExtension, sizeof(*DriverExtension));
|
||||
DriverExtension->MiniControllerExtensionSize = ExtensionSize;
|
||||
DriverExtension->HwGetControllerProperties = HwGetControllerProperties;
|
||||
|
||||
|
||||
@@ -6,47 +6,346 @@
|
||||
* Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _PCIIDEX_PCH_
|
||||
#define _PCIIDEX_PCH_
|
||||
#pragma once
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <ntstrsafe.h>
|
||||
#include <ntintsafe.h>
|
||||
#include <initguid.h>
|
||||
#include <wdmguid.h>
|
||||
|
||||
#include <ata.h>
|
||||
#include <ide.h>
|
||||
|
||||
#include <scsi.h>
|
||||
#include <reactos/drivers/ata/ata_shared.h>
|
||||
#include <reactos/drivers/ata/ata_user.h>
|
||||
#include "debug.h"
|
||||
#include "ahci.h"
|
||||
|
||||
#include <debug/driverdbg.h>
|
||||
|
||||
typedef struct _CHANNEL_DATA_PATA CHANNEL_DATA_PATA, *PCHANNEL_DATA_PATA;
|
||||
typedef struct _CHANNEL_DATA_COMMON CHANNEL_DATA_COMMON, *PCHANNEL_DATA_COMMON;
|
||||
typedef struct _PCIIDE_PRD_TABLE_ENTRY PCIIDE_PRD_TABLE_ENTRY, *PPCIIDE_PRD_TABLE_ENTRY;
|
||||
|
||||
#define TAG_PCIIDEX 'XedI'
|
||||
|
||||
#define IS_FDO(p) (((PCOMMON_DEVICE_EXTENSION)(p))->IsFDO)
|
||||
#define ASSUME(cond) \
|
||||
do { \
|
||||
ASSERT(cond); \
|
||||
__assume(cond); \
|
||||
} while (0)
|
||||
|
||||
#define IS_FDO(p) \
|
||||
((((PCOMMON_DEVICE_EXTENSION)(p))->Flags & DO_IS_FDO) != 0)
|
||||
|
||||
#define IS_PRIMARY_CHANNEL(PdoExtension) (PdoExtension->Channel == 0)
|
||||
|
||||
/*
|
||||
* Legacy ranges and interrupts
|
||||
*/
|
||||
#define PCIIDE_LEGACY_RESOURCE_COUNT 3
|
||||
#define PCIIDE_LEGACY_COMMAND_IO_RANGE_LENGTH 8
|
||||
#define PCIIDE_LEGACY_CONTROL_IO_RANGE_LENGTH 1
|
||||
#define PCIIDE_LEGACY_PRIMARY_COMMAND_BASE 0x1F0
|
||||
#define PCIIDE_LEGACY_PRIMARY_CONTROL_BASE 0x3F6
|
||||
#define PCIIDE_LEGACY_PRIMARY_IRQ 14
|
||||
#define PCIIDE_LEGACY_SECONDARY_COMMAND_BASE 0x170
|
||||
#define PCIIDE_LEGACY_SECONDARY_CONTROL_BASE 0x376
|
||||
#define PCIIDE_LEGACY_SECONDARY_IRQ 15
|
||||
#if defined(_MSC_VER)
|
||||
#pragma section("PAGECONS", read)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Programming Interface Register
|
||||
*/
|
||||
#define PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE 0x01
|
||||
#define PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE_CAPABLE 0x02
|
||||
#define PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE 0x04
|
||||
#define PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE_CAPABLE 0x08
|
||||
#define PCIIDE_PROGIF_DMA_CAPABLE 0x80
|
||||
/** Pageable read-only data */
|
||||
#define PCIIDEX_PAGED_DATA DATA_SEG("PAGECONS")
|
||||
|
||||
#define BM_SECONDARY_CHANNEL_OFFSET 8
|
||||
#define MAX_CHANNELS 32
|
||||
|
||||
#define PORT_TIMER_TICK_MS 10 // Timer interval is 10ms
|
||||
|
||||
#define DEV_NUMBER(Device) ((Device)->TransportFlags & DEVICE_NUMBER_MASK)
|
||||
|
||||
typedef struct _PDO_DEVICE_EXTENSION PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
|
||||
typedef struct _ATA_CONTROLLER ATA_CONTROLLER, *PATA_CONTROLLER;
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
typedef BOOLEAN
|
||||
(ATA_PCI_MATCH_FN)(
|
||||
_In_ PVOID Context,
|
||||
_In_ ULONG BusNumber,
|
||||
_In_ PCI_SLOT_NUMBER PciSlot,
|
||||
_In_ PPCI_COMMON_HEADER PciConfig);
|
||||
typedef ATA_PCI_MATCH_FN *PATA_PCI_MATCH_FN;
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
typedef IDE_CHANNEL_STATE
|
||||
(CONTROLLER_CHANNEL_ENABLED)(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel);
|
||||
typedef CONTROLLER_CHANNEL_ENABLED *PCONTROLLER_CHANNEL_ENABLED;
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CONTROLLER_START)(
|
||||
_In_ PATA_CONTROLLER Controller);
|
||||
typedef CONTROLLER_START *PCONTROLLER_START;
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CONTROLLER_STOP)(
|
||||
_In_ PATA_CONTROLLER Controller);
|
||||
typedef CONTROLLER_STOP *PCONTROLLER_STOP;
|
||||
|
||||
typedef VOID
|
||||
(CONTROLLER_FREE_RESOURCES)(
|
||||
_In_ PATA_CONTROLLER Controller);
|
||||
typedef CONTROLLER_FREE_RESOURCES *PCONTROLLER_FREE_RESOURCES;
|
||||
|
||||
typedef NTSTATUS
|
||||
(CONTROLLER_ATTACH_CHANNEL_EX)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN Attach);
|
||||
typedef CONTROLLER_ATTACH_CHANNEL_EX *PCONTROLLER_ATTACH_CHANNEL_EX;
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CHANNEL_SET_MODE_EX)(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel,
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList);
|
||||
typedef CHANNEL_SET_MODE_EX *PCHANNEL_SET_MODE_EX;
|
||||
|
||||
typedef NTSTATUS
|
||||
(CHANNEL_ALLOCATE_MEMORY)(
|
||||
_In_ PVOID ChannelContext);
|
||||
typedef CHANNEL_ALLOCATE_MEMORY *PCHANNEL_ALLOCATE_MEMORY;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_FREE_MEMORY)(
|
||||
_In_ PVOID ChannelContext);
|
||||
typedef CHANNEL_FREE_MEMORY *PCHANNEL_FREE_MEMORY;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_ENABLE_INTERRUPTS)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN Enable);
|
||||
typedef CHANNEL_ENABLE_INTERRUPTS *PCHANNEL_ENABLE_INTERRUPTS;
|
||||
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_CHECK_INTERRUPT)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData);
|
||||
typedef CHANNEL_CHECK_INTERRUPT *PCHANNEL_CHECK_INTERRUPT;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_LOAD_TASK_FILE)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ PATA_DEVICE_REQUEST Request);
|
||||
typedef CHANNEL_LOAD_TASK_FILE *PCHANNEL_LOAD_TASK_FILE;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_SAVE_TASK_FILE)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_Inout_ PATA_DEVICE_REQUEST Request);
|
||||
typedef CHANNEL_SAVE_TASK_FILE *PCHANNEL_SAVE_TASK_FILE;
|
||||
|
||||
typedef UCHAR
|
||||
(CHANNEL_READ_STATUS)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData);
|
||||
typedef CHANNEL_READ_STATUS *PCHANNEL_READ_STATUS;
|
||||
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_READ_SCR)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ PULONG Result);
|
||||
typedef CHANNEL_READ_SCR *PCHANNEL_READ_SCR;
|
||||
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_WRITE_SCR)(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ SATA_SCR_REGISTER Register,
|
||||
_In_ ULONG PortNumber,
|
||||
_In_ ULONG Value);
|
||||
typedef CHANNEL_WRITE_SCR *PCHANNEL_WRITE_SCR;
|
||||
|
||||
typedef struct _ATA_PCI_ENABLE_BITS
|
||||
{
|
||||
UCHAR Register;
|
||||
UCHAR Mask;
|
||||
UCHAR ValueEnabled;
|
||||
} ATA_PCI_ENABLE_BITS, *PATA_PCI_ENABLE_BITS;
|
||||
|
||||
typedef struct _ATA_CONTROLLER
|
||||
{
|
||||
CM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc;
|
||||
PKINTERRUPT InterruptObject;
|
||||
struct
|
||||
{
|
||||
USHORT VendorID;
|
||||
USHORT DeviceID;
|
||||
USHORT Command;
|
||||
UCHAR RevisionID;
|
||||
UCHAR ProgIf;
|
||||
UCHAR SubClass;
|
||||
UCHAR BaseClass;
|
||||
UCHAR CacheLineSize;
|
||||
USHORT SubVendorID;
|
||||
USHORT SubSystemID;
|
||||
} Pci;
|
||||
|
||||
struct
|
||||
{
|
||||
ULONG Flags;
|
||||
#define RANGE_IS_VALID 0x01
|
||||
#define RANGE_IS_MEMORY 0x02
|
||||
#define RANGE_IS_MAPPED 0x04
|
||||
ULONG Length;
|
||||
PVOID IoBase;
|
||||
} AccessRange[PCI_TYPE0_ADDRESSES];
|
||||
|
||||
PGET_SET_DEVICE_DATA SetBusData;
|
||||
PGET_SET_DEVICE_DATA GetBusData;
|
||||
PVOID BusInterfaceContext;
|
||||
PVOID ChanDataBlock;
|
||||
PCONTROLLER_OBJECT HwSyncObject;
|
||||
PCONTROLLER_START Start;
|
||||
PCONTROLLER_STOP Stop;
|
||||
PCONTROLLER_FREE_RESOURCES FreeResources;
|
||||
PCONTROLLER_ATTACH_CHANNEL_EX AttachChannel;
|
||||
union
|
||||
{
|
||||
const ATA_PCI_ENABLE_BITS* ChannelEnableBits;
|
||||
PCONTROLLER_CHANNEL_ENABLED ChannelEnabledTest;
|
||||
};
|
||||
PVOID HwExt;
|
||||
ULONG AlignmentRequirement;
|
||||
ULONG MaxChannels;
|
||||
ULONG ChannelBitmap;
|
||||
|
||||
PUCHAR IoBase;
|
||||
ULONG AhciVersion;
|
||||
ULONG AhciCapabilities;
|
||||
ULONG AhciCapabilitiesEx;
|
||||
|
||||
ULONG QueueDepth;
|
||||
ULONG Flags;
|
||||
#define CTRL_FLAG_NATIVE_PCI 0x00000001
|
||||
#define CTRL_FLAG_IS_SIMPLEX 0x00000002
|
||||
#define CTRL_FLAG_SATA_HBA_ACPI 0x00000002
|
||||
#define CTRL_FLAG_USE_TEST_FUNCTION 0x00000004
|
||||
#define CTRL_FLAG_IS_AHCI 0x00000008
|
||||
#define CTRL_FLAG_NON_PNP 0x00000010
|
||||
#define CTRL_FLAG_MANUAL_RES 0x00000020
|
||||
#define CTRL_FLAG_DMA_INTERRUPT 0x00000040
|
||||
|
||||
KSPIN_LOCK Lock;
|
||||
PVOID Channels[MAX_CHANNELS];
|
||||
} ATA_CONTROLLER, *PATA_CONTROLLER;
|
||||
|
||||
typedef struct _CHANNEL_DATA_COMMON
|
||||
{
|
||||
PPDO_DEVICE_EXTENSION PdoExt;
|
||||
CM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc;
|
||||
PKINTERRUPT InterruptObject;
|
||||
PCHANNEL_ALLOCATE_MEMORY AllocateMemory;
|
||||
PCHANNEL_FREE_MEMORY FreeMemory;
|
||||
PCHANNEL_SET_MODE_EX SetTransferMode;
|
||||
PCHANNEL_PREPARE_PRD_TABLE PreparePrdTable;
|
||||
PCHANNEL_PREPARE_IO PrepareIo;
|
||||
PCHANNEL_START_IO StartIo;
|
||||
PCHANNEL_ENABLE_INTERRUPTS EnableInterrupts;
|
||||
PATA_CONTROLLER Controller;
|
||||
PDMA_ADAPTER DmaAdapter;
|
||||
ULONG TransferModeSupported;
|
||||
ULONG MaximumTransferLength;
|
||||
ULONG Channel;
|
||||
struct
|
||||
{
|
||||
ULONG TransferModeSupported;
|
||||
ULONG MaximumTransferLength;
|
||||
} Current;
|
||||
ULONG MaximumPhysicalPages;
|
||||
ULONG ChanInfo;
|
||||
#define CHANNEL_FLAG_IO32 0x00000001
|
||||
#define CHANNEL_FLAG_DRIVE0_DMA_CAPABLE 0x00000002
|
||||
#define CHANNEL_FLAG_DRIVE1_DMA_CAPABLE 0x00000004
|
||||
#define CHANNEL_FLAG_CONTROL_PORT_BASE_MAPPED 0x00000008
|
||||
#define CHANNEL_FLAG_COMMAND_PORT_BASE_MAPPED 0x00000010
|
||||
#define CHANNEL_FLAG_DMA_PORT_BASE_MAPPED 0x00000020
|
||||
#define CHANNEL_FLAG_64_BIT_DMA 0x00000040
|
||||
#define CHANNEL_FLAG_PRIMARY_ADDRESS_CLAIMED 0x00000080
|
||||
#define CHANNEL_FLAG_SECONDARY_ADDRESS_CLAIMED 0x00000100
|
||||
#define CHANNEL_FLAG_PIO_VIA_DMA 0x00000200
|
||||
#define CHANNEL_FLAG_NO_SLAVE 0x00000400
|
||||
#define CHANNEL_FLAG_IS_EXTERNAL 0x00000800
|
||||
#define CHANNEL_FLAG_IS_PMP 0x00001000
|
||||
#define CHANNEL_FLAG_HAS_FBS 0x00002000
|
||||
#define CHANNEL_FLAG_FBS_ENABLED 0x00004000
|
||||
#define CHANNEL_FLAG_HAS_ACPI_GTM 0x00008000
|
||||
#define CHANNEL_FLAG_HAS_NCQ 0x00010000
|
||||
#define CHANNEL_FLAG_PIO_FOR_LBA48_XFER 0x00020000 // TODO: Not used yet
|
||||
#define CHANNEL_FLAG_NO_ATAPI_DMA 0x00040000
|
||||
#define CHANNEL_FLAG_DMA_BEFORE_CMD 0x00080000
|
||||
#define CHANNEL_FLAG_MRES_TF 0x00100000 // MRES_TF
|
||||
#define CHANNEL_FLAG_MRES_DMA 0x00200000 // MRES_DMA
|
||||
#define CHANNEL_FLAG_MRES_CTRL 0x00400000 // MRES_CTRL
|
||||
#define CHANNEL_FLAG_CBUS 0x80000000
|
||||
|
||||
PVOID PortContext;
|
||||
PPORT_NOTIFICATION PortNotification;
|
||||
ULONG ActiveSlotsBitmap;
|
||||
ULONG ActiveQueuedSlotsBitmap;
|
||||
PATA_DEVICE_REQUEST* Slots;
|
||||
} CHANNEL_DATA_COMMON, *PCHANNEL_DATA_COMMON;
|
||||
|
||||
typedef struct _CHANNEL_DATA_PATA
|
||||
{
|
||||
/** Common data, must be the first member. */
|
||||
CHANNEL_DATA_COMMON;
|
||||
|
||||
PCHANNEL_LOAD_TASK_FILE LoadTaskFile;
|
||||
PCHANNEL_SAVE_TASK_FILE SaveTaskFile;
|
||||
PCHANNEL_READ_STATUS ReadStatus;
|
||||
PPCIIDE_PRD_TABLE_ENTRY PrdTable;
|
||||
ULONG PrdTablePhysicalAddress;
|
||||
IDE_REGISTERS Regs;
|
||||
PCHANNEL_CHECK_INTERRUPT CheckInterrupt;
|
||||
PUCHAR DataBuffer;
|
||||
ULONG BytesToTransfer;
|
||||
ULONG CommandFlags;
|
||||
ULONG DrqByteCount;
|
||||
#if defined(_M_IX86)
|
||||
UCHAR LastAtaBankId;
|
||||
#endif
|
||||
BOOLEAN IsPollingActive;
|
||||
KDPC PollingTimerDpc;
|
||||
PCHANNEL_READ_SCR ScrRead;
|
||||
PCHANNEL_WRITE_SCR ScrWrite;
|
||||
IDE_ACPI_TIMING_MODE_BLOCK CurrentTimingMode;
|
||||
ULONG HwFlags;
|
||||
PUCHAR HwExt[ANYSIZE_ARRAY];
|
||||
} CHANNEL_DATA_PATA, *PCHANNEL_DATA_PATA;
|
||||
|
||||
typedef struct _CHANNEL_INFO_AHCI
|
||||
{
|
||||
ULONG64 ReceivedFisPhys;
|
||||
ULONG64 CommandListPhys;
|
||||
PVOID ReceivedFisOriginal;
|
||||
PVOID CommandListOriginal;
|
||||
PVOID CommandTableOriginal[AHCI_MAX_COMMAND_SLOTS];
|
||||
ULONG CommandTableSize[AHCI_MAX_COMMAND_SLOTS];
|
||||
ULONG CommandListSize;
|
||||
PHYSICAL_ADDRESS ReceivedFisPhysOriginal;
|
||||
PHYSICAL_ADDRESS CommandListPhysOriginal;
|
||||
PHYSICAL_ADDRESS CommandTablePhysOriginal[AHCI_MAX_COMMAND_SLOTS];
|
||||
PVOID LocalBuffer;
|
||||
} CHANNEL_INFO_AHCI, *PCHANNEL_INFO_AHCI;
|
||||
|
||||
typedef struct _CHANNEL_DATA_AHCI
|
||||
{
|
||||
/** Common data, must be the first member. */
|
||||
CHANNEL_DATA_COMMON;
|
||||
|
||||
PVOID IoBase;
|
||||
PAHCI_RECEIVED_FIS ReceivedFis;
|
||||
PAHCI_COMMAND_LIST CommandList;
|
||||
PAHCI_COMMAND_TABLE CommandTable[AHCI_MAX_COMMAND_SLOTS];
|
||||
UCHAR LastPmpDeviceNumber;
|
||||
UCHAR LastFbsDeviceNumber;
|
||||
ULONG TotalPortCount;
|
||||
CHANNEL_INFO_AHCI Mem;
|
||||
} CHANNEL_DATA_AHCI, *PCHANNEL_DATA_AHCI;
|
||||
|
||||
typedef struct _PCIIDEX_DRIVER_EXTENSION
|
||||
{
|
||||
@@ -56,9 +355,6 @@ typedef struct _PCIIDEX_DRIVER_EXTENSION
|
||||
|
||||
typedef struct _COMMON_DEVICE_EXTENSION
|
||||
{
|
||||
BOOLEAN IsFDO;
|
||||
PDEVICE_OBJECT Self;
|
||||
|
||||
_Write_guarded_by_(_Global_interlock_)
|
||||
volatile LONG PageFiles;
|
||||
|
||||
@@ -67,30 +363,36 @@ typedef struct _COMMON_DEVICE_EXTENSION
|
||||
|
||||
_Write_guarded_by_(_Global_interlock_)
|
||||
volatile LONG DumpFiles;
|
||||
|
||||
union
|
||||
{
|
||||
/** Lower device object. This applies to FDO only. */
|
||||
PDEVICE_OBJECT LowerDeviceObject;
|
||||
|
||||
/** Parent FDO. This applies to PDO only. */
|
||||
PVOID FdoExt;
|
||||
};
|
||||
|
||||
PDEVICE_OBJECT Self;
|
||||
|
||||
ULONG Flags;
|
||||
#define DO_IS_FDO 0x80000000
|
||||
|
||||
IO_REMOVE_LOCK RemoveLock;
|
||||
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
|
||||
|
||||
typedef struct _FDO_DEVICE_EXTENSION
|
||||
{
|
||||
/** Common data, must be the first member. */
|
||||
COMMON_DEVICE_EXTENSION Common;
|
||||
PDEVICE_OBJECT Ldo;
|
||||
|
||||
ULONG ControllerNumber;
|
||||
BOOLEAN InNativeMode;
|
||||
BOOLEAN IoBaseMapped;
|
||||
BOOLEAN MiniportStarted;
|
||||
|
||||
FAST_MUTEX DeviceSyncMutex;
|
||||
_Guarded_by_(DeviceSyncMutex)
|
||||
PPDO_DEVICE_EXTENSION Channels[MAX_IDE_CHANNEL];
|
||||
|
||||
USHORT VendorId;
|
||||
USHORT DeviceId;
|
||||
PDRIVER_OBJECT DriverObject;
|
||||
PUCHAR BusMasterPortBase;
|
||||
|
||||
KSPIN_LOCK BusDataLock;
|
||||
BUS_INTERFACE_STANDARD BusInterface;
|
||||
|
||||
PDEVICE_OBJECT Pdo;
|
||||
ULONG ControllerNumber;
|
||||
FAST_MUTEX PdoListSyncMutex;
|
||||
_Guarded_by_(PdoListSyncMutex)
|
||||
LIST_ENTRY PdoListHead;
|
||||
ATA_CONTROLLER Controller;
|
||||
IDE_CONTROLLER_PROPERTIES Properties;
|
||||
|
||||
/* Must be the last entry */
|
||||
@@ -99,13 +401,110 @@ typedef struct _FDO_DEVICE_EXTENSION
|
||||
|
||||
typedef struct _PDO_DEVICE_EXTENSION
|
||||
{
|
||||
/** Common data, must be the first member. */
|
||||
COMMON_DEVICE_EXTENSION Common;
|
||||
|
||||
ULONG Channel;
|
||||
PFDO_DEVICE_EXTENSION ParentController;
|
||||
BOOLEAN ReportedMissing;
|
||||
PUCHAR IoBase;
|
||||
ULONG Flags;
|
||||
#define PDO_FLAG_NOT_PRESENT 0x00000001
|
||||
#define PDO_FLAG_REPORTED_MISSING 0x00000002
|
||||
|
||||
PCHANNEL_DATA_COMMON ChanData;
|
||||
|
||||
LIST_ENTRY ListEntry;
|
||||
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
|
||||
|
||||
VOID
|
||||
AtaWritePortUchar(
|
||||
_In_ PUCHAR Port,
|
||||
_In_ UCHAR Value,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
#include "pata.h"
|
||||
|
||||
extern NTSYSAPI ULONG InitSafeBootMode;
|
||||
|
||||
/* acpi.c *********************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
AtaAcpiGetTimingMode(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Out_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode);
|
||||
|
||||
NTSTATUS
|
||||
AtaAcpiSetTimingMode(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode,
|
||||
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock1,
|
||||
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock2);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
PVOID
|
||||
AtaAcpiGetTaskFile(
|
||||
_In_ PDEVICE_OBJECT DeviceObject);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
AtaAcpiSetDeviceData(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIDENTIFY_DEVICE_DATA IdBlock);
|
||||
|
||||
/* fdo.c **********************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CONTROLLER_ATTACH_CHANNEL AtaCtrlAttachChannel;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CHANNEL_SET_DEVICE_DATA AtaCtrlSetDeviceData;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CHANNEL_GET_INIT_TASK_FILE AtaCtrlGetInitTaskFile;
|
||||
|
||||
CHANNEL_SET_MODE AtaCtrlSetTransferMode;
|
||||
CHANNEL_DOWNGRADE_INTERFACE_SPEED AtaCtrlDowngradeInterfaceSpeed;
|
||||
CHANNEL_ABORT_CHANNEL AtaCtrlAbortChannel;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CONTROLLER_PNP_START_DEVICE PciIdeXFdoStartDevice;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CONTROLLER_PNP_REMOVE_DEVICE PciIdeXFdoRemoveDevice;
|
||||
|
||||
DECLSPEC_NOINLINE_FROM_PAGED
|
||||
VOID
|
||||
AtaChanEnableInterruptsSync(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN Enable);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
PVOID
|
||||
AtaCtrlPciMapBar(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_range_(0, PCI_TYPE0_ADDRESSES) ULONG Index,
|
||||
_In_ ULONG MinimumIoLength);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
IDE_CHANNEL_STATE
|
||||
PciIdeXGetChannelState(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXFdoDispatchPnp(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
||||
_Inout_ PIRP Irp);
|
||||
|
||||
/* miniport.c *****************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
IDE_CHANNEL_STATE
|
||||
PciIdeXChannelState(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
||||
_In_ ULONG Channel);
|
||||
|
||||
/* pciidex.c ******************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
|
||||
@@ -115,32 +514,396 @@ DRIVER_UNLOAD PciIdeXUnload;
|
||||
CODE_SEG("PAGE")
|
||||
DRIVER_ADD_DEVICE PciIdeXAddDevice;
|
||||
|
||||
_Dispatch_type_(IRP_MJ_PNP)
|
||||
CODE_SEG("PAGE")
|
||||
DRIVER_DISPATCH_PAGED PciIdeXDispatchPnp;
|
||||
|
||||
_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
||||
CODE_SEG("PAGE")
|
||||
DRIVER_DISPATCH_PAGED PciIdeXDispatchWmi;
|
||||
|
||||
IO_COMPLETION_ROUTINE PciIdeXPdoCompletionRoutine;
|
||||
|
||||
BOOLEAN
|
||||
PciFindDevice(
|
||||
_In_ __callback PATA_PCI_MATCH_FN MatchFunction,
|
||||
_In_ PVOID Context);
|
||||
|
||||
VOID
|
||||
PciRead(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_Out_writes_bytes_all_(BufferLength) PVOID Buffer,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength);
|
||||
|
||||
VOID
|
||||
PciWrite(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_reads_bytes_(BufferLength) PVOID Buffer,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG BufferLength);
|
||||
|
||||
VOID
|
||||
AtaSleep(VOID);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpRepeatRequest(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp,
|
||||
_In_opt_ PDEVICE_CAPABILITIES DeviceCapabilities);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpQueryDeviceUsageNotification(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPnpQueryPnpDeviceState(
|
||||
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||
_In_ PIRP Irp);
|
||||
|
||||
/* pdo.c **********************************************************************/
|
||||
|
||||
_Dispatch_type_(IRP_MJ_PNP)
|
||||
CODE_SEG("PAGE")
|
||||
DRIVER_DISPATCH_PAGED PciIdeXDispatchPnp;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXPdoRemoveDevice(
|
||||
_In_ PPDO_DEVICE_EXTENSION PdoExtension,
|
||||
_In_ PIRP Irp,
|
||||
_In_ BOOLEAN FinalRemove);
|
||||
|
||||
/* power.c ********************************************************************/
|
||||
|
||||
_Dispatch_type_(IRP_MJ_POWER)
|
||||
DRIVER_DISPATCH_RAISED PciIdeXDispatchPower;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXFdoDispatchPnp(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
||||
_Inout_ PIRP Irp);
|
||||
/* ahci_generic.c *************************************************************/
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeXStartMiniport(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension);
|
||||
AhciGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
/* ahci_hw.c ******************************************************************/
|
||||
|
||||
CHANNEL_ENABLE_INTERRUPTS AtaAhciEnableInterrupts;
|
||||
CHANNEL_ENUMERATE_CHANNEL AtaAhciEnumerateChannel;
|
||||
CHANNEL_IDENTIFY_DEVICE AtaAhciIdentifyDevice;
|
||||
CHANNEL_RESET_CHANNEL AtaAhciResetChannel;
|
||||
|
||||
VOID
|
||||
AtaAhciStopDma(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData);
|
||||
|
||||
VOID
|
||||
AtaAhciSaveTaskFile(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData,
|
||||
_Inout_ PATA_DEVICE_REQUEST Request,
|
||||
_In_ BOOLEAN ProcessErrorStatus);
|
||||
|
||||
VOID
|
||||
AtaAhciHandleFatalError(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData);
|
||||
|
||||
VOID
|
||||
AtaAhciHandlePortStateChange(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData,
|
||||
_In_ ULONG InterruptStatus);
|
||||
|
||||
BOOLEAN
|
||||
AtaAhciDowngradeInterfaceSpeed(
|
||||
_In_ PCHANNEL_DATA_AHCI ChanData);
|
||||
|
||||
ULONG
|
||||
AtaAhciChannelGetMaximumDeviceCount(
|
||||
_In_ PVOID ChannelContext);
|
||||
|
||||
/* ahci_io.c ******************************************************************/
|
||||
|
||||
CHANNEL_START_IO AtaAhciStartIo;
|
||||
CHANNEL_PREPARE_IO AtaAhciPrepareIo;
|
||||
CHANNEL_PREPARE_PRD_TABLE AtaAhciPreparePrdTable;
|
||||
CHANNEL_ALLOCATE_SLOT AtaAhciAllocateSlot;
|
||||
KSERVICE_ROUTINE AtaAhciHbaIsr;
|
||||
|
||||
/* pata_generic.c *************************************************************/
|
||||
|
||||
CHANNEL_SET_MODE_EX SataSetTransferMode;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
CONTROLLER_ATTACH_CHANNEL_EX PciIdeAttachChannel;
|
||||
|
||||
VOID
|
||||
AtaSelectTimings(
|
||||
_In_reads_(MAX_IDE_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList,
|
||||
_Out_writes_all_(MAX_IDE_DEVICE) PATA_TIMING Timings,
|
||||
_In_range_(>, 0) ULONG ClockPeriodPs,
|
||||
_In_ ULONG Flags);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
PciIdeInitTaskFileIoResources(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ ULONG_PTR CommandPortBase,
|
||||
_In_ ULONG_PTR ControlPortBase,
|
||||
_In_ ULONG CommandBlockSpare);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
IDE_CHANNEL_STATE
|
||||
PciIdeXChannelState(
|
||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
||||
PciIdeGetChannelState(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel);
|
||||
|
||||
#endif /* _PCIIDEX_PCH_ */
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeParseResources(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData,
|
||||
_In_ PCM_RESOURCE_LIST ResourcesTranslated);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
VOID
|
||||
PciIdeFreeResources(
|
||||
_In_ PVOID ChannelContext);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeConnectInterrupt(
|
||||
_In_ PVOID ChannelContext);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeCreateChannelData(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG HwExtensionSize);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PciIdeGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
/* pata_hw.c ******************************************************************/
|
||||
|
||||
CHANNEL_RESET_CHANNEL PataResetChannel;
|
||||
CHANNEL_ENUMERATE_CHANNEL PataEnumerateChannel;
|
||||
CHANNEL_IDENTIFY_DEVICE PataIdentifyDevice;
|
||||
|
||||
ULONG
|
||||
PataChannelGetMaximumDeviceCount(
|
||||
_In_ PVOID ChannelContext);
|
||||
|
||||
/* pata_io.c ******************************************************************/
|
||||
|
||||
CHANNEL_ALLOCATE_SLOT PataAllocateSlot;
|
||||
CHANNEL_PREPARE_PRD_TABLE PciIdePreparePrdTable;
|
||||
CHANNEL_PREPARE_IO PataPrepareIo;
|
||||
CHANNEL_START_IO PataStartIo;
|
||||
KSERVICE_ROUTINE PataChannelIsr;
|
||||
KSERVICE_ROUTINE PciIdeChannelIsr;
|
||||
CHANNEL_CHECK_INTERRUPT PciIdeCheckInterrupt;
|
||||
CHANNEL_LOAD_TASK_FILE PataLoadTaskFile;
|
||||
CHANNEL_SAVE_TASK_FILE PataSaveTaskFile;
|
||||
CHANNEL_READ_STATUS PataReadStatus;
|
||||
KDEFERRED_ROUTINE PataPollingTimerDpc;
|
||||
|
||||
VOID
|
||||
AtaWriteBlock16(
|
||||
_In_ PUSHORT Port,
|
||||
_In_ PUSHORT Buffer,
|
||||
_In_ ULONG Count,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
VOID
|
||||
AtaReadBlock16(
|
||||
_In_ PUSHORT Port,
|
||||
_In_ PUSHORT Buffer,
|
||||
_In_ ULONG Count,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
VOID
|
||||
AtaWriteBlock32(
|
||||
_In_ PULONG Port,
|
||||
_In_ PULONG Buffer,
|
||||
_In_ ULONG Count,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
VOID
|
||||
AtaReadBlock32(
|
||||
_In_ PULONG Port,
|
||||
_In_ PULONG Buffer,
|
||||
_In_ ULONG Count,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
UCHAR
|
||||
AtaReadPortUchar(
|
||||
_In_ PUCHAR Port,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
VOID
|
||||
AtaWritePortUlong(
|
||||
_In_ PULONG Port,
|
||||
_In_ ULONG Value,
|
||||
_In_ ULONG MmioFlags);
|
||||
|
||||
VOID
|
||||
PciIdeDmaStop(
|
||||
_In_ PCHANNEL_DATA_PATA ChanData);
|
||||
|
||||
/* misc ***********************************************************************/
|
||||
|
||||
#if defined(ATA_DETECT_LEGACY_DEVICES)
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller,
|
||||
_In_ PCM_RESOURCE_LIST ResourcesTranslated);
|
||||
#endif
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AmdGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
AtiGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
CmdGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
Sil680GetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
IntelGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
PcTechGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
SvwPataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
SvwSataGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ToshibaGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
NTSTATUS
|
||||
ViaGetControllerProperties(
|
||||
_Inout_ PATA_CONTROLLER Controller);
|
||||
|
||||
CHANNEL_SET_MODE_EX SvwSetTransferMode;
|
||||
|
||||
CODE_SEG("PAGE")
|
||||
BOOLEAN
|
||||
SvwHasUdmaCable(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG Channel);
|
||||
|
||||
VOID
|
||||
ViaClampTimings(
|
||||
_Inout_ PATA_TIMING Timing);
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
CountSetBits(
|
||||
_In_ ULONG x)
|
||||
{
|
||||
x -= x >> 1 & 0x55555555;
|
||||
x = (x & 0x33333333) + (x >> 2 & 0x33333333);
|
||||
|
||||
return ((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101 >> 24;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
IsPowerOfTwo(
|
||||
_In_ ULONG x)
|
||||
{
|
||||
/* Also exclude zero numbers */
|
||||
return (x != 0) && ((x & (x - 1)) == 0);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
UCHAR
|
||||
PciRead8(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset)
|
||||
{
|
||||
UCHAR Result;
|
||||
|
||||
PciRead(Controller, &Result, ConfigDataOffset, sizeof(Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
USHORT
|
||||
PciRead16(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset)
|
||||
{
|
||||
USHORT Result;
|
||||
|
||||
PciRead(Controller, &Result, ConfigDataOffset, sizeof(Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
ULONG
|
||||
PciRead32(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset)
|
||||
{
|
||||
ULONG Result;
|
||||
|
||||
PciRead(Controller, &Result, ConfigDataOffset, sizeof(Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
PciWrite8(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ UCHAR Value)
|
||||
{
|
||||
PciWrite(Controller, &Value, ConfigDataOffset, sizeof(Value));
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
PciWrite16(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ USHORT Value)
|
||||
{
|
||||
PciWrite(Controller, &Value, ConfigDataOffset, sizeof(Value));
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
PciWrite32(
|
||||
_In_ PATA_CONTROLLER Controller,
|
||||
_In_ ULONG ConfigDataOffset,
|
||||
_In_ ULONG Value)
|
||||
{
|
||||
PciWrite(Controller, &Value, ConfigDataOffset, sizeof(Value));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "PCI IDE bus driver extension"
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ATA Bus Driver Extension"
|
||||
#define REACTOS_STR_INTERNAL_NAME "pciidex"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "pciidex.sys"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
@ stdcall PciIdeXGetBusData(ptr ptr long long)
|
||||
@ stdcall PciIdeXInitialize(ptr ptr ptr long)
|
||||
@ stdcall PciIdeXSetBusData(ptr ptr ptr long long)
|
||||
@ stdcall -version=0x600+ PciIdexGetBusLocation(ptr ptr)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,6 @@
|
||||
|
||||
#include "pciidex.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
static
|
||||
NTSTATUS
|
||||
PciIdeXPdoDispatchPower(
|
||||
@@ -48,7 +45,7 @@ PciIdeXFdoDispatchPower(
|
||||
{
|
||||
PoStartNextPowerIrp(Irp);
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
return PoCallDriver(FdoExtension->Ldo, Irp);
|
||||
return PoCallDriver(FdoExtension->Common.LowerDeviceObject, Irp);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
@@ -57,10 +54,24 @@ PciIdeXDispatchPower(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Inout_ PIRP Irp)
|
||||
{
|
||||
PVOID DeviceExtension = DeviceObject->DeviceExtension;
|
||||
PCOMMON_DEVICE_EXTENSION CommonExt = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
if (IS_FDO(DeviceExtension))
|
||||
return PciIdeXFdoDispatchPower(DeviceExtension, Irp);
|
||||
Status = IoAcquireRemoveLock(&CommonExt->RemoveLock, Irp);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (IS_FDO(CommonExt))
|
||||
Status = PciIdeXFdoDispatchPower((PVOID)CommonExt, Irp);
|
||||
else
|
||||
return PciIdeXPdoDispatchPower(DeviceExtension, Irp);
|
||||
Status = PciIdeXPdoDispatchPower((PVOID)CommonExt, Irp);
|
||||
|
||||
IoReleaseRemoveLock(&CommonExt->RemoveLock, Irp);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
@@ -294,6 +294,7 @@ PciIdeXSetBusData(
|
||||
#define UDMA_MODE3 (1 << 14)
|
||||
#define UDMA_MODE4 (1 << 15)
|
||||
#define UDMA_MODE5 (1 << 16)
|
||||
#define UDMA_MODE6 (1 << 17)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
547
sdk/include/reactos/drivers/ata/ata_shared.h
Normal file
547
sdk/include/reactos/drivers/ata/ata_shared.h
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Storage Stack
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* or MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: Internal shared ATA driver definitions
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @sa PCIIDE_INTERFACE */
|
||||
#define PCIIDEX_INTERFACE_VERSION 1
|
||||
|
||||
/** Maximum number of devices (target ID) per channel */
|
||||
#define ATA_MAX_DEVICE 15
|
||||
|
||||
/**
|
||||
* @brief 256 sectors of 512 bytes (128 kB).
|
||||
*
|
||||
* This ensures that the sector count register will not overflow in LBA-28 and CHS modes.
|
||||
* In the case of the sector count (0x100) being truncated to 8-bits, 0 still means 256 sectors.
|
||||
*/
|
||||
/*@{*/
|
||||
#define ATA_MIN_SECTOR_SIZE 512
|
||||
#define ATA_MAX_SECTORS_PER_IO 0x100
|
||||
#define ATA_MAX_TRANSFER_LENGTH (ATA_MAX_SECTORS_PER_IO * ATA_MIN_SECTOR_SIZE) // 0x20000
|
||||
/*@}*/
|
||||
|
||||
/** Minimum DMA buffer alignment because of the reserved PRDT byte 0 */
|
||||
#define ATA_MIN_BUFFER_ALIGNMENT FILE_WORD_ALIGNMENT
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
/** IDE channel timing information block */
|
||||
typedef struct _IDE_ACPI_TIMING_MODE_BLOCK
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG PioSpeed; ///< PIO cycle timing in ns
|
||||
ULONG DmaSpeed; ///< DMA cycle timing in ns
|
||||
/** The mode is not supported */
|
||||
#define IDE_ACPI_TIMING_MODE_NOT_SUPPORTED 0xFFFFFFFF // aka -1 ns
|
||||
} Drive[MAX_IDE_DEVICE];
|
||||
|
||||
ULONG ModeFlags;
|
||||
/** Use the UDMA mode on drive 0/1 */
|
||||
#define IDE_ACPI_TIMING_MODE_FLAG_UDMA(Drive) (0x01 << (2 * (Drive)))
|
||||
|
||||
/** Enable the IORDY signal on drive 0/1 */
|
||||
#define IDE_ACPI_TIMING_MODE_FLAG_IORDY(Drive) (0x02 << (2 * (Drive)))
|
||||
|
||||
/** Independent timing available */
|
||||
#define IDE_ACPI_TIMING_MODE_FLAG_INDEPENDENT_TIMINGS 0x10
|
||||
} IDE_ACPI_TIMING_MODE_BLOCK, *PIDE_ACPI_TIMING_MODE_BLOCK;
|
||||
|
||||
/** _GTF data buffer */
|
||||
typedef struct _ATA_ACPI_TASK_FILE
|
||||
{
|
||||
UCHAR Feature;
|
||||
UCHAR SectorCount;
|
||||
UCHAR LowLba;
|
||||
UCHAR MidLba;
|
||||
UCHAR HighLba;
|
||||
UCHAR DriveSelect;
|
||||
UCHAR Command;
|
||||
} ATA_ACPI_TASK_FILE, *PATA_ACPI_TASK_FILE;
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
typedef struct _ATA_DEVICE_REQUEST ATA_DEVICE_REQUEST, *PATA_DEVICE_REQUEST;
|
||||
|
||||
typedef enum _PORT_NOTIFICATION_TYPE
|
||||
{
|
||||
AtaRequestComplete = 0,
|
||||
AtaResetDetected,
|
||||
AtaBusChangeDetected,
|
||||
AtaRequestFailed,
|
||||
AtaAsyncNotificationDetected,
|
||||
} PORT_NOTIFICATION_TYPE, *PPORT_NOTIFICATION_TYPE;
|
||||
|
||||
typedef enum _ATA_CONNECTION_STATUS
|
||||
{
|
||||
CONN_STATUS_FAILURE,
|
||||
CONN_STATUS_NO_DEVICE,
|
||||
CONN_STATUS_DEV_UNKNOWN,
|
||||
CONN_STATUS_DEV_ATA,
|
||||
CONN_STATUS_DEV_ATAPI,
|
||||
} ATA_CONNECTION_STATUS;
|
||||
|
||||
typedef struct _IDE_REGISTERS
|
||||
{
|
||||
PUCHAR Data;
|
||||
union
|
||||
{
|
||||
PUCHAR Features;
|
||||
PUCHAR Error;
|
||||
};
|
||||
union
|
||||
{
|
||||
PUCHAR SectorCount;
|
||||
PUCHAR InterruptReason;
|
||||
};
|
||||
PUCHAR LbaLow; ///< LBA bits 0-7, 24-31
|
||||
union
|
||||
{
|
||||
PUCHAR LbaMid; ///< LBA bits 8-15, 32-39
|
||||
PUCHAR ByteCountLow;
|
||||
PUCHAR SignatureLow;
|
||||
};
|
||||
union
|
||||
{
|
||||
PUCHAR LbaHigh; ///< LBA bits 16-23, 40-47
|
||||
PUCHAR ByteCountHigh;
|
||||
PUCHAR SignatureHigh;
|
||||
};
|
||||
PUCHAR Device;
|
||||
union
|
||||
{
|
||||
PUCHAR Command;
|
||||
PUCHAR Status;
|
||||
};
|
||||
union
|
||||
{
|
||||
PUCHAR Control;
|
||||
PUCHAR AlternateStatus;
|
||||
};
|
||||
PUCHAR Dma;
|
||||
PUCHAR Scr;
|
||||
} IDE_REGISTERS, *PIDE_REGISTERS;
|
||||
|
||||
typedef struct _CHANNEL_DEVICE_CONFIG
|
||||
{
|
||||
ULONG SupportedModes;
|
||||
ULONG PioMode;
|
||||
ULONG DmaMode;
|
||||
ULONG MinPioCycleTime;
|
||||
ULONG MinMwDmaCycleTime;
|
||||
ULONG MinSwDmaCycleTime;
|
||||
ULONG CurrentModes;
|
||||
BOOLEAN IsFixedDisk;
|
||||
BOOLEAN IoReadySupported;
|
||||
BOOLEAN IsNewDevice;
|
||||
PCSTR FriendlyName;
|
||||
PIDENTIFY_DEVICE_DATA IdentifyDeviceData;
|
||||
} CHANNEL_DEVICE_CONFIG, *PCHANNEL_DEVICE_CONFIG;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COMPLETE_IRP = 0,
|
||||
COMPLETE_NO_IRP,
|
||||
COMPLETE_START_AGAIN,
|
||||
} ATA_COMPLETION_ACTION;
|
||||
|
||||
typedef ATA_COMPLETION_ACTION
|
||||
(REQUEST_COMPLETION_ROUTINE)(
|
||||
_In_ PATA_DEVICE_REQUEST Request);
|
||||
typedef REQUEST_COMPLETION_ROUTINE *PREQUEST_COMPLETION_ROUTINE;
|
||||
|
||||
typedef struct _ATA_IO_CONTEXT_COMMON
|
||||
{
|
||||
ULONG SectorSize;
|
||||
|
||||
ULONG TransportFlags;
|
||||
#define DEVICE_NUMBER_MASK 0x0000000F
|
||||
#define DEVICE_IS_ATAPI 0x00000010
|
||||
#define DEVICE_HAS_CDB_INTERRUPT 0x00000020
|
||||
#define DEVICE_NEED_DMA_DIRECTION 0x00000040
|
||||
#define DEVICE_IS_NEC_CDR260 0x00000080
|
||||
#define DEVICE_QUEUE_DEPTH_MASK 0x0000FF00
|
||||
|
||||
#define DEVICE_QUEUE_DEPTH_SHIFT 8
|
||||
|
||||
UCHAR MultiSectorCount;
|
||||
UCHAR CdbSize;
|
||||
UCHAR DeviceSelect;
|
||||
} ATA_IO_CONTEXT_COMMON, *PATA_IO_CONTEXT_COMMON;
|
||||
|
||||
/** ATA Task File interface */
|
||||
typedef struct _ATA_TASKFILE
|
||||
{
|
||||
union
|
||||
{
|
||||
UCHAR Command;
|
||||
UCHAR Status;
|
||||
};
|
||||
union
|
||||
{
|
||||
UCHAR Feature;
|
||||
UCHAR Error;
|
||||
};
|
||||
UCHAR LowLba; ///< LBA bits 0-7
|
||||
UCHAR MidLba; ///< LBA bits 8-15
|
||||
UCHAR HighLba; ///< LBA bits 16-23
|
||||
UCHAR DriveSelect;
|
||||
UCHAR LowLbaEx; ///< LBA bits 24-31
|
||||
UCHAR MidLbaEx; ///< LBA bits 32-39
|
||||
UCHAR HighLbaEx; ///< LBA bits 40-47
|
||||
UCHAR FeatureEx;
|
||||
UCHAR SectorCount;
|
||||
UCHAR SectorCountEx;
|
||||
UCHAR Icc; ///< Isochronous Command Completion
|
||||
ULONG Auxiliary;
|
||||
} ATA_TASKFILE, *PATA_TASKFILE;
|
||||
|
||||
/** ATA device request context */
|
||||
typedef struct _ATA_DEVICE_REQUEST
|
||||
{
|
||||
union
|
||||
{
|
||||
/** Completion queue entry */
|
||||
SLIST_ENTRY CompletionEntry;
|
||||
|
||||
/** Port queue entry */
|
||||
LIST_ENTRY PortEntry;
|
||||
};
|
||||
union
|
||||
{
|
||||
UCHAR Cdb[16];
|
||||
ATA_TASKFILE TaskFile;
|
||||
};
|
||||
PVOID DataBuffer;
|
||||
PSCATTER_GATHER_LIST SgList;
|
||||
PATA_IO_CONTEXT_COMMON Device;
|
||||
ULONG DataTransferLength;
|
||||
ULONG Flags;
|
||||
PMDL Mdl;
|
||||
PIRP Irp;
|
||||
PSCSI_REQUEST_BLOCK Srb;
|
||||
UCHAR SrbStatus;
|
||||
PREQUEST_COMPLETION_ROUTINE Complete;
|
||||
ULONG Tag;
|
||||
ULONG Slot;
|
||||
ULONG TimeOut;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UCHAR InternalState;
|
||||
UCHAR TranslationState;
|
||||
UCHAR Reserved1;
|
||||
UCHAR Reserved2;
|
||||
};
|
||||
ULONG State;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ATA normal/error outputs.
|
||||
*
|
||||
* The contents of registers are only valid
|
||||
* if flags has the REQUEST_FLAG_HAS_TASK_FILE bit set.
|
||||
*
|
||||
* The driver always updates it on ATA errors as we have to set the ATA LBA field.
|
||||
* For ATAPI errors only the Status and Error fields are updated, as an optimization.
|
||||
*/
|
||||
ATA_TASKFILE Output;
|
||||
|
||||
#if DBG
|
||||
ULONG Signature;
|
||||
#define ATA_DEVICE_REQUEST_SIGNATURE 'rATA'
|
||||
#endif
|
||||
} ATA_DEVICE_REQUEST, *PATA_DEVICE_REQUEST;
|
||||
|
||||
/** Initial state */
|
||||
#define REQUEST_STATE_NONE 0
|
||||
|
||||
/** SRB not translated into the device request or translaton failed */
|
||||
#define REQUEST_STATE_NOT_STARTED 1
|
||||
|
||||
/** Requeue the device request */
|
||||
#define REQUEST_STATE_REQUEUE 2
|
||||
|
||||
/** Freeze the device queue upon completion of IRP */
|
||||
#define REQUEST_STATE_FREEZE_QUEUE 3
|
||||
|
||||
/** ATA protocols */
|
||||
/*@{*/
|
||||
/** DMA ATA command */
|
||||
#define REQUEST_FLAG_DMA 0x00000001
|
||||
|
||||
/** ATAPI PACKET command */
|
||||
#define REQUEST_FLAG_PACKET_COMMAND 0x00000002
|
||||
|
||||
/** DMA Queued command */
|
||||
#define REQUEST_FLAG_NCQ 0x00000004
|
||||
|
||||
/** Data-In command */
|
||||
#define REQUEST_FLAG_DATA_IN 0x00000040
|
||||
|
||||
/** Data-Out command */
|
||||
#define REQUEST_FLAG_DATA_OUT 0x00000080
|
||||
|
||||
/** Software Reset command (AHCI only) */
|
||||
#define REQUEST_FLAG_RST_COMMAND 0x00040000
|
||||
/*@}*/
|
||||
|
||||
/** 48-bit command */
|
||||
#define REQUEST_FLAG_LBA48 0x00000008
|
||||
|
||||
/** Multiple mode command */
|
||||
#define REQUEST_FLAG_READ_WRITE_MULTIPLE 0x00000010
|
||||
|
||||
/** ATA read/write command */
|
||||
#define REQUEST_FLAG_READ_WRITE 0x00000020
|
||||
|
||||
/** Forced unit access command */
|
||||
#define REQUEST_FLAG_FUA 0x00000100
|
||||
|
||||
/** Return the contents of task file registers to the caller */
|
||||
#define REQUEST_FLAG_SAVE_TASK_FILE 0x00000200
|
||||
|
||||
/** Holds the saved contents of task file registers */
|
||||
#define REQUEST_FLAG_HAS_TASK_FILE 0x00000400
|
||||
|
||||
/** Has extra bits in the device register */
|
||||
#define REQUEST_FLAG_SET_DEVICE_REGISTER 0x00000800
|
||||
|
||||
/** Has extra bits in the Auxiliary field */
|
||||
#define REQUEST_FLAG_SET_AUXILIARY_FIELD 0x00001000
|
||||
|
||||
/** Has extra bits in the Isochronous Command Completion field */
|
||||
#define REQUEST_FLAG_SET_ICC_FIELD 0x00002000
|
||||
|
||||
/** Exclusive port access required */
|
||||
#define REQUEST_FLAG_EXCLUSIVE 0x00004000
|
||||
|
||||
/** The request owns the local buffer */
|
||||
#define REQUEST_FLAG_HAS_LOCAL_BUFFER 0x00008000
|
||||
|
||||
/** The request owns the S/G list and will also release it */
|
||||
#define REQUEST_FLAG_HAS_SG_LIST 0x00010000
|
||||
|
||||
/** The request owns the MDL and will also release it */
|
||||
#define REQUEST_FLAG_HAS_MDL 0x00020000
|
||||
|
||||
/** The request owns the reserved memory mapping and will also release it */
|
||||
#define REQUEST_FLAG_HAS_RESERVED_MAPPING 0x00080000
|
||||
|
||||
/** Copy of SRB_FLAGS_NO_KEEP_AWAKE */
|
||||
#define REQUEST_FLAG_NO_KEEP_AWAKE 0x00100000
|
||||
|
||||
/** Use the DMA engine for the transfer */
|
||||
#define REQUEST_FLAG_PROGRAM_DMA 0x00200000
|
||||
|
||||
/** Internal command */
|
||||
#define REQUEST_FLAG_INTERNAL 0x00400000
|
||||
|
||||
/** ATA or SCSI pass-through command */
|
||||
#define REQUEST_FLAG_PASSTHROUGH 0x00800000
|
||||
|
||||
#define REQUEST_FLAG_DEVICE_EXCLUSIVE_ACCESS 0x01000000
|
||||
|
||||
/** Polled command */
|
||||
#define REQUEST_FLAG_POLL 0x80000000
|
||||
|
||||
/**
|
||||
* Exclusive port access required.
|
||||
*
|
||||
* 1) Since there is only one Received FIS structure, it should be necessary to
|
||||
* synchronize RFIS reads amongst multiple I/O requests.
|
||||
*
|
||||
* 2) We also mark all requests that modify the device extension state
|
||||
* (IDE_COMMAND_IDENTIFY, IDE_COMMAND_ATAPI_IDENTIFY,
|
||||
* IDE_COMMAND_SET_FEATURE, and others) as REQUEST_FLAG_EXCLUSIVE.
|
||||
*/
|
||||
#define REQUEST_EXCLUSIVE_ACCESS_FLAGS \
|
||||
(REQUEST_FLAG_SAVE_TASK_FILE | REQUEST_FLAG_EXCLUSIVE)
|
||||
|
||||
/** DMA command translation */
|
||||
#define REQUEST_DMA_FLAGS \
|
||||
(REQUEST_FLAG_DMA | REQUEST_FLAG_PROGRAM_DMA)
|
||||
|
||||
typedef VOID
|
||||
(__cdecl PORT_NOTIFICATION)(
|
||||
_In_ PORT_NOTIFICATION_TYPE NotificationType,
|
||||
_In_ PVOID PortContext,
|
||||
...);
|
||||
typedef PORT_NOTIFICATION *PPORT_NOTIFICATION;
|
||||
|
||||
typedef NTSTATUS
|
||||
(CONTROLLER_ATTACH_CHANNEL)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN Attach);
|
||||
typedef CONTROLLER_ATTACH_CHANNEL *PCONTROLLER_ATTACH_CHANNEL;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_SET_DEVICE_DATA)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_In_ PIDENTIFY_DEVICE_DATA IdentifyDeviceData);
|
||||
typedef CHANNEL_SET_DEVICE_DATA *PCHANNEL_SET_DEVICE_DATA;
|
||||
|
||||
typedef PVOID
|
||||
(CHANNEL_GET_INIT_TASK_FILE)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PDEVICE_OBJECT DeviceObject);
|
||||
typedef CHANNEL_GET_INIT_TASK_FILE *PCHANNEL_GET_INIT_TASK_FILE;
|
||||
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_DOWNGRADE_INTERFACE_SPEED)(
|
||||
_In_ PVOID ChannelContext);
|
||||
typedef CHANNEL_DOWNGRADE_INTERFACE_SPEED *PCHANNEL_DOWNGRADE_INTERFACE_SPEED;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_ABORT_CHANNEL)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ BOOLEAN DisableInterrupts);
|
||||
typedef CHANNEL_ABORT_CHANNEL *PCHANNEL_ABORT_CHANNEL;
|
||||
|
||||
typedef VOID
|
||||
(CHANNEL_RESET_CHANNEL)(
|
||||
_In_ PVOID ChannelContext);
|
||||
typedef CHANNEL_RESET_CHANNEL *PCHANNEL_RESET_CHANNEL;
|
||||
|
||||
typedef ULONG
|
||||
(CHANNEL_ENUMERATE_CHANNEL)(
|
||||
_In_ PVOID ChannelContext);
|
||||
typedef CHANNEL_ENUMERATE_CHANNEL *PCHANNEL_ENUMERATE_CHANNEL;
|
||||
|
||||
typedef ATA_CONNECTION_STATUS
|
||||
(CHANNEL_IDENTIFY_DEVICE)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ ULONG DeviceNumber);
|
||||
typedef CHANNEL_IDENTIFY_DEVICE *PCHANNEL_IDENTIFY_DEVICE;
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CHANNEL_SET_MODE)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_reads_(ATA_MAX_DEVICE) PCHANNEL_DEVICE_CONFIG* DeviceList);
|
||||
typedef CHANNEL_SET_MODE *PCHANNEL_SET_MODE;
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_ALLOCATE_SLOT)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request,
|
||||
_In_ BOOLEAN Allocate);
|
||||
typedef CHANNEL_ALLOCATE_SLOT *PCHANNEL_ALLOCATE_SLOT;
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CHANNEL_PREPARE_PRD_TABLE)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request,
|
||||
_In_ SCATTER_GATHER_LIST* __restrict SgList);
|
||||
typedef CHANNEL_PREPARE_PRD_TABLE *PCHANNEL_PREPARE_PRD_TABLE;
|
||||
|
||||
_IRQL_requires_(DISPATCH_LEVEL)
|
||||
typedef VOID
|
||||
(CHANNEL_PREPARE_IO)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request);
|
||||
typedef CHANNEL_PREPARE_IO *PCHANNEL_PREPARE_IO;
|
||||
|
||||
_IRQL_requires_(HIGH_LEVEL)
|
||||
typedef BOOLEAN
|
||||
(CHANNEL_START_IO)(
|
||||
_In_ PVOID ChannelContext,
|
||||
_In_ PATA_DEVICE_REQUEST Request);
|
||||
typedef CHANNEL_START_IO *PCHANNEL_START_IO;
|
||||
|
||||
typedef NTSTATUS
|
||||
(CONTROLLER_PNP_ADD_DEVICE)(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_In_ PDEVICE_OBJECT PhysicalDeviceObject,
|
||||
_Out_ PVOID *ControllerContext);
|
||||
typedef CONTROLLER_PNP_ADD_DEVICE *PCONTROLLER_PNP_ADD_DEVICE;
|
||||
|
||||
typedef NTSTATUS
|
||||
(CONTROLLER_PNP_START_DEVICE)(
|
||||
_In_ PVOID ControllerContext,
|
||||
_In_ PCM_RESOURCE_LIST ResourcesTranslated);
|
||||
typedef CONTROLLER_PNP_START_DEVICE *PCONTROLLER_PNP_START_DEVICE;
|
||||
|
||||
typedef VOID
|
||||
(CONTROLLER_PNP_REMOVE_DEVICE)(
|
||||
_In_ PVOID ControllerContext);
|
||||
typedef CONTROLLER_PNP_REMOVE_DEVICE *PCONTROLLER_PNP_REMOVE_DEVICE;
|
||||
|
||||
/* ReactOS-specific legacy detection magic */
|
||||
#define PCIIDEX_GET_CONTROLLER_INTERFACE_SIGNATURE (0xFFFFFFFF - 0x1000)
|
||||
|
||||
/**
|
||||
* @brief Legacy detection interface with the PCIIDEX driver.
|
||||
*
|
||||
* @note This interface is ROS-specific.
|
||||
*/
|
||||
typedef struct _PCIIDEX_LEGACY_CONTROLLER_INTERFACE
|
||||
{
|
||||
ULONG Version;
|
||||
PCONTROLLER_PNP_ADD_DEVICE AddDevice;
|
||||
PCONTROLLER_PNP_START_DEVICE StartDevice;
|
||||
PCONTROLLER_PNP_REMOVE_DEVICE RemoveDevice;
|
||||
} PCIIDEX_LEGACY_CONTROLLER_INTERFACE, *PPCIIDEX_LEGACY_CONTROLLER_INTERFACE;
|
||||
|
||||
/**
|
||||
* @brief Channel interface with the PCIIDEX driver.
|
||||
*
|
||||
* This interface is ROS-specific.
|
||||
*/
|
||||
typedef struct _PCIIDEX_CHANNEL_INTERFACE
|
||||
{
|
||||
/* Common interface header */
|
||||
USHORT Size;
|
||||
USHORT Version;
|
||||
PVOID Context;
|
||||
PINTERFACE_REFERENCE InterfaceReference;
|
||||
PINTERFACE_DEREFERENCE InterfaceDereference;
|
||||
|
||||
PVOID ChannelContext;
|
||||
PCONTROLLER_ATTACH_CHANNEL AttachChannel;
|
||||
PKINTERRUPT InterruptObject;
|
||||
ULONG Channel;
|
||||
ULONG TransferModeSupported;
|
||||
ULONG MaximumTransferLength;
|
||||
ULONG MaximumPhysicalPages;
|
||||
ULONG QueueDepth;
|
||||
ULONG MaxTargetId;
|
||||
PCHANNEL_SET_DEVICE_DATA SetDeviceData;
|
||||
PCHANNEL_GET_INIT_TASK_FILE GetInitTaskFile;
|
||||
PCHANNEL_DOWNGRADE_INTERFACE_SPEED DowngradeInterfaceSpeed;
|
||||
PCHANNEL_ABORT_CHANNEL AbortChannel;
|
||||
PCHANNEL_RESET_CHANNEL ResetChannel;
|
||||
PCHANNEL_ENUMERATE_CHANNEL EnumerateChannel;
|
||||
PCHANNEL_IDENTIFY_DEVICE IdentifyDevice;
|
||||
PCHANNEL_SET_MODE SetTransferMode;
|
||||
PCHANNEL_ALLOCATE_SLOT AllocateSlot;
|
||||
PCHANNEL_PREPARE_PRD_TABLE PreparePrdTable;
|
||||
PCHANNEL_PREPARE_IO PrepareIo;
|
||||
PCHANNEL_START_IO StartIo;
|
||||
PCONTROLLER_OBJECT HwSyncObject;
|
||||
PDMA_ADAPTER DmaAdapter;
|
||||
PDEVICE_OBJECT ChannelObject;
|
||||
ULONG Flags;
|
||||
#define ATA_CHANNEL_FLAG_PIO_VIA_DMA 0x00000001
|
||||
#define ATA_CHANNEL_FLAG_IS_EXTERNAL 0x00000002
|
||||
#define ATA_CHANNEL_FLAG_NCQ 0x00000004
|
||||
#define ATA_CHANNEL_FLAG_IS_AHCI 0x00000008
|
||||
#define ATA_CHANNEL_FLAG_PIO_FOR_LBA48_XFER 0x00000010
|
||||
|
||||
PVOID* PortContext;
|
||||
PPORT_NOTIFICATION* PortNotification;
|
||||
PATA_DEVICE_REQUEST** Slots;
|
||||
} PCIIDEX_CHANNEL_INTERFACE, *PPCIIDEX_CHANNEL_INTERFACE;
|
||||
|
||||
DEFINE_GUID(GUID_PCIIDE_INTERFACE_ROS,
|
||||
0xD677FBCF, 0xABED, 0x47C8, 0x80, 0xA3, 0xE4, 0x34, 0x7E, 0xA4, 0x96, 0x47);
|
||||
52
sdk/include/reactos/drivers/ata/ata_user.h
Normal file
52
sdk/include/reactos/drivers/ata/ata_user.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Storage Stack
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* or MIT (https://spdx.org/licenses/MIT)
|
||||
* PURPOSE: ATA driver user mode interface
|
||||
* COPYRIGHT: Copyright 2026 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define DD_ATA_REG_ATA_DEVICE_TYPE L"DeviceType"
|
||||
#define DD_ATA_REG_SCSI_DEVICE_TYPE L"ScsiDeviceType"
|
||||
#define DD_ATA_REG_MAX_TARGET_ID L"MaxTargetId"
|
||||
#define DD_ATA_REG_XFER_MODE_ALLOWED L"UserTimingModeAllowed"
|
||||
#define DD_ATA_REG_XFER_MODE_SUPPORTED L"DeviceTimingModeSupported"
|
||||
#define DD_ATA_REG_XFER_MODE_SELECTED L"DeviceTimingMode"
|
||||
|
||||
/** PIO modes 0-4 */
|
||||
#define PIO_ALL \
|
||||
(PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4)
|
||||
|
||||
/** SWDMA modes 0-2 */
|
||||
#define SWDMA_ALL \
|
||||
(SWDMA_MODE0 | SWDMA_MODE1 | SWDMA_MODE2)
|
||||
|
||||
/** MWDMA modes 0-2 */
|
||||
#define MWDMA_ALL \
|
||||
(MWDMA_MODE0 | MWDMA_MODE1 | MWDMA_MODE2)
|
||||
|
||||
/** UDMA modes 0-6 */
|
||||
#define UDMA_ALL \
|
||||
(UDMA_MODE0 | UDMA_MODE1 | UDMA_MODE2 | UDMA_MODE3 | UDMA_MODE4 | UDMA_MODE5 | UDMA_MODE6)
|
||||
|
||||
/** Converts the provided mode number into a mode index in the bit map */
|
||||
/*@{*/
|
||||
#define PIO_MODE(n) (n)
|
||||
#define SWDMA_MODE(n) (5 + (n))
|
||||
#define MWDMA_MODE(n) (8 + (n))
|
||||
#define UDMA_MODE(n) (11 + (n))
|
||||
/*@}*/
|
||||
|
||||
/**
|
||||
* @brief Private enum between the ATA driver and storprop.dll
|
||||
* @sa DD_ATA_REG_ATA_DEVICE_TYPE
|
||||
*/
|
||||
typedef enum _ATA_DEVICE_TYPE
|
||||
{
|
||||
DEV_UNKNOWN = 0,
|
||||
DEV_ATA = 1,
|
||||
DEV_ATAPI = 2,
|
||||
DEV_NONE = 3
|
||||
} ATA_DEVICE_TYPE;
|
||||
Reference in New Issue
Block a user