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

📄 ata.c

📁 在SOPC平台上
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2002 by Linus Nielsen Feltzing
 *
 * All files in this archive are subject to the GNU General Public License.
 * See the file COPYING in the source tree root for full license agreement.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include <unistd.h>
#include "ata.h"
#include "fat_file.h"
#include "system.h"
#include "debug.h"
#include "altera_avalon_cf_regs.h"
#include "altera_avalon_cf.h"
#include "sys/alt_alarm.h"

#ifndef CF_IDE_BASE
#error This IDE software requires a CompactFlash Interface component named "cf"
#endif

#ifndef CF_CTL_BASE
#error This IDE software requires a CompactFlash Interface component named "cf"
#endif

#define ide_base (int*)CF_IDE_BASE
#define ctl_base (int*)CF_CTL_BASE

/* wrap-safe macros for tick comparison */
#define TIME_AFTER(a,b)         ((long)(b) - (long)(a) < 0)
#define TIME_BEFORE(a,b)        TIME_AFTER(b,a)

#define ATA_STATUS IORD_ALTERA_AVALON_CF_IDE_STATUS( ide_base )
#define ATA_ALT_STATUS IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS( ide_base )
#define ATA_DATA IORD_ALTERA_AVALON_CF_IDE_DATA( ide_base )
#define ATA_ERROR IORD_ALTERA_AVALON_CF_IDE_ERROR( ide_base )

#define SECTOR_SIZE 512

#define WRITE_PATTERN1 0xa5
#define WRITE_PATTERN2 0x5a
#define WRITE_PATTERN3 0xaa
#define WRITE_PATTERN4 0x55

#define STATUS_BSY      0x80
#define STATUS_RDY      0x40
#define STATUS_DF       0x20
#define STATUS_DRQ      0x08
#define STATUS_ERR      0x01

#define ERROR_ABRT      0x0400

#define SELECT_DEVICE1  0x10
#define SELECT_LBA      0x40

#define CONTROL_nIEN    0x02
#define CONTROL_SRST    0x04

#define CMD_READ_SECTORS           0x20
#define CMD_WRITE_SECTORS          0x30
#define CMD_READ_MULTIPLE          0xC4
#define CMD_WRITE_MULTIPLE         0xC5
#define CMD_SET_MULTIPLE_MODE      0xC6
#define CMD_STANDBY_IMMEDIATE      0xE0
#define CMD_STANDBY                0xE2
#define CMD_IDENTIFY               0xEC
#define CMD_SLEEP                  0xE6
#define CMD_SET_FEATURES           0xEF
#define CMD_SECURITY_FREEZE_LOCK   0xF5

static bool initialized = false;
char ata_device; /* device 0 (master) or 1 (slave) */
long last_disk_activity = -1;
static int multisectors; /* number of supported multisectors */
static unsigned short identify_info[SECTOR_SIZE];


static int check_registers(void)
{
    int i;
    
    if ( ATA_STATUS & STATUS_BSY )
            return -1;

    for (i = 0; i<64; i++) {
      IOWR_ALTERA_AVALON_CF_IDE_SECTOR_COUNT(ide_base, WRITE_PATTERN1);
      IOWR_ALTERA_AVALON_CF_IDE_SECTOR_NUMBER(ide_base, WRITE_PATTERN2);
      IOWR_ALTERA_AVALON_CF_IDE_CYLINDER_LOW(ide_base, WRITE_PATTERN3);
      IOWR_ALTERA_AVALON_CF_IDE_CYLINDER_HIGH(ide_base, WRITE_PATTERN4);
      
      if ( (IORD_ALTERA_AVALON_CF_IDE_SECTOR_COUNT( ide_base )   == WRITE_PATTERN1) &&
           (IORD_ALTERA_AVALON_CF_IDE_SECTOR_NUMBER( ide_base )  == WRITE_PATTERN2) &&
           (IORD_ALTERA_AVALON_CF_IDE_CYLINDER_LOW( ide_base )   == WRITE_PATTERN3) &&
           (IORD_ALTERA_AVALON_CF_IDE_CYLINDER_HIGH( ide_base )  == WRITE_PATTERN4) )
        return 0;
    }

    return -2;
}

static int master_slave_detect(void)
{

    /* master? */
    IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base, 0);
    if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
        ata_device = 0;
        DEBUGF("Found master harddisk\n");
    }
    else {
        /* slave? */
        IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base, 0);
        if ( ATA_STATUS & (STATUS_RDY|STATUS_BSY) ) {
            ata_device = SELECT_DEVICE1;
            DEBUGF("Found slave harddisk\n");
        }
        else
            return -1;
    }
    return 0;
}

void yield( void )
{
  return;
}

static int wait_for_bsy(void)
{

    long timeout = alt_nticks() + (alt_ticks_per_second() * 30);
    
    while (TIME_BEFORE(alt_nticks(), timeout) && (ATA_STATUS & STATUS_BSY)) {
        last_disk_activity = alt_nticks();
        yield();
    }

    if (TIME_BEFORE(alt_nticks(), timeout))
        return 1;
    else
        return 0; /* timeout */
}


static int wait_for_rdy(void)
{
    long timeout;

    if (!wait_for_bsy())
        return 0;

    timeout = alt_nticks() + (alt_ticks_per_second() * 10);

    while (TIME_BEFORE(alt_nticks(), timeout) &&
           !(ATA_ALT_STATUS & STATUS_RDY)) {
        last_disk_activity = alt_nticks();
        yield();
    }

    if (TIME_BEFORE(alt_nticks(), timeout))
        return STATUS_RDY;
    else
        return 0; /* timeout */
}


static int init_and_check(bool reset)
{
    int rc;

    if ( reset )
    {
        if (alt_avalon_ide_cf_init( ide_base ))
            return -1;
    }

    rc = master_slave_detect();
    if (rc)
        return -10 + rc;

    rc = check_registers();
    if (rc)
        return -30 + rc;
    
    return 0;
}

static int wait_for_start_of_transfer(void)
{
    if (!wait_for_bsy())
        return 0;
    return (ATA_ALT_STATUS & (STATUS_BSY|STATUS_DRQ)) == STATUS_DRQ;
}

static int identify(void)
{
    int i;

    IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD( ide_base, ata_device );

    if(!wait_for_rdy()) {
        DEBUGF("identify() - not RDY\n");
        return -1;
    }

    IOWR_ALTERA_AVALON_CF_IDE_COMMAND( ide_base, CMD_IDENTIFY);

    if (!wait_for_start_of_transfer())
    {
        DEBUGF("identify() - CMD failed\n");
        return -2;
    }

    for (i=0; i<SECTOR_SIZE/2; i++) {
        /* the IDENTIFY words are already swapped, so we need to treat
           this info differently that normal sector data */
#ifdef SWAP_WORDS
        identify_info[i] = ATA_DATA;
#else
        identify_info[i] = SWAB16(ATA_DATA);
#endif
    }
    
    return 0;
}

static int freeze_lock(void)
{
    /* does the disk support Security Mode feature set? */
    if (identify_info[82] & 2)
    {
        IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD( ide_base, ata_device );

        if (!wait_for_rdy())
            return -1;

        IOWR_ALTERA_AVALON_CF_IDE_COMMAND( ide_base, CMD_SECURITY_FREEZE_LOCK );

        if (!wait_for_rdy())
            return -2;
    }

    return 0;
}

static int set_features(void)
{
    struct {
        unsigned char id_word;
        unsigned char id_bit;
        unsigned char subcommand;
        unsigned char parameter;
    } features[] = {
        { 83, 3, 0x05, 0x80 }, /* power management: lowest power without standby */
        { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */
        { 82, 6, 0xaa, 0 },    /* enable read look-ahead */
        { 83, 14, 0x03, 0 },   /* force PIO mode */
        { 0, 0, 0, 0 }         /* <end of list> */
    };
    int i;
    int pio_mode = 2;

    /* Find out the highest supported PIO mode */
    if(identify_info[64] & 2)
        pio_mode = 4;
    else
        if(identify_info[64] & 1)
            pio_mode = 3;

    /* Update the table */
    features[3].parameter = 8 + pio_mode;
    
    IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD( ide_base, ata_device );
//    SET_REG(ATA_SELECT, ata_device);

    if (!wait_for_rdy()) {
        DEBUGF("set_features() - not RDY\n");
        return -1;
    }

    for (i=0; features[i].id_word; i++) {
        if (identify_info[features[i].id_word] & (1 << features[i].id_bit)) {
            IOWR_ALTERA_AVALON_CF_IDE_FEATURES( ide_base, features[i].subcommand );
            IOWR_ALTERA_AVALON_CF_IDE_SECTOR_COUNT( ide_base, features[i].parameter );
            IOWR_ALTERA_AVALON_CF_IDE_COMMAND( ide_base, CMD_SET_FEATURES );

            if (!wait_for_rdy()) {
                DEBUGF("set_features() - CMD failed\n");
                return -10 - i;
            }

            if(ATA_ALT_STATUS & STATUS_ERR) {
                if(ATA_ERROR & ERROR_ABRT) {
                    return -20 - i;
                }
            }
        }
    }

    return 0;
}

static int set_multiple_mode(int sectors)
{
    IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD( ide_base, ata_device );

    if(!wait_for_rdy()) {
        DEBUGF("set_multiple_mode() - not RDY\n");
        return -1;
    }

    IOWR_ALTERA_AVALON_CF_IDE_SECTOR_COUNT( ide_base, sectors );
    IOWR_ALTERA_AVALON_CF_IDE_COMMAND( ide_base, CMD_SET_MULTIPLE_MODE );

    if (!wait_for_rdy())
    {
        DEBUGF("set_multiple_mode() - CMD failed\n");
        return -2;
    }

    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -