summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
authordzwdz2021-10-08 13:06:42 +0000
committerdzwdz2021-10-08 13:06:42 +0000
commit0c000a03560eeab06154c1fb80b7a59a5c0f9ac7 (patch)
tree7b6d02f6aa18540964e8fd010392e05e72645209 /src/kernel/arch
parent574d2cf63006cabbf9db4a80c55a407b5b33a700 (diff)
ata: proper drive type detection; soft reset; 400ns delay function
Diffstat (limited to 'src/kernel/arch')
-rw-r--r--src/kernel/arch/i386/ata.c67
1 files changed, 49 insertions, 18 deletions
diff --git a/src/kernel/arch/i386/ata.c b/src/kernel/arch/i386/ata.c
index 4bc4293..916b918 100644
--- a/src/kernel/arch/i386/ata.c
+++ b/src/kernel/arch/i386/ata.c
@@ -20,6 +20,10 @@ enum {
DRV = 6,
CMD = 7,
STATUS = 7,
+
+ /* note: the OSDev wiki uses a different base port for the control port
+ * however i can just use this offset and stuff will just work tm */
+ CTRL = 0x206,
}; // offsets
// get I/O port base for drive
@@ -28,6 +32,12 @@ static uint16_t ata_iobase(int drive) {
return secondary ? 0x170 : 0x1F0;
}
+static void ata_400ns(void) {
+ uint16_t base = ata_iobase(0); // doesn't matter
+ for (int i = 0; i < 4; i++)
+ port_in8(base + STATUS);
+}
+
static void ata_driveselect(int drive, int block) {
uint8_t v = 0xE0;
if (drive&1) // slave?
@@ -36,6 +46,38 @@ static void ata_driveselect(int drive, int block) {
port_out8(ata_iobase(drive) + DRV, v);
}
+static void ata_softreset(int drive) {
+ uint16_t iobase = ata_iobase(drive);
+ port_out8(iobase + CTRL, 4);
+ port_out8(iobase + CTRL, 0);
+ ata_400ns();
+
+ uint16_t timeout = 10000;
+ while (--timeout) { // TODO separate polling function
+ uint8_t v = port_in8(iobase + STATUS);
+ if (v & 0x80) continue; // still BSY, continue
+ if (v & 0x40) break; // RDY, break
+ // TODO check for ERR
+ }
+}
+
+static void ata_detecttype(int drive) {
+ ata_softreset(drive);
+ ata_driveselect(drive, 0);
+ ata_400ns();
+ switch (port_in8(ata_iobase(drive) + LBAmid)) {
+ case 0:
+ ata_drives[drive].type = DEV_PATA;
+ break;
+ case 0x14:
+ ata_drives[drive].type = DEV_PATAPI;
+ return true;
+ default:
+ ata_drives[drive].type = DEV_UNKNOWN;
+ return false;
+ }
+}
+
static bool ata_identify(int drive) {
uint16_t iobase = ata_iobase(drive);
uint16_t data[256];
@@ -52,19 +94,6 @@ static bool ata_identify(int drive) {
if (v == 0) return false; // nonexistent drive
while (port_in8(iobase + STATUS) & 0x80);
- /* detect device type */
- switch (port_in8(iobase + LBAmid)) {
- case 0:
- ata_drives[drive].type = DEV_PATA;
- break;
- case 0x14:
- ata_drives[drive].type = DEV_PATAPI;
- return true;
- default:
- ata_drives[drive].type = DEV_UNKNOWN;
- return false;
- }
-
/* pool until bit 3 (DRQ) or 0 (ERR) is set */
while (!((v = port_in8(iobase + STATUS) & 0x9)));
if (v & 1) return false; /* ERR was set, bail */
@@ -80,11 +109,13 @@ void ata_init(void) {
for (int i = 0; i < 4; i++) {
tty_const("probing drive ");
_tty_var(i);
- if (ata_identify(i)) {
- tty_const(" - ");
- _tty_var(ata_drives[i].sectors);
- tty_const(" sectors (512b)");
- }
+ ata_detecttype(i);
+ _tty_var(ata_drives[i].type);
+ // if (ata_identify(i)) {
+ // tty_const(" - ");
+ // _tty_var(ata_drives[i].sectors);
+ // tty_const(" sectors (512b)");
+ // }
tty_const("\n");
}
}