mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[PCIIDEX] Add DMA support
CORE-17256
This commit is contained in:
committed by
Carl J. Bialorucki
parent
5418987cb8
commit
ae2827f481
@@ -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)
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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
|
* PROJECT: PCI IDE bus driver
|
||||||
* FILE: drivers/storage/pciide/pciide.c
|
* FILE: drivers/storage/pciide/pciide.c
|
||||||
* PURPOSE: Main file
|
* PURPOSE: Main file
|
||||||
* PROGRAMMERS: Hervé Poussineau ([email protected])
|
* PROGRAMMERS: Hervé Poussineau ([email protected])
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pciide.h"
|
#include "pciide.h"
|
||||||
@@ -16,34 +16,8 @@ PciIdeChannelEnabled(
|
|||||||
IN PVOID DeviceExtension,
|
IN PVOID DeviceExtension,
|
||||||
IN ULONG Channel)
|
IN ULONG Channel)
|
||||||
{
|
{
|
||||||
PCI_COMMON_CONFIG PciConfig;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
DPRINT("PciIdeChannelEnabled(%p, %lu)\n", DeviceExtension, Channel);
|
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;
|
return ChannelStateUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,24 +25,9 @@ BOOLEAN NTAPI
|
|||||||
PciIdeSyncAccessRequired(
|
PciIdeSyncAccessRequired(
|
||||||
IN PVOID DeviceExtension)
|
IN PVOID DeviceExtension)
|
||||||
{
|
{
|
||||||
DPRINT1("PciIdeSyncAccessRequired %p\n", DeviceExtension);
|
DPRINT("PciIdeSyncAccessRequired %p\n", DeviceExtension);
|
||||||
|
|
||||||
return FALSE; /* FIXME */
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG NTAPI
|
ULONG NTAPI
|
||||||
@@ -88,27 +47,40 @@ PciIdeGetControllerProperties(
|
|||||||
IN PVOID DeviceExtension,
|
IN PVOID DeviceExtension,
|
||||||
OUT PIDE_CONTROLLER_PROPERTIES ControllerProperties)
|
OUT PIDE_CONTROLLER_PROPERTIES ControllerProperties)
|
||||||
{
|
{
|
||||||
|
ULONG SupportedMode;
|
||||||
|
USHORT PciCommand;
|
||||||
|
|
||||||
if (ControllerProperties->Size != sizeof(IDE_CONTROLLER_PROPERTIES))
|
if (ControllerProperties->Size != sizeof(IDE_CONTROLLER_PROPERTIES))
|
||||||
return STATUS_REVISION_MISMATCH;
|
return STATUS_REVISION_MISMATCH;
|
||||||
|
|
||||||
ControllerProperties->PciIdeChannelEnabled = PciIdeChannelEnabled;
|
ControllerProperties->PciIdeChannelEnabled = PciIdeChannelEnabled;
|
||||||
ControllerProperties->PciIdeSyncAccessRequired = PciIdeSyncAccessRequired;
|
ControllerProperties->PciIdeSyncAccessRequired = PciIdeSyncAccessRequired;
|
||||||
ControllerProperties->PciIdeTransferModeSelect = PciIdeTransferModeSelect;
|
|
||||||
ControllerProperties->IgnoreActiveBitForAtaDevice = FALSE;
|
ControllerProperties->IgnoreActiveBitForAtaDevice = FALSE;
|
||||||
ControllerProperties->AlwaysClearBusMasterInterrupt = TRUE;
|
ControllerProperties->AlwaysClearBusMasterInterrupt = TRUE;
|
||||||
ControllerProperties->PciIdeUseDma = PciIdeUseDma;
|
ControllerProperties->PciIdeUseDma = PciIdeUseDma;
|
||||||
ControllerProperties->AlignmentRequirement = 1;
|
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][0] =
|
||||||
ControllerProperties->SupportedTransferMode[0][1] =
|
ControllerProperties->SupportedTransferMode[0][1] =
|
||||||
ControllerProperties->SupportedTransferMode[1][0] =
|
ControllerProperties->SupportedTransferMode[1][0] =
|
||||||
ControllerProperties->SupportedTransferMode[1][1] =
|
ControllerProperties->SupportedTransferMode[1][1] = 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;
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,36 @@
|
|||||||
spec2def(pciidex.sys pciidex.spec ADD_IMPORTLIB)
|
spec2def(pciidex.sys pciidex.spec ADD_IMPORTLIB)
|
||||||
|
|
||||||
list(APPEND SOURCE
|
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
|
fdo.c
|
||||||
miniport.c
|
miniport.c
|
||||||
pciidex.c
|
pciidex.c
|
||||||
|
pciidex.h
|
||||||
pdo.c
|
pdo.c
|
||||||
power.c
|
power.c)
|
||||||
pciidex.h)
|
|
||||||
|
if(ARCH STREQUAL "i386")
|
||||||
|
add_definitions(-DATA_DETECT_LEGACY_DEVICES)
|
||||||
|
list(APPEND SOURCE chipset/pata_legacy.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(pciidex MODULE
|
add_library(pciidex MODULE
|
||||||
${SOURCE}
|
${SOURCE}
|
||||||
|
|||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
/*
|
||||||
|
* PROJECT: ReactOS ATA Bus Driver
|
||||||
|
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||||
|
* PURPOSE: AHCI header file
|
||||||
|
* COPYRIGHT: Copyright 2026 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from the FreeBSD ata-ati driver
|
||||||
|
* Copyright (c) 1998-2008 Søren Schmidt <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from the FreeBSD ata-serverworks driver
|
||||||
|
* Copyright (c) 1998-2008 Søren Schmidt <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapted from the FreeBSD ata-serverworks driver
|
||||||
|
* Copyright (c) 1998-2008 Søren Schmidt <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
@@ -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 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
+760
-236
File diff suppressed because it is too large
Load Diff
@@ -7,42 +7,9 @@
|
|||||||
|
|
||||||
#include "pciidex.h"
|
#include "pciidex.h"
|
||||||
|
|
||||||
#define NDEBUG
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
/** @brief Global debugging level. Valid values are between 0 (Error) and 3 (Trace). */
|
/** @brief Global debugging level. Valid values are between 0 (Error) and 3 (Trace). */
|
||||||
ULONG PciIdeDebug = 0;
|
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")
|
CODE_SEG("PAGE")
|
||||||
IDE_CHANNEL_STATE
|
IDE_CHANNEL_STATE
|
||||||
PciIdeXChannelState(
|
PciIdeXChannelState(
|
||||||
@@ -95,21 +62,21 @@ PciIdeXGetBusData(
|
|||||||
_In_ ULONG ConfigDataOffset,
|
_In_ ULONG ConfigDataOffset,
|
||||||
_In_ ULONG BufferLength)
|
_In_ ULONG BufferLength)
|
||||||
{
|
{
|
||||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
PFDO_DEVICE_EXTENSION FdoExt;
|
||||||
|
PATA_CONTROLLER Controller;
|
||||||
ULONG BytesRead;
|
ULONG BytesRead;
|
||||||
|
|
||||||
DPRINT("PciIdeXGetBusData(%p %p 0x%lx 0x%lx)\n",
|
INFO("PciIdeXGetBusData(%p %p 0x%lx 0x%lx)\n",
|
||||||
DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
||||||
|
|
||||||
FdoExtension = CONTAINING_RECORD(DeviceExtension,
|
FdoExt = CONTAINING_RECORD(DeviceExtension, FDO_DEVICE_EXTENSION, MiniControllerExtension);
|
||||||
FDO_DEVICE_EXTENSION,
|
Controller = &FdoExt->Controller;
|
||||||
MiniControllerExtension);
|
|
||||||
|
|
||||||
BytesRead = (*FdoExtension->BusInterface.GetBusData)(FdoExtension->BusInterface.Context,
|
BytesRead = Controller->GetBusData(Controller->BusInterfaceContext,
|
||||||
PCI_WHICHSPACE_CONFIG,
|
PCI_WHICHSPACE_CONFIG,
|
||||||
Buffer,
|
Buffer,
|
||||||
ConfigDataOffset,
|
ConfigDataOffset,
|
||||||
BufferLength);
|
BufferLength);
|
||||||
if (BytesRead != BufferLength)
|
if (BytesRead != BufferLength)
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
@@ -126,24 +93,38 @@ PciIdeXSetBusData(
|
|||||||
_In_ ULONG ConfigDataOffset,
|
_In_ ULONG ConfigDataOffset,
|
||||||
_In_ ULONG BufferLength)
|
_In_ ULONG BufferLength)
|
||||||
{
|
{
|
||||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
PFDO_DEVICE_EXTENSION FdoExt;
|
||||||
|
PATA_CONTROLLER Controller;
|
||||||
|
UCHAR LocalBuffer[4];
|
||||||
ULONG i, BytesWritten;
|
ULONG i, BytesWritten;
|
||||||
PUCHAR CurrentBuffer;
|
PUCHAR CurrentBuffer;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT("PciIdeXSetBusData(%p %p %p 0x%lx 0x%lx)\n",
|
INFO("PciIdeXSetBusData(%p %p %p 0x%lx 0x%lx)\n",
|
||||||
DeviceExtension, Buffer, DataMask, ConfigDataOffset, BufferLength);
|
DeviceExtension, Buffer, DataMask, ConfigDataOffset, BufferLength);
|
||||||
|
|
||||||
CurrentBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferLength, TAG_PCIIDEX);
|
/* Optimize the common case (4-byte PCI access) */
|
||||||
if (!CurrentBuffer)
|
if (BufferLength <= sizeof(LocalBuffer))
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
{
|
||||||
|
CurrentBuffer = LocalBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentBuffer = ExAllocatePoolUninitialized(NonPagedPool, BufferLength, TAG_PCIIDEX);
|
||||||
|
if (!CurrentBuffer)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
FdoExtension = CONTAINING_RECORD(DeviceExtension,
|
FdoExt = CONTAINING_RECORD(DeviceExtension, FDO_DEVICE_EXTENSION, MiniControllerExtension);
|
||||||
FDO_DEVICE_EXTENSION,
|
Controller = &FdoExt->Controller;
|
||||||
MiniControllerExtension);
|
|
||||||
|
|
||||||
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);
|
Status = PciIdeXGetBusData(DeviceExtension, Buffer, ConfigDataOffset, BufferLength);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
@@ -155,19 +136,40 @@ PciIdeXSetBusData(
|
|||||||
(((PUCHAR)DataMask)[i] & ((PUCHAR)Buffer)[i]);
|
(((PUCHAR)DataMask)[i] & ((PUCHAR)Buffer)[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
BytesWritten = (*FdoExtension->BusInterface.SetBusData)(FdoExtension->BusInterface.Context,
|
BytesWritten = Controller->SetBusData(Controller->BusInterfaceContext,
|
||||||
PCI_WHICHSPACE_CONFIG,
|
PCI_WHICHSPACE_CONFIG,
|
||||||
CurrentBuffer,
|
CurrentBuffer,
|
||||||
ConfigDataOffset,
|
ConfigDataOffset,
|
||||||
BufferLength);
|
BufferLength);
|
||||||
if (BytesWritten != BufferLength)
|
if (BytesWritten != BufferLength)
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
Status = STATUS_UNSUCCESSFUL;
|
||||||
else
|
else
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
Cleanup:
|
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;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* PROJECT: ReactOS ATA Bus Driver
|
||||||
|
* LICENSE: MIT (https://spdx.org/licenses/MIT)
|
||||||
|
* PURPOSE: PATA definitions
|
||||||
|
* COPYRIGHT: Copyright 2026 <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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"
|
#include "pciidex.h"
|
||||||
|
|
||||||
#define NDEBUG
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
ULONG PciIdeControllerNumber = 0;
|
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")
|
CODE_SEG("PAGE")
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
@@ -28,7 +127,7 @@ PciIdeXDispatchWmi(
|
|||||||
PFDO_DEVICE_EXTENSION FdoExtension = DeviceObject->DeviceExtension;
|
PFDO_DEVICE_EXTENSION FdoExtension = DeviceObject->DeviceExtension;
|
||||||
|
|
||||||
IoSkipCurrentIrpStackLocation(Irp);
|
IoSkipCurrentIrpStackLocation(Irp);
|
||||||
Status = IoCallDriver(FdoExtension->Ldo, Irp);
|
Status = IoCallDriver(FdoExtension->Common.LowerDeviceObject, Irp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -52,13 +151,156 @@ PciIdeXUnload(
|
|||||||
NOTHING;
|
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
|
static
|
||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
PciIdeXQueryInterface(
|
PciIdeXPnpQueryInterface(
|
||||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
_In_ PCOMMON_DEVICE_EXTENSION CommonExt,
|
||||||
_In_ const GUID* Guid,
|
_In_ const GUID* Guid,
|
||||||
_Out_ PVOID Interface,
|
_Out_ PVOID Interface,
|
||||||
|
_In_ ULONG Version,
|
||||||
_In_ ULONG Size)
|
_In_ ULONG Size)
|
||||||
{
|
{
|
||||||
KEVENT Event;
|
KEVENT Event;
|
||||||
@@ -72,7 +314,7 @@ PciIdeXQueryInterface(
|
|||||||
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
||||||
|
|
||||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
||||||
FdoExtension->Ldo,
|
CommonExt->LowerDeviceObject,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -87,12 +329,12 @@ PciIdeXQueryInterface(
|
|||||||
Stack = IoGetNextIrpStackLocation(Irp);
|
Stack = IoGetNextIrpStackLocation(Irp);
|
||||||
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||||||
Stack->Parameters.QueryInterface.InterfaceType = Guid;
|
Stack->Parameters.QueryInterface.InterfaceType = Guid;
|
||||||
Stack->Parameters.QueryInterface.Version = 1;
|
Stack->Parameters.QueryInterface.Version = Version;
|
||||||
Stack->Parameters.QueryInterface.Size = Size;
|
Stack->Parameters.QueryInterface.Size = Size;
|
||||||
Stack->Parameters.QueryInterface.Interface = Interface;
|
Stack->Parameters.QueryInterface.Interface = Interface;
|
||||||
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||||||
|
|
||||||
Status = IoCallDriver(FdoExtension->Ldo, Irp);
|
Status = IoCallDriver(CommonExt->LowerDeviceObject, Irp);
|
||||||
if (Status == STATUS_PENDING)
|
if (Status == STATUS_PENDING)
|
||||||
{
|
{
|
||||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||||
@@ -105,86 +347,40 @@ PciIdeXQueryInterface(
|
|||||||
static
|
static
|
||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
PciIdeXGetConfigurationInfo(
|
PciIdeXAddDeviceEx(
|
||||||
_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(
|
|
||||||
_In_ PDRIVER_OBJECT DriverObject,
|
_In_ PDRIVER_OBJECT DriverObject,
|
||||||
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
|
_In_ PDEVICE_OBJECT PhysicalDeviceObject,
|
||||||
|
_Out_ PVOID *ControllerContext)
|
||||||
{
|
{
|
||||||
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
||||||
PFDO_DEVICE_EXTENSION FdoExtension;
|
PFDO_DEVICE_EXTENSION FdoExtension;
|
||||||
ULONG DeviceExtensionSize;
|
ULONG DeviceExtensionSize;
|
||||||
PDEVICE_OBJECT Fdo;
|
PDEVICE_OBJECT Fdo;
|
||||||
UNICODE_STRING DeviceName;
|
UNICODE_STRING DeviceName;
|
||||||
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde999")];
|
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde99999")];
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
Status = RtlStringCbPrintfW(DeviceNameBuffer,
|
Status = RtlStringCbPrintfW(DeviceNameBuffer,
|
||||||
sizeof(DeviceNameBuffer),
|
sizeof(DeviceNameBuffer),
|
||||||
L"\\Device\\Ide\\PciIde%u",
|
L"\\Device\\Ide\\PciIde%lu",
|
||||||
PciIdeControllerNumber);
|
PciIdeControllerNumber);
|
||||||
ASSERT(NT_SUCCESS(Status));
|
ASSERT(NT_SUCCESS(Status));
|
||||||
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
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);
|
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
|
||||||
ASSERT(DriverExtension);
|
ASSERT(DriverExtension);
|
||||||
|
|
||||||
Status = RtlULongAdd(DriverExtension->MiniControllerExtensionSize,
|
Status = RtlULongAdd(DriverExtension->MiniControllerExtensionSize,
|
||||||
sizeof(FDO_DEVICE_EXTENSION),
|
sizeof(*FdoExtension),
|
||||||
&DeviceExtensionSize);
|
&DeviceExtensionSize);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("Invalid miniport extension size %lx\n",
|
ERR("Invalid miniport extension size %lx\n", DriverExtension->MiniControllerExtensionSize);
|
||||||
DriverExtension->MiniControllerExtensionSize);
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,61 +393,90 @@ PciIdeXAddDevice(
|
|||||||
&Fdo);
|
&Fdo);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("Failed to create FDO 0x%lx\n", Status);
|
ERR("Failed to create FDO 0x%lx\n", Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
FdoExtension = Fdo->DeviceExtension;
|
FdoExtension = Fdo->DeviceExtension;
|
||||||
|
|
||||||
RtlZeroMemory(FdoExtension, sizeof(FDO_DEVICE_EXTENSION));
|
RtlZeroMemory(FdoExtension, sizeof(*FdoExtension));
|
||||||
FdoExtension->Common.IsFDO = TRUE;
|
FdoExtension->Common.Flags = DO_IS_FDO;
|
||||||
FdoExtension->Common.Self = Fdo;
|
FdoExtension->Common.Self = Fdo;
|
||||||
|
IoInitializeRemoveLock(&FdoExtension->Common.RemoveLock, TAG_PCIIDEX, 0, 0);
|
||||||
|
|
||||||
FdoExtension->DriverObject = DriverObject;
|
FdoExtension->DriverObject = DriverObject;
|
||||||
|
FdoExtension->Pdo = PhysicalDeviceObject;
|
||||||
FdoExtension->ControllerNumber = PciIdeControllerNumber++;
|
FdoExtension->ControllerNumber = PciIdeControllerNumber++;
|
||||||
|
|
||||||
KeInitializeSpinLock(&FdoExtension->BusDataLock);
|
ExInitializeFastMutex(&FdoExtension->PdoListSyncMutex);
|
||||||
ExInitializeFastMutex(&FdoExtension->DeviceSyncMutex);
|
InitializeListHead(&FdoExtension->PdoListHead);
|
||||||
|
|
||||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo, PhysicalDeviceObject, &FdoExtension->Ldo);
|
KeInitializeSpinLock(&FdoExtension->Controller.Lock);
|
||||||
|
|
||||||
|
Status = IoAttachDeviceToDeviceStackSafe(Fdo,
|
||||||
|
PhysicalDeviceObject,
|
||||||
|
&FdoExtension->Common.LowerDeviceObject);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT("Failed to attach FDO 0x%lx\n", Status);
|
ERR("Failed to attach FDO 0x%lx\n", Status);
|
||||||
goto Failure;
|
goto Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DMA buffers alignment */
|
/* 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,
|
#if defined(ATA_DETECT_LEGACY_DEVICES)
|
||||||
&GUID_BUS_INTERFACE_STANDARD,
|
if (ControllerContext)
|
||||||
&FdoExtension->BusInterface,
|
|
||||||
sizeof(BUS_INTERFACE_STANDARD));
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
DPRINT1("No bus interface 0x%lx\n", Status);
|
FdoExtension->Controller.Flags |= CTRL_FLAG_NON_PNP;
|
||||||
goto Failure;
|
*ControllerContext = FdoExtension;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Status = PciIdeXGetConfigurationInfo(FdoExtension);
|
#endif
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
{
|
||||||
DPRINT1("Unable to retrieve the configuration info %lx\n", Status);
|
BUS_INTERFACE_STANDARD BusInterface;
|
||||||
goto Failure;
|
|
||||||
|
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;
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
Failure:
|
Failure:
|
||||||
if (FdoExtension->Ldo)
|
if (FdoExtension->Common.LowerDeviceObject)
|
||||||
IoDetachDevice(FdoExtension->Ldo);
|
IoDetachDevice(FdoExtension->Common.LowerDeviceObject);
|
||||||
|
|
||||||
IoDeleteDevice(Fdo);
|
IoDeleteDevice(Fdo);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CODE_SEG("PAGE")
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
PciIdeXAddDevice(
|
||||||
|
_In_ PDRIVER_OBJECT DriverObject,
|
||||||
|
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
|
||||||
|
{
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
return PciIdeXAddDeviceEx(DriverObject, PhysicalDeviceObject, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
VOID
|
VOID
|
||||||
@@ -297,17 +522,35 @@ PciIdeXInitialize(
|
|||||||
|
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
DPRINT("PciIdeXInitialize(%p '%wZ' %p 0x%lx)\n",
|
INFO("PciIdeXInitialize(%p '%wZ' %p 0x%lx)\n",
|
||||||
DriverObject, RegistryPath, HwGetControllerProperties, ExtensionSize);
|
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,
|
Status = IoAllocateDriverObjectExtension(DriverObject,
|
||||||
DriverObject,
|
DriverObject,
|
||||||
sizeof(PCIIDEX_DRIVER_EXTENSION),
|
sizeof(*DriverExtension),
|
||||||
(PVOID*)&DriverExtension);
|
(PVOID*)&DriverExtension);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
return Status;
|
return Status;
|
||||||
|
|
||||||
RtlZeroMemory(DriverExtension, sizeof(PCIIDEX_DRIVER_EXTENSION));
|
RtlZeroMemory(DriverExtension, sizeof(*DriverExtension));
|
||||||
DriverExtension->MiniControllerExtensionSize = ExtensionSize;
|
DriverExtension->MiniControllerExtensionSize = ExtensionSize;
|
||||||
DriverExtension->HwGetControllerProperties = HwGetControllerProperties;
|
DriverExtension->HwGetControllerProperties = HwGetControllerProperties;
|
||||||
|
|
||||||
|
|||||||
@@ -6,47 +6,346 @@
|
|||||||
* Copyright 2023 Dmitry Borisov <[email protected]>
|
* Copyright 2023 Dmitry Borisov <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PCIIDEX_PCH_
|
#pragma once
|
||||||
#define _PCIIDEX_PCH_
|
|
||||||
|
|
||||||
#include <ntddk.h>
|
#include <ntddk.h>
|
||||||
#include <ntstrsafe.h>
|
#include <ntstrsafe.h>
|
||||||
#include <ntintsafe.h>
|
#include <ntintsafe.h>
|
||||||
#include <initguid.h>
|
#include <initguid.h>
|
||||||
#include <wdmguid.h>
|
#include <wdmguid.h>
|
||||||
|
|
||||||
|
#include <ata.h>
|
||||||
#include <ide.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 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)
|
#define IS_PRIMARY_CHANNEL(PdoExtension) (PdoExtension->Channel == 0)
|
||||||
|
|
||||||
/*
|
#if defined(_MSC_VER)
|
||||||
* Legacy ranges and interrupts
|
#pragma section("PAGECONS", read)
|
||||||
*/
|
#endif
|
||||||
#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
|
|
||||||
|
|
||||||
/*
|
/** Pageable read-only data */
|
||||||
* Programming Interface Register
|
#define PCIIDEX_PAGED_DATA DATA_SEG("PAGECONS")
|
||||||
*/
|
|
||||||
#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
|
|
||||||
|
|
||||||
#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 _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
|
typedef struct _PCIIDEX_DRIVER_EXTENSION
|
||||||
{
|
{
|
||||||
@@ -56,9 +355,6 @@ typedef struct _PCIIDEX_DRIVER_EXTENSION
|
|||||||
|
|
||||||
typedef struct _COMMON_DEVICE_EXTENSION
|
typedef struct _COMMON_DEVICE_EXTENSION
|
||||||
{
|
{
|
||||||
BOOLEAN IsFDO;
|
|
||||||
PDEVICE_OBJECT Self;
|
|
||||||
|
|
||||||
_Write_guarded_by_(_Global_interlock_)
|
_Write_guarded_by_(_Global_interlock_)
|
||||||
volatile LONG PageFiles;
|
volatile LONG PageFiles;
|
||||||
|
|
||||||
@@ -67,30 +363,36 @@ typedef struct _COMMON_DEVICE_EXTENSION
|
|||||||
|
|
||||||
_Write_guarded_by_(_Global_interlock_)
|
_Write_guarded_by_(_Global_interlock_)
|
||||||
volatile LONG DumpFiles;
|
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;
|
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
|
||||||
|
|
||||||
typedef struct _FDO_DEVICE_EXTENSION
|
typedef struct _FDO_DEVICE_EXTENSION
|
||||||
{
|
{
|
||||||
|
/** Common data, must be the first member. */
|
||||||
COMMON_DEVICE_EXTENSION Common;
|
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;
|
PDRIVER_OBJECT DriverObject;
|
||||||
PUCHAR BusMasterPortBase;
|
PDEVICE_OBJECT Pdo;
|
||||||
|
ULONG ControllerNumber;
|
||||||
KSPIN_LOCK BusDataLock;
|
FAST_MUTEX PdoListSyncMutex;
|
||||||
BUS_INTERFACE_STANDARD BusInterface;
|
_Guarded_by_(PdoListSyncMutex)
|
||||||
|
LIST_ENTRY PdoListHead;
|
||||||
|
ATA_CONTROLLER Controller;
|
||||||
IDE_CONTROLLER_PROPERTIES Properties;
|
IDE_CONTROLLER_PROPERTIES Properties;
|
||||||
|
|
||||||
/* Must be the last entry */
|
/* Must be the last entry */
|
||||||
@@ -99,13 +401,110 @@ typedef struct _FDO_DEVICE_EXTENSION
|
|||||||
|
|
||||||
typedef struct _PDO_DEVICE_EXTENSION
|
typedef struct _PDO_DEVICE_EXTENSION
|
||||||
{
|
{
|
||||||
|
/** Common data, must be the first member. */
|
||||||
COMMON_DEVICE_EXTENSION Common;
|
COMMON_DEVICE_EXTENSION Common;
|
||||||
|
|
||||||
ULONG Channel;
|
ULONG Channel;
|
||||||
PFDO_DEVICE_EXTENSION ParentController;
|
ULONG Flags;
|
||||||
BOOLEAN ReportedMissing;
|
#define PDO_FLAG_NOT_PRESENT 0x00000001
|
||||||
PUCHAR IoBase;
|
#define PDO_FLAG_REPORTED_MISSING 0x00000002
|
||||||
|
|
||||||
|
PCHANNEL_DATA_COMMON ChanData;
|
||||||
|
|
||||||
|
LIST_ENTRY ListEntry;
|
||||||
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
|
} 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")
|
CODE_SEG("PAGE")
|
||||||
DRIVER_INITIALIZE DriverEntry;
|
DRIVER_INITIALIZE DriverEntry;
|
||||||
|
|
||||||
@@ -115,32 +514,396 @@ DRIVER_UNLOAD PciIdeXUnload;
|
|||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
DRIVER_ADD_DEVICE PciIdeXAddDevice;
|
DRIVER_ADD_DEVICE PciIdeXAddDevice;
|
||||||
|
|
||||||
_Dispatch_type_(IRP_MJ_PNP)
|
|
||||||
CODE_SEG("PAGE")
|
|
||||||
DRIVER_DISPATCH_PAGED PciIdeXDispatchPnp;
|
|
||||||
|
|
||||||
_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
DRIVER_DISPATCH_PAGED PciIdeXDispatchWmi;
|
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)
|
_Dispatch_type_(IRP_MJ_POWER)
|
||||||
DRIVER_DISPATCH_RAISED PciIdeXDispatchPower;
|
DRIVER_DISPATCH_RAISED PciIdeXDispatchPower;
|
||||||
|
|
||||||
CODE_SEG("PAGE")
|
/* ahci_generic.c *************************************************************/
|
||||||
NTSTATUS
|
|
||||||
PciIdeXFdoDispatchPnp(
|
|
||||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
||||||
_Inout_ PIRP Irp);
|
|
||||||
|
|
||||||
CODE_SEG("PAGE")
|
CODE_SEG("PAGE")
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
PciIdeXStartMiniport(
|
AhciGetControllerProperties(
|
||||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension);
|
_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")
|
CODE_SEG("PAGE")
|
||||||
IDE_CHANNEL_STATE
|
IDE_CHANNEL_STATE
|
||||||
PciIdeXChannelState(
|
PciIdeGetChannelState(
|
||||||
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
_In_ PATA_CONTROLLER Controller,
|
||||||
_In_ ULONG Channel);
|
_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_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_INTERNAL_NAME "pciidex"
|
||||||
#define REACTOS_STR_ORIGINAL_FILENAME "pciidex.sys"
|
#define REACTOS_STR_ORIGINAL_FILENAME "pciidex.sys"
|
||||||
#include <reactos/version.rc>
|
#include <reactos/version.rc>
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
@ stdcall PciIdeXGetBusData(ptr ptr long long)
|
@ stdcall PciIdeXGetBusData(ptr ptr long long)
|
||||||
@ stdcall PciIdeXInitialize(ptr ptr ptr long)
|
@ stdcall PciIdeXInitialize(ptr ptr ptr long)
|
||||||
@ stdcall PciIdeXSetBusData(ptr ptr ptr long long)
|
@ stdcall PciIdeXSetBusData(ptr ptr ptr long long)
|
||||||
|
@ stdcall -version=0x600+ PciIdexGetBusLocation(ptr ptr)
|
||||||
|
|||||||
+630
-387
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
#include "pciidex.h"
|
#include "pciidex.h"
|
||||||
|
|
||||||
#define NDEBUG
|
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
static
|
static
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
PciIdeXPdoDispatchPower(
|
PciIdeXPdoDispatchPower(
|
||||||
@@ -48,7 +45,7 @@ PciIdeXFdoDispatchPower(
|
|||||||
{
|
{
|
||||||
PoStartNextPowerIrp(Irp);
|
PoStartNextPowerIrp(Irp);
|
||||||
IoSkipCurrentIrpStackLocation(Irp);
|
IoSkipCurrentIrpStackLocation(Irp);
|
||||||
return PoCallDriver(FdoExtension->Ldo, Irp);
|
return PoCallDriver(FdoExtension->Common.LowerDeviceObject, Irp);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
@@ -57,10 +54,24 @@ PciIdeXDispatchPower(
|
|||||||
_In_ PDEVICE_OBJECT DeviceObject,
|
_In_ PDEVICE_OBJECT DeviceObject,
|
||||||
_Inout_ PIRP Irp)
|
_Inout_ PIRP Irp)
|
||||||
{
|
{
|
||||||
PVOID DeviceExtension = DeviceObject->DeviceExtension;
|
PCOMMON_DEVICE_EXTENSION CommonExt = DeviceObject->DeviceExtension;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
if (IS_FDO(DeviceExtension))
|
Status = IoAcquireRemoveLock(&CommonExt->RemoveLock, Irp);
|
||||||
return PciIdeXFdoDispatchPower(DeviceExtension, 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
|
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_MODE3 (1 << 14)
|
||||||
#define UDMA_MODE4 (1 << 15)
|
#define UDMA_MODE4 (1 << 15)
|
||||||
#define UDMA_MODE5 (1 << 16)
|
#define UDMA_MODE5 (1 << 16)
|
||||||
|
#define UDMA_MODE6 (1 << 17)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ([email protected])
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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);
|
||||||
@@ -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 ([email protected])
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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