--- /dev/null
+#include <kern/devices/atapio.h>
+#include <inc/x86.h>
+#include <inc/stringformat.h>
+
+static uint8_t drive_attached = 0;
+static uint8_t current_drive = 0;
+
+void atapio_init()
+{
+ base_port = ATA_BUS1_BASE;
+
+ // Confirm if a disk drive even exists!
+ uint8_t result = inb(ATA_COMMAND_STATUS_PORT);
+ if (result == 0xFF) {
+ drive_attached = 0;
+ return;
+ }
+
+ // Reset the bus
+ _kern_print("Resetting ATA bus\n");
+ outb(ATA_DEVCONTROL, 0x04);
+ // Stall for 2ms
+ int i;
+ for (i=0; i<20; i++)
+ {
+ inb(ATA_COMMAND_STATUS_PORT);
+ }
+ outb(ATA_COMMAND_STATUS_PORT, 0x00);
+
+ // Really, we should issue an IDENTIFY command here
+ // but we'll just presume for now. Select the master
+ // disc and let it go
+
+ outb(ATA_DEVCONTROL, SELECT_MASTER_DRIVE);
+
+ // Drives may need up to 500ns for drive select to
+ // complete, and an IO read is about 100ns, so burn
+ // 400ns.
+
+ inb(ATA_COMMAND_STATUS_PORT);
+ inb(ATA_COMMAND_STATUS_PORT);
+ inb(ATA_COMMAND_STATUS_PORT);
+ inb(ATA_COMMAND_STATUS_PORT);
+
+ uint8_t cl=inb(ATA_LBAMID_PORT); /* get the "signature bytes" */
+ uint8_t ch=inb(ATA_LBAHI_PORT);
+
+ _kern_print("Read signature bytes %x and %x\n", cl, ch);
+ /* differentiate ATA, ATAPI, SATA and SATAPI */
+ if (cl==0x14 && ch==0xEB)
+ {
+ _kern_print("Detected PATAPI device on default bus and drive\n");
+ }
+ else if (cl==0x69 && ch==0x96)
+ {
+ _kern_print("Detected SATAPI device on default bus and drive\n");
+ }
+ else if (cl==0 && ch == 0)
+ {
+ _kern_print("Detected PATA device on default bus and drive\n");
+ }
+ else if (cl==0x3c && ch==0xc3)
+ {
+ _kern_print("Detected SATA device on default bus and drive\n");
+ }
+ else
+ {
+ _kern_print("UNKNOWN device on default bus and drive\n");
+ }
+
+}
+
+void atapio_read(uint32_t sector, uint32_t sector_count, char *buffer)
+{
+/*
+An example of a 28 bit LBA PIO mode read on the Primary bus:
+Send 0xE0 for the "master" or 0xF0 for the "slave", ORed with the highest 4 bits of the LBA to port 0x1F6: outb(0x1F6, 0xE0 | (slavebit << 4) | ((LBA >> 24) & 0x0F))
+Send a NULL byte to port 0x1F1, if you like (it is ignored and wastes lots of CPU time): outb(0x1F1, 0x00)
+Send the sectorcount to port 0x1F2: outb(0x1F2, (unsigned char) count)
+Send the low 8 bits of the LBA to port 0x1F3: outb(0x1F3, (unsigned char) LBA))
+Send the next 8 bits of the LBA to port 0x1F4: outb(0x1F4, (unsigned char)(LBA >> 8))
+Send the next 8 bits of the LBA to port 0x1F5: outb(0x1F5, (unsigned char)(LBA >> 16))
+Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20)
+Wait for an IRQ or poll.
+Transfer 256 words, a word at a time, into your buffer from I/O port 0x1F0. (In assembler, REP INSW works well for this.)
+Then loop back to waiting for the next IRQ (or poll again -- see next note) for each successive sector.
+*/
+
+
+}
\ No newline at end of file
--- /dev/null
+#include <inc/types.h>
+
+/**
+Port Offset Function Description
+0 Data Port Read/Write PIO data bytes on this port.
+1 Features / Error Information Usually used for ATAPI devices.
+2 Sector Count Number of sectors to read/write (0 is a special value).
+3 Sector Number / LBAlo This is CHS / LBA28 / LBA48 specific.
+4 Cylinder Low / LBAmid Partial Disk Sector address.
+5 Cylinder High / LBAhi Partial Disk Sector address.
+6 Drive / Head Port Used to select a drive and/or head. May supports extra address/flag bits.
+7 Command port / Regular Status port Used to send commands or read the current status.
+*/
+
+
+#define ATA_BUS1_BASE 0x1F0
+#define ATA_BUS2_BASE 0x170
+
+uint16_t base_port;
+
+
+
+#define ATA_DATA_PORT (base_port + 0)
+#define ATA_FEATURES_ERR_INFO_PORT (base_port + 1)
+#define ATA_SECTOR_COUNT_PORT (base_port + 2)
+#define ATA_LBALOW_PORT (base_port + 3)
+#define ATA_LBAMID_PORT (base_port + 4)
+#define ATA_LBAHI_PORT (base_port + 5)
+#define ATA_DRIVE_HEAD_PORT (base_port + 6)
+#define ATA_COMMAND_STATUS_PORT (base_port + 7)
+
+#define ATA_DEVCONTROL ((base_port == ATA_BUS1_BASE) ? 0x3F6 : 0x376)
+#define ATA_ALT_STATUS_PORT ATA_DEVCONTROL
+
+/*
+ * Bit Abbreviation Function
+0 ERR Indicates an error occurred. Send a new command to clear it (or nuke it with a Software Reset).
+3 DRQ Set when the drive has PIO data to transfer, or is ready to accept PIO data.
+4 SRV Overlapped Mode Service Request.
+5 DF Drive Fault Error (does not set ERR).
+6 RDY Bit is clear when drive is spun down, or after an error. Set otherwise.
+7 BSY Indicates the drive is preparing to send/receive data (wait for it to clear). In case of 'hang' (it never clears), do a software reset.
+*/
+
+#define STATUS_ERR (1 << 0)
+#define STATUS_DRQ (1 << 3)
+#define STATUS_SRV (1 << 4)
+#define STATUS_DF (1 << 5)
+#define STATUS_RDY (1 << 6)
+#define STATUS_BSY (1 << 7)
+
+#define SELECT_MASTER_DRIVE 0xA0
+#define SELECT_SLAVE_DRIVE 0xB0
+
+#define RW_MASTER_DRIVE 0xE0
+#define RW_SLAVE_DRIVE 0xF0
+
+#define COMMAND_READ_SECTORS 0x20
+#define COMMAND_IDENTIFY 0xEC
\ No newline at end of file