Fix ata_read

This commit is contained in:
Baptiste Wicht 2013-11-03 14:50:12 +01:00
parent c5afd61093
commit 5d0273ca50
3 changed files with 105 additions and 18 deletions

View File

@ -7,12 +7,13 @@ struct drive_descriptor {
uint16_t controller;
uint8_t drive;
bool present;
uint8_t slave;
};
void detect_disks();
uint8_t number_of_disks();
drive_descriptor& drive(uint8_t disk);
void ata_read_sectors(drive_descriptor& drive, std::size_t start, uint8_t count, void* destination);
bool ata_read_sectors(drive_descriptor& drive, std::size_t start, uint8_t count, void* destination);
#endif

View File

@ -10,14 +10,17 @@ drive_descriptor* drives;
} //end of anonymous namespace
#define MASTER_BIT 0
#define SLAVE_BIT 1
void detect_disks(){
if(!detected){
drives = reinterpret_cast<drive_descriptor*>(k_malloc(4 * sizeof(drive_descriptor)));
drives[0] = {0x1F0, 0xE0, false};
drives[1] = {0x1F0, 0xF0, false};
drives[2] = {0x170, 0xE0, false};
drives[3] = {0x170, 0xF0, false};
drives[0] = {0x1F0, 0xE0, false, MASTER_BIT};
drives[1] = {0x1F0, 0xF0, false, SLAVE_BIT};
drives[2] = {0x170, 0xE0, false, MASTER_BIT};
drives[3] = {0x170, 0xF0, false, SLAVE_BIT};
for(uint8_t i = 0; i < 4; ++i){
auto& drive = drives[i];
@ -26,6 +29,8 @@ void detect_disks(){
sleep_ms(4);
drive.present = in_byte(drive.controller + 0x7) & 0x40;
}
detected = true;
}
}
@ -45,34 +50,101 @@ drive_descriptor& drive(uint8_t disk){
return drives[disk];
}
void ata_read_sectors(drive_descriptor& drive, std::size_t start, uint8_t count, void* destination){
// I/O Controllers ports
#define ATA_DATA 0
#define ATA_ERROR 1
#define ATA_NSECTOR 2
#define ATA_SECTOR 3
#define ATA_LCYL 4
#define ATA_HCYL 5
#define ATA_DRV_HEAD 6
#define ATA_STATUS 7
#define ATA_COMMAND 7
#define ATA_DEV_CTL 0x206
// Status bits
#define ATA_STATUS_BSY 0x80
#define ATA_STATUS_DRDY 0x40
#define ATA_STATUS_DRQ 0x08
#define ATA_STATUS_ERR 0x01
// Commands
#define ATA_IDENTIFY 0xEC
#define ATAPI_IDENTIFY 0xA1
#define ATA_READ_BLOCK 0x20
#define ATA_WRITE_BLOCK 0x30
//TODO MOVE to anonymous
static uint8_t wait_for_controller(uint16_t controller, uint8_t mask, uint8_t value, uint16_t timeout){
uint8_t status;
do {
status = in_byte(controller + ATA_STATUS);
sleep_ms(1);
} while ((status & mask) != value && --timeout);
return timeout;
}
bool select_device(drive_descriptor& drive){
auto controller = drive.controller;
out_byte(controller + 0x6, drive.drive | ((start >> 24) & 0x0F)); //TODO CHECK THIS
if(in_byte(controller + ATA_STATUS) & (ATA_STATUS_BSY | ATA_STATUS_DRQ)){
return false;
}
out_byte(controller + 0x1, 0x00);
out_byte(controller + 0x2, count);
out_byte(controller + ATA_DRV_HEAD, 0xA0 | (drive.slave << 4));
sleep_ms(1);
//Send the LBA28 value
out_byte(controller + 0x3, static_cast<uint8_t>(start));
out_byte(controller + 0x4, static_cast<uint8_t>(start >> 8));
out_byte(controller + 0x5, static_cast<uint8_t>(start >> 16));
//out_byte(controller + 0x6, drive | ((start >> 24) & 0x0F)); //TODO CHECK THIS
if(in_byte(controller + ATA_STATUS) & (ATA_STATUS_BSY | ATA_STATUS_DRQ)){
return false;
}
//Send the read sectors command
out_byte(controller + 0x7, 0x20);
return true;
}
bool ata_read_sectors(drive_descriptor& drive, std::size_t start, uint8_t count, void* destination){
if(!select_device(drive)){
return false;
}
auto controller = drive.controller;
uint8_t sc = start & 0xFF;
uint8_t cl = (start >> 8) & 0xFF;
uint8_t ch = (start >> 16) & 0xFF;
uint8_t hd = (start >> 24) & 0x0F;
out_byte(controller + ATA_NSECTOR, count);
out_byte(controller + ATA_SECTOR, sc);
out_byte(controller + ATA_LCYL, cl);
out_byte(controller + ATA_HCYL, ch);
out_byte(controller + ATA_DRV_HEAD, (1 << 6) | (drive.slave << 4) | hd);
out_byte(controller + ATA_COMMAND, ATA_READ_BLOCK);
sleep_ms(1);
if(!wait_for_controller(controller, ATA_STATUS_BSY, 0, 30000)){
return false;
}
if(in_byte(controller + ATA_STATUS) & ATA_STATUS_ERR){
return false;
}
uint16_t* buffer = reinterpret_cast<uint16_t*>(destination);
for(uint8_t sector = 0; sector < count; ++sector){
sleep_ms(1);
while (!(in_byte(0x1F7) & 0x08)) {
while (!(in_byte(controller + ATA_STATUS) & ATA_STATUS_DRQ)) {
__asm__ __volatile__ ("nop; nop;");
}
for(int i = 0; i < 256; ++i){
(*buffer++) = in_word(controller + 0x0);
*buffer++ = in_word(controller + ATA_DATA);
}
}
return true;
}

View File

@ -259,6 +259,20 @@ void memory_command(const char*){
k_printf("Total used memory: %m\n", used_memory());
k_printf("Total free memory: %m\n", free_memory());
}
uint16_t* buffer = reinterpret_cast<uint16_t*>(k_malloc(512));
if(!ata_read_sectors(drive(0), 2048, 1, buffer)){
k_print_line("Read failed");
} else {
for(int i = 0; i < 80; i += 8){
k_printf("%h %h %h %h %h %h %h %h\n",
buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3],
buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7]);
}
k_free(reinterpret_cast<std::size_t*>(buffer));
}
}
void disks_command(const char*){