170 lines
5.8 KiB
C++
170 lines
5.8 KiB
C++
#include <base.hpp>
|
|
#include <blockdev.hpp>
|
|
#include <io.h>
|
|
#include <textDISP.hpp>
|
|
#include <string.h>
|
|
#define ATAPIO_ERR 0x01
|
|
#define ATAPIO_DRQ 0x08
|
|
#define ATAPIO_SRV 0x10
|
|
#define ATAPIO_DF 0x20
|
|
#define ATAPIO_RDY 0x40
|
|
#define ATAPIO_BSY 0x80
|
|
#define DATA 0
|
|
#define ATAPI_RESV 1
|
|
#define SECTOR_CNT 2
|
|
#define LBAlo 3
|
|
#define LBAmid 4
|
|
#define LBAhi 5
|
|
#define DRV 6
|
|
#define CMD 7
|
|
#define ALTCMD 0x206
|
|
namespace MTGosHAL {
|
|
IDE::IDE(uint16_t baseport, uint8_t num): baseport(baseport), num(num), existent(0), numDevices(0) {
|
|
if(inb(baseport+CMD)!=0xFF) { //Does the ATA controller return floating bus?
|
|
// Checking existence of the master
|
|
outb(baseport+DRV, 0xE0);
|
|
outb(baseport+LBAlo,0x55);
|
|
if(inb(baseport+LBAlo)==0x55) {
|
|
existent|=1;
|
|
numDevices++;
|
|
}
|
|
// Checking existence of the slave
|
|
outb(baseport+DRV, 0xF0);
|
|
outb(baseport+LBAlo,0x55);
|
|
if(inb(baseport+LBAlo)==0x55) {
|
|
existent|=2;
|
|
numDevices++;
|
|
}
|
|
} else {
|
|
//err << "ATA device could not be found!\n";
|
|
}
|
|
outb(baseport+ALTCMD,0x40);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
outb(baseport+ALTCMD,0x00);
|
|
}
|
|
auto IDE::getDriveCnt() -> int32_t {return numDevices;}
|
|
auto IDE::getDriveNumByName(const char* name) -> int32_t {
|
|
if(strlen(name)!=5)
|
|
return -1; //Format is ATA[0-3][sm] (regex)
|
|
if((name[0]!=name[2])||(name[2]!='A'))
|
|
return -1;
|
|
if(name[1]!='T')
|
|
return -1;
|
|
int32_t drivenum=name[3]-0x30;
|
|
if(drivenum!=num)
|
|
return -1;
|
|
if((name[4]!='s')&&(name[4]!='m'))
|
|
return -1;
|
|
drivenum<<=1;
|
|
drivenum+=(name[4]=='s')?1:0;
|
|
if(!(existent&(1<<drivenum)))
|
|
return -1;
|
|
return drivenum;
|
|
}
|
|
auto IDE::readSector(int32_t drive, uint64_t sectorNum, uint8_t *buf) -> void {
|
|
if(drive<(num*2)||drive>(num*2+1))
|
|
return;
|
|
if(!(existent&(1<<(drive-num*2))))
|
|
return;
|
|
while(inb(baseport+ALTCMD)&ATAPIO_BSY);
|
|
outb(baseport+DRV, 0x40 | (drive&1)<<4);
|
|
outb(baseport+SECTOR_CNT, 0);
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum>>24));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>32));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>40));
|
|
outb(baseport+SECTOR_CNT, 1);
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>8));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>16));
|
|
outb(baseport+CMD, 0x24);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
while(inb(baseport+CMD)&0x80);
|
|
uint16_t *bufw=(uint16_t *)buf;
|
|
asm volatile ("rep insw" : : "D"((int)bufw),"d"(baseport),"c"(256));
|
|
}
|
|
auto IDE::readSector(int32_t drive, uint64_t sectorNum, uint32_t num, uint8_t *buf) -> void {
|
|
if(drive<(this->num*2)||drive>(this->num*2+1))
|
|
return;
|
|
if(!(existent&(1<<(drive-this->num*2))))
|
|
return;
|
|
if(num==0)
|
|
return;
|
|
if(num>65536)
|
|
return;
|
|
if(num==65536)
|
|
num=0;
|
|
while(inb(baseport+ALTCMD)&ATAPIO_BSY);
|
|
outb(baseport+DRV, 0x40 | (drive&1)<<4);
|
|
outb(baseport+SECTOR_CNT, (uint8_t)(num >> 8));
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum>>24));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>32));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>40));
|
|
outb(baseport+SECTOR_CNT, (uint8_t)num);
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>8));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>16));
|
|
outb(baseport+CMD, 0x24);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
while(inb(baseport+CMD)&0x80);
|
|
uint16_t *bufw=(uint16_t *)buf;
|
|
asm volatile ("rep insw" : : "D"((int)bufw),"d"(baseport),"c"(256*num));
|
|
}
|
|
auto IDE::writeSector(int32_t drive, uint64_t sectorNum, uint8_t *buf) -> void {
|
|
if(drive<(this->num*2)||drive>(this->num*2+1))
|
|
return;
|
|
if(!(existent&(1<<(drive-this->num*2))))
|
|
return;
|
|
while(inb(baseport+ALTCMD)&ATAPIO_BSY);
|
|
outb(baseport+SECTOR_CNT, (uint8_t)(0));
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum>>24));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>32));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>40));
|
|
outb(baseport+SECTOR_CNT, (uint8_t)1);
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>8));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>16));
|
|
outb(baseport+CMD, 0x34);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
while(inb(baseport+CMD)&ATAPIO_BSY);
|
|
for(int i=0;i<256;i++) {
|
|
asm volatile("outsw; aad" : : "S"((int)buf),"d"(baseport),"a"(8787)); //The AAD is for creating a short delay between writes, as the compiler might unroll this loop.
|
|
}
|
|
}
|
|
auto IDE::writeSector(int32_t drive, uint64_t sectorNum, uint32_t num, uint8_t *buf) -> void {
|
|
if(drive<(this->num*2)||drive>(this->num*2+1))
|
|
return;
|
|
if(!(existent&(1<<(drive-this->num*2))))
|
|
return;
|
|
if(num==0)
|
|
return;
|
|
if(num>65536)
|
|
return;
|
|
if(num==65536)
|
|
num=0;
|
|
while(inb(baseport+ALTCMD)&ATAPIO_BSY);
|
|
outb(baseport+SECTOR_CNT, (uint8_t)(num >> 8));
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum>>24));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>32));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>40));
|
|
outb(baseport+SECTOR_CNT, (uint8_t)num);
|
|
outb(baseport+LBAlo, (uint8_t)(sectorNum));
|
|
outb(baseport+LBAmid, (uint8_t)(sectorNum>>8));
|
|
outb(baseport+LBAhi, (uint8_t)(sectorNum>>16));
|
|
outb(baseport+CMD, 0x34);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
inb(baseport+CMD);
|
|
while(inb(baseport+CMD)&ATAPIO_BSY);
|
|
for(uint32_t i=0;i<(num<<8);i++) {
|
|
asm volatile("outsw; aad" : : "S"((int)buf),"d"(baseport),"a"(8787)); //The AAD is for creating a short delay between writes, as the compiler might partially unroll this loop.
|
|
}
|
|
}
|
|
}
|