xnoe-os/src/kernel/ata.cpp

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;
}