⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atapi.c

📁 1. 8623L平台
💻 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 + -