kern

diff src/ata.c @ 86:379332fc1667

implementing ata read/write
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 07 Dec 2011 14:03:11 +0200
parents 4ef83db5f4cd
children 178d5a95e6de
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)