# HG changeset patch # User John Tsiombikas # Date 1323259391 -7200 # Node ID 379332fc16678150ad18bfca9057848962706168 # Parent 5fb7ad5967a8459167d18685eeabb9f9c437c222 implementing ata read/write diff -r 5fb7ad5967a8 -r 379332fc1667 src/ata.c --- a/src/ata.c Wed Dec 07 06:58:05 2011 +0000 +++ b/src/ata.c Wed Dec 07 14:03:11 2011 +0200 @@ -7,6 +7,7 @@ #include "ata.h" #include "intr.h" #include "asmops.h" +#include "mutex.h" /* registers */ #define REG_DATA 0 /* R/W */ @@ -31,9 +32,14 @@ /* device select bit in control register */ #define DEV_SEL(x) (((x) & 1) << 4) +#define DEV_LBA (1 << 6) /* ATA commands */ #define CMD_IDENTIFY 0xec +#define CMD_READ 0x20 +#define CMD_READ48 0x24 +#define CMD_WRITE 0x30 +#define CMD_WRITE48 0x34 struct device { @@ -69,7 +75,14 @@ */ #define MAX_IFACES 2 #define MAX_DEV (MAX_IFACES * 2) -static struct device dev[MAX_DEV]; +static struct device devices[MAX_DEV]; + +static int use_irq; + +/* This serves as a sync point for I/O. While the mutex is held, + * some process is doing I/O and all the others must wait. + */ +static mutex_t pending; void init_ata(void) @@ -82,10 +95,87 @@ int iface = i / MAX_IFACES; int id = i % MAX_IFACES; - if(identify(dev + i, iface, id) == -1) { - dev[i].id = -1; + if(identify(devices + i, iface, id) == -1) { + devices[i].id = -1; } } + + /* init code done, from now on use the irq sleep/wakeup mechanism */ + use_irq = 1; +} + +int ata_read_pio(int devno, uint64_t sect, void *buf) +{ + int cmd, st, res = -1; + uint32_t sect_low; + struct device *dev = device + devno; + + if(dev->id == -1) { + return -1; + } + + if(use_irq) { + /* wait for the interface to become available */ + mutex_lock(&pending); + } + + select_dev(dev); + + /* LBA48 requires the high-order bits first */ + if(sect >= dev->nsect_lba) { + uint32_t sect_high = (uint32_t)(sect >> 24); + sect_low = (uint32_t)sect & 0xffffff; + + if(sect >= dev->nsect_lba48) { + goto end; + } + cmd = CMD_READ48; + + write_reg8(dev, REG_COUNT, 0); + write_reg8(dev, REG_LBA0, sect_high & 0xff); + write_reg8(dev, REG_LBA1, (sect_high >> 8) & 0xff); + write_reg8(dev, REG_LBA2, (sect_high >> 16) & 0xff); + } else { + cmd = CMD_READ; + sect_low = (uint32_t)sect & 0xffffff; + } + + write_reg8(dev, REG_COUNT, 1); + write_reg8(dev, REG_LBA0, sect_low & 0xff); + write_reg8(dev, REG_LBA1, (sect_low >> 8) & 0xff); + write_reg8(dev, REG_LBA2, (sect_low >> 16) & 0xff); + write_reg8(dev, REG_DEVICE, ((sect_low >> 24) & 0xf) | DEV_LBA | DEV_SEL(dev->id)) + /* execute */ + write_reg8(dev, REG_CMD, cmd); + + /* wait for the data to become available */ + do { + if(use_irq) { + /* also sleep on the mutex if we're called from userspace */ + wait(&pending); + } + } while((st = read_reg8(dev, REG_ALTSTAT)) & (ST_DRQ | ST_ERR) == 0); + + if(st & ST_ERR) { + print_error(); + goto end; + } + + /* read the data and we're done */ + read_data(dev, buf); + res = 0; +end: + if(use_irq) { + mutex_unlock(&pending); + } + return res; +} + +int ata_write_pio(int devno, uint64_t sect, void *buf) +{ + if(dev[devno].id == -1) { + return -1; + } } static int identify(struct device *dev, int iface, int id) @@ -106,8 +196,6 @@ } select_dev(dev); - /* wait a bit to allow the device time to respond */ - iodelay(); iodelay(); iodelay(); iodelay(); write_reg8(dev, REG_CMD, CMD_IDENTIFY); @@ -161,6 +249,9 @@ /* set the correct device bit to the device register */ write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id)); + + /* wait a bit to allow the device time to respond */ + iodelay(); iodelay(); iodelay(); iodelay(); } static int wait_busy(struct device *dev) diff -r 5fb7ad5967a8 -r 379332fc1667 src/ata.h --- a/src/ata.h Wed Dec 07 06:58:05 2011 +0000 +++ b/src/ata.h Wed Dec 07 14:03:11 2011 +0200 @@ -3,4 +3,7 @@ void init_ata(void); +int ata_read_pio(int devno, uint64_t sect, void *buf); +int ata_write_pio(int devno, uint64_t sect, void *buf); + #endif /* ATA_H_ */ diff -r 5fb7ad5967a8 -r 379332fc1667 src/mutex.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mutex.c Wed Dec 07 14:03:11 2011 +0200 @@ -0,0 +1,45 @@ +#include +#include "mutex.h" +#include "sched.h" +#include "intr.h" + +void mutex_lock(mutex_t *m) +{ + int istate = get_intr_state(); + disable_intr(); + + /* sleep while the mutex is held */ + while(*m > 0) { + wait(m); + } + /* then grab it... */ + (*m)++; + + set_intr_state(istate); +} + +void mutex_unlock(mutex_t *m) +{ + int istate = get_intr_state(); + disable_intr(); + + assert(*m); + /* release the mutex and wakeup everyone waiting on it */ + (*m)--; + wakeup(m); + + set_intr_state(istate); +} + +int mutex_trylock(mutex_t *m) +{ + int res = -1, istate = get_intr_state(); + disable_intr(); + + if(*m == 0) { + (*m)++; + res = 0; + } + set_intr_state(istate); + return res; +} diff -r 5fb7ad5967a8 -r 379332fc1667 src/mutex.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mutex.h Wed Dec 07 14:03:11 2011 +0200 @@ -0,0 +1,11 @@ +#ifndef MUTEX_H_ +#define MUTEX_H_ + +typedef unsigned int mutex_t; + +void mutex_lock(mutex_t *m); +void mutex_unlock(mutex_t *m); + +int mutex_trylock(mutex_t *m); + +#endif /* MUTEX_H_ */ diff -r 5fb7ad5967a8 -r 379332fc1667 src/rbtree.h --- a/src/rbtree.h Wed Dec 07 06:58:05 2011 +0000 +++ b/src/rbtree.h Wed Dec 07 14:03:11 2011 +0200 @@ -1,6 +1,8 @@ #ifndef RBTREE_H_ #define RBTREE_H_ +#include /* for size_t */ + struct rbtree; struct rbnode;