HelenOS sources
This source file includes following definitions.
- isa_ide_channel_init
- isa_ide_channel_fini
- isa_ide_init_io
- isa_ide_fini_io
- isa_ide_init_irq
- isa_ide_fini_irq
- isa_ide_irq_handler
- isa_ide_write_data_16
- isa_ide_read_data_16
- isa_ide_write_cmd_8
- isa_ide_read_cmd_8
- isa_ide_write_ctl_8
- isa_ide_read_ctl_8
- isa_ide_irq_enable
- isa_ide_irq_disable
- isa_ide_add_device
- isa_ide_remove_device
- isa_ide_msg_debug
- isa_ide_msg_note
- isa_ide_msg_warn
- isa_ide_msg_error
#include <ddi.h>
#include <ddf/interrupt.h>
#include <ddf/log.h>
#include <async.h>
#include <as.h>
#include <fibril_synch.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stddef.h>
#include <str.h>
#include <inttypes.h>
#include <errno.h>
#include "isa-ide.h"
#include "main.h"
static errno_t isa_ide_init_io(isa_ide_channel_t *);
static void isa_ide_fini_io(isa_ide_channel_t *);
static errno_t isa_ide_init_irq(isa_ide_channel_t *);
static void isa_ide_fini_irq(isa_ide_channel_t *);
static void isa_ide_irq_handler(ipc_call_t *, void *);
static void isa_ide_write_data_16(void *, uint16_t *, size_t);
static void isa_ide_read_data_16(void *, uint16_t *, size_t);
static void isa_ide_write_cmd_8(void *, uint16_t, uint8_t);
static uint8_t isa_ide_read_cmd_8(void *, uint16_t);
static void isa_ide_write_ctl_8(void *, uint16_t, uint8_t);
static uint8_t isa_ide_read_ctl_8(void *, uint16_t);
static errno_t isa_ide_irq_enable(void *);
static errno_t isa_ide_irq_disable(void *);
static errno_t isa_ide_add_device(void *, unsigned, void *);
static errno_t isa_ide_remove_device(void *, unsigned);
static void isa_ide_msg_debug(void *, char *);
static void isa_ide_msg_note(void *, char *);
static void isa_ide_msg_warn(void *, char *);
static void isa_ide_msg_error(void *, char *);
static const irq_pio_range_t isa_ide_irq_ranges[] = {
{
.base = 0,
.size = sizeof(ata_cmd_t)
}
};
static const irq_cmd_t isa_ide_irq_cmds[] = {
{
.cmd = CMD_PIO_READ_8,
.addr = NULL,
.dstarg = 1
},
{
.cmd = CMD_ACCEPT
}
};
errno_t isa_ide_channel_init(isa_ide_ctrl_t *ctrl, isa_ide_channel_t *chan,
unsigned chan_id, isa_ide_hwres_t *res)
{
errno_t rc;
bool irq_inited = false;
ata_params_t params;
ddf_msg(LVL_DEBUG, "isa_ide_ctrl_init()");
chan->ctrl = ctrl;
chan->chan_id = chan_id;
fibril_mutex_initialize(&chan->lock);
if (chan_id == 0) {
chan->cmd_physical = res->cmd1;
chan->ctl_physical = res->ctl1;
chan->irq = res->irq1;
} else {
chan->cmd_physical = res->cmd2;
chan->ctl_physical = res->ctl2;
chan->irq = res->irq2;
}
ddf_msg(LVL_NOTE, "I/O address %p/%p", (void *) chan->cmd_physical,
(void *) chan->ctl_physical);
ddf_msg(LVL_DEBUG, "Init I/O");
rc = isa_ide_init_io(chan);
if (rc != EOK)
return rc;
ddf_msg(LVL_DEBUG, "Init IRQ");
rc = isa_ide_init_irq(chan);
if (rc != EOK) {
ddf_msg(LVL_NOTE, "init IRQ failed");
return rc;
}
irq_inited = true;
ddf_msg(LVL_DEBUG, "isa_ide_ctrl_init(): Initialize IDE channel");
params.arg = (void *)chan;
params.have_irq = (chan->irq >= 0) ? true : false;
params.write_data_16 = isa_ide_write_data_16;
params.read_data_16 = isa_ide_read_data_16;
params.write_cmd_8 = isa_ide_write_cmd_8;
params.read_cmd_8 = isa_ide_read_cmd_8;
params.write_ctl_8 = isa_ide_write_ctl_8;
params.read_ctl_8 = isa_ide_read_ctl_8;
params.irq_enable = isa_ide_irq_enable;
params.irq_disable = isa_ide_irq_disable;
params.add_device = isa_ide_add_device;
params.remove_device = isa_ide_remove_device;
params.msg_debug = isa_ide_msg_debug;
params.msg_note = isa_ide_msg_note;
params.msg_warn = isa_ide_msg_warn;
params.msg_error = isa_ide_msg_error;
rc = ata_channel_create(¶ms, &chan->channel);
if (rc != EOK)
goto error;
rc = ata_channel_initialize(chan->channel);
if (rc != EOK)
goto error;
ddf_msg(LVL_DEBUG, "isa_ide_ctrl_init: DONE");
return EOK;
error:
if (chan->channel != NULL) {
(void) ata_channel_destroy(chan->channel);
chan->channel = NULL;
}
if (irq_inited)
isa_ide_fini_irq(chan);
isa_ide_fini_io(chan);
return rc;
}
errno_t isa_ide_channel_fini(isa_ide_channel_t *chan)
{
errno_t rc;
ddf_msg(LVL_DEBUG, ": isa_ide_ctrl_remove()");
fibril_mutex_lock(&chan->lock);
rc = ata_channel_destroy(chan->channel);
if (rc != EOK) {
fibril_mutex_unlock(&chan->lock);
return rc;
}
isa_ide_fini_irq(chan);
isa_ide_fini_io(chan);
fibril_mutex_unlock(&chan->lock);
return EOK;
}
static errno_t isa_ide_init_io(isa_ide_channel_t *chan)
{
errno_t rc;
void *vaddr;
rc = pio_enable((void *) chan->cmd_physical, sizeof(ata_cmd_t), &vaddr);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
return rc;
}
chan->cmd = vaddr;
rc = pio_enable((void *) chan->ctl_physical, sizeof(ata_ctl_t), &vaddr);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
return rc;
}
chan->ctl = vaddr;
return EOK;
}
static void isa_ide_fini_io(isa_ide_channel_t *chan)
{
(void) chan;
}
static errno_t isa_ide_init_irq(isa_ide_channel_t *chan)
{
irq_code_t irq_code;
irq_pio_range_t *ranges;
irq_cmd_t *cmds;
errno_t rc;
if (chan->irq < 0)
return EOK;
ranges = malloc(sizeof(isa_ide_irq_ranges));
if (ranges == NULL)
return ENOMEM;
cmds = malloc(sizeof(isa_ide_irq_cmds));
if (cmds == NULL) {
free(cmds);
return ENOMEM;
}
memcpy(ranges, &isa_ide_irq_ranges, sizeof(isa_ide_irq_ranges));
ranges[0].base = chan->cmd_physical;
memcpy(cmds, &isa_ide_irq_cmds, sizeof(isa_ide_irq_cmds));
cmds[0].addr = &chan->cmd->status;
irq_code.rangecount = sizeof(isa_ide_irq_ranges) / sizeof(irq_pio_range_t);
irq_code.ranges = ranges;
irq_code.cmdcount = sizeof(isa_ide_irq_cmds) / sizeof(irq_cmd_t);
irq_code.cmds = cmds;
ddf_msg(LVL_NOTE, "IRQ %d", chan->irq);
rc = register_interrupt_handler(chan->ctrl->dev, chan->irq,
isa_ide_irq_handler, (void *)chan, &irq_code, &chan->ihandle);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error registering IRQ.");
goto error;
}
ddf_msg(LVL_DEBUG, "Interrupt handler registered");
free(ranges);
free(cmds);
return EOK;
error:
free(ranges);
free(cmds);
return rc;
}
static void isa_ide_fini_irq(isa_ide_channel_t *chan)
{
errno_t rc;
async_sess_t *parent_sess;
parent_sess = ddf_dev_parent_sess_get(chan->ctrl->dev);
rc = hw_res_disable_interrupt(parent_sess, chan->irq);
if (rc != EOK)
ddf_msg(LVL_ERROR, "Error disabling IRQ.");
(void) unregister_interrupt_handler(chan->ctrl->dev, chan->ihandle);
}
static void isa_ide_irq_handler(ipc_call_t *call, void *arg)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
uint8_t status;
async_sess_t *parent_sess;
status = ipc_get_arg1(call);
ata_channel_irq(chan->channel, status);
parent_sess = ddf_dev_parent_sess_get(chan->ctrl->dev);
hw_res_clear_interrupt(parent_sess, chan->irq);
}
static void isa_ide_write_data_16(void *arg, uint16_t *data, size_t nwords)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
size_t i;
for (i = 0; i < nwords; i++)
pio_write_16(&chan->cmd->data_port, data[i]);
}
static void isa_ide_read_data_16(void *arg, uint16_t *buf, size_t nwords)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
size_t i;
for (i = 0; i < nwords; i++)
buf[i] = pio_read_16(&chan->cmd->data_port);
}
static void isa_ide_write_cmd_8(void *arg, uint16_t off, uint8_t value)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
pio_write_8(((ioport8_t *)chan->cmd) + off, value);
}
static uint8_t isa_ide_read_cmd_8(void *arg, uint16_t off)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
return pio_read_8(((ioport8_t *)chan->cmd) + off);
}
static void isa_ide_write_ctl_8(void *arg, uint16_t off, uint8_t value)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
pio_write_8(((ioport8_t *)chan->ctl) + off, value);
}
static uint8_t isa_ide_read_ctl_8(void *arg, uint16_t off)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
return pio_read_8(((ioport8_t *)chan->ctl) + off);
}
static errno_t isa_ide_irq_enable(void *arg)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
async_sess_t *parent_sess;
errno_t rc;
ddf_msg(LVL_DEBUG, "Enable IRQ %d for channel %u",
chan->irq, chan->chan_id);
parent_sess = ddf_dev_parent_sess_get(chan->ctrl->dev);
rc = hw_res_enable_interrupt(parent_sess, chan->irq);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error enabling IRQ.");
return rc;
}
return EOK;
}
static errno_t isa_ide_irq_disable(void *arg)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
async_sess_t *parent_sess;
errno_t rc;
ddf_msg(LVL_DEBUG, "Disable IRQ");
parent_sess = ddf_dev_parent_sess_get(chan->ctrl->dev);
rc = hw_res_disable_interrupt(parent_sess, chan->irq);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error disabling IRQ.");
return rc;
}
return EOK;
}
static errno_t isa_ide_add_device(void *arg, unsigned idx, void *charg)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
return isa_ide_fun_create(chan, idx, charg);
}
static errno_t isa_ide_remove_device(void *arg, unsigned idx)
{
isa_ide_channel_t *chan = (isa_ide_channel_t *)arg;
return isa_ide_fun_remove(chan, idx);
}
static void isa_ide_msg_debug(void *arg, char *msg)
{
(void)arg;
ddf_msg(LVL_DEBUG, "%s", msg);
}
static void isa_ide_msg_note(void *arg, char *msg)
{
(void)arg;
ddf_msg(LVL_NOTE, "%s", msg);
}
static void isa_ide_msg_warn(void *arg, char *msg)
{
(void)arg;
ddf_msg(LVL_WARN, "%s", msg);
}
static void isa_ide_msg_error(void *arg, char *msg)
{
(void)arg;
ddf_msg(LVL_ERROR, "%s", msg);
}
HelenOS homepage, sources at GitHub