170 lines
4.2 KiB
C++
170 lines
4.2 KiB
C++
#include "ata.h"
|
|
|
|
uint16_t controlBase[4] = {0x1f0, 0x170, 0x1e8, 0x168};
|
|
uint16_t dcrBase[4] = {0x3f6, 0x376, 0x3e6, 0x366};
|
|
|
|
uint8_t ATA::readStatus() {
|
|
uint8_t status;
|
|
for (int i=0; i<15; i++)
|
|
status=StatusRegister.readb();
|
|
return status;
|
|
}
|
|
|
|
uint8_t ATA::pollTillNotBSY() {
|
|
uint8_t lastStatus;
|
|
while (((lastStatus=StatusRegister.readb()) & 0x80))
|
|
if (lastStatus&0x1)
|
|
return lastStatus;
|
|
return 0;
|
|
}
|
|
|
|
uint8_t ATA::pollTillDRQ() {
|
|
uint8_t lastStatus;
|
|
while (!((lastStatus=StatusRegister.readb()) & 0x8))
|
|
if (lastStatus&0x1)
|
|
return lastStatus;
|
|
return 0;
|
|
}
|
|
|
|
ATA::ATA(uint32_t bus) :
|
|
DataRegister(controlBase[bus]+0),
|
|
ErrorRegister(controlBase[bus]+1),
|
|
FeaturesRegister(controlBase[bus]+1),
|
|
SectorCountRegister(controlBase[bus]+2),
|
|
LBALo(controlBase[bus]+3),
|
|
LBAMid(controlBase[bus]+4),
|
|
LBAHi(controlBase[bus]+5),
|
|
DriveSelectRegister(controlBase[bus]+6),
|
|
StatusRegister(controlBase[bus]+7),
|
|
CommandRegister(controlBase[bus]+7) {
|
|
this->isValid = 0;
|
|
|
|
DriveSelectRegister.writeb(0xA0);
|
|
LBALo.writeb(0);
|
|
LBAMid.writeb(0);
|
|
LBAHi.writeb(0);
|
|
CommandRegister.writeb(0xEC);
|
|
|
|
if (!readStatus()) {
|
|
this->isValid = false;
|
|
} else {
|
|
pollTillNotBSY();
|
|
uint8_t LBAmid;
|
|
uint8_t LBAhi;
|
|
if ((LBAmid = LBAMid.readb()) || (LBAhi = LBAHi.readb())) {
|
|
this->isValid = false;
|
|
} else {
|
|
uint8_t status = pollTillDRQ();
|
|
if (!(status&0x1)) {
|
|
for (int i=0; i<256; i++)
|
|
((uint16_t*)identifyResult)[i] = DataRegister.readw();
|
|
this->isValid = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->isValid) {
|
|
this->totalLBA28Sectors = *((uint32_t*)(identifyResult+60));
|
|
this->diskSize = this->totalLBA28Sectors * 512;
|
|
}
|
|
}
|
|
|
|
bool ATA::validDevice() {
|
|
return this->isValid;
|
|
}
|
|
|
|
void ATA::ATARead(uint32_t sector, uint8_t* buffer) {
|
|
driveLock.lock();
|
|
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
|
SectorCountRegister.writeb(1);
|
|
LBALo.writeb((uint8_t)sector);
|
|
LBAMid.writeb((uint8_t)(sector>>8));
|
|
LBAHi.writeb((uint8_t)(sector>>16));
|
|
CommandRegister.writeb(0x20);
|
|
pollTillNotBSY();
|
|
for (int i=0; i<256; i++)
|
|
((uint16_t*)buffer)[i] = DataRegister.readw();
|
|
driveLock.unlock();
|
|
}
|
|
|
|
void ATA::ATAWrite(uint32_t sector, uint8_t* buffer) {
|
|
driveLock.lock();
|
|
DriveSelectRegister.writeb(0xE0 | ((sector >> 24) & 0xf));
|
|
SectorCountRegister.writeb(1);
|
|
LBALo.writeb((uint8_t)sector);
|
|
LBAMid.writeb((uint8_t)(sector>>8));
|
|
LBAHi.writeb((uint8_t)(sector>>16));
|
|
CommandRegister.writeb(0x30);
|
|
pollTillNotBSY();
|
|
for (int i=0; i<256; i++)
|
|
DataRegister.writew(((uint16_t*)buffer)[i]);
|
|
CommandRegister.writeb(0xe7);
|
|
driveLock.unlock();
|
|
}
|
|
|
|
ATAReadWriter::ATAReadWriter(uint32_t bus):
|
|
ATA(bus) {
|
|
this->currentPosition = 0;
|
|
}
|
|
|
|
uint32_t ATAReadWriter::read(uint32_t count, uint8_t* buffer) {
|
|
driveLock.lock();
|
|
uint32_t remainingBytes = count;
|
|
uint32_t inThisSector = currentPosition % 512;
|
|
|
|
uint32_t index=0;
|
|
|
|
uint32_t c=0;
|
|
|
|
ATARead(currentPosition / 512, sectorBuffer);
|
|
while (remainingBytes) {
|
|
if (currentPosition >= diskSize)
|
|
break;
|
|
buffer[index++] = sectorBuffer[inThisSector++];
|
|
remainingBytes--;
|
|
currentPosition++;
|
|
if (inThisSector == 512) {
|
|
ATARead(currentPosition / 512, sectorBuffer);
|
|
inThisSector = 0;
|
|
}
|
|
c++;
|
|
}
|
|
driveLock.unlock();
|
|
return c;
|
|
}
|
|
uint32_t ATAReadWriter::write(uint32_t count, uint8_t* buffer) {
|
|
driveLock.lock();
|
|
uint32_t remainingBytes = count;
|
|
uint32_t inThisSector = currentPosition % 512;
|
|
|
|
uint32_t index=0;
|
|
|
|
uint32_t c=0;
|
|
|
|
ATARead(currentPosition / 512, sectorBuffer);
|
|
while (remainingBytes) {
|
|
if (currentPosition >= diskSize)
|
|
break;
|
|
sectorBuffer[inThisSector++] = buffer[index++];
|
|
remainingBytes--;
|
|
currentPosition++;
|
|
if (inThisSector == 512) {
|
|
ATAWrite((currentPosition / 512) - 1, sectorBuffer);
|
|
ATARead(currentPosition / 512, sectorBuffer);
|
|
inThisSector = 0;
|
|
}
|
|
c++;
|
|
}
|
|
// Perform a final write to ensure that we've written everything to disk.
|
|
ATAWrite((currentPosition / 512), sectorBuffer);
|
|
driveLock.unlock();
|
|
return c;
|
|
}
|
|
uint32_t ATAReadWriter::size() {
|
|
return this->diskSize;
|
|
}
|
|
uint32_t ATAReadWriter::seek(uint32_t position) {
|
|
this->currentPosition = position;
|
|
return position;
|
|
}
|