X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Ffdc.c;h=9b4bfe76b3d031fbea601643e198e8e2c9dbddce;hb=4b19ec0c2be507954352fdcc7172737c46348476;hp=97f8805b9a5858974efdea7c77e72224ef7ffe5a;hpb=e309de25a617b683a86d6a42df4977bde22b8b26;p=qemu diff --git a/hw/fdc.c b/hw/fdc.c index 97f8805..9b4bfe7 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1,5 +1,5 @@ /* - * QEMU Floppy disk emulator + * QEMU Floppy disk emulator (Intel 82078) * * Copyright (c) 2003 Jocelyn Mayer * @@ -94,10 +94,7 @@ static void fd_init (fdrive_t *drv, BlockDriverState *bs) { /* Drive */ drv->bs = bs; - if (bs) - drv->drive = FDRIVE_DRV_144; - else - drv->drive = FDRIVE_DRV_NONE; + drv->drive = FDRIVE_DRV_NONE; drv->drflags = 0; drv->perpendicular = 0; /* Disk */ @@ -312,7 +309,7 @@ static void fd_reset (fdrive_t *drv) } /********************************************************/ -/* Intel 82078 floppy disk controler emulation */ +/* Intel 82078 floppy disk controller emulation */ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); static void fdctrl_reset_fifo (fdctrl_t *fdctrl); @@ -366,13 +363,13 @@ do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0) struct fdctrl_t { fdctrl_t *fdctrl; - /* Controler's identification */ + /* Controller's identification */ uint8_t version; /* HW */ int irq_lvl; int dma_chann; uint32_t io_base; - /* Controler state */ + /* Controller state */ QEMUTimer *result_timer; uint8_t state; uint8_t dma_en; @@ -385,6 +382,7 @@ struct fdctrl_t { uint8_t data_state; uint8_t data_dir; uint8_t int_status; + uint8_t eot; /* last wanted sector */ /* States kept only to be returned back */ /* Timers state */ uint8_t timer0; @@ -477,14 +475,14 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, // int io_mem; int i; - FLOPPY_DPRINTF("init controler\n"); + FLOPPY_DPRINTF("init controller\n"); fdctrl = qemu_mallocz(sizeof(fdctrl_t)); if (!fdctrl) return NULL; fdctrl->result_timer = qemu_new_timer(vm_clock, fdctrl_result_timer, fdctrl); - fdctrl->version = 0x90; /* Intel 82078 controler */ + fdctrl->version = 0x90; /* Intel 82078 controller */ fdctrl->irq_lvl = irq_lvl; fdctrl->dma_chann = dma_chann; fdctrl->io_base = io_base; @@ -547,14 +545,14 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) fdctrl->int_status = status; } -/* Reset controler */ +/* Reset controller */ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq) { int i; - FLOPPY_DPRINTF("reset controler\n"); + FLOPPY_DPRINTF("reset controller\n"); fdctrl_reset_irq(fdctrl); - /* Initialise controler */ + /* Initialise controller */ fdctrl->cur_drv = 0; /* FIFO state */ fdctrl->data_pos = 0; @@ -616,7 +614,7 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { if (!(value & 0x04)) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } } @@ -638,12 +636,12 @@ static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) /* Reset */ if (!(value & 0x04)) { if (!(fdctrl->state & FD_CTRL_RESET)) { - FLOPPY_DPRINTF("controler enter RESET state\n"); + FLOPPY_DPRINTF("controller enter RESET state\n"); fdctrl->state |= FD_CTRL_RESET; } } else { if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("controler out of RESET state\n"); + FLOPPY_DPRINTF("controller out of RESET state\n"); fdctrl_reset(fdctrl, 1); fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); } @@ -669,7 +667,7 @@ static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); @@ -706,7 +704,7 @@ static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) { /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); @@ -765,7 +763,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) fdrive_t *cur_drv; cur_drv = get_cur_drv(fdctrl); - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv; + fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = 0x00; fdctrl->fifo[2] = 0x00; fdctrl_set_fifo(fdctrl, 3, 1); @@ -785,8 +783,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, cur_drv = get_cur_drv(fdctrl); FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, - status0 | (cur_drv->head << 1) | fdctrl->cur_drv); - fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv; + status0 | (cur_drv->head << 2) | fdctrl->cur_drv); + fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; fdctrl->fifo[1] = status1; fdctrl->fifo[2] = status2; fdctrl->fifo[3] = cur_drv->track; @@ -813,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) kt = fdctrl->fifo[2]; kh = fdctrl->fifo[3]; ks = fdctrl->fifo[4]; - FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", + FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n", fdctrl->cur_drv, kh, kt, ks, _fd_sector(kh, kt, ks, cur_drv->last_sect)); did_seek = 0; @@ -867,6 +865,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) tmp += cur_drv->last_sect; fdctrl->data_len *= tmp; } + fdctrl->eot = fdctrl->fifo[6]; if (fdctrl->dma_en) { int dma_mode; /* DMA transfer are enabled. Check if DMA channel is well programmed */ @@ -882,7 +881,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) (direction == FD_DIR_READ && dma_mode == 1)) { /* No access is allowed until DMA transfer has completed */ fdctrl->state |= FD_CTRL_BUSY; - /* Now, we just have to wait for the DMA controler to + /* Now, we just have to wait for the DMA controller to * recall us... */ DMA_hold_DREQ(fdctrl->dma_chann); @@ -927,14 +926,14 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) status2 = 0x04; if (size > fdctrl->data_len) size = fdctrl->data_len; - if (cur_drv->bs == NULL) { + if (cur_drv->bs == NULL) { if (fdctrl->data_dir == FD_DIR_WRITE) fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); else fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); len = 0; - goto transfer_error; - } + goto transfer_error; + } rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { len = size - fdctrl->data_pos; @@ -955,7 +954,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) /* Sure, image size is too small... */ memset(fdctrl->fifo, 0, FD_SECTOR_LEN); } - } + } switch (fdctrl->data_dir) { case FD_DIR_READ: /* READ commands */ @@ -971,7 +970,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); goto transfer_error; - } + } break; default: /* SCAN commands */ @@ -997,30 +996,34 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; if (rel_pos == 0) { /* Seek to next sector */ - cur_drv->sect++; FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv), fdctrl->data_pos - size); - if (cur_drv->sect > cur_drv->last_sect) { + /* XXX: cur_drv->sect >= cur_drv->last_sect should be an + error in fact */ + if (cur_drv->sect >= cur_drv->last_sect || + cur_drv->sect == fdctrl->eot) { 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->head = 1; - } else { - cur_drv->head = 0; + cur_drv->head = 1; + } else { + cur_drv->head = 0; cur_drv->track++; if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) break; + } + } else { + cur_drv->track++; + break; } - } else { - cur_drv->track++; - break; - } FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", cur_drv->head, cur_drv->track, cur_drv->sect, fd_sector(cur_drv)); + } else { + cur_drv->sect++; } } } @@ -1036,7 +1039,7 @@ end_transfer: status0 |= 0x20; fdctrl->data_len -= len; // if (fdctrl->data_len == 0) - fdctrl_stop_transfer(fdctrl, status0, status1, status2); + fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: return len; @@ -1069,7 +1072,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) retval = fdctrl->fifo[pos]; if (++fdctrl->data_pos == fdctrl->data_len) { fdctrl->data_pos = 0; - /* Switch from transfert mode to status mode + /* Switch from transfer mode to status mode * then from status mode to command mode */ if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { @@ -1156,7 +1159,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) cur_drv = get_cur_drv(fdctrl); /* Reset mode */ if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controler in RESET state !\n"); + FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); return; } fdctrl->state &= ~FD_CTRL_SLEEP; @@ -1173,7 +1176,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, FD_SECTOR_LEN); } - /* Switch from transfert mode to status mode + /* Switch from transfer mode to status mode * then from status mode to command mode */ if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) @@ -1297,7 +1300,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) /* VERSION */ FLOPPY_DPRINTF("VERSION command\n"); /* No parameters cmd */ - /* Controler's version */ + /* Controller's version */ fdctrl->fifo[0] = fdctrl->version; fdctrl_set_fifo(fdctrl, 1, 1); return; @@ -1513,7 +1516,9 @@ enqueue: /* 1 Byte status back */ fdctrl->fifo[0] = (cur_drv->ro << 6) | (cur_drv->track == 0 ? 0x10 : 0x00) | - fdctrl->cur_drv; + (cur_drv->head << 2) | + fdctrl->cur_drv | + 0x28; fdctrl_set_fifo(fdctrl, 1, 0); break; case 0x07: @@ -1584,6 +1589,7 @@ enqueue: /* READ_ID */ 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_get_clock(vm_clock) + (ticks_per_sec / 50)); break;