mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[FREELDR] Add ATA/ATAPI driver. (#2167)
CORE-16220 CORE-16216 * Create a new driver. * Use the functions from the library in xboxdisk.c Driver now supports PC, Xbox and NEC PC-98. Co-Authored-By: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
This commit is contained in:
parent
7789ce1ebc
commit
9a12473280
6 changed files with 1251 additions and 475 deletions
|
@ -66,6 +66,7 @@ list(APPEND FREELDR_NTLDR_SOURCE
|
|||
|
||||
list(APPEND FREELDR_ARC_SOURCE
|
||||
arcname.c
|
||||
arch/drivers/hwide.c
|
||||
arch/arcemul.c
|
||||
arch/archwsup.c
|
||||
disk/disk.c
|
||||
|
|
822
boot/freeldr/freeldr/arch/drivers/hwide.c
Normal file
822
boot/freeldr/freeldr/arch/drivers/hwide.c
Normal file
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: ATA/ATAPI polled I/O driver.
|
||||
* COPYRIGHT: Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
#include <hwide.h>
|
||||
|
||||
/* DDK */
|
||||
#include <ata.h>
|
||||
#include <scsi.h>
|
||||
|
||||
#include <debug.h>
|
||||
DBG_DEFAULT_CHANNEL(DISK);
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define TAG_ATA_DEVICE 'DatA'
|
||||
#define ATAPI_PACKET_SIZE(IdentifyData) (IdentifyData.AtapiCmdSize ? 16 : 12)
|
||||
|
||||
/* Used in WaitForFlags() and should be 31 seconds (31e5), but it's too much for polled I/O */
|
||||
#define ATA_STATUS_TIMEOUT 36000
|
||||
#define ATA_READ_TIMEOUT 4e5
|
||||
|
||||
#define AtaWritePort(Channel, Port, Data) \
|
||||
WRITE_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)), (Data))
|
||||
|
||||
#define AtaReadPort(Channel, Port) \
|
||||
READ_PORT_UCHAR(UlongToPtr(BaseArray[(Channel)] + (Port)))
|
||||
|
||||
#define AtaWriteBuffer(Channel, Buffer, Count) \
|
||||
WRITE_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_o_Data), \
|
||||
(PUSHORT)(Buffer), (Count)/sizeof(USHORT))
|
||||
|
||||
#define AtaReadBuffer(Channel, Buffer, Count) \
|
||||
READ_PORT_BUFFER_USHORT(UlongToPtr(BaseArray[(Channel)] + IDX_IO1_i_Data), \
|
||||
(PUSHORT)(Buffer), (Count)/sizeof(USHORT))
|
||||
|
||||
/* IDE/ATA Channels base - Primary, Secondary, Tertiary, Quaternary */
|
||||
static const ULONG BaseArray[] =
|
||||
{
|
||||
#if defined(SARCH_XBOX)
|
||||
0x1F0
|
||||
#elif defined(SARCH_PC98)
|
||||
0x640, 0x640
|
||||
#else
|
||||
0x1F0, 0x170, 0x1E8, 0x168
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MAX_CHANNELS RTL_NUMBER_OF(BaseArray)
|
||||
#define MAX_DEVICES 2 /* Master/Slave */
|
||||
|
||||
static PDEVICE_UNIT Units[MAX_CHANNELS * MAX_DEVICES];
|
||||
|
||||
/* PRIVATE PROTOTYPES *********************************************************/
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
WaitForFlags(
|
||||
IN UCHAR Channel,
|
||||
IN UCHAR Flags,
|
||||
IN UCHAR ExpectedValue,
|
||||
IN ULONG Timeout
|
||||
);
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SelectDevice(
|
||||
IN UCHAR Channel,
|
||||
IN UCHAR DeviceNumber
|
||||
);
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
IdentifyDevice(
|
||||
IN UCHAR Channel,
|
||||
IN UCHAR DeviceNumber,
|
||||
OUT PDEVICE_UNIT *DeviceUnit
|
||||
);
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtapiReadyCheck(
|
||||
IN OUT PDEVICE_UNIT DeviceUnit
|
||||
);
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtapiReadLogicalSectorLBA(
|
||||
IN PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
OUT PVOID Buffer
|
||||
);
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtaReadLogicalSectorsLBA(
|
||||
IN PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer
|
||||
);
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
/* Don't call this before running the system timer calibration and MM initialization */
|
||||
BOOLEAN
|
||||
AtaInit(OUT PUCHAR DetectedCount)
|
||||
{
|
||||
UCHAR Channel, DeviceNumber;
|
||||
PDEVICE_UNIT DeviceUnit = NULL;
|
||||
|
||||
TRACE("AtaInit()\n");
|
||||
|
||||
*DetectedCount = 0;
|
||||
|
||||
RtlZeroMemory(&Units, sizeof(Units));
|
||||
|
||||
/* Detect and enumerate ATA/ATAPI devices */
|
||||
for (Channel = 0; Channel < MAX_CHANNELS; ++Channel)
|
||||
{
|
||||
for (DeviceNumber = 0; DeviceNumber < MAX_DEVICES; ++DeviceNumber)
|
||||
{
|
||||
if (IdentifyDevice(Channel, DeviceNumber, &DeviceUnit))
|
||||
{
|
||||
Units[(*DetectedCount)++] = DeviceUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (*DetectedCount > 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
AtaFree(VOID)
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(Units); ++i)
|
||||
{
|
||||
if (Units[i])
|
||||
FrLdrTempFree(Units[i], TAG_ATA_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
PDEVICE_UNIT
|
||||
AtaGetDevice(IN UCHAR UnitNumber)
|
||||
{
|
||||
if (UnitNumber < RTL_NUMBER_OF(Units))
|
||||
return Units[UnitNumber];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
AtaAtapiReadLogicalSectorsLBA(
|
||||
IN OUT PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
UCHAR RetryCount;
|
||||
BOOLEAN Success;
|
||||
|
||||
if (DeviceUnit == NULL || SectorCount == 0)
|
||||
return FALSE;
|
||||
|
||||
if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
if ((DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA) || (DeviceUnit->Flags & ATA_DEVICE_NOT_READY))
|
||||
{
|
||||
/* Retry 4 times */
|
||||
for (RetryCount = 0; RetryCount < 4; ++RetryCount)
|
||||
{
|
||||
/* Make the device ready */
|
||||
if (AtapiReadyCheck(DeviceUnit))
|
||||
break;
|
||||
}
|
||||
if (RetryCount >= 4)
|
||||
{
|
||||
ERR("AtaAtapiReadLogicalSectorsLBA(): Device not ready.\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (SectorNumber + SectorCount > DeviceUnit->TotalSectors + 1)
|
||||
{
|
||||
ERR("AtaAtapiReadLogicalSectorsLBA(): Attempt to read more than there is to read.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (SectorCount > 0)
|
||||
{
|
||||
/* Read a single sector */
|
||||
Success = AtapiReadLogicalSectorLBA(DeviceUnit, SectorNumber, Buffer);
|
||||
if (!Success)
|
||||
return FALSE;
|
||||
|
||||
--SectorCount;
|
||||
++SectorNumber;
|
||||
Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Retry 3 times */
|
||||
for (RetryCount = 0; RetryCount < 3; ++RetryCount)
|
||||
{
|
||||
/* Read a multiple sectors */
|
||||
Success = AtaReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
|
||||
if (Success)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtaReadLogicalSectorsLBA(
|
||||
IN PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
UCHAR Command;
|
||||
ULONG ChsTemp;
|
||||
USHORT Cylinder;
|
||||
UCHAR Head;
|
||||
UCHAR Sector;
|
||||
ULONG BlockCount;
|
||||
ULONG RemainingBlockCount;
|
||||
ULONGLONG Lba;
|
||||
BOOLEAN UseLBA48;
|
||||
|
||||
UseLBA48 = (DeviceUnit->Flags & ATA_DEVICE_LBA48) &&
|
||||
(((SectorNumber + SectorCount) >= UINT64_C(0x0FFFFF80)) || SectorCount > 256);
|
||||
|
||||
while (SectorCount > 0)
|
||||
{
|
||||
/* Prevent sector count overflow, divide it into maximum possible chunks and loop each one */
|
||||
if (UseLBA48)
|
||||
BlockCount = min(SectorCount, USHRT_MAX);
|
||||
else
|
||||
BlockCount = min(SectorCount, UCHAR_MAX);
|
||||
|
||||
/* Convert LBA into a format CHS if needed */
|
||||
if (DeviceUnit->Flags & ATA_DEVICE_CHS)
|
||||
{
|
||||
ChsTemp = DeviceUnit->IdentifyData.SectorsPerTrack * DeviceUnit->IdentifyData.NumberOfHeads;
|
||||
if (ChsTemp)
|
||||
{
|
||||
Cylinder = SectorNumber / ChsTemp;
|
||||
Head = (SectorNumber % ChsTemp) / DeviceUnit->IdentifyData.SectorsPerTrack;
|
||||
Sector = (SectorNumber % DeviceUnit->IdentifyData.SectorsPerTrack) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cylinder = 0;
|
||||
Head = 0;
|
||||
Sector = 1;
|
||||
}
|
||||
Lba = (Sector & 0xFF) | ((Cylinder & 0xFFFFF) << 8) | ((Head & 0x0F) << 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
Lba = SectorNumber;
|
||||
}
|
||||
|
||||
/* Select the drive */
|
||||
if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
|
||||
return FALSE;
|
||||
|
||||
/* Disable interrupts */
|
||||
#ifndef SARCH_PC98
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_AltStatus, IDE_DC_DISABLE_INTERRUPTS);
|
||||
StallExecutionProcessor(1);
|
||||
#endif
|
||||
|
||||
if (UseLBA48)
|
||||
{
|
||||
/* FIFO */
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, 0);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, (BlockCount & 0xFF) >> 8);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, (Lba >> 24) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 32) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 40) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 16) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
|
||||
IDE_USE_LBA | (DeviceUnit->DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1));
|
||||
Command = IDE_COMMAND_READ_EXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Feature, ATA_PIO);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockCount, BlockCount & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_BlockNumber, Lba & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderLow, (Lba >> 8) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_CylinderHigh, (Lba >> 16) & 0xFF);
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_DriveSelect,
|
||||
((Lba >> 24) & 0x0F) |
|
||||
(DeviceUnit->Flags & ATA_DEVICE_CHS ? 0x00 : IDE_USE_LBA) |
|
||||
(DeviceUnit->DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1));
|
||||
Command = IDE_COMMAND_READ;
|
||||
}
|
||||
|
||||
/* Send read command */
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO1_o_Command, Command);
|
||||
StallExecutionProcessor(5);
|
||||
|
||||
for (RemainingBlockCount = BlockCount; RemainingBlockCount > 0; --RemainingBlockCount)
|
||||
{
|
||||
/* Wait for ready to transfer data block */
|
||||
if (!WaitForFlags(DeviceUnit->Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | IDE_STATUS_ERROR),
|
||||
IDE_STATUS_DRQ, ATA_READ_TIMEOUT))
|
||||
{
|
||||
ERR("AtaReadLogicalSectorsLBA() failed. Status: 0x%02x, Error: 0x%02x\n",
|
||||
AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Status),
|
||||
AtaReadPort(DeviceUnit->Channel, IDX_IO1_i_Error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Transfer the data block */
|
||||
AtaReadBuffer(DeviceUnit->Channel, Buffer, DeviceUnit->SectorSize);
|
||||
|
||||
Buffer = (PVOID)((ULONG_PTR)Buffer + DeviceUnit->SectorSize);
|
||||
}
|
||||
|
||||
SectorNumber += BlockCount;
|
||||
SectorCount -= BlockCount;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtaSendAtapiPacket(
|
||||
IN UCHAR Channel,
|
||||
IN PUCHAR AtapiPacket,
|
||||
IN UCHAR PacketSize,
|
||||
IN USHORT ByteCount)
|
||||
{
|
||||
/* No DRQ for TEST UNIT READY */
|
||||
BOOLEAN NoData = (AtapiPacket[0] == SCSIOP_TEST_UNIT_READY);
|
||||
UCHAR ExpectedFlags = NoData ? IDE_STATUS_DRDY : (IDE_STATUS_DRQ | IDE_STATUS_DRDY);
|
||||
|
||||
/* PIO mode */
|
||||
AtaWritePort(Channel, IDX_ATAPI_IO1_o_Feature, ATA_PIO);
|
||||
|
||||
/* Maximum byte count that is to be transferred */
|
||||
AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountLow, ByteCount & 0xFF);
|
||||
AtaWritePort(Channel, IDX_ATAPI_IO1_o_ByteCountHigh, (ByteCount >> 8) & 0xFF);
|
||||
|
||||
/* Prepare to transfer a device command via a command packet */
|
||||
AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_PACKET);
|
||||
StallExecutionProcessor(50);
|
||||
if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | IDE_STATUS_ERROR),
|
||||
IDE_STATUS_DRQ, NoData ? ATA_STATUS_TIMEOUT : ATA_READ_TIMEOUT))
|
||||
{
|
||||
ERR("AtaSendAtapiPacket(0x%x) failed. A device error occurred Status: 0x%02x, Error: 0x%02x\n",
|
||||
AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Command packet transfer */
|
||||
AtaWriteBuffer(Channel, AtapiPacket, PacketSize);
|
||||
if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | IDE_STATUS_DRDY | IDE_STATUS_ERROR),
|
||||
ExpectedFlags, NoData ? ATA_STATUS_TIMEOUT : ATA_READ_TIMEOUT))
|
||||
{
|
||||
TRACE("AtaSendAtapiPacket(0x%x) failed. An execution error occurred Status: 0x%02x, Error: 0x%02x\n",
|
||||
AtapiPacket[0], AtaReadPort(Channel, IDX_ATAPI_IO1_i_Status), AtaReadPort(Channel, IDX_ATAPI_IO1_i_Error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtapiReadLogicalSectorLBA(
|
||||
IN PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
OUT PVOID Buffer)
|
||||
{
|
||||
UCHAR AtapiPacket[16];
|
||||
USHORT DataSize;
|
||||
BOOLEAN Success;
|
||||
|
||||
/* Select the drive */
|
||||
if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
|
||||
return FALSE;
|
||||
|
||||
/* Disable interrupts */
|
||||
AtaWritePort(DeviceUnit->Channel, IDX_IO2_o_AltStatus, IDE_DC_DISABLE_INTERRUPTS);
|
||||
StallExecutionProcessor(1);
|
||||
|
||||
/* Send the SCSI READ command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
#if defined(SARCH_PC98)
|
||||
AtapiPacket[0] = SCSIOP_READ;
|
||||
AtapiPacket[8] = 1;
|
||||
AtapiPacket[9] = 0;
|
||||
#else
|
||||
AtapiPacket[0] = SCSIOP_READ12;
|
||||
AtapiPacket[8] = 0;
|
||||
AtapiPacket[9] = 1;
|
||||
#endif
|
||||
AtapiPacket[2] = (SectorNumber >> 24) & 0xFF;
|
||||
AtapiPacket[3] = (SectorNumber >> 16) & 0xFF;
|
||||
AtapiPacket[4] = (SectorNumber >> 8) & 0xFF;
|
||||
AtapiPacket[5] = SectorNumber & 0xFF;
|
||||
Success = AtaSendAtapiPacket(DeviceUnit->Channel,
|
||||
AtapiPacket,
|
||||
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
|
||||
DeviceUnit->SectorSize);
|
||||
if (!Success)
|
||||
{
|
||||
ERR("AtapiReadLogicalSectorLBA() failed. A read error occurred.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DataSize = (AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountHigh) << 8) |
|
||||
AtaReadPort(DeviceUnit->Channel, IDX_ATAPI_IO1_i_ByteCountLow);
|
||||
|
||||
/* Transfer the data block */
|
||||
AtaReadBuffer(DeviceUnit->Channel, Buffer, DataSize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtapiCapacityDetect(
|
||||
IN PDEVICE_UNIT DeviceUnit,
|
||||
OUT PULONGLONG TotalSectors,
|
||||
OUT PULONG SectorSize)
|
||||
{
|
||||
UCHAR AtapiPacket[16];
|
||||
UCHAR AtapiCapacity[8];
|
||||
|
||||
/* Send the SCSI READ CAPACITY(10) command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
AtapiPacket[0] = SCSIOP_READ_CAPACITY;
|
||||
if (AtaSendAtapiPacket(DeviceUnit->Channel, AtapiPacket, ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData), 8))
|
||||
{
|
||||
AtaReadBuffer(DeviceUnit->Channel, &AtapiCapacity, 8);
|
||||
|
||||
*TotalSectors = (AtapiCapacity[0] << 24) | (AtapiCapacity[1] << 16) |
|
||||
(AtapiCapacity[2] << 8) | AtapiCapacity[3];
|
||||
|
||||
*SectorSize = (AtapiCapacity[4] << 24) | (AtapiCapacity[5] << 16) |
|
||||
(AtapiCapacity[6] << 8) | AtapiCapacity[7];
|
||||
}
|
||||
else
|
||||
{
|
||||
*TotalSectors = 0;
|
||||
*SectorSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
AtapiReadyCheck(IN OUT PDEVICE_UNIT DeviceUnit)
|
||||
{
|
||||
UCHAR AtapiPacket[16];
|
||||
UCHAR DummyData[MAXIMUM_CDROM_SIZE];
|
||||
SENSE_DATA SenseData;
|
||||
BOOLEAN Success;
|
||||
|
||||
/* Select the drive */
|
||||
if (!SelectDevice(DeviceUnit->Channel, DeviceUnit->DeviceNumber))
|
||||
return FALSE;
|
||||
|
||||
/* Send the SCSI TEST UNIT READY command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
AtapiPacket[0] = SCSIOP_TEST_UNIT_READY;
|
||||
AtaSendAtapiPacket(DeviceUnit->Channel,
|
||||
AtapiPacket,
|
||||
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
|
||||
0);
|
||||
|
||||
/* Send the SCSI REQUEST SENSE command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
RtlZeroMemory(&SenseData, SENSE_BUFFER_SIZE);
|
||||
AtapiPacket[0] = SCSIOP_REQUEST_SENSE;
|
||||
AtapiPacket[4] = SENSE_BUFFER_SIZE;
|
||||
Success = AtaSendAtapiPacket(DeviceUnit->Channel,
|
||||
AtapiPacket,
|
||||
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
|
||||
SENSE_BUFFER_SIZE);
|
||||
if (!Success)
|
||||
return FALSE;
|
||||
|
||||
AtaReadBuffer(DeviceUnit->Channel, &SenseData, SENSE_BUFFER_SIZE);
|
||||
TRACE("SK 0x%x, ASC 0x%x, ASCQ 0x%x\n",
|
||||
SenseData.SenseKey,
|
||||
SenseData.AdditionalSenseCode,
|
||||
SenseData.AdditionalSenseCodeQualifier);
|
||||
|
||||
if (SenseData.SenseKey == SCSI_SENSE_NOT_READY)
|
||||
{
|
||||
if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)
|
||||
{
|
||||
switch (SenseData.AdditionalSenseCodeQualifier)
|
||||
{
|
||||
case SCSI_SENSEQ_BECOMING_READY:
|
||||
/* Wait until the CD is spun up */
|
||||
StallExecutionProcessor(4e6);
|
||||
return FALSE;
|
||||
|
||||
case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
|
||||
/* The drive needs to be spun up, send the SCSI READ TOC command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
AtapiPacket[0] = SCSIOP_READ_TOC;
|
||||
AtapiPacket[7] = (MAXIMUM_CDROM_SIZE << 8) & 0xFF;
|
||||
AtapiPacket[8] = MAXIMUM_CDROM_SIZE & 0xFF;
|
||||
AtapiPacket[9] = READ_TOC_FORMAT_SESSION << 6;
|
||||
Success = AtaSendAtapiPacket(DeviceUnit->Channel,
|
||||
AtapiPacket,
|
||||
ATAPI_PACKET_SIZE(DeviceUnit->IdentifyData),
|
||||
MAXIMUM_CDROM_SIZE);
|
||||
if (!Success)
|
||||
return FALSE;
|
||||
|
||||
AtaReadBuffer(DeviceUnit->Channel, &DummyData, MAXIMUM_CDROM_SIZE);
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
}
|
||||
else if (SenseData.AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
|
||||
{
|
||||
DeviceUnit->Flags |= ATA_DEVICE_NO_MEDIA;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceUnit->Flags &= ~ATA_DEVICE_NOT_READY;
|
||||
}
|
||||
|
||||
if (DeviceUnit->Flags & ATA_DEVICE_NO_MEDIA)
|
||||
{
|
||||
/* Detect a medium's capacity */
|
||||
AtapiCapacityDetect(DeviceUnit, &DeviceUnit->TotalSectors, &DeviceUnit->SectorSize);
|
||||
|
||||
/* If nothing was returned, reset to defaults */
|
||||
if (DeviceUnit->SectorSize == 0)
|
||||
DeviceUnit->SectorSize = 2048;
|
||||
if (DeviceUnit->TotalSectors == 0)
|
||||
DeviceUnit->TotalSectors = 0xFFFFFFFF;
|
||||
|
||||
DeviceUnit->Flags &= ~ATA_DEVICE_NO_MEDIA;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
WaitForFlags(
|
||||
IN UCHAR Channel,
|
||||
IN UCHAR Flags,
|
||||
IN UCHAR ExpectedValue,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ASSERT(Timeout != 0);
|
||||
|
||||
while (Timeout--)
|
||||
{
|
||||
if ((AtaReadPort(Channel, IDX_IO1_i_Status) & Flags) == ExpectedValue)
|
||||
return TRUE;
|
||||
else
|
||||
StallExecutionProcessor(10);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
AtaHardReset(IN UCHAR Channel)
|
||||
{
|
||||
TRACE("AtaHardReset(Controller %d)\n", Channel);
|
||||
|
||||
AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER);
|
||||
StallExecutionProcessor(200000);
|
||||
AtaWritePort(Channel, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
|
||||
StallExecutionProcessor(1);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
SelectDevice(IN UCHAR Channel, IN UCHAR DeviceNumber)
|
||||
{
|
||||
#if defined(SARCH_PC98)
|
||||
/* Select IDE Channel */
|
||||
WRITE_PORT_UCHAR((PUCHAR)IDE_IO_o_BankSelect, Channel);
|
||||
StallExecutionProcessor(1);
|
||||
#endif
|
||||
|
||||
AtaWritePort(Channel, IDX_IO1_o_DriveSelect,
|
||||
DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1);
|
||||
StallExecutionProcessor(500);
|
||||
if (!WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ), 0, ATA_STATUS_TIMEOUT))
|
||||
{
|
||||
TRACE("SelectDevice() failed. Device(%d:%d) is busy.\n", Channel, DeviceNumber);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
IdentifyDevice(
|
||||
IN UCHAR Channel,
|
||||
IN UCHAR DeviceNumber,
|
||||
OUT PDEVICE_UNIT *DeviceUnit)
|
||||
{
|
||||
UCHAR SignatureLow, SignatureHigh;
|
||||
IDENTIFY_DATA Id;
|
||||
INQUIRYDATA AtapiInquiry;
|
||||
BOOLEAN Success;
|
||||
UCHAR AtapiPacket[16];
|
||||
ULONG i;
|
||||
ULONG SectorSize;
|
||||
ULONGLONG TotalSectors;
|
||||
USHORT Flags = 0;
|
||||
|
||||
TRACE("IdentifyDevice() Channel = %x, Device = %x, BaseIoAddress = 0x%x\n",
|
||||
Channel, DeviceNumber, BaseArray[Channel]);
|
||||
|
||||
/* Reset the controller */
|
||||
AtaHardReset(Channel);
|
||||
|
||||
/* Select the drive */
|
||||
if (!SelectDevice(Channel, DeviceNumber))
|
||||
goto Failure;
|
||||
|
||||
/* Send the IDENTIFY DEVICE command */
|
||||
AtaWritePort(Channel, IDX_IO1_o_Command, IDE_COMMAND_IDENTIFY);
|
||||
StallExecutionProcessor(50);
|
||||
if (WaitForFlags(Channel, (IDE_STATUS_BUSY | IDE_STATUS_DRQ | IDE_STATUS_ERROR),
|
||||
IDE_STATUS_DRQ, ATA_STATUS_TIMEOUT))
|
||||
{
|
||||
SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
|
||||
SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
|
||||
TRACE("IdentifyDevice(): SignatureLow = 0x%x, SignatureHigh = 0x%x\n", SignatureLow, SignatureHigh);
|
||||
if (SignatureLow == 0x00 && SignatureHigh == 0x00)
|
||||
{
|
||||
/* This is PATA */
|
||||
TRACE("IdentifyDevice(): Found PATA device at %d:%d\n", Channel, DeviceNumber);
|
||||
goto Identify;
|
||||
}
|
||||
}
|
||||
|
||||
/* If not PATA, ATAPI maybe? Send the IDENTIFY PACKET DEVICE command */
|
||||
AtaWritePort(Channel, IDX_ATAPI_IO1_o_Command, IDE_COMMAND_ATAPI_IDENTIFY);
|
||||
StallExecutionProcessor(500);
|
||||
SignatureLow = AtaReadPort(Channel, IDX_IO1_i_CylinderLow);
|
||||
SignatureHigh = AtaReadPort(Channel, IDX_IO1_i_CylinderHigh);
|
||||
TRACE("IdentifyDevice(): SignatureLow = 0x%x, SignatureHigh = 0x%x\n", SignatureLow, SignatureHigh);
|
||||
/* Check for devices that implements the PACKET Command feature */
|
||||
if (SignatureLow == ATAPI_MAGIC_LSB && SignatureHigh == ATAPI_MAGIC_MSB)
|
||||
{
|
||||
/* This is ATAPI */
|
||||
Flags |= ATA_DEVICE_ATAPI | ATA_DEVICE_LBA | ATA_DEVICE_NOT_READY;
|
||||
TRACE("IdentifyDevice(): Found ATAPI device at %d:%d\n", Channel, DeviceNumber);
|
||||
goto Identify;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto Failure;
|
||||
}
|
||||
|
||||
Identify:
|
||||
/* Receive parameter information from the device */
|
||||
AtaReadBuffer(Channel, &Id, IDENTIFY_DATA_SIZE);
|
||||
|
||||
/* Swap byte order of the ASCII data */
|
||||
for (i = 0; i < RTL_NUMBER_OF(Id.SerialNumber); ++i)
|
||||
Id.SerialNumber[i] = RtlUshortByteSwap(Id.SerialNumber[i]);
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(Id.FirmwareRevision); ++i)
|
||||
Id.FirmwareRevision[i] = RtlUshortByteSwap(Id.FirmwareRevision[i]);
|
||||
|
||||
for (i = 0; i < RTL_NUMBER_OF(Id.ModelNumber); ++i)
|
||||
Id.ModelNumber[i] = RtlUshortByteSwap(Id.ModelNumber[i]);
|
||||
|
||||
TRACE("S/N %.*s\n", sizeof(Id.SerialNumber), Id.SerialNumber);
|
||||
TRACE("FR %.*s\n", sizeof(Id.FirmwareRevision), Id.FirmwareRevision);
|
||||
TRACE("MN %.*s\n", sizeof(Id.ModelNumber), Id.ModelNumber);
|
||||
|
||||
/* Detect the type of device */
|
||||
if (Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
/* Send the SCSI INQUIRY command */
|
||||
RtlZeroMemory(&AtapiPacket, sizeof(AtapiPacket));
|
||||
AtapiPacket[0] = SCSIOP_INQUIRY;
|
||||
AtapiPacket[4] = INQUIRYDATABUFFERSIZE;
|
||||
Success = AtaSendAtapiPacket(Channel, AtapiPacket, ATAPI_PACKET_SIZE(Id), INQUIRYDATABUFFERSIZE);
|
||||
if (!Success)
|
||||
goto Failure;
|
||||
|
||||
AtaReadBuffer(Channel, &AtapiInquiry, INQUIRYDATABUFFERSIZE);
|
||||
if (AtapiInquiry.DeviceType != READ_ONLY_DIRECT_ACCESS_DEVICE)
|
||||
{
|
||||
TRACE("IdentifyDevice(): Unsupported device type 0x%x!\n", AtapiInquiry.DeviceType);
|
||||
goto Failure;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a new device unit structure */
|
||||
*DeviceUnit = FrLdrTempAlloc(sizeof(DEVICE_UNIT), TAG_ATA_DEVICE);
|
||||
if (*DeviceUnit == NULL)
|
||||
{
|
||||
ERR("Failed to allocate device unit!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RtlZeroMemory(*DeviceUnit, sizeof(DEVICE_UNIT));
|
||||
(*DeviceUnit)->Channel = Channel;
|
||||
(*DeviceUnit)->DeviceNumber = DeviceNumber;
|
||||
(*DeviceUnit)->IdentifyData = Id;
|
||||
|
||||
/* Detect a medium's capacity */
|
||||
if (Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
AtapiCapacityDetect(*DeviceUnit, &TotalSectors, &SectorSize);
|
||||
if (SectorSize == 0 || TotalSectors == 0)
|
||||
{
|
||||
/* It's ok and can be used to show alert like "Please insert the CD" */
|
||||
TRACE("No media found.\n");
|
||||
Flags |= ATA_DEVICE_NO_MEDIA;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Id.SupportLba || (Id.MajorRevision && Id.UserAddressableSectors))
|
||||
{
|
||||
if (Id.FeaturesSupport.Address48)
|
||||
{
|
||||
TRACE("Using LBA48 addressing mode.\n");
|
||||
Flags |= ATA_DEVICE_LBA48 | ATA_DEVICE_LBA;
|
||||
TotalSectors = Id.UserAddressableSectors48;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Using LBA28 addressing mode.\n");
|
||||
Flags |= ATA_DEVICE_LBA;
|
||||
TotalSectors = Id.UserAddressableSectors;
|
||||
}
|
||||
|
||||
/* LBA ATA drives always have a sector size of 512 */
|
||||
SectorSize = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Using CHS addressing mode.\n");
|
||||
Flags |= ATA_DEVICE_CHS;
|
||||
|
||||
if (Id.UnformattedBytesPerSector == 0)
|
||||
{
|
||||
SectorSize = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1 << 15; i > 0; i >>= 1)
|
||||
{
|
||||
if ((Id.UnformattedBytesPerSector & i) != 0)
|
||||
{
|
||||
SectorSize = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
TotalSectors = Id.NumberOfCylinders * Id.NumberOfHeads * Id.SectorsPerTrack;
|
||||
}
|
||||
}
|
||||
TRACE("Sector size %d ; Total sectors %I64d\n", SectorSize, TotalSectors);
|
||||
|
||||
(*DeviceUnit)->Flags = Flags;
|
||||
(*DeviceUnit)->SectorSize = SectorSize;
|
||||
(*DeviceUnit)->TotalSectors = TotalSectors;
|
||||
if (Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
(*DeviceUnit)->Cylinders = 0xFFFFFFFF;
|
||||
(*DeviceUnit)->Heads = 0xFFFFFFFF;
|
||||
(*DeviceUnit)->Sectors = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*DeviceUnit)->Cylinders = Id.NumberOfCylinders;
|
||||
(*DeviceUnit)->Heads = Id.NumberOfHeads;
|
||||
(*DeviceUnit)->Sectors = Id.SectorsPerTrack;
|
||||
}
|
||||
|
||||
#if DBG
|
||||
DbgDumpBuffer(DPRINT_DISK, &Id, IDENTIFY_DATA_SIZE);
|
||||
#endif
|
||||
|
||||
TRACE("IdentifyDevice() done.\n");
|
||||
return TRUE;
|
||||
|
||||
Failure:
|
||||
TRACE("IdentifyDevice() done. No device present at %d:%d\n", Channel, DeviceNumber);
|
||||
return FALSE;
|
||||
}
|
|
@ -299,8 +299,9 @@ XboxMachInit(const char *CmdLine)
|
|||
VOID
|
||||
XboxPrepareForReactOS(VOID)
|
||||
{
|
||||
/* On XBOX, prepare video and turn off the floppy motor */
|
||||
/* On Xbox, prepare video and disk support */
|
||||
XboxVideoPrepareForReactOS();
|
||||
XboxDiskInit(FALSE);
|
||||
DiskStopFloppyMotor();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,513 +1,120 @@
|
|||
/*
|
||||
* FreeLoader
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Note: mostly ripped from atapi.c
|
||||
* Some of this code was based on knowledge and/or code developed
|
||||
* by the Xbox Linux group: http://www.xbox-linux.org
|
||||
*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Xbox specific disk access routines
|
||||
* COPYRIGHT: Copyright 2004 Gé van Geldorp (gvg@reactos.com)
|
||||
* Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <freeldr.h>
|
||||
#include <hwide.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
DBG_DEFAULT_CHANNEL(DISK);
|
||||
|
||||
#define XBOX_IDE_COMMAND_PORT 0x1f0
|
||||
#define XBOX_IDE_CONTROL_PORT 0x170
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define IDE_SECTOR_BUF_SZ 512
|
||||
#define IDE_MAX_POLL_RETRIES 100000
|
||||
#define IDE_MAX_BUSY_RETRIES 50000
|
||||
static PDEVICE_UNIT HardDrive = NULL;
|
||||
static PDEVICE_UNIT CdDrive = NULL;
|
||||
static BOOLEAN AtaInitialized = FALSE;
|
||||
|
||||
/* Control Block offsets and masks */
|
||||
#define IDE_REG_ALT_STATUS 0x0000
|
||||
#define IDE_REG_DEV_CNTRL 0x0000 /* device control register */
|
||||
#define IDE_DC_SRST 0x04 /* drive reset (both drives) */
|
||||
#define IDE_DC_nIEN 0x02 /* IRQ enable (active low) */
|
||||
#define IDE_REG_DRV_ADDR 0x0001
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
/* Command Block offsets and masks */
|
||||
#define IDE_REG_DATA_PORT 0x0000
|
||||
#define IDE_REG_ERROR 0x0001 /* error register */
|
||||
#define IDE_ER_AMNF 0x01 /* addr mark not found */
|
||||
#define IDE_ER_TK0NF 0x02 /* track 0 not found */
|
||||
#define IDE_ER_ABRT 0x04 /* command aborted */
|
||||
#define IDE_ER_MCR 0x08 /* media change requested */
|
||||
#define IDE_ER_IDNF 0x10 /* ID not found */
|
||||
#define IDE_ER_MC 0x20 /* Media changed */
|
||||
#define IDE_ER_UNC 0x40 /* Uncorrectable data error */
|
||||
#define IDE_REG_PRECOMP 0x0001
|
||||
#define IDE_REG_SECTOR_CNT 0x0002
|
||||
#define IDE_REG_SECTOR_NUM 0x0003
|
||||
#define IDE_REG_CYL_LOW 0x0004
|
||||
#define IDE_REG_CYL_HIGH 0x0005
|
||||
#define IDE_REG_DRV_HEAD 0x0006
|
||||
#define IDE_DH_FIXED 0xA0
|
||||
#define IDE_DH_LBA 0x40
|
||||
#define IDE_DH_HDMASK 0x0F
|
||||
#define IDE_DH_DRV0 0x00
|
||||
#define IDE_DH_DRV1 0x10
|
||||
#define IDE_REG_STATUS 0x0007
|
||||
#define IDE_SR_BUSY 0x80
|
||||
#define IDE_SR_DRDY 0x40
|
||||
#define IDE_SR_WERR 0x20
|
||||
#define IDE_SR_DRQ 0x08
|
||||
#define IDE_SR_ERR 0x01
|
||||
#define IDE_REG_COMMAND 0x0007
|
||||
|
||||
/* IDE/ATA commands */
|
||||
#define IDE_CMD_RESET 0x08
|
||||
#define IDE_CMD_READ 0x20
|
||||
#define IDE_CMD_READ_RETRY 0x21
|
||||
#define IDE_CMD_WRITE 0x30
|
||||
#define IDE_CMD_WRITE_RETRY 0x31
|
||||
#define IDE_CMD_PACKET 0xA0
|
||||
#define IDE_CMD_READ_MULTIPLE 0xC4
|
||||
#define IDE_CMD_WRITE_MULTIPLE 0xC5
|
||||
#define IDE_CMD_READ_DMA 0xC8
|
||||
#define IDE_CMD_WRITE_DMA 0xCA
|
||||
#define IDE_CMD_FLUSH_CACHE 0xE7
|
||||
#define IDE_CMD_FLUSH_CACHE_EXT 0xEA
|
||||
#define IDE_CMD_IDENT_ATA_DRV 0xEC
|
||||
#define IDE_CMD_IDENT_ATAPI_DRV 0xA1
|
||||
#define IDE_CMD_GET_MEDIA_STATUS 0xDA
|
||||
|
||||
/*
|
||||
* Access macros for command registers
|
||||
* Each macro takes an address of the command port block, and data
|
||||
*/
|
||||
#define IDEReadError(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ERROR)))
|
||||
#define IDEWritePrecomp(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_PRECOMP), (Data)))
|
||||
#define IDEReadSectorCount(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT)))
|
||||
#define IDEWriteSectorCount(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT), (Data)))
|
||||
#define IDEReadSectorNum(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM)))
|
||||
#define IDEWriteSectorNum(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM), (Data)))
|
||||
#define IDEReadCylinderLow(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW)))
|
||||
#define IDEWriteCylinderLow(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW), (Data)))
|
||||
#define IDEReadCylinderHigh(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH)))
|
||||
#define IDEWriteCylinderHigh(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH), (Data)))
|
||||
#define IDEReadDriveHead(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD)))
|
||||
#define IDEWriteDriveHead(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD), (Data)))
|
||||
#define IDEReadStatus(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_STATUS)))
|
||||
#define IDEWriteCommand(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_COMMAND), (Data)))
|
||||
#define IDEReadDMACommand(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address))))
|
||||
#define IDEWriteDMACommand(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address)), (Data)))
|
||||
#define IDEReadDMAStatus(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + 2)))
|
||||
#define IDEWriteDMAStatus(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + 2), (Data)))
|
||||
#define IDEWritePRDTable(Address, Data) \
|
||||
(WRITE_PORT_ULONG((PULONG)((Address) + 4), (Data)))
|
||||
|
||||
/*
|
||||
* Data block read and write commands
|
||||
*/
|
||||
#define IDEReadBlock(Address, Buffer, Count) \
|
||||
(READ_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
|
||||
#define IDEWriteBlock(Address, Buffer, Count) \
|
||||
(WRITE_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
|
||||
|
||||
#define IDEReadBlock32(Address, Buffer, Count) \
|
||||
(READ_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
|
||||
#define IDEWriteBlock32(Address, Buffer, Count) \
|
||||
(WRITE_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
|
||||
|
||||
#define IDEReadWord(Address) \
|
||||
(READ_PORT_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT)))
|
||||
|
||||
/*
|
||||
* Access macros for control registers
|
||||
* Each macro takes an address of the control port blank and data
|
||||
*/
|
||||
#define IDEReadAltStatus(Address) \
|
||||
(READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ALT_STATUS)))
|
||||
#define IDEWriteDriveControl(Address, Data) \
|
||||
(WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DEV_CNTRL), (Data)))
|
||||
|
||||
/* IDE_DRIVE_IDENTIFY */
|
||||
typedef struct _IDE_DRIVE_IDENTIFY
|
||||
VOID
|
||||
XboxDiskInit(BOOLEAN Init)
|
||||
{
|
||||
USHORT ConfigBits; /*00*/
|
||||
USHORT LogicalCyls; /*01*/
|
||||
USHORT Reserved02; /*02*/
|
||||
USHORT LogicalHeads; /*03*/
|
||||
USHORT BytesPerTrack; /*04*/
|
||||
USHORT BytesPerSector; /*05*/
|
||||
USHORT SectorsPerTrack; /*06*/
|
||||
UCHAR InterSectorGap; /*07*/
|
||||
UCHAR InterSectorGapSize;
|
||||
UCHAR Reserved08H; /*08*/
|
||||
UCHAR BytesInPLO;
|
||||
USHORT VendorUniqueCnt; /*09*/
|
||||
UCHAR SerialNumber[20]; /*10*/
|
||||
USHORT ControllerType; /*20*/
|
||||
USHORT BufferSize; /*21*/
|
||||
USHORT ECCByteCnt; /*22*/
|
||||
UCHAR FirmwareRev[8]; /*23*/
|
||||
UCHAR ModelNumber[40]; /*27*/
|
||||
USHORT RWMultImplemented; /*47*/
|
||||
USHORT DWordIo; /*48*/
|
||||
USHORT Capabilities; /*49*/
|
||||
#define IDE_DRID_STBY_SUPPORTED 0x2000
|
||||
#define IDE_DRID_IORDY_SUPPORTED 0x0800
|
||||
#define IDE_DRID_IORDY_DISABLE 0x0400
|
||||
#define IDE_DRID_LBA_SUPPORTED 0x0200
|
||||
#define IDE_DRID_DMA_SUPPORTED 0x0100
|
||||
USHORT Reserved50; /*50*/
|
||||
USHORT MinPIOTransTime; /*51*/
|
||||
USHORT MinDMATransTime; /*52*/
|
||||
USHORT TMFieldsValid; /*53*/
|
||||
USHORT TMCylinders; /*54*/
|
||||
USHORT TMHeads; /*55*/
|
||||
USHORT TMSectorsPerTrk; /*56*/
|
||||
USHORT TMCapacityLo; /*57*/
|
||||
USHORT TMCapacityHi; /*58*/
|
||||
USHORT RWMultCurrent; /*59*/
|
||||
USHORT TMSectorCountLo; /*60*/
|
||||
USHORT TMSectorCountHi; /*61*/
|
||||
USHORT DmaModes; /*62*/
|
||||
USHORT MultiDmaModes; /*63*/
|
||||
USHORT Reserved64[5]; /*64*/
|
||||
USHORT Reserved69[2]; /*69*/
|
||||
USHORT Reserved71[4]; /*71*/
|
||||
USHORT MaxQueueDepth; /*75*/
|
||||
USHORT Reserved76[4]; /*76*/
|
||||
USHORT MajorRevision; /*80*/
|
||||
USHORT MinorRevision; /*81*/
|
||||
USHORT SupportedFeatures82; /*82*/
|
||||
USHORT SupportedFeatures83; /*83*/
|
||||
USHORT SupportedFeatures84; /*84*/
|
||||
USHORT EnabledFeatures85; /*85*/
|
||||
USHORT EnabledFeatures86; /*86*/
|
||||
USHORT EnabledFeatures87; /*87*/
|
||||
USHORT UltraDmaModes; /*88*/
|
||||
USHORT Reserved89[11]; /*89*/
|
||||
USHORT Max48BitAddress[4]; /*100*/
|
||||
USHORT Reserved104[151]; /*104*/
|
||||
USHORT Checksum; /*255*/
|
||||
} IDE_DRIVE_IDENTIFY, *PIDE_DRIVE_IDENTIFY;
|
||||
UCHAR DetectedCount;
|
||||
UCHAR UnitNumber;
|
||||
PDEVICE_UNIT DeviceUnit = NULL;
|
||||
|
||||
/* XboxDiskPolledRead
|
||||
*
|
||||
* DESCRIPTION:
|
||||
* Read a sector of data from the drive in a polled fashion.
|
||||
*
|
||||
* RUN LEVEL:
|
||||
* PASSIVE_LEVEL
|
||||
*
|
||||
* ARGUMENTS:
|
||||
* ULONG CommandPort Address of command port for drive
|
||||
* ULONG ControlPort Address of control port for drive
|
||||
* UCHAR PreComp Value to write to precomp register
|
||||
* UCHAR SectorCnt Value to write to sectorCnt register
|
||||
* UCHAR SectorNum Value to write to sectorNum register
|
||||
* UCHAR CylinderLow Value to write to CylinderLow register
|
||||
* UCHAR CylinderHigh Value to write to CylinderHigh register
|
||||
* UCHAR DrvHead Value to write to Drive/Head register
|
||||
* UCHAR Command Value to write to Command register
|
||||
* PVOID Buffer Buffer for output data
|
||||
*
|
||||
* RETURNS:
|
||||
* BOOLEAN: TRUE success, FALSE error
|
||||
*/
|
||||
static BOOLEAN
|
||||
XboxDiskPolledRead(ULONG CommandPort,
|
||||
ULONG ControlPort,
|
||||
UCHAR PreComp,
|
||||
UCHAR SectorCnt,
|
||||
UCHAR SectorNum,
|
||||
UCHAR CylinderLow,
|
||||
UCHAR CylinderHigh,
|
||||
UCHAR DrvHead,
|
||||
UCHAR Command,
|
||||
PVOID Buffer)
|
||||
{
|
||||
ULONG SectorCount = 0;
|
||||
ULONG RetryCount;
|
||||
BOOLEAN Junk = FALSE;
|
||||
UCHAR Status;
|
||||
|
||||
/* Wait for BUSY to clear */
|
||||
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
|
||||
if (Init & !AtaInitialized)
|
||||
{
|
||||
Status = IDEReadStatus(CommandPort);
|
||||
if (!(Status & IDE_SR_BUSY))
|
||||
break;
|
||||
|
||||
StallExecutionProcessor(10);
|
||||
}
|
||||
TRACE("status=0x%x\n", Status);
|
||||
TRACE("waited %d usecs for busy to clear\n", RetryCount * 10);
|
||||
if (RetryCount >= IDE_MAX_BUSY_RETRIES)
|
||||
{
|
||||
WARN("Drive is BUSY for too long\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Write Drive/Head to select drive */
|
||||
IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
|
||||
StallExecutionProcessor(500);
|
||||
|
||||
/* Disable interrupts */
|
||||
IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
|
||||
StallExecutionProcessor(500);
|
||||
|
||||
/* Issue command to drive */
|
||||
if (DrvHead & IDE_DH_LBA)
|
||||
{
|
||||
TRACE("READ:DRV=%d:LBA=1:BLK=%d:SC=0x%x:CM=0x%x\n",
|
||||
DrvHead & IDE_DH_DRV1 ? 1 : 0,
|
||||
((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
|
||||
SectorCnt,
|
||||
Command);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("READ:DRV=%d:LBA=0:CH=0x%x:CL=0x%x:HD=0x%x:SN=0x%x:SC=0x%x:CM=0x%x\n",
|
||||
DrvHead & IDE_DH_DRV1 ? 1 : 0,
|
||||
CylinderHigh,
|
||||
CylinderLow,
|
||||
DrvHead & 0x0f,
|
||||
SectorNum,
|
||||
SectorCnt,
|
||||
Command);
|
||||
}
|
||||
|
||||
/* Setup command parameters */
|
||||
IDEWritePrecomp(CommandPort, PreComp);
|
||||
IDEWriteSectorCount(CommandPort, SectorCnt);
|
||||
IDEWriteSectorNum(CommandPort, SectorNum);
|
||||
IDEWriteCylinderHigh(CommandPort, CylinderHigh);
|
||||
IDEWriteCylinderLow(CommandPort, CylinderLow);
|
||||
IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
|
||||
|
||||
/* Issue the command */
|
||||
IDEWriteCommand(CommandPort, Command);
|
||||
StallExecutionProcessor(50);
|
||||
|
||||
/* Wait for DRQ or error */
|
||||
for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
|
||||
{
|
||||
Status = IDEReadStatus(CommandPort);
|
||||
if (!(Status & IDE_SR_BUSY))
|
||||
/* Find first HDD and CD */
|
||||
AtaInit(&DetectedCount);
|
||||
for (UnitNumber = 0; UnitNumber <= DetectedCount; UnitNumber++)
|
||||
{
|
||||
if (Status & IDE_SR_ERR)
|
||||
DeviceUnit = AtaGetDevice(UnitNumber);
|
||||
if (DeviceUnit)
|
||||
{
|
||||
IDEWriteDriveControl(ControlPort, 0);
|
||||
StallExecutionProcessor(50);
|
||||
IDEReadStatus(CommandPort);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Status & IDE_SR_DRQ)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
IDEWriteDriveControl(ControlPort, 0);
|
||||
StallExecutionProcessor(50);
|
||||
IDEReadStatus(CommandPort);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
StallExecutionProcessor(10);
|
||||
}
|
||||
|
||||
/* Timed out */
|
||||
if (RetryCount >= IDE_MAX_POLL_RETRIES)
|
||||
{
|
||||
IDEWriteDriveControl(ControlPort, 0);
|
||||
StallExecutionProcessor(50);
|
||||
IDEReadStatus(CommandPort);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read data into buffer */
|
||||
if (Junk == FALSE)
|
||||
{
|
||||
IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
|
||||
Buffer = (PVOID)((ULONG_PTR)Buffer + IDE_SECTOR_BUF_SZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
|
||||
IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
|
||||
}
|
||||
SectorCount++;
|
||||
|
||||
/* Check for error or more sectors to read */
|
||||
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
|
||||
{
|
||||
Status = IDEReadStatus(CommandPort);
|
||||
if (!(Status & IDE_SR_BUSY))
|
||||
{
|
||||
if (Status & IDE_SR_ERR)
|
||||
if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
|
||||
{
|
||||
IDEWriteDriveControl(ControlPort, 0);
|
||||
StallExecutionProcessor(50);
|
||||
IDEReadStatus(CommandPort);
|
||||
return FALSE;
|
||||
}
|
||||
if (Status & IDE_SR_DRQ)
|
||||
{
|
||||
if (SectorCount >= SectorCnt)
|
||||
{
|
||||
TRACE("Buffer size exceeded!\n");
|
||||
Junk = TRUE;
|
||||
}
|
||||
break;
|
||||
if (!CdDrive)
|
||||
CdDrive = DeviceUnit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SectorCount > SectorCnt)
|
||||
{
|
||||
TRACE("Read %lu sectors of junk!\n",
|
||||
SectorCount - SectorCnt);
|
||||
}
|
||||
|
||||
IDEWriteDriveControl(ControlPort, 0);
|
||||
StallExecutionProcessor(50);
|
||||
IDEReadStatus(CommandPort);
|
||||
return TRUE;
|
||||
if (!HardDrive)
|
||||
HardDrive = DeviceUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
AtaInitialized = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
AtaFree();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
BOOLEAN
|
||||
XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber, PDEVICE_UNIT *DeviceUnit)
|
||||
{
|
||||
/* Xbox has only 1 IDE controller and no floppy */
|
||||
if (DriveNumber < 0x80 || (DriveNumber & 0x0F) >= 2)
|
||||
return FALSE;
|
||||
|
||||
if (!AtaInitialized)
|
||||
XboxDiskInit(TRUE);
|
||||
|
||||
/* HDD */
|
||||
if ((DriveNumber == 0x80) && HardDrive)
|
||||
{
|
||||
*DeviceUnit = HardDrive;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* CD */
|
||||
if ((DriveNumber & 0xF0) > 0x80 && CdDrive)
|
||||
{
|
||||
*DeviceUnit = CdDrive;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
|
||||
{
|
||||
ULONG StartSector;
|
||||
UCHAR Count;
|
||||
PDEVICE_UNIT DeviceUnit = NULL;
|
||||
|
||||
if (DriveNumber < 0x80 || (DriveNumber & 0x0f) >= 2)
|
||||
{
|
||||
/* Xbox has only 1 IDE controller and no floppy */
|
||||
WARN("Invalid drive number\n");
|
||||
TRACE("XboxDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n",
|
||||
DriveNumber, SectorNumber, SectorCount, Buffer);
|
||||
|
||||
if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (((SectorNumber + SectorCount) & UINT64_C(0xfffffffff0000000)) != UINT64_C(0))
|
||||
{
|
||||
FIXME("48bit LBA required but not implemented\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
StartSector = (ULONG) SectorNumber;
|
||||
while (SectorCount > 0)
|
||||
{
|
||||
Count = (SectorCount <= 255 ? (UCHAR)SectorCount : 255);
|
||||
if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
|
||||
XBOX_IDE_CONTROL_PORT,
|
||||
0, Count,
|
||||
StartSector & 0xff,
|
||||
(StartSector >> 8) & 0xff,
|
||||
(StartSector >> 16) & 0xff,
|
||||
((StartSector >> 24) & 0x0f) | IDE_DH_LBA |
|
||||
((DriveNumber & 0x0f) == 0 ? IDE_DH_DRV0 : IDE_DH_DRV1),
|
||||
IDE_CMD_READ,
|
||||
Buffer))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
SectorCount -= Count;
|
||||
Buffer = (PVOID) ((PCHAR) Buffer + Count * IDE_SECTOR_BUF_SZ);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return AtaAtapiReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
|
||||
{
|
||||
IDE_DRIVE_IDENTIFY DrvParms;
|
||||
ULONG i;
|
||||
BOOLEAN Atapi;
|
||||
PDEVICE_UNIT DeviceUnit = NULL;
|
||||
|
||||
Atapi = FALSE; /* FIXME */
|
||||
/* Get the Drive Identify block from drive or die */
|
||||
if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
|
||||
XBOX_IDE_CONTROL_PORT,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
((DriveNumber & 0x0f) == 0 ? IDE_DH_DRV0 : IDE_DH_DRV1),
|
||||
(Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
|
||||
(PUCHAR) &DrvParms))
|
||||
{
|
||||
ERR("XboxDiskPolledRead() failed\n");
|
||||
TRACE("XboxDiskGetDriveGeometry(0x%x)\n", DriveNumber);
|
||||
|
||||
if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Geometry->Cylinders = DrvParms.LogicalCyls;
|
||||
Geometry->Heads = DrvParms.LogicalHeads;
|
||||
Geometry->Sectors = DrvParms.SectorsPerTrack;
|
||||
|
||||
if (!Atapi && (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED) != 0)
|
||||
{
|
||||
/* LBA ATA drives always have a sector size of 512 */
|
||||
Geometry->BytesPerSector = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("BytesPerSector %d\n", DrvParms.BytesPerSector);
|
||||
if (DrvParms.BytesPerSector == 0)
|
||||
{
|
||||
Geometry->BytesPerSector = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1 << 15; i; i /= 2)
|
||||
{
|
||||
if ((DrvParms.BytesPerSector & i) != 0)
|
||||
{
|
||||
Geometry->BytesPerSector = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("Cylinders %d\n", Geometry->Cylinders);
|
||||
TRACE("Heads %d\n", Geometry->Heads);
|
||||
TRACE("Sectors %d\n", Geometry->Sectors);
|
||||
TRACE("BytesPerSector %d\n", Geometry->BytesPerSector);
|
||||
Geometry->Cylinders = DeviceUnit->Cylinders;
|
||||
Geometry->Heads = DeviceUnit->Heads;
|
||||
Geometry->Sectors = DeviceUnit->Sectors;
|
||||
Geometry->BytesPerSector = DeviceUnit->SectorSize;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -515,8 +122,19 @@ XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
|
|||
ULONG
|
||||
XboxDiskGetCacheableBlockCount(UCHAR DriveNumber)
|
||||
{
|
||||
/* 64 seems a nice number, it is used by the machpc code for LBA devices */
|
||||
return 64;
|
||||
}
|
||||
PDEVICE_UNIT DeviceUnit = NULL;
|
||||
|
||||
/* EOF */
|
||||
TRACE("XboxDiskGetCacheableBlockCount(0x%x)\n", DriveNumber);
|
||||
|
||||
if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If LBA is supported then the block size will be 64 sectors (32k)
|
||||
* If not then the block size is the size of one track.
|
||||
*/
|
||||
if (DeviceUnit->Flags & ATA_DEVICE_LBA)
|
||||
return 64;
|
||||
else
|
||||
return DeviceUnit->Sectors;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ VOID XboxPrepareForReactOS(VOID);
|
|||
VOID XboxMemInit(VOID);
|
||||
PFREELDR_MEMORY_DESCRIPTOR XboxMemGetMemoryMap(ULONG *MemoryMapSize);
|
||||
|
||||
VOID XboxDiskInit(BOOLEAN Init);
|
||||
BOOLEAN XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer);
|
||||
BOOLEAN XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY DriveGeometry);
|
||||
ULONG XboxDiskGetCacheableBlockCount(UCHAR DriveNumber);
|
||||
|
|
333
boot/freeldr/freeldr/include/hwide.h
Normal file
333
boot/freeldr/freeldr/include/hwide.h
Normal file
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* PROJECT: FreeLoader
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: ATA/ATAPI polled I/O driver header file.
|
||||
* COPYRIGHT: Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
|
||||
*/
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
/* Some definitions were taken from UniATA driver by Alter */
|
||||
|
||||
/*
|
||||
* IDE registers offsets
|
||||
*/
|
||||
#if defined(SARCH_PC98)
|
||||
#define IDX_IO1_i_Data 0x00
|
||||
#define IDX_IO1_i_Error 0x02
|
||||
#define IDX_IO1_i_BlockCount 0x04
|
||||
#define IDX_IO1_i_BlockNumber 0x06
|
||||
#define IDX_IO1_i_CylinderLow 0x08
|
||||
#define IDX_IO1_i_CylinderHigh 0x0A
|
||||
#define IDX_IO1_i_DriveSelect 0x0C
|
||||
#define IDX_IO1_i_Status 0x0E
|
||||
|
||||
#define IDX_IO2_i_AltStatus 0x10C
|
||||
#define IDX_IO2_i_DriveAddress 0x10E
|
||||
#define IDE_IO_i_Bank 0x432
|
||||
|
||||
#define IDX_IO1_o_Data 0x00
|
||||
#define IDX_IO1_o_Feature 0x02
|
||||
#define IDX_IO1_o_BlockCount 0x04
|
||||
#define IDX_IO1_o_BlockNumber 0x06
|
||||
#define IDX_IO1_o_CylinderLow 0x08
|
||||
#define IDX_IO1_o_CylinderHigh 0x0A
|
||||
#define IDX_IO1_o_DriveSelect 0x0C
|
||||
#define IDX_IO1_o_Command 0x0E
|
||||
|
||||
#define IDX_IO2_o_AltStatus 0x10C
|
||||
#define IDX_IO2_o_Control 0x10E
|
||||
#define IDE_IO_o_BankSelect 0x432
|
||||
#else /* SARCH_PC98 */
|
||||
#define IDX_IO1_i_Data 0x00
|
||||
#define IDX_IO1_i_Error 0x01
|
||||
#define IDX_IO1_i_BlockCount 0x02
|
||||
#define IDX_IO1_i_BlockNumber 0x03
|
||||
#define IDX_IO1_i_CylinderLow 0x04
|
||||
#define IDX_IO1_i_CylinderHigh 0x05
|
||||
#define IDX_IO1_i_DriveSelect 0x06
|
||||
#define IDX_IO1_i_Status 0x07
|
||||
|
||||
#define IDX_IO2_i_AltStatus 0x206
|
||||
#define IDX_IO2_i_DriveAddress 0x207
|
||||
|
||||
#define IDX_IO1_o_Data 0x00
|
||||
#define IDX_IO1_o_Feature 0x01
|
||||
#define IDX_IO1_o_BlockCount 0x02
|
||||
#define IDX_IO1_o_BlockNumber 0x03
|
||||
#define IDX_IO1_o_CylinderLow 0x04
|
||||
#define IDX_IO1_o_CylinderHigh 0x05
|
||||
#define IDX_IO1_o_DriveSelect 0x06
|
||||
#define IDX_IO1_o_Command 0x07
|
||||
|
||||
#define IDX_IO2_o_AltStatus 0x206
|
||||
#define IDX_IO2_o_Control 0x207
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ATAPI registers offsets
|
||||
*/
|
||||
#if defined(SARCH_PC98)
|
||||
#define IDX_ATAPI_IO1_i_Data 0x00
|
||||
#define IDX_ATAPI_IO1_i_Error 0x02
|
||||
#define IDX_ATAPI_IO1_i_InterruptReason 0x04
|
||||
#define IDX_ATAPI_IO1_i_Unused1 0x06
|
||||
#define IDX_ATAPI_IO1_i_ByteCountLow 0x08
|
||||
#define IDX_ATAPI_IO1_i_ByteCountHigh 0x0A
|
||||
#define IDX_ATAPI_IO1_i_DriveSelect 0x0C
|
||||
#define IDX_ATAPI_IO1_i_Status 0x0E
|
||||
|
||||
#define IDX_ATAPI_IO1_o_Data 0x00
|
||||
#define IDX_ATAPI_IO1_o_Feature 0x02
|
||||
#define IDX_ATAPI_IO1_o_Unused0 0x04
|
||||
#define IDX_ATAPI_IO1_o_Unused1 0x06
|
||||
#define IDX_ATAPI_IO1_o_ByteCountLow 0x08
|
||||
#define IDX_ATAPI_IO1_o_ByteCountHigh 0x0A
|
||||
#define IDX_ATAPI_IO1_o_DriveSelect 0x0C
|
||||
#define IDX_ATAPI_IO1_o_Command 0x0E
|
||||
#else /* SARCH_PC98 */
|
||||
#define IDX_ATAPI_IO1_i_Data 0x00
|
||||
#define IDX_ATAPI_IO1_i_Error 0x01
|
||||
#define IDX_ATAPI_IO1_i_InterruptReason 0x02
|
||||
#define IDX_ATAPI_IO1_i_Unused1 0x03
|
||||
#define IDX_ATAPI_IO1_i_ByteCountLow 0x04
|
||||
#define IDX_ATAPI_IO1_i_ByteCountHigh 0x05
|
||||
#define IDX_ATAPI_IO1_i_DriveSelect 0x06
|
||||
#define IDX_ATAPI_IO1_i_Status 0x07
|
||||
|
||||
#define IDX_ATAPI_IO1_o_Data 0x00
|
||||
#define IDX_ATAPI_IO1_o_Feature 0x01
|
||||
#define IDX_ATAPI_IO1_o_Unused0 0x02
|
||||
#define IDX_ATAPI_IO1_o_Unused1 0x03
|
||||
#define IDX_ATAPI_IO1_o_ByteCountLow 0x04
|
||||
#define IDX_ATAPI_IO1_o_ByteCountHigh 0x05
|
||||
#define IDX_ATAPI_IO1_o_DriveSelect 0x06
|
||||
#define IDX_ATAPI_IO1_o_Command 0x07
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IDE status definitions
|
||||
*/
|
||||
#define IDE_STATUS_SUCCESS 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_DMA 0x20 /* DMA ready */
|
||||
#define IDE_STATUS_DWF 0x20 /* drive write fault */
|
||||
#define IDE_STATUS_DRDY 0x40
|
||||
#define IDE_STATUS_IDLE 0x50
|
||||
#define IDE_STATUS_BUSY 0x80
|
||||
|
||||
#define IDE_STATUS_WRONG 0xff
|
||||
#define IDE_STATUS_MASK 0xff
|
||||
|
||||
/*
|
||||
* IDE drive select/head definitions
|
||||
*/
|
||||
#define IDE_DRIVE_SELECT 0xA0
|
||||
#define IDE_DRIVE_1 0x00
|
||||
#define IDE_DRIVE_2 0x10
|
||||
#define IDE_DRIVE_SELECT_1 (IDE_DRIVE_SELECT | IDE_DRIVE_1)
|
||||
#define IDE_DRIVE_SELECT_2 (IDE_DRIVE_SELECT | IDE_DRIVE_2)
|
||||
#define IDE_DRIVE_MASK (IDE_DRIVE_SELECT_1 | IDE_DRIVE_SELECT_2)
|
||||
#define IDE_USE_LBA 0x40
|
||||
|
||||
/*
|
||||
* IDE drive control definitions
|
||||
*/
|
||||
#define IDE_DC_DISABLE_INTERRUPTS 0x02
|
||||
#define IDE_DC_RESET_CONTROLLER 0x04
|
||||
#define IDE_DC_A_4BIT 0x80
|
||||
#define IDE_DC_USE_HOB 0x80 // use high-order byte(s)
|
||||
#define IDE_DC_REENABLE_CONTROLLER 0x00
|
||||
|
||||
/*
|
||||
* IDE error definitions
|
||||
*/
|
||||
#define IDE_ERROR_ICRC 0x80
|
||||
#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_NO_MEDIA 0x02
|
||||
#define IDE_ERROR_ILLEGAL_LENGTH 0x01
|
||||
|
||||
/*
|
||||
* Values for TransferMode
|
||||
*/
|
||||
#define ATA_PIO 0x00
|
||||
|
||||
/*
|
||||
* IDENTIFY data
|
||||
*/
|
||||
#include <pshpack1.h>
|
||||
typedef struct _IDENTIFY_DATA
|
||||
{
|
||||
UCHAR AtapiCmdSize:2; // 00 00 General configuration
|
||||
UCHAR Unused1:3;
|
||||
UCHAR DrqType:2;
|
||||
UCHAR Removable:1;
|
||||
UCHAR DeviceType:5;
|
||||
UCHAR Unused2:1;
|
||||
UCHAR CmdProtocol:2;
|
||||
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 ReadWriteMultipleSupport; // 5E 47
|
||||
UCHAR VendorUnique2; // 5F
|
||||
USHORT DoubleWordIo; // 60 48
|
||||
USHORT Reserved62_0:8; // 62 49 Capabilities
|
||||
USHORT SupportDma:1;
|
||||
USHORT SupportLba:1;
|
||||
USHORT DisableIordy:1;
|
||||
USHORT SupportIordy:1;
|
||||
USHORT SoftReset:1;
|
||||
USHORT StandbyOverlap:1;
|
||||
USHORT SupportQTag:1;
|
||||
USHORT SupportIDma:1;
|
||||
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 Reserved73_74[2]; // 73-74
|
||||
USHORT QueueLength:5; // 75
|
||||
USHORT Reserved75_6:11;
|
||||
USHORT SataCapabilities; // 76
|
||||
USHORT Reserved77; // 77
|
||||
USHORT SataSupport; // 78
|
||||
USHORT SataEnable; // 79
|
||||
USHORT MajorRevision; // 80
|
||||
USHORT MinorRevision; // 81
|
||||
struct {
|
||||
USHORT Smart:1; // 82
|
||||
USHORT Security:1;
|
||||
USHORT Removable:1;
|
||||
USHORT PowerMngt:1;
|
||||
USHORT Packet:1;
|
||||
USHORT WriteCache:1;
|
||||
USHORT LookAhead:1;
|
||||
USHORT ReleaseDRQ:1;
|
||||
USHORT ServiceDRQ:1;
|
||||
USHORT Reset:1;
|
||||
USHORT Protected:1;
|
||||
USHORT Reserved_82_11:1;
|
||||
USHORT WriteBuffer:1;
|
||||
USHORT ReadBuffer:1;
|
||||
USHORT Nop:1;
|
||||
USHORT Reserved_82_15:1;
|
||||
USHORT Microcode:1; // 83/86
|
||||
USHORT Queued:1;
|
||||
USHORT CFA:1;
|
||||
USHORT APM:1;
|
||||
USHORT Notify:1;
|
||||
USHORT Standby:1;
|
||||
USHORT Spinup:1;
|
||||
USHORT Reserver_83_7:1;
|
||||
USHORT MaxSecurity:1;
|
||||
USHORT AutoAcoustic:1;
|
||||
USHORT Address48:1;
|
||||
USHORT ConfigOverlay:1;
|
||||
USHORT FlushCache:1;
|
||||
USHORT FlushCache48:1;
|
||||
USHORT SupportOne:1;
|
||||
USHORT SupportZero:1;
|
||||
USHORT SmartErrorLog:1; // 84/87
|
||||
USHORT SmartSelfTest:1;
|
||||
USHORT MediaSerialNo:1;
|
||||
USHORT MediaCardPass:1;
|
||||
USHORT Streaming:1;
|
||||
USHORT Logging:1;
|
||||
USHORT Reserver_84_6:8;
|
||||
USHORT ExtendedOne:1;
|
||||
USHORT ExtendedZero:1;
|
||||
} FeaturesSupport, FeaturesEnabled;
|
||||
USHORT Reserved6[13]; // 88-99
|
||||
ULONGLONG UserAddressableSectors48; // 100-103
|
||||
USHORT Reserved7[151]; // 104-255
|
||||
} IDENTIFY_DATA, *PIDENTIFY_DATA;
|
||||
#include <poppack.h>
|
||||
#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
|
||||
|
||||
#define ATAPI_MAGIC_LSB 0x14
|
||||
#define ATAPI_MAGIC_MSB 0xEB
|
||||
#define MAXIMUM_CDROM_SIZE 804
|
||||
|
||||
typedef struct _DEVICE_UNIT
|
||||
{
|
||||
UCHAR Channel;
|
||||
UCHAR DeviceNumber;
|
||||
ULONG Cylinders;
|
||||
ULONG Heads;
|
||||
ULONG Sectors;
|
||||
ULONG SectorSize;
|
||||
ULONGLONG TotalSectors; /* This number starts from 0 */
|
||||
USHORT Flags;
|
||||
IDENTIFY_DATA IdentifyData;
|
||||
} DEVICE_UNIT, *PDEVICE_UNIT;
|
||||
|
||||
#define ATA_DEVICE_ATAPI (1 << 0)
|
||||
#define ATA_DEVICE_NO_MEDIA (1 << 1)
|
||||
#define ATA_DEVICE_NOT_READY (1 << 2)
|
||||
#define ATA_DEVICE_LBA48 (1 << 3)
|
||||
#define ATA_DEVICE_LBA (1 << 4)
|
||||
#define ATA_DEVICE_CHS (1 << 5)
|
||||
|
||||
/* PROTOTYPES ****************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
AtaInit(
|
||||
OUT PUCHAR DetectedCount
|
||||
);
|
||||
|
||||
VOID
|
||||
AtaFree();
|
||||
|
||||
PDEVICE_UNIT
|
||||
AtaGetDevice(
|
||||
IN UCHAR UnitNumber
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
AtaAtapiReadLogicalSectorsLBA(
|
||||
IN OUT PDEVICE_UNIT DeviceUnit,
|
||||
IN ULONGLONG SectorNumber,
|
||||
IN ULONG SectorCount,
|
||||
OUT PVOID Buffer
|
||||
);
|
Loading…
Reference in a new issue