BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / e4c4dfe6cc8f70e0d4919a434e62f1d061477add / drivers / storage / ide.c

// Related

Nucleus

Barry Driver core e4c4dfe (3 years, 2 months ago)
diff --git a/drivers/storage/ide.c b/drivers/storage/ide.c
new file mode 100644
index 0000000..0cc9253
--- /dev/null
+++ b/drivers/storage/ide.c
@@ -0,0 +1,222 @@
+/*
+ * This file is the driver for the PCI IDE devices.  It handles detecting drives
+ * and accessing them through the IDE interface.  The ATA and ATAPI drivers
+ * handle reading and writing to the devices individually through this.
+ * This driver will access the drives in the best available way, presenting a
+ * uniform interface for any other code to use.  It also adds a device node to
+ * the devfs mount for every device it finds, to provide access for the rest of
+ * the OS easily.
+ */
+
+#include <stdint.h>
+#include <io.h>
+#include <nucleus/pci.h>
+#include "ide.h"
+
+struct IDEChannelRegs ideChannels[2];
+struct IDEDevice ideDevices[4];
+uint8_t ideBuf[2048] = {0};
+int ideIrqInvoked = 0;
+
+/* Read identification space */
+static void
+ide_read_buffer(uint8_t channel, void *buffer, uint32_t dwords)
+{
+	struct IDEChannelRegs *c = &ideChannels[channel];
+	insl(c->base, buffer, dwords);
+}
+
+/* Initialise an IDE drive */
+static void
+ide_drive_init(uint32_t bar0, uint32_t bar1, uint32_t bar2, uint32_t bar3,
+               uint32_t bar4)
+{
+	ideChannels[IDE_PRIMARY].base = bar0 & ~3;
+	ideChannels[IDE_PRIMARY].ctrl = bar1 & ~3;
+	ideChannels[IDE_PRIMARY].busmaster = bar4 & ~3;
+	ideChannels[IDE_SECONDARY].base = bar2 & ~3;
+	ideChannels[IDE_SECONDARY].ctrl = bar3 & ~3;
+	ideChannels[IDE_SECONDARY].busmaster = (bar4 & ~3) + 8;
+
+	/* Disable IRQs */
+	ide_write(IDE_PRIMARY, IDE_REG_CONTROL, 2);
+	ide_write(IDE_SECONDARY, IDE_REG_CONTROL, 2);
+
+	/* Iterate all possible devices */
+	uint32_t count = 0;
+	uint8_t channel, drive, err, type, status;
+	struct IDEDevice *dev;
+	for (count = 0; count < 4; count++) {
+		dev = &ideDevices[count];
+		dev->reserved = 0;
+		channel = count / 2;
+		drive = count % 2;
+		type = IDE_ATA;
+		err = 0;
+
+		ide_write(channel, IDE_REG_HDDEVSEL, 0xA0 | (drive << 4));
+		ide_write(channel, IDE_REG_COMMAND, IDE_CMD_IDENTIFY);
+		if (ide_read(channel, IDE_REG_STATUS) == 0)
+			continue;
+
+		/* Wait for response */
+		while (1) {
+			status = ide_read(channel, IDE_REG_STATUS);
+			if ((status & IDE_SR_ERROR)) {
+				err = 1;
+				break;
+			}
+			if (!(status & IDE_SR_BUSY)
+			 && (status & IDE_SR_DATA_READY))
+				break;
+		}
+
+		/* Check type */
+		if (err) {
+			uint8_t cl = ide_read(channel, IDE_REG_LBA1);
+			uint8_t ch = ide_read(channel, IDE_REG_LBA2);
+			if (cl == 0x14 && ch == 0xEB)
+				type = IDE_ATAPI;
+			else if (cl == 0x69 && ch == 0x96)
+				type = IDE_ATAPI;
+			else
+				continue;
+
+			ide_write(channel, IDE_REG_COMMAND,
+			          IDE_CMD_IDENTIFY_PACKET);
+		}
+
+		/* Fill in IDE Device structure */
+		ide_read_buffer(channel, ideBuf, 128);
+		uint32_t size;
+		uint16_t sig, cap, set;
+		sig = *(uint16_t *) (ideBuf + IDE_IDENT_DEVICETYPE);
+		cap = *(uint16_t *) (ideBuf + IDE_IDENT_CAPABILITIES);
+		set = *(uint16_t *) (ideBuf + IDE_IDENT_COMMANDSETS);
+		if (set & (1 << 26))
+			size = *(uint32_t *) (ideBuf + IDE_IDENT_MAX_LBA_EXT);
+		else
+			size = *(uint32_t *) (ideBuf + IDE_IDENT_MAX_LBA);
+
+		dev->reserved = 1;
+		dev->type = type;
+		dev->channel = channel;
+		dev->drive = drive;
+		dev->signature = sig;
+		dev->capabilities = cap;
+		dev->commandSets = set;
+		dev->size = size;
+
+		uint32_t k;
+		for (k = 0; k < 40; k += 2) {
+			dev->model[k] = ideBuf[IDE_IDENT_MODEL + k + 1];
+			dev->model[k + 1] = ideBuf[IDE_IDENT_MODEL + k];
+		}
+		dev->model[40] = 0;
+	}
+}
+
+/* Read channel */
+uint8_t
+ide_read(uint8_t channel, uint8_t reg)
+{
+	uint8_t result;
+	struct IDEChannelRegs *c = &ideChannels[channel];
+	if (reg > 0x07 && reg < 0x0C)
+		ide_write(channel, IDE_REG_CONTROL, 0x80 | c->noint);
+	if (reg < 0x08)
+		result = inb(c->base + reg - 0);
+	else if (reg < 0x0C)
+		result = inb(c->base + reg - 6);
+	else if (reg < 0x0E)
+		result = inb(c->ctrl + reg - 10);
+	else if (reg < 0x16)
+		result = inb(c->busmaster + reg - 14);
+	if (reg > 0x07 && reg < 0x0C)
+		ide_write(channel, IDE_REG_CONTROL, c->noint);
+	return result;
+}
+
+/* Write channel */
+void
+ide_write(uint8_t channel, uint8_t reg, uint8_t data)
+{
+	struct IDEChannelRegs *c = &ideChannels[channel];
+	if (reg > 0x07 && reg < 0x0C)
+		ide_write(channel, IDE_REG_CONTROL, 0x80 | c->noint);
+	if (reg < 0x08)
+		outb(c->base + reg - 0, data);
+	else if (reg < 0x0C)
+		outb(c->base + reg - 6, data);
+	else if (reg < 0x0E)
+		outb(c->ctrl + reg - 10, data);
+	else if (reg < 0x16)
+		outb(c->busmaster + reg - 14, data);
+	if (reg > 0x07 && reg < 0x0C)
+		ide_write(channel, IDE_REG_CONTROL, c->noint);
+}
+
+/* Poll for status after command */
+uint8_t
+ide_poll_status(uint8_t channel, uint32_t check)
+{
+	uint8_t i, state;
+	/* Wait for BUSY */
+	for (i = 0; i < 4; i++)
+		ide_read(channel, IDE_REG_ALTSTATUS);
+	/* Wait for BUSY to clear */
+	while (ide_read(channel, IDE_REG_STATUS) & IDE_SR_BUSY);
+
+	/* Check the status */
+	if (check) {
+		state = ide_read(channel, IDE_REG_STATUS);
+		if (state & IDE_SR_ERROR)
+			return ERROR_GENERIC;
+		if (state & IDE_SR_WRITE_FAULT)
+			return ERROR_WRITE_FAULT;
+		if ((state & IDE_SR_DATA_READY) == 0)
+			return ERROR_NOT_READY;
+	}
+
+	return ERROR_NONE;
+}
+
+/* Initialise a PCI IDE controller */
+void
+pci_init_ide(uint8_t bus, uint8_t dev, uint8_t func)
+{
+	uint8_t class, subclass, progif, header;
+	class = pci_read_byte(bus, dev, func, 11);
+	subclass = pci_read_byte(bus, dev, func, 10);
+	progif = pci_read_byte(bus, dev, func, 9);
+	header = pci_read_byte(bus, dev, func, 14);
+
+	/* Parallel IDE defaults */
+	uint32_t bar[5] = {0x1F0, 0x3F6, 0x170, 0x376, 0x00};
+
+	/* Primary Native */
+	if (progif & (1 << 0)) {
+		bar[0] = pci_read_dword(bus, dev, func, 0x10);
+		bar[1] = pci_read_dword(bus, dev, func, 0x14);
+	}
+	/* Secondary Native */
+	if (progif & (1 << 2)) {
+		bar[2] = pci_read_dword(bus, dev, func, 0x18);
+		bar[3] = pci_read_dword(bus, dev, func, 0x1C);
+	}
+	/* Bus Master */
+	if (progif & (1 << 7))
+		bar[4] = pci_read_dword(bus, dev, func, 0x20);
+
+	ide_drive_init(bar[0], bar[1], bar[2], bar[3], bar[4]);
+
+	uint8_t i;
+	for (i = 0; i < 4; i++) {
+		if (!ideDevices[i].reserved)
+			continue;
+		if (ideDevices[i].type == IDE_ATA)
+			ata_init(&ideDevices[i]);
+//		if (ideDevices[i].type == IDE_ATAPI)
+//			atapi_init(&ideDevices[i]);
+	}
+}