summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev/ide/ata_util.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-03 07:20:11 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-04 10:13:28 +0200
commit27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a (patch)
treedef0664dcddc53fd5d599b455c64f76ca2293606 /bsps/shared/dev/ide/ata_util.c
parentbsps: Move config macros to RTEMS_BSP_CONFIGURE (diff)
downloadrtems-27de4e1fb8bcdbdd8cb882fc0d7a2c152b4e027a.tar.bz2
bsps: Move libchip to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/shared/dev/ide/ata_util.c')
-rw-r--r--bsps/shared/dev/ide/ata_util.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/bsps/shared/dev/ide/ata_util.c b/bsps/shared/dev/ide/ata_util.c
new file mode 100644
index 0000000000..68e0f0bbe5
--- /dev/null
+++ b/bsps/shared/dev/ide/ata_util.c
@@ -0,0 +1,215 @@
+/*
+ * 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.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+#include <libchip/ata_internal.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;
+#if 0
+ uint8_t dev;
+#endif
+ uint16_t val, val1;
+ volatile unsigned retries;
+
+ assert(areq);
+
+#if 0
+ dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
+ IDE_REGISTER_DEVICE_HEAD_DEV;
+#endif
+
+ 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;
+}