ata #2
@ -12,6 +12,11 @@ static inline void outb(uint16_t port, uint8_t val)
|
|||||||
* number a wider C type */
|
* number a wider C type */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void outw(uint16_t port, int16_t val)
|
||||||
|
{
|
||||||
|
asm volatile("outw %w0, %w1" :: "a"(val), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t inb(uint16_t port)
|
static inline uint8_t inb(uint16_t port)
|
||||||
{
|
{
|
||||||
uint8_t ret;
|
uint8_t ret;
|
||||||
|
101
drivers/ata.c
101
drivers/ata.c
@ -395,7 +395,8 @@ static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{
|
|||||||
int ATADetectDevice(struct ata_device *dev)
|
int ATADetectDevice(struct ata_device *dev)
|
||||||
{
|
{
|
||||||
struct ata_controller *ctl = dev->ctl;
|
struct ata_controller *ctl = dev->ctl;
|
||||||
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER);
|
outb(ctl->base + ATA_PIO_DRIVE,
|
||||||
|
ATA_PIO_DRIVE_IBM | dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER);
|
||||||
unsigned st = inb(ctl->base + ATA_PIO_STATUS);
|
unsigned st = inb(ctl->base + ATA_PIO_STATUS);
|
||||||
if (st & ATA_PIO_STATUS_DRIVE_BUSY)
|
if (st & ATA_PIO_STATUS_DRIVE_BUSY)
|
||||||
goto no_disk;
|
goto no_disk;
|
||||||
@ -427,7 +428,8 @@ int ATAGetDeviceInfo(struct ata_device *dev)
|
|||||||
struct ata_controller *ctl = dev->ctl;
|
struct ata_controller *ctl = dev->ctl;
|
||||||
struct _IDENTIFY_DEVICE_DATA *deviceInfo;
|
struct _IDENTIFY_DEVICE_DATA *deviceInfo;
|
||||||
|
|
||||||
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER);
|
outb(ctl->base + ATA_PIO_DRIVE,
|
||||||
|
ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER));
|
||||||
outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY);
|
outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY);
|
||||||
|
|
||||||
/* Wait for command completion (wait while busy bit is set) */
|
/* Wait for command completion (wait while busy bit is set) */
|
||||||
@ -459,12 +461,13 @@ int ATAGetDeviceInfo(struct ata_device *dev)
|
|||||||
int ATADetectController(struct ata_controller *controller)
|
int ATADetectController(struct ata_controller *controller)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
mutexInit(&controller[0].mutex);
|
||||||
|
mutexInit(&controller[1].mutex);
|
||||||
controller->devices[0].id = 0;
|
controller->devices[0].id = 0;
|
||||||
controller->devices[0].isSlave = 0;
|
controller->devices[0].isSlave = 0;
|
||||||
controller->devices[0].ctl = controller;
|
controller->devices[0].ctl = controller;
|
||||||
controller->devices[0].type = ATADetectDevice(&controllers->devices[0]);
|
controller->devices[0].type = ATADetectDevice(&controllers->devices[0]);
|
||||||
|
|
||||||
|
|
||||||
if (controller->devices[0].type == ATA_DEV_PATA ||
|
if (controller->devices[0].type == ATA_DEV_PATA ||
|
||||||
controller->devices[0].type == ATA_DEV_SATA) {
|
controller->devices[0].type == ATA_DEV_SATA) {
|
||||||
ATAGetDeviceInfo(&controller->devices[0]);
|
ATAGetDeviceInfo(&controller->devices[0]);
|
||||||
@ -491,35 +494,111 @@ int ATAInit()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ATARead(struct ata_device *dev, int lba, int size, void *buf)
|
int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf)
|
||||||
{
|
{
|
||||||
struct ata_controller *ctl = dev->ctl;
|
struct ata_controller *ctl = dev->ctl;
|
||||||
uint nb_block = DIV_ROUND_UP(size, DISK_SECTOR_SIZE);
|
|
||||||
|
|
||||||
mutexLock(&ctl->mutex);
|
mutexLock(&ctl->mutex);
|
||||||
|
|
||||||
if (ctl->last_device_used != dev->id) {
|
if (ctl->last_device_used != dev->id) {
|
||||||
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4);
|
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4);
|
||||||
while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY);
|
while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) {
|
||||||
|
}
|
||||||
ctl->last_device_used = dev->id;
|
ctl->last_device_used = dev->id;
|
||||||
}
|
}
|
||||||
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA);
|
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA);
|
||||||
outb(ctl->base + ATA_PIO_SEC_COUNT, nb_block);
|
outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector);
|
||||||
outb(ctl->base + ATA_PIO_LBALO, lba & 0xff);
|
outb(ctl->base + ATA_PIO_LBALO, lba & 0xff);
|
||||||
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
|
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
|
||||||
outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff);
|
outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff);
|
||||||
|
outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_READ);
|
||||||
|
|
||||||
uint16_t *ptr = (uint16_t *)buf;
|
uint16_t *ptr = (uint16_t *)buf;
|
||||||
for(uint block = 0; block < nb_block ; block ++){
|
for (uint sector = 0; sector < nb_sector; sector++) {
|
||||||
while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY);
|
while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) {
|
||||||
for(int i = 0; i< 256 && size >0; i++, size --){
|
}
|
||||||
|
if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) {
|
||||||
|
mutexUnlock(&ctl->mutex);
|
||||||
|
printf("ATA read error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) {
|
||||||
*ptr = inw(ctl->base + ATA_PIO_DATA);
|
*ptr = inw(ctl->base + ATA_PIO_DATA);
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutexUnlock(&ctl->mutex);
|
mutexUnlock(&ctl->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf)
|
||||||
|
{
|
||||||
|
struct ata_controller *ctl = dev->ctl;
|
||||||
|
|
||||||
|
mutexLock(&ctl->mutex);
|
||||||
|
|
||||||
|
if (ctl->last_device_used != dev->id) {
|
||||||
|
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4);
|
||||||
|
while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) {
|
||||||
|
}
|
||||||
|
ctl->last_device_used = dev->id;
|
||||||
|
}
|
||||||
|
outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA);
|
||||||
|
outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector);
|
||||||
|
outb(ctl->base + ATA_PIO_LBALO, lba & 0xff);
|
||||||
|
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
|
||||||
|
outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff);
|
||||||
|
outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_WRITE);
|
||||||
|
|
||||||
|
uint16_t *ptr = (uint16_t *)buf;
|
||||||
|
for (uint sector = 0; sector < nb_sector; sector++) {
|
||||||
|
while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) {
|
||||||
|
}
|
||||||
|
if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) {
|
||||||
|
mutexUnlock(&ctl->mutex);
|
||||||
|
printf("ATA write error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
int status = inb(ctl->base + ATA_PIO_STATUS);
|
||||||
|
if (status & ATA_PIO_STATUS_REG_ERR) {
|
||||||
|
mutexUnlock(&ctl->mutex);
|
||||||
|
printf("ATA write error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((status & ATA_PIO_STATUS_DRQ) &&
|
||||||
|
!(status & ATA_PIO_STATUS_DRIVE_BUSY))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) {
|
||||||
|
outw(ctl->base + ATA_PIO_DATA, *ptr++);
|
||||||
|
}
|
||||||
|
// Wait for the device to receive the data
|
||||||
|
while (1) {
|
||||||
|
int status = inb(ctl->base + ATA_PIO_STATUS);
|
||||||
|
if (status & ATA_PIO_STATUS_REG_ERR) {
|
||||||
|
mutexUnlock(&ctl->mutex);
|
||||||
|
printf("ATA write error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!(status & ATA_PIO_STATUS_DRQ) &&
|
||||||
|
!(status & ATA_PIO_STATUS_DRIVE_BUSY))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutexUnlock(&ctl->mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ata_device *ATAGetDevice(int ctlId, int devId)
|
||||||
|
{
|
||||||
|
if (ctlId >= MAX_ATA_CONTROLLER)
|
||||||
|
return NULL;
|
||||||
|
if (devId >= MAX_ATA_DEVICES)
|
||||||
|
return NULL;
|
||||||
|
return &controllers[ctlId].devices[devId];
|
||||||
|
}
|
||||||
|
@ -84,3 +84,6 @@ struct ata_controller {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int ATAInit();
|
int ATAInit();
|
||||||
|
int ATAReadSector(struct ata_device *dev, int lba, uint nbSector, void *buf);
|
||||||
|
int ATAWriteSector(struct ata_device *dev, int lba, uint nbSector, void *buf);
|
||||||
|
struct ata_device *ATAGetDevice(int ctlId, int devId);
|
||||||
|
22
tests/test.c
22
tests/test.c
@ -1,4 +1,5 @@
|
|||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
|
#include "ata.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cpu_context.h"
|
#include "cpu_context.h"
|
||||||
#include "klibc.h"
|
#include "klibc.h"
|
||||||
@ -338,8 +339,29 @@ void testKthread()
|
|||||||
kthreadCreate("mtest3", mutThread, "mut3");
|
kthreadCreate("mtest3", mutThread, "mut3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testATAThread(){
|
||||||
|
uint16_t buf[DISK_SECTOR_SIZE/2];
|
||||||
|
struct ata_device *dev = ATAGetDevice(0, 0);
|
||||||
|
if(dev != NULL){
|
||||||
|
ATAReadSector(dev, 0, 1, buf);
|
||||||
|
printf("Reading from disk 0x%x 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2], buf[3]);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
buf[0]= 0x1;
|
||||||
|
buf[1]= 0x2;
|
||||||
|
buf[2]= 0x3;
|
||||||
|
buf[3]= 0x4;
|
||||||
|
ATAWriteSector(dev, 0, 1, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testATA(){
|
||||||
|
kthreadCreate("ATA_TEST", testATAThread, NULL);
|
||||||
|
//testATAThread();
|
||||||
|
}
|
||||||
|
|
||||||
void run_test(void)
|
void run_test(void)
|
||||||
{
|
{
|
||||||
|
testATA();
|
||||||
testMemcpyPerf();
|
testMemcpyPerf();
|
||||||
{
|
{
|
||||||
int test = 1000;
|
int test = 1000;
|
||||||
|
Loading…
Reference in New Issue
Block a user