forked from Imagelibrary/rtems
2010-08-17 Sebastian Huber <sebastian.huber@embedded-brains.de>
* libchip/ide/ata_util.c: New file. * libchip/Makefile.am: Reflect change from above. * libchip/ide/ata.c: Moved ata_breq_init(), ata_identify_device(), and ata_process_request_on_init_phase() into new file.
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
2010-08-17 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
||||
|
||||
* libchip/ide/ata_util.c: New file.
|
||||
* libchip/Makefile.am: Reflect change from above.
|
||||
* libchip/ide/ata.c: Moved ata_breq_init(), ata_identify_device(), and
|
||||
ata_process_request_on_init_phase() into new file.
|
||||
|
||||
2010-08-17 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
||||
|
||||
* libchip/ide/ata_internal.h, libchip/ide/ata.c: Moved code into
|
||||
|
||||
@@ -30,7 +30,8 @@ include_libchip_HEADERS += ide/ata.h ide/ide_ctrl_cfg.h ide/ide_ctrl.h \
|
||||
ide/ide_ctrl_io.h
|
||||
|
||||
noinst_LIBRARIES += libide.a
|
||||
libide_a_SOURCES = ide/ata.c ide/ide_controller.c ide/ata_internal.h
|
||||
libide_a_SOURCES = ide/ata.c ide/ata_util.c ide/ide_controller.c \
|
||||
ide/ata_internal.h
|
||||
libide_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
# network
|
||||
|
||||
@@ -1400,199 +1400,3 @@ rtems_ata_initialize(rtems_device_major_number major,
|
||||
ata_initialized = true;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/* ata_process_request_on_init_phase --
|
||||
* Process the ATA request during system initialization. Request
|
||||
* processing is syncronous and doesn't use multiprocessing enviroment.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* ctrl_minor - controller identifier
|
||||
* areq - ATA request
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor,
|
||||
ata_req_t *areq)
|
||||
{
|
||||
uint16_t byte;/* emphasize that only 8 low bits is meaningful */
|
||||
uint8_t i, dev;
|
||||
uint16_t val, val1;
|
||||
volatile unsigned retries;
|
||||
|
||||
assert(areq);
|
||||
|
||||
dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
|
||||
IDE_REGISTER_DEVICE_HEAD_DEV;
|
||||
|
||||
ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
|
||||
areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
|
||||
|
||||
retries = 0;
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
/* If device (on INIT, i.e. it should be idle) is neither
|
||||
* busy nor ready something's fishy, i.e., there is probably
|
||||
* no device present.
|
||||
* I'd like to do a proper timeout but don't know of a portable
|
||||
* timeout routine (w/o using multitasking / rtems_task_wake_after())
|
||||
*/
|
||||
if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
|
||||
retries++;
|
||||
if ( 10000 == retries ) {
|
||||
/* probably no drive connected */
|
||||
areq->breq->status = RTEMS_UNSATISFIED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while ((byte & IDE_REGISTER_STATUS_BSY) ||
|
||||
(!(byte & IDE_REGISTER_STATUS_DRDY)));
|
||||
|
||||
for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
|
||||
{
|
||||
uint32_t reg = (1 << i);
|
||||
if (areq->regs.to_write & reg)
|
||||
ide_controller_write_register(ctrl_minor, i,
|
||||
areq->regs.regs[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
} while (byte & IDE_REGISTER_STATUS_BSY);
|
||||
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
|
||||
|
||||
if (val & IDE_REGISTER_STATUS_ERR)
|
||||
{
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(areq->type)
|
||||
{
|
||||
case ATA_COMMAND_TYPE_PIO_IN:
|
||||
if (areq->cnt)
|
||||
{
|
||||
int ccbuf = areq->cbuf;
|
||||
ide_controller_read_data_block(ctrl_minor,
|
||||
areq->breq->bufs[0].length * areq->cnt,
|
||||
areq->breq->bufs, &areq->cbuf,
|
||||
&areq->pos);
|
||||
ccbuf = areq->cbuf - ccbuf;
|
||||
areq->cnt -= ccbuf;
|
||||
}
|
||||
if (areq->cnt == 0)
|
||||
{
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* this shouldn't happend on the initialization
|
||||
* phase!
|
||||
*/
|
||||
rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATA_COMMAND_TYPE_NON_DATA:
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
areq->info = val1;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if ATA_DEBUG
|
||||
ata_printf("ata_queue_task: non-supported command type\n");
|
||||
#endif
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
|
||||
{
|
||||
memset(breq, 0, sizeof(*breq));
|
||||
|
||||
breq->req.done_arg = breq;
|
||||
breq->req.bufnum = 1;
|
||||
breq->req.bufs [0].length = ATA_SECTOR_SIZE;
|
||||
breq->req.bufs [0].buffer = sector_buffer;
|
||||
}
|
||||
|
||||
rtems_status_code ata_identify_device(
|
||||
rtems_device_minor_number ctrl_minor,
|
||||
int dev,
|
||||
uint16_t *sector_buffer,
|
||||
ata_dev_t *device_entry
|
||||
)
|
||||
{
|
||||
ata_req_t areq;
|
||||
blkdev_request1 breq;
|
||||
|
||||
ata_breq_init(&breq, sector_buffer);
|
||||
|
||||
/*
|
||||
* Issue DEVICE IDENTIFY ATA command and get device
|
||||
* configuration
|
||||
*/
|
||||
memset(&areq, 0, sizeof(ata_req_t));
|
||||
areq.type = ATA_COMMAND_TYPE_PIO_IN;
|
||||
areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
|
||||
areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
|
||||
areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
|
||||
areq.breq = (rtems_blkdev_request *)&breq;
|
||||
areq.cnt = breq.req.bufnum;
|
||||
areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
|
||||
dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
|
||||
|
||||
/*
|
||||
* Process the request. Special processing of requests on
|
||||
* initialization phase is needed because at this moment there
|
||||
* is no multitasking enviroment
|
||||
*/
|
||||
ata_process_request_on_init_phase(ctrl_minor, &areq);
|
||||
|
||||
/* check status of I/O operation */
|
||||
if (breq.req.status != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse returned device configuration and fill in ATA internal
|
||||
* device info structure
|
||||
*/
|
||||
device_entry->cylinders =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
|
||||
device_entry->heads =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
|
||||
device_entry->sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
|
||||
device_entry->lba_sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
|
||||
device_entry->lba_sectors <<= 16;
|
||||
device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
|
||||
device_entry->lba_avaible =
|
||||
(CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
|
||||
|
||||
if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
|
||||
ATA_IDENT_BIT_VALID) == 0) {
|
||||
/* no "supported modes" info -> use default */
|
||||
device_entry->mode_active = ATA_MODES_PIO3;
|
||||
} else {
|
||||
device_entry->modes_available =
|
||||
((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
|
||||
((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x2) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x4) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
|
||||
if (device_entry->modes_available == 0) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
213
c/src/libchip/ide/ata_util.c
Normal file
213
c/src/libchip/ide/ata_util.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2010 embedded brains GmbH.
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#include "ata_internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libchip/ide_ctrl_io.h>
|
||||
#include <libchip/ide_ctrl_cfg.h>
|
||||
|
||||
/* ata_process_request_on_init_phase --
|
||||
* Process the ATA request during system initialization. Request
|
||||
* processing is syncronous and doesn't use multiprocessing enviroment.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* ctrl_minor - controller identifier
|
||||
* areq - ATA request
|
||||
*
|
||||
* RETURNS:
|
||||
* NONE
|
||||
*/
|
||||
void
|
||||
ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor,
|
||||
ata_req_t *areq)
|
||||
{
|
||||
uint16_t byte;/* emphasize that only 8 low bits is meaningful */
|
||||
uint8_t i, dev;
|
||||
uint16_t val, val1;
|
||||
volatile unsigned retries;
|
||||
|
||||
assert(areq);
|
||||
|
||||
dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
|
||||
IDE_REGISTER_DEVICE_HEAD_DEV;
|
||||
|
||||
ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
|
||||
areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
|
||||
|
||||
retries = 0;
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
/* If device (on INIT, i.e. it should be idle) is neither
|
||||
* busy nor ready something's fishy, i.e., there is probably
|
||||
* no device present.
|
||||
* I'd like to do a proper timeout but don't know of a portable
|
||||
* timeout routine (w/o using multitasking / rtems_task_wake_after())
|
||||
*/
|
||||
if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
|
||||
retries++;
|
||||
if ( 10000 == retries ) {
|
||||
/* probably no drive connected */
|
||||
areq->breq->status = RTEMS_UNSATISFIED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while ((byte & IDE_REGISTER_STATUS_BSY) ||
|
||||
(!(byte & IDE_REGISTER_STATUS_DRDY)));
|
||||
|
||||
for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
|
||||
{
|
||||
uint32_t reg = (1 << i);
|
||||
if (areq->regs.to_write & reg)
|
||||
ide_controller_write_register(ctrl_minor, i,
|
||||
areq->regs.regs[i]);
|
||||
}
|
||||
|
||||
do {
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
||||
} while (byte & IDE_REGISTER_STATUS_BSY);
|
||||
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
|
||||
ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
|
||||
|
||||
if (val & IDE_REGISTER_STATUS_ERR)
|
||||
{
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(areq->type)
|
||||
{
|
||||
case ATA_COMMAND_TYPE_PIO_IN:
|
||||
if (areq->cnt)
|
||||
{
|
||||
int ccbuf = areq->cbuf;
|
||||
ide_controller_read_data_block(ctrl_minor,
|
||||
areq->breq->bufs[0].length * areq->cnt,
|
||||
areq->breq->bufs, &areq->cbuf,
|
||||
&areq->pos);
|
||||
ccbuf = areq->cbuf - ccbuf;
|
||||
areq->cnt -= ccbuf;
|
||||
}
|
||||
if (areq->cnt == 0)
|
||||
{
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* this shouldn't happend on the initialization
|
||||
* phase!
|
||||
*/
|
||||
rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATA_COMMAND_TYPE_NON_DATA:
|
||||
areq->breq->status = RTEMS_SUCCESSFUL;
|
||||
areq->info = val1;
|
||||
break;
|
||||
|
||||
default:
|
||||
areq->breq->status = RTEMS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
|
||||
{
|
||||
memset(breq, 0, sizeof(*breq));
|
||||
|
||||
breq->req.done_arg = breq;
|
||||
breq->req.bufnum = 1;
|
||||
breq->req.bufs [0].length = ATA_SECTOR_SIZE;
|
||||
breq->req.bufs [0].buffer = sector_buffer;
|
||||
}
|
||||
|
||||
rtems_status_code ata_identify_device(
|
||||
rtems_device_minor_number ctrl_minor,
|
||||
int dev,
|
||||
uint16_t *sector_buffer,
|
||||
ata_dev_t *device_entry
|
||||
)
|
||||
{
|
||||
ata_req_t areq;
|
||||
blkdev_request1 breq;
|
||||
|
||||
ata_breq_init(&breq, sector_buffer);
|
||||
|
||||
/*
|
||||
* Issue DEVICE IDENTIFY ATA command and get device
|
||||
* configuration
|
||||
*/
|
||||
memset(&areq, 0, sizeof(ata_req_t));
|
||||
areq.type = ATA_COMMAND_TYPE_PIO_IN;
|
||||
areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
|
||||
areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
|
||||
areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
|
||||
areq.breq = (rtems_blkdev_request *)&breq;
|
||||
areq.cnt = breq.req.bufnum;
|
||||
areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
|
||||
dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
|
||||
|
||||
/*
|
||||
* Process the request. Special processing of requests on
|
||||
* initialization phase is needed because at this moment there
|
||||
* is no multitasking enviroment
|
||||
*/
|
||||
ata_process_request_on_init_phase(ctrl_minor, &areq);
|
||||
|
||||
/* check status of I/O operation */
|
||||
if (breq.req.status != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse returned device configuration and fill in ATA internal
|
||||
* device info structure
|
||||
*/
|
||||
device_entry->cylinders =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
|
||||
device_entry->heads =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
|
||||
device_entry->sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
|
||||
device_entry->lba_sectors =
|
||||
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
|
||||
device_entry->lba_sectors <<= 16;
|
||||
device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
|
||||
device_entry->lba_avaible =
|
||||
(CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
|
||||
|
||||
if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
|
||||
ATA_IDENT_BIT_VALID) == 0) {
|
||||
/* no "supported modes" info -> use default */
|
||||
device_entry->mode_active = ATA_MODES_PIO3;
|
||||
} else {
|
||||
device_entry->modes_available =
|
||||
((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
|
||||
((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x2) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
|
||||
((CF_LE_W(sector_buffer[63]) & 0x4) ?
|
||||
ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
|
||||
if (device_entry->modes_available == 0) {
|
||||
return RTEMS_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
Reference in New Issue
Block a user