/*
* QEMU Floppy disk emulator (Intel 82078)
*
- * Copyright (c) 2003 Jocelyn Mayer
+ * Copyright (c) 2003, 2007 Jocelyn Mayer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
/* Controller's identification */
uint8_t version;
/* HW */
- int irq_lvl;
+ qemu_irq irq;
int dma_chann;
- uint32_t io_base;
+ target_phys_addr_t io_base;
/* Controller state */
QEMUTimer *result_timer;
uint8_t state;
static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
{
- return fdctrl_read(opaque, reg);
+ return fdctrl_read(opaque, (uint32_t)reg);
}
static void fdctrl_write_mem (void *opaque,
target_phys_addr_t reg, uint32_t value)
{
- fdctrl_write(opaque, reg, value);
+ fdctrl_write(opaque, (uint32_t)reg, value);
}
static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
fdctrl_write_mem,
};
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
- uint32_t io_base,
+static void fd_save (QEMUFile *f, fdrive_t *fd)
+{
+ uint8_t tmp;
+
+ tmp = fd->drflags;
+ qemu_put_8s(f, &tmp);
+ qemu_put_8s(f, &fd->head);
+ qemu_put_8s(f, &fd->track);
+ qemu_put_8s(f, &fd->sect);
+ qemu_put_8s(f, &fd->dir);
+ qemu_put_8s(f, &fd->rw);
+}
+
+static void fdc_save (QEMUFile *f, void *opaque)
+{
+ fdctrl_t *s = opaque;
+
+ qemu_put_8s(f, &s->state);
+ qemu_put_8s(f, &s->dma_en);
+ qemu_put_8s(f, &s->cur_drv);
+ qemu_put_8s(f, &s->bootsel);
+ qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
+ qemu_put_be32s(f, &s->data_pos);
+ qemu_put_be32s(f, &s->data_len);
+ qemu_put_8s(f, &s->data_state);
+ qemu_put_8s(f, &s->data_dir);
+ qemu_put_8s(f, &s->int_status);
+ qemu_put_8s(f, &s->eot);
+ qemu_put_8s(f, &s->timer0);
+ qemu_put_8s(f, &s->timer1);
+ qemu_put_8s(f, &s->precomp_trk);
+ qemu_put_8s(f, &s->config);
+ qemu_put_8s(f, &s->lock);
+ qemu_put_8s(f, &s->pwrd);
+ fd_save(f, &s->drives[0]);
+ fd_save(f, &s->drives[1]);
+}
+
+static int fd_load (QEMUFile *f, fdrive_t *fd)
+{
+ uint8_t tmp;
+
+ qemu_get_8s(f, &tmp);
+ fd->drflags = tmp;
+ qemu_get_8s(f, &fd->head);
+ qemu_get_8s(f, &fd->track);
+ qemu_get_8s(f, &fd->sect);
+ qemu_get_8s(f, &fd->dir);
+ qemu_get_8s(f, &fd->rw);
+
+ return 0;
+}
+
+static int fdc_load (QEMUFile *f, void *opaque, int version_id)
+{
+ fdctrl_t *s = opaque;
+ int ret;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_8s(f, &s->state);
+ qemu_get_8s(f, &s->dma_en);
+ qemu_get_8s(f, &s->cur_drv);
+ qemu_get_8s(f, &s->bootsel);
+ qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN);
+ qemu_get_be32s(f, &s->data_pos);
+ qemu_get_be32s(f, &s->data_len);
+ qemu_get_8s(f, &s->data_state);
+ qemu_get_8s(f, &s->data_dir);
+ qemu_get_8s(f, &s->int_status);
+ qemu_get_8s(f, &s->eot);
+ qemu_get_8s(f, &s->timer0);
+ qemu_get_8s(f, &s->timer1);
+ qemu_get_8s(f, &s->precomp_trk);
+ qemu_get_8s(f, &s->config);
+ qemu_get_8s(f, &s->lock);
+ qemu_get_8s(f, &s->pwrd);
+
+ ret = fd_load(f, &s->drives[0]);
+ if (ret == 0)
+ ret = fd_load(f, &s->drives[1]);
+
+ return ret;
+}
+
+static void fdctrl_external_reset(void *opaque)
+{
+ fdctrl_t *s = opaque;
+
+ fdctrl_reset(s, 0);
+}
+
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
+ target_phys_addr_t io_base,
BlockDriverState **fds)
{
fdctrl_t *fdctrl;
fdctrl_result_timer, fdctrl);
fdctrl->version = 0x90; /* Intel 82078 controller */
- fdctrl->irq_lvl = irq_lvl;
+ fdctrl->irq = irq;
fdctrl->dma_chann = dma_chann;
fdctrl->io_base = io_base;
fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
cpu_register_physical_memory(io_base, 0x08, io_mem);
} else {
- register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
- register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
- register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
- register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
+ register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
+ fdctrl);
+ register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
+ fdctrl);
+ register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
+ fdctrl);
+ register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
+ fdctrl);
}
+ register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
+ qemu_register_reset(fdctrl_external_reset, fdctrl);
for (i = 0; i < 2; i++) {
fd_revalidate(&fdctrl->drives[i]);
}
static void fdctrl_reset_irq (fdctrl_t *fdctrl)
{
FLOPPY_DPRINTF("Reset interrupt\n");
- pic_set_irq(fdctrl->irq_lvl, 0);
+ qemu_set_irq(fdctrl->irq, 0);
fdctrl->state &= ~FD_CTRL_INTR;
}
}
#endif
if (~(fdctrl->state & FD_CTRL_INTR)) {
- pic_set_irq(fdctrl->irq_lvl, 1);
+ qemu_set_irq(fdctrl->irq, 1);
fdctrl->state |= FD_CTRL_INTR;
}
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
fdctrl->data_len = fdctrl->fifo[8];
} else {
int tmp;
- fdctrl->data_len = 128 << fdctrl->fifo[5];
+ fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
tmp = (cur_drv->last_sect - ks + 1);
if (fdctrl->fifo[0] & 0x80)
tmp += cur_drv->last_sect;
#else
cur_drv->last_sect = fdctrl->fifo[3];
#endif
- /* Bochs BIOS is buggy and don't send format informations
- * for each sector. So, pretend all's done right now...
+ /* TODO: implement format using DMA expected by the Bochs BIOS
+ * and Linux fdformat (read 3 bytes per sector via DMA and fill
+ * the sector with the specified fill byte
*/
fdctrl->data_state &= ~FD_STATE_FORMAT;
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);