📄 atapi.c
字号:
/***************************************** Copyright (c) 2002-2007 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the EM86XX boot loader *//* * atapi.c * * ATAPI support * * modified from jasper boot loader by Ho Lee 03/09/2004 */#include "config.h"#include "uart.h"#include "io.h"#include "util.h"#include "hardware.h"#include "em86xxapi.h"#include "timer.h"#include "ide.h"#include "atapi.h"#define ATAPI_VERBOSE 0//// constant definitions//#define ATAPIPHASE_MAKE(i, s) (((i) << 8) | (s))#define ATAPIPHASE_MASK ATAPIPHASE_MAKE(IDEIREASON_CMD | IDEIREASON_IN, IDESTAT_DRQ)#define ATAPIPHASE_CMDOUT ATAPIPHASE_MAKE(IDEIREASON_CMD, IDESTAT_DRQ)#define ATAPIPHASE_DATAIN ATAPIPHASE_MAKE(IDEIREASON_IN, IDESTAT_DRQ)#define ATAPIPHASE_DATAOUT ATAPIPHASE_MAKE(0, IDESTAT_DRQ)#define ATAPIPHASE_COMPLETED ATAPIPHASE_MAKE(IDEIREASON_CMD | IDEIREASON_IN, 0)#define ATAPIPHASE_ABORTED 0//// function prototypes//int atapi_io(packet_command_t *pc);//// primitive functions//// atapi_wait #define ATAPI_WAIT_TIMEOUT 1000int atapi_wait(packet_command_t *pc, int mask, int wait, int mismatch){ int timeout = ATAPI_WAIT_TIMEOUT; int curphase; do { curphase = (ide_inb(IDE_IREASON_REG) << 8) | ide_inb(IDE_STATUS_REG); curphase &= mask; if ((!mismatch && curphase == wait) || (mismatch && curphase != wait)) return 0; em86xx_msleep(1); } while (--timeout > 0); pc->error = ide_inb(IDE_ERROR_REG); return 1;}int atapi_send_cmd(packet_command_t *pc){ int i; for (i = 0; i < sizeof pc->c; i += 2) ide_outw(*(unsigned short *)(pc->c + i), IDE_DATA_REG); return(0);}int atapi_command(int drive, packet_command_t *pc){ // initialize pc->addr = pc->buffer; pc->count = pc->buflen; // select drive if (ide_select_drive(drive, 1) != 0) {#if ATAPI_VERBOSE uart_puts("Drive is not ready\n");#endif return ATAPIRES_NOTRDY; } // program atapi registers ide_outb(0, IDE_FEATURE_REG); ide_outb(0, IDE_IREASON_REG); ide_outb(0, IDE_TAG_REG); ide_outb(pc->buflen & 0xff, IDE_LCYL_REG); ide_outb(pc->buflen >> 8, IDE_HCYL_REG); ide_outb(ATACMD_PACKET, IDE_COMMAND_REG); // wait for DRQ to be set if (atapi_wait(pc, ATAPIPHASE_MASK | IDESTAT_BUSY, ATAPIPHASE_CMDOUT, 0) != 0) {#if ATAPI_VERBOSE uart_puts("Command phase failed\n");#endif return ATAPIRES_NODRQ; } // send the packet command atapi_send_cmd(pc); // wait for data I/O phase if (atapi_wait(pc, ATAPIPHASE_MASK, ATAPIPHASE_CMDOUT, 1) != 0) {#if ATAPI_VERBOSE uart_puts("Data phase failed\n");#endif return ATAPIRES_ERR; } // Do all needed i/o (using PIO) while (atapi_io (pc)) { // wait for DRQ to be deasserted ide_wait_stat(IDESTAT_DRQ, 0, 0); em86xx_msleep(10); } if (pc->stat != 0) return pc->stat; return 0;}// Process the i/o phase, transferring the command/data to/from the device.// Return 1 if op continues, and we are waiting for new interrupt.// Return 0 when idle.int atapi_io(packet_command_t *pc){ int len, ireason, status, phase; ide_wait_stat(IDESTAT_BUSY, 0, 0); pc->stat = ATAPIRES_OK; pc->error = ide_inb(IDE_ERROR_REG); len = ide_inb(IDE_LCYL_REG); len |= ide_inb(IDE_HCYL_REG) << 8; ireason = ide_inb(IDE_IREASON_REG); status = ide_inb(IDE_STATUS_REG); phase = ATAPIPHASE_MAKE(ireason, status) & ATAPIPHASE_MASK; switch (phase) { case ATAPIPHASE_CMDOUT :#if ATAPI_VERBOSE uart_puts("Phase = CMDOUT\n");#endif if ((status & IDESTAT_DRQ) == 0) { pc->stat = ATAPIRES_NODRQ; break; } // send command again atapi_send_cmd(pc); return 1; case ATAPIPHASE_DATAOUT :#if ATAPI_VERBOSE uart_puts("Phase = DATAOUT\n");#endif if (pc->data_direction != ATAPIDIR_WRITE) { pc->stat = ATAPIRES_INVDIR; break; } if (pc->count < len) {#if ATAPI_VERBOSE uart_puts("DATAIN: Data underrun\n");#endif pc->stat = ATAPIRES_UNDERRUN; ide_output_data((unsigned short *) pc->addr, pc->count / 2); ide_output_data(NULL, (len - pc->count) / 2); } else { ide_output_data((unsigned short *) pc->addr, pc->count / 2); } pc->addr += len; pc->count -= len; return 1; case ATAPIPHASE_DATAIN :#if ATAPI_VERBOSE uart_puts("Phase = DATAIN\n");#endif if (pc->data_direction != ATAPIDIR_READ) { pc->stat = ATAPIRES_INVDIR; break; } if (pc->count < len) {#if ATAPI_VERBOSE uart_puts("DATAIN: Data overrun\n");#endif pc->stat = ATAPIRES_OVERRUN; ide_input_data((unsigned short *) pc->addr, pc->count / 2); ide_input_data(NULL, (len - pc->count) / 2); } else { ide_input_data((unsigned short *) pc->addr, len / 2); } pc->addr += len; pc->count -= len; return 1; case ATAPIPHASE_ABORTED : case ATAPIPHASE_COMPLETED :#if ATAPI_VERBOSE uart_puts("Phase = COMPLETED\n");#endif if (status & (IDESTAT_ERROR | IDESTAT_WRITEERROR)) pc->stat = ATAPIRES_ERR; else if (pc->count) { if (pc->data_direction == ATAPIDIR_READ) pc->stat = ATAPIRES_OVERRUN; else if (pc->data_direction == ATAPIDIR_WRITE) pc->stat = ATAPIRES_UNDERRUN; } break; default :#if ATAPI_VERBOSE uart_printf("Phase = unknown : ireason = %02x, status = %02x\n", ireason, status);#endif pc->stat = ATAPIRES_ERR; break; } return 0;}void atapi_init_pc(packet_command_t *pc){ memset(pc, 0, sizeof(packet_command_t)); pc->data_direction = ATAPIDIR_NONE;}int atapi_eject(int drive, int open){ static unsigned char s_cmd_eject[] = { 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; packet_command_t pc; atapi_init_pc(&pc); memcpy(pc.c, s_cmd_eject, 12); pc.c[4] = open ? 0x03 : 0x02; return atapi_command(drive, &pc);}int atapi_readsense(int drive, char *sensedata){ static unsigned char s_cmd_readsense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; packet_command_t pc; atapi_init_pc(&pc); pc.buffer = (unsigned char *) sensedata; pc.buflen = ATAPI_SENSEDATA_LEN; pc.data_direction = ATAPIDIR_READ; memcpy(pc.c, s_cmd_readsense, 12); return atapi_command(drive, &pc);}int atapi_waitready(int drive, int timeout){ int ret; packet_command_t pc; unsigned char sensedata[ATAPI_SENSEDATA_LEN]; unsigned int startticks = timer_getticks(); do { atapi_init_pc(&pc); ret = atapi_command(drive, &pc); if (pc.error >> 4 == 2) { atapi_readsense(drive, sensedata); if (sensedata[12] != 0x04 && sensedata[13] != 0x28) return 1; } } while (ret != 0 && !timer_timeout(startticks, timeout)); return ret;}int atapi_readsector(int drive, void *buf, unsigned long first, int nsector){ static unsigned char s_cmd_readsector[] = { 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; packet_command_t pc; int retry = 10; while (retry-- > 0) { atapi_init_pc(&pc); pc.buffer = (unsigned char *) buf; pc.buflen = nsector * CDSECTOR_SIZE; pc.data_direction = ATAPIDIR_READ; memcpy(pc.c, s_cmd_readsector, 12); pc.c[2] = (first >> 24) & 0xff; pc.c[3] = (first >> 16) & 0xff; pc.c[4] = (first >> 8) & 0xff; pc.c[5] = (first >> 0) & 0xff; pc.c[7] = (nsector >> 8) & 0xff; pc.c[8] = (nsector >> 0) & 0xff; if (atapi_command(drive, &pc) == 0) return 0; } return ATAPIRES_ERR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -