mirror of https://github.com/reactos/reactos.git
Compare commits
10 Commits
022a0fcf55
...
48b2ff7004
Author | SHA1 | Date |
---|---|---|
Dmitry Borisov | 48b2ff7004 | |
Timo Kreuzer | 45aa8f8111 | |
Timo Kreuzer | 6beff505d7 | |
Dmitry Borisov | 93ec419a7d | |
Dmitry Borisov | ff45d61932 | |
Dmitry Borisov | c04df3f2c9 | |
Dmitry Borisov | b0c9c12a4a | |
Dmitry Borisov | 16897cf20f | |
Dmitry Borisov | 769cff3f1e | |
Dmitry Borisov | ef0cd511d6 |
|
@ -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}"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
add_subdirectory(atapi)
|
||||
add_subdirectory(pciahci)
|
||||
add_subdirectory(pciide)
|
||||
add_subdirectory(pciidex)
|
||||
add_subdirectory(uniata)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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))
|
||||
|
|
@ -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>
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -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)*/
|
||||
|
|
Loading…
Reference in New Issue