aboutsummaryrefslogtreecommitdiff
path: root/platform/pc/ide.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/pc/ide.c')
-rw-r--r--platform/pc/ide.c908
1 files changed, 0 insertions, 908 deletions
diff --git a/platform/pc/ide.c b/platform/pc/ide.c
deleted file mode 100644
index a1aa62a4..00000000
--- a/platform/pc/ide.c
+++ /dev/null
@@ -1,908 +0,0 @@
-/*
- * Copyright (c) 2013 Corey Tabaka
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <reg.h>
-#include <debug.h>
-#include <trace.h>
-#include <assert.h>
-#include <err.h>
-#include <malloc.h>
-#include <arch/x86.h>
-#include <sys/types.h>
-#include <platform/interrupts.h>
-#include <platform/ide.h>
-#include <platform/pc.h>
-#include <platform.h>
-#include <dev/pci.h>
-#include <dev/driver.h>
-#include <dev/class/block.h>
-#include <kernel/event.h>
-
-#define LOCAL_TRACE 0
-
-// status register bits
-#define IDE_CTRL_BSY 0x80
-#define IDE_DRV_RDY 0x40
-#define IDE_DRV_WRTFLT 0x20
-#define IDE_DRV_SKCOMP 0x10
-#define IDE_DRV_DRQ 0x08
-#define IDE_DRV_CORDAT 0x04
-#define IDE_DRV_IDX 0x02
-#define IDE_DRV_ERR 0x01
-
-// ATA commands
-#define ATA_NOP 0x00
-#define ATA_ATAPIRESET 0x08
-#define ATA_RECALIBRATE 0x10
-#define ATA_READMULT_RET 0x20
-#define ATA_READMULT 0x21
-#define ATA_READECC_RET 0x22
-#define ATA_READECC 0x23
-#define ATA_WRITEMULT_RET 0x30
-#define ATA_WRITEMULT 0x31
-#define ATA_WRITEECC_RET 0x32
-#define ATA_WRITEECC 0x33
-#define ATA_VERIFYMULT_RET 0x40
-#define ATA_VERIFYMULT 0x41
-#define ATA_FORMATTRACK 0x50
-#define ATA_SEEK 0x70
-#define ATA_DIAG 0x90
-#define ATA_INITPARAMS 0x91
-#define ATA_ATAPIPACKET 0xA0
-#define ATA_ATAPIIDENTIFY 0xA1
-#define ATA_ATAPISERVICE 0xA2
-#define ATA_READ_DMA 0xC8
-#define ATA_READ_DMA_EXT 0x25
-#define ATA_WRITE_DMA 0xCA
-#define ATA_WRITE_DMA_EXT 0x35
-#define ATA_GETDEVINFO 0xEC
-#define ATA_ATAPISETFEAT 0xEF
-
-// error codes
-#define IDE_NOERROR 0
-#define IDE_ADDRESSMARK 1
-#define IDE_CYLINDER0 2
-#define IDE_INVALIDCOMMAND 3
-#define IDE_MEDIAREQ 4
-#define IDE_SECTNOTFOUND 5
-#define IDE_MEDIACHANGED 6
-#define IDE_BADDATA 7
-#define IDE_BADSECTOR 8
-#define IDE_TIMEOUT 9
-#define IDE_DMAERROR 10
-
-enum {
- IDE_REG_DATA = 0,
- IDE_REG_ERROR = 1,
- IDE_REG_PRECOMP = 1,
- IDE_REG_SECTOR_COUNT = 2,
- IDE_REG_SECTOR_NUM = 3,
- IDE_REG_CYLINDER_LOW = 4,
- IDE_REG_CYLINDER_HIGH = 5,
- IDE_REG_DRIVE_HEAD = 6,
- IDE_REG_STATUS = 7,
- IDE_REG_COMMAND = 7,
- IDE_REG_ALT_STATUS = 8,
- IDE_REG_DEVICE_CONTROL = 8,
-
- IDE_REG_NUM,
-};
-
-enum {
- TYPE_NONE,
- TYPE_UNKNOWN,
- TYPE_FLOPPY,
- TYPE_IDECDROM,
- TYPE_SCSICDROM,
- TYPE_IDEDISK,
- TYPE_SCSIDISK
-};
-
-static const char *ide_type_str[] = {
- "None",
- "Unknown",
- "Floppy",
- "IDE CDROM",
- "SCSI CDROM",
- "IDE Disk",
- "SCSI Disk",
-};
-
-static const char *ide_error_str[] = {
- "Unknown error",
- "Address mark not found",
- "Cylinder 0 not found",
- "Command aborted - invalid command",
- "Media change requested",
- "ID or target sector not found",
- "Media changed",
- "Uncorrectable data error",
- "Bad sector detected",
- "Command timed out",
- "DMA error"
-};
-
-struct ide_driver_state {
- int irq;
- const uint16_t *regs;
-
- event_t completion;
-
- int type[2];
- struct {
- int sectors;
- int sector_size;
- } drive[2];
-};
-
-static const uint16_t ide_device_regs[][IDE_REG_NUM] = {
- { 0x01F0, 0x01F1, 0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x03F6 },
- { 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0376 },
-};
-
-static const int ide_device_irqs[] = {
- INT_IDE0,
- INT_IDE1,
-};
-
-static status_t ide_init(struct device *dev);
-
-static enum handler_return ide_irq_handler(void *arg);
-
-static status_t ide_init(struct device *dev);
-static ssize_t ide_get_block_size(struct device *dev);
-static ssize_t ide_get_block_count(struct device *dev);
-static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count);
-static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count);
-
-static struct block_ops the_ops = {
- .std = {
- .init = ide_init,
- },
- .get_block_size = ide_get_block_size,
- .get_block_count = ide_get_block_count,
- .write = ide_write,
- .read = ide_read,
-};
-
-DRIVER_EXPORT(ide, &the_ops.std);
-
-static uint8_t ide_read_reg8(struct device *dev, int index);
-static uint16_t ide_read_reg16(struct device *dev, int index);
-static uint32_t ide_read_reg32(struct device *dev, int index);
-
-static void ide_write_reg8(struct device *dev, int index, uint8_t value);
-static void ide_write_reg16(struct device *dev, int index, uint16_t value);
-static void ide_write_reg32(struct device *dev, int index, uint32_t value);
-
-static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count);
-static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count);
-static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count);
-
-static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count);
-static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count);
-static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count);
-
-static void ide_device_select(struct device *dev, int index);
-static void ide_device_reset(struct device *dev);
-static void ide_delay_400ns(struct device *dev);
-static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask);
-static int ide_eval_error(struct device *dev);
-static void ide_detect_drives(struct device *dev);
-static int ide_wait_for_completion(struct device *dev);
-static int ide_detect_ata(struct device *dev, int index);
-static void ide_lba_setup(struct device *dev, uint32_t addr, int index);
-
-static status_t ide_init(struct device *dev)
-{
- pci_location_t loc;
- pci_config_t pci_config;
- status_t res = NO_ERROR;
- uint32_t i;
- int err;
-
- if (!dev)
- return ERR_INVALID_ARGS;
-
- if (!dev->config)
- return ERR_NOT_CONFIGURED;
-
- __UNUSED const struct platform_ide_config *config = dev->config;
-
- err = pci_find_pci_class_code(&loc, 0x010180, 0);
- if (err != _PCI_SUCCESSFUL) {
- LTRACEF("Failed to find IDE device\n");
- res = ERR_NOT_FOUND;
- }
-
- LTRACEF("Found IDE device at %02x:%02x\n", loc.bus, loc.dev_fn);
-
- for (i=0; i < sizeof(pci_config) / sizeof(uint32_t); i++) {
- uint32_t reg = sizeof(uint32_t) * i;
-
- err = pci_read_config_word(&loc, reg, ((uint32_t *) &pci_config) + i);
- if (err != _PCI_SUCCESSFUL) {
- LTRACEF("Failed to read config reg %d: 0x%02x\n", reg, err);
- res = ERR_NOT_CONFIGURED;
- goto done;
- }
- }
-
- for (i=0; i < 6; i++) {
- LTRACEF("BAR[%d]: 0x%08x\n", i, pci_config.base_addresses[i]);
- }
-
- struct ide_driver_state *state = malloc(sizeof(struct ide_driver_state));
- if (!state) {
- res = ERR_NO_MEMORY;
- goto done;
- }
- dev->state = state;
-
- /* TODO: select io regs and irq based on device index */
- state->irq = ide_device_irqs[0];
- state->regs = ide_device_regs[0];
- state->type[0] = state->type[1] = TYPE_NONE;
-
- event_init(&state->completion, false, EVENT_FLAG_AUTOUNSIGNAL);
-
- register_int_handler(state->irq, ide_irq_handler, dev);
- unmask_interrupt(state->irq);
-
- /* enable interrupts */
- ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0);
-
- /* detect drives */
- ide_detect_drives(dev);
-
-done:
- return res;
-}
-
-static enum handler_return ide_irq_handler(void *arg)
-{
- struct device *dev = arg;
- struct ide_driver_state *state = dev->state;
- uint8_t val;
-
- val = ide_read_reg8(dev, IDE_REG_STATUS);
-
- if ((val & IDE_DRV_ERR) == 0) {
- event_signal(&state->completion, false);
-
- return INT_RESCHEDULE;
- } else {
- return INT_NO_RESCHEDULE;
- }
-}
-
-static ssize_t ide_get_block_size(struct device *dev)
-{
- DEBUG_ASSERT(dev);
- DEBUG_ASSERT(dev->state);
-
- struct ide_driver_state *state = dev->state;
- return state->drive[0].sector_size;
-}
-
-static ssize_t ide_get_block_count(struct device *dev)
-{
- DEBUG_ASSERT(dev);
- DEBUG_ASSERT(dev->state);
-
- struct ide_driver_state *state = dev->state;
- return state->drive[0].sectors;
-}
-
-static ssize_t ide_write(struct device *dev, off_t offset, const void *buf, size_t count)
-{
- DEBUG_ASSERT(dev);
- DEBUG_ASSERT(dev->state);
-
- __UNUSED struct ide_driver_state *state = dev->state;
-
- size_t sectors, do_sectors, i;
- const uint16_t *ubuf = buf;
- int index = 0; // hard code drive for now
- ssize_t ret = 0;
- int err;
-
- ide_device_select(dev, index);
- ide_delay_400ns(dev);
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- sectors = count;
-
- while (sectors > 0) {
- do_sectors = sectors;
-
- if (do_sectors > 256)
- do_sectors = 256;
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_lba_setup(dev, offset, index);
-
- if (do_sectors == 256)
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0);
- else
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors);
-
- err = ide_poll_status(dev, IDE_DRV_RDY, 0);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_write_reg8(dev, IDE_REG_COMMAND, ATA_WRITEMULT_RET);
- ide_delay_400ns(dev);
-
- for (i=0; i < do_sectors; i++) {
- err = ide_poll_status(dev, IDE_DRV_DRQ, 0);
- if (err) {
- LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_write_reg16_array(dev, IDE_REG_DATA, ubuf, 256);
-
- ubuf += 256;
- }
-
- err = ide_wait_for_completion(dev);
- if (err) {
- LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]);
- ret = ERR_TIMED_OUT;
- goto done;
- }
-
- sectors -= do_sectors;
- offset += do_sectors;
- }
-
- ret = count;
-
-done:
- return ret;
-}
-
-static ssize_t ide_read(struct device *dev, off_t offset, void *buf, size_t count)
-{
- DEBUG_ASSERT(dev);
- DEBUG_ASSERT(dev->state);
-
- __UNUSED struct ide_driver_state *state = dev->state;
-
- size_t sectors, do_sectors, i;
- uint16_t *ubuf = buf;
- int index = 0; // hard code drive for now
- ssize_t ret = 0;
- int err;
-
- ide_device_select(dev, index);
- ide_delay_400ns(dev);
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- sectors = count;
-
- while (sectors > 0) {
- do_sectors = sectors;
-
- if (do_sectors > 256)
- do_sectors = 256;
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_lba_setup(dev, offset, index);
-
- if (do_sectors == 256)
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0);
- else
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, do_sectors);
-
- err = ide_poll_status(dev, IDE_DRV_RDY, 0);
- if (err) {
- LTRACEF("Error while waiting for controller: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_write_reg8(dev, IDE_REG_COMMAND, ATA_READMULT_RET);
- ide_delay_400ns(dev);
-
- for (i=0; i < do_sectors; i++) {
- err = ide_poll_status(dev, IDE_DRV_DRQ, 0);
- if (err) {
- LTRACEF("Error while waiting for drive: %s\n", ide_error_str[err]);
- ret = ERR_GENERIC;
- goto done;
- }
-
- ide_read_reg16_array(dev, IDE_REG_DATA, ubuf, 256);
-
- ubuf += 256;
- }
-
- err = ide_wait_for_completion(dev);
- if (err) {
- LTRACEF("Error waiting for completion: %s\n", ide_error_str[err]);
- ret = ERR_TIMED_OUT;
- goto done;
- }
-
- sectors -= do_sectors;
- offset += do_sectors;
- }
-
- ret = count;
-
-done:
- return ret;
-}
-
-static uint8_t ide_read_reg8(struct device *dev, int index)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- return inp(state->regs[index]);
-}
-
-static uint16_t ide_read_reg16(struct device *dev, int index)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- return inpw(state->regs[index]);
-}
-
-static uint32_t ide_read_reg32(struct device *dev, int index)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- return inpd(state->regs[index]);
-}
-
-static void ide_read_reg8_array(struct device *dev, int index, void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- inprep(state->regs[index], (uint8_t *) buf, count);
-}
-
-static void ide_read_reg16_array(struct device *dev, int index, void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- inpwrep(state->regs[index], (uint16_t *) buf, count);
-}
-
-static void ide_read_reg32_array(struct device *dev, int index, void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- inpdrep(state->regs[index], (uint32_t *) buf, count);
-}
-
-static void ide_write_reg8_array(struct device *dev, int index, const void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outprep(state->regs[index], (uint8_t *) buf, count);
-}
-
-static void ide_write_reg16_array(struct device *dev, int index, const void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outpwrep(state->regs[index], (uint16_t *) buf, count);
-}
-
-static void ide_write_reg32_array(struct device *dev, int index, const void *buf, size_t count)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outpdrep(state->regs[index], (uint32_t *) buf, count);
-}
-
-static void ide_write_reg8(struct device *dev, int index, uint8_t value)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outp(state->regs[index], value);
-}
-
-static void ide_write_reg16(struct device *dev, int index, uint16_t value)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outpw(state->regs[index], value);
-}
-
-static void ide_write_reg32(struct device *dev, int index, uint32_t value)
-{
- DEBUG_ASSERT(index >= 0 && index < IDE_REG_NUM);
-
- struct ide_driver_state *state = dev->state;
-
- outpd(state->regs[index], value);
-}
-
-static void ide_device_select(struct device *dev, int index)
-{
- ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, (index & 1) << 4);
-}
-
-static void ide_delay_400ns(struct device *dev)
-{
- ide_read_reg8(dev, IDE_REG_ALT_STATUS);
- ide_read_reg8(dev, IDE_REG_ALT_STATUS);
- ide_read_reg8(dev, IDE_REG_ALT_STATUS);
- ide_read_reg8(dev, IDE_REG_ALT_STATUS);
-}
-
-static void ide_device_reset(struct device *dev)
-{
- struct ide_driver_state *state = dev->state;
-
- lk_time_t start;
- uint8_t sect_cnt, sect_num;
- int err;
-
- ide_device_select(dev, 0);
- ide_delay_400ns(dev);
-
- // set bit 2 for at least 4.8us
- ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 1<<2);
-
- // delay 5us
- spin(5);
-
- ide_write_reg8(dev, IDE_REG_DEVICE_CONTROL, 0x00);
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
- if (err) {
- LTRACEF("Failed while waiting for controller to be ready: %s\n", ide_error_str[err]);
- return;
- }
-
- // make sure the slave is ready if present
- if (state->type[1] != TYPE_NONE) {
- ide_device_select(dev, 1);
- ide_delay_400ns(dev);
-
- start = current_time();
-
- do {
- sect_cnt = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
- sect_num = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
-
- if (sect_cnt == 1 && sect_num == 1) {
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY);
- if (err) {
- LTRACEF("Failed while waiting for slave ready: %s\n", ide_error_str[err]);
- return;
- }
-
- break;
- }
- } while (TIME_LTE(current_time(), start + 20000));
-
- err = ide_read_reg8(dev, IDE_REG_ALT_STATUS);
- if (err & IDE_DRV_ERR) {
- err = ide_eval_error(dev);
- LTRACEF("Failed while resetting controller: %s\n", ide_error_str[err]);
- return;
- }
- }
-}
-
-static int ide_eval_error(struct device *dev)
-{
- int err = 0;
- uint8_t data = 0;
-
- data = ide_read_reg8(dev, IDE_REG_ERROR);
-
- if (data & 0x01) {
- err = IDE_ADDRESSMARK;
- } else if (data & 0x02) {
- err = IDE_CYLINDER0;
- } else if (data & 0x04) {
- err = IDE_INVALIDCOMMAND;
- } else if (data & 0x08) {
- err = IDE_MEDIAREQ;
- } else if (data & 0x10) {
- err = IDE_SECTNOTFOUND;
- } else if (data & 0x20) {
- err = IDE_MEDIACHANGED;
- } else if (data & 0x40) {
- err = IDE_BADDATA;
- } else if (data & 0x80) {
- err = IDE_BADSECTOR;
- } else {
- err = IDE_NOERROR;
- }
-
- return err;
-}
-
-static int ide_poll_status(struct device *dev, uint8_t on_mask, uint8_t off_mask)
-{
- int err;
- uint8_t value;
- lk_time_t start = current_time();
-
- do {
- value = ide_read_reg8(dev, IDE_REG_ALT_STATUS);
-
- if (value & IDE_DRV_ERR) {
- err = ide_eval_error(dev);
- LTRACEF("Error while polling status: %s\n", ide_error_str[err]);
- return err;
- }
-
- if ((value & on_mask) == on_mask && (value & off_mask) == 0)
- return IDE_NOERROR;
- } while (TIME_LTE(current_time(), start + 20000));
-
- return IDE_TIMEOUT;
-}
-
-static void ide_detect_drives(struct device *dev)
-{
- struct ide_driver_state *state = dev->state;
- uint8_t sc = 0, sn = 0, st = 0, cl = 0, ch = 0;
-
- ide_device_select(dev, 0);
- ide_delay_400ns(dev);
- ide_delay_400ns(dev);
-
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
-
- sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
- sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
-
- if (sc == 0x55 && sn == 0xaa) {
- state->type[0] = TYPE_UNKNOWN;
- }
-
- // check for device 1
- ide_device_select(dev, 1);
- ide_delay_400ns(dev);
-
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0xaa);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_COUNT, 0x55);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, 0xaa);
-
- sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
- sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
-
- if (sc == 0x55 && sn == 0xaa) {
- state->type[1] = TYPE_UNKNOWN;
- }
-
- // now the drives present should be known
- // soft reset now
- ide_device_select(dev, 0);
- ide_delay_400ns(dev);
- ide_device_reset(dev);
-
- ide_device_select(dev, 0);
- ide_delay_400ns(dev);
-
- sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
- sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
- if (sc == 0x01 && sn == 0x01) {
- state->type[0] = TYPE_UNKNOWN;
-
- st = ide_read_reg8(dev, IDE_REG_STATUS);
- cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW);
- ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH);
-
- // PATAPI or SATAPI respectively
- if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) {
- state->type[0] = TYPE_IDECDROM;
- } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) {
- state->type[0] = TYPE_IDEDISK;
- }
- }
-
- ide_device_select(dev, 1);
- ide_delay_400ns(dev);
-
- sc = ide_read_reg8(dev, IDE_REG_SECTOR_COUNT);
- sn = ide_read_reg8(dev, IDE_REG_SECTOR_NUM);
- if (sc == 0x01 && sn == 0x01) {
- state->type[1] = TYPE_UNKNOWN;
-
- st = ide_read_reg8(dev, IDE_REG_STATUS);
- cl = ide_read_reg8(dev, IDE_REG_CYLINDER_LOW);
- ch = ide_read_reg8(dev, IDE_REG_CYLINDER_HIGH);
-
- // PATAPI or SATAPI respectively
- if ((cl == 0x14 && ch == 0xeb) || (cl == 0x69 && ch == 0x96)) {
- state->type[1] = TYPE_IDECDROM;
- } else if (st != 0 && ((cl == 0x00 && ch == 0x00) || (cl == 0x3c && ch == 0xc3))) {
- state->type[1] = TYPE_IDEDISK;
- }
- }
-
- LTRACEF("Detected drive 0: %s\n", ide_type_str[state->type[0]]);
- LTRACEF("Detected drive 1: %s\n", ide_type_str[state->type[1]]);
-
- switch (state->type[0]) {
- case TYPE_IDEDISK:
- ide_detect_ata(dev, 0);
- break;
-
- default:
- break;
- }
-
- switch (state->type[1]) {
- case TYPE_IDEDISK:
- ide_detect_ata(dev, 1);
- break;
-
- default:
- break;
- }
-}
-
-static int ide_wait_for_completion(struct device *dev)
-{
- struct ide_driver_state *state = dev->state;
- status_t err;
-
- err = event_wait_timeout(&state->completion, 20000);
- if (err)
- return IDE_TIMEOUT;
-
- return IDE_NOERROR;
-}
-
-static status_t ide_detect_ata(struct device *dev, int index)
-{
- struct ide_driver_state *state = dev->state;
- status_t res = NO_ERROR;
- uint8_t *info = NULL;
- int err;
-
- ide_device_select(dev, index);
- ide_delay_400ns(dev);
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
- if (err) {
- LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]);
- res = ERR_TIMED_OUT;
- goto error;
- }
-
- ide_device_select(dev, index);
- ide_delay_400ns(dev);
-
- err = ide_poll_status(dev, 0, IDE_CTRL_BSY | IDE_DRV_DRQ);
- if (err) {
- LTRACEF("Error while detecting drive %d: %s\n", index, ide_error_str[err]);
- res = ERR_TIMED_OUT;
- goto error;
- }
-
- // try to wait for the selected drive to be ready, but don't quit if not
- // since CD-ROMs don't seem to respond to this when they're masters
- ide_poll_status(dev, IDE_DRV_RDY, 0);
-
- // send the "identify device" command
- ide_write_reg8(dev, IDE_REG_COMMAND, ATA_GETDEVINFO);
- ide_delay_400ns(dev);
-
- err = ide_wait_for_completion(dev);
- if (err) {
- LTRACEF("Error while waiting for command: %s\n", ide_error_str[err]);
- res = ERR_TIMED_OUT;
- goto error;
- }
-
- info = malloc(512);
- if (!info) {
- res = ERR_NO_MEMORY;
- goto error;
- }
-
- LTRACEF("Found ATA hard disk on channel %d!\n", index);
-
- ide_read_reg16_array(dev, IDE_REG_DATA, info, 256);
-
- state->drive[index].sectors = *((uint32_t *) (info + 120));
- state->drive[index].sector_size = 512;
-
- LTRACEF("Disk supports %u sectors for a total of %u bytes\n", state->drive[index].sectors,
- state->drive[index].sectors * 512);
-
-error:
- free(info);
- return res;
-}
-
-static void ide_lba_setup(struct device *dev, uint32_t addr, int drive)
-{
- ide_write_reg8(dev, IDE_REG_DRIVE_HEAD, 0xe0 | ((drive & 0x00000001) << 4) | ((addr >> 24) & 0xf));
- ide_write_reg8(dev, IDE_REG_CYLINDER_LOW, (addr >> 8) & 0xff);
- ide_write_reg8(dev, IDE_REG_CYLINDER_HIGH, (addr >> 16) & 0xff);
- ide_write_reg8(dev, IDE_REG_SECTOR_NUM, addr & 0xff);
- ide_write_reg8(dev, IDE_REG_PRECOMP, 0xff);
-}
-