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

📄 ata.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ata.c * * ATA RTEMS driver. ATA driver is hardware independant implementation of  * ATA-2 standart, working draft X3T10/0948D, revision 4c. ATA driver bases  * on RTEMS IDE controller driver. * * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. *  * $Id: ata.c,v 1.1.2.3 2003/09/04 18:46:04 joel Exp $ *  */#include <errno.h>#include <chain.h>#include <assert.h>#include <string.h> /* for "memset" declaration */#include <rtems/diskdevs.h>#include <rtems/blkdev.h>#include <libchip/ide_ctrl_io.h>#include <libchip/ide_ctrl_cfg.h>#include "ata_internal.h"#include <libchip/ata.h>#define DEBUG#ifdef DEBUG#include <stdio.h>#endif#define SAFE#ifdef SAFEtypedef rtems_mode preemption_key;#define DISABLE_PREEMPTION(key) \    do {                                                               \        rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \    } while (0)#define ENABLE_PREEMPTION(key) \    do {                                                        \        rtems_mode temp;                                        \        rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp);      \    } while (0)#else typedef boolean preemption_key;#define DISABLE_PREEMPTION(key) \    do {                                             \        (key) = _Thread_Executing->is_preemptible;   \        _Thread_Executing->is_preemptible = 0;       \    } while (0)    #define ENABLE_PREEMPTION(key) \    do {                                             \        _Thread_Executing->is_preemptible = (key);   \        if (_Thread_Evaluate_mode())                 \            _Thread_Dispatch();                      \    } while (0)#endif/* FIXME: case if ATA device is FLASH device need more attention */#undef ATA_DEV_IS_FLASH_DISK/* Block device request with a single buffer provided */typedef struct blkdev_request1 {    blkdev_request   req;    blkdev_sg_buffer sg[1];} blkdev_request1;/* Array indexed by controllers minor number */static ata_ide_ctrl_t ata_ide_ctrls[IDE_CTRL_MAX_MINOR_NUMBER];/* * Mapping from ATA-minor numbers to  * controller-minor and device on this controller. */static ata_ide_dev_t ata_devs[2 * IDE_CTRL_MAX_MINOR_NUMBER];static int ata_devs_number;/* Flag meaning that ATA driver has already been initialized */static rtems_boolean ata_initialized = FALSE;/* task and queue used for asynchronous I/O operations */static rtems_id ata_task_id;static rtems_id ata_queue_id;/* Mapping of interrupt vectors to devices */static Chain_Control ata_int_vec[ATA_MAX_RTEMS_INT_VEC_NUMBER + 1];  static voidata_process_request(rtems_device_minor_number ctrl_minor);static voidata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,                                  ata_req_t                 *areq);static void ata_add_to_controller_queue(rtems_device_minor_number  ctrl_minor,                             ata_req_t                 *areq);/* * read/write, open/close and ioctl are provided by general block device  * driver. Only initialization and ata-specific ioctl are here. *//* ata_io_data_request --  *     Form read/write request for an ATA device and enqueue it to  *     IDE controller.  *  * PARAMETERS: *     device - device identifier *     req    - read/write request from block device driver * * RETURNS: *     RTEMS_SUCCESSFUL on success, or error code if *     error occured  */static rtems_status_codeata_io_data_request(dev_t device, blkdev_request *req){    ata_req_t                 *areq; /* ATA request */    rtems_device_minor_number  rel_minor; /* relative minor which indexes                                            * ata_devs array                                           */    rtems_device_minor_number  ctrl_minor;    unsigned8                  dev;        rel_minor = (rtems_filesystem_dev_minor_t(device)) /                 ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;        /* get controller which serves the ATA device */    ctrl_minor = ata_devs[rel_minor].ctrl_minor;    /* get ATA device identifier (0 or 1) */    dev = ata_devs[rel_minor].device;    areq = malloc(sizeof(ata_req_t));    if (areq == NULL)    {        return RTEMS_NO_MEMORY;    }                                                                areq->breq = req;    areq->cnt = req->count;    areq->cbuf = 0;    areq->pos = 0;        /* set up registers masks */       areq->regs.to_write = ATA_REGISTERS_POSITION;    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);        /* choose device on the controller for which the command will be issued */    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] =                                     (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);    /* Find ATA command and its type */    if (ATA_DEV_INFO(ctrl_minor, dev).mode_active & ATA_MODES_DMA)    {        /* XXX: never has been tested */        areq->type = ATA_COMMAND_TYPE_DMA;        if (req->req == BLKDEV_REQ_READ)            areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_READ_DMA;        else             areq->regs.regs[IDE_REGISTER_COMMAND] = ATA_COMMAND_WRITE_DMA;    }    else     {        if (req->req == BLKDEV_REQ_READ)        {            areq->type = ATA_COMMAND_TYPE_PIO_IN;                          /*              * choose command to issue: if the number of blocks to be              * exchanged is greater then 1 and for ATA command READ MULTIPLE             * data block consists of more then 1 sector choose READ MULTIPLE             * otherwise READ SECTORS             */            areq->regs.regs[IDE_REGISTER_COMMAND] =                 ((ATA_DEV_INFO(ctrl_minor, dev).max_multiple) &&                  (req->count > 1) &&                  (ATA_DEV_INFO(ctrl_minor, dev).current_multiple > 1)) ?                  ATA_COMMAND_READ_MULTIPLE :                  ATA_COMMAND_READ_SECTORS;        }        else        {            areq->type = ATA_COMMAND_TYPE_PIO_OUT;            /*              * choose command to issue: if the number of blocks to be              * exchanged is greater then 1 and for ATA command WRITE MULTIPLE             * data block consists of more then 1 sector choose WRITE MULTIPLE             * otherwise WRITE SECTORS             */            areq->regs.regs[IDE_REGISTER_COMMAND] =               ((ATA_DEV_INFO(ctrl_minor, dev).max_multiple) &&               (req->count > 1) &&               (ATA_DEV_INFO(ctrl_minor, dev).current_multiple > 1)) ?                ATA_COMMAND_WRITE_MULTIPLE :                ATA_COMMAND_WRITE_SECTORS;        }    }    /*     * Fill position registers     */    if (ATA_DEV_INFO(ctrl_minor, dev).lba_avaible)    {        areq->regs.regs[IDE_REGISTER_LBA0] = (unsigned8)req->start;        areq->regs.regs[IDE_REGISTER_LBA1] = (unsigned8)(req->start >> 8);        areq->regs.regs[IDE_REGISTER_LBA2] = (unsigned8)(req->start >> 16);        areq->regs.regs[IDE_REGISTER_LBA3] |= (unsigned8) (req->start >> 24);        areq->regs.regs[IDE_REGISTER_LBA3] |= IDE_REGISTER_LBA3_L;    }    else    {        unsigned32 count = req->start;        areq->regs.regs[IDE_REGISTER_SECTOR_NUMBER] =                        (count % ATA_DEV_INFO(ctrl_minor, dev).sectors) + 1;        /* now count = number of tracks: */        count /= ATA_DEV_INFO(ctrl_minor, dev).sectors;        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |=                           (count / ATA_DEV_INFO(ctrl_minor, dev).cylinders);        /* now count = number of cylinders */        count %= ATA_DEV_INFO(ctrl_minor, dev).cylinders;        areq->regs.regs[IDE_REGISTER_CYLINDER_LOW] = (unsigned8)count;        areq->regs.regs[IDE_REGISTER_CYLINDER_HIGH] = (unsigned8)(count >> 8);        areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &=                                                 ~IDE_REGISTER_DEVICE_HEAD_L;    }    /* fill sector count register */    areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] = areq->breq->count;        /* add request to the queue of awaiting requests to the controller */    ata_add_to_controller_queue(ctrl_minor, areq);     return RTEMS_SUCCESSFUL;}/* ata_non_data_request --  *     Form and serve request of NON DATA type for an ATA device.  *     Processing of NON DATA request is SYNChronous operation. *  * PARAMETERS: *     device - device identifier *     cmd    - command *     argp   - arguments for command * * RETURNS: *     RTEMS_SUCCESSFUL on success, or error code if *     error occured  */static rtems_status_codeata_non_data_request(dev_t device, int cmd, void *argp){    rtems_status_code          rc;    ata_req_t                 *areq;       /* ATA request */    rtems_device_minor_number  rel_minor; /* relative minor which indexes                                           * ata_devs array                                           */    rtems_device_minor_number  ctrl_minor;    unsigned8                  dev;    ata_queue_msg_t            msg;            rel_minor = (rtems_filesystem_dev_minor_t(device)) /                ATA_MINOR_NUM_RESERVED_PER_ATA_DEVICE;     /* get controller which serves the ATA device */    ctrl_minor = ata_devs[rel_minor].ctrl_minor;    /* get ATA device identifier (0 or 1) */    dev = ata_devs[rel_minor].device;    /* form the request */    areq = malloc(sizeof(ata_req_t));    if (areq == NULL)    {        return RTEMS_NO_MEMORY;    }    memset(areq, 0, sizeof(ata_req_t));        areq->type = ATA_COMMAND_TYPE_NON_DATA;    areq->regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);    areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] |=                                     (dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS);    areq->breq = NULL;    areq->regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_ERROR);        /*      * depending on command fill command register and additional registers      * which are needed for command execution     */    switch(cmd)    {         case ATAIO_SET_MULTIPLE_MODE:            areq->regs.regs[IDE_REGISTER_COMMAND] =                                                 ATA_COMMAND_SET_MULTIPLE_MODE;            areq->regs.to_write |=                                ATA_REGISTERS_VALUE(IDE_REGISTER_SECTOR_COUNT);            areq->regs.regs[IDE_REGISTER_SECTOR_COUNT] = *(unsigned8 *)argp;            break;                default:            free(areq);            return RTEMS_INVALID_NUMBER;            break;                                    }      rc = rtems_semaphore_create(rtems_build_name('I', 'D', 'E', 'S'),                                 0,                                 RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE |                                 RTEMS_NO_INHERIT_PRIORITY |                                RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,                                0,                                &(areq->sema));    if (rc != RTEMS_SUCCESSFUL)    {        free(areq);        return rc;    }                                                                             ata_add_to_controller_queue(ctrl_minor, areq);        /* wait for request processing... */    rc = rtems_semaphore_obtain(areq->sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);    if (rc != RTEMS_SUCCESSFUL)    {        free(areq);        return rc;    }                                     rtems_semaphore_delete(areq->sema);        /*      * if no error occurred and if necessary, update internal ata driver data      * structures to reflect changes (in device configuration, for example)     */     if (areq->status == RTEMS_SUCCESSFUL)    {        switch(cmd)        {             case ATAIO_SET_MULTIPLE_MODE:                ATA_DEV_INFO(ctrl_minor, dev).current_multiple =                                                            *(unsigned8 *)argp;                break;                    default:                rc = RTEMS_INVALID_NUMBER;                break;                                        }      }        else        {            /* XXX: should be correct error processing: for ex, may be          * ABRT and then we should return RTEMS_NOT_IMPLEMENTED         */        rc = RTEMS_IO_ERROR;    }            /* tell ata driver that controller ready to serve next request */    ATA_SEND_EVT(msg, ATA_MSG_SUCCESS_EVT, ctrl_minor, 0);                                                     return rc;}/* ata_process_request --  *     Get first request from controller's queue and process it.  *  * PARAMETERS: *     ctrl_minor - controller identifier * * RETURNS: *     NONE  */static voidata_process_request(rtems_device_minor_number ctrl_minor){    ata_req_t       *areq;    unsigned16       byte; /* emphasize that only 8 low bits is meaningful */    ata_queue_msg_t  msg;    unsigned8        i, dev;    unsigned16       val;    unsigned16       data_bs; /* the number of 512-bytes sectors in one                                * data block                                */    ISR_Level        level;                                       /* if no requests to controller then do nothing */    if (Chain_Is_empty(&ata_ide_ctrls[ctrl_minor].reqs))        return;    /* get first request in the controller's queue */    _ISR_Disable(level);    areq = (ata_req_t *)(ata_ide_ctrls[ctrl_minor].reqs.first);    _ISR_Enable(level);        /* get ATA device identifier (0 or 1) */    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &            IDE_REGISTER_DEVICE_HEAD_DEV;    /* get data block size */    data_bs = ATA_DEV_INFO(ctrl_minor, dev).current_multiple ?                ATA_DEV_INFO(ctrl_minor, dev).current_multiple : 1;              /* execute device select protocol */    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,                                   areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);        do {        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);    } while ((byte & IDE_REGISTER_STATUS_BSY) ||              (!(byte & IDE_REGISTER_STATUS_DRDY)));    /* fill in all  necessary registers on the controller */    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)    {        unsigned32 reg = (1 << i);        if (areq->regs.to_write & reg)            ide_controller_write_register(ctrl_minor, i, areq->regs.regs[i]);    }    /* continue to execute ATA protocols depending on type of request */    if (areq->type == ATA_COMMAND_TYPE_PIO_OUT)    {        do {

⌨️ 快捷键说明

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