kern
changeset 86:379332fc1667
implementing ata read/write
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 07 Dec 2011 14:03:11 +0200 |
parents | 5fb7ad5967a8 |
children | 178d5a95e6de |
files | src/ata.c src/ata.h src/mutex.c src/mutex.h src/rbtree.h |
diffstat | 5 files changed, 157 insertions(+), 5 deletions(-) [+] |
line diff
1.1 --- a/src/ata.c Wed Dec 07 06:58:05 2011 +0000 1.2 +++ b/src/ata.c Wed Dec 07 14:03:11 2011 +0200 1.3 @@ -7,6 +7,7 @@ 1.4 #include "ata.h" 1.5 #include "intr.h" 1.6 #include "asmops.h" 1.7 +#include "mutex.h" 1.8 1.9 /* registers */ 1.10 #define REG_DATA 0 /* R/W */ 1.11 @@ -31,9 +32,14 @@ 1.12 1.13 /* device select bit in control register */ 1.14 #define DEV_SEL(x) (((x) & 1) << 4) 1.15 +#define DEV_LBA (1 << 6) 1.16 1.17 /* ATA commands */ 1.18 #define CMD_IDENTIFY 0xec 1.19 +#define CMD_READ 0x20 1.20 +#define CMD_READ48 0x24 1.21 +#define CMD_WRITE 0x30 1.22 +#define CMD_WRITE48 0x34 1.23 1.24 1.25 struct device { 1.26 @@ -69,7 +75,14 @@ 1.27 */ 1.28 #define MAX_IFACES 2 1.29 #define MAX_DEV (MAX_IFACES * 2) 1.30 -static struct device dev[MAX_DEV]; 1.31 +static struct device devices[MAX_DEV]; 1.32 + 1.33 +static int use_irq; 1.34 + 1.35 +/* This serves as a sync point for I/O. While the mutex is held, 1.36 + * some process is doing I/O and all the others must wait. 1.37 + */ 1.38 +static mutex_t pending; 1.39 1.40 1.41 void init_ata(void) 1.42 @@ -82,10 +95,87 @@ 1.43 int iface = i / MAX_IFACES; 1.44 int id = i % MAX_IFACES; 1.45 1.46 - if(identify(dev + i, iface, id) == -1) { 1.47 - dev[i].id = -1; 1.48 + if(identify(devices + i, iface, id) == -1) { 1.49 + devices[i].id = -1; 1.50 } 1.51 } 1.52 + 1.53 + /* init code done, from now on use the irq sleep/wakeup mechanism */ 1.54 + use_irq = 1; 1.55 +} 1.56 + 1.57 +int ata_read_pio(int devno, uint64_t sect, void *buf) 1.58 +{ 1.59 + int cmd, st, res = -1; 1.60 + uint32_t sect_low; 1.61 + struct device *dev = device + devno; 1.62 + 1.63 + if(dev->id == -1) { 1.64 + return -1; 1.65 + } 1.66 + 1.67 + if(use_irq) { 1.68 + /* wait for the interface to become available */ 1.69 + mutex_lock(&pending); 1.70 + } 1.71 + 1.72 + select_dev(dev); 1.73 + 1.74 + /* LBA48 requires the high-order bits first */ 1.75 + if(sect >= dev->nsect_lba) { 1.76 + uint32_t sect_high = (uint32_t)(sect >> 24); 1.77 + sect_low = (uint32_t)sect & 0xffffff; 1.78 + 1.79 + if(sect >= dev->nsect_lba48) { 1.80 + goto end; 1.81 + } 1.82 + cmd = CMD_READ48; 1.83 + 1.84 + write_reg8(dev, REG_COUNT, 0); 1.85 + write_reg8(dev, REG_LBA0, sect_high & 0xff); 1.86 + write_reg8(dev, REG_LBA1, (sect_high >> 8) & 0xff); 1.87 + write_reg8(dev, REG_LBA2, (sect_high >> 16) & 0xff); 1.88 + } else { 1.89 + cmd = CMD_READ; 1.90 + sect_low = (uint32_t)sect & 0xffffff; 1.91 + } 1.92 + 1.93 + write_reg8(dev, REG_COUNT, 1); 1.94 + write_reg8(dev, REG_LBA0, sect_low & 0xff); 1.95 + write_reg8(dev, REG_LBA1, (sect_low >> 8) & 0xff); 1.96 + write_reg8(dev, REG_LBA2, (sect_low >> 16) & 0xff); 1.97 + write_reg8(dev, REG_DEVICE, ((sect_low >> 24) & 0xf) | DEV_LBA | DEV_SEL(dev->id)) 1.98 + /* execute */ 1.99 + write_reg8(dev, REG_CMD, cmd); 1.100 + 1.101 + /* wait for the data to become available */ 1.102 + do { 1.103 + if(use_irq) { 1.104 + /* also sleep on the mutex if we're called from userspace */ 1.105 + wait(&pending); 1.106 + } 1.107 + } while((st = read_reg8(dev, REG_ALTSTAT)) & (ST_DRQ | ST_ERR) == 0); 1.108 + 1.109 + if(st & ST_ERR) { 1.110 + print_error(); 1.111 + goto end; 1.112 + } 1.113 + 1.114 + /* read the data and we're done */ 1.115 + read_data(dev, buf); 1.116 + res = 0; 1.117 +end: 1.118 + if(use_irq) { 1.119 + mutex_unlock(&pending); 1.120 + } 1.121 + return res; 1.122 +} 1.123 + 1.124 +int ata_write_pio(int devno, uint64_t sect, void *buf) 1.125 +{ 1.126 + if(dev[devno].id == -1) { 1.127 + return -1; 1.128 + } 1.129 } 1.130 1.131 static int identify(struct device *dev, int iface, int id) 1.132 @@ -106,8 +196,6 @@ 1.133 } 1.134 1.135 select_dev(dev); 1.136 - /* wait a bit to allow the device time to respond */ 1.137 - iodelay(); iodelay(); iodelay(); iodelay(); 1.138 1.139 write_reg8(dev, REG_CMD, CMD_IDENTIFY); 1.140 1.141 @@ -161,6 +249,9 @@ 1.142 1.143 /* set the correct device bit to the device register */ 1.144 write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id)); 1.145 + 1.146 + /* wait a bit to allow the device time to respond */ 1.147 + iodelay(); iodelay(); iodelay(); iodelay(); 1.148 } 1.149 1.150 static int wait_busy(struct device *dev)
2.1 --- a/src/ata.h Wed Dec 07 06:58:05 2011 +0000 2.2 +++ b/src/ata.h Wed Dec 07 14:03:11 2011 +0200 2.3 @@ -3,4 +3,7 @@ 2.4 2.5 void init_ata(void); 2.6 2.7 +int ata_read_pio(int devno, uint64_t sect, void *buf); 2.8 +int ata_write_pio(int devno, uint64_t sect, void *buf); 2.9 + 2.10 #endif /* ATA_H_ */
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/mutex.c Wed Dec 07 14:03:11 2011 +0200 3.3 @@ -0,0 +1,45 @@ 3.4 +#include <assert.h> 3.5 +#include "mutex.h" 3.6 +#include "sched.h" 3.7 +#include "intr.h" 3.8 + 3.9 +void mutex_lock(mutex_t *m) 3.10 +{ 3.11 + int istate = get_intr_state(); 3.12 + disable_intr(); 3.13 + 3.14 + /* sleep while the mutex is held */ 3.15 + while(*m > 0) { 3.16 + wait(m); 3.17 + } 3.18 + /* then grab it... */ 3.19 + (*m)++; 3.20 + 3.21 + set_intr_state(istate); 3.22 +} 3.23 + 3.24 +void mutex_unlock(mutex_t *m) 3.25 +{ 3.26 + int istate = get_intr_state(); 3.27 + disable_intr(); 3.28 + 3.29 + assert(*m); 3.30 + /* release the mutex and wakeup everyone waiting on it */ 3.31 + (*m)--; 3.32 + wakeup(m); 3.33 + 3.34 + set_intr_state(istate); 3.35 +} 3.36 + 3.37 +int mutex_trylock(mutex_t *m) 3.38 +{ 3.39 + int res = -1, istate = get_intr_state(); 3.40 + disable_intr(); 3.41 + 3.42 + if(*m == 0) { 3.43 + (*m)++; 3.44 + res = 0; 3.45 + } 3.46 + set_intr_state(istate); 3.47 + return res; 3.48 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/mutex.h Wed Dec 07 14:03:11 2011 +0200 4.3 @@ -0,0 +1,11 @@ 4.4 +#ifndef MUTEX_H_ 4.5 +#define MUTEX_H_ 4.6 + 4.7 +typedef unsigned int mutex_t; 4.8 + 4.9 +void mutex_lock(mutex_t *m); 4.10 +void mutex_unlock(mutex_t *m); 4.11 + 4.12 +int mutex_trylock(mutex_t *m); 4.13 + 4.14 +#endif /* MUTEX_H_ */