📄 ata-ops.c
字号:
/* ATA Driver for FD32 * by Luca Abeni & Nils Labugt * * This is free software; see GPL.txt */#include <dr-env.h>#include "ata.h"#include "disk.h"#include "ata-ops.h"#include "ata-wait.h"#include "ata-detect.h"extern int ata_global_flags;extern int max_pio_mode;#ifdef _DEBUG_void reg_dump(const struct ata_device* dev){ BYTE b; b = fd32_inb(dev->interface->command_port + CMD_ERROR); fd32_message("ERR:0x%x ", (BYTE)b); b = fd32_inb(dev->interface->command_port + CMD_STATUS); fd32_message("ST:0x%x ", (BYTE)b); b = fd32_inb(dev->interface->command_port + CMD_SECT); fd32_message("SCT:%u ", (BYTE)b); b = fd32_inb(dev->interface->command_port + CMD_CYL_L); fd32_message("CL:%u ", (BYTE)b); b = fd32_inb(dev->interface->command_port + CMD_CYL_H); fd32_message("CH:%u ", (BYTE)b); b = fd32_inb(dev->interface->command_port + CMD_DEVHEAD); fd32_message("DH:0x%x\n", (BYTE)b);}#endifint dev_is_busy(const struct ide_interface* iface){ return ((fd32_inb(iface->control_port) & ATA_STATUS_BSY) != 0);}int dev_not_ready(const struct ide_interface* iface){ return ((fd32_inb(iface->control_port) & ATA_STATUS_DRDY) == 0);}int bsy_drq_is_set(const struct ide_interface* iface){ return (fd32_inb(iface->control_port) & (ATA_STATUS_BSY | ATA_STATUS_DRQ));}int device_select( unsigned long max_wait, const struct ata_device* dev){ int res; BYTE status; extern int irq_reset(int i); if(dev->flags & DEV_FLG_SLEEP) {#if 1 return ATA_ESLEEP;#else if(ata_reset( dev ) < 0) return ATA_ESLEEP;#endif } if(bsy_drq_is_set(dev->interface)) { res = ata_poll(MAX_WAIT_1, &bsy_drq_is_set, dev->interface); if(res) { status = fd32_inb(dev->interface->command_port + CMD_STATUS); if(status & ATA_STATUS_DRQ) { return ATA_DRQ_SET; } return ATA_ETOBUSY; } } /* Skip device selection if already selected */ if(dev->interface->current_dev_bit != dev->dev_bit) { fd32_outb(dev->interface->command_port + CMD_DEVHEAD, dev->dev_bit); dev->interface->current_dev_bit = dev->dev_bit; if(bsy_drq_is_set(dev->interface)) { res = ata_poll(MAX_WAIT_1, &bsy_drq_is_set, dev->interface); if(res) { status = fd32_inb(dev->interface->command_port + CMD_STATUS); if(status & ATA_STATUS_DRQ) { return ATA_DRQ_SET; } return ATA_ETOBUSY; } } } irq_reset(dev->interface->irq); return 0;}static void write_reg_start_count(DWORD start, WORD count, int use_48bit, const struct ata_device* dev){ if(dev->capabilities & ATA_CAPAB_LBA) { if(use_48bit) { fd32_outb(dev->interface->command_port + CMD_SECT, (BYTE)(start>>24)); fd32_outb(dev->interface->command_port + CMD_CYL_L, (BYTE)((QWORD)start>>32)); fd32_outb(dev->interface->command_port + CMD_CYL_H, (BYTE)((QWORD)start>>40)); fd32_outb(dev->interface->command_port + CMD_CNT, (BYTE)(count>>8)); } else fd32_outb(dev->interface->command_port + CMD_DEVHEAD, (BYTE)( ((start>>24) & 0x0F) | dev->dev_bit | ATA_DEVHEAD_L | 0xA0)); fd32_outb(dev->interface->command_port + CMD_SECT, (BYTE)start); fd32_outb(dev->interface->command_port + CMD_CYL_L, (BYTE)(start>>8)); fd32_outb(dev->interface->command_port + CMD_CYL_H, (BYTE)(start>>16)); } else { fd32_outb(dev->interface->command_port + CMD_SECT, (start % dev->sectors) + 1); start /= dev->sectors; fd32_outb(dev->interface->command_port + CMD_DEVHEAD, (BYTE)( (start % dev->heads) | dev->dev_bit | 0xA0 ) ); start /= dev->heads; fd32_outb(dev->interface->command_port + CMD_CYL_L, (BYTE) start ); fd32_outb(dev->interface->command_port + CMD_CYL_H, (BYTE)(start>>8)); } fd32_outb(dev->interface->command_port + CMD_CNT, (BYTE)count);}int pio_data_in(unsigned long max_wait, BYTE count, DWORD start, void* buffer, struct ata_device* dev, BYTE command, int use_48bit){ int res, i, j, k; BYTE status; WORD* b = (WORD*)buffer; res = device_select( max_wait, dev); if(res) return res; if(command != ATA_CMD_IDENTIFY) { write_reg_start_count(start, count, use_48bit, dev); } fd32_outb(dev->interface->command_port + CMD_COMMAND, command); do { if(dev->polled_mode) { delay(400); fd32_inb(dev->interface->control_port); if(dev_is_busy(dev->interface)) { res = ata_poll(max_wait, &dev_is_busy, dev->interface); if(res) return ATA_ETOBUSY; } status = fd32_inb(dev->interface->command_port + CMD_STATUS); } else { status = ata_cmd_irq(max_wait, dev->interface); if(status == 0xFF) return ATA_ETOIRQ; } if((status & ATA_STATUS_DRQ) != ATA_STATUS_DRQ) return ATA_EDRQ_CLEAR; /* If sectors_per_block == 0, then block mode is not enabled */ if(dev->sectors_per_block == 0) { for (i = 0; i < 256; i++) { *b++ = fd32_inw(dev->interface->command_port + CMD_DATA); } count--; } else { k = dev->sectors_per_block; for(j=0; j<k; j++) { for (i = 0; i < 256; i++) { *b++ = fd32_inw(dev->interface->command_port + CMD_DATA); } count--; if(count == 0) break; } } if(status & ATA_STATUS_ERR) { dev->status_reg = status; dev->error_reg = fd32_inb(dev->interface->command_port + CMD_ERROR); return ATA_ESTATUS; } if(count == 0) break; } while(count); return 0;}int ata_read(struct ata_device *d, DWORD start, DWORD count, void *b){ int res; BYTE command; WORD* buff = (WORD*)b; unsigned long max_wait; int use_48bit = FALSE; int max_per_irq; if(b == NULL || d == NULL) { return -1; } if(d->flags & (DEV_FLG_ST_TIMER_ACTIVE | DEV_FLG_STANDBY)) { /* TODO: check timer (and DRDY?) first */ max_wait = 30 * 1000 * 1000; } else max_wait = MAX_WAIT_1; if(start + count > d->total_blocks) return ATA_ERANGE; start += d->first_sector; if((start + count - 1) & 0xF0000000) { if(d->flags & DEV_FLG_48BIT_LBA) use_48bit = TRUE; else return ATA_ERANGE; if(d->sectors_per_block != 0) command = ATA_CMD_READ_MULTIPLE_EXT; else command = ATA_CMD_READ_SECTORS_EXT; max_per_irq = 256 * 256; } else { if(d->sectors_per_block != 0) command = ATA_CMD_READ_MULTIPLE; else command = ATA_CMD_READ_SECTORS; max_per_irq = 256; } while(count) { if(count >= max_per_irq) { /* When we ask for 0 sectors, then we mean 256 sectors */ res = pio_data_in(max_wait, 0, start, (void*)buff, d, command, use_48bit); count -= max_per_irq; buff += max_per_irq; } else { res = pio_data_in(max_wait, (BYTE)count, start, (void*)buff, d, command, use_48bit); count = 0; } if(res) { return -1; } } d->flags &= ~DEV_FLG_STANDBY; return 0;}int pio_data_out(unsigned long max_wait, WORD count, DWORD start, void* buffer, struct ata_device* dev, BYTE command, int use_48bit){ int res, i, j, k; BYTE status; WORD* b = (WORD*)buffer; res = device_select( max_wait, dev ); if(res) return res; write_reg_start_count(start, count, use_48bit, dev); fd32_outb(dev->interface->command_port + CMD_CNT, count); fd32_outb(dev->interface->command_port + CMD_COMMAND, command); delay(400); if(dev_is_busy(dev->interface)) { res = ata_poll(MAX_WAIT_1, &dev_is_busy, dev->interface); if(res) return ATA_ETOBUSY; } status = fd32_inb(dev->interface->command_port + CMD_STATUS); if(status & ATA_STATUS_ERR) return ATA_ESTATUS; do { if((status & ATA_STATUS_DRQ) != ATA_STATUS_DRQ) return ATA_EDRQ_CLEAR; /* If sectors_per_block == 0, then block mode is not enabled */ if(dev->sectors_per_block == 0) { for (i = 0; i < 256; i++) { fd32_outw(dev->interface->command_port + CMD_DATA, *b++ ); } count--; } else { k = dev->sectors_per_block; for(j=0; j<k; j++) { for (i = 0; i < 256; i++) { fd32_outw(dev->interface->command_port + CMD_DATA, *b++ ); } count--; if(count == 0) break; } } if(dev->polled_mode) { delay(400); fd32_inb(dev->interface->control_port); if(dev_is_busy(dev->interface)) { res = ata_poll(max_wait, &dev_is_busy, dev->interface); if(res) return ATA_ETOBUSY; } status = fd32_inb(dev->interface->command_port + CMD_STATUS); } else { status = ata_cmd_irq(max_wait, dev->interface); if(status == 0xFF) return ATA_ETOIRQ; } if(status & ATA_STATUS_ERR) { dev->status_reg = status; dev->error_reg = fd32_inb(dev->interface->command_port + CMD_ERROR); return ATA_ESTATUS; } if(count == 0) break; } while(count); return 0;}int ata_write(struct ata_device *d, DWORD start, DWORD count, const void *b){ int res; BYTE command; WORD* buff = (WORD*)b; unsigned long max_wait; int use_48bit = FALSE; int max_per_irq; if(b == NULL || d == NULL) { return -1; } if(d->flags & (DEV_FLG_ST_TIMER_ACTIVE | DEV_FLG_STANDBY)) { /* TODO: check timer (and DRDY?) first */ max_wait = 30 * 1000 * 1000; } else max_wait = MAX_WAIT_1; if(start + count > d->total_blocks) return ATA_ERANGE; start += d->first_sector; if((start + count - 1) & 0xF0000000) { if(d->flags & DEV_FLG_48BIT_LBA) use_48bit = TRUE; else return ATA_ERANGE; if(d->sectors_per_block != 0) command = ATA_CMD_WRITE_MULTIPLE_EXT; else command = ATA_CMD_WRITE_SECTORS_EXT; max_per_irq = 256 * 256; } else { if(d->sectors_per_block != 0) command = ATA_CMD_WRITE_MULTIPLE; else command = ATA_CMD_WRITE_SECTORS; max_per_irq = 256; } while(count) { if(count >= max_per_irq)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -