Compare commits

...

10 Commits

Author SHA1 Message Date
Dmitry Borisov 48b2ff7004
Merge 93ec419a7d into 45aa8f8111 2024-04-27 06:26:18 +07:00
Timo Kreuzer 45aa8f8111 [CRT] Remove useless #undef abort from process.h 2024-04-26 15:16:31 +02:00
Timo Kreuzer 6beff505d7 [CRT] Add _Exit to process.h
This is already done this way in our stdlib.h. It is needed by GCC 13 C++ headers. The problem happens like this:
- telnet/precomp.h includes fstream from GCC
- fstream includes pthread.h from GCC
- pthread.h includes process.h from ReactOS
- process.h defines _CRT_TERMINATE_DEFINED, but doesn't declare _Exit
- fstream includes cstdlib from GCC
- cstdlib includes stdlib.h from GCC (#include_next)
- stdlib.h doesn't declare _Exit, because _CRT_TERMINATE_DEFINED is defined
- cstdlib uses _Exit
2024-04-26 15:16:31 +02:00
Dmitry Borisov 93ec419a7d [UNIATA] Disable the driver and enable the new ATA stack
CORE-17256
2024-04-25 20:06:54 +06:00
Dmitry Borisov ff45d61932 [ATAPI] Add ATA storage driver
CORE-17256
CORE-17191
CORE-17716
CORE-17977
CORE-16216
2024-04-25 20:06:51 +06:00
Dmitry Borisov c04df3f2c9 [PCIIDEX] Add AHCI support
WIP

CORE-17256
2024-03-11 21:16:12 +06:00
Dmitry Borisov b0c9c12a4a [XDK] Add missing PCI subclass type definition
CORE-17256
2024-03-10 23:29:23 +06:00
Dmitry Borisov 16897cf20f [DDK] Update IDENTIFY data and other ATA definitions
Based on the MinGW header
CORE-17256
2024-03-10 23:29:22 +06:00
Dmitry Borisov 769cff3f1e [NDK] Introduce function attributes for section placement
Increase code readability by using the function attributes
instead of a plain DECLSPEC_NOINLINE
2024-03-10 23:25:45 +06:00
Dmitry Borisov ef0cd511d6 [ATAPI] Disable the driver 2024-03-04 19:34:45 +06:00
49 changed files with 21030 additions and 7183 deletions

View File

@ -65,6 +65,15 @@ HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#ROOT_HUB","Cla
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#ROOT_HUB20","Service",0x00000000,"usbhub"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#ROOT_HUB20","ClassGUID",0x00000000,"{36FC9E60-C465-11CF-8056-444553540000}"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0101","Service",0x00000000,"pciide"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0101","ClassGUID",0x00000000,"{4D36E96A-E325-11CE-BFC1-08002BE10318}"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0106","Service",0x00000000,"pciahci"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\PCI#CC_0106","ClassGUID",0x00000000,"{4D36E96A-E325-11CE-BFC1-08002BE10318}"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\*PNP0600","Service",0x00000000,"atapi"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\*PNP0600","ClassGUID",0x00000000,"{4D36E96A-E325-11CE-BFC1-08002BE10318}"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\GenCdRom","Service",0x00000000,"cdrom"
HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\GenCdRom","ClassGUID",0x00000000,"{4D36E965-E325-11CE-BFC1-08002BE10318}"

View File

@ -90,7 +90,7 @@ FreeSysPartDiskSpace=450
acpi.sys = 1,,,,,,,4,1,,,1,4
nmidebug.sys = 1,,,,,,x,4,,,,1,4
sacdrv.sys = 1,,,,,,x,4,,,,1,4
uniata.sys = 1,,,,,,x,4,,,,1,4
atapi.sys = 1,,,,,,x,4,,,,1,4
buslogic.sys = 1,,,,,,x,4,,,,1,4
blue.sys = 1,,,,,,x,4,,,,1,4
vgafonts.cab = 1,,,,,,,1,,,,1,1
@ -126,7 +126,8 @@ storport.sys = 1,,,,,,,4,,,,1,4
fastfat.sys = 1,,,,,,x,4,,,,1,4
btrfs.sys = 1,,,,,,x,4,,,,1,4
ramdisk.sys = 1,,,,,,x,4,,,,1,4
pciide.sys = 1,,,,,,,4,,,,1,4
pciahci.sys = 1,,,,,,x,4,,,,1,4
pciide.sys = 1,,,,,,x,4,,,,1,4
pciidex.sys = 1,,,,,,,4,,,,1,4
pcix.sys = 1,,,,,,,4,,,,1,4
pcmcia.sys = 1,,,,,,,4,,,,1,4
@ -156,11 +157,9 @@ PCI\CC_0601 = isapnp
PCI\CC_0604 = pci
PCI\VEN_104B&CC_0100 = buslogic
PCI\CC_0101 = pciide
PCI\CC_0104 = uniata
PCI\CC_0105 = uniata
PCI\CC_0106 = uniata
PCI\CC_0106 = pciahci
;PCI\CC_0106 = storahci
*PNP0600 = uniata
*PNP0600 = atapi
USB\CLASS_09 = usbhub
USB\ROOT_HUB = usbhub
USB\ROOT_HUB20 = usbhub
@ -199,9 +198,10 @@ i8042prt = i8042prt.sys
[BusExtenders.Load]
pciide = pciide.sys
pciahci = pciahci.sys
[SCSI.Load]
uniata = uniata.sys
atapi = atapi.sys
buslogic = buslogic.sys
storahci = storahci.sys
disk = disk.sys

View File

@ -1,5 +1,5 @@
add_subdirectory(atapi)
add_subdirectory(pciahci)
add_subdirectory(pciide)
add_subdirectory(pciidex)
add_subdirectory(uniata)

View File

@ -1,6 +1,37 @@
add_library(atapi MODULE atapi.c atapi.rc)
target_link_libraries(atapi libcntpr)
if(ARCH STREQUAL "i386")
set(DETECT_LEGACY_DEVICES TRUE)
add_definitions(-DATA_DETECT_LEGACY_DEVICES)
endif()
list(APPEND SOURCE
atahw.h
atapi.c
atapi.h
data.c
debug.h
enum.c
fdo.c
hwahci.c
hwpata.c
ideacpi.c
ioctl.c
pdo.c
satl.c
scsi.c
smart.c
timings.c
wmi.c)
if(DETECT_LEGACY_DEVICES)
list(APPEND SOURCE legacy.c)
endif()
add_library(atapi MODULE ${SOURCE} atapi.rc)
set_module_type(atapi kernelmodedriver)
add_importlibs(atapi scsiport)
target_link_libraries(atapi memcmp)
# add_pch(atapi atapi.h SOURCE) # TODO
add_importlibs(atapi ntoskrnl hal wmilib)
add_cd_file(TARGET atapi DESTINATION reactos/system32/drivers NO_CAB FOR all)
add_registry_inf(atapi_reg.inf)

View File

@ -0,0 +1,349 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: AHCI header file
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#define AHCI_MAX_PORTS 32
#define AHCI_MAX_PM_DEVICES 16
#define AHCI_MAX_COMMAND_SLOTS 32
#define AHCI_MAX_PRDT_ENTRIES 0xFFFFF
#define AHCI_COMMAND_TABLE_ALIGNMENT 128
#define AHCI_RECEIVED_FIS_AREA_ALIGNMENT 256
#define AHCI_COMMAND_LIST_ALIGNMENT 1024
#define AHCI_RECEIVED_FIS_AREA_FBS_ALIGNMENT 4096
#define AHCI_FBS_RECEIVE_AREA_SIZE 4096
#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
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,
} AHCI_PORT_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_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 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 0xF0000000
#define AHCI_PXTFD_STATUS_MASK 0x000000FF
#define AHCI_PXTFD_ERROR_MASK 0x0000FF00
#define AHCI_PXTFD_STATUS_ERR 0x01
#define AHCI_PXTFD_STATUS_DRQ 0x08
#define AHCI_PXTFD_STATUS_BUSY 0x80
#define AHCI_PXSIG_INVALID 0xFFFFFFFF
#define AHCI_PXSSTS_DET_MASK 0x0000000F
#define AHCI_PXSSTS_SPD_MASK 0x000000F0
#define AHCI_PXSSTS_IPM_MASK 0x00000F00
#define AHCI_PXSSTS_SPD_SHIFT 4
#define AHCI_PXSSTS_IPM_SHIFT 8
#define AHCI_PXSSTS_IPM_NO_DEVICE 0
#define AHCI_PXSSTS_IPM_ACTIVE 1
#define AHCI_PXSSTS_IPM_PARTIAL_PM 2
#define AHCI_PXSSTS_IPM_SLUMBER_PM 6
#define AHCI_PXSSTS_DET_IDLE 0
#define AHCI_PXSSTS_DET_DEVICE_NO_PHY 1
#define AHCI_PXSSTS_DET_DEVICE_PHY 3
#define AHCI_PXSSTS_DET_PHY_OFFLINE 4
#define AHCI_PXCTL_DET_MASK 0x0000000F
#define AHCI_PXCTL_SPD 0x000000F0
#define AHCI_PXCTL_IPM 0x00000F00
#define AHCI_PXCTL_DET_IDLE 0
#define AHCI_PXCTL_DET_RESET 1
#define AHCI_PXCTL_DET_DISABLE_SATA 4
#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)
#define AHCI_VERSION_0_95 0x00000905
#define AHCI_VERSION_1_0 0x00010000
#define AHCI_VERSION_1_2 0x00010200
#define AHCI_VERSION_1_3 0x00010300
#define AHCI_GHC_HR 0x00000001
#define AHCI_GHC_IE 0x00000002
#define AHCI_GHC_MRSM 0x00000004
#define AHCI_GHC_AE 0x80000000
#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
#define AHCI_CAP2_BOH 0x00000001
#define AHCI_CAP2_NVMP 0x00000002
#define AHCI_CAP2_APST 0x00000004
#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_RECEIVED_FIS_AREA
{
UCHAR DmaSetup[0x1C];
ULONG Reserved;
UCHAR PioSetup[0x14];
ULONG Reserved2[3];
UCHAR DeviceToHost[0x14];
ULONG Reserved3;
UCHAR DeviceBits[0x08];
UCHAR UnknownFis[0x40];
UCHAR Reserved4[0x60];
} AHCI_RECEIVED_FIS_AREA, *PAHCI_RECEIVED_FIS_AREA;
C_ASSERT(sizeof(AHCI_RECEIVED_FIS_AREA) == 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
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
{
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);
typedef struct _AHCI_FIS_HOST_TO_DEVICE
{
UCHAR Type;
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 Reserved0;
UCHAR Control;
ULONG Reserved1;
} AHCI_FIS_HOST_TO_DEVICE, *PAHCI_FIS_HOST_TO_DEVICE;
C_ASSERT(sizeof(AHCI_FIS_HOST_TO_DEVICE) == 20);
#include <poppack.h>
#define AHCI_PORT_BASE(HbaIoBase, PortNumber) \
(PULONG)((ULONG_PTR)(HbaIoBase) + (PortNumber) * 0x80 + 0x100)
FORCEINLINE
ULONG
AHCI_HBA_READ(
_In_ PULONG HbaIoBase,
_In_ AHCI_HOST_BUS_ADAPTER_REGISTER Register)
{
return READ_REGISTER_ULONG((PULONG)((ULONG_PTR)HbaIoBase + Register));
}
FORCEINLINE
VOID
AHCI_HBA_WRITE(
_In_ PULONG 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_ PULONG PortIoBase,
_In_ AHCI_PORT_REGISTER Register)
{
return READ_REGISTER_ULONG((PULONG)((ULONG_PTR)PortIoBase + Register));
}
FORCEINLINE
VOID
AHCI_PORT_WRITE(
_In_ PULONG PortIoBase,
_In_ AHCI_PORT_REGISTER Register,
_In_ ULONG Value)
{
WRITE_REGISTER_ULONG((PULONG)((ULONG_PTR)PortIoBase + Register), Value);
}

View File

@ -0,0 +1,654 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: ATA header file
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
#define ATA_MAX_LBA_28 0x0FFFFFFFULL
/* Master/Slave devices */
#define CHANNEL_PCAT_MAX_DEVICES 2
/* Master/Slave devices for Bank 0 and Bank 1 */
#define CHANNEL_PC98_MAX_DEVICES 4
#define SRB_FLAG_INTERNAL 0x00000001
#define SRB_FLAG_PACKET_COMMAND 0x00000002
#define SRB_FLAG_POLL 0x00000008
#define SRB_FLAG_RETRY 0x00000010
#define SRB_FLAG_DEVICE_CHECK SRB_FLAG_INTERNAL
#define SRB_FLAGS_PASSTHROUGH 0x08000000
#define SRB_SET_FLAG(Srb, Flags) \
((Srb)->SrbExtension = (PVOID)((ULONG_PTR)(Srb)->SrbExtension | (Flags)))
#define SRB_CLEAR_FLAGS(Srb, Flags) \
((Srb)->SrbExtension = (PVOID)((ULONG_PTR)(Srb)->SrbExtension & ~(Flags)))
#define SRB_GET_FLAGS(Srb) \
((ULONG_PTR)(Srb)->SrbExtension)
#define QUEUE_ENTRY_FROM_IRP(Irp) \
((PREQUEST_QUEUE_ENTRY)&(((PIRP)(Irp))->Tail.Overlay.DriverContext[0]))
#define IRP_FROM_QUEUE_ENTRY(QueueEntry) \
CONTAINING_RECORD(QueueEntry, IRP, Tail.Overlay.DriverContext[0])
#define ATA_IO_WAIT() \
KeStallExecutionProcessor(1)
#define CMD_FLAG_NONE 0x00000000
#define CMD_FLAG_AWAIT_INTERRUPT 0x80000000
#define CMD_FLAG_REQUEST_MASK 0x00000003
#define CMD_FLAG_CDB 0x00000004
#define CMD_FLAG_READ_TASK_FILE 0x00000008
#define CMD_FLAG_DATA_IN 0x00000040
#define CMD_FLAG_DATA_OUT 0x00000080
#define CMD_FLAG_ATAPI_REQUEST 0x00000001
#define CMD_FLAG_ATA_REQUEST 0x00000002
#define CMD_FLAG_DMA_TRANSFER 0x00000003
C_ASSERT(CMD_FLAG_DATA_IN == SRB_FLAGS_DATA_IN);
C_ASSERT(CMD_FLAG_DATA_OUT == SRB_FLAGS_DATA_OUT);
/* Ignore the REL and Tag bits */
#define ATAPI_INTERRUPT_REASON_MASK 0x03
#define ATAPI_INTERRUPT_REASON_INVALID 0x00
#define ATAPI_INTERRUPT_REASON_CMD_COMPLETION 0x03
#define ATAPI_INTERRUPT_REASON_DATA_OUT 0x08
#define ATAPI_INTERRUPT_REASON_AWAIT_CDB 0x09
#define ATAPI_INTERRUPT_REASON_DATA_IN 0x0A
#define ATA_TIME_BUSY_SELECT 2000 /* 20 ms */
#define ATA_TIME_BUSY_NORMAL 200000
#define ATA_TIME_BUSY_ISR 3
#define ATA_TIME_BUSY_POLL 5
#define ATA_TIME_DRQ_NORMAL 100000
#define ATA_TIME_DRQ_ISR 1000
#define IDE_DRIVE_SELECT 0xA0
#define IDE_HIGH_ORDER_BYTE 0x80
#define IDE_ERROR_WRITE_PROTECT 0x40
FORCEINLINE
UCHAR
ATA_READ(
_In_ PUCHAR Port)
{
return READ_PORT_UCHAR(Port);
}
FORCEINLINE
VOID
ATA_WRITE(
_In_ PUCHAR Port,
_In_ UCHAR Value)
{
WRITE_PORT_UCHAR(Port, Value);
}
#define ATA_WRITE_ULONG(Port, Value) \
WRITE_PORT_ULONG(Port, Value)
FORCEINLINE
VOID
ATA_WRITE_BLOCK_16(
_In_ PUSHORT Port,
_In_ PUSHORT Buffer,
_In_ ULONG Count)
{
ASSERT(Buffer);
ASSERT(Count);
WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
FORCEINLINE
VOID
ATA_WRITE_BLOCK_32(
_In_ PULONG Port,
_In_ PULONG Buffer,
_In_ ULONG Count)
{
ASSERT(Buffer);
ASSERT(Count);
WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
FORCEINLINE
VOID
ATA_READ_BLOCK_16(
_In_ PUSHORT Port,
_In_ PUSHORT Buffer,
_In_ ULONG Count)
{
ASSERT(Buffer);
ASSERT(Count);
READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
}
FORCEINLINE
VOID
ATA_READ_BLOCK_32(
_In_ PULONG Port,
_In_ PULONG Buffer,
_In_ ULONG Count)
{
ASSERT(Buffer);
ASSERT(Count);
READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
}
#if defined(_M_IX86)
FORCEINLINE
VOID
ATA_SELECT_BANK(
_In_ UCHAR Number)
{
ASSERT((Number & ~1) == 0);
/* The 0x432 port is used to select the primary or secondary IDE channel */
WRITE_PORT_UCHAR((PUCHAR)0x432, Number);
}
#endif
FORCEINLINE
VOID
ATA_SELECT_DEVICE(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ UCHAR DeviceHead)
{
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
{
ATA_SELECT_BANK((DeviceHead >> 1) & 1);
}
#endif
ATA_WRITE(ChannelExtension->Registers.DriveSelect, DeviceHead & 0xF8);
ATA_IO_WAIT();
}
FORCEINLINE
VOID
ATA_WAIT_ON_BUSY(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_Inout_ PUCHAR Status,
_In_ ULONG Timeout)
{
ULONG i;
if (!(*Status & IDE_STATUS_BUSY))
return;
for (i = 0; i < Timeout; ++i)
{
KeStallExecutionProcessor(10);
*Status = ATA_READ(ChannelExtension->Registers.Status);
if (!(*Status & IDE_STATUS_BUSY))
break;
if (*Status == 0xFF)
break;
}
}
FORCEINLINE
VOID
ATA_WAIT_FOR_DRQ(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_Inout_ PUCHAR Status,
_In_ UCHAR Mask,
_In_ ULONG Timeout)
{
ULONG i;
if (*Status & IDE_STATUS_DRQ)
return;
for (i = 0; i < Timeout; ++i)
{
KeStallExecutionProcessor(10);
*Status = ATA_READ(ChannelExtension->Registers.Status);
if (!(*Status & IDE_STATUS_BUSY))
{
if (*Status & (IDE_STATUS_DRQ | Mask))
return;
if (*Status == 0xFF)
break;
}
}
}
FORCEINLINE
ATA_DEVICE_CLASS
AtaPdoGetDeviceClass(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
if (IS_ATAPI(DeviceExtension))
return DEV_ATAPI;
return DEV_ATA;
}
FORCEINLINE
BOOLEAN
AtaPdoSerialNumberValid(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
return (DeviceExtension->SerialNumber[0] != ANSI_NULL);
}
FORCEINLINE
ULONG
AtaFdoMaxDeviceCount(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
return CHANNEL_PC98_MAX_DEVICES;
else
#endif
return CHANNEL_PCAT_MAX_DEVICES;
}
FORCEINLINE
UCHAR
AtaReadWriteCommand(
_In_ PATA_DEVICE_REQUEST Request,
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
ULONG CmdEntry;
CmdEntry = (Request->Flags & REQUEST_FLAG_DATA_IN) ? 3 : 0;
if (Request->Flags & REQUEST_FLAG_FUA)
{
CmdEntry += 6;
}
if (Request->Flags & REQUEST_FLAG_DMA_ENABLED)
{
CmdEntry += 2;
}
else
{
if (Request->Flags & REQUEST_FLAG_READ_WRITE_MULTIPLE)
{
CmdEntry += 1;
}
}
return AtapAtaCommand[CmdEntry][(Request->Flags & REQUEST_FLAG_LBA48) ? 1 : 0];
}
FORCEINLINE
BOOLEAN
AtaAtapiUseDma(
_In_ UCHAR OpCode)
{
return (OpCode == SCSIOP_READ6 ||
OpCode == SCSIOP_WRITE6 ||
OpCode == SCSIOP_READ ||
OpCode == SCSIOP_WRITE ||
OpCode == SCSIOP_READ12 ||
OpCode == SCSIOP_WRITE12 ||
OpCode == SCSIOP_READ16 ||
OpCode == SCSIOP_WRITE16);
}
FORCEINLINE
BOOLEAN
AtaReadWriteUseLba48(
_In_ ULONG64 SectorNumber,
_In_ ULONG SectorCount)
{
/* Use the 48-bit command when reasonable */
return (((SectorNumber + SectorCount) >= ATA_MAX_LBA_28) || (SectorCount > 0x100));
}
FORCEINLINE
BOOLEAN
AtaDeviceHasCdbInterrupt(
_In_ PIDENTIFY_PACKET_DATA IdentifyPacketData)
{
/* Bits 5:6 of word 0 */
return (IdentifyPacketData->GeneralConfiguration.DrqDelay == 1);
}
FORCEINLINE
UCHAR
AtaDeviceCdbSizeInWords(
_In_ PIDENTIFY_PACKET_DATA IdentifyPacketData)
{
/* Bits 0:2 of word 0 */
return (IdentifyPacketData->GeneralConfiguration.PacketType != 0) ? 8 : 6;
}
FORCEINLINE
BOOLEAN
AtaDeviceMaxLun(
_In_ PIDENTIFY_PACKET_DATA IdentifyPacketData)
{
/* Bits 0:2 of word 126 */
USHORT LastLunIdentifier = IdentifyPacketData->ReservedWord126 & 7;
/*
* Make sure this field has no value that represents all bits set.
* We perform additional validation because
* most ATAPI devices ignore the LUN field in the CDB and respond to each LUN.
*/
if (LastLunIdentifier != 7)
return LastLunIdentifier + 1;
return 1;
}
FORCEINLINE
BOOLEAN
AtaDeviceSerialNumberValid(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Some ancient IDE drives return the empty serial number */
return (IdentifyData->SerialNumber[0] != ' ' &&
IdentifyData->SerialNumber[0] != ANSI_NULL);
}
FORCEINLINE
BOOLEAN
AtaHas48BitAddressFeature(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 83: 15 = 0, 14 = 1 */
if (IdentifyData->CommandSetSupport.WordValid83 == 1)
{
/* Bits 10 of word 83 */
return IdentifyData->CommandSetSupport.BigLba;
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaCurrentGeometryValid(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
return ((IdentifyData->TranslationFieldsValid & 1) &&
(IdentifyData->NumberOfCurrentCylinders != 0) &&
(IdentifyData->NumberOfCurrentCylinders <= 63) &&
(IdentifyData->NumberOfCurrentHeads != 0) &&
(IdentifyData->NumberOfCurrentHeads <= 16) &&
(IdentifyData->CurrentSectorsPerTrack != 0));
}
FORCEINLINE
UCHAR
AtaMaximumSectorsPerDrq(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
UCHAR MultiSectorMax;
/* The word 47 should be a power of 2 */
MultiSectorMax = IdentifyData->MaximumBlockTransfer;
if ((MultiSectorMax > 0) && ((MultiSectorMax & (MultiSectorMax - 1)) == 0))
return MultiSectorMax;
return 0;
}
FORCEINLINE
ULONG
AtaBytesPerLogicalSector(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 106: 15 = 0, 14 = 1, 12 = 1 */
if (IdentifyData->PhysicalLogicalSectorSize.Reserved1 == 1 &&
IdentifyData->PhysicalLogicalSectorSize.LogicalSectorLongerThan256Words)
{
/* Words 116-117 */
return (((ULONG)IdentifyData->WordsPerLogicalSector[1] << 16) |
IdentifyData->WordsPerLogicalSector[0]) * sizeof(USHORT);
}
/* 256 words = 512 bytes */
return 256 * sizeof(USHORT);
}
FORCEINLINE
ULONG
AtaLogicalSectorsPerPhysicalSector(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData,
_Out_ PULONG Exponent)
{
/* Word 106: 15 = 0, 14 = 1, 13 = 1 */
if (IdentifyData->PhysicalLogicalSectorSize.Reserved1 == 1 &&
IdentifyData->PhysicalLogicalSectorSize.MultipleLogicalSectorsPerPhysicalSector)
{
/* Bits 0:3 of word 106 */
*Exponent = IdentifyData->PhysicalLogicalSectorSize.LogicalSectorsPerPhysicalSector;
return 1 << *Exponent;
}
*Exponent = 0;
return 1 << 0;
}
FORCEINLINE
ULONG
AtaLogicalSectorAlignment(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 209: 15 = 0, 14 = 1 */
if (IdentifyData->BlockAlignment.Word209Supported &&
IdentifyData->BlockAlignment.Reserved0 == 0)
{
/* Bits 0:13 of word 209 */
return IdentifyData->BlockAlignment.AlignmentOfLogicalWithinPhysical;
}
return 0;
}
FORCEINLINE
BOOLEAN
AtaDeviceInPuisState(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 2 of word 0 */
if (IdentifyData->GeneralConfiguration.ResponseIncomplete)
{
/* Word 2 */
if (IdentifyData->SpecificConfiguration == 0x37C8 ||
IdentifyData->SpecificConfiguration == 0x738C)
{
return TRUE;
}
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaDeviceIsRemovable(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 7 of word 0 */
return IdentifyData->GeneralConfiguration.RemovableMedia;
}
FORCEINLINE
BOOLEAN
AtaDeviceHasRemovableMediaStatusNotificationFeature(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 127: bit 0 = 1, bit 1 = 0 */
return (IdentifyData->MsnSupport == 1);
}
FORCEINLINE
BOOLEAN
AtaDeviceHasIeee1667(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
// TODO: verify word 48
/* Bit 0 of word 48 */
if (IdentifyData->TrustedComputing.FeatureSupported)
{
/* Bit 7 of word 69 */
return IdentifyData->AdditionalSupported.IEEE1667;
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaDeviceHasWorldWideName(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 87: 15 = 0, 14 = 1 */
if (IdentifyData->CommandSetActive.Reserved4 == 1)
{
/* Bit 8 of word 87 */
return IdentifyData->CommandSetActive.WWN64Bit;
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaDeviceIsZonedDevice(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bits 0:1 of word 69 */
return (IdentifyData->AdditionalSupported.ZonedCapabilities != 0);
}
FORCEINLINE
BOOLEAN
AtaDeviceHasSmartFeature(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 0 of word 82 */
return IdentifyData->CommandSetSupport.SmartCommands;
}
FORCEINLINE
BOOLEAN
AtaDeviceIsVolatileWriteCacheEnabled(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 83: 15 = 0, 14 = 1 */
if (IdentifyData->CommandSetSupport.WordValid == 1)
{
/* Bit 5 of word 82 and bit 5 of word 85 */
return (IdentifyData->CommandSetSupport.WriteCache &&
IdentifyData->CommandSetActive.WriteCache);
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaDeviceIsReadLookAHeadEnabled(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 83: 15 = 0, 14 = 1 */
if (IdentifyData->CommandSetSupport.WordValid == 1)
{
/* Bit 6 of word 82 and bit 6 of word 85 */
return (IdentifyData->CommandSetSupport.LookAhead &&
IdentifyData->CommandSetActive.LookAhead);
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaDeviceIsRotatingDevice(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 217 */
return (IdentifyData->NominalMediaRotationRate >= 0x0401 &&
IdentifyData->NominalMediaRotationRate <= 0xFFFE);
}
FORCEINLINE
BOOLEAN
AtaDeviceIsSsd(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 217 */
return (IdentifyData->NominalMediaRotationRate == 1);
}
FORCEINLINE
BOOLEAN
AtaHasTrimFunction(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 0 of word 169 */
return IdentifyData->DataSetManagementFeature.SupportsTrim;
}
FORCEINLINE
BOOLEAN
AtaHasRzatFunction(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 5 of word 69 */
return IdentifyData->AdditionalSupported.ReadZeroAfterTrimSupported;
}
FORCEINLINE
BOOLEAN
AtaHasDratFunction(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 14 of word 69 */
return IdentifyData->AdditionalSupported.DeterministicReadAfterTrimSupported;
}
FORCEINLINE
BOOLEAN
AtaHasForceUnitAccessCommands(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Word 84: 15 = 0, 14 = 1 */
if (IdentifyData->CommandSetSupport.WordValid == 1)
{
/* Bit 6 of word 84 */
return IdentifyData->CommandSetSupport.WriteFua;
}
return FALSE;
}
FORCEINLINE
BOOLEAN
AtaStandybyTimerPeriodsValid(
_In_ PIDENTIFY_DEVICE_DATA IdentifyData)
{
/* Bit 13 of word 49 */
return IdentifyData->Capabilities.StandybyTimerSupport;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "ATAPI IDE Miniport Driver"
#define REACTOS_STR_FILE_DESCRIPTION "ATA Port Driver"
#define REACTOS_STR_INTERNAL_NAME "atapi"
#define REACTOS_STR_ORIGINAL_FILENAME "atapi.sys"
#include <reactos/version.rc>

View File

@ -0,0 +1,9 @@
; ATA Port Driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","ErrorControl",0x00010001,0x00000003
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","Group",0x00000000,"SCSI Miniport"
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","ImagePath",0x00020000,"system32\drivers\atapi.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","Start",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\atapi","Tag",0x00010001,0x00000021
HKLM,"SYSTEM\CurrentControlSet\Services\atapi\Parameters","LegacyDetection",0x00010001,0x00000001

View File

@ -0,0 +1,88 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Global pageable data
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
const WCHAR* const AtapTargetToDeviceTypeKey[] =
{
L"MasterDeviceType", L"SlaveDeviceType",
#if defined(_M_IX86)
L"MasterDeviceType2", L"SlaveDeviceType2"
#endif
};
static
const ATAPORT_DEVICE_NAME AtapGenericDeviceNames[] =
{
/* Device Type Generic Type Peripheral ID */
{"Disk", "GenDisk", "DiskPeripheral" }, // DIRECT_ACCESS_DEVICE
{"Sequential", "GenSequential", "TapePeripheral" }, // SEQUENTIAL_ACCESS_DEVICE
{"Printer", "GenPrinter", "PrinterPeripheral" }, // PRINTER_DEVICE
/* There is no 'ProcessorPeripheral' */
{"Processor", "GenProcessor", "OtherPeripheral" }, // PROCESSOR_DEVICE
{"Worm", "GenWorm", "WormPeripheral" }, // WRITE_ONCE_READ_MULTIPLE_DEVICE
{"CdRom", "GenCdRom", "CdRomPeripheral" }, // READ_ONLY_DIRECT_ACCESS_DEVICE
{"Scanner", "GenScanner", "ScannerPeripheral" }, // SCANNER_DEVICE
{"Optical", "GenOptical", "OpticalDiskPeripheral" }, // OPTICAL_DEVICE
{"Changer", "GenChanger", "MediumChangerPeripheral" }, // MEDIUM_CHANGER
{"Net", "GenNet", "CommunicationsPeripheral" }, // COMMUNICATION_DEVICE,
{"Other", "GenOther", "OtherPeripheral" }, // 10
};
const CHAR* const AtapBrokenInquiryDrive[] =
{
"THOMSON-DVD",
"PHILIPS XBOX DVD DRIVE",
"PHILIPS J5 3235C",
"SAMSUNG DVD-ROM SDG-605B"
};
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
PCSTR
AtaTypeCodeToName(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ DEVICE_TYPE_NAME Type)
{
UCHAR DeviceType = DeviceExtension->InquiryData.DeviceType;
PAGED_CODE();
switch (Type)
{
case GetDeviceType:
{
if (DeviceType < RTL_NUMBER_OF(AtapGenericDeviceNames))
return AtapGenericDeviceNames[DeviceType].DeviceType;
else
return "Other";
}
case GetGenericType:
{
if (DeviceExtension->Flags & DEVICE_IS_SUPER_FLOPPY)
return "GenSFloppy";
else if (DeviceType < RTL_NUMBER_OF(AtapGenericDeviceNames))
return AtapGenericDeviceNames[DeviceType].GenericType;
else
return "IdeOther";
}
case GetPeripheralId:
{
if (DeviceType < RTL_NUMBER_OF(AtapGenericDeviceNames))
return AtapGenericDeviceNames[DeviceType].PeripheralId;
else
return "OtherPeripheral";
}
DEFAULT_UNREACHABLE;
}
}

View File

@ -0,0 +1,72 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Debug support header file
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
#pragma once
#ifndef __RELFILE__
#define __RELFILE__ __FILE__
#endif
#if DBG
// #define DEBUG_TRACE
// #define DEBUG_INFO
#define DEBUG_WARN
#define DEBUG_ERR
#ifdef DEBUG_TRACE
#define TRACE(fmt, ...) \
do { \
if (DbgPrint("(%s:%d) %s " fmt, __RELFILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)) \
DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \
} while (0)
#else
#define TRACE
#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
#define INFO
#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
#define WARN
#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
#define ERR
#endif
#else
#define TRACE
#define INFO
#define WARN
#define ERR
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,915 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: ATA channel device object (FDO) dispatch routines
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
static const WCHAR AtapDevSymLinkFormat[] = L"\\Device\\ScsiPort%lu";
static const WCHAR AtapDosSymLinkFormat[] = L"\\DosDevices\\Scsi%lu:";
static KSYNCHRONIZE_ROUTINE AtaFdoEnableInterruptsSync;
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
VOID
AtaFdoClaimLegacyAddressRanges(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
PAGED_CODE();
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
{
/* On NEC PC-98 systems we have at least four PDOs in use for the legacy IDE interface */
ConfigInfo->AtDiskPrimaryAddressClaimed =
ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
ChannelExtension->Flags |= CHANNEL_PRIMARY_ADDRESS_CLAIMED |
CHANNEL_SECONDARY_ADDRESS_CLAIMED;
}
else
#endif
if (ChannelExtension->CommandPortBase == (PVOID)0x1F0)
{
ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
ChannelExtension->Flags |= CHANNEL_PRIMARY_ADDRESS_CLAIMED;
}
else if (ChannelExtension->CommandPortBase == (PVOID)0x170)
{
ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
ChannelExtension->Flags |= CHANNEL_SECONDARY_ADDRESS_CLAIMED;
}
}
static
CODE_SEG("PAGE")
VOID
AtaFdoReleaseLegacyAddressRanges(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
PAGED_CODE();
if (ChannelExtension->Flags & CHANNEL_PRIMARY_ADDRESS_CLAIMED)
ConfigInfo->AtDiskPrimaryAddressClaimed = FALSE;
if (ChannelExtension->Flags & CHANNEL_SECONDARY_ADDRESS_CLAIMED)
ConfigInfo->AtDiskSecondaryAddressClaimed = FALSE;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoCreateSymLinks(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
UNICODE_STRING ChannelName;
ULONG ScsiAdapter, ScsiPortCount;
WCHAR ChannelNameBuffer[sizeof("\\Device\\Ide\\IdePort999")];
NTSTATUS Status;
static const WCHAR IdeChannelFormat[] = L"\\Device\\Ide\\IdePort%lu";
PAGED_CODE();
Status = RtlStringCbPrintfW(ChannelNameBuffer,
sizeof(ChannelNameBuffer),
IdeChannelFormat,
ChannelExtension->ChannelNumber);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&ChannelName, ChannelNameBuffer);
ScsiPortCount = IoGetConfigurationInformation()->ScsiPortCount;
/* Search for a free SCSI port adapter in the system */
for (ScsiAdapter = 0; ScsiAdapter <= ScsiPortCount; ++ScsiAdapter)
{
WCHAR SymLinkNameBuffer[sizeof("\\DosDevices\\Scsi999:")];
UNICODE_STRING SymLinkName;
Status = RtlStringCbPrintfW(SymLinkNameBuffer,
sizeof(SymLinkNameBuffer),
AtapDevSymLinkFormat,
ScsiAdapter);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&SymLinkName, SymLinkNameBuffer);
/* Create a symbolic link '\Device\ScsiPortX' -> '\Device\Ide\IdePortN' */
Status = IoCreateSymbolicLink(&SymLinkName, &ChannelName);
if (NT_SUCCESS(Status))
{
INFO("Symlink created '%wZ' -> '%wZ'\n", &SymLinkName, &ChannelName);
Status = RtlStringCbPrintfW(SymLinkNameBuffer,
sizeof(SymLinkNameBuffer),
AtapDosSymLinkFormat,
ScsiAdapter);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&SymLinkName, SymLinkNameBuffer);
/* Create a symbolic link '\DosDevices\ScsiX:' -> '\Device\Ide\IdePortN' */
Status = IoCreateSymbolicLink(&SymLinkName, &ChannelName);
if (NT_SUCCESS(Status))
{
INFO("Symlink created '%wZ' -> '%wZ'\n", &SymLinkName, &ChannelName);
}
/* Register ourselves (ATA channel) as a SCSI port adapter */
++IoGetConfigurationInformation()->ScsiPortCount;
ChannelExtension->PortNumber = ScsiAdapter;
ChannelExtension->Flags |= CHANNEL_SYMLINK_CREATED;
break;
}
}
return Status;
}
static
CODE_SEG("PAGE")
VOID
AtaFdoRemoveSymLinks(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
NTSTATUS Status;
UNICODE_STRING SymLinkName;
WCHAR SymLinkNameBuffer[sizeof("\\DosDevices\\Scsi999:")];
PAGED_CODE();
if (!(ChannelExtension->Flags & CHANNEL_SYMLINK_CREATED))
return;
/* Delete the '\DosDevices\\ScsiX:' symbolic link */
Status = RtlStringCbPrintfW(SymLinkNameBuffer,
sizeof(SymLinkNameBuffer),
AtapDevSymLinkFormat,
ChannelExtension->PortNumber);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&SymLinkName, SymLinkNameBuffer);
(VOID)IoDeleteSymbolicLink(&SymLinkName);
/* Delete the '\Device\\ScsiPortX' symbolic link */
Status = RtlStringCbPrintfW(SymLinkNameBuffer,
sizeof(SymLinkNameBuffer),
AtapDosSymLinkFormat,
ChannelExtension->PortNumber);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&SymLinkName, SymLinkNameBuffer);
(VOID)IoDeleteSymbolicLink(&SymLinkName);
/* Unregister the SCSI port adapter */
--IoGetConfigurationInformation()->ScsiPortCount;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoQueryInterface(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ const GUID* Guid,
_Out_ PVOID Interface,
_In_ ULONG Size)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
PAGED_CODE();
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
ChannelExtension->Ldo,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (!Irp)
return STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
IoStack->Parameters.QueryInterface.InterfaceType = Guid;
IoStack->Parameters.QueryInterface.Size = Size;
IoStack->Parameters.QueryInterface.Version = 1;
IoStack->Parameters.QueryInterface.Interface = Interface;
IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(ChannelExtension->Ldo, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
return Status;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoParseResources(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PCM_RESOURCE_LIST ResourcesTranslated)
{
PIDE_REGISTERS Registers = &ChannelExtension->Registers;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CommandPortDescriptor = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ControlPortDescriptor = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDescriptor = NULL;
PVOID IoBase;
ULONG i, Spare;
PAGED_CODE();
if (!ResourcesTranslated)
return STATUS_INSUFFICIENT_RESOURCES;
for (i = 0; i < ResourcesTranslated->List[0].PartialResourceList.Count; ++i)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
Descriptor = &ResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
switch (Descriptor->Type)
{
case CmResourceTypePort:
case CmResourceTypeMemory:
{
C_ASSERT(FIELD_OFFSET(CM_PARTIAL_RESOURCE_DESCRIPTOR, u.Port.Length) ==
FIELD_OFFSET(CM_PARTIAL_RESOURCE_DESCRIPTOR, u.Memory.Length));
switch (Descriptor->u.Port.Length)
{
case 1:
{
/*
* Note that on PC-98 systems we still need to support PCI IDE controllers
* with a different register layout. The NEC PC-98 legacy IDE interface
* can coexist with a normal PCI IDE controller.
*/
if (IsNEC_98 &&
ResourcesTranslated->List[0].PartialResourceList.Count >= 12)
{
if ((Descriptor->u.Port.Start.QuadPart == (ULONG64)0x640))
{
CommandPortDescriptor = Descriptor;
ChannelExtension->Flags |= CHANNEL_CBUS_IDE;
}
else if ((Descriptor->u.Port.Start.QuadPart == (ULONG64)0x74C))
{
ControlPortDescriptor = Descriptor;
ChannelExtension->Flags |= CHANNEL_CBUS_IDE;
}
}
else if (!ControlPortDescriptor)
{
ControlPortDescriptor = Descriptor;
}
break;
}
case 8:
{
if (!CommandPortDescriptor)
CommandPortDescriptor = Descriptor;
break;
}
default:
break;
}
break;
}
case CmResourceTypeInterrupt:
{
if (!InterruptDescriptor)
InterruptDescriptor = Descriptor;
break;
}
default:
break;
}
}
if (!CommandPortDescriptor || !ControlPortDescriptor || !InterruptDescriptor)
return STATUS_DEVICE_CONFIGURATION_ERROR;
/* Command port base */
if ((CommandPortDescriptor->Type == CmResourceTypePort) &&
(CommandPortDescriptor->Flags & CM_RESOURCE_PORT_IO))
{
IoBase = (PVOID)(ULONG_PTR)CommandPortDescriptor->u.Port.Start.QuadPart;
}
else
{
ASSERT(!(ChannelExtension->Flags & CHANNEL_CBUS_IDE));
IoBase = MmMapIoSpace(CommandPortDescriptor->u.Memory.Start, 8, MmNonCached);
if (!IoBase)
return STATUS_INSUFFICIENT_RESOURCES;
ChannelExtension->Flags |= CHANNEL_COMMAND_PORT_BASE_MAPPED;
}
ChannelExtension->CommandPortBase =
(PVOID)(ULONG_PTR)CommandPortDescriptor->u.Port.Start.QuadPart;
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
{
Spare = 2;
}
else
#endif
{
Spare = 1;
}
Registers->Data = IoBase;
Registers->Error = (PVOID)((ULONG_PTR)IoBase + 1 * Spare);
Registers->SectorCount = (PVOID)((ULONG_PTR)IoBase + 2 * Spare);
Registers->LowLba = (PVOID)((ULONG_PTR)IoBase + 3 * Spare);
Registers->MidLba = (PVOID)((ULONG_PTR)IoBase + 4 * Spare);
Registers->HighLba = (PVOID)((ULONG_PTR)IoBase + 5 * Spare);
Registers->DriveSelect = (PVOID)((ULONG_PTR)IoBase + 6 * Spare);
Registers->Status = (PVOID)((ULONG_PTR)IoBase + 7 * Spare);
/* Control port base */
if ((ControlPortDescriptor->Type == CmResourceTypePort) &&
(ControlPortDescriptor->Flags & CM_RESOURCE_PORT_IO))
{
IoBase = (PVOID)(ULONG_PTR)ControlPortDescriptor->u.Port.Start.QuadPart;
}
else
{
ASSERT(!(ChannelExtension->Flags & CHANNEL_CBUS_IDE));
IoBase = MmMapIoSpace(ControlPortDescriptor->u.Memory.Start, 1, MmNonCached);
if (!IoBase)
return STATUS_INSUFFICIENT_RESOURCES;
ChannelExtension->Flags |= CHANNEL_CONTROL_PORT_BASE_MAPPED;
}
ChannelExtension->ControlPortBase =
(PVOID)(ULONG_PTR)ControlPortDescriptor->u.Port.Start.QuadPart;
Registers->Control = (PVOID)IoBase;
/* Interrupt */
ChannelExtension->InterruptVector = InterruptDescriptor->u.Interrupt.Vector;
ChannelExtension->InterruptLevel = InterruptDescriptor->u.Interrupt.Level;
ChannelExtension->InterruptAffinity = InterruptDescriptor->u.Interrupt.Affinity;
if (InterruptDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
ChannelExtension->InterruptMode = Latched;
else
ChannelExtension->InterruptMode = LevelSensitive;
if (InterruptDescriptor->ShareDisposition == CmResourceShareShared)
ChannelExtension->Flags |= CHANNEL_INTERRUPT_SHARED;
else
ChannelExtension->Flags &= ~CHANNEL_INTERRUPT_SHARED;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
VOID
AtaFdoFreeResources(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PAGED_CODE();
if (ChannelExtension->InterruptObject)
{
IoDisconnectInterrupt(ChannelExtension->InterruptObject);
ChannelExtension->InterruptObject = NULL;
}
if (ChannelExtension->Flags & CHANNEL_COMMAND_PORT_BASE_MAPPED)
{
ChannelExtension->Flags &= ~CHANNEL_COMMAND_PORT_BASE_MAPPED;
MmUnmapIoSpace(ChannelExtension->Registers.Data, 8);
}
if (ChannelExtension->Flags & CHANNEL_CONTROL_PORT_BASE_MAPPED)
{
ChannelExtension->Flags &= ~CHANNEL_CONTROL_PORT_BASE_MAPPED;
MmUnmapIoSpace(ChannelExtension->Registers.Control, 1);
}
}
static
BOOLEAN
NTAPI
AtaFdoEnableInterruptsSync(
_In_ PVOID SynchronizeContext)
{
PIDE_ENABLE_INTERRUPTS_CONTEXT Context = SynchronizeContext;
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context->ChannelExtension;
UCHAR Command;
Command = Context->Enable ? IDE_DC_REENABLE_CONTROLLER : IDE_DC_DISABLE_INTERRUPTS;
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
{
ATA_SELECT_BANK(1);
ATA_WRITE(ChannelExtension->Registers.Control, Command);
ATA_SELECT_BANK(0);
}
#endif
ATA_WRITE(ChannelExtension->Registers.Control, Command);
return TRUE;
}
static
CODE_SEG("PAGE")
VOID
AtaFdoEnableInterrupts(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ BOOLEAN Enable)
{
IDE_ENABLE_INTERRUPTS_CONTEXT SynchronizeContext;
PAGED_CODE();
SynchronizeContext.ChannelExtension = ChannelExtension;
SynchronizeContext.Enable = Enable;
KeSynchronizeExecution(ChannelExtension->InterruptObject,
AtaFdoEnableInterruptsSync,
&SynchronizeContext);
}
static
CODE_SEG("PAGE")
VOID
AtaFdoInitializeMemory(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PSCSI_REQUEST_BLOCK Srb;
PIRP Irp;
ATA_SRB_TYPE i;
PAGED_CODE();
for (i = 0; i < SRB_TYPE_MAX; ++i)
{
Srb = &ChannelExtension->InternalSrb[i];
Irp = &ChannelExtension->InternalIrp[i];
Srb->OriginalRequest = Irp;
}
}
CODE_SEG("PAGE")
NTSTATUS
AtaFdoStartDevice(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PCM_RESOURCE_LIST ResourcesTranslated)
{
NTSTATUS Status;
PKSERVICE_ROUTINE IsrHandler;
PAGED_CODE();
INFO("Starting channel %lu\n", ChannelExtension->ChannelNumber);
ChannelExtension->MaximumTransferLength = ATA_MAX_TRANSFER_LENGTH;
/* Get the interface of the AHCI Port */
Status = AtaFdoQueryInterface(ChannelExtension,
&GUID_AHCI_PORT_INTERFACE,
&ChannelExtension->AhciPortInterface,
sizeof(ChannelExtension->AhciPortInterface));
if (NT_SUCCESS(Status))
ChannelExtension->Flags |= CHANNEL_AHCI;
else
ChannelExtension->Flags &= ~CHANNEL_AHCI;
if (!IS_AHCI(ChannelExtension))
{
/* Get the interface of the PCI IDE controller */
Status = AtaFdoQueryInterface(ChannelExtension,
&GUID_PCIIDE_INTERFACE,
&ChannelExtension->PciIdeInterface,
sizeof(ChannelExtension->PciIdeInterface));
if (NT_SUCCESS(Status))
{
PPCIIDE_INTERFACE PciIdeInterface = &ChannelExtension->PciIdeInterface;
ChannelExtension->Flags |= CHANNEL_PCI_IDE;
ChannelExtension->MaximumTransferLength = PciIdeInterface->MaximumTransferLength;
}
else
{
ChannelExtension->Flags &= ~CHANNEL_PCI_IDE;
}
Status = AtaFdoParseResources(ChannelExtension, ResourcesTranslated);
if (!NT_SUCCESS(Status))
{
ERR("Failed to parse resources 0x%lx\n", Status);
return Status;
}
AtaFdoClaimLegacyAddressRanges(ChannelExtension);
}
AtaFdoInitializeMemory(ChannelExtension);
Status = AtaFdoCreateSymLinks(ChannelExtension);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create symbolic links 0x%lx\n", Status);
return Status;
}
/* Reserve memory resources early. Storage drivers should not fail paging I/O operations */
if (!ChannelExtension->ReservedVaSpace)
{
ChannelExtension->ReservedVaSpace =
MmAllocateMappingAddress(ATA_RESERVED_PAGES * PAGE_SIZE, IDEPORT_TAG);
}
/* Initialize the path ID value for legacy IDE channels */
if (ChannelExtension->PathId == (UCHAR)-1)
{
switch ((ULONG_PTR)ChannelExtension->CommandPortBase)
{
case 0x1F0: ChannelExtension->PathId = 0; break;
case 0x170: ChannelExtension->PathId = 1; break;
case 0x1E8: ChannelExtension->PathId = 2; break;
case 0x168: ChannelExtension->PathId = 3; break;
default:
{
#if defined(_M_IX86)
if (ChannelExtension->Flags & CHANNEL_CBUS_IDE)
ChannelExtension->PathId = 0;
else
#endif
ChannelExtension->PathId = ChannelExtension->ChannelNumber;
break;
}
}
}
ChannelExtension->MaximumTransferLength =
min(ChannelExtension->MaximumTransferLength, ATA_MAX_TRANSFER_LENGTH);
if (!IS_AHCI(ChannelExtension))
{
if (ChannelExtension->Flags & CHANNEL_PCI_IDE)
IsrHandler = AtaPciIdeChannelIsr;
else
IsrHandler = AtaIdeChannelIsr;
ChannelExtension->ServiceRoutine = IsrHandler;
Status = IoConnectInterrupt(&ChannelExtension->InterruptObject,
IsrHandler,
ChannelExtension,
NULL,
ChannelExtension->InterruptVector,
ChannelExtension->InterruptLevel,
ChannelExtension->InterruptLevel,
ChannelExtension->InterruptMode,
!!(ChannelExtension->Flags & CHANNEL_INTERRUPT_SHARED),
ChannelExtension->InterruptAffinity,
FALSE);
if (!NT_SUCCESS(Status))
{
ERR("Could not connect to interrupt %lu, status 0x%lx\n",
ChannelExtension->InterruptVector, Status);
return Status;
}
AtaFdoEnableInterrupts(ChannelExtension, TRUE);
}
IoInitializeTimer(ChannelExtension->Common.Self, AtaIoTimer, ChannelExtension);
IoStartTimer(ChannelExtension->Common.Self);
ChannelExtension->Flags |= CHANNEL_IO_TIMER_ACTIVE;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoStopDevice(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
if (!IS_AHCI(ChannelExtension))
{
AtaFdoEnableInterrupts(ChannelExtension, FALSE);
}
AtaFdoFreeResources(ChannelExtension);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
AtaFdoRemoveDevice(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp)
{
NTSTATUS Status;
PAGED_CODE();
if (ChannelExtension->Flags & CHANNEL_IO_TIMER_ACTIVE)
IoStopTimer(ChannelExtension->Common.Self);
AtaFdoRemoveSymLinks(ChannelExtension);
AtaFdoReleaseLegacyAddressRanges(ChannelExtension);
AtaFdoFreeResources(ChannelExtension);
if (ChannelExtension->ReservedVaSpace)
{
MmFreeMappingAddress(ChannelExtension->ReservedVaSpace, IDEPORT_TAG);
}
if (Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(ChannelExtension->Ldo, Irp);
IoReleaseRemoveLockAndWait(&ChannelExtension->RemoveLock, Irp);
}
IoDetachDevice(ChannelExtension->Ldo);
IoDeleteDevice(ChannelExtension->Common.Self);
return Status;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoQueryPnpDeviceState(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
if (ChannelExtension->Common.PageFiles ||
ChannelExtension->Common.HibernateFiles ||
ChannelExtension->Common.DumpFiles)
{
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoQueryDeviceUsageNotification(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
volatile LONG* Counter;
PAGED_CODE();
if (!NT_VERIFY(IoForwardIrpSynchronously(ChannelExtension->Ldo, 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 = &ChannelExtension->Common.PageFiles;
break;
case DeviceUsageTypeHibernation:
Counter = &ChannelExtension->Common.HibernateFiles;
break;
case DeviceUsageTypeDumpFile:
Counter = &ChannelExtension->Common.DumpFiles;
break;
default:
return Status;
}
IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoQueryId(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
NTSTATUS Status;
PAGED_CODE();
switch (IoStack->Parameters.QueryId.IdType)
{
case BusQueryHardwareIDs:
case BusQueryCompatibleIDs:
{
if (!NT_VERIFY(IoForwardIrpSynchronously(ChannelExtension->Ldo, Irp)))
{
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = Irp->IoStatus.Status;
/*
* We provide a generic identifier necessary to install the device
* in case our FDO is root-enumerated device.
*/
if (Status == STATUS_NOT_SUPPORTED)
{
static const WCHAR IdeGenericId[] = L"*PNP0600\0";
PWCHAR Buffer;
Buffer = ExAllocatePoolUninitialized(PagedPool, sizeof(IdeGenericId), IDEPORT_TAG);
if (!Buffer)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(Buffer, IdeGenericId, sizeof(IdeGenericId));
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
Status = STATUS_SUCCESS;
}
break;
}
default:
{
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(ChannelExtension->Ldo, Irp);
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
return Status;
}
}
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
AtaFdoPnp(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_Inout_ PIRP Irp)
{
NTSTATUS Status;
PIO_STACK_LOCATION IoStack;
PAGED_CODE();
Status = IoAcquireRemoveLock(&ChannelExtension->RemoveLock, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch (IoStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
if (!NT_VERIFY(IoForwardIrpSynchronously(ChannelExtension->Ldo, Irp)))
{
Status = STATUS_UNSUCCESSFUL;
goto CompleteIrp;
}
Status = Irp->IoStatus.Status;
if (!NT_SUCCESS(Status))
{
goto CompleteIrp;
}
Status = AtaFdoStartDevice(ChannelExtension,
IoStack->Parameters.
StartDevice.AllocatedResourcesTranslated);
goto CompleteIrp;
}
case IRP_MN_STOP_DEVICE:
Status = AtaFdoStopDevice(ChannelExtension, Irp);
break;
case IRP_MN_REMOVE_DEVICE:
return AtaFdoRemoveDevice(ChannelExtension, Irp);
case IRP_MN_QUERY_PNP_DEVICE_STATE:
Status = AtaFdoQueryPnpDeviceState(ChannelExtension, Irp);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
break;
Status = AtaFdoQueryBusRelations(ChannelExtension, Irp);
if (!NT_SUCCESS(Status))
{
goto CompleteIrp;
}
Irp->IoStatus.Status = Status;
break;
}
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
Status = AtaFdoQueryDeviceUsageNotification(ChannelExtension, Irp);
break;
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_ID:
return AtaFdoQueryId(ChannelExtension, Irp, IoStack);
default:
break;
}
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(ChannelExtension->Ldo, Irp);
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
return Status;
CompleteIrp:
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

View File

@ -0,0 +1,578 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: AHCI request handling
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* FUNCTIONS ******************************************************************/
#if DBG
VOID
AhciVerifyStart(
_In_ PULONG PortIoBase)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
ULONG PxTFD = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
ULONG PxSSTS = AHCI_PORT_READ(PortIoBase, PxSataStatus);
ULONG InterfacePm = (PxSSTS & AHCI_PXSSTS_IPM_MASK) >> AHCI_PXSSTS_SPD_SHIFT;
/* 10.3.1 */
ASSERT(!(OldValue & AHCI_PXCMD_CR));
ASSERT(OldValue & AHCI_PXCMD_FRE);
ASSERT(!(PxTFD & AHCI_PXTFD_STATUS_BUSY));
ASSERT(!(PxTFD & AHCI_PXTFD_STATUS_DRQ));
ASSERT(PxTFD & AHCI_PXCMD_FRE);
ASSERT(((PxSSTS & AHCI_PXSSTS_DET_MASK) == AHCI_PXSSTS_DET_DEVICE_PHY) ||
(InterfacePm == AHCI_PXSSTS_IPM_PARTIAL_PM) ||
(InterfacePm == AHCI_PXSSTS_IPM_SLUMBER_PM));
}
VOID
AhciVerifySpinUp(
_In_ PULONG PortIoBase,
_In_ BOOLEAN Enable)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
ULONG PxSCTL = AHCI_PORT_READ(PortIoBase, PxSataControl);
/* 5.3.2.3 */
ASSERT(!(OldValue & AHCI_PXCMD_ST));
/* 10.3.1 */
ASSERT(!(OldValue & AHCI_PXCMD_CR));
if (Enable)
{
/* 10.10.1 */
ASSERT((PxSCTL & AHCI_PXCTL_DET_MASK) == AHCI_PXCTL_DET_IDLE);
}
else
{
ULONG PxSSTS = AHCI_PORT_READ(PortIoBase, PxSataStatus);
/* 10.10.1 */
ASSERT((PxSCTL & AHCI_PXCTL_DET_MASK) != AHCI_PXCTL_DET_RESET);
ASSERT((PxSSTS & AHCI_PXSSTS_DET_MASK) == AHCI_PXSSTS_DET_IDLE);
}
}
VOID
AhciVerifyPowerOn(
_In_ PULONG PortIoBase)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
/* 5.3.2.3 */
ASSERT(!(OldValue & AHCI_PXCMD_ST));
/* 10.3.1 */
ASSERT(!(OldValue & AHCI_PXCMD_CR));
}
VOID
AhciVerifyCommandListOverride(
_In_ PULONG PortIoBase)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
ASSERT(!(OldValue & AHCI_PXCMD_ST));
}
VOID
AhciVerifyFisReceive(
_In_ PULONG PortIoBase,
_In_ BOOLEAN Enable)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
/* 5.3.2.3 */
ASSERT(!(OldValue & AHCI_PXCMD_ST));
if (!Enable)
{
ASSERT(!(OldValue & AHCI_PXCMD_CR));
}
}
VOID
AhciVerifyPmaEnable(
_In_ PULONG PortIoBase)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
/* 10.3.2 */
ASSERT(!(OldValue & AHCI_PXCMD_ST));
}
VOID
AhciVerifyDetChange(
_In_ PULONG PortIoBase,
_In_ ULONG Value)
{
ULONG OldValue = AHCI_PORT_READ(PortIoBase, PxSataControl);
ULONG CmdStatus = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
ASSERT(!(CmdStatus & AHCI_PXCMD_ST));
if ((Value ^ OldValue) & AHCI_PXCTL_DET_MASK)
{
/* 10.3.1 */
ASSERT(!(OldValue & AHCI_PXCMD_CR));
}
}
VOID
AhciVerifySactChange(
_In_ PULONG PortIoBase)
{
ULONG CmdStatus = AHCI_PORT_READ(PortIoBase, PxCmdStatus);
/* 3.3.13 */
ASSERT(CmdStatus & AHCI_PXCMD_ST);
}
#endif
BOOLEAN
NTAPI
AtaHbaIsr(
_In_ PKINTERRUPT Interrupt,
_In_ PVOID Context)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context;
ULONG InterruptStatus;
InterruptStatus = AHCI_HBA_READ(ChannelExtension->IoBase, HbaInterruptStatus);
INFO("HBA interrupt %08lx\n", InterruptStatus);
return TRUE;
}
VOID
NTAPI
AtaAhciPreparePrdTable(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_ PSCATTER_GATHER_LIST SgList,
_In_ PVOID Context)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context;
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
Request->SgList = SgList;
AtaReqDataTransferReady(ChannelExtension);
}
ULONG
AhciExecuteCommand(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
return SRB_STATUS_PENDING;
}
VOID
AhciPortEnumerate(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ ULONG PortNumber)
{
}
static
CODE_SEG("PAGE")
BOOLEAN
AhciPortAllocateMemory(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PATAPORT_AHCI_PORT_DATA PortData)
{
PDMA_OPERATIONS DmaOperations;
ULONG i, j, Slot, CommandSlots, Length;
ULONG CommandListSize, CommandTableLength, CommandTablesPerPage;
PVOID Buffer;
ULONG_PTR BufferVa;
ULONG64 BufferPa;
PHYSICAL_ADDRESS PhysicalAddress;
PAGED_CODE();
DmaOperations = ChannelExtension->AdapterObject->DmaOperations;
CommandSlots = ((ChannelExtension->AhciCapabilities & AHCI_CAP_NCS) >> 8) + 1;
CommandTableLength = FIELD_OFFSET(AHCI_COMMAND_TABLE,
PrdTable[ChannelExtension->MapRegisterCount]);
ASSERT(ChannelExtension->MapRegisterCount != 0 &&
ChannelExtension->MapRegisterCount <= AHCI_MAX_PRDT_ENTRIES);
/*
* See ATA_MAX_TRANSFER_LENGTH, currently the MapRegisterCount is restricted to
* a maximum of (0x20000 / PAGE_SIZE) + 1 = 33 pages.
* Each command table will require 128 + 16 * 33 + (128 - 1) = 783 kB 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));
/* Allocate shared memory for the command table */
for (i = CommandSlots, Slot = 0; i > 0; )
{
ULONG Count, Size;
Count = min(i, CommandTablesPerPage);
Size = (CommandTableLength + (AHCI_COMMAND_TABLE_ALIGNMENT - 1)) * Count;
Buffer = DmaOperations->AllocateCommonBuffer(ChannelExtension->AdapterObject,
Size,
&PhysicalAddress,
FALSE);
if (!Buffer)
return FALSE;
RtlZeroMemory(Buffer, Size);
PortData->CommandTableOriginal[Slot] = Buffer;
PortData->CommandTablePhysOriginal[Slot].QuadPart = PhysicalAddress.QuadPart;
BufferVa = (ULONG_PTR)Buffer;
BufferPa = PhysicalAddress.QuadPart;
/* Split the allocation into command tables */
for (j = 0; j < Count; ++j)
{
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 (!(ChannelExtension->AhciCapabilities & AHCI_CAP_S64A))
{
ASSERT((ULONG)(BufferPa >> 32) == 0);
}
PortData->CommandTable[Slot] = (PVOID)BufferVa;
PortData->CommandTablePhys[Slot] = BufferPa;
++Slot;
BufferVa += CommandTableLength;
BufferPa += CommandTableLength;
}
i -= Count;
}
CommandListSize = FIELD_OFFSET(AHCI_COMMAND_LIST, CommandHeader[CommandSlots]);
Length = CommandListSize + (AHCI_COMMAND_LIST_ALIGNMENT - 1);
if (TRUE) // TODO !FBS
{
/* Add the receive area structure (256 bytes) */
Length += sizeof(AHCI_RECEIVED_FIS_AREA);
/* The command list is 1024-byte aligned, which saves us some bytes of allocation size */
Length += ALIGN_UP_BY(CommandListSize, AHCI_RECEIVED_FIS_AREA_ALIGNMENT) - CommandListSize;
}
Buffer = DmaOperations->AllocateCommonBuffer(ChannelExtension->AdapterObject,
Length,
&PhysicalAddress,
FALSE);
if (!Buffer)
return FALSE;
RtlZeroMemory(Buffer, Length);
PortData->CommandListOriginal = Buffer;
PortData->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);
PortData->CommandList = (PVOID)BufferVa;
PortData->CommandListPhys = BufferPa;
BufferVa += CommandListSize;
BufferPa += CommandListSize;
/* Alignment requirement */
ASSERT((ULONG_PTR)PortData->CommandListPhys % AHCI_COMMAND_LIST_ALIGNMENT == 0);
/* Received FIS */
if (TRUE) // TODO !FBS
{
BufferVa = ALIGN_UP_BY(BufferVa, AHCI_RECEIVED_FIS_AREA_ALIGNMENT);
BufferPa = ALIGN_UP_BY(BufferPa, AHCI_RECEIVED_FIS_AREA_ALIGNMENT);
PortData->ReceivedFis = (PVOID)BufferVa;
PortData->ReceivedFisPhys = BufferPa;
/* Alignment requirement */
ASSERT((ULONG_PTR)PortData->ReceivedFisPhys % AHCI_RECEIVED_FIS_AREA_ALIGNMENT == 0);
}
else
{
/* The FBS receive area is 4kB, optimize the most common case */
if (AHCI_FBS_RECEIVE_AREA_SIZE == PAGE_SIZE)
{
/* Allocate a 4kB page which is also 4kB-aligned */
Length = PAGE_SIZE;
}
else
{
/* Some other architectures (e.g. ia64) use a different page size */
Length = AHCI_FBS_RECEIVE_AREA_SIZE + (AHCI_RECEIVED_FIS_AREA_FBS_ALIGNMENT - 1);
}
Buffer = DmaOperations->AllocateCommonBuffer(ChannelExtension->AdapterObject,
Length,
&PhysicalAddress,
FALSE);
if (!Buffer)
return FALSE;
RtlZeroMemory(Buffer, Length);
PortData->ReceivedFisOriginal = Buffer;
PortData->ReceivedFisPhysOriginal.QuadPart = PhysicalAddress.QuadPart;
BufferVa = (ULONG_PTR)Buffer;
BufferPa = PhysicalAddress.QuadPart;
if (AHCI_FBS_RECEIVE_AREA_SIZE != PAGE_SIZE)
{
BufferVa = ALIGN_UP_BY(BufferVa, AHCI_RECEIVED_FIS_AREA_FBS_ALIGNMENT);
BufferPa = ALIGN_UP_BY(BufferPa, AHCI_RECEIVED_FIS_AREA_FBS_ALIGNMENT);
}
PortData->ReceivedFis = (PVOID)BufferVa;
PortData->ReceivedFisPhys = BufferPa;
/* Alignment requirement */
ASSERT(BufferPa % AHCI_RECEIVED_FIS_AREA_FBS_ALIGNMENT == 0);
}
/* 32-bit DMA */
if (!(ChannelExtension->AhciCapabilities & AHCI_CAP_S64A))
{
ASSERT((ULONG)(PortData->CommandListPhys >> 32) == 0);
ASSERT((ULONG)(PortData->ReceivedFisPhys >> 32) == 0);
}
return TRUE;
}
static
CODE_SEG("PAGE")
BOOLEAN
AhciPortIdle(
_In_ PULONG PortRegisters)
{
ULONG i, CmdStatus;
PAGED_CODE();
CmdStatus = AHCI_PORT_READ(PortRegisters, PxCmdStatus);
/* Already in idle state */
if (!(CmdStatus & (AHCI_PXCMD_ST | AHCI_PXCMD_CR | AHCI_PXCMD_FRE | AHCI_PXCMD_FR)))
return TRUE;
/* Stop the command list DMA engine */
CmdStatus &= ~AHCI_PXCMD_ST;
AHCI_PORT_WRITE(PortRegisters, PxCmdStatus, CmdStatus);
for (i = 5000; i > 0; --i)
{
KeStallExecutionProcessor(100);
CmdStatus = AHCI_PORT_READ(PortRegisters, PxCmdStatus);
if (!(CmdStatus & AHCI_PXCMD_CR))
break;
}
if (i == 0)
{
WARN("Failed to stop the command list DMA engine %08lx\n", CmdStatus);
return FALSE;
}
if (!(CmdStatus & AHCI_PXCMD_FRE))
return TRUE;
/* Stop the FIS Receive DMA engine */
CmdStatus &= ~AHCI_PXCMD_FRE;
AHCI_PORT_WRITE(PortRegisters, PxCmdStatus, CmdStatus);
for (i = 5000; i > 0; --i)
{
KeStallExecutionProcessor(100);
CmdStatus = AHCI_PORT_READ(PortRegisters, PxCmdStatus);
if (!(CmdStatus & AHCI_PXCMD_FR))
return TRUE;
}
WARN("Failed to stop the FIS Receive DMA engine %08lx\n", CmdStatus);
return TRUE;
}
static
CODE_SEG("PAGE")
BOOLEAN
AhciPortInit(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ ULONG PortNumber,
_Inout_ PATAPORT_AHCI_PORT_DATA PortData)
{
PULONG IoBase = AHCI_PORT_BASE(ChannelExtension->IoBase, PortNumber);
PAGED_CODE();
/* Disable interrupts */
AHCI_PORT_WRITE(IoBase, PxInterruptEnable, 0);
/* Clear interrupts */
AHCI_PORT_WRITE(IoBase, PxInterruptStatus, 0xFFFFFFFF);
AHCI_HBA_WRITE(ChannelExtension->IoBase, HbaInterruptStatus, 1 << PortNumber);
/* Clear the error register */
AHCI_PORT_WRITE(IoBase, PxSataError, 0xFFFFFFFF);
/* Put the DMA engine in idle state */
if (!AhciPortIdle(IoBase))
return FALSE;
/* Allocate shared memory */
if (!AhciPortAllocateMemory(ChannelExtension, PortData))
return FALSE;
/* Physical address of the allocated command list */
AHCI_PORT_WRITE(IoBase, PxCommandListBaseLow, (ULONG)PortData->CommandListPhys);
if (ChannelExtension->AhciCapabilities & AHCI_CAP_S64A)
{
AHCI_PORT_WRITE(IoBase, PxCommandListBaseHigh, (ULONG)(PortData->CommandListPhys >> 32));
}
/* Physical address of the allocated FIS receive area */
AHCI_PORT_WRITE(IoBase, PxFisBaseLow, (ULONG)PortData->ReceivedFisPhys);
if (ChannelExtension->AhciCapabilities & AHCI_CAP_S64A)
{
AHCI_PORT_WRITE(IoBase, PxFisBaseHigh, (ULONG)(PortData->ReceivedFisPhys >> 32));
}
/* Apply the interrupt mask */
AHCI_PORT_WRITE(IoBase, PxInterruptEnable, AHCI_PORT_INTERRUPT_MASK);
return TRUE;
}
static
CODE_SEG("PAGE")
BOOLEAN
AtaFdoGetDmaAdapter(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
DEVICE_DESCRIPTION DeviceDescription = { 0 };
PAGED_CODE();
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = TRUE;
DeviceDescription.ScatterGather = TRUE;
DeviceDescription.Dma32BitAddresses = !(ChannelExtension->AhciCapabilities & AHCI_CAP_S64A);
DeviceDescription.InterfaceType = PCIBus;
DeviceDescription.MaximumLength = ATA_MAX_TRANSFER_LENGTH;
ChannelExtension->AdapterObject = IoGetDmaAdapter(ChannelExtension->Ldo,
&DeviceDescription,
&ChannelExtension->MapRegisterCount);
if (!ChannelExtension->AdapterObject)
return FALSE;
ChannelExtension->AdapterDeviceObject = ChannelExtension->Ldo;
return TRUE;
}
CODE_SEG("PAGE")
NTSTATUS
AtaFdoAhciInit(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
ULONG i, GlobalControl, AhciVersion, NumberOfPorts;
PATAPORT_AHCI_PORT_DATA PortData;
PAGED_CODE();
/* Set AE before accessing other AHCI registers */
GlobalControl = AHCI_HBA_READ(ChannelExtension->IoBase, HbaGlobalControl);
if (!(GlobalControl & AHCI_GHC_AE))
{
GlobalControl |= AHCI_GHC_AE;
AHCI_HBA_WRITE(ChannelExtension->IoBase, HbaGlobalControl, GlobalControl);
}
AhciVersion = AHCI_HBA_READ(ChannelExtension->IoBase, HbaAhciVersion);
if (AhciVersion >= AHCI_VERSION_1_2)
{
ChannelExtension->AhciCapabilitiesEx =
AHCI_HBA_READ(ChannelExtension->IoBase, HbaCapabilitiesEx);
}
ChannelExtension->AhciCapabilities =
AHCI_HBA_READ(ChannelExtension->IoBase, HbaCapabilities);
ChannelExtension->PortBitmap =
AHCI_HBA_READ(ChannelExtension->IoBase, HbaPortBitmap);
/* Disable interrupts */
GlobalControl = AHCI_HBA_READ(ChannelExtension->IoBase, HbaGlobalControl);
GlobalControl &= ~AHCI_GHC_IE;
AHCI_HBA_WRITE(ChannelExtension->IoBase, HbaGlobalControl, GlobalControl);
INFO("AhciVersion %08lx\n", AhciVersion);
INFO("Capabilities %08lx\n", ChannelExtension->AhciCapabilities);
INFO("PortsImplemented %08lx\n", ChannelExtension->PortBitmap);
NumberOfPorts = CountSetBits(ChannelExtension->PortBitmap);
ChannelExtension->PortData = ExAllocatePoolZero(PagedPool,
sizeof(*PortData) * NumberOfPorts,
IDEPORT_TAG);
if (!ChannelExtension->PortData)
return STATUS_INSUFFICIENT_RESOURCES;
if (!AtaFdoGetDmaAdapter(ChannelExtension))
return STATUS_INSUFFICIENT_RESOURCES;
PortData = ChannelExtension->PortData;
/* Initialize each port on the HBA */
for (i = 0; i < AHCI_MAX_PORTS; ++i)
{
if (!(ChannelExtension->PortBitmap & (1 << i)))
continue;
ERR("i %lu\n", i);
if (!AhciPortInit(ChannelExtension, i, PortData))
{
WARN("Failed to initialize port %lu\n", i);
}
++PortData;
}
return STATUS_SUCCESS;
}

View File

@ -0,0 +1,877 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Request handling
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* FUNCTIONS ******************************************************************/
static
VOID
AtaPciIdeDmaPrepare(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PUCHAR IoBase = ChannelExtension->PciIdeInterface.IoBase;
/* Clear the interrupt and error bits in the status register */
ATA_WRITE(IoBase + DMA_COMMAND, DMA_COMMAND_STOP);
ATA_WRITE(IoBase + DMA_STATUS, DMA_STATUS_INTERRUPT | DMA_STATUS_ERROR);
/* Beginning of the the Physical Region Descriptor (PRD) Table */
ATA_WRITE_ULONG((PULONG)(IoBase + DMA_PRDT_PHYSICAL_ADDRESS),
ChannelExtension->PciIdeInterface.PrdTablePhysicalAddress);
}
VOID
NTAPI
AtaPciIdeDmaPreparePrdTable(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_ PSCATTER_GATHER_LIST SgList,
_In_ PVOID Context)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context;
PPCIIDE_INTERFACE PciIdeDma = &ChannelExtension->PciIdeInterface;
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
PPRD_TABLE_ENTRY PrdTableEntry;
ULONG i;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
Request->SgList = SgList;
PrdTableEntry = PciIdeDma->PrdTable;
for (i = 0; i < SgList->NumberOfElements; ++i)
{
ULONG Address = SgList->Elements[i].Address.LowPart;
ULONG Length = SgList->Elements[i].Length;
/* Alignment */
ASSERT((Address % sizeof(USHORT)) == 0);
/* 32-bit DMA */
ASSERT(SgList->Elements[i].Address.HighPart == 0);
while (Length > 0)
{
ULONG TransferLength;
if (((Address & PRD_LENGTH_MASK) + Length) > PRD_LIMIT)
{
TransferLength = PRD_LIMIT - (Address & PRD_LENGTH_MASK);
}
else
{
TransferLength = Length;
}
/* Bit 0 is reserved */
ASSERT(!(TransferLength & 1));
PrdTableEntry->Address = Address;
PrdTableEntry->Length = TransferLength & PRD_LENGTH_MASK;
++PrdTableEntry;
Address += TransferLength;
Length -= TransferLength;
}
}
/* Last entry */
--PrdTableEntry;
PrdTableEntry->Length |= PRD_END_OF_TABLE;
KeFlushIoBuffers(Request->Mdl, !!(Request->Flags & REQUEST_FLAG_DATA_IN), TRUE);
AtaPciIdeDmaPrepare(ChannelExtension);
AtaReqDataTransferReady(ChannelExtension);
}
static
VOID
AtaPciIdeDmaStart(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
UCHAR Command;
/* Transfer direction */
if (Request->Flags & REQUEST_FLAG_DATA_IN)
Command = DMA_COMMAND_WRITE_TO_SYSTEM_MEMORY;
else
Command = DMA_COMMAND_READ_FROM_SYSTEM_MEMORY;
/* Begin transaction */
ATA_WRITE(ChannelExtension->PciIdeInterface.IoBase + DMA_COMMAND, Command | DMA_COMMAND_START);
}
static
VOID
AtaPciIdeDmaStop(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PUCHAR IoBase = ChannelExtension->PciIdeInterface.IoBase;
(VOID)ATA_READ(IoBase + DMA_STATUS);
ATA_WRITE(IoBase + DMA_COMMAND, DMA_COMMAND_STOP);
ATA_WRITE(IoBase + DMA_STATUS, DMA_STATUS_INTERRUPT);
}
static
UCHAR
AtaPciIdeDmaReadStatus(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
return ATA_READ(ChannelExtension->PciIdeInterface.IoBase + DMA_STATUS);
}
static
ULONG
AtaSendRequestSense(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
PSCSI_REQUEST_BLOCK Srb;
PCDB Cdb;
ULONG DataTransferLength;
/* Don't use DMA for the transfer to avoid DMA errors */
Request->Flags &= ~(REQUEST_FLAG_DATA_OUT | REQUEST_FLAG_DMA_ENABLED);
Request->Flags |= REQUEST_FLAG_REQUEST_SENSE | REQUEST_FLAG_DATA_IN;
Srb = Request->Srb;
DataTransferLength = Srb->SenseInfoBufferLength;
ChannelExtension->DataBuffer = Srb->SenseInfoBuffer;
ChannelExtension->BytesToTransfer = DataTransferLength;
/* Save the request data length */
Request->OldDataTransferLength = Request->DataTransferLength;
Request->DataTransferLength = DataTransferLength;
/* Build CDB for REQUEST SENSE */
Cdb = (PCDB)Request->Cdb;
Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
Cdb->CDB6INQUIRY.Reserved1 = 0;
Cdb->CDB6INQUIRY.PageCode = 0;
Cdb->CDB6INQUIRY.IReserved = 0;
Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)DataTransferLength;
Cdb->CDB6INQUIRY.Control = 0;
return AtaExecuteCommand(ChannelExtension);
}
static
VOID
AtaSendCdb(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
/* Command packet transfer */
if (!(Request->DeviceExtension->CdbSize & (sizeof(ULONG) - 1)) &&
(ChannelExtension->Flags & CHANNEL_IO32))
{
ATA_WRITE_BLOCK_32((PULONG)ChannelExtension->Registers.Data,
(PULONG)Request->Cdb,
Request->DeviceExtension->CdbSize / sizeof(USHORT));
}
else
{
ATA_WRITE_BLOCK_16((PUSHORT)ChannelExtension->Registers.Data,
(PUSHORT)Request->Cdb,
Request->DeviceExtension->CdbSize);
}
if (Request->Flags & REQUEST_FLAG_DMA_ENABLED)
{
/* Start the DMA engine */
AtaPciIdeDmaStart(ChannelExtension);
ChannelExtension->CommandFlags &= ~CMD_FLAG_REQUEST_MASK;
ChannelExtension->CommandFlags |= CMD_FLAG_DMA_TRANSFER;
}
}
static
VOID
AtaReadTaskFile(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
Request->TaskFile.Error = ATA_READ(ChannelExtension->Registers.Error);
Request->TaskFile.SectorCount = ATA_READ(ChannelExtension->Registers.SectorCount);
Request->TaskFile.LowLba = ATA_READ(ChannelExtension->Registers.LowLba);
Request->TaskFile.MidLba = ATA_READ(ChannelExtension->Registers.MidLba);
Request->TaskFile.HighLba = ATA_READ(ChannelExtension->Registers.HighLba);
Request->TaskFile.DriveSelect = ATA_READ(ChannelExtension->Registers.DriveSelect);
Request->TaskFile.Command = ATA_READ(ChannelExtension->Registers.Command);
if (Request->DeviceExtension->Flags & DEVICE_LBA48)
{
UCHAR Control = ATA_READ(ChannelExtension->Registers.Control);
ATA_WRITE(ChannelExtension->Registers.Control, Control | IDE_HIGH_ORDER_BYTE);
/* Read the extra information from the second byte of FIFO */
Request->TaskFile.FeatureEx = ATA_READ(ChannelExtension->Registers.Feature);
Request->TaskFile.SectorCountEx = ATA_READ(ChannelExtension->Registers.SectorCount);
Request->TaskFile.LowLbaEx = ATA_READ(ChannelExtension->Registers.LowLba);
Request->TaskFile.MidLbaEx = ATA_READ(ChannelExtension->Registers.MidLba);
Request->TaskFile.HighLbaEx = ATA_READ(ChannelExtension->Registers.HighLba);
ATA_WRITE(ChannelExtension->Registers.Control, Control);
}
}
static
VOID
AtaPioDataIn(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ ULONG ByteCount)
{
ByteCount = min(ByteCount, ChannelExtension->BytesToTransfer);
/* Transfer the data block */
if (!(ByteCount & (sizeof(ULONG) - 1)) && (ChannelExtension->Flags & CHANNEL_IO32))
{
ATA_READ_BLOCK_32((PULONG)ChannelExtension->Registers.Data,
(PULONG)ChannelExtension->DataBuffer,
ByteCount / sizeof(ULONG));
}
else
{
ATA_READ_BLOCK_16((PUSHORT)ChannelExtension->Registers.Data,
(PUSHORT)ChannelExtension->DataBuffer,
ByteCount / sizeof(USHORT));
/* Read one last byte */
if (ByteCount & (sizeof(USHORT) - 1))
{
PUCHAR Buffer = ChannelExtension->DataBuffer + ByteCount - 1;
*Buffer = ATA_READ(ChannelExtension->Registers.Data);
}
}
ChannelExtension->DataBuffer += ByteCount;
ChannelExtension->BytesToTransfer -= ByteCount;
}
static
VOID
AtaPioDataOut(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ ULONG ByteCount)
{
ByteCount = min(ByteCount, ChannelExtension->BytesToTransfer);
/* Transfer the data block */
if (!(ByteCount & (sizeof(ULONG) - 1)) && (ChannelExtension->Flags & CHANNEL_IO32))
{
ATA_WRITE_BLOCK_32((PULONG)ChannelExtension->Registers.Data,
(PULONG)ChannelExtension->DataBuffer,
ByteCount / sizeof(ULONG));
}
else
{
ATA_WRITE_BLOCK_16((PUSHORT)ChannelExtension->Registers.Data,
(PUSHORT)ChannelExtension->DataBuffer,
ByteCount / sizeof(USHORT));
/* Write one last byte */
if (ByteCount & (sizeof(USHORT) - 1))
{
PUCHAR Buffer = ChannelExtension->DataBuffer + ByteCount - 1;
ATA_WRITE(ChannelExtension->Registers.Data, *Buffer);
}
}
ChannelExtension->DataBuffer += ByteCount;
ChannelExtension->BytesToTransfer -= ByteCount;
}
BOOLEAN
AtaProcessRequest(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ UCHAR IdeStatus,
_In_ UCHAR DmaStatus)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
UCHAR InterruptReason;
ULONG ByteCount;
BOOLEAN Success;
ULONG SrbStatus;
ASSERT(!(IdeStatus & IDE_STATUS_BUSY));
switch (ChannelExtension->CommandFlags & CMD_FLAG_REQUEST_MASK)
{
case CMD_FLAG_DMA_TRANSFER:
{
if (DmaStatus & DMA_STATUS_ERROR)
{
SrbStatus = SRB_STATUS_ERROR;
}
else if ((DmaStatus & DMA_STATUS_ACTIVE) &&
!(ChannelExtension->Flags & CHANNEL_IGNORE_ACTIVE_DMA))
{
SrbStatus = SRB_STATUS_DATA_OVERRUN;
}
else
{
SrbStatus = SRB_STATUS_SUCCESS;
}
Success = !(IdeStatus & IDE_STATUS_ERROR);
goto Complete;
}
case CMD_FLAG_ATA_REQUEST:
{
ULONG BlockCount;
if (IdeStatus & (IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT))
{
Success = FALSE;
break;
}
if (!(IdeStatus & IDE_STATUS_DRQ))
{
Success = TRUE;
break;
}
if (Request->Flags & REQUEST_FLAG_READ_WRITE_MULTIPLE)
BlockCount = Request->DeviceExtension->MultiSectorTransfer;
else
BlockCount = 1;
ByteCount = BlockCount * Request->DeviceExtension->SectorSize;
if (ChannelExtension->CommandFlags & CMD_FLAG_DATA_IN)
{
AtaPioDataIn(ChannelExtension, ByteCount);
if (!ChannelExtension->BytesToTransfer)
{
Success = TRUE;
break;
}
}
else
{
AtaPioDataOut(ChannelExtension, ByteCount);
}
return FALSE;
}
case CMD_FLAG_ATAPI_REQUEST:
{
InterruptReason = ATA_READ(ChannelExtension->Registers.InterruptReason);
InterruptReason &= ATAPI_INTERRUPT_REASON_MASK;
InterruptReason |= IdeStatus & IDE_STATUS_DRQ;
switch (InterruptReason)
{
case ATAPI_INTERRUPT_REASON_AWAIT_CDB:
{
if (ChannelExtension->CommandFlags & CMD_FLAG_CDB)
{
WARN("Invalid interrupt reason %02x\n", InterruptReason);
Success = FALSE;
break;
}
ChannelExtension->CommandFlags |= CMD_FLAG_CDB;
AtaSendCdb(ChannelExtension);
return FALSE;
}
case ATAPI_INTERRUPT_REASON_DATA_IN:
{
if (ChannelExtension->CommandFlags & CMD_FLAG_DATA_OUT)
{
WARN("Invalid interrupt reason %02x\n", InterruptReason);
Success = FALSE;
break;
}
ByteCount = ATA_READ(ChannelExtension->Registers.ByteCountLow) |
(ATA_READ(ChannelExtension->Registers.ByteCountHigh) << 8);
AtaPioDataIn(ChannelExtension, ByteCount);
return FALSE;
}
case ATAPI_INTERRUPT_REASON_DATA_OUT:
{
if (ChannelExtension->CommandFlags & CMD_FLAG_DATA_IN)
{
WARN("Invalid interrupt reason %02x\n", InterruptReason);
Success = FALSE;
break;
}
ByteCount = ATA_READ(ChannelExtension->Registers.ByteCountLow) |
(ATA_READ(ChannelExtension->Registers.ByteCountHigh) << 8);
AtaPioDataOut(ChannelExtension, ByteCount);
return FALSE;
}
case ATAPI_INTERRUPT_REASON_INVALID:
{
/* The NEC CDR-260 drive clears CoD and IO on command completion */
if (!(Request->DeviceExtension->Flags & DEVICE_IS_NEC_CDR260))
{
WARN("Invalid interrupt reason %02x\n", InterruptReason);
Success = FALSE;
break;
}
__fallthrough;
}
case ATAPI_INTERRUPT_REASON_CMD_COMPLETION:
{
Success = !(IdeStatus & (IDE_STATUS_ERROR | IDE_STATUS_DEVICE_FAULT));
break;
}
default:
{
WARN("Invalid interrupt reason %02x\n", InterruptReason);
Success = FALSE;
break;
}
}
break;
}
default:
{
ASSERT(FALSE);
UNREACHABLE;
}
}
if (ChannelExtension->BytesToTransfer)
SrbStatus = SRB_STATUS_DATA_OVERRUN;
else
SrbStatus = SRB_STATUS_SUCCESS;
Complete:
if (!Success)
{
UCHAR Error = ATA_READ(ChannelExtension->Registers.Error);
SrbStatus = SRB_STATUS_ERROR;
Request->Error = Error;
Request->DataTransferLength = 0;
}
if (SrbStatus == SRB_STATUS_DATA_OVERRUN)
{
ASSERT(Request->DataTransferLength >= ChannelExtension->BytesToTransfer);
Request->DataTransferLength -= ChannelExtension->BytesToTransfer;
}
Request->SrbStatus = SrbStatus;
Request->Status = IdeStatus;
/* Make sure that the request handler won't be invoked from the interrupt handler */
ChannelExtension->CommandFlags = CMD_FLAG_NONE;
/* Handle failed ATAPI commands */
if ((SrbStatus == SRB_STATUS_ERROR) && (Request->Flags & REQUEST_FLAG_PACKET_COMMAND))
{
PSCSI_REQUEST_BLOCK Srb = Request->Srb;
/* Send the REQUEST SENSE command to figure out why the current command failed */
if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
!(Request->Flags & REQUEST_FLAG_REQUEST_SENSE))
{
SrbStatus = AtaSendRequestSense(ChannelExtension);
if (SrbStatus == SRB_STATUS_PENDING)
return FALSE;
Request->SrbStatus = SrbStatus;
}
}
/* Save the latest copy of the task file registers */
if (Request->Flags & REQUEST_FLAG_SAVE_TASK_FILE)
{
Request->Flags |= REQUEST_FLAG_HAS_TASK_FILE;
AtaReadTaskFile(ChannelExtension);
}
Request->Flags |= REQUEST_FLAG_COMPLETED;
/* Complete the request */
KeInsertQueueDpc(&ChannelExtension->Dpc, NULL, NULL);
return TRUE;
}
BOOLEAN
NTAPI
AtaPciIdeChannelIsr(
_In_ PKINTERRUPT Interrupt,
_In_ PVOID Context)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context;
UCHAR IdeStatus, DmaStatus;
BOOLEAN Handled;
UNREFERENCED_PARAMETER(Interrupt);
DmaStatus = AtaPciIdeDmaReadStatus(ChannelExtension);
if (DmaStatus & DMA_STATUS_INTERRUPT)
{
/* Stop the DMA engine */
AtaPciIdeDmaStop(ChannelExtension);
Handled = TRUE;
}
else
{
Handled = FALSE;
}
/* Acknowledge the IDE interrupt */
IdeStatus = ATA_READ(ChannelExtension->Registers.Status);
/* This interrupt is not ours */
if (!(ChannelExtension->CommandFlags & CMD_FLAG_AWAIT_INTERRUPT) ||
(IdeStatus & IDE_STATUS_BUSY))
{
if (Handled)
{
WARN("Spurious bus-master interrupt %02x, %02x\n", IdeStatus, DmaStatus);
}
return Handled;
}
AtaProcessRequest(ChannelExtension, IdeStatus, DmaStatus);
return TRUE;
}
BOOLEAN
NTAPI
AtaIdeChannelIsr(
_In_ PKINTERRUPT Interrupt,
_In_ PVOID Context)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = Context;
UCHAR IdeStatus;
UNREFERENCED_PARAMETER(Interrupt);
/* Acknowledge the IDE interrupt */
IdeStatus = ATA_READ(ChannelExtension->Registers.Status);
/* This interrupt is spurious or not ours */
if (!(ChannelExtension->CommandFlags & CMD_FLAG_AWAIT_INTERRUPT) ||
(IdeStatus & IDE_STATUS_BUSY))
{
WARN("Spurious IDE interrupt %02x\n", IdeStatus);
return FALSE;
}
AtaProcessRequest(ChannelExtension, IdeStatus, 0);
return TRUE;
}
static
ULONG
AtaExecuteAtaCommand(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
ULONG CommandFlags;
UCHAR Status;
/* Prepare the registers */
if (Request->Flags & REQUEST_FLAG_LBA48)
{
ATA_WRITE(ChannelExtension->Registers.Feature, Request->TaskFile.FeatureEx);
ATA_WRITE(ChannelExtension->Registers.SectorCount, Request->TaskFile.SectorCountEx);
ATA_WRITE(ChannelExtension->Registers.LowLba, Request->TaskFile.LowLbaEx);
ATA_WRITE(ChannelExtension->Registers.MidLba, Request->TaskFile.MidLbaEx);
ATA_WRITE(ChannelExtension->Registers.HighLba, Request->TaskFile.HighLbaEx);
/* Store the extra information in the second byte of FIFO */
}
ATA_WRITE(ChannelExtension->Registers.Feature, Request->TaskFile.Feature);
ATA_WRITE(ChannelExtension->Registers.SectorCount, Request->TaskFile.SectorCount);
ATA_WRITE(ChannelExtension->Registers.LowLba, Request->TaskFile.LowLba);
ATA_WRITE(ChannelExtension->Registers.MidLba, Request->TaskFile.MidLba);
ATA_WRITE(ChannelExtension->Registers.HighLba, Request->TaskFile.HighLba);
if (Request->Flags & REQUEST_FLAG_SET_DEVICE_REGISTER)
{
ATA_WRITE(ChannelExtension->Registers.DriveSelect,
Request->TaskFile.DriveSelect | (DeviceExtension->DeviceHead & 0xF8));
}
ATA_WRITE(ChannelExtension->Registers.Command, Request->TaskFile.Command);
CommandFlags = Request->Flags & REQUEST_FLAG_ASYNC_MODE; // Set CMD_FLAG_AWAIT_INTERRUPT
if (Request->Flags & REQUEST_FLAG_DMA_ENABLED)
{
CommandFlags |= CMD_FLAG_DMA_TRANSFER;
/* Start the DMA engine */
AtaPciIdeDmaStart(ChannelExtension);
/* Wait for an interrupt */
goto WaitIntr;
}
CommandFlags |= CMD_FLAG_ATA_REQUEST;
/*
* For PIO writes we need to send the first data block
* to make the devive start generating interrupts.
*/
if ((Request->Flags & (REQUEST_FLAG_DATA_OUT | REQUEST_FLAG_ASYNC_MODE)) ==
(REQUEST_FLAG_DATA_OUT | REQUEST_FLAG_ASYNC_MODE))
{
ULONG BlockCount, ByteCount;
/* Need to wait for a valid status */
ATA_IO_WAIT();
Status = ATA_READ(ChannelExtension->Registers.Status);
/* Wait for busy being cleared and DRQ or ERR bit being set */
ATA_WAIT_ON_BUSY(ChannelExtension, &Status, ATA_TIME_BUSY_NORMAL);
if (Status & IDE_STATUS_BUSY)
{
TRACE("Timeout, status 0x%02x\n", Status);
return SRB_STATUS_TIMEOUT;
}
if (Status & IDE_STATUS_ERROR)
{
TRACE("Device error, status 0x%02x\n", Status);
/* On device error we will get an interrupt anyway */
goto WaitIntr;
}
ATA_WAIT_FOR_DRQ(ChannelExtension, &Status, IDE_STATUS_DRDY, ATA_TIME_DRQ_NORMAL);
if (!(Status & IDE_STATUS_DRQ))
{
TRACE("DRQ timeout, status 0x%02x\n", Status);
return SRB_STATUS_TIMEOUT;
}
if (Request->Flags & REQUEST_FLAG_READ_WRITE_MULTIPLE)
BlockCount = Request->DeviceExtension->MultiSectorTransfer;
else
BlockCount = 1;
ByteCount = BlockCount * Request->DeviceExtension->SectorSize;
/* Transfer the first data block */
AtaPioDataOut(ChannelExtension, ByteCount);
}
/* Wait for remaining interrupts */
WaitIntr:
CommandFlags |= (Request->Flags & (REQUEST_FLAG_DATA_IN | REQUEST_FLAG_DATA_OUT));
ChannelExtension->CommandFlags = CommandFlags;
return SRB_STATUS_PENDING;
}
static
ULONG
AtaExecutePacketCommand(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
ULONG CommandFlags;
USHORT ByteCount;
UCHAR Status, Feature;
CommandFlags = Request->Flags & REQUEST_FLAG_ASYNC_MODE; // Set CMD_FLAG_AWAIT_INTERRUPT
/* Prepare to transfer a device command */
if (Request->Flags & REQUEST_FLAG_DMA_ENABLED)
{
/* DMA transfer */
ByteCount = 0;
Feature = 1;
CommandFlags |= CMD_FLAG_DMA_TRANSFER;
}
else
{
/* PIO transfer */
ByteCount = min(ChannelExtension->BytesToTransfer, 0xFFFF - 1);
Feature = 0;
CommandFlags |= CMD_FLAG_ATAPI_REQUEST;
}
ATA_WRITE(ChannelExtension->Registers.ByteCountLow, (UCHAR)ByteCount);
ATA_WRITE(ChannelExtension->Registers.ByteCountHigh, ByteCount >> 8);
ATA_WRITE(ChannelExtension->Registers.Feature, Feature);
ATA_WRITE(ChannelExtension->Registers.Command, IDE_COMMAND_ATAPI_PACKET);
/* Wait for an interrupt that signals that device is ready to accept the command packet */
if (DeviceExtension->Flags & DEVICE_HAS_CDB_INTERRUPT)
{
CommandFlags &= ~CMD_FLAG_REQUEST_MASK;
CommandFlags |= CMD_FLAG_ATAPI_REQUEST;
goto WaitIntr;
}
CommandFlags |= CMD_FLAG_CDB;
/* Need to wait for a valid status */
ATA_IO_WAIT();
Status = ATA_READ(ChannelExtension->Registers.Status);
/* Wait for busy being cleared and DRQ or ERR bit being set */
ATA_WAIT_ON_BUSY(ChannelExtension, &Status, ATA_TIME_BUSY_NORMAL);
if (Status & IDE_STATUS_BUSY)
{
TRACE("Timeout, status 0x%02x\n", Status);
return SRB_STATUS_TIMEOUT;
}
if (Status & IDE_STATUS_ERROR)
{
TRACE("Device error, status 0x%02x\n", Status);
/* On device error we will get an interrupt anyway */
goto WaitIntr;
}
ATA_WAIT_FOR_DRQ(ChannelExtension, &Status, 0, ATA_TIME_DRQ_NORMAL);
if (!(Status & IDE_STATUS_DRQ))
{
TRACE("DRQ timeout, status 0x%02x\n", Status);
return SRB_STATUS_TIMEOUT;
}
/* Command packet transfer */
if (!(Request->DeviceExtension->CdbSize & (sizeof(ULONG) - 1)) &&
(ChannelExtension->Flags & CHANNEL_IO32))
{
ATA_WRITE_BLOCK_32((PULONG)ChannelExtension->Registers.Data,
(PULONG)Request->Cdb,
Request->DeviceExtension->CdbSize / sizeof(USHORT));
}
else
{
ATA_WRITE_BLOCK_16((PUSHORT)ChannelExtension->Registers.Data,
(PUSHORT)Request->Cdb,
DeviceExtension->CdbSize);
}
if (Request->Flags & REQUEST_FLAG_DMA_ENABLED)
{
/* Start the DMA engine */
AtaPciIdeDmaStart(ChannelExtension);
}
/* Wait for remaining interrupts */
WaitIntr:
CommandFlags |= (Request->Flags & (REQUEST_FLAG_DATA_IN | REQUEST_FLAG_DATA_OUT));
ChannelExtension->CommandFlags = CommandFlags;
return SRB_STATUS_PENDING;
}
BOOLEAN
AtaDevicePresent(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
UCHAR Status;
/* Do a quick check first */
Status = ATA_READ(ChannelExtension->Registers.Status);
if (Status == 0xFF || Status == 0x7F)
return FALSE;
/* Look at controller */
ATA_WRITE(ChannelExtension->Registers.ByteCountLow, 0x55);
ATA_WRITE(ChannelExtension->Registers.ByteCountLow, 0xAA);
ATA_WRITE(ChannelExtension->Registers.ByteCountLow, 0x55);
if (ATA_READ(ChannelExtension->Registers.ByteCountLow) != 0x55)
return FALSE;
ATA_WRITE(ChannelExtension->Registers.ByteCountHigh, 0xAA);
ATA_WRITE(ChannelExtension->Registers.ByteCountHigh, 0x55);
ATA_WRITE(ChannelExtension->Registers.ByteCountHigh, 0xAA);
if (ATA_READ(ChannelExtension->Registers.ByteCountHigh) != 0xAA)
return FALSE;
return TRUE;
}
static
VOID
AtaChangeInterruptMode(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
UCHAR Control;
if (Request->Flags & REQUEST_FLAG_ASYNC_MODE)
Control = 0;
else
Control = IDE_DC_DISABLE_INTERRUPTS;
ATA_WRITE(ChannelExtension->Registers.Control, Control);
}
ULONG
AtaExecuteCommand(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
UCHAR Status;
/* Select the device */
ATA_SELECT_DEVICE(ChannelExtension, Request->DeviceExtension->DeviceHead);
/* Determine device presence */
if (SRB_GET_FLAGS(Request->Srb) & SRB_FLAG_DEVICE_CHECK)
{
if (!AtaDevicePresent(ChannelExtension))
return SRB_STATUS_SELECTION_TIMEOUT;
}
/* Wait for busy to clear */
Status = ATA_READ(ChannelExtension->Registers.Status);
ATA_WAIT_ON_BUSY(ChannelExtension, &Status, ATA_TIME_BUSY_SELECT);
if (Status & IDE_STATUS_BUSY)
return SRB_STATUS_BUSY;
AtaChangeInterruptMode(ChannelExtension);
/* Execute the command */
if (Request->Flags & REQUEST_FLAG_PACKET_COMMAND)
return AtaExecutePacketCommand(ChannelExtension, Request->DeviceExtension);
else
return AtaExecuteAtaCommand(ChannelExtension, Request->DeviceExtension);
}

View File

@ -0,0 +1,352 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: ACPI interface with IDE controllers and drives
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
#include <acpiioct.h>
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
NTSTATUS
AtaAcpiEvaluateObject(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_Out_opt_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,
_In_ ULONG OutputBufferLength)
{
PIRP Irp;
IO_STATUS_BLOCK IoStatusBlock;
KEVENT Event;
NTSTATUS Status;
PDEVICE_OBJECT TopDeviceObject;
PAGED_CODE();
/* Get the ACPI bus filter device for this DO */
TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_ACPI_EVAL_METHOD,
DeviceObject,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
FALSE,
&Event,
&IoStatusBlock);
if (!Irp)
{
ObDereferenceObject(TopDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
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;
}
}
ObDereferenceObject(TopDeviceObject);
return Status;
}
CODE_SEG("PAGE")
VOID
AtaAcpiSetTimingMode(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode,
_In_ PIDENTIFY_DEVICE_DATA IdBlock1,
_In_ PIDENTIFY_DEVICE_DATA IdBlock2)
{
PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
PACPI_METHOD_ARGUMENT Argument;
NTSTATUS Status;
ULONG InputSize;
PAGED_CODE();
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 = ExAllocatePoolZero(NonPagedPool, InputSize, IDEPORT_TAG);
if (!InputBuffer)
{
ERR("Failed to allocate memory\n");
return;
}
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);
ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, IdBlock1, sizeof(*IdBlock1));
/* Argument 3: The ATA drive ID block */
Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, IdBlock2, sizeof(*IdBlock2));
/* Evaluate the _STM method */
Status = AtaAcpiEvaluateObject(ChannelExtension->Common.Self,
InputBuffer,
InputSize,
NULL,
0);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to set transfer timings, status 0x%lx\n", Status);
}
ExFreePoolWithTag(InputBuffer, IDEPORT_TAG);
}
CODE_SEG("PAGE")
BOOLEAN
AtaAcpiGetTimingMode(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_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;
PAGED_CODE();
RtlZeroMemory(Buffer, sizeof(Buffer));
InputBuffer.MethodNameAsUlong = 'MTG_'; // _GTM
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
/* Evaluate the _GTM method */
Status = AtaAcpiEvaluateObject(ChannelExtension->Common.Self,
&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;
}
CODE_SEG("PAGE")
PVOID
AtaAcpiGetTaskFile(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
ACPI_EVAL_INPUT_BUFFER InputBuffer;
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
ULONG RetryCount, OutputSize;
NTSTATUS Status;
PAGED_CODE();
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 */
OutputSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(IDE_ACPI_TASK_FILE) * 10);
for (RetryCount = 0; RetryCount < 2; ++RetryCount)
{
OutputBuffer = ExAllocatePoolZero(NonPagedPool, OutputSize, IDEPORT_TAG);
if (!OutputBuffer)
return NULL;
/* Evaluate the _GTF method */
Status = AtaAcpiEvaluateObject(DeviceExtension->Common.Self,
&InputBuffer,
sizeof(InputBuffer),
OutputBuffer,
OutputSize);
if (NT_SUCCESS(Status))
break;
/* Increase the allocation size if it's too small */
if (Status == STATUS_BUFFER_OVERFLOW)
{
ExFreePoolWithTag(OutputBuffer, IDEPORT_TAG);
OutputSize = OutputBuffer->Length;
continue;
}
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(IDE_ACPI_TASK_FILE))
{
ERR("Incorrect command stream length %u\n", OutputBuffer->Argument[0].DataLength);
goto Cleanup;
}
return OutputBuffer;
Cleanup:
ExFreePoolWithTag(OutputBuffer, IDEPORT_TAG);
return NULL;
}
static
CODE_SEG("PAGE")
BOOLEAN
AtaAcpiFilterTaskFile(
_In_ PIDE_ACPI_TASK_FILE AcpiTaskFile)
{
PAGED_CODE();
switch (AcpiTaskFile->Command)
{
case IDE_COMMAND_SET_FEATURE:
{
if (AcpiTaskFile->Feature == IDE_FEATURE_SET_TRANSFER_MODE)
return FALSE;
break;
}
case IDE_COMMAND_SET_DRIVE_PARAMETERS:
case IDE_COMMAND_SET_MULTIPLE:
return FALSE;
default:
break;
}
return TRUE;
}
static
CODE_SEG("PAGE")
VOID
AtaAcpiTaskFileToInternalTaskFile(
_In_ PIDE_ACPI_TASK_FILE AcpiTaskFile,
_Out_ PATA_TASKFILE TaskFile)
{
PAGED_CODE();
TaskFile->Feature = AcpiTaskFile->Feature;
TaskFile->SectorCount = AcpiTaskFile->SectorCount;
TaskFile->LowLba = AcpiTaskFile->LowLba;
TaskFile->MidLba = AcpiTaskFile->MidLba;
TaskFile->HighLba = AcpiTaskFile->HighLba;
TaskFile->DriveSelect = AcpiTaskFile->DriveSelect;
TaskFile->Command = AcpiTaskFile->Command;
}
CODE_SEG("PAGE")
VOID
AtaAcpiExecuteTaskFile(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PVOID GtfDataBuffer,
_In_ PATA_TASKFILE TaskFile)
{
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = GtfDataBuffer;
PIDE_ACPI_TASK_FILE AcpiTaskFile = (PIDE_ACPI_TASK_FILE)OutputBuffer->Argument[0].Data;
ULONG i;
PAGED_CODE();
/* Execute task files */
for (i = 0; i < OutputBuffer->Argument[0].DataLength / sizeof(*AcpiTaskFile); ++i)
{
PCSTR Result;
NTSTATUS Status;
if (!AtaAcpiFilterTaskFile(AcpiTaskFile))
{
Result = "filtered out";
}
else
{
AtaAcpiTaskFileToInternalTaskFile(AcpiTaskFile, TaskFile);
Status = AtaSendTaskFile(DeviceExtension,
TaskFile,
SRB_TYPE_CONFIG,
FALSE,
10,
NULL,
0);
Result = NT_SUCCESS(Status) ? "completed" : "aborted";
}
TRACE("GTF[%lu]: %02x:%02x:%02x:%02x:%02x:%02x:%02x -- %s\n",
i,
AcpiTaskFile->Feature,
AcpiTaskFile->SectorCount,
AcpiTaskFile->LowLba,
AcpiTaskFile->MidLba,
AcpiTaskFile->HighLba,
AcpiTaskFile->DriveSelect,
AcpiTaskFile->Command,
Result);
++AcpiTaskFile;
}
}

View File

@ -0,0 +1,932 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: I/O control handling
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
#define AtaVerifyInBuffer(Stack, Struct) \
((Stack)->Parameters.DeviceIoControl.InputBufferLength >= sizeof(Struct))
#define AtaVerifyOutBuffer(Stack, Struct) \
((Stack)->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(Struct))
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
BOOLEAN
AtaCheckPropertyQuery(
_Inout_ PIRP Irp,
_In_ ULONG DescriptorSize,
_Out_ NTSTATUS* Status)
{
PSTORAGE_PROPERTY_QUERY PropertyQuery = Irp->AssociatedIrp.SystemBuffer;
PIO_STACK_LOCATION IoStack;
PAGED_CODE();
/* Check the type of a property query */
if (PropertyQuery->QueryType != PropertyStandardQuery &&
PropertyQuery->QueryType != PropertyExistsQuery)
{
*Status = STATUS_NOT_SUPPORTED;
return FALSE;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (!AtaVerifyOutBuffer(IoStack, STORAGE_DESCRIPTOR_HEADER))
{
*Status = STATUS_INFO_LENGTH_MISMATCH;
return FALSE;
}
/* The requested property is supported */
if (PropertyQuery->QueryType == PropertyExistsQuery)
{
*Status = STATUS_SUCCESS;
return FALSE;
}
/* Caller can determine required size based upon DescriptorHeader */
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < DescriptorSize)
{
PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)PropertyQuery;
DescriptorHeader->Version = DescriptorSize;
DescriptorHeader->Size = DescriptorSize;
Irp->IoStatus.Information = sizeof(*DescriptorHeader);
*Status = STATUS_SUCCESS;
return FALSE;
}
return TRUE;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryStorageDeviceProperty(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PINQUIRYDATA InquiryData = &DeviceExtension->InquiryData;
PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
PUCHAR Buffer;
NTSTATUS Status;
ULONG DescriptorSize, RawPropertiesLength, Length1, Length2, Length3;
PAGED_CODE();
Length1 = strlen(DeviceExtension->FriendlyName) + sizeof(ANSI_NULL);
Length2 = strlen(DeviceExtension->RevisionNumber) + sizeof(ANSI_NULL);
Length3 = strlen(DeviceExtension->SerialNumber) + sizeof(ANSI_NULL);
RawPropertiesLength = Length1 + Length2 + Length3;
DescriptorSize = FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties) +
RawPropertiesLength;
if (!AtaCheckPropertyQuery(Irp, DescriptorSize, &Status))
return Status;
DeviceDescriptor = Irp->AssociatedIrp.SystemBuffer;
DeviceDescriptor->RawPropertiesLength = RawPropertiesLength;
DeviceDescriptor->Version = sizeof(*DeviceDescriptor);
DeviceDescriptor->Size = DescriptorSize;
DeviceDescriptor->DeviceType = InquiryData->DeviceType;
DeviceDescriptor->DeviceTypeModifier = InquiryData->DeviceTypeModifier;
DeviceDescriptor->RemovableMedia = InquiryData->RemovableMedia;
DeviceDescriptor->CommandQueueing = FALSE; /* Disable request tagging TODO: SATA */
DeviceDescriptor->BusType = BusTypeAta;
/* Property 1: The vendor ID. We return a NULL string here */
DeviceDescriptor->VendorIdOffset = 0;
/* Property 2: The product ID */
DeviceDescriptor->ProductIdOffset =
FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
Buffer = (PUCHAR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductIdOffset);
RtlCopyMemory(Buffer, DeviceExtension->FriendlyName, Length1);
Buffer += Length1;
/* Property 3: The product revision */
DeviceDescriptor->ProductRevisionOffset = DeviceDescriptor->ProductIdOffset + Length1;
RtlCopyMemory(Buffer, DeviceExtension->RevisionNumber, Length2);
Buffer += Length2;
/* Property 4: The serial number */
DeviceDescriptor->SerialNumberOffset = DeviceDescriptor->ProductRevisionOffset + Length2;
RtlCopyMemory(Buffer, DeviceExtension->SerialNumber, Length3);
Irp->IoStatus.Information = DescriptorSize;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryStorageAccessAlignmentProperty(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR AccessAlignmentDescriptor;
ULONG LogicalSectorsPerPhysicalSector, Dummy;
NTSTATUS Status;
PAGED_CODE();
if (IS_ATAPI(DeviceExtension))
return STATUS_NOT_SUPPORTED;
if (!AtaCheckPropertyQuery(Irp, sizeof(*AccessAlignmentDescriptor), &Status))
return Status;
AccessAlignmentDescriptor = Irp->AssociatedIrp.SystemBuffer;
AccessAlignmentDescriptor->Version = sizeof(*AccessAlignmentDescriptor);
AccessAlignmentDescriptor->Size = sizeof(*AccessAlignmentDescriptor);
AccessAlignmentDescriptor->BytesPerCacheLine = 0;
AccessAlignmentDescriptor->BytesOffsetForCacheAlignment = 0;
AccessAlignmentDescriptor->BytesPerLogicalSector = DeviceExtension->SectorSize;
LogicalSectorsPerPhysicalSector =
AtaLogicalSectorsPerPhysicalSector(&DeviceExtension->IdentifyDeviceData, &Dummy);
AccessAlignmentDescriptor->BytesPerPhysicalSector =
DeviceExtension->SectorSize * LogicalSectorsPerPhysicalSector;
AccessAlignmentDescriptor->BytesOffsetForSectorAlignment =
DeviceExtension->SectorSize *
AtaLogicalSectorAlignment(&DeviceExtension->IdentifyDeviceData);
Irp->IoStatus.Information = sizeof(*AccessAlignmentDescriptor);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryStorageDeviceSeekPenaltyProperty(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PDEVICE_SEEK_PENALTY_DESCRIPTOR PenaltyDescriptor;
NTSTATUS Status;
BOOLEAN IncursSeekPenalty;
PAGED_CODE();
if (!AtaCheckPropertyQuery(Irp, sizeof(*PenaltyDescriptor), &Status))
return Status;
if (AtaDeviceIsRotatingDevice(&DeviceExtension->IdentifyDeviceData))
IncursSeekPenalty = TRUE;
else if (AtaDeviceIsSsd(&DeviceExtension->IdentifyDeviceData))
IncursSeekPenalty = FALSE;
else
return STATUS_UNSUCCESSFUL; /* Undetermined */
PenaltyDescriptor = Irp->AssociatedIrp.SystemBuffer;
PenaltyDescriptor->Version = sizeof(*PenaltyDescriptor);
PenaltyDescriptor->Size = sizeof(*PenaltyDescriptor);
PenaltyDescriptor->IncursSeekPenalty = IncursSeekPenalty;
Irp->IoStatus.Information = sizeof(*PenaltyDescriptor);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryStorageDeviceTrimProperty(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PDEVICE_TRIM_DESCRIPTOR TrimDescriptor;
NTSTATUS Status;
PAGED_CODE();
if (IS_ATAPI(DeviceExtension))
return STATUS_NOT_SUPPORTED;
if (!AtaCheckPropertyQuery(Irp, sizeof(*TrimDescriptor), &Status))
return Status;
TrimDescriptor = Irp->AssociatedIrp.SystemBuffer;
TrimDescriptor->Version = sizeof(*TrimDescriptor);
TrimDescriptor->Size = sizeof(*TrimDescriptor);
TrimDescriptor->TrimEnabled = AtaHasTrimFunction(&DeviceExtension->IdentifyDeviceData);
Irp->IoStatus.Information = sizeof(*TrimDescriptor);
return STATUS_SUCCESS;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleStorageQueryProperty(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack,
_Out_ PBOOLEAN ForwardToFdo)
{
PSTORAGE_PROPERTY_QUERY PropertyQuery;
NTSTATUS Status;
PAGED_CODE();
if (!AtaVerifyInBuffer(IoStack, STORAGE_PROPERTY_QUERY))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
PropertyQuery = Irp->AssociatedIrp.SystemBuffer;
switch (PropertyQuery->PropertyId)
{
case StorageDeviceProperty:
Status = AtaPdoQueryStorageDeviceProperty(DeviceExtension, Irp);
break;
case StorageAccessAlignmentProperty:
Status = AtaPdoQueryStorageAccessAlignmentProperty(DeviceExtension, Irp);
break;
case StorageDeviceSeekPenaltyProperty:
Status = AtaPdoQueryStorageDeviceSeekPenaltyProperty(DeviceExtension, Irp);
break;
case StorageDeviceTrimProperty:
Status = AtaPdoQueryStorageDeviceTrimProperty(DeviceExtension, Irp);
break;
default:
*ForwardToFdo = TRUE;
return STATUS_MORE_PROCESSING_REQUIRED;
}
*ForwardToFdo = FALSE;
return Status;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleGetScsiAddress(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PSCSI_ADDRESS ScsiAddress;
ATA_SCSI_ADDRESS AtaScsiAddress;
PAGED_CODE();
if (!AtaVerifyOutBuffer(IoStack, SCSI_ADDRESS))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
AtaScsiAddress = DeviceExtension->AtaScsiAddress;
ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
ScsiAddress->Length = sizeof(*ScsiAddress);
ScsiAddress->PortNumber = DeviceExtension->ChannelExtension->PortNumber;
ScsiAddress->PathId = AtaScsiAddress.PathId;
ScsiAddress->TargetId = AtaScsiAddress.TargetId;
ScsiAddress->Lun = AtaScsiAddress.Lun;
Irp->IoStatus.Information = sizeof(*ScsiAddress);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoSendHbaControl(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PSRB_IO_CONTROL SrbControl,
_In_ ULONG BufferSize)
{
PSCSI_REQUEST_BLOCK Srb;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
KEVENT Event;
NTSTATUS Status;
LARGE_INTEGER LargeInt;
PIO_STACK_LOCATION IoStack;
PAGED_CODE();
Srb = ExAllocatePoolZero(NonPagedPool, sizeof(*Srb), IDEPORT_TAG);
if (!Srb)
return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
LargeInt.QuadPart = 1;
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SCSI,
DeviceExtension->Common.Self,
SrbControl,
BufferSize,
&LargeInt,
&Event,
&IoStatusBlock);
if (!Irp)
{
ExFreePoolWithTag(Srb, IDEPORT_TAG);
return STATUS_INSUFFICIENT_RESOURCES;
}
Srb->OriginalRequest = Irp;
Srb->Function = SRB_FUNCTION_IO_CONTROL;
Srb->Length = sizeof(*Srb);
Srb->TargetId = DeviceExtension->AtaScsiAddress.TargetId;
Srb->Lun = DeviceExtension->AtaScsiAddress.Lun;
Srb->PathId = DeviceExtension->AtaScsiAddress.PathId;
Srb->TimeOutValue = SrbControl->Timeout;
Srb->SrbFlags = SRB_FLAGS_NO_QUEUE_FREEZE | SRB_FLAGS_DATA_IN;
Srb->DataBuffer = SrbControl;
Srb->DataTransferLength = BufferSize;
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->Parameters.Scsi.Srb = Srb;
Status = IoCallDriver(DeviceExtension->Common.Self, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
ExFreePoolWithTag(Srb, IDEPORT_TAG);
return Irp->IoStatus.Status;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleScsiMiniport(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PSRB_IO_CONTROL SrbControl;
NTSTATUS Status;
ULONG CmdBufferSize, BufferSize;
PAGED_CODE();
if (!AtaVerifyInBuffer(IoStack, SRB_IO_CONTROL))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
SrbControl = Irp->AssociatedIrp.SystemBuffer;
if (SrbControl->HeaderLength != sizeof(*SrbControl))
{
ERR("Unknown structure size %u\n", SrbControl->HeaderLength);
return STATUS_REVISION_MISMATCH;
}
Status = RtlULongAdd(SrbControl->Length, sizeof(*SrbControl), &BufferSize);
if (!NT_SUCCESS(Status))
{
ERR("Too large buffer 0x%lx\n", SrbControl->Length);
return Status;
}
CmdBufferSize = IoStack->Parameters.DeviceIoControl.InputBufferLength;
CmdBufferSize = max(CmdBufferSize, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
if (CmdBufferSize < BufferSize)
{
ERR("Cmd buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
if (RtlEqualMemory(SrbControl->Signature, "SCSIDISK", sizeof("SCSIDISK") - 1))
{
Status = AtaPdoSendHbaControl(DeviceExtension, SrbControl, BufferSize);
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
return Status;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleAtaPassthrough(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PATA_PASS_THROUGH_EX RequestHeader;
PIDEREGS IdeRegs;
PSCSI_REQUEST_BLOCK Srb;
IO_STATUS_BLOCK IoStatusBlock;
PIRP NewIrp;
KEVENT Event;
NTSTATUS Status;
LARGE_INTEGER LargeInt;
PIO_STACK_LOCATION NewIoStack;
PVOID Buffer;
PAGED_CODE();
#if defined(_WIN64)
if (IoIs32bitProcess(Irp))
{
if (!AtaVerifyInBuffer(IoStack, ATA_PASS_THROUGH_EX32))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
}
else
#endif
{
if (!AtaVerifyInBuffer(IoStack, ATA_PASS_THROUGH_EX))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
}
RequestHeader = Irp->AssociatedIrp.SystemBuffer;
if (RequestHeader->Length != sizeof(*RequestHeader))
{
ERR("Unknown structure size %u\n", RequestHeader->Length);
return STATUS_REVISION_MISMATCH;
}
IdeRegs = (PIDEREGS)RequestHeader->CurrentTaskFile;
TRACE("AtaFlags 0x%x\n", RequestHeader->AtaFlags);
TRACE("DataTransferLength %lu\n", RequestHeader->DataTransferLength);
TRACE("DataBufferOffset 0x%x\n", RequestHeader->DataBufferOffset);
TRACE("TF: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
IdeRegs->bFeaturesReg,
IdeRegs->bSectorCountReg,
IdeRegs->bSectorNumberReg,
IdeRegs->bCylLowReg,
IdeRegs->bCylHighReg,
IdeRegs->bCommandReg,
IdeRegs->bDriveHeadReg);
if (RequestHeader->DataTransferLength)
{
Buffer = (PVOID)((PUCHAR)RequestHeader + RequestHeader->DataBufferOffset);
}
else
{
Buffer = NULL;
}
Srb = ExAllocatePoolZero(NonPagedPool, sizeof(*Srb), IDEPORT_TAG);
if (!Srb)
return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
LargeInt.QuadPart = 1;
NewIrp = IoBuildSynchronousFsdRequest(IRP_MJ_SCSI,
DeviceExtension->Common.Self,
Buffer,
RequestHeader->DataTransferLength,
&LargeInt,
&Event,
&IoStatusBlock);
if (!NewIrp)
{
ExFreePoolWithTag(Srb, IDEPORT_TAG);
return STATUS_INSUFFICIENT_RESOURCES;
}
Srb->OriginalRequest = NewIrp;
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
Srb->Length = sizeof(*Srb);
Srb->TargetId = DeviceExtension->AtaScsiAddress.TargetId;
Srb->Lun = DeviceExtension->AtaScsiAddress.Lun;
Srb->PathId = DeviceExtension->AtaScsiAddress.PathId;
Srb->TimeOutValue = RequestHeader->TimeOutValue;
Srb->SrbFlags = SRB_FLAGS_NO_QUEUE_FREEZE | SRB_FLAGS_PASSTHROUGH;
if (RequestHeader->AtaFlags & ATA_FLAGS_DATA_IN)
Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
if (RequestHeader->AtaFlags & ATA_FLAGS_DATA_OUT)
Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
Srb->DataBuffer = Buffer;
Srb->DataTransferLength = RequestHeader->DataTransferLength;
RtlCopyMemory(Srb->Cdb,
RequestHeader->PreviousTaskFile,
RTL_FIELD_SIZE(ATA_PASS_THROUGH_EX, PreviousTaskFile) +
RTL_FIELD_SIZE(ATA_PASS_THROUGH_EX, CurrentTaskFile));
Srb->Cdb[7] = (UCHAR)RequestHeader->AtaFlags;
NewIoStack = IoGetNextIrpStackLocation(NewIrp);
NewIoStack->Parameters.Scsi.Srb = Srb;
Status = IoCallDriver(DeviceExtension->Common.Self, NewIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
RtlCopyMemory(RequestHeader->CurrentTaskFile,
&Srb->Cdb[8],
RTL_FIELD_SIZE(ATA_PASS_THROUGH_EX, CurrentTaskFile));
ExFreePoolWithTag(Srb, IDEPORT_TAG);
Status = NewIrp->IoStatus.Status;
return Status;
}
static
NTSTATUS
AtaPdoDeviceControl(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
BOOLEAN ForwardToFdo = FALSE;
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_STORAGE_QUERY_PROPERTY:
Status = AtaPdoHandleStorageQueryProperty(DeviceExtension, Irp, IoStack, &ForwardToFdo);
break;
case IOCTL_SCSI_GET_ADDRESS:
Status = AtaPdoHandleGetScsiAddress(DeviceExtension, Irp, IoStack);
break;
case IOCTL_SCSI_MINIPORT:
Status = AtaPdoHandleScsiMiniport(DeviceExtension, Irp, IoStack);
break;
case IOCTL_ATA_PASS_THROUGH:
case IOCTL_ATA_PASS_THROUGH_DIRECT:
Status = AtaPdoHandleAtaPassthrough(DeviceExtension, Irp, IoStack);
break;
case IOCTL_SCSI_GET_CAPABILITIES:
case IOCTL_SCSI_GET_INQUIRY_DATA:
ForwardToFdo = TRUE;
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (ForwardToFdo)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = DeviceExtension->ChannelExtension;
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(ChannelExtension->Common.Self, Irp);
}
else
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
return Status;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaFdoQueryStorageAdapterProperty(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp)
{
PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
NTSTATUS Status;
if (!AtaCheckPropertyQuery(Irp, sizeof(*AdapterDescriptor), &Status))
return Status;
AdapterDescriptor = Irp->AssociatedIrp.SystemBuffer;
/*
* This structure has to be zeroed out first
* in order to not confuse the upper storage class drivers.
* Also the new version of the descriptor structure (NT6.2+)
* has two extra fields instead of the unnamed "padding" fields.
*/
RtlZeroMemory(AdapterDescriptor, sizeof(*AdapterDescriptor));
AdapterDescriptor->Version = sizeof(*AdapterDescriptor);
AdapterDescriptor->Size = sizeof(*AdapterDescriptor);
AdapterDescriptor->MaximumPhysicalPages = (ULONG)-1; /* Undetermined */
AdapterDescriptor->AlignmentMask = ChannelExtension->Common.Self->AlignmentRequirement;
AdapterDescriptor->AdapterUsesPio = TRUE;
AdapterDescriptor->AdapterScansDown = FALSE;
AdapterDescriptor->CommandQueueing = FALSE;
AdapterDescriptor->AcceleratedTransfer = FALSE;
AdapterDescriptor->BusType = BusTypeAta;
AdapterDescriptor->BusMajorVersion = 1;
AdapterDescriptor->BusMinorVersion = 0;
AdapterDescriptor->MaximumTransferLength = ChannelExtension->MaximumTransferLength;
Irp->IoStatus.Information = sizeof(*AdapterDescriptor);
return STATUS_SUCCESS;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaFdoHandleStorageQueryProperty(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
NTSTATUS Status;
PSTORAGE_PROPERTY_QUERY PropertyQuery;
PAGED_CODE();
if (!AtaVerifyInBuffer(IoStack, STORAGE_PROPERTY_QUERY))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
PropertyQuery = Irp->AssociatedIrp.SystemBuffer;
switch (PropertyQuery->PropertyId)
{
case StorageAdapterProperty:
Status = AtaFdoQueryStorageAdapterProperty(ChannelExtension, Irp);
break;
default:
Status = STATUS_NOT_SUPPORTED;
break;
}
return Status;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaFdoHandleGetScsiCapabilities(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PIO_SCSI_CAPABILITIES Capabilities;
PAGED_CODE();
if (!AtaVerifyOutBuffer(IoStack, IO_SCSI_CAPABILITIES))
{
ERR("Buffer too small\n");
return STATUS_BUFFER_TOO_SMALL;
}
Capabilities = Irp->AssociatedIrp.SystemBuffer;
Capabilities->Length = sizeof(*Capabilities);
Capabilities->MaximumPhysicalPages = (ULONG)-1; /* Undetermined */
Capabilities->SupportedAsynchronousEvents = FALSE;
Capabilities->AlignmentMask = ChannelExtension->Common.Self->AlignmentRequirement;
Capabilities->TaggedQueuing = FALSE;
Capabilities->AdapterScansDown = FALSE;
Capabilities->AdapterUsesPio = FALSE; /* This differs from what AdapterProperty returns */
Capabilities->MaximumTransferLength = ChannelExtension->MaximumTransferLength;
Irp->IoStatus.Information = sizeof(*Capabilities);
return STATUS_SUCCESS;
}
static
DECLSPEC_NOINLINE_FROM_NOT_PAGED
CODE_SEG("PAGE")
NTSTATUS
AtaFdoHandleGetScsiInquiryData(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PSCSI_INQUIRY_DATA ScsiInquiryData;
PSCSI_ADAPTER_BUS_INFO ScsiAdapterBusInfo;
ULONG DeviceCount, EntrySize, TotalSize;
PSINGLE_LIST_ENTRY Entry;
PAGED_CODE();
/*
* Save the current device count. This structure member can be
* modified while we are handling this IOCTL request.
*/
DeviceCount = ChannelExtension->DeviceCount;
KeMemoryBarrierWithoutFence();
EntrySize = ALIGN_UP(sizeof(*ScsiInquiryData) - 1 + INQUIRYDATABUFFERSIZE, ULONG);
TotalSize = sizeof(*ScsiAdapterBusInfo) + EntrySize * DeviceCount;
TRACE("Total size %lu\n", TotalSize);
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < TotalSize)
return STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = TotalSize;
ScsiAdapterBusInfo = Irp->AssociatedIrp.SystemBuffer;
ScsiAdapterBusInfo->NumberOfBuses = 1;
ScsiAdapterBusInfo->BusData[0].NumberOfLogicalUnits = 0;
ScsiAdapterBusInfo->BusData[0].InitiatorBusId = 0xFF;
ScsiAdapterBusInfo->BusData[0].InquiryDataOffset = sizeof(*ScsiAdapterBusInfo);
ScsiInquiryData = (PSCSI_INQUIRY_DATA)(ScsiAdapterBusInfo + 1);
ExAcquireFastMutex(&ChannelExtension->DeviceSyncMutex);
for (Entry = &ChannelExtension->DeviceList;
Entry != NULL;
Entry = Entry->Next)
{
PATAPORT_DEVICE_EXTENSION DeviceExtension;
ATA_SCSI_ADDRESS AtaScsiAddress;
PINQUIRYDATA InquiryData;
DeviceExtension = CONTAINING_RECORD(Entry, ATAPORT_DEVICE_EXTENSION, ListEntry);
if (DeviceExtension->ReportedMissing)
continue;
AtaScsiAddress = DeviceExtension->AtaScsiAddress;
ScsiInquiryData->PathId = AtaScsiAddress.PathId;
ScsiInquiryData->TargetId = AtaScsiAddress.TargetId;
ScsiInquiryData->Lun = AtaScsiAddress.Lun;
ScsiInquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
ScsiInquiryData->DeviceClaimed = DeviceExtension->DeviceClaimed;
ScsiInquiryData->NextInquiryDataOffset =
(ULONG)((ULONG_PTR)ScsiInquiryData + EntrySize - (ULONG_PTR)ScsiAdapterBusInfo);
RtlCopyMemory(ScsiInquiryData->InquiryData,
&DeviceExtension->InquiryData,
INQUIRYDATABUFFERSIZE);
/* Limit the standard INQUIRY data to 36 bytes */
InquiryData = (PINQUIRYDATA)ScsiInquiryData->InquiryData;
InquiryData->AdditionalLength =
INQUIRYDATABUFFERSIZE - RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength);
ScsiInquiryData = (PSCSI_INQUIRY_DATA)((ULONG_PTR)ScsiInquiryData + EntrySize);
if (++ScsiAdapterBusInfo->BusData[0].NumberOfLogicalUnits >= DeviceCount)
break;
}
ExReleaseFastMutex(&ChannelExtension->DeviceSyncMutex);
/* Terminate the last entry */
if (ScsiAdapterBusInfo->BusData[0].NumberOfLogicalUnits != 0)
{
ScsiInquiryData = ((PSCSI_INQUIRY_DATA)((ULONG_PTR)ScsiInquiryData - EntrySize));
ScsiInquiryData->NextInquiryDataOffset = 0;
}
else
{
ScsiAdapterBusInfo->BusData[0].InquiryDataOffset = 0;
}
return STATUS_SUCCESS;
}
static
NTSTATUS
AtaFdoDeviceControl(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_Inout_ PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
Status = IoAcquireRemoveLock(&ChannelExtension->RemoveLock, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_STORAGE_QUERY_PROPERTY:
Status = AtaFdoHandleStorageQueryProperty(ChannelExtension, Irp, IoStack);
break;
case IOCTL_SCSI_GET_CAPABILITIES:
Status = AtaFdoHandleGetScsiCapabilities(ChannelExtension, Irp, IoStack);
break;
case IOCTL_SCSI_GET_INQUIRY_DATA:
Status = AtaFdoHandleGetScsiInquiryData(ChannelExtension, Irp, IoStack);
break;
case IOCTL_SCSI_RESCAN_BUS:
IoInvalidateDeviceRelations(ChannelExtension->Common.Self, BusRelations);
Status = STATUS_SUCCESS;
break;
default:
{
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(ChannelExtension->Ldo, Irp);
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
return Status;
}
}
IoReleaseRemoveLock(&ChannelExtension->RemoveLock, Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/*
* For storage drivers this dispatch function must be not paged,
* because it must be present when it is received unknown IOCTL,
* otherwise we risk locking up the whole system.
*/
NTSTATUS
NTAPI
AtaDispatchDeviceControl(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
if (IS_FDO(DeviceObject->DeviceExtension))
return AtaFdoDeviceControl(DeviceObject->DeviceExtension, Irp);
else
return AtaPdoDeviceControl(DeviceObject->DeviceExtension, Irp);
}

View File

@ -0,0 +1,765 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Legacy (non-PnP) IDE controllers support
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
typedef struct _ATA_LEGACY_CHANNEL
{
ULONG IoBase;
ULONG Irq;
} ATA_LEGACY_CHANNEL, *PATA_LEGACY_CHANNEL;
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("INIT")
BOOLEAN
AtaDeviceSignatureValid(
_In_ PIDE_REGISTERS Registers)
{
UCHAR SignatureLow, SignatureHigh;
SignatureLow = ATA_READ(Registers->SignatureLow);
SignatureHigh = ATA_READ(Registers->SignatureHigh);
TRACE("SL = 0x%02x, SH = 0x%02x\n", SignatureLow, SignatureHigh);
/* ATA signature */
if (SignatureLow == 0x00 && SignatureHigh == 0x00)
return TRUE;
/* ATAPI signature */
if (SignatureLow == 0x14 && SignatureHigh == 0xEB)
return TRUE;
return FALSE;
}
static
CODE_SEG("INIT")
BOOLEAN
AtaLegacyIdentifyDevice(
_In_ ULONG DeviceNumber,
_In_ PIDE_REGISTERS Registers,
_In_ BOOLEAN TryAtapi)
{
IDENTIFY_DEVICE_DATA IdentifyDeviceData;
UCHAR Status, ErrorCode;
ULONG i;
/* Select the device */
ATA_WRITE(Registers->DriveSelect, ((DeviceNumber << 4) | IDE_DRIVE_SELECT));
ATA_IO_WAIT();
/*
* Signature check after device reset.
* Note that the NEC CDR-260 drive reports an ATA signature.
*/
if (AtaDeviceSignatureValid(Registers))
return TRUE;
/*
* One last check to make sure the IDE device is there: send the identify command,
* it should be successfully completed or failed (aborted or time-out).
*/
ATA_WRITE(Registers->Feature, 0);
ATA_WRITE(Registers->SectorCount, 0);
ATA_WRITE(Registers->LowLba, 0);
ATA_WRITE(Registers->MidLba, 0);
ATA_WRITE(Registers->HighLba, 0);
ATA_WRITE(Registers->Command, TryAtapi ? IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY);
/* Need to wait for a valid status */
ATA_IO_WAIT();
/* Wait for busy being cleared and DRQ or ERR bit being set */
for (i = 0; i < 100000; ++i)
{
Status = ATA_READ(Registers->Status);
if (Status == 0xFF || Status == 0x7F)
return FALSE;
if (!(Status & IDE_STATUS_BUSY))
break;
KeStallExecutionProcessor(10);
}
if (Status & IDE_STATUS_BUSY)
{
TRACE("Timeout, status 0x%02x\n", Status);
return FALSE;
}
if (Status & IDE_STATUS_ERROR)
{
ErrorCode = ATA_READ(Registers->Error);
TRACE("Command 0x%02x aborted, status 0x%02x, error 0x%02x\n",
TryAtapi ? IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
Status,
ErrorCode);
return FALSE;
}
/* Wait for DRQ */
if (!(Status & IDE_STATUS_DRQ))
{
for (i = 0; i < 100000; ++i)
{
Status = ATA_READ(Registers->Status);
if (Status == 0xFF || Status == 0x7F)
return FALSE;
if (Status & IDE_STATUS_DRQ)
break;
KeStallExecutionProcessor(10);
}
}
if (!(Status & IDE_STATUS_DRQ))
{
TRACE("Timeout, status 0x%02x\n", Status);
return FALSE;
}
/* Receive parameter information from the device to complete the data transfer */
ATA_READ_BLOCK_16((PUSHORT)Registers->Data,
(PUSHORT)&IdentifyDeviceData,
sizeof(IdentifyDeviceData) / sizeof(USHORT));
/* Need to wait for a valid status */
ATA_IO_WAIT();
/* Wait for an idle state */
for (i = 0; i < 100000; ++i)
{
Status = ATA_READ(Registers->Status);
if (Status == 0xFF || Status == 0x7F)
return FALSE;
if (!(Status & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)))
{
if (!(Status & IDE_STATUS_DRDY) && !TryAtapi)
return FALSE;
return TRUE;
}
KeStallExecutionProcessor(10);
}
TRACE("Timeout, status 0x%02x\n", Status);
return FALSE;
}
static
CODE_SEG("INIT")
BOOLEAN
AtaLegacyChannelPresent(
_In_ PIDE_REGISTERS Registers)
{
ULONG DeviceNumber, i;
UCHAR Status;
/* The on-board IDE interface is always assumed to be present */
if (IsNEC_98)
return TRUE;
for (DeviceNumber = 0; DeviceNumber < CHANNEL_PCAT_MAX_DEVICES; ++DeviceNumber)
{
/* Select the device */
ATA_WRITE(Registers->DriveSelect, ((DeviceNumber << 4) | IDE_DRIVE_SELECT));
ATA_IO_WAIT();
/* Do a quick check first */
Status = ATA_READ(Registers->Status);
if (Status == 0xFF || Status == 0x7F)
continue;
/* Look at controller */
ATA_WRITE(Registers->ByteCountLow, 0x55);
ATA_WRITE(Registers->ByteCountLow, 0xAA);
ATA_WRITE(Registers->ByteCountLow, 0x55);
if (ATA_READ(Registers->ByteCountLow) != 0x55)
continue;
ATA_WRITE(Registers->ByteCountHigh, 0xAA);
ATA_WRITE(Registers->ByteCountHigh, 0x55);
ATA_WRITE(Registers->ByteCountHigh, 0xAA);
if (ATA_READ(Registers->ByteCountHigh) != 0xAA)
continue;
/* Perform a software reset so that we can check the device signature */
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 != 0)
{
for (i = 200000; i > 0; --i)
{
/* Select the device again */
ATA_WRITE(Registers->DriveSelect, ((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)
{
TRACE("Selection timeout\n");
break;
}
}
/* Now wait for busy to clear */
for (i = 0; i < 500000; ++i)
{
Status = ATA_READ(Registers->Status);
if (Status == 0xFF || Status == 0x7F)
goto SkipDevice;
if (!(Status & IDE_STATUS_BUSY))
break;
KeStallExecutionProcessor(10);
}
if (Status & IDE_STATUS_BUSY)
{
TRACE("Timeout, status 0x%02x\n", Status);
SkipDevice:
continue;
}
/* Check for an ATA or ATAPI device on the channel */
if (AtaLegacyIdentifyDevice(DeviceNumber, Registers, FALSE) ||
AtaLegacyIdentifyDevice(DeviceNumber, Registers, TRUE))
{
TRACE("Found IDE device\n");
return TRUE;
}
}
return FALSE;
}
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;
if (IsNEC_98)
{
if (ConfigInfo->AtDiskPrimaryAddressClaimed ||
ConfigInfo->AtDiskSecondaryAddressClaimed)
{
return FALSE;
}
/*
* Create the 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
*/
#define CHANNEL_PC98_RESOURCE_COUNT 12
Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = 0x640;
Descriptor->u.Port.Length = 1;
++Descriptor;
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = 0x74C;
Descriptor->u.Port.Length = 1;
++Descriptor;
Descriptor->Type = CmResourceTypeInterrupt;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
Descriptor->u.Interrupt.Level = 9;
Descriptor->u.Interrupt.Vector = 9;
Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
++Descriptor;
for (i = 0; i < 7; ++i)
{
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = 0x642 + i * 2;
Descriptor->u.Port.Length = 1;
++Descriptor;
}
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = 0x432;
Descriptor->u.Port.Length = 2;
++Descriptor;
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = 0x435;
Descriptor->u.Port.Length = 1;
}
else
{
if (LegacyChannel->IoBase == 0x1F0 && ConfigInfo->AtDiskPrimaryAddressClaimed)
return FALSE;
if (LegacyChannel->IoBase == 0x170 && ConfigInfo->AtDiskSecondaryAddressClaimed)
return FALSE;
/*
* For example, the following resource list is created for the primary IDE channel:
*
* [ShareDisposition 1, Flags 11] IO: Start 0:168, Len 8
* [ShareDisposition 1, Flags 11] IO: Start 0:36E, Len 1
* [ShareDisposition 1, Flags 1] INT: Lev A Vec A Aff FFFFFFFF
*/
#define CHANNEL_PCAT_RESOURCE_COUNT 3
Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = LegacyChannel->IoBase;
Descriptor->u.Port.Length = 8;
++Descriptor;
Descriptor->Type = CmResourceTypePort;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
Descriptor->u.Port.Start.u.LowPart = LegacyChannel->IoBase + 0x206;
Descriptor->u.Port.Length = 1;
++Descriptor;
Descriptor->Type = CmResourceTypeInterrupt;
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
Descriptor->u.Interrupt.Level = LegacyChannel->Irq;
Descriptor->u.Interrupt.Vector = LegacyChannel->Irq;
Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
}
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);
}
static
CODE_SEG("INIT")
PVOID
AtaTranslateBusAddress(
_In_ ULONG Address,
_In_ ULONG NumberOfBytes,
_Out_ PBOOLEAN MappedAddress)
{
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)
{
*MappedAddress = FALSE;
return (PVOID)(ULONG_PTR)TranslatedAddress.QuadPart;
}
else
{
*MappedAddress = 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")
VOID
AtaLegacyDetectChannel(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PATA_LEGACY_CHANNEL LegacyChannel,
_In_ PCM_RESOURCE_LIST ResourceList,
_In_ ULONG ResourceListSize)
{
NTSTATUS Status;
BOOLEAN MappedAddress;
PDEVICE_OBJECT PhysicalDeviceObject;
PATAPORT_CHANNEL_EXTENSION ChannelExtension;
IDE_REGISTERS Registers;
ULONG Spare;
TRACE("IDE Channel IO %lx, Irq %lu\n", LegacyChannel->IoBase, LegacyChannel->Irq);
if (!AtaLegacyChannelBuildResources(LegacyChannel, ResourceList))
{
TRACE("Failed to build the resource list\n");
return;
}
if (!AtaLegacyClaimHardwareResources(DriverObject, ResourceList, ResourceListSize))
{
TRACE("Failed to claim resources\n");
return;
}
Status = STATUS_SUCCESS;
MappedAddress = 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 = AtaTranslateBusAddress(LegacyChannel->IoBase, 8, &MappedAddress);
if (!Registers.Data)
{
TRACE("Failed to map command port\n");
Status = STATUS_UNSUCCESSFUL;
goto ReleaseResources;
}
Registers.Control = AtaTranslateBusAddress(LegacyChannel->IoBase + 0x206, 1, &MappedAddress);
if (!Registers.Control)
{
TRACE("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.LowLba = (PVOID)((ULONG_PTR)Registers.Data + 3 * Spare);
Registers.MidLba = (PVOID)((ULONG_PTR)Registers.Data + 4 * Spare);
Registers.HighLba = (PVOID)((ULONG_PTR)Registers.Data + 5 * Spare);
Registers.DriveSelect = (PVOID)((ULONG_PTR)Registers.Data + 6 * Spare);
Registers.Status = (PVOID)((ULONG_PTR)Registers.Data + 7 * Spare);
if (!AtaLegacyChannelPresent(&Registers))
{
TRACE("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))
{
TRACE("IoReportDetectedDevice() failed with status 0x%lx\n", Status);
goto Cleanup;
}
Status = AtaAddChannel(DriverObject, PhysicalDeviceObject, &ChannelExtension);
if (!NT_SUCCESS(Status))
{
TRACE("AtaAddChannel() failed with status 0x%lx\n", Status);
goto Cleanup;
}
AtaLegacyChannelTranslateResources(ResourceList, Registers.Data, Registers.Control);
Status = AtaFdoStartDevice(ChannelExtension, ResourceList);
if (!NT_SUCCESS(Status))
{
ERR("Failed to start the legacy channel, status 0x%lx\n", Status);
AtaFdoRemoveDevice(ChannelExtension, NULL);
}
Cleanup:
if (MappedAddress)
{
if (Registers.Data)
MmUnmapIoSpace(Registers.Data, 8);
if (Registers.Control)
MmUnmapIoSpace(Registers.Control, 1);
}
}
static
CODE_SEG("INIT")
BOOLEAN
AtaLegacyShouldDetectChannels(VOID)
{
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))
{
TRACE("Skip legacy detection on a PnP system\n");
return FALSE;
}
/* Open the driver's software key */
Status = AtaOpenRegistryKey(&SoftKeyHandle,
NULL,
&AtapDriverRegistryPath,
FALSE);
if (!NT_SUCCESS(Status))
{
ERR("Failed to open the '%wZ' key, status 0x%lx\n", &AtapDriverRegistryPath, Status);
return FALSE;
}
/* Open the 'Parameters' key */
Status = AtaOpenRegistryKey(&ParamsKeyHandle,
SoftKeyHandle,
&ParametersKeyName,
FALSE);
if (!NT_SUCCESS(Status))
{
ERR("Failed to open the 'Parameters' key, status 0x%lx\n", Status);
ZwClose(SoftKeyHandle);
return FALSE;
}
/* Check whether it's 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);
/* Don't 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")
VOID
AtaDetectLegacyDevices(
_In_ PDRIVER_OBJECT DriverObject)
{
ATA_LEGACY_CHANNEL LegacyChannel[4 + 1] = {0};
PCM_RESOURCE_LIST ResourceList;
ULONG ListSize, ResourceCount, i;
if (!AtaLegacyShouldDetectChannels())
return;
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, IDEPORT_TAG);
if (!ResourceList)
{
INFO("Failed to allocate the resource list\n");
return;
}
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;
for (i = 0; LegacyChannel[i].IoBase; ++i)
{
AtaLegacyDetectChannel(DriverObject, &LegacyChannel[i], ResourceList, ListSize);
}
ExFreePoolWithTag(ResourceList, IDEPORT_TAG);
}

View File

@ -0,0 +1,842 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Child device object (PDO) dispatch routines
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
static
CODE_SEG("PAGE")
VOID
AtaPdoSetConfig(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension)
{
PATA_TASKFILE TaskFile = &DeviceExtension->ChannelExtension->TaskFile[SRB_TYPE_CONFIG];
NTSTATUS Status;
PAGED_CODE();
/* ACPI initialization */
if (DeviceExtension->GtfDataBuffer)
{
AtaAcpiExecuteTaskFile(DeviceExtension, DeviceExtension->GtfDataBuffer, TaskFile);
}
RtlZeroMemory(TaskFile, sizeof(*TaskFile));
/* Make the device settings persistent for a software reset */
TaskFile->Command = IDE_COMMAND_SET_FEATURE;
TaskFile->Feature = IDE_FEATURE_DISABLE_REVERT_TO_POWER_ON;
Status = AtaSendTaskFile(DeviceExtension, TaskFile, SRB_TYPE_CONFIG, FALSE, 10, NULL, 0);
TRACE("Feature Lock status 0x%lx\n", Status);
/* Enable multiple mode */
if (!IS_ATAPI(DeviceExtension))
{
DeviceExtension->MultiSectorTransfer =
AtaMaximumSectorsPerDrq(&DeviceExtension->IdentifyDeviceData);
if (DeviceExtension->MultiSectorTransfer != 0)
{
TaskFile->Command = IDE_COMMAND_SET_MULTIPLE;
TaskFile->SectorCount = DeviceExtension->MultiSectorTransfer;
Status = AtaSendTaskFile(DeviceExtension, TaskFile, SRB_TYPE_CONFIG, FALSE, 3, NULL, 0);
if (!NT_SUCCESS(Status))
{
WARN("Multiple mode failed with status 0x%lx\n", Status);
DeviceExtension->MultiSectorTransfer = 0;
}
}
}
/* Lock the security mode feature commands (secure erase and friends) */
if (!AtapInPEMode && !IS_ATAPI(DeviceExtension))
{
TaskFile->Command = IDE_COMMAND_SECURITY_FREEZE_LOCK;
TaskFile->Feature = 0;
Status = AtaSendTaskFile(DeviceExtension, TaskFile, SRB_TYPE_CONFIG, FALSE, 10, NULL, 0);
TRACE("SEC Lock status 0x%lx\n", Status);
}
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoStartDevice(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
AtaPdoWmiRegistration(DeviceExtension, TRUE);
/*
* Get the IDE initialization commands to restore the boot up defaults.
* This should be executed after _STM has been evaluated,
* because it's expected that ACPI BIOS will use the identity data buffers
* to construct the list of ATA commands to the drive.
*/
if (!DeviceExtension->GtfDataBuffer)
{
DeviceExtension->GtfDataBuffer = AtaAcpiGetTaskFile(DeviceExtension);
}
AtaPdoSetConfig(DeviceExtension);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoStopDevice(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoRemoveDevice(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp,
_In_ BOOLEAN FinalRemove)
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = DeviceExtension->ChannelExtension;
PAGED_CODE();
AtaPdoWmiRegistration(DeviceExtension, FALSE);
if (DeviceExtension->GtfDataBuffer)
ExFreePoolWithTag(DeviceExtension->GtfDataBuffer, IDEPORT_TAG);
if (FinalRemove && DeviceExtension->ReportedMissing)
{
PATAPORT_DEVICE_EXTENSION CurrentDeviceExtension;
PSINGLE_LIST_ENTRY Entry, PrevEntry;
ATA_SCSI_ADDRESS Address = DeviceExtension->AtaScsiAddress;
IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, Irp);
ExAcquireFastMutex(&ChannelExtension->DeviceSyncMutex);
for (Entry = ChannelExtension->DeviceList.Next, PrevEntry = NULL;
Entry != NULL;
Entry = Entry->Next)
{
CurrentDeviceExtension = CONTAINING_RECORD(Entry, ATAPORT_DEVICE_EXTENSION, ListEntry);
if (CurrentDeviceExtension->AtaScsiAddress.AsULONG > Address.AsULONG)
break;
PrevEntry = Entry;
}
if (PrevEntry)
{
DeviceExtension->ListEntry.Next = PrevEntry->Next;
PrevEntry->Next = DeviceExtension->ListEntry.Next;
}
else
{
PopEntryList(&DeviceExtension->ListEntry);
}
ExReleaseFastMutex(&ChannelExtension->DeviceSyncMutex);
IoDeleteDevice(DeviceExtension->Common.Self);
}
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryStopRemoveDevice(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
if (DeviceExtension->Common.PageFiles ||
DeviceExtension->Common.HibernateFiles ||
DeviceExtension->Common.DumpFiles)
{
return STATUS_DEVICE_BUSY;
}
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryPnpDeviceState(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
if (DeviceExtension->Common.PageFiles ||
DeviceExtension->Common.HibernateFiles ||
DeviceExtension->Common.DumpFiles)
{
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
}
return STATUS_SUCCESS;
}
static IO_COMPLETION_ROUTINE AtaOnRepeaterCompletion;
static
NTSTATUS
NTAPI
AtaOnRepeaterCompletion(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
_In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned)
KeSetEvent(Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoRepeatRequest(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_opt_ PDEVICE_CAPABILITIES DeviceCapabilities)
{
PDEVICE_OBJECT Fdo, TopDeviceObject;
PIO_STACK_LOCATION IoStack, SubStack;
PIRP SubIrp;
KEVENT Event;
NTSTATUS Status;
PAGED_CODE();
Fdo = DeviceExtension->ChannelExtension->Common.Self;
TopDeviceObject = IoGetAttachedDeviceReference(Fdo);
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(*IoStack));
if (DeviceCapabilities)
SubStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
IoSetCompletionRoutine(SubIrp,
AtaOnRepeaterCompletion,
&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;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryCapabilities(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
DEVICE_CAPABILITIES ParentCapabilities;
PDEVICE_CAPABILITIES DeviceCapabilities;
NTSTATUS Status;
ATA_SCSI_ADDRESS AtaScsiAddress;
PAGED_CODE();
/* Get the capabilities of the parent device */
RtlZeroMemory(&ParentCapabilities, sizeof(ParentCapabilities));
ParentCapabilities.Size = sizeof(ParentCapabilities);
ParentCapabilities.Version = 1;
ParentCapabilities.Address = MAXULONG;
ParentCapabilities.UINumber = MAXULONG;
Status = AtaPdoRepeatRequest(DeviceExtension, Irp, &ParentCapabilities);
if (!NT_SUCCESS(Status))
return Status;
DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
*DeviceCapabilities = ParentCapabilities;
AtaScsiAddress = DeviceExtension->AtaScsiAddress;
/* Override some fields */
DeviceCapabilities->UINumber = AtaScsiAddress.TargetId;
DeviceCapabilities->Address = (AtaScsiAddress.Lun << 4) | (AtaScsiAddress.TargetId & 0x0F);
DeviceCapabilities->UniqueID = AtaPdoSerialNumberValid(DeviceExtension);
DeviceCapabilities->Removable = FALSE;
DeviceCapabilities->SurpriseRemovalOK = FALSE;
DeviceCapabilities->D1Latency =
DeviceCapabilities->D2Latency =
DeviceCapabilities->D3Latency = 31 * 10000; /* 31 seconds */
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoDeviceUsageNotification(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
NTSTATUS Status;
volatile LONG* Counter;
PAGED_CODE();
Status = AtaPdoRepeatRequest(DeviceExtension, Irp, NULL);
if (!NT_SUCCESS(Status))
return Status;
switch (IoStack->Parameters.UsageNotification.Type)
{
case DeviceUsageTypePaging:
Counter = &DeviceExtension->Common.PageFiles;
break;
case DeviceUsageTypeHibernation:
Counter = &DeviceExtension->Common.HibernateFiles;
break;
case DeviceUsageTypeDumpFile:
Counter = &DeviceExtension->Common.DumpFiles;
break;
default:
return Status;
}
IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
IoInvalidateDeviceState(DeviceExtension->Common.Self);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryTargetDeviceRelations(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp)
{
PDEVICE_RELATIONS DeviceRelations;
PAGED_CODE();
DeviceRelations = ExAllocatePoolUninitialized(PagedPool,
sizeof(*DeviceRelations),
IDEPORT_TAG);
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
DeviceRelations->Count = 1;
DeviceRelations->Objects[0] = DeviceExtension->Common.Self;
ObReferenceObject(DeviceExtension->Common.Self);
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryId(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
CHAR LocalBuffer[ATAPORT_FN_FIELD + ATAPORT_RN_FIELD];
NTSTATUS Status;
PWCHAR Buffer, End;
PCSTR DeviceType, GenericType;
size_t CharCount, Remaining;
PAGED_CODE();
switch (IoStack->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
{
DeviceType = AtaTypeCodeToName(DeviceExtension, GetDeviceType);
/* 'IDE\CdRomVBOX_CD-ROM_____________________________1.0_____' */
CharCount = (sizeof("IDE\\") - 1) + strlen(DeviceType) +
ATAPORT_FN_FIELD + ATAPORT_RN_FIELD +
sizeof(ANSI_NULL);
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
AtaCopyIdString(LocalBuffer,
(PUCHAR)DeviceExtension->FriendlyName,
ATAPORT_FN_FIELD,
'_');
AtaCopyIdString(&LocalBuffer[ATAPORT_FN_FIELD],
(PUCHAR)DeviceExtension->RevisionNumber,
ATAPORT_RN_FIELD,
'_');
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
NULL,
NULL,
0,
L"IDE\\%hs%.48hs",
DeviceType,
LocalBuffer);
ASSERT(NT_SUCCESS(Status));
INFO("DeviceID: '%S'\n", Buffer);
break;
}
case BusQueryHardwareIDs:
{
PWCHAR IdStart;
DBG_UNREFERENCED_LOCAL_VARIABLE(IdStart);
DeviceType = AtaTypeCodeToName(DeviceExtension, GetDeviceType);
GenericType = AtaTypeCodeToName(DeviceExtension, GetGenericType);
/*
* |------------------ 40 -----------------|-- 8 --|
* v v v
* 1) 'IDE\CdRomVBOX_CD-ROM_____________________________1.0_____'
* 2) 'IDE\VBOX_CD-ROM_____________________________1.0_____'
* 3) 'IDE\CdRomVBOX_CD-ROM_____________________________'
* 4) 'VBOX_CD-ROM_____________________________1.0_____'
* 5) 'GenCdRom'
*/
CharCount = strlen(DeviceType) * 2 +
strlen(GenericType) +
(sizeof("IDE\\") - 1) * 3 +
ATAPORT_FN_FIELD * 4 +
ATAPORT_RN_FIELD * 3 +
5 * sizeof(ANSI_NULL) +
sizeof(ANSI_NULL); /* multi-string */
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
AtaCopyIdString(LocalBuffer,
(PUCHAR)DeviceExtension->FriendlyName,
ATAPORT_FN_FIELD,
'_');
AtaCopyIdString(&LocalBuffer[ATAPORT_FN_FIELD],
(PUCHAR)DeviceExtension->RevisionNumber,
ATAPORT_RN_FIELD,
'_');
INFO("HardwareIDs:\n");
/* ID 1 */
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"IDE\\%hs%.48hs",
DeviceType,
LocalBuffer);
ASSERT(NT_SUCCESS(Status));
INFO(" '%S'\n", Buffer);
++End;
--Remaining;
/* ID 2 */
IdStart = End;
Status = RtlStringCchPrintfExW(End,
Remaining,
&End,
&Remaining,
0,
L"IDE\\%.48hs",
LocalBuffer);
ASSERT(NT_SUCCESS(Status));
INFO(" '%S'\n", IdStart);
++End;
--Remaining;
/* ID 3 */
IdStart = End;
Status = RtlStringCchPrintfExW(End,
Remaining,
&End,
&Remaining,
0,
L"IDE\\%hs%.40hs",
DeviceType,
LocalBuffer);
ASSERT(NT_SUCCESS(Status));
INFO(" '%S'\n", IdStart);
++End;
--Remaining;
/* ID 4 */
IdStart = End;
Status = RtlStringCchPrintfExW(End,
Remaining,
&End,
&Remaining,
0,
L"%.48hs",
LocalBuffer);
ASSERT(NT_SUCCESS(Status));
INFO(" '%S'\n", IdStart);
++End;
--Remaining;
/* ID 5 */
IdStart = End;
Status = RtlStringCchPrintfExW(End,
Remaining,
&End,
&Remaining,
0,
L"%hs",
GenericType);
ASSERT(NT_SUCCESS(Status));
*++End = UNICODE_NULL; /* multi-string */
INFO(" '%S'\n", IdStart);
break;
}
case BusQueryCompatibleIDs:
{
GenericType = AtaTypeCodeToName(DeviceExtension, GetGenericType);
/* 'GenCdRom' */
CharCount = strlen(GenericType) + 2 * sizeof(ANSI_NULL); /* multi-string */
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"%hs",
GenericType);
ASSERT(NT_SUCCESS(Status));
*++End = UNICODE_NULL; /* multi-string */
INFO("CompatibleIDs: '%S'\n", Buffer);
break;
}
case BusQueryInstanceID:
{
if (AtaPdoSerialNumberValid(DeviceExtension))
{
/* The serial number in string form ('42562d3131303066333036662020202020202020') */
CharCount = strlen(DeviceExtension->SerialNumber) + sizeof(ANSI_NULL);
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"%hs",
DeviceExtension->SerialNumber);
ASSERT(NT_SUCCESS(Status));
}
else
{
ATA_SCSI_ADDRESS AtaScsiAddress;
/*
* Use the 'Path.Target.Lun' format as a fallback.
* Note that on some ancient (pre-1994) IDE drives,
* IDENTIFY DEVICE words 7-255 are reserved and filled with zeros.
*/
CharCount = sizeof("FF.FF.FF");
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
AtaScsiAddress = DeviceExtension->AtaScsiAddress;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"%x.%x.%x",
AtaScsiAddress.PathId,
AtaScsiAddress.TargetId,
AtaScsiAddress.Lun);
ASSERT(NT_SUCCESS(Status));
}
INFO("InstanceID: '%S'\n", Buffer);
break;
}
default:
return Irp->IoStatus.Status;
}
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoQueryDeviceText(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
NTSTATUS Status;
PWCHAR Buffer;
size_t CharCount;
PAGED_CODE();
switch (IoStack->Parameters.QueryDeviceText.DeviceTextType)
{
case DeviceTextDescription:
{
CharCount = strlen(DeviceExtension->FriendlyName) + sizeof(ANSI_NULL);
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
NULL,
NULL,
0,
L"%hs",
DeviceExtension->FriendlyName);
ASSERT(NT_SUCCESS(Status));
INFO("TextDescription: '%S'\n", Buffer);
break;
}
case DeviceTextLocationInformation:
{
/* The target ID (0 - Master, 1 - Slave) */
CharCount = sizeof("0");
Buffer = ExAllocatePoolUninitialized(PagedPool,
CharCount * sizeof(WCHAR),
IDEPORT_TAG);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
NULL,
NULL,
0,
L"%u",
/* The C-Bus IDE can support up to 4 target devices */
DeviceExtension->AtaScsiAddress.TargetId & 1);
ASSERT(NT_SUCCESS(Status));
INFO("TextLocationInformation: '%S'\n", Buffer);
break;
}
default:
return Irp->IoStatus.Status;
}
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoPnp(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp)
{
NTSTATUS Status;
PIO_STACK_LOCATION IoStack;
PAGED_CODE();
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch (IoStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
Status = AtaPdoStartDevice(DeviceExtension, Irp);
break;
case IRP_MN_STOP_DEVICE:
Status = AtaPdoStopDevice(DeviceExtension, Irp);
break;
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
Status = AtaPdoRemoveDevice(DeviceExtension,
Irp,
(IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE));
break;
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
Status = AtaPdoQueryStopRemoveDevice(DeviceExtension, Irp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_CAPABILITIES:
Status = AtaPdoQueryCapabilities(DeviceExtension, Irp, IoStack);
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
Status = AtaPdoQueryPnpDeviceState(DeviceExtension, Irp);
break;
case IRP_MN_QUERY_ID:
Status = AtaPdoQueryId(DeviceExtension, Irp, IoStack);
break;
case IRP_MN_QUERY_DEVICE_TEXT:
Status = AtaPdoQueryDeviceText(DeviceExtension, Irp, IoStack);
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
Status = AtaPdoDeviceUsageNotification(DeviceExtension, Irp, IoStack);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
Status = AtaPdoQueryTargetDeviceRelations(DeviceExtension, Irp);
else
Status = Irp->IoStatus.Status;
break;
}
default:
Status = Irp->IoStatus.Status;
break;
}
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaDispatchPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PAGED_CODE();
if (IS_FDO(DeviceObject->DeviceExtension))
return AtaFdoPnp(DeviceObject->DeviceExtension, Irp);
else
return AtaPdoPnp(DeviceObject->DeviceExtension, Irp);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: SMART Feature Set support
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* FUNCTIONS ******************************************************************/
static
ATA_COMPLETION_STATUS
AtaReqCompleteSmartCommand(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
PSENDCMDOUTPARAMS CmdOut = Request->OldDataBuffer;
if (Request->SrbStatus == SRB_STATUS_SUCCESS)
{
CmdOut->DriverStatus.bDriverError = SMART_NO_ERROR;
CmdOut->DriverStatus.bIDEError = 0;
}
else
{
CmdOut->DriverStatus.bDriverError = SMART_IDE_ERROR;
CmdOut->DriverStatus.bIDEError = Request->Error;
}
/* Return the SMART status */
if (Request->Flags & REQUEST_FLAG_SAVE_TASK_FILE)
{
if (Request->Flags & REQUEST_FLAG_HAS_TASK_FILE)
{
PIDEREGS IdeRegs = Request->DataBuffer;
IdeRegs->bFeaturesReg = Request->TaskFile.Feature;
IdeRegs->bSectorCountReg = Request->TaskFile.SectorCount;
IdeRegs->bSectorNumberReg = Request->TaskFile.LowLba;
IdeRegs->bCylLowReg = Request->TaskFile.MidLba;
IdeRegs->bCylHighReg = Request->TaskFile.HighLba;
IdeRegs->bCommandReg = Request->TaskFile.Command;
IdeRegs->bDriveHeadReg = Request->TaskFile.DriveSelect;
}
else
{
CmdOut->DriverStatus.bDriverError = SMART_IDE_ERROR;
CmdOut->DriverStatus.bIDEError = Request->Error;
}
}
return COMPLETE_IRP;
}
ULONG
AtaReqIoControl(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
PATA_DEVICE_REQUEST Request = &ChannelExtension->Request;
PATA_TASKFILE TaskFile = &Request->TaskFile;
union _PARAMS
{
PSENDCMDINPARAMS CmdIn;
PSENDCMDOUTPARAMS CmdOut;
} Buffer;
if (Srb->DataTransferLength < (sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdIn) - 1))
return SRB_STATUS_INVALID_REQUEST;
Buffer.CmdIn = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (Buffer.CmdIn->irDriveRegs.bCommandReg != SMART_CMD)
return SRB_STATUS_INVALID_REQUEST;
Request->Complete = AtaReqCompleteSmartCommand;
Request->DeviceExtension = DeviceExtension;
Request->Mdl = Request->Irp->MdlAddress;
Request->OldDataBuffer = Buffer.CmdOut;
switch (Buffer.CmdIn->irDriveRegs.bFeaturesReg)
{
case READ_ATTRIBUTES:
case READ_THRESHOLDS:
case SMART_READ_LOG:
{
if (Buffer.CmdIn->irDriveRegs.bFeaturesReg == SMART_READ_LOG)
{
Request->DataTransferLength =
Buffer.CmdIn->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
}
else
{
Request->DataTransferLength = READ_ATTRIBUTE_BUFFER_SIZE;
}
Request->DataBuffer = Buffer.CmdOut->bBuffer;
Request->Flags = REQUEST_FLAG_ASYNC_MODE | REQUEST_FLAG_DATA_IN;
break;
}
case SMART_WRITE_LOG:
{
Request->DataTransferLength =
Buffer.CmdIn->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
Request->DataBuffer = Buffer.CmdOut->bBuffer;
Request->Flags = REQUEST_FLAG_ASYNC_MODE | REQUEST_FLAG_DATA_OUT;
break;
}
case RETURN_SMART_STATUS:
{
Request->DataTransferLength = sizeof(IDEREGS);
Request->DataBuffer = Buffer.CmdOut->bBuffer;
Request->Flags = REQUEST_FLAG_ASYNC_MODE | REQUEST_FLAG_SAVE_TASK_FILE;
break;
}
case EXECUTE_OFFLINE_DIAGS:
{
UCHAR Subcommand = Buffer.CmdIn->irDriveRegs.bSectorNumberReg;
if (Subcommand == SMART_SHORT_SELFTEST_CAPTIVE ||
Subcommand == SMART_EXTENDED_SELFTEST_CAPTIVE)
{
return SRB_STATUS_INVALID_REQUEST;
}
__fallthrough;
}
case ENABLE_DISABLE_AUTOSAVE:
case SAVE_ATTRIBUTE_VALUES:
case ENABLE_SMART:
case DISABLE_SMART:
case ENABLE_DISABLE_AUTO_OFFLINE:
{
Request->DataTransferLength = 0;
Request->DataBuffer = NULL;
Request->Flags = REQUEST_FLAG_ASYNC_MODE;
break;
}
default:
return SRB_STATUS_INVALID_REQUEST;
}
if (Request->Flags & (REQUEST_FLAG_DATA_OUT | REQUEST_FLAG_SAVE_TASK_FILE))
{
if (Srb->DataTransferLength <
(sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdOut) - 1 + Request->DataTransferLength))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_BUFFER_TOO_SMALL;
}
}
TaskFile->Feature = Buffer.CmdIn->irDriveRegs.bFeaturesReg;
TaskFile->SectorCount = Buffer.CmdIn->irDriveRegs.bSectorCountReg;
TaskFile->LowLba = Buffer.CmdIn->irDriveRegs.bSectorNumberReg;
TaskFile->MidLba = Buffer.CmdIn->irDriveRegs.bCylLowReg;
TaskFile->HighLba = Buffer.CmdIn->irDriveRegs.bCylHighReg;
TaskFile->Command = Buffer.CmdIn->irDriveRegs.bCommandReg;
TaskFile->DriveSelect = Buffer.CmdIn->irDriveRegs.bDriveHeadReg;
return SRB_STATUS_PENDING;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleMiniportIdentify(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
union _PARAMS
{
PSENDCMDINPARAMS CmdIn;
PSENDCMDOUTPARAMS CmdOut;
} Buffer;
PAGED_CODE();
if (Srb->DataTransferLength <
(sizeof(SRB_IO_CONTROL) + sizeof(*Buffer.CmdOut) - 1 + IDENTIFY_BUFFER_SIZE))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_BUFFER_TOO_SMALL;
}
Buffer.CmdIn = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
if (Buffer.CmdIn->irDriveRegs.bCommandReg != ID_CMD)
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_INVALID_DEVICE_REQUEST;
}
Buffer.CmdOut->cBufferSize = IDENTIFY_BUFFER_SIZE;
Buffer.CmdOut->DriverStatus.bDriverError = 0;
Buffer.CmdOut->DriverStatus.bIDEError = 0;
RtlCopyMemory(Buffer.CmdOut->bBuffer,
&DeviceExtension->IdentifyDeviceData,
IDENTIFY_BUFFER_SIZE);
Srb->SrbStatus = SRB_STATUS_SUCCESS;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPdoHandleMiniportSmartVersion(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PSCSI_REQUEST_BLOCK Srb)
{
PGETVERSIONINPARAMS VersionParameters;
PATAPORT_DEVICE_EXTENSION DeviceExtension;
ULONG MaxDevices, DeviceNumber;
UCHAR DeviceBitmap;
PAGED_CODE();
if (Srb->DataTransferLength < (sizeof(*VersionParameters) + sizeof(SRB_IO_CONTROL)))
{
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
return STATUS_BUFFER_TOO_SMALL;
}
VersionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
/* SMART 1.03 */
VersionParameters->bVersion = 1;
VersionParameters->bRevision = 1;
VersionParameters->bReserved = 0;
VersionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
DeviceBitmap = 0;
MaxDevices = AtaFdoMaxDeviceCount(ChannelExtension);
for (DeviceNumber = 0; DeviceNumber < MaxDevices; ++DeviceNumber)
{
ATA_SCSI_ADDRESS AtaScsiAddress;
AtaScsiAddress = AtaMarshallScsiAddress(ChannelExtension->PathId, DeviceNumber, 0);
DeviceExtension = AtaFdoFindDeviceByPath(ChannelExtension, AtaScsiAddress);
if (DeviceExtension)
{
if (IS_ATAPI(DeviceExtension))
DeviceBitmap |= (1 << DeviceNumber) << 4;
else
DeviceBitmap |= (1 << DeviceNumber);
}
}
/* Secondary channel bits */
if ((ChannelExtension->PathId == 1) && (!(ChannelExtension->Flags & CHANNEL_CBUS_IDE)))
DeviceBitmap <<= 2;
VersionParameters->bIDEDeviceMap = DeviceBitmap;
Srb->SrbStatus = SRB_STATUS_SUCCESS;
return STATUS_SUCCESS;
}

View File

@ -0,0 +1,317 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: PATA timings support
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
#define ADVPIO_MODE_MASK ((1 << 2) - 1) /* 2 modes */
#define SWMA_MODE_MASK ((1 << 3) - 1) /* 3 modes */
#define MWMA_MODE_MASK ((1 << 3) - 1) /* 3 modes */
#define UDMA_MODE_MASK ((1 << 7) - 1) /* 7 modes */
#define PIO0_SHIFT 0
#define PIO3_SHIFT 3
#define PIO4_SHIFT 4
#define SWDMA0_SHIFT 5
#define MWDMA0_SHIFT 8
#define UDMA0_SHIFT 11
static const ULONG AtapTimingTable[] =
{
/* PIO 0-4 */
600, 383, 240, 180, 120,
/* SWDMA 0-2 */
960, 480, 240,
/* MWDMA 0-2 */
480, 150, 120,
/* UDMA 0-6 */
120, 80, 60, 45, 30, 20, 15
};
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
VOID
AtaTimInitPioMode(
_In_ ULONG Device,
_Inout_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
PIDENTIFY_DEVICE_DATA IdentifyData = (PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[Device];
ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
PAGED_CODE();
CycleTime = (ULONG)-1;
/* Find the best possible PIO mode */
if (IdentifyData->TranslationFieldsValid & 0x2)
{
/* PIO 3-4 */
SupportedMode = IdentifyData->AdvancedPIOModes & ADVPIO_MODE_MASK;
SupportedMode <<= PIO3_SHIFT;
/* The device is assumed to have PIO 0-2 */
SupportedMode |= (PIO_MODE0 | PIO_MODE1 | PIO_MODE2);
if (IdentifyData->Capabilities.IordySupported)
CycleTime = IdentifyData->MinimumPIOCycleTimeIORDY;
else
CycleTime = IdentifyData->MinimumPIOCycleTime;
}
else
{
/* PIO 0-4 */
SupportedMode = IdentifyData->ObsoleteWords51[0] >> 8;
if (SupportedMode > PIO4_SHIFT)
{
SupportedMode = PIO0_SHIFT;
}
BestMode = SupportedMode;
SupportedMode = (1 << (SupportedMode + 1)) - 1;
if (BestMode < XferMode->TransferModeTableLength)
{
CycleTime = XferMode->TransferModeTimingTable[BestMode];
}
}
XferMode->DeviceTransferModeSupported[Device] |= SupportedMode;
XferMode->BestPioCycleTime[Device] = CycleTime;
/* FIXME: How to get the current PIO mode? */
_BitScanReverse(&BestMode, SupportedMode);
CurrentMode = BestMode;
XferMode->DeviceTransferModeCurrent[Device] |= 1 << CurrentMode;
}
static
CODE_SEG("PAGE")
VOID
AtaTimInitSingleWordDmaMode(
_In_ ULONG Device,
_Inout_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
PIDENTIFY_DEVICE_DATA IdentifyData = (PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[Device];
ULONG BestMode, CurrentMode, CycleTime;
PAGED_CODE();
CycleTime = (ULONG)-1;
/* Find the current active SWDMA mode */
CurrentMode = ((IdentifyData->ObsoleteWord62 & 0xFF00) >> 16) & SWMA_MODE_MASK;
if (CurrentMode != 0)
{
_BitScanReverse(&CurrentMode, CurrentMode);
CurrentMode += SWDMA0_SHIFT;
XferMode->DeviceTransferModeCurrent[Device] |= 1 << CurrentMode;
}
/* Find the best possible SWDMA mode */
BestMode = (IdentifyData->ObsoleteWord62 & 0x00FF) & SWMA_MODE_MASK;
if (BestMode != 0)
{
BestMode <<= SWDMA0_SHIFT;
XferMode->DeviceTransferModeSupported[Device] |= BestMode;
_BitScanReverse(&BestMode, BestMode);
if (BestMode < XferMode->TransferModeTableLength)
{
CycleTime = XferMode->TransferModeTimingTable[BestMode];
}
}
XferMode->BestSwDmaCycleTime[Device] = CycleTime;
}
static
CODE_SEG("PAGE")
VOID
AtaTimInitMultiWordDmaMode(
_In_ ULONG Device,
_Inout_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
PIDENTIFY_DEVICE_DATA IdentifyData = (PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[Device];
ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
PAGED_CODE();
CycleTime = (ULONG)-1;
/* Find the current active MWDMA mode */
CurrentMode = IdentifyData->MultiWordDMAActive & MWMA_MODE_MASK;
if (CurrentMode != 0)
{
_BitScanReverse(&CurrentMode, CurrentMode);
CurrentMode += MWDMA0_SHIFT;
XferMode->DeviceTransferModeCurrent[Device] |= 1 << CurrentMode;
}
/* Find the best possible MWDMA mode */
SupportedMode = IdentifyData->MultiWordDMASupport & MWMA_MODE_MASK;
if (SupportedMode != 0)
{
SupportedMode <<= MWDMA0_SHIFT;
XferMode->DeviceTransferModeSupported[Device] |= SupportedMode;
_BitScanReverse(&BestMode, SupportedMode);
/* Prefer the minimum cycle time, if words 64-70 are valid */
if ((IdentifyData->TranslationFieldsValid & 0x2) &&
(IdentifyData->MinimumMWXferCycleTime != 0) &&
(IdentifyData->RecommendedMWXferCycleTime != 0))
{
CycleTime = IdentifyData->MinimumMWXferCycleTime;
}
else if (BestMode < XferMode->TransferModeTableLength)
{
CycleTime = XferMode->TransferModeTimingTable[BestMode];
}
}
XferMode->BestMwDmaCycleTime[Device] = CycleTime;
}
static
CODE_SEG("PAGE")
VOID
AtaTimInitUltraDmaMode(
_In_ ULONG Device,
_Inout_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
PIDENTIFY_DEVICE_DATA IdentifyData = (PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[Device];
ULONG SupportedMode, BestMode, CurrentMode, CycleTime;
PAGED_CODE();
CycleTime = (ULONG)-1;
/* Word 88 is not valid */
if (!(IdentifyData->TranslationFieldsValid & 0x4))
goto Exit;
/* Find the current active UDMA mode */
CurrentMode = IdentifyData->UltraDMAActive & UDMA_MODE_MASK;
if (CurrentMode != 0)
{
_BitScanReverse(&CurrentMode, CurrentMode);
CurrentMode += UDMA0_SHIFT;
XferMode->DeviceTransferModeCurrent[Device] |= 1 << CurrentMode;
}
/* Find the best possible UDMA mode */
SupportedMode = IdentifyData->UltraDMASupport & UDMA_MODE_MASK;
if (SupportedMode != 0)
{
SupportedMode <<= UDMA0_SHIFT;
XferMode->DeviceTransferModeSupported[Device] |= SupportedMode;
_BitScanReverse(&BestMode, SupportedMode);
if (BestMode < XferMode->TransferModeTableLength)
{
CycleTime = XferMode->TransferModeTimingTable[BestMode];
}
}
Exit:
XferMode->BestUDmaCycleTime[Device] = CycleTime;
}
static
CODE_SEG("PAGE")
VOID
AtaAcpiSelectTimings(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension,
_In_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
IDE_ACPI_TIMING_MODE_BLOCK TimingMode;
ULONG i, CurrentModeFlags;
PAGED_CODE();
CurrentModeFlags = ChannelExtension->TimingMode.ModeFlags;
CurrentModeFlags &= (IDE_ACPI_TIMING_MODE_FLAG_INDEPENDENT_TIMINGS |
IDE_ACPI_TIMING_MODE_FLAG_IORDY |
IDE_ACPI_TIMING_MODE_FLAG_IORDY2);
TimingMode.ModeFlags = CurrentModeFlags;
/* NOTE: Some ACPI BIOS implementations (e.g. VPC 2007) don't return correct timings */
for (i = 0; i < MAX_IDE_DEVICE; ++i)
{
TimingMode.Drive[i].PioSpeed = ChannelExtension->TimingMode.Drive[i].PioSpeed;
TimingMode.Drive[i].DmaSpeed = ChannelExtension->TimingMode.Drive[i].DmaSpeed;
}
AtaAcpiSetTimingMode(ChannelExtension,
&TimingMode,
(PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[0],
(PIDENTIFY_DEVICE_DATA)&XferMode->IdentifyData[1]);
}
CODE_SEG("PAGE")
VOID
AtaSelectTimings(
_In_ PATAPORT_CHANNEL_EXTENSION ChannelExtension)
{
PCIIDE_TRANSFER_MODE_SELECT XferMode;
ULONG i;
PAGED_CODE();
RtlZeroMemory(&XferMode, sizeof(XferMode));
if (!(ChannelExtension->Flags & CHANNEL_HAS_CHIPSET_INTERFACE))
{
XferMode.TransferModeTimingTable = (PULONG)AtapTimingTable;
XferMode.TransferModeTableLength = RTL_NUMBER_OF(AtapTimingTable);
}
for (i = 0; i < MAX_IDE_DEVICE; ++i)
{
PATAPORT_DEVICE_EXTENSION DeviceExtension = ChannelExtension->Device[i];
PIDENTIFY_DEVICE_DATA IdentifyData = &DeviceExtension->IdentifyDeviceData;
if (!DeviceExtension)
continue;
RtlCopyMemory(&XferMode.IdentifyData[i], IdentifyData, sizeof(*IdentifyData));
XferMode.DevicePresent[i] = TRUE;
XferMode.FixedDisk[i] = IS_ATAPI(DeviceExtension);
XferMode.IoReadySupported[i] = !!IdentifyData->Capabilities.IordySupported;
XferMode.UserChoiceTransferMode[i] = 0x7FFFFFFF;
AtaTimInitPioMode(i, &XferMode);
AtaTimInitSingleWordDmaMode(i, &XferMode);
AtaTimInitMultiWordDmaMode(i, &XferMode);
AtaTimInitUltraDmaMode(i, &XferMode);
INFO("PIO cycle time %ld\n", (LONG)XferMode.BestPioCycleTime[i]);
INFO("SWDMA cycle time %ld\n", (LONG)XferMode.BestSwDmaCycleTime[i]);
INFO("MWDMA cycle time %ld\n", (LONG)XferMode.BestMwDmaCycleTime[i]);
INFO("UDMA cycle time %ld\n", (LONG)XferMode.BestUDmaCycleTime[i]);
INFO("DeviceTransferModeCurrent 0x%08lx\n", XferMode.DeviceTransferModeCurrent[i]);
INFO("DeviceTransferModeSupported 0x%08lx\n", XferMode.DeviceTransferModeSupported[i]);
INFO("UserChoiceTransferMode 0x%08lx\n", XferMode.UserChoiceTransferMode[i]);
INFO("IOREADY support %u\n", XferMode.IoReadySupported[i]);
}
if (ChannelExtension->Flags & CHANNEL_HAS_GTM)
{
/* Set the transfer timings through ACPI */
AtaAcpiSelectTimings(ChannelExtension, &XferMode);
}
}

View File

@ -0,0 +1,205 @@
/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: WMI support
* COPYRIGHT: Copyright 2024 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
static WMIGUIDREGINFO AtapWmiGuidList[] =
{
{&MSIde_PortDeviceInfo_GUID, 1, 0}
};
/* FUNCTIONS ******************************************************************/
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaQueryWmiRegInfo(
PDEVICE_OBJECT DeviceObject,
PULONG RegFlags,
PUNICODE_STRING InstanceName,
PUNICODE_STRING *RegistryPath,
PUNICODE_STRING MofResourceName,
PDEVICE_OBJECT *Pdo)
{
PATAPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
UNREFERENCED_PARAMETER(InstanceName);
UNREFERENCED_PARAMETER(MofResourceName);
PAGED_CODE();
*RegFlags = WMIREG_FLAG_INSTANCE_PDO;
*RegistryPath = &AtapDriverRegistryPath;
*Pdo = DeviceExtension->Common.Self;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaQueryWmiDataBlock(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
ULONG GuidIndex,
ULONG InstanceIndex,
ULONG InstanceCount,
PULONG InstanceLengthArray,
ULONG BufferAvail,
PUCHAR Buffer)
{
PATAPORT_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
ATA_SCSI_ADDRESS AtaScsiAddress;
PMSIde_PortDeviceInfo DeviceInfo;
PAGED_CODE();
if (GuidIndex > RTL_NUMBER_OF(AtapWmiGuidList))
{
Status = STATUS_WMI_GUID_NOT_FOUND;
goto Complete;
}
/* Only ever register 1 instance per GUID */
if (InstanceIndex != 0 || InstanceCount != 1)
{
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
goto Complete;
}
if (!InstanceLengthArray || BufferAvail < sizeof(*DeviceInfo))
{
Status = STATUS_BUFFER_TOO_SMALL;
goto Complete;
}
DeviceExtension = DeviceObject->DeviceExtension;
AtaScsiAddress = DeviceExtension->AtaScsiAddress;
DeviceInfo = (PMSIde_PortDeviceInfo)Buffer;
DeviceInfo->Bus = AtaScsiAddress.PathId;
DeviceInfo->Target = AtaScsiAddress.TargetId;
DeviceInfo->Lun = AtaScsiAddress.Lun;
*InstanceLengthArray = sizeof(*DeviceInfo);
Status = STATUS_SUCCESS;
Complete:
return WmiCompleteRequest(DeviceObject,
Irp,
Status,
sizeof(*DeviceInfo),
IO_NO_INCREMENT);
}
CODE_SEG("PAGE")
NTSTATUS
AtaPdoWmiRegistration(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_In_ BOOLEAN Register)
{
PAGED_CODE();
if (!Register)
{
return IoWMIRegistrationControl(DeviceExtension->Common.Self,
WMIREG_ACTION_DEREGISTER);
}
DeviceExtension->WmiLibInfo.GuidCount = RTL_NUMBER_OF(AtapWmiGuidList);
DeviceExtension->WmiLibInfo.GuidList = AtapWmiGuidList;
DeviceExtension->WmiLibInfo.QueryWmiRegInfo = AtaQueryWmiRegInfo;
DeviceExtension->WmiLibInfo.QueryWmiDataBlock = AtaQueryWmiDataBlock;
return IoWMIRegistrationControl(DeviceExtension->Common.Self,
WMIREG_ACTION_REGISTER);
}
static
CODE_SEG("PAGE")
NTSTATUS
AtaPdoWmi(
_In_ PATAPORT_DEVICE_EXTENSION DeviceExtension,
_Inout_ PIRP Irp)
{
NTSTATUS Status;
SYSCTL_IRP_DISPOSITION Disposition;
PAGED_CODE();
TRACE("%s(%p, %p)\n", __FUNCTION__, DeviceExtension, Irp);
Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(Status))
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
Status = WmiSystemControl(&DeviceExtension->WmiLibInfo,
DeviceExtension->Common.Self,
Irp,
&Disposition);
switch (Disposition)
{
case IrpProcessed:
break;
case IrpNotCompleted:
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IrpForward:
case IrpNotWmi:
Status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
default:
ASSERT(FALSE);
UNREACHABLE;
break;
}
IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaDispatchWmi(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PAGED_CODE();
if (IS_FDO(DeviceObject->DeviceExtension))
{
PATAPORT_CHANNEL_EXTENSION ChannelExtension = DeviceObject->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(ChannelExtension->Ldo, Irp);
}
else
{
return AtaPdoWmi(DeviceObject->DeviceExtension, Irp);
}
}

View File

@ -0,0 +1,6 @@
add_library(atapi MODULE atapi.c atapi.rc)
target_link_libraries(atapi libcntpr)
set_module_type(atapi kernelmodedriver)
add_importlibs(atapi scsiport)
add_cd_file(TARGET atapi DESTINATION reactos/system32/drivers NO_CAB FOR all)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,461 @@
/*
* PROJECT: ReactOS Storage Stack
* LICENSE: DDK - see license.txt in the root dir
* FILE: drivers/storage/atapi/atapi.h
* PURPOSE: ATAPI IDE miniport driver
* PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
*/
#include <srb.h>
#include <scsi.h>
//
// IDE register definition
//
typedef struct _IDE_REGISTERS_1 {
USHORT Data;
UCHAR BlockCount;
UCHAR BlockNumber;
UCHAR CylinderLow;
UCHAR CylinderHigh;
UCHAR DriveSelect;
UCHAR Command;
} IDE_REGISTERS_1, *PIDE_REGISTERS_1;
typedef struct _IDE_REGISTERS_2 {
UCHAR AlternateStatus;
UCHAR DriveAddress;
} IDE_REGISTERS_2, *PIDE_REGISTERS_2;
typedef struct _IDE_REGISTERS_3 {
ULONG Data;
UCHAR Others[4];
} IDE_REGISTERS_3, *PIDE_REGISTERS_3;
//
// Device Extension Device Flags
//
#define DFLAGS_DEVICE_PRESENT 0x0001 // Indicates that some device is present.
#define DFLAGS_ATAPI_DEVICE 0x0002 // Indicates whether Atapi commands can be used.
#define DFLAGS_TAPE_DEVICE 0x0004 // Indicates whether this is a tape device.
#define DFLAGS_INT_DRQ 0x0008 // Indicates whether device interrupts as DRQ is set after
// receiving Atapi Packet Command
#define DFLAGS_REMOVABLE_DRIVE 0x0010 // Indicates that the drive has the 'removable' bit set in
// identify data (offset 128)
#define DFLAGS_MEDIA_STATUS_ENABLED 0x0020 // Media status notification enabled
#define DFLAGS_ATAPI_CHANGER 0x0040 // Indicates atapi 2.5 changer present.
#define DFLAGS_SANYO_ATAPI_CHANGER 0x0080 // Indicates multi-platter device, not conforming to the 2.5 spec.
#define DFLAGS_CHANGER_INITED 0x0100 // Indicates that the init path for changers has already been done.
//
// Used to disable 'advanced' features.
//
#define MAX_ERRORS 4
//
// ATAPI command definitions
//
#define ATAPI_MODE_SENSE 0x5A
#define ATAPI_MODE_SELECT 0x55
#define ATAPI_FORMAT_UNIT 0x24
//
// ATAPI Command Descriptor Block
//
typedef struct _MODE_SENSE_10 {
UCHAR OperationCode;
UCHAR Reserved1;
UCHAR PageCode : 6;
UCHAR Pc : 2;
UCHAR Reserved2[4];
UCHAR ParameterListLengthMsb;
UCHAR ParameterListLengthLsb;
UCHAR Reserved3[3];
} MODE_SENSE_10, *PMODE_SENSE_10;
typedef struct _MODE_SELECT_10 {
UCHAR OperationCode;
UCHAR Reserved1 : 4;
UCHAR PFBit : 1;
UCHAR Reserved2 : 3;
UCHAR Reserved3[5];
UCHAR ParameterListLengthMsb;
UCHAR ParameterListLengthLsb;
UCHAR Reserved4[3];
} MODE_SELECT_10, *PMODE_SELECT_10;
typedef struct _MODE_PARAMETER_HEADER_10 {
UCHAR ModeDataLengthMsb;
UCHAR ModeDataLengthLsb;
UCHAR MediumType;
UCHAR Reserved[5];
}MODE_PARAMETER_HEADER_10, *PMODE_PARAMETER_HEADER_10;
//
// IDE command definitions
//
#define IDE_COMMAND_ATAPI_RESET 0x08
#define IDE_COMMAND_RECALIBRATE 0x10
#define IDE_COMMAND_READ 0x20
#define IDE_COMMAND_WRITE 0x30
#define IDE_COMMAND_VERIFY 0x40
#define IDE_COMMAND_SEEK 0x70
#define IDE_COMMAND_SET_DRIVE_PARAMETERS 0x91
#define IDE_COMMAND_ATAPI_PACKET 0xA0
#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1
#define IDE_COMMAND_READ_MULTIPLE 0xC4
#define IDE_COMMAND_WRITE_MULTIPLE 0xC5
#define IDE_COMMAND_SET_MULTIPLE 0xC6
#define IDE_COMMAND_READ_DMA 0xC8
#define IDE_COMMAND_WRITE_DMA 0xCA
#define IDE_COMMAND_GET_MEDIA_STATUS 0xDA
#define IDE_COMMAND_ENABLE_MEDIA_STATUS 0xEF
#define IDE_COMMAND_IDENTIFY 0xEC
#define IDE_COMMAND_MEDIA_EJECT 0xED
//
// IDE status definitions
//
#define IDE_STATUS_ERROR 0x01
#define IDE_STATUS_INDEX 0x02
#define IDE_STATUS_CORRECTED_ERROR 0x04
#define IDE_STATUS_DRQ 0x08
#define IDE_STATUS_DSC 0x10
#define IDE_STATUS_DRDY 0x40
#define IDE_STATUS_IDLE 0x50
#define IDE_STATUS_BUSY 0x80
//
// IDE drive select/head definitions
//
#define IDE_DRIVE_SELECT_1 0xA0
#define IDE_DRIVE_SELECT_2 0x10
//
// IDE drive control definitions
//
#define IDE_DC_DISABLE_INTERRUPTS 0x02
#define IDE_DC_RESET_CONTROLLER 0x04
#define IDE_DC_REENABLE_CONTROLLER 0x00
//
// IDE error definitions
//
#define IDE_ERROR_BAD_BLOCK 0x80
#define IDE_ERROR_DATA_ERROR 0x40
#define IDE_ERROR_MEDIA_CHANGE 0x20
#define IDE_ERROR_ID_NOT_FOUND 0x10
#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08
#define IDE_ERROR_COMMAND_ABORTED 0x04
#define IDE_ERROR_END_OF_MEDIA 0x02
#define IDE_ERROR_ILLEGAL_LENGTH 0x01
//
// ATAPI register definition
//
typedef struct _ATAPI_REGISTERS_1 {
USHORT Data;
UCHAR InterruptReason;
UCHAR Unused1;
UCHAR ByteCountLow;
UCHAR ByteCountHigh;
UCHAR DriveSelect;
UCHAR Command;
} ATAPI_REGISTERS_1, *PATAPI_REGISTERS_1;
typedef struct _ATAPI_REGISTERS_2 {
UCHAR AlternateStatus;
UCHAR DriveAddress;
} ATAPI_REGISTERS_2, *PATAPI_REGISTERS_2;
//
// ATAPI interrupt reasons
//
#define ATAPI_IR_COD 0x01
#define ATAPI_IR_IO 0x02
//
// IDENTIFY data
//
typedef struct _IDENTIFY_DATA {
USHORT GeneralConfiguration; // 00 00
USHORT NumberOfCylinders; // 02 1
USHORT Reserved1; // 04 2
USHORT NumberOfHeads; // 06 3
USHORT UnformattedBytesPerTrack; // 08 4
USHORT UnformattedBytesPerSector; // 0A 5
USHORT SectorsPerTrack; // 0C 6
USHORT VendorUnique1[3]; // 0E 7-9
USHORT SerialNumber[10]; // 14 10-19
USHORT BufferType; // 28 20
USHORT BufferSectorSize; // 2A 21
USHORT NumberOfEccBytes; // 2C 22
USHORT FirmwareRevision[4]; // 2E 23-26
USHORT ModelNumber[20]; // 36 27-46
UCHAR MaximumBlockTransfer; // 5E 47
UCHAR VendorUnique2; // 5F
USHORT DoubleWordIo; // 60 48
USHORT Capabilities; // 62 49
USHORT Reserved2; // 64 50
UCHAR VendorUnique3; // 66 51
UCHAR PioCycleTimingMode; // 67
UCHAR VendorUnique4; // 68 52
UCHAR DmaCycleTimingMode; // 69
USHORT TranslationFieldsValid:1; // 6A 53
USHORT Reserved3:15;
USHORT NumberOfCurrentCylinders; // 6C 54
USHORT NumberOfCurrentHeads; // 6E 55
USHORT CurrentSectorsPerTrack; // 70 56
ULONG CurrentSectorCapacity; // 72 57-58
USHORT CurrentMultiSectorSetting; // 59
ULONG UserAddressableSectors; // 60-61
USHORT SingleWordDMASupport : 8; // 62
USHORT SingleWordDMAActive : 8;
USHORT MultiWordDMASupport : 8; // 63
USHORT MultiWordDMAActive : 8;
USHORT AdvancedPIOModes : 8; // 64
USHORT Reserved4 : 8;
USHORT MinimumMWXferCycleTime; // 65
USHORT RecommendedMWXferCycleTime; // 66
USHORT MinimumPIOCycleTime; // 67
USHORT MinimumPIOCycleTimeIORDY; // 68
USHORT Reserved5[2]; // 69-70
USHORT ReleaseTimeOverlapped; // 71
USHORT ReleaseTimeServiceCommand; // 72
USHORT MajorRevision; // 73
USHORT MinorRevision; // 74
USHORT Reserved6[50]; // 75-126
USHORT SpecialFunctionsEnabled; // 127
USHORT Reserved7[128]; // 128-255
} IDENTIFY_DATA, *PIDENTIFY_DATA;
//
// Identify data without the Reserved4.
//
typedef struct _IDENTIFY_DATA2 {
USHORT GeneralConfiguration; // 00
USHORT NumberOfCylinders; // 02
USHORT Reserved1; // 04
USHORT NumberOfHeads; // 06
USHORT UnformattedBytesPerTrack; // 08
USHORT UnformattedBytesPerSector; // 0A
USHORT SectorsPerTrack; // 0C
USHORT VendorUnique1[3]; // 0E
USHORT SerialNumber[10]; // 14
USHORT BufferType; // 28
USHORT BufferSectorSize; // 2A
USHORT NumberOfEccBytes; // 2C
USHORT FirmwareRevision[4]; // 2E
USHORT ModelNumber[20]; // 36
UCHAR MaximumBlockTransfer; // 5E
UCHAR VendorUnique2; // 5F
USHORT DoubleWordIo; // 60
USHORT Capabilities; // 62
USHORT Reserved2; // 64
UCHAR VendorUnique3; // 66
UCHAR PioCycleTimingMode; // 67
UCHAR VendorUnique4; // 68
UCHAR DmaCycleTimingMode; // 69
USHORT TranslationFieldsValid:1; // 6A
USHORT Reserved3:15;
USHORT NumberOfCurrentCylinders; // 6C
USHORT NumberOfCurrentHeads; // 6E
USHORT CurrentSectorsPerTrack; // 70
ULONG CurrentSectorCapacity; // 72
} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
//
// IDENTIFY capability bit definitions.
//
#define IDENTIFY_CAPABILITIES_DMA_SUPPORTED 0x0100
#define IDENTIFY_CAPABILITIES_LBA_SUPPORTED 0x0200
//
// IDENTIFY DMA timing cycle modes.
//
#define IDENTIFY_DMA_CYCLES_MODE_0 0x00
#define IDENTIFY_DMA_CYCLES_MODE_1 0x01
#define IDENTIFY_DMA_CYCLES_MODE_2 0x02
typedef struct _BROKEN_CONTROLLER_INFORMATION {
PCHAR VendorId;
ULONG VendorIdLength;
PCHAR DeviceId;
ULONG DeviceIdLength;
}BROKEN_CONTROLLER_INFORMATION, *PBROKEN_CONTROLLER_INFORMATION;
BROKEN_CONTROLLER_INFORMATION const BrokenAdapters[] = {
{ "1095", 4, "0640", 4},
{ "1039", 4, "0601", 4}
};
#define BROKEN_ADAPTERS (sizeof(BrokenAdapters) / sizeof(BROKEN_CONTROLLER_INFORMATION))
typedef struct _NATIVE_MODE_CONTROLLER_INFORMATION {
PCHAR VendorId;
ULONG VendorIdLength;
PCHAR DeviceId;
ULONG DeviceIdLength;
}NATIVE_MODE_CONTROLLER_INFORMATION, *PNATIVE_MODE_CONTROLLER_INFORMATION;
NATIVE_MODE_CONTROLLER_INFORMATION const NativeModeAdapters[] = {
{ "10ad", 4, "0105", 4}
};
#define NUM_NATIVE_MODE_ADAPTERS (sizeof(NativeModeAdapters) / sizeof(NATIVE_MODE_CONTROLLER_INFORMATION))
//
// Beautification macros
//
#define GetStatus(BaseIoAddress, Status) \
Status = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus);
#define GetBaseStatus(BaseIoAddress, Status) \
Status = ScsiPortReadPortUchar(&BaseIoAddress->Command);
#define WriteCommand(BaseIoAddress, Command) \
ScsiPortWritePortUchar(&BaseIoAddress->Command, Command);
#define ReadBuffer(BaseIoAddress, Buffer, Count) \
ScsiPortReadPortBufferUshort(&BaseIoAddress->Data, \
Buffer, \
Count);
#define WriteBuffer(BaseIoAddress, Buffer, Count) \
ScsiPortWritePortBufferUshort(&BaseIoAddress->Data, \
Buffer, \
Count);
#define ReadBuffer2(BaseIoAddress, Buffer, Count) \
ScsiPortReadPortBufferUlong(&BaseIoAddress->Data, \
Buffer, \
Count);
#define WriteBuffer2(BaseIoAddress, Buffer, Count) \
ScsiPortWritePortBufferUlong(&BaseIoAddress->Data, \
Buffer, \
Count);
#define WaitOnBusy(BaseIoAddress, Status) \
{ \
ULONG i; \
for (i=0; i<20000; i++) { \
GetStatus(BaseIoAddress, Status); \
if (Status & IDE_STATUS_BUSY) { \
ScsiPortStallExecution(150); \
continue; \
} else { \
break; \
} \
} \
}
#define WaitOnBaseBusy(BaseIoAddress, Status) \
{ \
ULONG i; \
for (i=0; i<20000; i++) { \
GetBaseStatus(BaseIoAddress, Status); \
if (Status & IDE_STATUS_BUSY) { \
ScsiPortStallExecution(150); \
continue; \
} else { \
break; \
} \
} \
}
#define WaitForDrq(BaseIoAddress, Status) \
{ \
ULONG i; \
for (i=0; i<1000; i++) { \
GetStatus(BaseIoAddress, Status); \
if (Status & IDE_STATUS_BUSY) { \
ScsiPortStallExecution(100); \
} else if (Status & IDE_STATUS_DRQ) { \
break; \
} else { \
ScsiPortStallExecution(200); \
} \
} \
}
#define WaitShortForDrq(BaseIoAddress, Status) \
{ \
ULONG i; \
for (i=0; i<2; i++) { \
GetStatus(BaseIoAddress, Status); \
if (Status & IDE_STATUS_BUSY) { \
ScsiPortStallExecution(100); \
} else if (Status & IDE_STATUS_DRQ) { \
break; \
} else { \
ScsiPortStallExecution(100); \
} \
} \
}
#define AtapiSoftReset(BaseIoAddress,DeviceNumber) \
{\
UCHAR statusByte; \
ULONG i = 1000*1000;\
ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)(((DeviceNumber & 0x1) << 4) | 0xA0)); \
ScsiPortStallExecution(500);\
ScsiPortWritePortUchar(&BaseIoAddress->Command, IDE_COMMAND_ATAPI_RESET); \
while ((ScsiPortReadPortUchar(&BaseIoAddress->Command) & IDE_STATUS_BUSY) && i--)\
ScsiPortStallExecution(30);\
ScsiPortWritePortUchar(&BaseIoAddress->DriveSelect,(UCHAR)((DeviceNumber << 4) | 0xA0)); \
WaitOnBusy( ((PIDE_REGISTERS_2)((PUCHAR)BaseIoAddress + 0x206)), statusByte); \
ScsiPortStallExecution(500);\
}
#define IdeHardReset(BaseIoAddress,result) \
{\
UCHAR statusByte;\
ULONG i;\
ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_RESET_CONTROLLER );\
ScsiPortStallExecution(50 * 1000);\
ScsiPortWritePortUchar(&BaseIoAddress->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);\
for (i = 0; i < 1000 * 1000; i++) {\
statusByte = ScsiPortReadPortUchar(&BaseIoAddress->AlternateStatus);\
if (statusByte != IDE_STATUS_IDLE && statusByte != 0x0) {\
ScsiPortStallExecution(5);\
} else {\
break;\
}\
}\
if (i == 1000*1000) {\
result = FALSE;\
}\
result = TRUE;\
}
#define IS_RDP(OperationCode)\
((OperationCode == SCSIOP_ERASE)||\
(OperationCode == SCSIOP_LOAD_UNLOAD)||\
(OperationCode == SCSIOP_LOCATE)||\
(OperationCode == SCSIOP_REWIND) ||\
(OperationCode == SCSIOP_SPACE)||\
(OperationCode == SCSIOP_SEEK)||\
(OperationCode == SCSIOP_WRITE_FILEMARKS))

View File

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "ATAPI IDE Miniport Driver"
#define REACTOS_STR_INTERNAL_NAME "atapi"
#define REACTOS_STR_ORIGINAL_FILENAME "atapi.sys"
#include <reactos/version.rc>

View File

@ -0,0 +1,14 @@
add_library(pciahci MODULE pciahci.c pciahci.rc)
set_module_type(pciahci kernelmodedriver)
if(MSVC)
target_link_options(pciahci PRIVATE /SECTION:.rsrc,!D)
else()
add_custom_command(
TARGET pciahci POST_BUILD
COMMAND native-pefixup --section:.rsrc,!D $<TARGET_FILE:pciahci>
VERBATIM)
endif()
add_importlibs(pciahci pciidex ntoskrnl)
add_cd_file(TARGET pciahci DESTINATION reactos/system32/drivers NO_CAB FOR all)
add_registry_inf(pciahci_reg.inf)

View File

@ -0,0 +1,121 @@
/*
* PROJECT: ReactOS AHCI Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Common file
* COPYRIGHT: Copyright 2024 Dmitry Borisov (di.sean@protonmail.com)
*/
/* INCLUDES *******************************************************************/
#include "pciahci.h"
/* GLOBALS ********************************************************************/
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
IDE_CHANNEL_STATE
NTAPI
PciAhciPortEnabled(
_In_ PVOID DeviceExtension,
_In_ ULONG Channel)
{
PAHCI_DEVICE_EXTENSION AhciExtension = DeviceExtension;
if (AhciExtension->Hba->PortsImplemented & (1 << Channel))
{
DPRINT1("AHCI Port %lu is enabled\n", Channel);
return ChannelEnabled;
}
return ChannelDisabled;
}
BOOLEAN
NTAPI
PciAhciSyncAccessRequired(
_In_ PVOID DeviceExtension)
{
return FALSE;
}
NTSTATUS
NTAPI
PciAhciTransferModeSelect(
_In_ PVOID DeviceExtension,
_In_ PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
return STATUS_SUCCESS;
}
ULONG
NTAPI
PciAhciUseDma(
_In_ PVOID DeviceExtension,
_In_ PUCHAR CdbCommand,
_In_ PUCHAR Slave)
{
/* Nothing should prevent us to use DMA */
return 1;
}
NTSTATUS
NTAPI
PciAhciGetControllerProperties(
_In_ PVOID DeviceExtension,
_Out_ PIDE_CONTROLLER_PROPERTIES ControllerProperties)
{
PAHCI_DEVICE_EXTENSION AhciExtension = DeviceExtension;
ULONG i;
if (ControllerProperties->Size != sizeof(*ControllerProperties))
return STATUS_REVISION_MISMATCH;
ControllerProperties->PciIdeChannelEnabled = PciAhciPortEnabled;
ControllerProperties->PciIdeSyncAccessRequired = PciAhciSyncAccessRequired;
ControllerProperties->PciIdeTransferModeSelect = PciAhciTransferModeSelect;
ControllerProperties->IgnoreActiveBitForAtaDevice = FALSE;
ControllerProperties->AlwaysClearBusMasterInterrupt = TRUE;
ControllerProperties->PciIdeUseDma = PciAhciUseDma;
ControllerProperties->AlignmentRequirement = 1;
ControllerProperties->DefaultPIO = 0;
ControllerProperties->SupportedTransferMode[0][0] =
ControllerProperties->SupportedTransferMode[0][1] =
ControllerProperties->SupportedTransferMode[1][0] =
ControllerProperties->SupportedTransferMode[1][1] = 0x7FFFFFFF;
AhciExtension->Hba->GlobalControl |= AHCI_GHC_AE;
for (i = 0; i < MAX_AHCI_DEVICES; ++i)
{
PAHCI_PORT_REGISTERS Port;
if (!(AhciExtension->Hba->PortsImplemented & (1 << i)))
continue;
Port = &AhciExtension->Hba->Port[i];
Port->SataError = Port->SataError;
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS Status;
Status = PciIdeXInitialize(DriverObject,
RegistryPath,
PciAhciGetControllerProperties,
sizeof(AHCI_DEVICE_EXTENSION));
return Status;
}

View File

@ -0,0 +1,11 @@
/*
* PROJECT: ReactOS AHCI Port Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Common header file
* COPYRIGHT: Copyright 2024 Dmitry Borisov (di.sean@protonmail.com)
*/
#include <ntddk.h>
#include <ide.h>
#include <reactos/drivers/ntddata.h>

View File

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "PCI AHCI bus driver"
#define REACTOS_STR_INTERNAL_NAME "pciahci"
#define REACTOS_STR_ORIGINAL_FILENAME "pciahci.sys"
#include <reactos/version.rc>

View File

@ -0,0 +1,8 @@
; PCI AHCI Driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","Group",0x00000000,"System Bus Extender"
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","ImagePath",0x00020000,"system32\drivers\pciahci.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","Start",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\pciahci","Tag",0x00010001,0x00000010

View File

@ -11,3 +11,4 @@ else()
endif()
add_importlibs(pciide pciidex ntoskrnl)
add_cd_file(TARGET pciide DESTINATION reactos/system32/drivers NO_CAB FOR all)
add_registry_inf(pciide_reg.inf)

View File

@ -0,0 +1,8 @@
; PCI IDE driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","Group",0x00000000,"System Bus Extender"
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","ImagePath",0x00020000,"system32\drivers\pciide.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","Start",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\pciide","Tag",0x00010001,0x00000010

View File

@ -14,7 +14,7 @@ add_library(pciidex MODULE
pciidex.rc
${CMAKE_CURRENT_BINARY_DIR}/pciidex.def)
add_pch(pciidex pciidex.h SOURCE)
# add_pch(pciidex pciidex.h SOURCE)
set_module_type(pciidex kernelmodedriver)
add_importlibs(pciidex ntoskrnl hal)
add_cd_file(TARGET pciidex DESTINATION reactos/system32/drivers NO_CAB FOR all)

View File

@ -19,6 +19,8 @@ PciIdeXFdoParseResources(
_In_ PCM_RESOURCE_LIST ResourcesTranslated)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR BusMasterDescriptor = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR AbarDescriptor = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDescriptor = NULL;
PVOID IoBase;
ULONG i;
@ -34,6 +36,13 @@ PciIdeXFdoParseResources(
Descriptor = &ResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
switch (Descriptor->Type)
{
case CmResourceTypeInterrupt:
{
if (!InterruptDescriptor)
InterruptDescriptor = Descriptor;
break;
}
case CmResourceTypePort:
case CmResourceTypeMemory:
{
@ -50,6 +59,13 @@ PciIdeXFdoParseResources(
default:
break;
}
/* AHCI Base Address (BAR5) */
if ((i == 5) && (FdoExtension->Flags & FDO_AHCI))
{
if (Descriptor->Type == CmResourceTypeMemory)
AbarDescriptor = Descriptor;
}
}
default:
@ -57,6 +73,34 @@ PciIdeXFdoParseResources(
}
}
if (FdoExtension->Flags & FDO_AHCI)
{
if (!AbarDescriptor || !InterruptDescriptor)
return STATUS_DEVICE_CONFIGURATION_ERROR;
DPRINT("ABAR 0x%I64x 0x%lx\n",
AbarDescriptor->u.Port.Start.QuadPart, AbarDescriptor->u.Port.Length);
FdoExtension->Abar = MmMapIoSpace(AbarDescriptor->u.Memory.Start,
AbarDescriptor->u.Port.Length,
MmNonCached);
if (!FdoExtension->Abar)
return STATUS_INSUFFICIENT_RESOURCES;
FdoExtension->IoLength = AbarDescriptor->u.Port.Length;
FdoExtension->Flags |= FDO_IO_BASE_MAPPED;
FdoExtension->InterruptVector = InterruptDescriptor->u.Interrupt.Vector;
FdoExtension->InterruptLevel = InterruptDescriptor->u.Interrupt.Level;
FdoExtension->InterruptMode =
(InterruptDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
FdoExtension->InterruptShared =
(InterruptDescriptor->ShareDisposition == CmResourceShareShared);
FdoExtension->InterruptAffinity = InterruptDescriptor->u.Interrupt.Affinity;
return STATUS_SUCCESS;
}
if (!BusMasterDescriptor)
return STATUS_DEVICE_CONFIGURATION_ERROR;
@ -71,7 +115,8 @@ PciIdeXFdoParseResources(
if (!IoBase)
return STATUS_INSUFFICIENT_RESOURCES;
FdoExtension->IoBaseMapped = TRUE;
FdoExtension->IoLength = 16;
FdoExtension->Flags |= FDO_IO_BASE_MAPPED;
}
FdoExtension->BusMasterPortBase = IoBase;
@ -128,10 +173,10 @@ PciIdeXFdoFreeResources(
{
PAGED_CODE();
if (FdoExtension->IoBaseMapped)
if (FdoExtension->Flags & FDO_IO_BASE_MAPPED)
{
MmUnmapIoSpace(FdoExtension->BusMasterPortBase, 16);
FdoExtension->IoBaseMapped = FALSE;
MmUnmapIoSpace(FdoExtension->BusMasterPortBase, FdoExtension->IoLength);
FdoExtension->Flags &= ~FDO_IO_BASE_MAPPED;
}
}
@ -165,7 +210,7 @@ PciIdeXFdoRemoveDevice(
ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
for (i = 0; i < MAX_IDE_CHANNEL; ++i)
for (i = 0; i < FdoExtension->MaxDevices; ++i)
{
PdoExtension = FdoExtension->Channels[i];
@ -285,7 +330,7 @@ PciIdeXFdoQueryBusRelations(
DeviceRelations = ExAllocatePoolWithTag(PagedPool,
FIELD_OFFSET(DEVICE_RELATIONS,
Objects[MAX_IDE_CHANNEL]),
Objects[FdoExtension->MaxDevices]),
TAG_PCIIDEX);
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
@ -294,7 +339,7 @@ PciIdeXFdoQueryBusRelations(
ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
for (i = 0; i < MAX_IDE_CHANNEL; ++i)
for (i = 0; i < FdoExtension->MaxDevices; ++i)
{
PdoExtension = FdoExtension->Channels[i];
@ -397,7 +442,7 @@ PciIdeXFdoQueryInterface(
ResourceType = (ULONG_PTR)IoStack->Parameters.QueryInterface.InterfaceSpecificData;
/* In native mode the IDE controller does not use any legacy interrupt resources */
if (FdoExtension->InNativeMode ||
if ((FdoExtension->Flags & FDO_IN_NATIVE_MODE) ||
ResourceType != CmResourceTypeInterrupt ||
IoStack->Parameters.QueryInterface.Size < sizeof(TRANSLATOR_INTERFACE))
{

View File

@ -32,6 +32,20 @@ PciIdeXStartMiniport(
FdoExtension->DriverObject);
ASSERT(DriverExtension);
if (FdoExtension->Flags & FDO_AHCI)
{
PAHCI_DEVICE_EXTENSION DeviceExtension =
(PAHCI_DEVICE_EXTENSION)FdoExtension->MiniControllerExtension;
DeviceExtension->Hba = FdoExtension->Abar;
FdoExtension->MaxDevices = MAX_AHCI_DEVICES;
}
else
{
FdoExtension->MaxDevices = MAX_IDE_CHANNEL;
}
FdoExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
FdoExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
Status = DriverExtension->HwGetControllerProperties(FdoExtension->MiniControllerExtension,

View File

@ -127,16 +127,27 @@ PciIdeXGetConfigurationInfo(
if (PciConfig->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR)
{
if (PciConfig->ProgIf & PCIIDE_PROGIF_DMA_CAPABLE)
{
FdoExtension->Flags |= FDO_DMA_CAPABLE;
}
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);
if ((PciConfig->ProgIf & PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE) &&
(PciConfig->ProgIf & PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE))
{
FdoExtension->Flags |= FDO_IN_NATIVE_MODE;
}
}
else if (PciConfig->SubClass == PCI_SUBCLASS_MSC_AHCI_CTLR)
{
FdoExtension->Flags |= FDO_AHCI | FDO_IN_NATIVE_MODE;
}
else if (PciConfig->SubClass == PCI_SUBCLASS_MSC_RAID_CTLR)
{
FdoExtension->InNativeMode = TRUE;
FdoExtension->Flags |= FDO_IN_NATIVE_MODE;
}
}
@ -144,7 +155,7 @@ PciIdeXGetConfigurationInfo(
FdoExtension->VendorId,
FdoExtension->DeviceId,
PciConfig->ProgIf,
FdoExtension->InNativeMode);
!!(FdoExtension->Flags & FDO_IN_NATIVE_MODE));
return STATUS_SUCCESS;
}
@ -239,6 +250,12 @@ PciIdeXAddDevice(
goto Failure;
}
if (FdoExtension->Flags & FDO_AHCI)
{
DPRINT1("AHCI support not implemented yet\n");
goto Failure;
}
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;

View File

@ -16,6 +16,8 @@
#include <wdmguid.h>
#include <ide.h>
#include <reactos/drivers/ntddata.h>
#define TAG_PCIIDEX 'XedI'
#define IS_FDO(p) (((PCOMMON_DEVICE_EXTENSION)(p))->IsFDO)
@ -44,8 +46,6 @@
#define PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE_CAPABLE 0x08
#define PCIIDE_PROGIF_DMA_CAPABLE 0x80
#define BM_SECONDARY_CHANNEL_OFFSET 8
typedef struct _PDO_DEVICE_EXTENSION PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
typedef struct _PCIIDEX_DRIVER_EXTENSION
@ -75,18 +75,35 @@ typedef struct _FDO_DEVICE_EXTENSION
PDEVICE_OBJECT Ldo;
ULONG ControllerNumber;
BOOLEAN InNativeMode;
BOOLEAN IoBaseMapped;
ULONG Flags;
#define FDO_IN_NATIVE_MODE 0x00000001
#define FDO_AHCI 0x00000002
#define FDO_DMA_CAPABLE 0x00000004
#define FDO_IO_BASE_MAPPED 0x00000008
BOOLEAN MiniportStarted;
FAST_MUTEX DeviceSyncMutex;
_Guarded_by_(DeviceSyncMutex)
PPDO_DEVICE_EXTENSION Channels[MAX_IDE_CHANNEL];
PPDO_DEVICE_EXTENSION Channels[MAX_AHCI_DEVICES];
USHORT VendorId;
USHORT DeviceId;
PDRIVER_OBJECT DriverObject;
PUCHAR BusMasterPortBase;
union
{
PUCHAR BusMasterPortBase;
PVOID Abar;
};
ULONG IoLength;
ULONG MaxDevices;
PKINTERRUPT InterruptObject;
KINTERRUPT_MODE InterruptMode;
KAFFINITY InterruptAffinity;
ULONG InterruptVector;
KIRQL InterruptLevel;
BOOLEAN InterruptShared;
KSPIN_LOCK BusDataLock;
BUS_INTERFACE_STANDARD BusInterface;
@ -103,7 +120,17 @@ typedef struct _PDO_DEVICE_EXTENSION
ULONG Channel;
PFDO_DEVICE_EXTENSION ParentController;
BOOLEAN ReportedMissing;
PUCHAR IoBase;
ULONG Flags;
#define PDO_PIO_ONLY 0x00000001
#define PDO_DRIVE0_DMA_CAPABLE 0x00000002
#define PDO_DRIVE1_DMA_CAPABLE 0x00000004
PVOID PrdTable;
ULONG PrdTablePhysicalAddress;
ULONG MapRegisterCount;
PDMA_ADAPTER AdapterObject;
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
CODE_SEG("PAGE")

View File

@ -11,6 +11,153 @@
#define NDEBUG
#include <debug.h>
static
CODE_SEG("PAGE")
VOID
PciIdeXPdoFreeDmaResources(
_In_ PPDO_DEVICE_EXTENSION PdoExtension)
{
PDMA_OPERATIONS DmaOperations;
PDMA_ADAPTER AdapterObject;
PAGED_CODE();
PdoExtension->Flags &= ~(PDO_PIO_ONLY | PDO_DRIVE0_DMA_CAPABLE | PDO_DRIVE1_DMA_CAPABLE);
AdapterObject = PdoExtension->AdapterObject;
if (!AdapterObject)
return;
DmaOperations = AdapterObject->DmaOperations;
if (PdoExtension->PrdTable)
{
PHYSICAL_ADDRESS PrdTablePhysicalAddress;
PrdTablePhysicalAddress.QuadPart = PdoExtension->PrdTablePhysicalAddress;
DmaOperations->FreeCommonBuffer(AdapterObject,
PdoExtension->MapRegisterCount * sizeof(PRD_TABLE_ENTRY),
PrdTablePhysicalAddress,
PdoExtension->PrdTable,
FALSE);
PdoExtension->PrdTable = NULL;
}
DmaOperations->PutDmaAdapter(AdapterObject);
PdoExtension->AdapterObject = NULL;
}
static
CODE_SEG("PAGE")
BOOLEAN
PciIdeXPdoGetDmaAdapter(
_In_ PPDO_DEVICE_EXTENSION PdoExtension)
{
DEVICE_DESCRIPTION DeviceDescription = { 0 };
PAGED_CODE();
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = TRUE;
DeviceDescription.ScatterGather = TRUE;
DeviceDescription.Dma32BitAddresses = TRUE;
DeviceDescription.InterfaceType = PCIBus;
DeviceDescription.MaximumLength = ATA_MAX_TRANSFER_LENGTH;
PdoExtension->AdapterObject = IoGetDmaAdapter(PdoExtension->ParentController->Ldo,
&DeviceDescription,
&PdoExtension->MapRegisterCount);
if (!PdoExtension->AdapterObject)
return FALSE;
return TRUE;
}
static
CODE_SEG("PAGE")
BOOLEAN
PciIdeXPdoAllocatePrdTable(
_In_ PPDO_DEVICE_EXTENSION PdoExtension)
{
PHYSICAL_ADDRESS LogicalAddress;
PAGED_CODE();
PdoExtension->PrdTable = PdoExtension->AdapterObject->DmaOperations->
AllocateCommonBuffer(PdoExtension->AdapterObject,
PdoExtension->MapRegisterCount * sizeof(PRD_TABLE_ENTRY),
&LogicalAddress,
FALSE);
if (!PdoExtension->PrdTable)
return FALSE;
/* 32-bit DMA */
ASSERT(LogicalAddress.HighPart == 0);
PdoExtension->PrdTablePhysicalAddress = LogicalAddress.LowPart;
return TRUE;
}
static
CODE_SEG("PAGE")
VOID
PciIdeXPdoAllocateDmaResources(
_In_ PPDO_DEVICE_EXTENSION PdoExtension)
{
BOOLEAN Success;
UCHAR DmaStatus;
PAGED_CODE();
PdoExtension->IoBase = PdoExtension->ParentController->BusMasterPortBase;
if (!IS_PRIMARY_CHANNEL(PdoExtension))
{
PdoExtension->IoBase += DMA_SECONDARY_CHANNEL_OFFSET;
}
DmaStatus = READ_PORT_UCHAR(PdoExtension->IoBase + DMA_STATUS);
DPRINT("I/O Base %p, status 0x%02x\n", PdoExtension->IoBase, DmaStatus);
/* The status bits 3:4 must return 0 on reads */
if (DmaStatus & (DMA_STATUS_RESERVED1 | DMA_STATUS_RESERVED2))
{
DPRINT1("Unexpected DMA status 0x%02x\n", DmaStatus);
goto DisableDma;
}
/* The status bits 5:6 are set by the miniport driver or BIOS firmware at boot */
if (DmaStatus & DMA_STATUS_DRIVE0_DMA_CAPABLE)
PdoExtension->Flags |= PDO_DRIVE0_DMA_CAPABLE;
if (DmaStatus & DMA_STATUS_DRIVE1_DMA_CAPABLE)
PdoExtension->Flags |= PDO_DRIVE1_DMA_CAPABLE;
Success = PciIdeXPdoGetDmaAdapter(PdoExtension);
if (!Success)
{
DPRINT1("Unable to get DMA adapter\n");
goto DisableDma;
}
Success = PciIdeXPdoAllocatePrdTable(PdoExtension);
if (!Success)
{
DPRINT1("Unable to allocate PRD table\n");
PciIdeXPdoFreeDmaResources(PdoExtension);
goto DisableDma;
}
return;
DisableDma:
/* Failed to setup DMA, falling back to PIO mode */
PdoExtension->Flags |= PDO_PIO_ONLY;
}
static
CODE_SEG("PAGE")
NTSTATUS
@ -18,16 +165,14 @@ PciIdeXPdoStartDevice(
_In_ PPDO_DEVICE_EXTENSION PdoExtension,
_In_ PCM_RESOURCE_LIST ResourceList)
{
PUCHAR IoBase;
PFDO_DEVICE_EXTENSION FdoExtension = PdoExtension->ParentController;
PAGED_CODE();
IoBase = PdoExtension->ParentController->BusMasterPortBase;
if (!IS_PRIMARY_CHANNEL(PdoExtension))
if (FdoExtension->Flags & FDO_DMA_CAPABLE)
{
IoBase += BM_SECONDARY_CHANNEL_OFFSET;
PciIdeXPdoAllocateDmaResources(PdoExtension);
}
DPRINT("Bus Master Base %p\n", IoBase);
return STATUS_SUCCESS;
}
@ -40,6 +185,8 @@ PciIdeXPdoStopDevice(
{
PAGED_CODE();
PciIdeXPdoFreeDmaResources(PdoExtension);
return STATUS_SUCCESS;
}
@ -55,11 +202,13 @@ PciIdeXPdoRemoveDevice(
PAGED_CODE();
PciIdeXPdoFreeDmaResources(PdoExtension);
if (FinalRemove && PdoExtension->ReportedMissing)
{
ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
for (i = 0; i < MAX_IDE_CHANNEL; ++i)
for (i = 0; i < FdoExtension->MaxDevices; ++i)
{
if (FdoExtension->Channels[i] == PdoExtension)
{
@ -266,7 +415,7 @@ PciIdeXPdoQueryResources(
PAGED_CODE();
FdoExtension = PdoExtension->ParentController;
if (FdoExtension->InNativeMode)
if (FdoExtension->Flags & FDO_IN_NATIVE_MODE)
return Irp->IoStatus.Status;
ChannelState = PciIdeXChannelState(FdoExtension, PdoExtension->Channel);
@ -346,7 +495,7 @@ PciIdeXPdoQueryResourceRequirements(
PAGED_CODE();
FdoExtension = PdoExtension->ParentController;
if (FdoExtension->InNativeMode)
if (FdoExtension->Flags & FDO_IN_NATIVE_MODE)
return Irp->IoStatus.Status;
ChannelState = PciIdeXChannelState(FdoExtension, PdoExtension->Channel);
@ -748,6 +897,103 @@ PciIdeXPdoQueryDeviceUsageNotification(
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
PciIdeXQueryAhciPortInterface(
_In_ PPDO_DEVICE_EXTENSION PdoExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PFDO_DEVICE_EXTENSION FdoExtension = PdoExtension->ParentController;
PAHCI_PORT_INTERFACE AhciPortInterface;
PAHCI_HOST_BUS_ADAPTER Hba;
PAGED_CODE();
if (!(FdoExtension->Flags & FDO_AHCI))
return Irp->IoStatus.Status;
if (IoStack->Parameters.QueryInterface.Size < sizeof(*AhciPortInterface))
return Irp->IoStatus.Status;
Hba = FdoExtension->Abar;
AhciPortInterface = (PAHCI_PORT_INTERFACE)IoStack->Parameters.QueryInterface.Interface;
AhciPortInterface->Port = &Hba->Port[PdoExtension->Channel];
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
PciIdeXQueryPciIdeInterface(
_In_ PPDO_DEVICE_EXTENSION PdoExtension,
_In_ PIRP Irp,
_In_ PIO_STACK_LOCATION IoStack)
{
PFDO_DEVICE_EXTENSION FdoExtension = PdoExtension->ParentController;
PPCIIDE_INTERFACE PciIdeInterface;
PAGED_CODE();
if (FdoExtension->Flags & FDO_AHCI)
return Irp->IoStatus.Status;
if (IoStack->Parameters.QueryInterface.Size < sizeof(*PciIdeInterface))
return Irp->IoStatus.Status;
PciIdeInterface = (PPCIIDE_INTERFACE)IoStack->Parameters.QueryInterface.Interface;
PciIdeInterface->IoBase = PdoExtension->IoBase;
if (PdoExtension->Flags & PDO_PIO_ONLY)
{
PciIdeInterface->PrdTable = NULL;
}
else
{
PciIdeInterface->PrdTable = PdoExtension->PrdTable;
PciIdeInterface->PrdTablePhysicalAddress = PdoExtension->PrdTablePhysicalAddress;
PciIdeInterface->MaximumTransferLength = PdoExtension->MapRegisterCount << PAGE_SHIFT;
PciIdeInterface->AdapterObject = PdoExtension->AdapterObject;
PciIdeInterface->DeviceObject = PdoExtension->Common.Self;
}
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
PciIdeXPdoQueryInterface(
_In_ PPDO_DEVICE_EXTENSION PdoExtension,
_Inout_ PIRP Irp)
{
NTSTATUS Status;
PIO_STACK_LOCATION IoStack;
PAGED_CODE();
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
&GUID_AHCI_PORT_INTERFACE))
{
Status = PciIdeXQueryAhciPortInterface(PdoExtension, Irp, IoStack);
}
else if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
&GUID_PCIIDE_INTERFACE))
{
Status = PciIdeXQueryPciIdeInterface(PdoExtension, Irp, IoStack);
}
else
{
Status = Irp->IoStatus.Status;
}
return Status;
}
static
CODE_SEG("PAGE")
NTSTATUS
@ -823,6 +1069,10 @@ PciIdeXPdoDispatchPnp(
Status = PciIdeXPdoQueryDeviceUsageNotification(PdoExtension, Irp);
break;
case IRP_MN_QUERY_INTERFACE:
Status = PciIdeXPdoQueryInterface(PdoExtension, Irp);
break;
default:
Status = Irp->IoStatus.Status;
break;

View File

@ -30,212 +30,212 @@ HKR, , Installer32, 0, "syssetup.dll,HdcClassInstaller"
[GenericMfg]
;Well-known adapters
%PCI\VEN_1191&DEV_0005.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0005
%PCI\VEN_1191&DEV_0006.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0006
%PCI\VEN_1191&DEV_0007.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0007
%PCI\VEN_1191&DEV_0008.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0008
%PCI\VEN_1191&DEV_0009.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0009
%PCI\VEN_10b9&DEV_5289.DeviceDesc%=uniata_Inst, PCI\VEN_10b9&DEV_5289
%PCI\VEN_10b9&DEV_5288.DeviceDesc%=uniata_Inst, PCI\VEN_10b9&DEV_5288
%PCI\VEN_10b9&DEV_5287.DeviceDesc%=uniata_Inst, PCI\VEN_10b9&DEV_5287
%PCI\VEN_10b9&DEV_5281.DeviceDesc%=uniata_Inst, PCI\VEN_10b9&DEV_5281
%PCI\VEN_10b9&DEV_5229&REV_c5.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c5
%PCI\VEN_10b9&DEV_5229&REV_c4.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c4
%PCI\VEN_10b9&DEV_5229&REV_c2.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c2
%PCI\VEN_10b9&DEV_5229&REV_20.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_20
%PCI\VEN_10b9&DEV_5229.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229
%PCI\VEN_1022&DEV_7401.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7401
%PCI\VEN_1022&DEV_7409.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7409
%PCI\VEN_1022&DEV_7411.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7411
%PCI\VEN_1022&DEV_7441.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7441
%PCI\VEN_1022&DEV_7469.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7469
%PCI\VEN_1022&DEV_209a.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_209a
%PCI\VEN_1002&DEV_4349.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4349
%PCI\VEN_1002&DEV_4369.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4369
%PCI\VEN_1002&DEV_4376.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4376
%PCI\VEN_1002&DEV_436e.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_436e
%PCI\VEN_1002&DEV_4379.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_4379
%PCI\VEN_1002&DEV_437a.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_437a
%PCI\VEN_1002&DEV_438c.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_438c
%PCI\VEN_1002&DEV_4380.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_4380
%PCI\VEN_1002&DEV_439c.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_439c
%PCI\VEN_1002&DEV_4390.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_4390
%PCI\VEN_1002&DEV_4391.DeviceDesc%=uniata_Inst, PCI\VEN_1002&DEV_4391
%PCI\VEN_1103&DEV_0004&REV_05.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_05
%PCI\VEN_1103&DEV_0004&REV_03.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_03
%PCI\VEN_1103&DEV_0004&REV_02.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_02
%PCI\VEN_1103&DEV_0004.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004
%PCI\VEN_1103&DEV_0005&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0005&REV_01
%PCI\VEN_1103&DEV_0005.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0005
%PCI\VEN_1103&DEV_0006&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0006&REV_01
%PCI\VEN_1103&DEV_0007&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0007&REV_01
%PCI\VEN_1103&DEV_0008&REV_07.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0008&REV_07
%PCI\VEN_8086&DEV_1230.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_1230
%PCI\VEN_8086&DEV_7010.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7010
%PCI\VEN_8086&DEV_7111.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7111
%PCI\VEN_8086&DEV_7199.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7199
%PCI\VEN_8086&DEV_84ca.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_84ca
%PCI\VEN_8086&DEV_7601.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7601
%PCI\VEN_8086&DEV_2421.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2421
%PCI\VEN_8086&DEV_2411.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2411
%PCI\VEN_8086&DEV_244a.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_244a
%PCI\VEN_8086&DEV_244b.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_244b
%PCI\VEN_8086&DEV_248a.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_248a
%PCI\VEN_8086&DEV_248b.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_248b
%PCI\VEN_8086&DEV_24cb.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24cb
%PCI\VEN_8086&DEV_24ca.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24ca
%PCI\VEN_8086&DEV_24db.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24db
%PCI\VEN_8086&DEV_24d1.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_24d1
%PCI\VEN_8086&DEV_24df.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_24df
%PCI\VEN_8086&DEV_25a2.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_25a2
%PCI\VEN_8086&DEV_25a3.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_25a3
%PCI\VEN_8086&DEV_25b0.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_25b0
%PCI\VEN_8086&DEV_266f.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_266f
%PCI\VEN_8086&DEV_2651.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2651
%PCI\VEN_8086&DEV_2652.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2652
%PCI\VEN_8086&DEV_2653.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2653
%PCI\VEN_8086&DEV_27df.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27df
%PCI\VEN_8086&DEV_27c0.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c0
%PCI\VEN_8086&DEV_27c1.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c1
%PCI\VEN_8086&DEV_27c3.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c3
%PCI\VEN_8086&DEV_27c4.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c4
%PCI\VEN_8086&DEV_27c5.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c5
%PCI\VEN_8086&DEV_27c6.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_27c6
%PCI\VEN_8086&DEV_269e.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_269e
%PCI\VEN_8086&DEV_2680.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2680
%PCI\VEN_8086&DEV_2681.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2681
%PCI\VEN_8086&DEV_2682.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2682
%PCI\VEN_8086&DEV_2683.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2683
%PCI\VEN_8086&DEV_2820.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2820
%PCI\VEN_8086&DEV_2821.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2821
%PCI\VEN_8086&DEV_2822.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2822
%PCI\VEN_8086&DEV_2824.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2824
%PCI\VEN_8086&DEV_2825.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2825
%PCI\VEN_8086&DEV_2828.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2828
%PCI\VEN_8086&DEV_2829.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2829
%PCI\VEN_8086&DEV_2850.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2850
%PCI\VEN_8086&DEV_282a.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_282a
%PCI\VEN_8086&DEV_2920.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2920
%PCI\VEN_8086&DEV_2921.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2921
%PCI\VEN_8086&DEV_2926.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2926
%PCI\VEN_8086&DEV_2923.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2923
%PCI\VEN_8086&DEV_2922.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2922
%PCI\VEN_8086&DEV_2928.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2928
%PCI\VEN_8086&DEV_2929.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_2929
%PCI\VEN_8086&DEV_292d.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_292d
%PCI\VEN_8086&DEV_292e.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_292e
%PCI\VEN_8086&DEV_3a00.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a00
%PCI\VEN_8086&DEV_3a02.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a02
%PCI\VEN_8086&DEV_3a03.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a03
%PCI\VEN_8086&DEV_3a06.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a06
%PCI\VEN_8086&DEV_3a20.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a20
%PCI\VEN_8086&DEV_3a22.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a22
%PCI\VEN_8086&DEV_3a23.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a23
%PCI\VEN_8086&DEV_3a26.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3a26
%PCI\VEN_8086&DEV_3b20.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b20
%PCI\VEN_8086&DEV_3b21.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b21
%PCI\VEN_8086&DEV_3b22.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b22
%PCI\VEN_8086&DEV_3b23.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b23
%PCI\VEN_8086&DEV_3b26.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b26
%PCI\VEN_8086&DEV_3b28.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b28
%PCI\VEN_8086&DEV_3b29.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b29
%PCI\VEN_8086&DEV_3b2d.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b2d
%PCI\VEN_8086&DEV_3b2e.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b2e
%PCI\VEN_8086&DEV_3b2f.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3b2f
; %PCI\VEN_8086&DEV_3200.DeviceDesc%=uniata_Inst, PCI\VEN_8086&DEV_3200
; %PCI\VEN_1191&DEV_0005.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0005
; %PCI\VEN_1191&DEV_0006.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0006
; %PCI\VEN_1191&DEV_0007.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0007
; %PCI\VEN_1191&DEV_0008.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0008
; %PCI\VEN_1191&DEV_0009.DeviceDesc%=PciIde_Inst, PCI\VEN_1191&DEV_0009
; %PCI\VEN_10b9&DEV_5289.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5289
; %PCI\VEN_10b9&DEV_5288.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5288
; %PCI\VEN_10b9&DEV_5287.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5287
; %PCI\VEN_10b9&DEV_5281.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5281
; %PCI\VEN_10b9&DEV_5229&REV_c5.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c5
; %PCI\VEN_10b9&DEV_5229&REV_c4.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c4
; %PCI\VEN_10b9&DEV_5229&REV_c2.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_c2
; %PCI\VEN_10b9&DEV_5229&REV_20.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229&REV_20
; %PCI\VEN_10b9&DEV_5229.DeviceDesc%=PciIde_Inst, PCI\VEN_10b9&DEV_5229
; %PCI\VEN_1022&DEV_7401.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7401
; %PCI\VEN_1022&DEV_7409.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7409
; %PCI\VEN_1022&DEV_7411.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7411
; %PCI\VEN_1022&DEV_7441.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7441
; %PCI\VEN_1022&DEV_7469.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_7469
; %PCI\VEN_1022&DEV_209a.DeviceDesc%=PciIde_Inst, PCI\VEN_1022&DEV_209a
; %PCI\VEN_1002&DEV_4349.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4349
; %PCI\VEN_1002&DEV_4369.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4369
; %PCI\VEN_1002&DEV_4376.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4376
; %PCI\VEN_1002&DEV_436e.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_436e
; %PCI\VEN_1002&DEV_4379.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4379
; %PCI\VEN_1002&DEV_437a.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_437a
; %PCI\VEN_1002&DEV_438c.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_438c
; %PCI\VEN_1002&DEV_4380.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4380
; %PCI\VEN_1002&DEV_439c.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_439c
; %PCI\VEN_1002&DEV_4390.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4390
; %PCI\VEN_1002&DEV_4391.DeviceDesc%=PciIde_Inst, PCI\VEN_1002&DEV_4391
; %PCI\VEN_1103&DEV_0004&REV_05.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_05
; %PCI\VEN_1103&DEV_0004&REV_03.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_03
; %PCI\VEN_1103&DEV_0004&REV_02.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004&REV_02
; %PCI\VEN_1103&DEV_0004.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0004
; %PCI\VEN_1103&DEV_0005&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0005&REV_01
; %PCI\VEN_1103&DEV_0005.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0005
; %PCI\VEN_1103&DEV_0006&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0006&REV_01
; %PCI\VEN_1103&DEV_0007&REV_01.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0007&REV_01
; %PCI\VEN_1103&DEV_0008&REV_07.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0008&REV_07
; %PCI\VEN_8086&DEV_1230.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_1230
; %PCI\VEN_8086&DEV_7010.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7010
; %PCI\VEN_8086&DEV_7111.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7111
; %PCI\VEN_8086&DEV_7199.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7199
; %PCI\VEN_8086&DEV_84ca.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_84ca
; %PCI\VEN_8086&DEV_7601.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_7601
; %PCI\VEN_8086&DEV_2421.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2421
; %PCI\VEN_8086&DEV_2411.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2411
; %PCI\VEN_8086&DEV_244a.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_244a
; %PCI\VEN_8086&DEV_244b.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_244b
; %PCI\VEN_8086&DEV_248a.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_248a
; %PCI\VEN_8086&DEV_248b.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_248b
; %PCI\VEN_8086&DEV_24cb.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24cb
; %PCI\VEN_8086&DEV_24ca.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24ca
; %PCI\VEN_8086&DEV_24db.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24db
; %PCI\VEN_8086&DEV_24d1.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24d1
; %PCI\VEN_8086&DEV_24df.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_24df
; %PCI\VEN_8086&DEV_25a2.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_25a2
; %PCI\VEN_8086&DEV_25a3.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_25a3
; %PCI\VEN_8086&DEV_25b0.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_25b0
; %PCI\VEN_8086&DEV_266f.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_266f
; %PCI\VEN_8086&DEV_2651.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2651
; %PCI\VEN_8086&DEV_2652.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2652
; %PCI\VEN_8086&DEV_2653.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2653
; %PCI\VEN_8086&DEV_27df.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27df
; %PCI\VEN_8086&DEV_27c0.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c0
; %PCI\VEN_8086&DEV_27c1.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c1
; %PCI\VEN_8086&DEV_27c3.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c3
; %PCI\VEN_8086&DEV_27c4.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c4
; %PCI\VEN_8086&DEV_27c5.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c5
; %PCI\VEN_8086&DEV_27c6.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_27c6
; %PCI\VEN_8086&DEV_269e.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_269e
; %PCI\VEN_8086&DEV_2680.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2680
; %PCI\VEN_8086&DEV_2681.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2681
; %PCI\VEN_8086&DEV_2682.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2682
; %PCI\VEN_8086&DEV_2683.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2683
; %PCI\VEN_8086&DEV_2820.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2820
; %PCI\VEN_8086&DEV_2821.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2821
; %PCI\VEN_8086&DEV_2822.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2822
; %PCI\VEN_8086&DEV_2824.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2824
; %PCI\VEN_8086&DEV_2825.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2825
; %PCI\VEN_8086&DEV_2828.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2828
; %PCI\VEN_8086&DEV_2829.DeviceDesc%=PciAhci_Inst, PCI\VEN_8086&DEV_2829
; %PCI\VEN_8086&DEV_2850.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2850
; %PCI\VEN_8086&DEV_282a.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_282a
; %PCI\VEN_8086&DEV_2920.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2920
; %PCI\VEN_8086&DEV_2921.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2921
; %PCI\VEN_8086&DEV_2926.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2926
; %PCI\VEN_8086&DEV_2923.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2923
; %PCI\VEN_8086&DEV_2922.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2922
; %PCI\VEN_8086&DEV_2928.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2928
; %PCI\VEN_8086&DEV_2929.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_2929
; %PCI\VEN_8086&DEV_292d.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_292d
; %PCI\VEN_8086&DEV_292e.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_292e
; %PCI\VEN_8086&DEV_3a00.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a00
; %PCI\VEN_8086&DEV_3a02.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a02
; %PCI\VEN_8086&DEV_3a03.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a03
; %PCI\VEN_8086&DEV_3a06.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a06
; %PCI\VEN_8086&DEV_3a20.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a20
; %PCI\VEN_8086&DEV_3a22.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a22
; %PCI\VEN_8086&DEV_3a23.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a23
; %PCI\VEN_8086&DEV_3a26.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3a26
; %PCI\VEN_8086&DEV_3b20.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b20
; %PCI\VEN_8086&DEV_3b21.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b21
; %PCI\VEN_8086&DEV_3b22.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b22
; %PCI\VEN_8086&DEV_3b23.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b23
; %PCI\VEN_8086&DEV_3b26.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b26
; %PCI\VEN_8086&DEV_3b28.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b28
; %PCI\VEN_8086&DEV_3b29.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b29
; %PCI\VEN_8086&DEV_3b2d.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b2d
; %PCI\VEN_8086&DEV_3b2e.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b2e
; %PCI\VEN_8086&DEV_3b2f.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3b2f
; %PCI\VEN_8086&DEV_3200.DeviceDesc%=PciIde_Inst, PCI\VEN_8086&DEV_3200
%PCI\VEN_11ab&DEV_5040.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5040
%PCI\VEN_11ab&DEV_5041.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5041
%PCI\VEN_11ab&DEV_5080.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5080
%PCI\VEN_11ab&DEV_5081.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5081
%PCI\VEN_11ab&DEV_6041.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6041
%PCI\VEN_11ab&DEV_6081.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6081
%PCI\VEN_11ab&DEV_6101.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6101
%PCI\VEN_11ab&DEV_6145.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6145
; %PCI\VEN_11ab&DEV_5040.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5040
; %PCI\VEN_11ab&DEV_5041.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5041
; %PCI\VEN_11ab&DEV_5080.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5080
; %PCI\VEN_11ab&DEV_5081.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_5081
; %PCI\VEN_11ab&DEV_6041.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6041
; %PCI\VEN_11ab&DEV_6081.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6081
; %PCI\VEN_11ab&DEV_6101.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6101
; %PCI\VEN_11ab&DEV_6145.DeviceDesc%=PciIde_Inst, PCI\VEN_11ab&DEV_6145
%PCI\VEN_10de&DEV_01bc.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_01bc
%PCI\VEN_10de&DEV_0065.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0065
%PCI\VEN_10de&DEV_0085.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0085
%PCI\VEN_10de&DEV_008e.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_008e
%PCI\VEN_10de&DEV_00d5.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00d5
%PCI\VEN_10de&DEV_00e5.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00e5
%PCI\VEN_10de&DEV_00e3.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_00e3
%PCI\VEN_10de&DEV_00ee.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_00ee
%PCI\VEN_10de&DEV_0035.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0035
%PCI\VEN_10de&DEV_0036.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_0036
%PCI\VEN_10de&DEV_003e.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_003e
%PCI\VEN_10de&DEV_0053.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0053
%PCI\VEN_10de&DEV_0054.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_0054
%PCI\VEN_10de&DEV_0055.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_0055
%PCI\VEN_10de&DEV_0265.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0265
%PCI\VEN_10de&DEV_0266.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_0266
%PCI\VEN_10de&DEV_0267.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_0267
%PCI\VEN_10de&DEV_036e.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_036e
%PCI\VEN_10de&DEV_037e.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_037e
%PCI\VEN_10de&DEV_037f.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_037f
%PCI\VEN_10de&DEV_03ec.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_03ec
%PCI\VEN_10de&DEV_03e7.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_03e7
%PCI\VEN_10de&DEV_03f6.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_03f6
%PCI\VEN_10de&DEV_03f7.DeviceDesc%=uniata_Inst, PCI\VEN_10de&DEV_03f7
%PCI\VEN_10de&DEV_0448.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0448
%PCI\VEN_10de&DEV_0560.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0560
%PCI\VEN_10de&DEV_056c.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_056c
%PCI\VEN_10de&DEV_0759.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0759
; %PCI\VEN_10de&DEV_01bc.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_01bc
; %PCI\VEN_10de&DEV_0065.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0065
; %PCI\VEN_10de&DEV_0085.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0085
; %PCI\VEN_10de&DEV_008e.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_008e
; %PCI\VEN_10de&DEV_00d5.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00d5
; %PCI\VEN_10de&DEV_00e5.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00e5
; %PCI\VEN_10de&DEV_00e3.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00e3
; %PCI\VEN_10de&DEV_00ee.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_00ee
; %PCI\VEN_10de&DEV_0035.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0035
; %PCI\VEN_10de&DEV_0036.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0036
; %PCI\VEN_10de&DEV_003e.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_003e
; %PCI\VEN_10de&DEV_0053.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0053
; %PCI\VEN_10de&DEV_0054.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0054
; %PCI\VEN_10de&DEV_0055.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0055
; %PCI\VEN_10de&DEV_0265.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0265
; %PCI\VEN_10de&DEV_0266.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0266
; %PCI\VEN_10de&DEV_0267.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0267
; %PCI\VEN_10de&DEV_036e.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_036e
; %PCI\VEN_10de&DEV_037e.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_037e
; %PCI\VEN_10de&DEV_037f.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_037f
; %PCI\VEN_10de&DEV_03ec.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_03ec
; %PCI\VEN_10de&DEV_03e7.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_03e7
; %PCI\VEN_10de&DEV_03f6.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_03f6
; %PCI\VEN_10de&DEV_03f7.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_03f7
; %PCI\VEN_10de&DEV_0448.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0448
; %PCI\VEN_10de&DEV_0560.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0560
; %PCI\VEN_10de&DEV_056c.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_056c
; %PCI\VEN_10de&DEV_0759.DeviceDesc%=PciIde_Inst, PCI\VEN_10de&DEV_0759
%PCI\VEN_100b&DEV_0502.DeviceDesc%=PciIde_Inst, PCI\VEN_100b&DEV_0502
; %PCI\VEN_100b&DEV_0502.DeviceDesc%=PciIde_Inst, PCI\VEN_100b&DEV_0502
%PCI\VEN_105a&DEV_4d33.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d33
%PCI\VEN_105a&DEV_4d38.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d38
%PCI\VEN_105a&DEV_0d38.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_0d38
%PCI\VEN_105a&DEV_0d30.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_0d30
%PCI\VEN_105a&DEV_4d30.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d30
%PCI\VEN_105a&DEV_4d68.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d68
%PCI\VEN_105a&DEV_4d69.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d69
%PCI\VEN_105a&DEV_6268.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6268
%PCI\VEN_105a&DEV_6269.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6269
%PCI\VEN_105a&DEV_1275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_1275
%PCI\VEN_105a&DEV_5275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_5275
%PCI\VEN_105a&DEV_7275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_7275
%PCI\VEN_105a&DEV_3318.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3318
%PCI\VEN_105a&DEV_3319.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3319
%PCI\VEN_105a&DEV_3371.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3371
%PCI\VEN_105a&DEV_3375.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3375
%PCI\VEN_105a&DEV_3376.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3376
%PCI\VEN_105a&DEV_3377.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3377
%PCI\VEN_105a&DEV_3373.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3373
%PCI\VEN_105a&DEV_3372.DeviceDesc%=uniata_Inst, PCI\VEN_105a&DEV_3372
%PCI\VEN_105a&DEV_6617.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6617
%PCI\VEN_105a&DEV_6626.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6626
%PCI\VEN_105a&DEV_6629.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6629
%PCI\VEN_105a&DEV_6620.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6620
%PCI\VEN_105a&DEV_6621.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6621
%PCI\VEN_105a&DEV_6622.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6622
; %PCI\VEN_105a&DEV_4d33.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d33
; %PCI\VEN_105a&DEV_4d38.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d38
; %PCI\VEN_105a&DEV_0d38.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_0d38
; %PCI\VEN_105a&DEV_0d30.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_0d30
; %PCI\VEN_105a&DEV_4d30.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d30
; %PCI\VEN_105a&DEV_4d68.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d68
; %PCI\VEN_105a&DEV_4d69.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d69
; %PCI\VEN_105a&DEV_6268.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6268
; %PCI\VEN_105a&DEV_6269.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6269
; %PCI\VEN_105a&DEV_1275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_1275
; %PCI\VEN_105a&DEV_5275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_5275
; %PCI\VEN_105a&DEV_7275.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_7275
; %PCI\VEN_105a&DEV_3318.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3318
; %PCI\VEN_105a&DEV_3319.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3319
; %PCI\VEN_105a&DEV_3371.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3371
; %PCI\VEN_105a&DEV_3375.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3375
; %PCI\VEN_105a&DEV_3376.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3376
; %PCI\VEN_105a&DEV_3377.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3377
; %PCI\VEN_105a&DEV_3373.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3373
; %PCI\VEN_105a&DEV_3372.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_3372
; %PCI\VEN_105a&DEV_6617.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6617
; %PCI\VEN_105a&DEV_6626.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6626
; %PCI\VEN_105a&DEV_6629.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6629
; %PCI\VEN_105a&DEV_6620.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6620
; %PCI\VEN_105a&DEV_6621.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6621
; %PCI\VEN_105a&DEV_6622.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6622
%PCI\VEN_1166&DEV_0211.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0211
%PCI\VEN_1166&DEV_0212&REV_92.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0212&REV_92
%PCI\VEN_1166&DEV_0212.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0212
%PCI\VEN_1166&DEV_0213.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0213
%PCI\VEN_1166&DEV_0217.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0217
%PCI\VEN_1166&DEV_0214.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0214
%PCI\VEN_1166&DEV_024b.DeviceDesc%=uniata_Inst, PCI\VEN_1166&DEV_024b
%PCI\VEN_1166&DEV_024a.DeviceDesc%=uniata_Inst, PCI\VEN_1166&DEV_024a
%PCI\VEN_1166&DEV_0240.DeviceDesc%=uniata_Inst, PCI\VEN_1166&DEV_0240
%PCI\VEN_1166&DEV_0241.DeviceDesc%=uniata_Inst, PCI\VEN_1166&DEV_0241
%PCI\VEN_1166&DEV_0242.DeviceDesc%=uniata_Inst, PCI\VEN_1166&DEV_0242
; %PCI\VEN_1166&DEV_0211.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0211
; %PCI\VEN_1166&DEV_0212&REV_92.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0212&REV_92
; %PCI\VEN_1166&DEV_0212.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0212
; %PCI\VEN_1166&DEV_0213.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0213
; %PCI\VEN_1166&DEV_0217.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0217
; %PCI\VEN_1166&DEV_0214.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0214
; %PCI\VEN_1166&DEV_024b.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_024b
; %PCI\VEN_1166&DEV_024a.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_024a
; %PCI\VEN_1166&DEV_0240.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0240
; %PCI\VEN_1166&DEV_0241.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0241
; %PCI\VEN_1166&DEV_0242.DeviceDesc%=PciIde_Inst, PCI\VEN_1166&DEV_0242
%PCI\VEN_1095&DEV_3114.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_3114
%PCI\VEN_1095&DEV_3512&REV_02.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_3512&REV_02
%PCI\VEN_1095&DEV_3112&REV_02.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_3112&REV_02
%PCI\VEN_1095&DEV_0240&REV_02.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_0240&REV_02
%PCI\VEN_1095&DEV_3512.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_3512
%PCI\VEN_1095&DEV_3112.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_3112
%PCI\VEN_1095&DEV_0240.DeviceDesc%=uniata_Inst, PCI\VEN_1095&DEV_0240
%PCI\VEN_1095&DEV_0680.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0680
%PCI\VEN_1095&DEV_0649.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0649
%PCI\VEN_1095&DEV_0648.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0648
%PCI\VEN_1095&DEV_0646&REV_07.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0646&REV_07
%PCI\VEN_1095&DEV_0646.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0646
%PCI\VEN_1095&DEV_0640.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0640
; %PCI\VEN_1095&DEV_3114.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_3114
; %PCI\VEN_1095&DEV_3512&REV_02.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_3512&REV_02
; %PCI\VEN_1095&DEV_3112&REV_02.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_3112&REV_02
; %PCI\VEN_1095&DEV_0240&REV_02.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0240&REV_02
; %PCI\VEN_1095&DEV_3512.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_3512
; %PCI\VEN_1095&DEV_3112.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_3112
; %PCI\VEN_1095&DEV_0240.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0240
; %PCI\VEN_1095&DEV_0680.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0680
; %PCI\VEN_1095&DEV_0649.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0649
; %PCI\VEN_1095&DEV_0648.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0648
; %PCI\VEN_1095&DEV_0646&REV_07.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0646&REV_07
; %PCI\VEN_1095&DEV_0646.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0646
; %PCI\VEN_1095&DEV_0640.DeviceDesc%=PciIde_Inst, PCI\VEN_1095&DEV_0640
; %PCI\VEN_1039&DEV_0963.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0963
; %PCI\VEN_1039&DEV_0962.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0962
@ -266,9 +266,9 @@ HKR, , Installer32, 0, "syssetup.dll,HdcClassInstaller"
; %PCI\VEN_1039&DEV_0550.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0550
; %PCI\VEN_1039&DEV_0540.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0540
; %PCI\VEN_1039&DEV_0530.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0530
%PCI\VEN_1039&DEV_5513&REV_c2.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_5513&REV_c2
%PCI\VEN_1039&DEV_5513.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_5513
%PCI\VEN_1039&DEV_0601.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0601
; %PCI\VEN_1039&DEV_5513&REV_c2.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_5513&REV_c2
; %PCI\VEN_1039&DEV_5513.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_5513
; %PCI\VEN_1039&DEV_0601.DeviceDesc%=PciIde_Inst, PCI\VEN_1039&DEV_0601
; %PCI\VEN_1106&DEV_0586&REV_41.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0586&REV_41
; %PCI\VEN_1106&DEV_0586&REV_40.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0586&REV_40
@ -284,15 +284,15 @@ HKR, , Installer32, 0, "syssetup.dll,HdcClassInstaller"
; %PCI\VEN_1106&DEV_3109.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3109
; %PCI\VEN_1106&DEV_3147.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3147
; %PCI\VEN_1106&DEV_3177.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3177
%PCI\VEN_1106&DEV_0571.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0571
%PCI\VEN_1106&DEV_3164.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3164
%PCI\VEN_1106&DEV_3149.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3149
%PCI\VEN_1106&DEV_3249.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3249
%PCI\VEN_1106&DEV_0591.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0591
%PCI\VEN_1106&DEV_5337.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_5337
%PCI\VEN_1106&DEV_3349.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3349
; %PCI\VEN_1106&DEV_0571.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0571
; %PCI\VEN_1106&DEV_3164.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3164
; %PCI\VEN_1106&DEV_3149.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3149
; %PCI\VEN_1106&DEV_3249.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3249
; %PCI\VEN_1106&DEV_0591.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_0591
; %PCI\VEN_1106&DEV_5337.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_5337
; %PCI\VEN_1106&DEV_3349.DeviceDesc%=PciIde_Inst, PCI\VEN_1106&DEV_3349
%PCI\VEN_1080&DEV_c693.DeviceDesc%=PciIde_Inst, PCI\VEN_1080&DEV_c693
; %PCI\VEN_1080&DEV_c693.DeviceDesc%=PciIde_Inst, PCI\VEN_1080&DEV_c693
; %PCI\VEN_105a&DEV_4d68.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_4d68
; %PCI\VEN_105a&DEV_6268.DeviceDesc%=PciIde_Inst, PCI\VEN_105a&DEV_6268
@ -310,36 +310,42 @@ HKR, , Installer32, 0, "syssetup.dll,HdcClassInstaller"
; %PCI\VEN_1103&DEV_0005.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0005
; %PCI\VEN_1103&DEV_0008.DeviceDesc%=PciIde_Inst, PCI\VEN_1103&DEV_0008
%PCI\VEN_16ca&DEV_0001.DeviceDesc%=PciIde_Inst, PCI\VEN_16ca&DEV_0001
%PCI\VEN_1078&DEV_0102.DeviceDesc%=PciIde_Inst, PCI\VEN_1078&DEV_0102
%PCI\VEN_1042&DEV_0102.DeviceDesc%=PciIde_Inst, PCI\VEN_1042&DEV_0102
; %PCI\VEN_16ca&DEV_0001.DeviceDesc%=PciIde_Inst, PCI\VEN_16ca&DEV_0001
; %PCI\VEN_1078&DEV_0102.DeviceDesc%=PciIde_Inst, PCI\VEN_1078&DEV_0102
; %PCI\VEN_1042&DEV_0102.DeviceDesc%=PciIde_Inst, PCI\VEN_1042&DEV_0102
%PCI\VEN_1283&DEV_8172.DeviceDesc%=PciIde_Inst, PCI\VEN_1283&DEV_8172
%PCI\VEN_1283&DEV_8212.DeviceDesc%=PciIde_Inst, PCI\VEN_1283&DEV_8212
; %PCI\VEN_1283&DEV_8172.DeviceDesc%=PciIde_Inst, PCI\VEN_1283&DEV_8172
; %PCI\VEN_1283&DEV_8212.DeviceDesc%=PciIde_Inst, PCI\VEN_1283&DEV_8212
%PCI\VEN_169c&DEV_0044.DeviceDesc%=PciIde_Inst, PCI\VEN_169c&DEV_0044
%PCI\VEN_3388&DEV_8013.DeviceDesc%=PciIde_Inst, PCI\VEN_3388&DEV_8013
; %PCI\VEN_169c&DEV_0044.DeviceDesc%=PciIde_Inst, PCI\VEN_169c&DEV_0044
; %PCI\VEN_3388&DEV_8013.DeviceDesc%=PciIde_Inst, PCI\VEN_3388&DEV_8013
%PCI\VEN_ffff&DEV_ffff&REV_ff.DeviceDesc%=PciIde_Inst, PCI\VEN_ffff&DEV_ffff&REV_ff
; %PCI\VEN_ffff&DEV_ffff&REV_ff.DeviceDesc%=PciIde_Inst, PCI\VEN_ffff&DEV_ffff&REV_ff
; Compatible adapters
%PCI\CC_0101.DeviceDesc%=PciIde_Inst,PCI\CC_0101 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%PCI\CC_0104.DeviceDesc%=uniata_Inst,PCI\CC_0104 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%PCI\CC_0105.DeviceDesc%=uniata_Inst,PCI\CC_0105 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%PCI\CC_0106.DeviceDesc%=uniata_Inst,PCI\CC_0106 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%*PNP0600.PriDeviceDesc%=uniata_Inst, Primary_IDE_Channel
%*PNP0600.SecDeviceDesc%=uniata_Inst, Secondary_IDE_Channel
%*PNP0600.DeviceDesc%=uniata_Inst, *PNP0600 ; Generic_ESDI_Hard_Disk_Controller (BAD_IDE)
%UniATA_Name%=uniata_Inst
%PCI\CC_0104.DeviceDesc%=PciIde_Inst,PCI\CC_0104 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%PCI\CC_0105.DeviceDesc%=PciIde_Inst,PCI\CC_0105 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%PCI\CC_0106.DeviceDesc%=PciAhci_Inst,PCI\CC_0106 ; Device ID for generic Dual PCI IDE (UNKNOWN_PCI_IDE)
%*PNP0600.PriDeviceDesc%=Atapi_Inst, Primary_IDE_Channel
%*PNP0600.SecDeviceDesc%=Atapi_Inst, Secondary_IDE_Channel
%*PNP0600.DeviceDesc%=Atapi_Inst, *PNP0600 ; Generic_ESDI_Hard_Disk_Controller (BAD_IDE)
%UniATA_Name%=PciIde_Inst
;---------------------------- PCI IDE DRIVER ----------------------------
[PciIde_Inst.NT]
CopyFiles = PciIde_CopyFiles.NT
AddReg = StorPropAddReg
[StorPropAddReg]
HKR,,EnumPropPages32,,"storprop.dll,IdePropPageProvider"
[PciIde_CopyFiles.NT]
atapi.sys
pciide.sys
pciidex.sys
storprop.dll
[PciIde_Inst.NT.Services]
AddService = pciide, 0x00000002, pciide_Service_Inst
@ -351,24 +357,46 @@ ErrorControl = 1
ServiceBinary = %12%\pciide.sys
LoadOrderGroup = System Bus Extender
;----------------------------- UNIATA DRIVER ----------------------------
;---------------------------- PCI AHCI DRIVER ---------------------------
[uniata_Inst.NT]
CopyFiles = uniata_CopyFiles.NT
[PciAhci_Inst.NT]
CopyFiles = PciAhci_CopyFiles.NT
[uniata_CopyFiles.NT]
uniata.sys
[PciAhci_CopyFiles.NT]
atapi.sys
pciahci.sys
pciidex.sys
[uniata_Inst.NT.Services]
AddService = UniATA, 0x00000002, uniata_Service_Inst
[PciAhci_Inst.NT.Services]
AddService = pciahci, 0x00000002, PciAhci_Service_Inst
[uniata_Service_Inst]
[PciAhci_Service_Inst]
ServiceType = 1
StartType = 0
ErrorControl = 1
ServiceBinary = %12%\uniata.sys
ServiceBinary = %12%\pciahci.sys
LoadOrderGroup = System Bus Extender
;---------------------------- ATA PORT DRIVER ----------------------------
[Atapi_Inst.NT]
CopyFiles = Atapi_CopyFiles.NT
AddReg = StorPropAddReg
[Atapi_CopyFiles.NT]
atapi.sys
storprop.dll
[Atapi_Inst.NT.Services]
AddService = atapi, 0x00000002, atapi_Service_Inst
[atapi_Service_Inst]
ServiceType = 1
StartType = 0
ErrorControl = 1
ServiceBinary = %12%\atapi.sys
LoadOrderGroup = SCSI Miniport
;-------------------------------- STRINGS -------------------------------
[Strings]

View File

@ -54,7 +54,12 @@ extern "C" {
#define _CRT_TERMINATE_DEFINED
__declspec(noreturn) void __cdecl exit(_In_ int _Code);
_CRTIMP __declspec(noreturn) void __cdecl _exit(_In_ int _Code);
#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */
/* C99 function name */
__declspec(noreturn) void __cdecl _Exit(int); /* Declare to get noreturn attribute. */
__CRT_INLINE void __cdecl _Exit(int status)
{ _exit(status); }
#endif
#if __MINGW_GNUC_PREREQ(4,4)
#pragma push_macro("abort")
#undef abort
@ -62,7 +67,6 @@ extern "C" {
__declspec(noreturn) void __cdecl abort(void);
#if __MINGW_GNUC_PREREQ(4,4)
#pragma pop_macro("abort")
#undef abort
#endif
#endif

View File

@ -14,7 +14,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT DeviceType :1;
} GeneralConfiguration;
USHORT NumCylinders;
USHORT ReservedWord2;
USHORT SpecificConfiguration;
USHORT NumHeads;
USHORT Retired1[2];
USHORT NumSectorsPerTrack;
@ -26,9 +26,13 @@ typedef struct _IDENTIFY_DEVICE_DATA {
UCHAR ModelNumber[40];
UCHAR MaximumBlockTransfer;
UCHAR VendorUnique2;
USHORT ReservedWord48;
struct {
UCHAR ReservedByte49;
USHORT FeatureSupported :1;
USHORT Reserved :15;
} TrustedComputing;
struct {
UCHAR CurrentLongPhysicalSectorAlignment :2;
UCHAR ReservedByte49 :6;
UCHAR DmaSupported :1;
UCHAR LbaSupported :1;
UCHAR IordyDisable :1;
@ -40,14 +44,19 @@ typedef struct _IDENTIFY_DEVICE_DATA {
} Capabilities;
USHORT ObsoleteWords51[2];
USHORT TranslationFieldsValid :3;
USHORT Reserved3 :13;
USHORT Reserved3 :5;
USHORT FreeFallControlSensitivity :8;
USHORT NumberOfCurrentCylinders;
USHORT NumberOfCurrentHeads;
USHORT CurrentSectorsPerTrack;
ULONG CurrentSectorCapacity;
UCHAR CurrentMultiSectorSetting;
UCHAR MultiSectorSettingValid :1;
UCHAR ReservedByte59 :7;
UCHAR ReservedByte59 :3;
UCHAR SanitizeFeatureSupported :1;
UCHAR CryptoScrambleExtCommandSupported :1;
UCHAR OverwriteExtCommandSupported :1;
UCHAR BlockEraseExtCommandSupported :1;
ULONG UserAddressableSectors;
USHORT ObsoleteWord62;
USHORT MultiWordDMASupport :8;
@ -58,10 +67,74 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT RecommendedMWXferCycleTime;
USHORT MinimumPIOCycleTime;
USHORT MinimumPIOCycleTimeIORDY;
USHORT ReservedWords69[6];
struct {
USHORT ZonedCapabilities :2;
USHORT NonVolatileWriteCache :1;
USHORT ExtendedUserAddressableSectorsSupported :1;
USHORT DeviceEncryptsAllUserData :1;
USHORT ReadZeroAfterTrimSupported :1;
USHORT Optional28BitCommandsSupported :1;
USHORT IEEE1667 :1;
USHORT DownloadMicrocodeDmaSupported :1;
USHORT SetMaxSetPasswordUnlockDmaSupported :1;
USHORT WriteBufferDmaSupported :1;
USHORT ReadBufferDmaSupported :1;
USHORT DeviceConfigIdentifySetDmaSupported :1;
USHORT LPSAERCSupported :1;
USHORT DeterministicReadAfterTrimSupported :1;
USHORT CFastSpecSupported :1;
} AdditionalSupported;
USHORT ReservedWords70[5];
USHORT QueueDepth :5;
USHORT ReservedWord75 :11;
USHORT ReservedWords76[4];
struct {
USHORT Reserved0 :1;
USHORT SataGen1 :1;
USHORT SataGen2 :1;
USHORT SataGen3 :1;
USHORT Reserved1 :4;
USHORT NCQ :1;
USHORT HIPM :1;
USHORT PhyEvents :1;
USHORT NcqUnload :1;
USHORT NcqPriority :1;
USHORT HostAutoPS :1;
USHORT DeviceAutoPS :1;
USHORT ReadLogDMA :1;
USHORT Reserved2 :1;
USHORT CurrentSpeed :3;
USHORT NcqStreaming :1;
USHORT NcqQueueMgmt :1;
USHORT NcqReceiveSend :1;
USHORT DEVSLPtoReducedPwrState :1;
USHORT Reserved3 :8;
} SerialAtaCapabilities;
struct {
USHORT Reserved0 :1;
USHORT NonZeroOffsets :1;
USHORT DmaSetupAutoActivate :1;
USHORT DIPM :1;
USHORT InOrderData :1;
USHORT HardwareFeatureControl :1;
USHORT SoftwareSettingsPreservation :1;
USHORT NCQAutosense :1;
USHORT DEVSLP :1;
USHORT HybridInformation :1;
USHORT Reserved1 :6;
} SerialAtaFeaturesSupported;
struct {
USHORT Reserved0 :1;
USHORT NonZeroOffsets :1;
USHORT DmaSetupAutoActivate :1;
USHORT DIPM :1;
USHORT InOrderData :1;
USHORT HardwareFeatureControl :1;
USHORT SoftwareSettingsPreservation :1;
USHORT DeviceAutoPS :1;
USHORT DEVSLP :1;
USHORT HybridInformation :1;
USHORT Reserved1 :6;
} SerialAtaFeaturesEnabled;
USHORT MajorRevision;
USHORT MinorRevision;
struct {
@ -95,7 +168,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT DeviceConfigOverlay :1;
USHORT FlushCache :1;
USHORT FlushCacheExt :1;
USHORT Resrved3 :2;
USHORT WordValid83 :2;
USHORT SmartErrorLog :1;
USHORT SmartSelfTest :1;
USHORT MediaSerialNumber :1;
@ -109,7 +182,7 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT URGWriteStream :1;
USHORT ReservedForTechReport :2;
USHORT IdleWithUnloadFeature :1;
USHORT Reserved4 :2;
USHORT WordValid :2;
} CommandSetSupport;
struct {
USHORT SmartCommands :1;
@ -142,7 +215,8 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT DeviceConfigOverlay :1;
USHORT FlushCache :1;
USHORT FlushCacheExt :1;
USHORT Resrved3 :2;
USHORT Resrved3 :1;
USHORT Words119_120Valid :1;
USHORT SmartErrorLog :1;
USHORT SmartSelfTest :1;
USHORT MediaSerialNumber :1;
@ -160,14 +234,27 @@ typedef struct _IDENTIFY_DEVICE_DATA {
} CommandSetActive;
USHORT UltraDMASupport :8;
USHORT UltraDMAActive :8;
USHORT ReservedWord89[4];
struct {
USHORT TimeRequired :15;
USHORT ExtendedTimeReported :1;
} NormalSecurityEraseUnit;
struct {
USHORT TimeRequired :15;
USHORT ExtendedTimeReported :1;
} EnhancedSecurityEraseUnit;
USHORT CurrentAPMLevel :8;
USHORT ReservedWord91 :8;
USHORT MasterPasswordID;
USHORT HardwareResetResult;
USHORT CurrentAcousticValue :8;
USHORT RecommendedAcousticValue :8;
USHORT ReservedWord95[5];
USHORT StreamMinRequestSize;
USHORT StreamingTransferTimeDMA;
USHORT StreamingAccessLatencyDMAPIO;
ULONG StreamingPerfGranularity;
ULONG Max48BitLBA[2];
USHORT StreamingTransferTime;
USHORT ReservedWord105;
USHORT DsmCap;
struct {
USHORT LogicalSectorsPerPhysicalSector :4;
USHORT Reserved0 :8;
@ -182,19 +269,31 @@ typedef struct _IDENTIFY_DEVICE_DATA {
USHORT WordsPerLogicalSector[2];
struct {
USHORT ReservedForDrqTechnicalReport :1;
USHORT WriteReadVerifySupported :1;
USHORT Reserved01 :11;
USHORT Reserved1 :2;
USHORT WriteReadVerify :1;
USHORT WriteUncorrectableExt :1;
USHORT ReadWriteLogDmaExt :1;
USHORT DownloadMicrocodeMode3 :1;
USHORT FreefallControl :1;
USHORT SenseDataReporting :1;
USHORT ExtendedPowerConditions :1;
USHORT Reserved0 :6;
USHORT WordValid :2;
} CommandSetSupportExt;
struct {
USHORT ReservedForDrqTechnicalReport :1;
USHORT WriteReadVerifyEnabled :1;
USHORT Reserved01 :11;
USHORT WriteReadVerify :1;
USHORT WriteUncorrectableExt :1;
USHORT ReadWriteLogDmaExt :1;
USHORT DownloadMicrocodeMode3 :1;
USHORT FreefallControl :1;
USHORT SenseDataReporting :1;
USHORT ExtendedPowerConditions :1;
USHORT Reserved0 :6;
USHORT Reserved1 :2;
} CommandSetActiveExt;
USHORT ReservedForExpandedSupportandActive[6];
USHORT MsnSupport :2;
USHORT ReservedWord1274 :14;
USHORT ReservedWord127 :14;
struct {
USHORT SecuritySupported :1;
USHORT SecurityEnabled :1;
@ -208,20 +307,32 @@ typedef struct _IDENTIFY_DEVICE_DATA {
} SecurityStatus;
USHORT ReservedWord129[31];
struct {
USHORT MaximumCurrentInMA2 :12;
USHORT MaximumCurrentInMA :12;
USHORT CfaPowerMode1Disabled :1;
USHORT CfaPowerMode1Required :1;
USHORT Reserved0 :1;
USHORT Word160Supported :1;
} CfaPowerModel;
USHORT ReservedForCfaWord161[8];
} CfaPowerMode1;
USHORT ReservedForCfaWord161[7];
USHORT NominalFormFactor :4;
USHORT ReservedWord168 :12;
struct {
USHORT SupportsTrim :1;
USHORT Reserved0 :15;
} DataSetManagementFeature;
USHORT ReservedForCfaWord170[6];
USHORT AdditionalProductID[4];
USHORT ReservedForCfaWord174[2];
USHORT CurrentMediaSerialNumber[30];
USHORT ReservedWord206;
struct {
USHORT Supported :1;
USHORT Reserved0 :1;
USHORT WriteSameSuported :1;
USHORT ErrorRecoveryControlSupported :1;
USHORT FeatureControlSuported :1;
USHORT DataTablesSuported :1;
USHORT Reserved1 :6;
USHORT VendorSpecific :4;
} SCTCommandTransport;
USHORT ReservedWord207[2];
struct {
USHORT AlignmentOfLogicalWithinPhysical :14;
@ -246,14 +357,260 @@ typedef struct _IDENTIFY_DEVICE_DATA {
UCHAR NVCacheEstimatedTimeToSpinUpInSeconds;
UCHAR Reserved;
} NVCacheOptions;
USHORT ReservedWord220[35];
USHORT WriteReadVerifySectorCountMode :8;
USHORT ReservedWord220 :8;
USHORT ReservedWord221;
struct {
USHORT MajorVersion :12;
USHORT TransportType :4;
} TransportMajorVersion;
USHORT TransportMinorVersion;
USHORT ReservedWord224[6];
ULONG ExtendedNumberOfUserAddressableSectors[2];
USHORT MinBlocksPerDownloadMicrocodeMode03;
USHORT MaxBlocksPerDownloadMicrocodeMode03;
USHORT ReservedWord236[19];
USHORT Signature :8;
USHORT CheckSum :8;
} IDENTIFY_DEVICE_DATA, *PIDENTIFY_DEVICE_DATA;
typedef struct _IDENTIFY_PACKET_DATA {
struct {
USHORT PacketType :2;
USHORT IncompleteResponse :1;
USHORT Reserved1 :2;
USHORT DrqDelay :2;
USHORT RemovableMedia :1;
USHORT CommandPacketType :5;
USHORT Reserved2 :1;
USHORT DeviceType :2;
} GeneralConfiguration;
USHORT ResevedWord1;
USHORT UniqueConfiguration;
USHORT ReservedWords3[7];
UCHAR SerialNumber[20];
USHORT ReservedWords20[3];
UCHAR FirmwareRevision[8];
UCHAR ModelNumber[40];
USHORT ReservedWords47[2];
struct {
USHORT VendorSpecific :8;
USHORT DmaSupported :1;
USHORT LbaSupported :1;
USHORT IordyDisabled :1;
USHORT IordySupported :1;
USHORT Obsolete :1;
USHORT OverlapSupported :1;
USHORT QueuedCommandsSupported :1;
USHORT InterleavedDmaSupported :1;
USHORT DeviceSpecificStandbyTimerValueMin :1;
USHORT Obsolete1 :1;
USHORT ReservedWord50 :12;
USHORT WordValid :2;
} Capabilities;
USHORT ObsoleteWords51[2];
USHORT TranslationFieldsValid :3;
USHORT Reserved3 :13;
USHORT ReservedWords54[8];
struct {
USHORT UDMA0Supported :1;
USHORT UDMA1Supported :1;
USHORT UDMA2Supported :1;
USHORT UDMA3Supported :1;
USHORT UDMA4Supported :1;
USHORT UDMA5Supported :1;
USHORT UDMA6Supported :1;
USHORT MDMA0Supported :1;
USHORT MDMA1Supported :1;
USHORT MDMA2Supported :1;
USHORT DMASupported :1;
USHORT ReservedWord62 :4;
USHORT DMADIRBitRequired :1;
} DMADIR;
USHORT MultiWordDMASupport :8;
USHORT MultiWordDMAActive :8;
USHORT AdvancedPIOModes :8;
USHORT ReservedByte64 :8;
USHORT MinimumMWXferCycleTime;
USHORT RecommendedMWXferCycleTime;
USHORT MinimumPIOCycleTime;
USHORT MinimumPIOCycleTimeIORDY;
USHORT ReservedWords69[2];
USHORT BusReleaseDelay;
USHORT ServiceCommandDelay;
USHORT ReservedWords73[2];
USHORT QueueDepth :5;
USHORT ReservedWord75 :11;
struct {
USHORT Reserved0 :1;
USHORT SataGen1 :1;
USHORT SataGen2 :1;
USHORT SataGen3 :1;
USHORT Reserved1 :5;
USHORT HIPM :1;
USHORT PhyEvents :1;
USHORT Reserved3 :2;
USHORT HostAutoPS :1;
USHORT DeviceAutoPS :1;
USHORT Reserved4 :1;
USHORT Reserved5 :1;
USHORT CurrentSpeed :3;
USHORT SlimlineDeviceAttention :1;
USHORT HostEnvironmentDetect :1;
USHORT Reserved :10;
} SerialAtaCapabilities;
struct {
USHORT Reserved0 :1;
USHORT Reserved1 :2;
USHORT DIPM :1;
USHORT Reserved2 :1;
USHORT AsynchronousNotification :1;
USHORT SoftwareSettingsPreservation :1;
USHORT Reserved3 :9;
} SerialAtaFeaturesSupported;
struct {
USHORT Reserved0 :1;
USHORT Reserved1 :2;
USHORT DIPM :1;
USHORT Reserved2 :1;
USHORT AsynchronousNotification :1;
USHORT SoftwareSettingsPreservation :1;
USHORT DeviceAutoPS :1;
USHORT Reserved3 :8;
} SerialAtaFeaturesEnabled;
USHORT MajorRevision;
USHORT MinorRevision;
struct {
USHORT SmartCommands :1;
USHORT SecurityMode :1;
USHORT RemovableMedia :1;
USHORT PowerManagement :1;
USHORT PacketCommands :1;
USHORT WriteCache :1;
USHORT LookAhead :1;
USHORT ReleaseInterrupt :1;
USHORT ServiceInterrupt :1;
USHORT DeviceReset :1;
USHORT HostProtectedArea :1;
USHORT Obsolete1 :1;
USHORT WriteBuffer :1;
USHORT ReadBuffer :1;
USHORT Nop :1;
USHORT Obsolete2 :1;
USHORT DownloadMicrocode :1;
USHORT Reserved1 :2;
USHORT AdvancedPm :1;
USHORT Msn :1;
USHORT PowerUpInStandby :1;
USHORT ManualPowerUp :1;
USHORT Reserved2 :1;
USHORT SetMax :1;
USHORT Reserved3 :3;
USHORT FlushCache :1;
USHORT Reserved4 :1;
USHORT WordValid :2;
} CommandSetSupport;
struct {
USHORT Reserved0 :5;
USHORT GpLogging :1;
USHORT Reserved1 :2;
USHORT WWN64Bit :1;
USHORT Reserved2 :5;
USHORT WordValid :2;
} CommandSetSupportExt;
struct {
USHORT SmartCommands :1;
USHORT SecurityMode :1;
USHORT RemovableMedia :1;
USHORT PowerManagement :1;
USHORT PacketCommands :1;
USHORT WriteCache :1;
USHORT LookAhead :1;
USHORT ReleaseInterrupt :1;
USHORT ServiceInterrupt :1;
USHORT DeviceReset :1;
USHORT HostProtectedArea :1;
USHORT Obsolete1 :1;
USHORT WriteBuffer :1;
USHORT ReadBuffer :1;
USHORT Nop :1;
USHORT Obsolete2 :1;
USHORT DownloadMicrocode :1;
USHORT Reserved1 :2;
USHORT AdvancedPm :1;
USHORT Msn :1;
USHORT PowerUpInStandby :1;
USHORT ManualPowerUp :1;
USHORT Reserved2 :1;
USHORT SetMax :1;
USHORT Reserved3 :3;
USHORT FlushCache :1;
USHORT Reserved :3;
} CommandSetActive;
struct {
USHORT Reserved0 :5;
USHORT GpLogging :1;
USHORT Reserved1 :2;
USHORT WWN64Bit :1;
USHORT Reserved2 :5;
USHORT WordValid :2;
} CommandSetActiveExt;
USHORT UltraDMASupport :8;
USHORT UltraDMAActive :8;
USHORT TimeRequiredForNormalEraseModeSecurityEraseUnit;
USHORT TimeRequiredForEnhancedEraseModeSecurityEraseUnit;
USHORT CurrentAPMLevel;
USHORT MasterPasswordID;
USHORT HardwareResetResult;
USHORT ReservedWords94[14];
USHORT WorldWideName[4];
USHORT ReservedWords112[13];
USHORT AtapiZeroByteCount;
USHORT ReservedWord126;
USHORT MsnSupport :2;
USHORT ReservedWord127 :14;
USHORT SecurityStatus;
USHORT VendorSpecific[31];
USHORT ReservedWord160[16];
USHORT ReservedWord176[46];
struct {
USHORT MajorVersion :12;
USHORT TransportType :4;
} TransportMajorVersion;
USHORT TransportMinorVersion;
USHORT ReservedWord224[31];
USHORT Signature :8;
USHORT CheckSum :8;
} IDENTIFY_PACKET_DATA, *PIDENTIFY_PACKET_DATA;
#include <poppack.h>
#define IDE_LBA_MODE (1 << 6)
#define IDE_DC_DISABLE_INTERRUPTS 0x02
#define IDE_DC_RESET_CONTROLLER 0x04
#define IDE_DC_REENABLE_CONTROLLER 0x00
#define IDE_STATUS_ERROR 0x01
#define IDE_STATUS_INDEX 0x02
#define IDE_STATUS_CORRECTED_ERROR 0x04
#define IDE_STATUS_DRQ 0x08
#define IDE_STATUS_DSC 0x10
#define IDE_STATUS_DEVICE_FAULT 0x20
#define IDE_STATUS_DRDY 0x40
#define IDE_STATUS_IDLE 0x50
#define IDE_STATUS_BUSY 0x80
#define IDE_ERROR_BAD_BLOCK 0x80
#define IDE_ERROR_CRC_ERROR IDE_ERROR_BAD_BLOCK
#define IDE_ERROR_DATA_ERROR 0x40
#define IDE_ERROR_MEDIA_CHANGE 0x20
#define IDE_ERROR_ID_NOT_FOUND 0x10
#define IDE_ERROR_MEDIA_CHANGE_REQ 0x08
#define IDE_ERROR_COMMAND_ABORTED 0x04
#define IDE_ERROR_END_OF_MEDIA 0x02
#define IDE_ERROR_ILLEGAL_LENGTH 0x01
#define IDE_ERROR_ADDRESS_NOT_FOUND IDE_ERROR_ILLEGAL_LENGTH
#define IDE_COMMAND_NOP 0x00
#define IDE_COMMAND_DATA_SET_MANAGEMENT 0x06
#define IDE_COMMAND_ATAPI_RESET 0x08
@ -298,4 +655,16 @@ typedef struct _IDENTIFY_DEVICE_DATA {
#define IDE_COMMAND_SECURITY_FREEZE_LOCK 0xF5
#define IDE_COMMAND_NOT_VALID 0xFF
#define IDE_FEATURE_ENABLE_WRITE_CACHE 0x2
#define IDE_FEATURE_SET_TRANSFER_MODE 0x3
#define IDE_FEATURE_ENABLE_PUIS 0x6
#define IDE_FEATURE_PUIS_SPIN_UP 0x7
#define IDE_FEATURE_ENABLE_SATA_FEATURE 0x10
#define IDE_FEATURE_DISABLE_MSN 0x31
#define IDE_FEATURE_DISABLE_REVERT_TO_POWER_ON 0x66
#define IDE_FEATURE_DISABLE_WRITE_CACHE 0x82
#define IDE_FEATURE_DISABLE_PUIS 0x86
#define IDE_FEATURE_DISABLE_SATA_FEATURE 0x90
#define IDE_FEATURE_ENABLE_MSN 0x95
#endif

View File

@ -33,3 +33,20 @@ Author:
#error Invalid compiler!
#endif
/*
* This attribute should be applied to a function that
* called from pageable code and raises the IRQL at DISPATCH_LEVEL or higher,
* and restores the IRQL before it returns. We must make sure that function is not inlined.
*/
#define DECLSPEC_NOINLINE_FROM_PAGED DECLSPEC_NOINLINE
/*
* This attribute should be applied to a function that
* called from non-pageable code at IRQL lower than DISPATCH_LEVEL.
* We should make sure that function is not inlined. Some compilers (GCC)
* can do inlining even if the function is in another section.
* See the discussion https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31362
* for more details.
*/
#define DECLSPEC_NOINLINE_FROM_NOT_PAGED DECLSPEC_NOINLINE

View File

@ -0,0 +1,198 @@
/*
* PROJECT: ReactOS Storage Stack
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: ATA driver definitions
* COPYRIGHT: Copyright 2024 Dmitry Borisov (di.sean@protonmail.com)
*/
#pragma once
/*
* 256 sectors of 512 bytes (128 kB).
* This ensures that the sector count register will not overflow
* in LBA-28 and CHS modes.
*/
#define ATA_MAX_TRANSFER_LENGTH 0x20000
/* Offset from base address */
#define DMA_SECONDARY_CHANNEL_OFFSET 8
/*
* IDE Bus Master I/O Registers
*/
#define DMA_COMMAND 0
#define DMA_STATUS 2
#define DMA_PRDT_PHYSICAL_ADDRESS 4
/*
* IDE Bus Master Command Register
*/
#define DMA_COMMAND_STOP 0x00
#define DMA_COMMAND_START 0x01
#define DMA_COMMAND_READ_FROM_SYSTEM_MEMORY 0x00
#define DMA_COMMAND_WRITE_TO_SYSTEM_MEMORY 0x08
/*
* IDE Bus Master Status Register
*/
#define DMA_STATUS_ACTIVE 0x01
#define DMA_STATUS_ERROR 0x02
#define DMA_STATUS_INTERRUPT 0x04
#define DMA_STATUS_RESERVED1 0x08
#define DMA_STATUS_RESERVED2 0x10
#define DMA_STATUS_DRIVE0_DMA_CAPABLE 0x20
#define DMA_STATUS_DRIVE1_DMA_CAPABLE 0x40
#define DMA_STATUS_SIMPLEX 0x80
/* 64 kB boundary */
#define PRD_LIMIT 0x10000
#include <pshpack1.h>
/*
* Physical Region Descriptor Table Entry
*/
typedef struct _PRD_TABLE_ENTRY
{
ULONG Address;
ULONG Length;
#define PRD_LENGTH_MASK 0xFFFF
#define PRD_END_OF_TABLE 0x80000000
} PRD_TABLE_ENTRY, *PPRD_TABLE_ENTRY;
/*
* Physical Region Descriptor Table
*/
typedef struct _PRD_TABLE
{
PRD_TABLE_ENTRY Entry[ANYSIZE_ARRAY];
} PRD_TABLE, *PPRD_TABLE;
#include <poppack.h>
typedef struct _PCIIDE_INTERFACE
{
USHORT Size;
USHORT Version;
PVOID Context;
PINTERFACE_REFERENCE InterfaceReference;
PINTERFACE_DEREFERENCE InterfaceDereference;
PUCHAR IoBase;
PVOID PrdTable;
ULONG PrdTablePhysicalAddress;
ULONG MaximumTransferLength;
PDMA_ADAPTER AdapterObject;
PDEVICE_OBJECT DeviceObject;
} PCIIDE_INTERFACE, *PPCIIDE_INTERFACE;
DEFINE_GUID(GUID_PCIIDE_INTERFACE,
0xD677FBCF, 0xABED, 0x47C8, 0x80, 0xA3, 0xE4, 0x34, 0x7E, 0xA4, 0x96, 0x47);
#define MAX_AHCI_DEVICES 32
#define AHCI_COMMAND_LIST_SIZE 0x400
#define AHCI_RECEIVED_FIS_SIZE 0x400
#include <pshpack1.h>
typedef struct _AHCI_PORT_REGISTERS
{
volatile ULONG CommandListBaseLow;
volatile ULONG CommandListBaseHigh;
volatile ULONG FisBaseLow;
volatile ULONG FisBaseHigh;
volatile ULONG InterruptStatus;
volatile ULONG InterruptEnable;
volatile ULONG CmdStatus;
volatile ULONG Reserved;
volatile ULONG TaskFileData;
volatile ULONG Signature;
volatile ULONG SataStatus;
volatile ULONG SataControl;
volatile ULONG SataError;
volatile ULONG SataActive;
volatile ULONG CommandIssue;
volatile ULONG SataNotification;
volatile ULONG FisSwitchingControl;
volatile ULONG Reserved2[11];
volatile ULONG Reserved3[4];
} AHCI_PORT_REGISTERS, *PAHCI_PORT_REGISTERS;
typedef struct _AHCI_HOST_BUS_ADAPTER
{
volatile ULONG Capabilities;
volatile ULONG GlobalControl;
#define AHCI_GHC_AE 0x80000000
volatile ULONG InterruptStatus;
volatile ULONG PortsImplemented;
volatile ULONG AhciVersion;
volatile ULONG CoalescingControl;
volatile ULONG CoalescingPorts;
volatile ULONG EnclosureManagementLocation;
volatile ULONG EnclosureManagementControl;
volatile ULONG CapabilitiesEx;
volatile ULONG BiosControl;
volatile ULONG Reserved[29 + 24];
AHCI_PORT_REGISTERS Port[MAX_AHCI_DEVICES];
} AHCI_HOST_BUS_ADAPTER, *PAHCI_HOST_BUS_ADAPTER;
typedef struct _AHCI_RECEIVED_FIS
{
UCHAR DmaSetup[0x1C];
ULONG Reserved;
UCHAR PioSetup[0x14];
ULONG Reserved2[3];
UCHAR DeviceToHost[0x14];
ULONG Reserved3;
UCHAR DeviceBits[0x08];
UCHAR UnknownFis[0x40];
UCHAR Reserved4[0x60];
} AHCI_RECEIVED_FIS, *PAHCI_RECEIVED_FIS;
typedef struct _AHCI_COMMAND_LIST_ENTRY
{
ULONG Control;
ULONG PrdByteCount;
ULONG CommandTableBaseLow;
ULONG CommandTableBaseHigh;
ULONG Reserved[4];
} AHCI_COMMAND_LIST_ENTRY, *PAHCI_COMMAND_LIST_ENTRY;
typedef struct _AHCI_PRD
{
ULONG DataBaseLow;
ULONG DataBaseHigh;
ULONG Reserved;
ULONG ByteCount;
} AHCI_PRD, *PAHCI_PRD;
#include <poppack.h>
typedef struct _AHCI_DEVICE_EXTENSION
{
PAHCI_HOST_BUS_ADAPTER Hba;
} AHCI_DEVICE_EXTENSION, *PAHCI_DEVICE_EXTENSION;
typedef struct _AHCI_PORT_INTERFACE
{
USHORT Size;
USHORT Version;
PVOID Context;
PINTERFACE_REFERENCE InterfaceReference;
PINTERFACE_DEREFERENCE InterfaceDereference;
PAHCI_PORT_REGISTERS Port;
} AHCI_PORT_INTERFACE, *PAHCI_PORT_INTERFACE;
DEFINE_GUID(GUID_AHCI_PORT_INTERFACE,
0xD677FBCF, 0xABED, 0x47C8, 0x80, 0xA3, 0xE4, 0x34, 0x7E, 0xA4, 0x96, 0x46);

View File

@ -4130,6 +4130,7 @@ typedef struct _PCI_EXPRESS_SRIOV_CAPABILITY {
#define PCI_SUBCLASS_MSC_FLOPPY_CTLR 0x02
#define PCI_SUBCLASS_MSC_IPI_CTLR 0x03
#define PCI_SUBCLASS_MSC_RAID_CTLR 0x04
#define PCI_SUBCLASS_MSC_AHCI_CTLR 0x06
#define PCI_SUBCLASS_MSC_OTHER 0x80
/* PCI device subclasses for class 2 (network controllers)*/