X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Ffdc.c;h=dcd1d46b4886ed6b1ca5a333a022b5be0146c068;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=073dafa4c884f215f25cb56b08dabaffac71312f;hpb=3bcb80f1af107c25bf8c255f3ca88ac467f27a1a;p=qemu diff --git a/hw/fdc.c b/hw/fdc.c index 073dafa..dcd1d46 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1,8 +1,8 @@ /* * 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 * in the Software without restriction, including without limitation the rights @@ -217,7 +217,7 @@ static fd_format_t fd_formats[] = { { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, - /* 320 kB 5"1/4 floppy disks */ + /* 320 kB 5"1/4 floppy disks */ { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, /* 360 kB must match 5"1/4 better than 3"1/2... */ @@ -368,9 +368,9 @@ struct fdctrl_t { /* 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; @@ -464,13 +464,13 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) 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, +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] = { @@ -485,8 +485,101 @@ static CPUWriteMemoryFunc *fdctrl_mem_write[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; @@ -497,11 +590,11 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; - fdctrl->result_timer = qemu_new_timer(vm_clock, + fdctrl->result_timer = qemu_new_timer(vm_clock, 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 */ @@ -520,11 +613,17 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, 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]); } @@ -542,7 +641,7 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) 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; } @@ -557,7 +656,7 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) } #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); @@ -743,7 +842,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) static int fdctrl_media_changed(fdrive_t *drv) { int ret; - if (!drv->bs) + if (!drv->bs) return 0; ret = bdrv_media_changed(drv->bs); if (ret) { @@ -1042,7 +1141,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, cur_drv->sect = 1; if (FD_MULTI_TRACK(fdctrl->data_state)) { if (cur_drv->head == 0 && - (cur_drv->flags & FDISK_DBL_SIDES) != 0) { + (cur_drv->flags & FDISK_DBL_SIDES) != 0) { cur_drv->head = 1; } else { cur_drv->head = 0; @@ -1169,7 +1268,7 @@ static void fdctrl_format_sector (fdctrl_t *fdctrl) memset(fdctrl->fifo, 0, FD_SECTOR_LEN); if (cur_drv->bs == NULL || bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv)); + FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); } else { if (cur_drv->sect == cur_drv->last_sect) { @@ -1633,7 +1732,7 @@ enqueue: FLOPPY_DPRINTF("treat READ_ID command\n"); /* XXX: should set main status register to busy */ cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - qemu_mod_timer(fdctrl->result_timer, + qemu_mod_timer(fdctrl->result_timer, qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); break; case 0x4C: @@ -1673,8 +1772,9 @@ enqueue: #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); @@ -1743,5 +1843,13 @@ enqueue: static void fdctrl_result_timer(void *opaque) { fdctrl_t *fdctrl = opaque; + fdrive_t *cur_drv = get_cur_drv(fdctrl); + /* Pretend we are spinning. + * This is needed for Coherent, which uses READ ID to check for + * sector interleaving. + */ + if (cur_drv->last_sect != 0) { + cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1; + } fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); }