📄 xboxdisk.c
字号:
}
StallExecutionProcessor(10);
}
DbgPrint((DPRINT_DISK, "status=0x%x\n", Status));
DbgPrint((DPRINT_DISK, "waited %d usecs for busy to clear\n", RetryCount * 10));
if (RetryCount >= IDE_MAX_BUSY_RETRIES)
{
DbgPrint((DPRINT_DISK, "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)
{
DbgPrint((DPRINT_DISK, "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
{
DbgPrint((DPRINT_DISK, "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))
{
if (Status & IDE_SR_ERR)
{
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)
{
IDEWriteDriveControl(ControlPort, 0);
StallExecutionProcessor(50);
IDEReadStatus(CommandPort);
return FALSE;
}
if (Status & IDE_SR_DRQ)
{
if (SectorCount >= SectorCnt)
{
DbgPrint((DPRINT_DISK, "Buffer size exceeded!\n"));
Junk = TRUE;
}
break;
}
else
{
if (SectorCount > SectorCnt)
{
DbgPrint((DPRINT_DISK, "Read %lu sectors of junk!\n",
SectorCount - SectorCnt));
}
IDEWriteDriveControl(ControlPort, 0);
StallExecutionProcessor(50);
IDEReadStatus(CommandPort);
return TRUE;
}
}
}
}
}
BOOLEAN
XboxDiskReadLogicalSectors(ULONG DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
{
ULONG StartSector;
UCHAR Count;
if (DriveNumber < 0x80 || 2 <= (DriveNumber & 0x0f))
{
/* Xbox has only 1 IDE controller and no floppy */
DbgPrint((DPRINT_DISK, "Invalid drive number\n"));
return FALSE;
}
if (UINT64_C(0) != ((SectorNumber + SectorCount) & UINT64_C(0xfffffffff0000000)))
{
DbgPrint((DPRINT_DISK, "48bit LBA required but not implemented\n"));
return FALSE;
}
StartSector = (ULONG) SectorNumber;
while (0 < SectorCount)
{
Count = (SectorCount <= 255 ? 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 |
(0 == (DriveNumber & 0x0f) ? 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;
}
BOOLEAN
XboxDiskGetPartitionEntry(ULONG DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
{
UCHAR SectorData[IDE_SECTOR_BUF_SZ];
/* This is the Xbox, chances are that there is a Xbox-standard partitionless
* disk in it so let's check that first */
if (1 <= PartitionNumber && PartitionNumber <= sizeof(XboxPartitions) / sizeof(XboxPartitions[0]) &&
MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, SectorData))
{
if (*((PULONG) SectorData) == XBOX_SIGNATURE)
{
memset(PartitionTableEntry, 0, sizeof(PARTITION_TABLE_ENTRY));
PartitionTableEntry->SystemIndicator = XboxPartitions[PartitionNumber - 1].SystemIndicator;
PartitionTableEntry->SectorCountBeforePartition = XboxPartitions[PartitionNumber - 1].SectorCountBeforePartition;
PartitionTableEntry->PartitionSectorCount = XboxPartitions[PartitionNumber - 1].PartitionSectorCount;
return TRUE;
}
}
/* No magic Xbox partitions. Maybe there's a MBR */
return DiskGetPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
}
BOOLEAN
XboxDiskGetDriveGeometry(ULONG DriveNumber, PGEOMETRY Geometry)
{
IDE_DRIVE_IDENTIFY DrvParms;
ULONG i;
BOOLEAN Atapi;
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,
(0 == (DriveNumber & 0x0f) ? IDE_DH_DRV0 : IDE_DH_DRV1),
(Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
(PUCHAR) &DrvParms))
{
DbgPrint((DPRINT_DISK, "XboxDiskPolledRead() failed\n"));
return FALSE;
}
Geometry->Cylinders = DrvParms.LogicalCyls;
Geometry->Heads = DrvParms.LogicalHeads;
Geometry->Sectors = DrvParms.SectorsPerTrack;
if (! Atapi && 0 != (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED))
{
/* LBA ATA drives always have a sector size of 512 */
Geometry->BytesPerSector = 512;
}
else
{
DbgPrint((DPRINT_DISK, "BytesPerSector %d\n", DrvParms.BytesPerSector));
if (DrvParms.BytesPerSector == 0)
{
Geometry->BytesPerSector = 512;
}
else
{
for (i = 15; i >= 0; i--)
{
if (0 != (DrvParms.BytesPerSector & (1 << i)))
{
Geometry->BytesPerSector = 1 << i;
break;
}
}
}
}
DbgPrint((DPRINT_DISK, "Cylinders %d\n", Geometry->Cylinders));
DbgPrint((DPRINT_DISK, "Heads %d\n", Geometry->Heads));
DbgPrint((DPRINT_DISK, "Sectors %d\n", Geometry->Sectors));
DbgPrint((DPRINT_DISK, "BytesPerSector %d\n", Geometry->BytesPerSector));
return TRUE;
}
ULONG
XboxDiskGetCacheableBlockCount(ULONG DriveNumber)
{
/* 64 seems a nice number, it is used by the machpc code for LBA devices */
return 64;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -