BarryServer : Git

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

// Related

Nucleus

Barry Driver core e4c4dfe (3 years, 2 months ago)
diff --git a/drivers/storage/ata.c b/drivers/storage/ata.c
new file mode 100644
index 0000000..4d26ab2
--- /dev/null
+++ b/drivers/storage/ata.c
@@ -0,0 +1,209 @@
+/*
+ * This is the driver for ATA storage devices.  It controls access to the drives
+ * and contains the devfs functions.  It uses the IDE driver for access to the
+ * actual hardware.
+ */
+
+#include <stdint.h>
+#include <io.h>
+#include <nucleus/panic.h>
+#include <nucleus/vfs.h>
+#include "ide.h"
+
+/* Structure for a MBR Partition entry */
+struct Partition {
+	uint8_t drive;
+	uint8_t shead, ssect, scyl;
+	uint8_t type;
+	uint8_t ehead, esect, ecyl;
+	uint32_t lba;
+	uint32_t size;
+};
+
+size_t ata_dev_read(File *file, char *buf, size_t size, off_t offset);
+size_t ata_dev_write(File *file, char *buf, size_t size, off_t offset);
+
+FileOps ataFileOps = {
+	.read = ata_dev_read,
+	.write = ata_dev_write,
+};
+
+/* Access an ATA drive */
+static uint8_t
+ata_access(int write, struct IDEDevice *dev, uint32_t lba, uint8_t sectors,
+           void *buf)
+{
+	struct IDEChannelRegs *channel = &ideChannels[dev->channel];
+	uint8_t lbaMode, dma, cmd;
+	uint8_t lbaIO[6];
+	uint16_t cyl, i;
+	uint8_t head, sect, err;
+
+//	ideIrqInvoked = 0;
+	channel->noint = 2;
+	ide_write(dev->channel, IDE_REG_CONTROL, channel->noint);
+
+	/* Configure access mode */
+	if (lba >= 0x10000000) {
+		lbaMode = LBA_48;
+		lbaIO[0] = (lba & 0x000000FF) >> 0;
+		lbaIO[1] = (lba & 0x0000FF00) >> 8;
+		lbaIO[2] = (lba & 0x00FF0000) >> 16;
+		lbaIO[3] = (lba & 0xFF000000) >> 24;
+		lbaIO[4] = 0;
+		lbaIO[5] = 0;
+		head = 0;
+	} else if (dev->capabilities & 0x200) {
+		lbaMode = LBA_28;
+		lbaIO[0] = (lba & 0x000000FF) >> 0;
+		lbaIO[1] = (lba & 0x0000FF00) >> 8;
+		lbaIO[2] = (lba & 0x00FF0000) >> 16;
+		lbaIO[3] = 0;
+		lbaIO[4] = 0;
+		lbaIO[5] = 0;
+		head = (lba & 0x0F000000) >> 24;
+	} else {
+		lbaMode = LBA_CHS;
+		sect = (lba % 63) + 1;
+		cyl = (lba + 1 - sect) / (16 * 63);
+		lbaIO[0] = sect;
+		lbaIO[1] = (cyl >> 0) & 0xFF;
+		lbaIO[2] = (cyl >> 8) & 0xFF;
+		lbaIO[3] = 0;
+		lbaIO[4] = 0;
+		lbaIO[5] = 0;
+		head = (lba + 1 - sect) % (16 * 63) / 63;
+	}
+
+	dma = 0; //dev->busmaster;
+
+	/* Wait for device to become available */
+	while (ide_read(dev->channel, IDE_REG_STATUS) & IDE_SR_BUSY);
+
+	/* Select drive */
+	if (lbaMode == LBA_CHS)
+		ide_write(dev->channel, IDE_REG_HDDEVSEL,
+		          0xA0 | (dev->drive << 4) | head);
+	else
+		ide_write(dev->channel, IDE_REG_HDDEVSEL,
+		          0xE0 | (dev->drive << 4) | head);
+
+	/* Specify sectors to read */
+	if (lbaMode = LBA_48) {
+		ide_write(dev->channel, IDE_REG_SECCOUNT1, 0);
+		ide_write(dev->channel, IDE_REG_LBA3, lbaIO[3]);
+		ide_write(dev->channel, IDE_REG_LBA4, lbaIO[4]);
+		ide_write(dev->channel, IDE_REG_LBA5, lbaIO[5]);
+	}
+	ide_write(dev->channel, IDE_REG_SECCOUNT0, sectors);
+	ide_write(dev->channel, IDE_REG_LBA0, lbaIO[0]);
+	ide_write(dev->channel, IDE_REG_LBA1, lbaIO[1]);
+	ide_write(dev->channel, IDE_REG_LBA2, lbaIO[2]);
+
+	/* Send command */
+	if (lbaMode == LBA_CHS && !dma && !write) cmd = IDE_CMD_READ_PIO;
+	if (lbaMode == LBA_28  && !dma && !write) cmd = IDE_CMD_READ_PIO;
+	if (lbaMode == LBA_48  && !dma && !write) cmd = IDE_CMD_READ_PIO_EXT;
+	if (lbaMode == LBA_CHS &&  dma && !write) cmd = IDE_CMD_READ_DMA;
+	if (lbaMode == LBA_28  &&  dma && !write) cmd = IDE_CMD_READ_DMA;
+	if (lbaMode == LBA_48  &&  dma && !write) cmd = IDE_CMD_READ_DMA_EXT;
+	if (lbaMode == LBA_CHS && !dma &&  write) cmd = IDE_CMD_WRITE_PIO;
+	if (lbaMode == LBA_28  && !dma &&  write) cmd = IDE_CMD_WRITE_PIO;
+	if (lbaMode == LBA_48  && !dma &&  write) cmd = IDE_CMD_WRITE_PIO_EXT;
+	if (lbaMode == LBA_CHS &&  dma &&  write) cmd = IDE_CMD_WRITE_DMA;
+	if (lbaMode == LBA_28  &&  dma &&  write) cmd = IDE_CMD_WRITE_DMA;
+	if (lbaMode == LBA_48  &&  dma &&  write) cmd = IDE_CMD_WRITE_DMA_EXT;
+	ide_write(dev->channel, IDE_REG_COMMAND, cmd);
+
+	/* Read/Write data */
+	if (dma) {
+		/* Use DMA */
+		if (write) {
+			/* TODO */
+		} else {
+			/* TODO */
+		}
+	} else {
+		/* Use PIO */
+		if (write) {
+			for (i = 0; i < sectors; i++) {
+				ide_poll_status(dev->channel, 0);
+				outsw(channel->base, buf + (i * 512), 256);
+			}
+			ide_write(dev->channel, IDE_REG_COMMAND,
+			          (lbaMode == LBA_48)
+			          ? IDE_CMD_CACHE_FLUSH_EXT
+			          : IDE_CMD_CACHE_FLUSH);
+			ide_poll_status(dev->channel, 0);
+		} else {
+			for (i = 0; i < sectors; i++) {
+				if (err = ide_poll_status(dev->channel, 1))
+					return err;
+				insw(channel->base, buf + (i * 512), 256);
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Read from an ATA drive */
+static inline uint8_t
+ata_read(struct IDEDevice *dev, uint32_t lba, uint8_t sectors, void *buf)
+{
+	ata_access(0, dev, lba, sectors, buf);
+}
+
+/* Write to an ATA drive */
+static inline uint8_t
+ata_write(struct IDEDevice *dev, uint32_t lba, uint8_t sectors, void *buf)
+{
+	ata_access(1, dev, lba, sectors, buf);
+}
+
+/* Initialise an ATA drive */
+void
+ata_init(struct IDEDevice *dev)
+{
+	static int drive = 0;
+	static void *ataDmaArea = NULL;
+	if (!ataDmaArea)
+		ataDmaArea = (void *) alloc_frame();
+
+	/* Create device node */
+	char name[16];
+	sprintf(name, "/dev/hd%d", drive);
+//	mknod(name, S_IFBLK | 0600, MKDEV());
+	kprintf("  ATA drive [%s] (%d MB) %s", name,
+	        dev->size / 1024 / 2, dev->model);
+
+	/* Attempt to read partition table */
+	int i;
+	struct Partition *part = ataDmaArea + 446;
+	if (ata_read(dev, 0, 1, ataDmaArea))
+		return;
+	for (i = 0; i < 4; i++) {
+		if (!part[i].type)
+			continue;
+		sprintf(name, "/dev/hd%dp%d", drive, i);
+//		mknod(name, S_IFBLK | 0600, MKDEV(ideDriver.major, ());
+		kprintf("    Partition [%s] %#.8x - %#.8x", name,
+		        part[i].lba*512, (part[i].lba + part[i].size) * 512);
+	}
+
+	drive++;
+}
+
+/* Read from an ATA drive */
+size_t
+ata_dev_read(File *file, char *buf, size_t size, off_t offset)
+{
+	
+}
+
+/* Write to an ATA drive */
+size_t
+ata_dev_write(File *file, char *buf, size_t size, off_t offset)
+{
+	
+}