atapi.c
来自「一个类似windows」· C语言 代码 · 共 2,047 行 · 第 1/5 页
C
2,047 行
UCHAR High;
UCHAR Low;
DPRINT("AtapiFindDevices() called\n");
CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
DPRINT(" CommandPortBase: %x\n", CommandPortBase);
ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
DPRINT(" ControlPortBase: %x\n", ControlPortBase);
for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
{
/* Select drive */
IDEWriteDriveHead(CommandPortBase,
IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
ScsiPortStallExecution(500);
/* Disable interrupts */
IDEWriteDriveControl(ControlPortBase,
IDE_DC_nIEN);
ScsiPortStallExecution(500);
/* Check if a device is attached to the interface */
IDEWriteCylinderHigh(CommandPortBase, 0xaa);
IDEWriteCylinderLow(CommandPortBase, 0x55);
High = IDEReadCylinderHigh(CommandPortBase);
Low = IDEReadCylinderLow(CommandPortBase);
IDEWriteCylinderHigh(CommandPortBase, 0);
IDEWriteCylinderLow(CommandPortBase, 0);
if (Low != 0x55 || High != 0xaa)
{
DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
continue;
}
AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
for (Retries = 0; Retries < 20000; Retries++)
{
if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
{
break;
}
ScsiPortStallExecution(150);
}
if (Retries >= 20000)
{
DPRINT("Timeout on drive %lu\n", UnitNumber);
DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
continue;
}
High = IDEReadCylinderHigh(CommandPortBase);
Low = IDEReadCylinderLow(CommandPortBase);
DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
UnitNumber,
High,
Low);
if (High == 0xEB && Low == 0x14)
{
if (AtapiIdentifyDevice(CommandPortBase,
ControlPortBase,
UnitNumber,
TRUE,
&DeviceExtension->DeviceParams[UnitNumber]))
{
DPRINT(" ATAPI drive found!\n");
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
DeviceExtension->TransferSize[UnitNumber] =
DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
#ifdef ENABLE_DMA
if (AtapiConfigDma(DeviceExtension, UnitNumber))
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
}
#endif
if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
!(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
}
/* Don't flush CD/DVD drives */
if (((DeviceExtension->DeviceParams[UnitNumber].ConfigBits >> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE)
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
}
DeviceFound = TRUE;
}
else
{
DPRINT(" No ATAPI drive found!\n");
}
}
else
{
if (AtapiIdentifyDevice(CommandPortBase,
ControlPortBase,
UnitNumber,
FALSE,
&DeviceExtension->DeviceParams[UnitNumber]))
{
DPRINT(" IDE drive found!\n");
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
(DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
(DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
(DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
{
DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
}
if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
}
if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
}
#ifdef ENABLE_DMA
if (AtapiConfigDma(DeviceExtension, UnitNumber))
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
}
#endif
if (DeviceExtension->DeviceFlags[UnitNumber] & DEVICE_48BIT_ADDRESS)
{
if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x2000) ||
!(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x2000))
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
}
}
else
{
if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
!(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
{
DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
}
}
DeviceFound = TRUE;
}
else
{
DPRINT(" No IDE drive found!\n");
}
}
}
/* Reset pending interrupts */
IDEReadStatus(CommandPortBase);
/* Reenable interrupts */
IDEWriteDriveControl(ControlPortBase, 0);
ScsiPortStallExecution(500);
/* Return with drive 0 selected */
IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
ScsiPortStallExecution(500);
DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
return(DeviceFound);
}
/*
* AtapiIdentifyDevice
*
* DESCRIPTION:
* Get the identification block from the drive
*
* RUN LEVEL:
* PASSIVE_LEVEL
*
* ARGUMENTS:
* CommandPort
* Address of the command port
* ControlPort
* Address of the control port
* DriveNum
* The drive index (0,1)
* Atapi
* Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
* DrvParms
* Address to write drive ident block
*
* RETURNS:
* TRUE: The drive identification block was retrieved successfully
* FALSE: an error ocurred
*/
static BOOLEAN
AtapiIdentifyDevice(IN ULONG CommandPort,
IN ULONG ControlPort,
IN ULONG DriveNum,
IN BOOLEAN Atapi,
OUT PIDE_DRIVE_IDENTIFY DrvParms)
{
LONG i;
ULONG mode;
char SerialNumber[20];
char FirmwareRev[8];
char ModelNumber[40];
/* Get the Drive Identify block from drive or die */
if (AtapiPolledRead(CommandPort,
ControlPort,
0,
1,
0,
0,
0,
(DriveNum ? IDE_DH_DRV1 : 0),
(Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
(PUCHAR)DrvParms) == FALSE)
{
DPRINT("AtapiPolledRead() failed\n");
return FALSE;
}
/* Report on drive parameters if debug mode */
memcpy(SerialNumber, DrvParms->SerialNumber, 20);
memcpy(FirmwareRev, DrvParms->FirmwareRev, 8);
memcpy(ModelNumber, DrvParms->ModelNumber, 40);
IDESwapBytePairs((PUCHAR)SerialNumber, 20);
IDESwapBytePairs((PUCHAR)FirmwareRev, 8);
IDESwapBytePairs((PUCHAR)ModelNumber, 40);
DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
DrvParms->ConfigBits,
DrvParms->LogicalCyls,
DrvParms->LogicalHeads,
DrvParms->SectorsPerTrack,
DrvParms->InterSectorGap,
DrvParms->InterSectorGapSize);
DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
DrvParms->BytesInPLO,
DrvParms->VendorUniqueCnt,
SerialNumber);
DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
DrvParms->ControllerType,
DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
DrvParms->ECCByteCnt,
FirmwareRev);
DPRINT("Model:[%.40s]\n", ModelNumber);
DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
(DrvParms->RWMultImplemented),
(DrvParms->RWMultCurrent) & 0xff,
(DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
(DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
DrvParms->MinPIOTransTime,
DrvParms->MinDMATransTime);
DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
DrvParms->TMCylinders,
DrvParms->TMHeads,
DrvParms->TMSectorsPerTrk,
(ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
DrvParms->TMSectorCountHi,
DrvParms->TMSectorCountLo,
(ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
if (DrvParms->TMFieldsValid & 0x0004)
{
if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
{
mode = 7;
while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
{
mode--;
}
DPRINT("Ultra DMA mode %d is selected\n", mode);
}
else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
{
mode = 2;
while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
{
mode--;
}
DPRINT("Multi DMA mode %d is selected\n", mode);
}
}
if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
{
/* LBA ATA drives always have a sector size of 512 */
DrvParms->BytesPerSector = 512;
}
else
{
DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
if (DrvParms->BytesPerSector == 0)
{
DrvParms->BytesPerSector = 512;
}
else
{
for (i = 15; i >= 0; i--)
{
if (DrvParms->BytesPerSector & (1 << i))
{
DrvParms->BytesPerSector = 1 << i;
break;
}
}
}
}
DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
return TRUE;
}
// AtapiPolledRead
//
// DESCRIPTION:
// Read a sector of data from the drive in a polled fashion.
//
// RUN LEVEL:
// PASSIVE_LEVEL
//
// ARGUMENTS:
// IN ULONG CommandPort Address of command port for drive
// IN ULONG ControlPort Address of control port for drive
// IN UCHAR PreComp Value to write to precomp register
// IN UCHAR SectorCnt Value to write to sectorCnt register
// IN UCHAR SectorNum Value to write to sectorNum register
// IN UCHAR CylinderLow Value to write to CylinderLow register
// IN UCHAR CylinderHigh Value to write to CylinderHigh register
// IN UCHAR DrvHead Value to write to Drive/Head register
// IN UCHAR Command Value to write to Command register
// OUT PUCHAR Buffer Buffer for output data
//
// RETURNS:
// BOOLEAN: TRUE success, FALSE error
//
static BOOLEAN
AtapiPolledRead(IN ULONG CommandPort,
IN ULONG ControlPort,
IN UCHAR PreComp,
IN UCHAR SectorCnt,
IN UCHAR SectorNum,
IN UCHAR CylinderLow,
IN UCHAR CylinderHigh,
IN UCHAR DrvHead,
IN UCHAR Command,
OUT PUCHAR 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++)
{
Status = IDEReadStatus(CommandPort);
if (!(Status & IDE_SR_BUSY))
{
break;
}
ScsiPortStallExecution(10);
}
DPRINT("status=%02x\n", Status);
DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
if (RetryCount >= IDE_MAX_BUSY_RETRIES)
{
DPRINT("Drive is BUSY for too long\n");
return FALSE;
}
/* Write Drive/Head to select drive */
IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
ScsiPortStallExecution(500);
/* Disable interrupts */
IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
ScsiPortStallExecution(500);
#if 0
/* Wait for STATUS.BUSY and STATUS.DRQ to clear */
for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
{
Status = IDEReadStatus(CommandPort);
if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
{
break;
}
ScsiPortStallExecution(10);
}
if (RetryCount >= IDE_MAX_BUSY_RETRIES)
{
return FALSE;
}
#endif
/* Issue command to drive */
if (DrvHead & IDE_DH_LBA)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?