HelenOS sources
This source file includes following definitions.
- pc_fdc_create
- pc_fdc_destroy
- pc_fdc_init_io
- pc_fdc_fini_io
- pc_fdc_init_irq
- pc_fdc_fini_irq
- pc_fdc_fun_name
- pc_fdc_connection
- pc_fdc_drive_create
- pc_fdc_send_byte
- pc_fdc_send
- pc_fdc_get_byte
- pc_fdc_get
- pc_fdc_reset
- pc_fdc_read_id
- pc_fdc_drive_read_data
- pc_fdc_drive_write_data
- pc_fdc_sense_int_sts
- pc_fdc_irq_handler
- bd_srv_drive
- pc_fdc_drive_ba_to_chs
- pc_fdc_bd_open
- pc_fdc_bd_close
- pc_fdc_bd_read_blocks
- pc_fdc_bd_read_toc
- pc_fdc_bd_write_blocks
- pc_fdc_bd_get_block_size
- pc_fdc_bd_get_num_blocks
- pc_fdc_bd_sync_cache
#include <bd_srv.h>
#include <ddi.h>
#include <ddf/interrupt.h>
#include <ddf/log.h>
#include <async.h>
#include <as.h>
#include <errno.h>
#include <fibril_synch.h>
#include <macros.h>
#include <perf.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stddef.h>
#include <str.h>
#include <str_error.h>
#include <inttypes.h>
#include <errno.h>
#include "pc-floppy.h"
static errno_t pc_fdc_init_io(pc_fdc_t *);
static void pc_fdc_fini_io(pc_fdc_t *);
static errno_t pc_fdc_init_irq(pc_fdc_t *);
static void pc_fdc_fini_irq(pc_fdc_t *);
static void pc_fdc_irq_handler(ipc_call_t *, void *);
static errno_t pc_fdc_drive_create(pc_fdc_t *, unsigned, pc_fdc_drive_t **);
static errno_t pc_fdc_reset(pc_fdc_t *);
static errno_t pc_fdc_read_id(pc_fdc_t *, bool, uint8_t, uint8_t);
static errno_t pc_fdc_sense_int_sts(pc_fdc_t *);
static errno_t pc_fdc_bd_open(bd_srvs_t *, bd_srv_t *);
static errno_t pc_fdc_bd_close(bd_srv_t *);
static errno_t pc_fdc_bd_read_blocks(bd_srv_t *, uint64_t, size_t, void *, size_t);
static errno_t pc_fdc_bd_read_toc(bd_srv_t *, uint8_t, void *, size_t);
static errno_t pc_fdc_bd_write_blocks(bd_srv_t *, uint64_t, size_t, const void *,
size_t);
static errno_t pc_fdc_bd_get_block_size(bd_srv_t *, size_t *);
static errno_t pc_fdc_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
static errno_t pc_fdc_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
static bd_ops_t pc_fdc_bd_ops = {
.open = pc_fdc_bd_open,
.close = pc_fdc_bd_close,
.read_blocks = pc_fdc_bd_read_blocks,
.read_toc = pc_fdc_bd_read_toc,
.write_blocks = pc_fdc_bd_write_blocks,
.get_block_size = pc_fdc_bd_get_block_size,
.get_num_blocks = pc_fdc_bd_get_num_blocks,
.sync_cache = pc_fdc_bd_sync_cache
};
enum {
msr_read_cycles = 100,
fdc_def_dma_buf_size = 4096
};
static const irq_pio_range_t pc_fdc_irq_ranges[] = {
{
.base = 0,
.size = sizeof(pc_fdc_regs_t)
}
};
static const irq_cmd_t pc_fdc_irq_cmds[] = {
{
.cmd = CMD_ACCEPT
}
};
errno_t pc_fdc_create(ddf_dev_t *dev, pc_fdc_hwres_t *res, pc_fdc_t **rfdc)
{
errno_t rc;
pc_fdc_t *fdc;
bool irq_inited = false;
void *buffer = NULL;
ddf_msg(LVL_DEBUG, "pc_fdc_init()");
fdc = ddf_dev_data_alloc(dev, sizeof(pc_fdc_t));
if (fdc == NULL) {
ddf_msg(LVL_ERROR, "Failed allocating FDC.");
rc = ENOMEM;
goto error;
}
fdc->dev = dev;
fibril_mutex_initialize(&fdc->lock);
fdc->regs_physical = res->regs;
fdc->irq = res->irq;
fdc->dma = res->dma;
ddf_msg(LVL_NOTE, "I/O address %p", (void *)fdc->regs_physical);
ddf_msg(LVL_DEBUG, "Init I/O");
rc = pc_fdc_init_io(fdc);
if (rc != EOK)
return rc;
ddf_msg(LVL_DEBUG, "Init IRQ");
rc = pc_fdc_init_irq(fdc);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Init IRQ failed");
return rc;
}
irq_inited = true;
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init(): read ID");
fdc->dma_buf_size = fdc_def_dma_buf_size;
buffer = AS_AREA_ANY;
rc = dmamem_map_anonymous(fdc->dma_buf_size, DMAMEM_1MiB | 0xffff,
AS_AREA_WRITE | AS_AREA_READ, 0, &fdc->dma_buf_pa, &buffer);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed allocating PRD table.");
goto error;
}
fdc->dma_buf = buffer;
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: reset controller...");
(void)pc_fdc_reset(fdc);
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: read_ID..");
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: MSR=0x%x",
pio_read_8(&fdc->regs->msr));
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: DIR=0x%x",
pio_read_8(&fdc->regs->dir));
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: SRA=0x%x",
pio_read_8(&fdc->regs->sra));
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: SRB=0x%x",
pio_read_8(&fdc->regs->srb));
rc = pc_fdc_sense_int_sts(fdc);
if (rc != EOK)
return rc;
rc = pc_fdc_sense_int_sts(fdc);
if (rc != EOK)
return rc;
rc = pc_fdc_sense_int_sts(fdc);
if (rc != EOK)
return rc;
rc = pc_fdc_sense_int_sts(fdc);
if (rc != EOK)
return rc;
rc = pc_fdc_read_id(fdc, true, 0, 0);
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: read_ID -> %d", rc);
rc = pc_fdc_drive_create(fdc, 0, &fdc->drive[0]);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "pc_fdc_ctrl_init: pc_fdc_drive_create "
"failed");
goto error;
}
fdc->drive[0]->sec_size = 512;
fdc->drive[0]->cylinders = 80;
fdc->drive[0]->heads = 2;
fdc->drive[0]->sectors = 18;
ddf_msg(LVL_DEBUG, "pc_fdc_ctrl_init: DONE");
return EOK;
error:
if (buffer != NULL)
dmamem_unmap_anonymous(buffer);
if (irq_inited)
pc_fdc_fini_irq(fdc);
pc_fdc_fini_io(fdc);
return rc;
}
errno_t pc_fdc_destroy(pc_fdc_t *fdc)
{
ddf_msg(LVL_DEBUG, ": pc_fdc_destroy()");
fibril_mutex_lock(&fdc->lock);
pc_fdc_fini_irq(fdc);
pc_fdc_fini_io(fdc);
fibril_mutex_unlock(&fdc->lock);
free(fdc);
return EOK;
}
static errno_t pc_fdc_init_io(pc_fdc_t *fdc)
{
errno_t rc;
void *vaddr;
rc = pio_enable((void *) fdc->regs_physical, sizeof(pc_fdc_regs_t),
&vaddr);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
return rc;
}
fdc->regs = vaddr;
return EOK;
}
static void pc_fdc_fini_io(pc_fdc_t *fdc)
{
(void)fdc;
}
static errno_t pc_fdc_init_irq(pc_fdc_t *fdc)
{
irq_code_t irq_code;
irq_pio_range_t *ranges;
irq_cmd_t *cmds;
async_sess_t *parent_sess;
errno_t rc;
if (fdc->irq < 0)
return EOK;
ranges = malloc(sizeof(pc_fdc_irq_ranges));
if (ranges == NULL)
return ENOMEM;
cmds = malloc(sizeof(pc_fdc_irq_cmds));
if (cmds == NULL) {
free(cmds);
return ENOMEM;
}
memcpy(ranges, &pc_fdc_irq_ranges, sizeof(pc_fdc_irq_ranges));
ranges[0].base = fdc->regs_physical;
memcpy(cmds, &pc_fdc_irq_cmds, sizeof(pc_fdc_irq_cmds));
irq_code.rangecount = sizeof(pc_fdc_irq_ranges) / sizeof(irq_pio_range_t);
irq_code.ranges = ranges;
irq_code.cmdcount = sizeof(pc_fdc_irq_cmds) / sizeof(irq_cmd_t);
irq_code.cmds = cmds;
ddf_msg(LVL_NOTE, "IRQ %d", fdc->irq);
rc = register_interrupt_handler(fdc->dev, fdc->irq,
pc_fdc_irq_handler, (void *)fdc, &irq_code, &fdc->ihandle);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error registering IRQ.");
goto error;
}
parent_sess = ddf_dev_parent_sess_get(fdc->dev);
rc = hw_res_enable_interrupt(parent_sess, fdc->irq);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Error enabling IRQ.");
return rc;
}
ddf_msg(LVL_DEBUG, "Interrupt handler registered");
free(ranges);
free(cmds);
return EOK;
error:
free(ranges);
free(cmds);
return rc;
}
static void pc_fdc_fini_irq(pc_fdc_t *fdc)
{
errno_t rc;
async_sess_t *parent_sess;
parent_sess = ddf_dev_parent_sess_get(fdc->dev);
rc = hw_res_disable_interrupt(parent_sess, fdc->irq);
if (rc != EOK)
ddf_msg(LVL_ERROR, "Error disabling IRQ.");
(void) unregister_interrupt_handler(fdc->dev, fdc->ihandle);
}
static char *pc_fdc_fun_name(pc_fdc_t *fdc, unsigned idx)
{
char *fun_name;
if (asprintf(&fun_name, "d%u", idx) < 0)
return NULL;
return fun_name;
}
static void pc_fdc_connection(ipc_call_t *icall, void *arg)
{
pc_fdc_drive_t *drive;
drive = (pc_fdc_drive_t *)ddf_fun_data_get((ddf_fun_t *)arg);
bd_conn(icall, &drive->bds);
}
static errno_t pc_fdc_drive_create(pc_fdc_t *fdc, unsigned idx,
pc_fdc_drive_t **rdrive)
{
errno_t rc;
char *fun_name = NULL;
ddf_fun_t *fun = NULL;
pc_fdc_drive_t *drive = NULL;
bool bound = false;
fun_name = pc_fdc_fun_name(fdc, idx);
if (fun_name == NULL) {
ddf_msg(LVL_ERROR, "Out of memory.");
rc = ENOMEM;
goto error;
}
fun = ddf_fun_create(fdc->dev, fun_exposed, fun_name);
if (fun == NULL) {
ddf_msg(LVL_ERROR, "Failed creating DDF function.");
rc = ENOMEM;
goto error;
}
drive = ddf_fun_data_alloc(fun, sizeof(pc_fdc_drive_t));
if (drive == NULL) {
ddf_msg(LVL_ERROR, "Failed allocating softstate.");
rc = ENOMEM;
goto error;
}
drive->fdc = fdc;
drive->fun = fun;
bd_srvs_init(&drive->bds);
drive->bds.ops = &pc_fdc_bd_ops;
drive->bds.sarg = (void *)drive;
ddf_fun_set_conn_handler(fun, pc_fdc_connection);
rc = ddf_fun_bind(fun);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed binding DDF function %s: %s",
fun_name, str_error(rc));
goto error;
}
bound = true;
#if 0
rc = ddf_fun_add_to_category(fun, "partition");
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed adding function %s to "
"category 'partition': %s", fun_name, str_error(rc));
goto error;
}
#endif
free(fun_name);
*rdrive = drive;
return EOK;
error:
if (bound)
ddf_fun_unbind(fun);
if (fun != NULL)
ddf_fun_destroy(fun);
if (fun_name != NULL)
free(fun_name);
return rc;
}
static errno_t pc_fdc_send_byte(pc_fdc_t *fdc, uint8_t byte)
{
unsigned cnt;
uint8_t status;
stopwatch_t sw;
nsec_t nsec;
stopwatch_init(&sw);
stopwatch_start(&sw);
status = pio_read_8(&fdc->regs->msr);
ddf_msg(LVL_DEBUG, "pc_fdc_send_byte: status=0x%x", status);
do {
cnt = msr_read_cycles;
while (cnt > 0) {
if ((status & fmsr_rqm) != 0 &&
(status & fmsr_dio) == 0) {
pio_write_8(&fdc->regs->data, byte);
return EOK;
}
--cnt;
status = pio_read_8(&fdc->regs->msr);
}
stopwatch_stop(&sw);
nsec = stopwatch_get_nanos(&sw);
ddf_msg(LVL_DEBUG, "nsec=%lld", nsec);
} while (nsec < 1000 * msr_max_wait_usec);
ddf_msg(LVL_ERROR, "pc_fdc_send_byte: FAILED (status=0x%x)", status);
return EIO;
}
static errno_t pc_fdc_send(pc_fdc_t *fdc, const void *data, size_t nbytes)
{
size_t i;
errno_t rc;
uint8_t status;
for (i = 0; i < nbytes; i++) {
rc = pc_fdc_send_byte(fdc, ((uint8_t *)data)[i]);
if (rc != EOK)
return rc;
}
status = pio_read_8(&fdc->regs->msr);
ddf_msg(LVL_DEBUG, "pc_fdc_send: final status=0x%x", status);
return EOK;
}
static errno_t pc_fdc_get_byte(pc_fdc_t *fdc, uint8_t *byte)
{
unsigned cnt;
uint8_t status;
stopwatch_t sw;
nsec_t nsec;
stopwatch_init(&sw);
stopwatch_start(&sw);
status = pio_read_8(&fdc->regs->msr);
ddf_msg(LVL_DEBUG, "pc_fdc_get_byte: status=0x%x", status);
do {
cnt = msr_read_cycles;
while (cnt > 0) {
if ((status & fmsr_rqm) != 0 &&
(status & fmsr_dio) != 0) {
*byte = pio_read_8(&fdc->regs->data);
return EOK;
}
--cnt;
status = pio_read_8(&fdc->regs->msr);
}
stopwatch_stop(&sw);
nsec = stopwatch_get_nanos(&sw);
} while (nsec / 1000 < 1000 * msr_max_wait_usec);
ddf_msg(LVL_ERROR, "pc_fdc_get_byte: FAILED (status=0x%x)", status);
return EIO;
}
static errno_t pc_fdc_get(pc_fdc_t *fdc, void *buf, size_t bsize)
{
size_t i;
errno_t rc;
uint8_t status;
for (i = 0; i < bsize; i++) {
rc = pc_fdc_get_byte(fdc, &((uint8_t *)buf)[i]);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "pc_fdc_get: abort after "
"reading %zu bytes", i);
return rc;
}
}
ddf_msg(LVL_DEBUG, "pc_fdc_get: successfully read %zu bytes", i);
status = pio_read_8(&fdc->regs->msr);
ddf_msg(LVL_DEBUG, "pc_fdc_get: final status=0x%x", status);
return EOK;
}
static errno_t pc_fdc_reset(pc_fdc_t *fdc)
{
uint8_t dor;
pio_write_8(&fdc->regs->dsr, fdsr_sw_reset | fdsr_drate_500kbps);
dor = pio_read_8(&fdc->regs->dor);
ddf_msg(LVL_DEBUG, "pc_fdc_reset: old DOR=0x%x, DOR := 0x%x", dor,
dor & ~fdor_nreset);
pio_write_8(&fdc->regs->dor, dor & ~fdor_nreset);
dor = pio_read_8(&fdc->regs->dor);
ddf_msg(LVL_DEBUG, "pc_fdc_reset: read DOR: value= 0x%x", dor);
fibril_usleep(4);
ddf_msg(LVL_DEBUG, "pc_fdc_reset: old DOR=0x%x, DOR := 0x%x", dor,
dor | fdor_nreset | fdor_ndmagate);
pio_write_8(&fdc->regs->dor, dor | fdor_nreset | fdor_ndmagate);
dor = pio_read_8(&fdc->regs->dor);
ddf_msg(LVL_DEBUG, "pc_fdc_reset: read DOR: value= 0x%x", dor);
return EOK;
}
static errno_t pc_fdc_read_id(pc_fdc_t *fdc, bool mfm, uint8_t drive,
uint8_t head)
{
pc_fdc_read_id_data_t cmd;
pc_fdc_cmd_status_t status;
uint8_t dor;
errno_t rc;
dor = pio_read_8(&fdc->regs->dor);
ddf_msg(LVL_DEBUG, "pc_fdc_read_id: read DOR: value= 0x%x", dor);
dor |= fdor_me0;
dor = (dor & ~0x03) | 0x00;
pio_write_8(&fdc->regs->dor, dor);
ddf_msg(LVL_DEBUG, "pc_fdc_read_id: DOR := 0x%x", dor);
dor = pio_read_8(&fdc->regs->dor);
ddf_msg(LVL_DEBUG, "pc_fdc_read_id: read DOR: value= 0x%x", dor);
fibril_usleep(500 * 1000);
cmd.flags_cc = fcf_mf | fcc_read_id;
cmd.hd_us = 0x00;
ddf_msg(LVL_DEBUG, "read ID: send");
rc = pc_fdc_send(fdc, &cmd, sizeof(cmd));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed sending READ ID command.");
return rc;
}
ddf_msg(LVL_DEBUG, "read ID: get");
rc = pc_fdc_get(fdc, &status, sizeof(status));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed getting status for READ ID");
return rc;
}
ddf_msg(LVL_DEBUG, "read ID: DONE");
ddf_msg(LVL_DEBUG, "st0=0x%x st1=0x%x st2=0x%x cyl=%u head=%u rec=%u "
"number=%u", status.st0, status.st1, status.st2,
status.cyl, status.head, status.rec, status.number);
if ((status.st0 & fsr0_ic_mask) != 0)
return EIO;
return EOK;
}
static errno_t pc_fdc_drive_read_data(pc_fdc_drive_t *drive,
uint8_t cyl, uint8_t head, uint8_t sec, void *buf, size_t buf_size)
{
pc_fdc_t *fdc = drive->fdc;
pc_fdc_cmd_data_t cmd;
pc_fdc_cmd_status_t status;
async_sess_t *sess;
size_t csize;
errno_t rc;
ddf_msg(LVL_DEBUG, "pc_fdc_drive_read_data");
memset(fdc->dma_buf, 0, fdc->dma_buf_size);
sess = ddf_dev_parent_sess_get(fdc->dev);
ddf_msg(LVL_DEBUG, "hw_res_dma_channel_setup(sess=%p, chan=%d "
"pa=%" PRIuPTR " size=%zu", sess, fdc->dma, fdc->dma_buf_pa,
fdc->dma_buf_size);
rc = hw_res_dma_channel_setup(sess, fdc->dma, fdc->dma_buf_pa,
fdc->dma_buf_size, DMA_MODE_READ | DMA_MODE_AUTO |
DMA_MODE_ON_DEMAND);
ddf_msg(LVL_DEBUG, "hw_res_dma_channel_setup->%d", rc);
cmd.flags_cc = fcf_mf | fcc_read_data;
cmd.hd_us = (head & 1) << 2 | 0x00 ;
cmd.cyl = cyl;
cmd.head = head;
cmd.rec = sec;
cmd.number = 2;
cmd.eot = sec;
cmd.gpl = 0x1b;
cmd.dtl = 0xff;
ddf_msg(LVL_DEBUG, "read data: send");
rc = pc_fdc_send(fdc, &cmd, sizeof(cmd));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed sending Read Data command.");
return rc;
}
ddf_msg(LVL_DEBUG, "read data: get");
rc = pc_fdc_get(fdc, &status, sizeof(status));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed getting status for Read Data");
return rc;
}
ddf_msg(LVL_DEBUG, "read data: DONE");
ddf_msg(LVL_DEBUG, "st0=0x%x st1=0x%x st2=0x%x cyl=%u head=%u rec=%u "
"number=%u", status.st0, status.st1, status.st2,
status.cyl, status.head, status.rec, status.number);
if ((status.st0 & fsr0_ic_mask) != 0)
return EIO;
csize = min(fdc->dma_buf_size, buf_size);
memcpy(buf, fdc->dma_buf, csize);
return EOK;
}
static errno_t pc_fdc_drive_write_data(pc_fdc_drive_t *drive,
uint8_t cyl, uint8_t head, uint8_t sec, const void *buf, size_t buf_size)
{
pc_fdc_t *fdc = drive->fdc;
pc_fdc_cmd_data_t cmd;
pc_fdc_cmd_status_t status;
async_sess_t *sess;
size_t csize;
errno_t rc;
ddf_msg(LVL_DEBUG, "pc_fdc_drive_write_data");
csize = min(fdc->dma_buf_size, buf_size);
memcpy(fdc->dma_buf, buf, csize);
sess = ddf_dev_parent_sess_get(fdc->dev);
ddf_msg(LVL_DEBUG, "hw_res_dma_channel_setup(sess=%p, chan=%d "
"pa=%" PRIuPTR " size=%zu", sess, fdc->dma, fdc->dma_buf_pa,
fdc->dma_buf_size);
rc = hw_res_dma_channel_setup(sess, fdc->dma, fdc->dma_buf_pa,
fdc->dma_buf_size, DMA_MODE_WRITE | DMA_MODE_AUTO |
DMA_MODE_ON_DEMAND);
ddf_msg(LVL_DEBUG, "hw_res_dma_channel_setup->%d", rc);
cmd.flags_cc = fcf_mf | fcc_write_data;
cmd.hd_us = (head & 1) << 2 | 0x00 ;
cmd.cyl = cyl;
cmd.head = head;
cmd.rec = sec;
cmd.number = 2;
cmd.eot = sec;
cmd.gpl = 0x1b;
cmd.dtl = 0xff;
ddf_msg(LVL_DEBUG, "write data: send");
rc = pc_fdc_send(fdc, &cmd, sizeof(cmd));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed sending Write Data command.");
return rc;
}
ddf_msg(LVL_DEBUG, "write data: get");
rc = pc_fdc_get(fdc, &status, sizeof(status));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed getting status for Write Data");
return rc;
}
ddf_msg(LVL_DEBUG, "write data: DONE");
ddf_msg(LVL_DEBUG, "st0=0x%x st1=0x%x st2=0x%x cyl=%u head=%u rec=%u "
"number=%u", status.st0, status.st1, status.st2,
status.cyl, status.head, status.rec, status.number);
if ((status.st0 & fsr0_ic_mask) != 0)
return EIO;
return EOK;
}
static errno_t pc_fdc_sense_int_sts(pc_fdc_t *fdc)
{
pc_fdc_sense_int_sts_data_t cmd;
pc_fdc_sense_int_sts_status_t status;
errno_t rc;
cmd.cc = fcc_sense_int_sts;
ddf_msg(LVL_DEBUG, "Sense Interrupt Status: send");
rc = pc_fdc_send(fdc, &cmd, sizeof(cmd));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed sending Sense Interrupt Status "
"command.");
return rc;
}
ddf_msg(LVL_DEBUG, "Sense Interrupt Status: get");
rc = pc_fdc_get(fdc, &status, sizeof(status));
if (rc != EOK) {
ddf_msg(LVL_WARN, "Failed getting status for Sense Interrupt "
"Status");
return rc;
}
ddf_msg(LVL_DEBUG, "Sense Interrupt Status: DONE");
ddf_msg(LVL_DEBUG, "st0=0x%x pcn=0x%x", status.st0, status.pcn);
return EOK;
}
static void pc_fdc_irq_handler(ipc_call_t *call, void *arg)
{
pc_fdc_t *fdc = (pc_fdc_t *)arg;
uint8_t st0;
uint8_t st1;
uint8_t st2;
uint8_t c, h, n;
async_sess_t *parent_sess;
st0 = ipc_get_arg1(call);
st1 = ipc_get_arg2(call);
st2 = ipc_get_arg3(call);
c = ipc_get_arg4(call);
h = ipc_get_arg5(call);
n = ipc_get_imethod(call);
ddf_msg(LVL_DEBUG, "pc_fdc_irq_handler st0=%x st1=%x st2=%x c=%u h=%u n=%u",
st0, st1, st2, c, h, n);
parent_sess = ddf_dev_parent_sess_get(fdc->dev);
hw_res_clear_interrupt(parent_sess, fdc->irq);
}
static pc_fdc_drive_t *bd_srv_drive(bd_srv_t *bd)
{
return (pc_fdc_drive_t *)bd->srvs->sarg;
}
static void pc_fdc_drive_ba_to_chs(pc_fdc_drive_t *drive, uint64_t ba,
uint8_t *cyl, uint8_t *head, uint8_t *sec)
{
unsigned ch;
*sec = 1 + (ba % drive->sectors);
ch = ba / drive->sectors;
*head = ch % drive->heads;
*cyl = ch / drive->heads;
}
static errno_t pc_fdc_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
{
return EOK;
}
static errno_t pc_fdc_bd_close(bd_srv_t *bd)
{
return EOK;
}
static errno_t pc_fdc_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
void *buf, size_t size)
{
pc_fdc_drive_t *drive = bd_srv_drive(bd);
uint8_t cyl, head, sec;
errno_t rc;
ddf_msg(LVL_DEBUG, "pc_fdc_bd_read_blocks");
if (size < cnt * drive->sec_size) {
rc = EINVAL;
goto error;
}
while (cnt > 0) {
pc_fdc_drive_ba_to_chs(drive, ba, &cyl, &head, &sec);
rc = pc_fdc_drive_read_data(drive, cyl, head, sec, buf,
drive->sec_size);
if (rc != EOK)
goto error;
++ba;
--cnt;
buf += drive->sec_size;
}
return EOK;
error:
ddf_msg(LVL_ERROR, "pc_fdc_bd_read_blocks: rc=%d", rc);
return rc;
}
static errno_t pc_fdc_bd_read_toc(bd_srv_t *bd, uint8_t session, void *buf, size_t size)
{
return ENOTSUP;
}
static errno_t pc_fdc_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
const void *buf, size_t size)
{
pc_fdc_drive_t *drive = bd_srv_drive(bd);
uint8_t cyl, head, sec;
errno_t rc;
ddf_msg(LVL_DEBUG, "pc_fdc_bd_write_blocks");
if (size < cnt * drive->sec_size) {
rc = EINVAL;
goto error;
}
while (cnt > 0) {
pc_fdc_drive_ba_to_chs(drive, ba, &cyl, &head, &sec);
rc = pc_fdc_drive_write_data(drive, cyl, head, sec, buf,
drive->sec_size);
if (rc != EOK)
goto error;
++ba;
--cnt;
buf += drive->sec_size;
}
return EOK;
error:
ddf_msg(LVL_ERROR, "pc_fdc_bd_write_blocks: rc=%d", rc);
return rc;
}
static errno_t pc_fdc_bd_get_block_size(bd_srv_t *bd, size_t *rbsize)
{
pc_fdc_drive_t *drive = bd_srv_drive(bd);
*rbsize = drive->sec_size;
return EOK;
}
static errno_t pc_fdc_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
{
pc_fdc_drive_t *drive = bd_srv_drive(bd);
*rnb = drive->cylinders * drive->heads * drive->sectors;
return EOK;
}
static errno_t pc_fdc_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
{
return EOK;
}
HelenOS homepage, sources at GitHub