4
* VBox storage devices:
5
* Floppy disk controller
9
* Copyright (C) 2006-2007 innotek GmbH
11
* This file is part of VirtualBox Open Source Edition (OSE), as
12
* available from http://www.virtualbox.org. This file is free software;
13
* you can redistribute it and/or modify it under the terms of the GNU
14
* General Public License as published by the Free Software Foundation,
15
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16
* distribution. VirtualBox OSE is distributed in the hope that it will
17
* be useful, but WITHOUT ANY WARRANTY of any kind.
18
* --------------------------------------------------------------------
20
* This code is based on:
22
* QEMU Floppy disk emulator (Intel 82078)
24
* Copyright (c) 2003 Jocelyn Mayer
26
* Permission is hereby granted, free of charge, to any person obtaining a copy
27
* of this software and associated documentation files (the "Software"), to deal
28
* in the Software without restriction, including without limitation the rights
29
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30
* copies of the Software, and to permit persons to whom the Software is
31
* furnished to do so, subject to the following conditions:
33
* The above copyright notice and this permission notice shall be included in
34
* all copies or substantial portions of the Software.
36
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
/*******************************************************************************
49
*******************************************************************************/
50
#define LOG_GROUP LOG_GROUP_DEV_FDC
51
#include <VBox/pdmdev.h>
52
#include <iprt/assert.h>
53
#include <iprt/uuid.h>
54
#include <iprt/string.h>
57
#include "../vl_vbox.h"
61
#define PDMIBASE_2_FDRIVE(pInterface) \
62
((fdrive_t *)((uintptr_t)(pInterface) - RT_OFFSETOF(fdrive_t, IBase)))
64
#define PDMIMOUNTNOTIFY_2_FDRIVE(p) \
65
((fdrive_t *)((uintptr_t)(p) - RT_OFFSETOF(fdrive_t, IMountNotify)))
73
/********************************************************/
74
/* debug Floppy devices */
75
/* #define DEBUG_FLOPPY */
79
#define FLOPPY_DPRINTF(fmt, args...) \
80
do { printf("FLOPPY: " fmt , ##args); } while (0)
84
static void FLOPPY_DPRINTF (const char *fmt, ...)
86
if (LogIsEnabled ()) {
89
RTLogLogger (NULL, NULL, "floppy: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
94
DECLINLINE(void) FLOPPY_DPRINTF(const char *pszFmt, ...) {}
99
#define FLOPPY_ERROR(fmt, args...) \
100
do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
102
# define FLOPPY_ERROR RTLogPrintf
106
typedef struct fdctrl_t fdctrl_t;
109
/********************************************************/
110
/* Floppy drive emulation */
112
/* Will always be a fixed parameter for us */
113
#define FD_SECTOR_LEN 512
114
#define FD_SECTOR_SC 2 /* Sector size code */
116
/* Floppy disk drive emulation */
117
typedef enum fdisk_type_t {
118
FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */
119
FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */
120
FDRIVE_DISK_720 = 0x03, /* 720 kB disk */
121
FDRIVE_DISK_USER = 0x04, /* User defined geometry */
122
FDRIVE_DISK_NONE = 0x05 /* No disk */
125
typedef enum fdrive_type_t {
126
FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
127
FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
128
FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
129
FDRIVE_DRV_NONE = 0x03 /* No drive connected */
132
typedef enum fdrive_flags_t {
133
FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
134
FDRIVE_REVALIDATE = 0x02 /* Revalidated */
137
typedef enum fdisk_flags_t {
138
FDISK_DBL_SIDES = 0x01
141
typedef struct fdrive_t {
143
BlockDriverState *bs;
145
/** Pointer to the attached driver's base interface. */
146
HCPTRTYPE(PPDMIBASE) pDrvBase;
147
/** Pointer to the attached driver's block interface. */
148
HCPTRTYPE(PPDMIBLOCK) pDrvBlock;
149
/** Pointer to the attached driver's block bios interface. */
150
HCPTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
151
/** Pointer to the attached driver's mount interface.
152
* This is NULL if the driver isn't a removable unit. */
153
HCPTRTYPE(PPDMIMOUNT) pDrvMount;
154
/** The base interface. */
156
/** The block port interface. */
158
/** The mount notify interface. */
159
PDMIMOUNTNOTIFY IMountNotify;
162
/** The LED for this LUN. */
164
/** The Diskette present/missing flag. */
169
fdrive_flags_t drflags;
170
uint8_t perpendicular; /* 2.88 MB access mode */
175
/* Last operation status */
176
uint8_t dir; /* Direction */
177
uint8_t rw; /* Read/write */
180
uint8_t last_sect; /* Nb sector per track */
181
uint8_t max_track; /* Nb of tracks */
182
uint16_t bps; /* Bytes per sector */
183
uint8_t ro; /* Is read-only */
187
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
191
drv->drive = FDRIVE_DRV_NONE;
193
drv->perpendicular = 0;
200
static int _fd_sector (uint8_t head, uint8_t track,
201
uint8_t sect, uint8_t last_sect)
203
return (((track * 2) + head) * last_sect) + sect - 1;
206
/* Returns current position, in sectors, for given drive */
207
static int fd_sector (fdrive_t *drv)
209
return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
212
static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
218
if (track > drv->max_track ||
219
(head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
220
FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
221
head, track, sect, 1,
222
(drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
223
drv->max_track, drv->last_sect);
226
if (sect > drv->last_sect) {
227
FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
228
head, track, sect, 1,
229
(drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
230
drv->max_track, drv->last_sect);
233
sector = _fd_sector(head, track, sect, drv->last_sect);
235
if (sector != fd_sector(drv)) {
238
FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
239
head, track, sect, 1, drv->max_track, drv->last_sect);
244
if (drv->track != track)
253
/* Set drive back to track 0 */
254
static void fd_recalibrate (fdrive_t *drv)
256
FLOPPY_DPRINTF("recalibrate\n");
264
/* Recognize floppy formats */
265
typedef struct fd_format_t {
274
static fd_format_t fd_formats[] = {
275
/* First entry is default format */
276
/* 1.44 MB 3"1/2 floppy disks */
277
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
278
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", },
279
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
280
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
281
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
282
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
283
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
284
{ FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
285
/* 2.88 MB 3"1/2 floppy disks */
286
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
287
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
288
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", },
289
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
290
{ FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
291
/* 720 kB 3"1/2 floppy disks */
292
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", },
293
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", },
294
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", },
295
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", },
296
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
297
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
298
/* 1.2 MB 5"1/4 floppy disks */
299
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", },
300
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
301
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
302
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
303
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", },
304
/* 720 kB 5"1/4 floppy disks */
305
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", },
306
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", },
307
/* 360 kB 5"1/4 floppy disks */
308
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", },
309
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", },
310
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", },
311
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", },
312
/* 320 kB 5"1/4 floppy disks */
313
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", },
314
{ FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", },
315
/* 360 kB must match 5"1/4 better than 3"1/2... */
316
{ FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", },
318
{ FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
321
/* Revalidate a disk drive after a disk change */
322
static void fd_revalidate (fdrive_t *drv)
325
int64_t nb_sectors, size;
326
int i, first_match, match;
327
int nb_heads, max_track, last_sect, ro;
329
FLOPPY_DPRINTF("revalidate\n");
330
drv->drflags &= ~FDRIVE_REVALIDATE;
332
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
333
ro = bdrv_is_read_only(drv->bs);
334
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
336
/** @todo */ /** @todo r=bird: todo what exactly? */
339
&& drv->pDrvMount->pfnIsMounted (drv->pDrvMount)) {
340
ro = drv->pDrvBlock->pfnIsReadOnly (drv->pDrvBlock);
345
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
346
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
347
nb_heads - 1, max_track, last_sect);
350
bdrv_get_geometry(drv->bs, &nb_sectors);
352
/* @todo */ /** @todo r=bird: todo what exactly?!?!? */
354
uint64_t size = drv->pDrvBlock->pfnGetSize (drv->pDrvBlock);
355
nb_sectors = size / 512;
361
parse = &fd_formats[i];
362
if (parse->drive == FDRIVE_DRV_NONE)
364
if (drv->drive == parse->drive ||
365
drv->drive == FDRIVE_DRV_NONE) {
366
size = (parse->max_head + 1) * parse->max_track *
368
if (nb_sectors == size) {
372
if (first_match == -1)
377
if (first_match == -1)
381
parse = &fd_formats[match];
383
nb_heads = parse->max_head + 1;
384
max_track = parse->max_track;
385
last_sect = parse->last_sect;
386
drv->drive = parse->drive;
387
FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
388
nb_heads, max_track, last_sect, ro ? "ro" : "rw");
391
drv->flags &= ~FDISK_DBL_SIDES;
393
drv->flags |= FDISK_DBL_SIDES;
395
drv->max_track = max_track;
396
drv->last_sect = last_sect;
399
drv->fMediaPresent = true;
402
FLOPPY_DPRINTF("No disk in drive\n");
405
drv->flags &= ~FDISK_DBL_SIDES;
407
drv->fMediaPresent = false;
410
drv->drflags |= FDRIVE_REVALIDATE;
414
static void fd_start (fdrive_t *drv)
416
drv->drflags |= FDRIVE_MOTOR_ON;
419
static void fd_stop (fdrive_t *drv)
421
drv->drflags &= ~FDRIVE_MOTOR_ON;
424
/* Re-initialise a drives (motor off, repositioned) */
425
static void fd_reset (fdrive_t *drv)
431
/********************************************************/
432
/* Intel 82078 floppy disk controller emulation */
434
#define target_ulong uint32_t
435
static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
436
static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
438
static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len);
440
static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
446
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
447
static void fdctrl_result_timer(void *opaque);
449
static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
450
static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
451
static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
452
static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
453
static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
454
static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
455
static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
456
static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
457
static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
458
static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
461
FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
462
FD_CTRL_RESET = 0x02,
463
FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */
464
FD_CTRL_BUSY = 0x08, /* dma transfer in progress */
478
FD_STATE_STATUS = 0x01,
479
FD_STATE_DATA = 0x02,
480
FD_STATE_STATE = 0x03,
481
FD_STATE_MULTI = 0x10,
482
FD_STATE_SEEK = 0x20,
483
FD_STATE_FORMAT = 0x40
486
#define FD_STATE(state) ((state) & FD_STATE_STATE)
487
#define FD_SET_STATE(state, new_state) \
488
do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
489
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
490
#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
491
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
497
/* Controller's identification */
508
/* Controller state */
509
QEMUTimer *result_timer;
515
uint8_t fifo[FD_SECTOR_LEN];
521
uint8_t eot; /* last wanted sector */
522
/* States kept only to be returned back */
526
/* precompensation */
530
/* Power down config (also with status regB access mode */
535
/** Pointer to device instance. */
538
/** Status Port - The base interface. */
539
PDMIBASE IBaseStatus;
540
/** Status Port - The Leds interface. */
542
/** Status Port - The Partner of ILeds. */
543
PPDMILEDCONNECTORS pLedsConnector;
547
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
549
fdctrl_t *fdctrl = opaque;
552
switch (reg & 0x07) {
554
retval = fdctrl_read_statusB(fdctrl);
557
retval = fdctrl_read_dor(fdctrl);
560
retval = fdctrl_read_tape(fdctrl);
563
retval = fdctrl_read_main_status(fdctrl);
566
retval = fdctrl_read_data(fdctrl);
569
retval = fdctrl_read_dir(fdctrl);
572
retval = (uint32_t)(-1);
575
FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
580
static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
582
fdctrl_t *fdctrl = opaque;
584
FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
586
switch (reg & 0x07) {
588
fdctrl_write_dor(fdctrl, value);
591
fdctrl_write_tape(fdctrl, value);
594
fdctrl_write_rate(fdctrl, value);
597
fdctrl_write_data(fdctrl, value);
605
static void fd_change_cb (void *opaque)
607
fdrive_t *drv = opaque;
609
FLOPPY_DPRINTF("disk change\n");
613
fdctrl_reset_fifo(drv->fdctrl);
614
fdctrl_raise_irq(drv->fdctrl, 0x20);
620
* Called when a media is mounted.
622
* @param pInterface Pointer to the interface structure
623
* containing the called function pointer.
625
static DECLCALLBACK(void) fdMountNotify(PPDMIMOUNTNOTIFY pInterface)
627
fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
628
LogFlow(("fdMountNotify:\n"));
633
* Called when a media is unmounted
634
* @param pInterface Pointer to the interface structure containing the called function pointer.
636
static DECLCALLBACK(void) fdUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
638
fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
639
LogFlow(("fdUnmountNotify:\n"));
645
fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
647
BlockDriverState **fds)
653
FLOPPY_DPRINTF("init controller\n");
654
fdctrl = qemu_mallocz(sizeof(fdctrl_t));
657
fdctrl->result_timer = qemu_new_timer(vm_clock,
658
fdctrl_result_timer, fdctrl);
660
fdctrl->version = 0x90; /* Intel 82078 controller */
661
fdctrl->irq_lvl = irq_lvl;
662
fdctrl->dma_chann = dma_chann;
663
fdctrl->io_base = io_base;
664
fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
665
if (fdctrl->dma_chann != -1) {
667
DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
671
for (i = 0; i < 2; i++) {
672
fd_init(&fdctrl->drives[i], fds[i]);
674
bdrv_set_change_cb(fds[i],
675
&fd_change_cb, &fdctrl->drives[i]);
678
fdctrl_reset(fdctrl, 0);
679
fdctrl->state = FD_CTRL_ACTIVE;
681
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
683
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
684
cpu_register_physical_memory(base, 0x08, io_mem);
687
register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
688
register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
689
register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
690
register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
692
for (i = 0; i < 2; i++) {
693
fd_revalidate(&fdctrl->drives[i]);
699
/* XXX: may change if moved to bdrv */
700
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
702
return fdctrl->drives[drive_num].drive;
706
/* Change IRQ state */
707
static void fdctrl_reset_irq (fdctrl_t *fdctrl)
709
FLOPPY_DPRINTF("Reset interrupt\n");
711
fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
714
pic_set_irq(fdctrl->irq_lvl, 0);
716
fdctrl->state &= ~FD_CTRL_INTR;
719
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
721
if (~(fdctrl->state & FD_CTRL_INTR)) {
723
fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
726
pic_set_irq(fdctrl->irq_lvl, 1);
728
fdctrl->state |= FD_CTRL_INTR;
730
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
731
fdctrl->int_status = status;
734
/* Reset controller */
735
static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
739
FLOPPY_DPRINTF("reset controller\n");
740
fdctrl_reset_irq(fdctrl);
741
/* Initialise controller */
744
fdctrl->data_pos = 0;
745
fdctrl->data_len = 0;
746
fdctrl->data_state = FD_STATE_CMD;
747
fdctrl->data_dir = FD_DIR_WRITE;
748
for (i = 0; i < MAX_FD; i++)
749
fd_reset(&fdctrl->drives[i]);
750
fdctrl_reset_fifo(fdctrl);
752
fdctrl_raise_irq(fdctrl, 0xc0);
755
static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
757
return &fdctrl->drives[fdctrl->bootsel];
760
static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
762
return &fdctrl->drives[1 - fdctrl->bootsel];
765
static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
767
return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
770
/* Status B register : 0x01 (read-only) */
771
static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
773
FLOPPY_DPRINTF("status register: 0x00\n");
777
/* Digital output register : 0x02 */
778
static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
782
/* Drive motors state indicators */
784
if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
786
if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
789
/* bit4: 0 = drive 0 motor off/1 = on */
790
if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
792
/* bit5: 0 = drive 1 motor off/1 = on */
793
if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
797
retval |= fdctrl->dma_en << 3;
798
/* Reset indicator */
799
retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
801
retval |= fdctrl->cur_drv;
802
FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
807
static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
810
if (fdctrl->state & FD_CTRL_RESET) {
811
if (!(value & 0x04)) {
812
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
816
FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
817
/* Drive motors state indicators */
819
fd_start(drv1(fdctrl));
821
fd_stop(drv1(fdctrl));
823
fd_start(drv0(fdctrl));
825
fd_stop(drv0(fdctrl));
828
if (fdctrl->dma_chann != -1)
829
fdctrl->dma_en = 1 - ((value >> 3) & 1);
832
if (!(value & 0x04)) {
833
if (!(fdctrl->state & FD_CTRL_RESET)) {
834
FLOPPY_DPRINTF("controller enter RESET state\n");
835
fdctrl->state |= FD_CTRL_RESET;
838
if (fdctrl->state & FD_CTRL_RESET) {
839
FLOPPY_DPRINTF("controller out of RESET state\n");
840
fdctrl_reset(fdctrl, 1);
841
fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
845
fdctrl->cur_drv = value & 1;
848
/* Tape drive register : 0x03 */
849
static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
853
/* Disk boot selection indicator */
854
retval |= fdctrl->bootsel << 2;
855
/* Tape indicators: never allowed */
856
FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
861
static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
864
if (fdctrl->state & FD_CTRL_RESET) {
865
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
868
FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
869
/* Disk boot selection indicator */
870
fdctrl->bootsel = (value >> 2) & 1;
871
/* Tape indicators: never allow */
874
/* Main status register : 0x04 (read) */
875
static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
879
fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
880
if (!(fdctrl->state & FD_CTRL_BUSY)) {
881
/* Data transfer allowed */
883
/* Data transfer direction indicator */
884
if (fdctrl->data_dir == FD_DIR_READ)
887
/* Should handle 0x20 for SPECIFY command */
888
/* Command busy indicator */
889
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
890
FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
892
FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
897
/* Data select rate register : 0x04 (write) */
898
static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
901
if (fdctrl->state & FD_CTRL_RESET) {
902
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
905
FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
906
/* Reset: autoclear */
908
fdctrl->state |= FD_CTRL_RESET;
909
fdctrl_reset(fdctrl, 1);
910
fdctrl->state &= ~FD_CTRL_RESET;
913
fdctrl->state |= FD_CTRL_SLEEP;
914
fdctrl_reset(fdctrl, 1);
916
/* // fdctrl.precomp = (value >> 2) & 0x07; */
919
/* Digital input register : 0x07 (read-only) */
920
static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
925
if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
926
drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
928
fdrive_t *cur_drv = get_cur_drv(fdctrl);
929
if ( drv0(fdctrl)->drflags & FDRIVE_REVALIDATE
930
|| drv1(fdctrl)->drflags & FDRIVE_REVALIDATE
931
|| !cur_drv->fMediaPresent)
935
FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
936
drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
937
drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
942
/* FIFO state control */
943
static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
945
fdctrl->data_dir = FD_DIR_WRITE;
946
fdctrl->data_pos = 0;
947
FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
950
/* Set FIFO status for the host to read */
951
static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
953
fdctrl->data_dir = FD_DIR_READ;
954
fdctrl->data_len = fifo_len;
955
fdctrl->data_pos = 0;
956
FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
958
fdctrl_raise_irq(fdctrl, 0x00);
961
/* Set an error: unimplemented/unknown command */
962
static void fdctrl_unimplemented (fdctrl_t *fdctrl)
967
cur_drv = get_cur_drv(fdctrl);
968
fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
969
fdctrl->fifo[1] = 0x00;
970
fdctrl->fifo[2] = 0x00;
971
fdctrl_set_fifo(fdctrl, 3, 1);
973
/* // fdctrl_reset_fifo(fdctrl); */
974
fdctrl->fifo[0] = 0x80;
975
fdctrl_set_fifo(fdctrl, 1, 0);
979
/* Callback for transfer end (stop or abort) */
980
static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
981
uint8_t status1, uint8_t status2)
985
cur_drv = get_cur_drv(fdctrl);
986
FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
987
status0, status1, status2,
988
status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
989
fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
990
fdctrl->fifo[1] = status1;
991
fdctrl->fifo[2] = status2;
992
fdctrl->fifo[3] = cur_drv->track;
993
fdctrl->fifo[4] = cur_drv->head;
994
fdctrl->fifo[5] = cur_drv->sect;
995
fdctrl->fifo[6] = FD_SECTOR_SC;
996
fdctrl->data_dir = FD_DIR_READ;
997
if (fdctrl->state & FD_CTRL_BUSY) {
999
fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
1003
DMA_release_DREQ(fdctrl->dma_chann);
1005
fdctrl->state &= ~FD_CTRL_BUSY;
1007
fdctrl_set_fifo(fdctrl, 7, 1);
1010
/* Prepare a data transfer (either DMA or FIFO) */
1011
static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
1017
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1018
cur_drv = get_cur_drv(fdctrl);
1019
kt = fdctrl->fifo[2];
1020
kh = fdctrl->fifo[3];
1021
ks = fdctrl->fifo[4];
1022
FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
1023
fdctrl->cur_drv, kh, kt, ks,
1024
_fd_sector(kh, kt, ks, cur_drv->last_sect));
1026
switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1029
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1030
fdctrl->fifo[3] = kt;
1031
fdctrl->fifo[4] = kh;
1032
fdctrl->fifo[5] = ks;
1036
fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1037
fdctrl->fifo[3] = kt;
1038
fdctrl->fifo[4] = kh;
1039
fdctrl->fifo[5] = ks;
1042
/* No seek enabled */
1043
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1044
fdctrl->fifo[3] = kt;
1045
fdctrl->fifo[4] = kh;
1046
fdctrl->fifo[5] = ks;
1054
/* Set the FIFO state */
1055
fdctrl->data_dir = direction;
1056
fdctrl->data_pos = 0;
1057
FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
1058
if (fdctrl->fifo[0] & 0x80)
1059
fdctrl->data_state |= FD_STATE_MULTI;
1061
fdctrl->data_state &= ~FD_STATE_MULTI;
1063
fdctrl->data_state |= FD_STATE_SEEK;
1065
fdctrl->data_state &= ~FD_STATE_SEEK;
1066
if (fdctrl->fifo[5] == 00) {
1067
fdctrl->data_len = fdctrl->fifo[8];
1070
fdctrl->data_len = 128 << fdctrl->fifo[5];
1071
tmp = (cur_drv->last_sect - ks + 1);
1072
if (fdctrl->fifo[0] & 0x80)
1073
tmp += cur_drv->last_sect;
1074
fdctrl->data_len *= tmp;
1076
fdctrl->eot = fdctrl->fifo[6];
1077
if (fdctrl->dma_en) {
1079
/* DMA transfer are enabled. Check if DMA channel is well programmed */
1081
dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
1083
dma_mode = fdctrl->pDevIns->pDevHlp->pfnDMAGetChannelMode (
1088
dma_mode = (dma_mode >> 2) & 3;
1089
FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1090
dma_mode, direction,
1091
(128 << fdctrl->fifo[5]) *
1092
(cur_drv->last_sect - ks + 1), fdctrl->data_len);
1093
if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
1094
direction == FD_DIR_SCANH) && dma_mode == 0) ||
1095
(direction == FD_DIR_WRITE && dma_mode == 2) ||
1096
(direction == FD_DIR_READ && dma_mode == 1)) {
1097
/* No access is allowed until DMA transfer has completed */
1098
fdctrl->state |= FD_CTRL_BUSY;
1099
/* Now, we just have to wait for the DMA controller to
1103
DMA_hold_DREQ(fdctrl->dma_chann);
1104
DMA_schedule(fdctrl->dma_chann);
1106
fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
1109
fdctrl->pDevIns->pDevHlp->pfnDMASchedule (fdctrl->pDevIns);
1113
FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
1116
FLOPPY_DPRINTF("start non-DMA transfer\n");
1117
/* IO based transfer: calculate len */
1118
fdctrl_raise_irq(fdctrl, 0x00);
1123
/* Prepare a transfer of deleted data */
1124
static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
1126
/* We don't handle deleted data,
1127
* so we don't return *ANYTHING*
1129
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1137
static void dump (void *p, size_t len)
1142
f = fopen ("dump", "wb");
1147
n = fwrite (p, len, 1, f);
1149
AssertMsgFailed (("failed to dump\n"));
1154
#define dump(a,b) do { } while (0)
1157
/* handlers for DMA transfers */
1159
static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
1165
static int fdctrl_transfer_handler (void *opaque, int nchan,
1166
int dma_pos, int dma_len)
1173
uint32_t len, start_pos, rel_pos;
1175
int len, start_pos, rel_pos;
1177
uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1180
if (!(fdctrl->state & FD_CTRL_BUSY)) {
1181
FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1184
cur_drv = get_cur_drv(fdctrl);
1185
if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1186
fdctrl->data_dir == FD_DIR_SCANH)
1188
if (dma_len > fdctrl->data_len)
1189
dma_len = fdctrl->data_len;
1191
if (cur_drv->bs == NULL) {
1193
if (cur_drv->pDrvBlock == NULL) {
1195
if (fdctrl->data_dir == FD_DIR_WRITE)
1196
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1198
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1200
goto transfer_error;
1202
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1203
for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1204
len = dma_len - fdctrl->data_pos;
1205
if (len + rel_pos > FD_SECTOR_LEN)
1206
len = FD_SECTOR_LEN - rel_pos;
1207
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1208
"(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
1209
fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1210
cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1211
fd_sector(cur_drv) * 512);
1212
if (fdctrl->data_dir != FD_DIR_WRITE ||
1213
len < FD_SECTOR_LEN || rel_pos != 0) {
1214
/* READ & SCAN commands and realign to a sector for WRITE */
1216
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1217
fdctrl->fifo, 1) < 0) {
1218
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1219
fd_sector(cur_drv));
1220
/* Sure, image size is too small... */
1221
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1224
cur_drv->Led.Asserted.s.fReading
1225
= cur_drv->Led.Actual.s.fReading = 1;
1227
rc = cur_drv->pDrvBlock->pfnRead (
1229
fd_sector (cur_drv) * 512,
1234
cur_drv->Led.Actual.s.fReading = 0;
1236
if (VBOX_FAILURE (rc)) {
1238
("Floppy: error getting sector %d, rc = %Vrc",
1239
fd_sector (cur_drv), rc));
1240
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1244
switch (fdctrl->data_dir) {
1250
int rc = fdctrl->pDevIns->pDevHlp->pfnDMAWriteMemory(
1253
fdctrl->fifo + rel_pos,
1257
dump (fdctrl->fifo + rel_pos, len);
1259
("DMAWriteMemory -> %Vrc\n", rc));
1262
DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
1263
fdctrl->data_pos, len);
1265
/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
1266
/* fdctrl->fifo + rel_pos, len); */
1269
/* WRITE commands */
1273
int rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory(
1276
fdctrl->fifo + rel_pos,
1281
("DMAReadMemory -> %Vrc\n", rc));
1284
DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
1285
fdctrl->data_pos, len);
1287
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1288
/* fdctrl->fifo + rel_pos, len); */
1290
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1291
fdctrl->fifo, 1) < 0) {
1292
FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1293
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1294
goto transfer_error;
1297
cur_drv->Led.Asserted.s.fWriting
1298
= cur_drv->Led.Actual.s.fWriting = 1;
1300
rc = cur_drv->pDrvBlock->pfnWrite (
1302
fd_sector (cur_drv) * 512,
1307
cur_drv->Led.Actual.s.fWriting = 0;
1309
if (VBOX_FAILURE (rc)) {
1310
AssertMsgFailed (("Floppy: error writing sector %d. rc=%Vrc",
1311
fd_sector (cur_drv), rc));
1312
fdctrl_stop_transfer (fdctrl, 0x60, 0x00, 0x00);
1313
goto transfer_error;
1320
uint8_t tmpbuf[FD_SECTOR_LEN];
1326
rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory (
1333
AssertMsg (VBOX_SUCCESS (rc),
1334
("DMAReadMemory -> %Vrc\n", rc));
1336
DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1338
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1340
ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1345
if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1346
(ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1353
fdctrl->data_pos += len;
1354
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1356
/* Seek to next sector */
1357
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1358
cur_drv->head, cur_drv->track, cur_drv->sect,
1360
fdctrl->data_pos - len);
1361
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1363
if (cur_drv->sect >= cur_drv->last_sect ||
1364
cur_drv->sect == fdctrl->eot) {
1366
if (FD_MULTI_TRACK(fdctrl->data_state)) {
1367
if (cur_drv->head == 0 &&
1368
(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1373
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1380
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1381
cur_drv->head, cur_drv->track,
1382
cur_drv->sect, fd_sector(cur_drv));
1389
len = fdctrl->data_pos - start_pos;
1390
FLOPPY_DPRINTF("end transfer %d %d %d\n",
1391
fdctrl->data_pos, len, fdctrl->data_len);
1392
if (fdctrl->data_dir == FD_DIR_SCANE ||
1393
fdctrl->data_dir == FD_DIR_SCANL ||
1394
fdctrl->data_dir == FD_DIR_SCANH)
1396
if (FD_DID_SEEK(fdctrl->data_state))
1398
fdctrl->data_len -= len;
1399
/* if (fdctrl->data_len == 0) */
1400
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1410
int len, start_pos, rel_pos;
1411
uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1414
if (!(fdctrl->state & FD_CTRL_BUSY)) {
1415
FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1418
cur_drv = get_cur_drv(fdctrl);
1419
if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1420
fdctrl->data_dir == FD_DIR_SCANH)
1422
if (size > fdctrl->data_len)
1423
size = fdctrl->data_len;
1425
if (cur_drv->bs == NULL) {
1427
if (cur_drv->pDrvBase == NULL) {
1429
if (fdctrl->data_dir == FD_DIR_WRITE)
1430
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1432
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1434
goto transfer_error;
1436
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1437
for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) {
1438
len = size - fdctrl->data_pos;
1439
if (len + rel_pos > FD_SECTOR_LEN)
1440
len = FD_SECTOR_LEN - rel_pos;
1441
FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
1442
"(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos,
1443
fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1444
cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1445
fd_sector(cur_drv) * 512, addr);
1446
if (fdctrl->data_dir != FD_DIR_WRITE ||
1447
len < FD_SECTOR_LEN || rel_pos != 0) {
1448
/* READ & SCAN commands and realign to a sector for WRITE */
1450
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1451
fdctrl->fifo, 1) < 0) {
1452
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1453
fd_sector(cur_drv));
1454
/* Sure, image size is too small... */
1455
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1460
cur_drv->Led.Asserted.s.fReading
1461
= cur_drv->Led.Actual.s.fReading = 1;
1463
rc = cur_drv->pDrvBlock->pfnRead (
1465
fd_sector (cur_drv) * 512,
1470
cur_drv->Led.Actual.s.fReading = 0;
1472
if (VBOX_FAILURE (rc)) {
1474
("Floppy: error getting sector %d. rc=%Vrc\n",
1475
fd_sector(cur_drv), rc));
1476
/* Sure, image size is too small... */
1477
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1479
/* *p_fd_activity = 1; */
1482
switch (fdctrl->data_dir) {
1486
fdctrl->pDevIns->pDevHlp->pfnPhysWrite (
1488
addr + fdctrl->data_pos,
1489
fdctrl->fifo + rel_pos,
1492
cpu_physical_memory_write(addr + fdctrl->data_pos,
1493
fdctrl->fifo + rel_pos, len);
1497
/* WRITE commands */
1502
fdctrl->pDevIns->pDevHlp->pfnPhysRead (
1504
addr + fdctrl->data_pos,
1505
fdctrl->fifo + rel_pos,
1508
cur_drv->Led.Asserted.s.fWriting
1509
= cur_drv->Led.Actual.s.fWriting = 1;
1511
rc = cur_drv->pDrvBlock->pfnWrite (
1513
fd_sector (cur_drv) * 512,
1518
cur_drv->Led.Actual.s.fWriting = 0;
1520
if (VBOX_FAILURE (rc)) {
1522
("Floppy: error writting sector %d. rc=%Vrc\n",
1523
fd_sector(cur_drv), rc));
1524
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1525
goto transfer_error;
1528
/* *p_fd_activity = 2; */
1530
cpu_physical_memory_read(addr + fdctrl->data_pos,
1531
fdctrl->fifo + rel_pos, len);
1532
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1533
fdctrl->fifo, 1) < 0) {
1534
FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1535
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1536
goto transfer_error;
1543
uint8_t tmpbuf[FD_SECTOR_LEN];
1546
fdctrl->pDevIns->pDevHlp->pfnPhysRead (
1548
addr + fdctrl->data_pos,
1552
cpu_physical_memory_read(addr + fdctrl->data_pos,
1555
ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1560
if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1561
(ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1568
fdctrl->data_pos += len;
1569
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1571
/* Seek to next sector */
1572
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1573
cur_drv->head, cur_drv->track, cur_drv->sect,
1575
fdctrl->data_pos - size);
1576
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1578
if (cur_drv->sect >= cur_drv->last_sect ||
1579
cur_drv->sect == fdctrl->eot) {
1581
if (FD_MULTI_TRACK(fdctrl->data_state)) {
1582
if (cur_drv->head == 0 &&
1583
(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1588
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1595
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1596
cur_drv->head, cur_drv->track,
1597
cur_drv->sect, fd_sector(cur_drv));
1604
len = fdctrl->data_pos - start_pos;
1605
FLOPPY_DPRINTF("end transfer %d %d %d\n",
1606
fdctrl->data_pos, len, fdctrl->data_len);
1607
if (fdctrl->data_dir == FD_DIR_SCANE ||
1608
fdctrl->data_dir == FD_DIR_SCANL ||
1609
fdctrl->data_dir == FD_DIR_SCANH)
1611
if (FD_DID_SEEK(fdctrl->data_state))
1613
fdctrl->data_len -= len;
1614
/* // if (fdctrl->data_len == 0) */
1615
fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1622
/* Data register : 0x05 */
1623
static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
1626
uint32_t retval = 0;
1632
cur_drv = get_cur_drv(fdctrl);
1633
fdctrl->state &= ~FD_CTRL_SLEEP;
1634
if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
1635
FLOPPY_ERROR("can't read data in CMD state\n");
1638
pos = fdctrl->data_pos;
1639
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1640
pos %= FD_SECTOR_LEN;
1642
len = fdctrl->data_len - fdctrl->data_pos;
1643
if (len > FD_SECTOR_LEN)
1644
len = FD_SECTOR_LEN;
1646
cur_drv->Led.Asserted.s.fReading
1647
= cur_drv->Led.Actual.s.fReading = 1;
1649
rc = cur_drv->pDrvBlock->pfnRead (
1651
fd_sector (cur_drv) * 512,
1656
cur_drv->Led.Actual.s.fReading = 0;
1658
if (VBOX_FAILURE (rc)) {
1660
("Floppy: Failure to read sector %d. rc=%Vrc",
1661
fd_sector (cur_drv), rc));
1664
bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1669
retval = fdctrl->fifo[pos];
1670
if (++fdctrl->data_pos == fdctrl->data_len) {
1671
fdctrl->data_pos = 0;
1672
/* Switch from transfer mode to status mode
1673
* then from status mode to command mode
1675
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1676
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1678
fdctrl_reset_fifo(fdctrl);
1679
fdctrl_reset_irq(fdctrl);
1682
FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1687
static void fdctrl_format_sector (fdctrl_t *fdctrl)
1696
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1697
cur_drv = get_cur_drv(fdctrl);
1698
kt = fdctrl->fifo[6];
1699
kh = fdctrl->fifo[7];
1700
ks = fdctrl->fifo[8];
1701
FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1702
fdctrl->cur_drv, kh, kt, ks,
1703
_fd_sector(kh, kt, ks, cur_drv->last_sect));
1705
switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1708
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1709
fdctrl->fifo[3] = kt;
1710
fdctrl->fifo[4] = kh;
1711
fdctrl->fifo[5] = ks;
1715
fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1716
fdctrl->fifo[3] = kt;
1717
fdctrl->fifo[4] = kh;
1718
fdctrl->fifo[5] = ks;
1721
/* No seek enabled */
1722
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1723
fdctrl->fifo[3] = kt;
1724
fdctrl->fifo[4] = kh;
1725
fdctrl->fifo[5] = ks;
1729
fdctrl->data_state |= FD_STATE_SEEK;
1734
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1736
/* *p_fd_activity = 2; */
1737
if (cur_drv->pDrvBlock) {
1738
cur_drv->Led.Asserted.s.fWriting = cur_drv->Led.Actual.s.fWriting = 1;
1740
rc = cur_drv->pDrvBlock->pfnWrite (
1742
fd_sector (cur_drv) * 512,
1747
cur_drv->Led.Actual.s.fWriting = 0;
1749
if (VBOX_FAILURE (rc)) {
1750
AssertMsgFailed (("Floppy: error formating sector %d. rc=%Vrc\n",
1751
fd_sector (cur_drv), rc));
1752
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1760
if (cur_drv->bs == NULL ||
1761
bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1762
FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));
1763
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1766
if (cur_drv->sect == cur_drv->last_sect) {
1767
fdctrl->data_state &= ~FD_STATE_FORMAT;
1768
/* Last sector done */
1769
if (FD_DID_SEEK(fdctrl->data_state))
1770
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1772
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1775
fdctrl->data_pos = 0;
1776
fdctrl->data_len = 4;
1781
static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1785
cur_drv = get_cur_drv(fdctrl);
1787
if (fdctrl->state & FD_CTRL_RESET) {
1788
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1791
fdctrl->state &= ~FD_CTRL_SLEEP;
1792
if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1793
FLOPPY_ERROR("can't write data in status mode\n");
1796
/* Is it write command time ? */
1797
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1798
/* FIFO data write */
1799
fdctrl->fifo[fdctrl->data_pos++] = value;
1800
if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1801
fdctrl->data_pos == fdctrl->data_len) {
1804
/* *p_fd_activity = 2; */
1805
cur_drv->Led.Asserted.s.fWriting
1806
= cur_drv->Led.Actual.s.fWriting = 1;
1808
rc = cur_drv->pDrvBlock->pfnWrite (
1810
fd_sector (cur_drv) * 512,
1815
cur_drv->Led.Actual.s.fWriting = 0;
1817
if (VBOX_FAILURE (rc)) {
1819
("Floppy: failed to write sector %d. rc=%Vrc\n",
1820
fd_sector (cur_drv), rc));
1823
bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1824
fdctrl->fifo, FD_SECTOR_LEN);
1827
/* Switch from transfer mode to status mode
1828
* then from status mode to command mode
1830
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1831
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1834
if (fdctrl->data_pos == 0) {
1836
switch (value & 0x5F) {
1839
FLOPPY_DPRINTF("READ command\n");
1840
/* 8 parameters cmd */
1841
fdctrl->data_len = 9;
1844
/* READ_DELETED variants */
1845
FLOPPY_DPRINTF("READ_DELETED command\n");
1846
/* 8 parameters cmd */
1847
fdctrl->data_len = 9;
1850
/* SCAN_EQUAL variants */
1851
FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1852
/* 8 parameters cmd */
1853
fdctrl->data_len = 9;
1856
/* VERIFY variants */
1857
FLOPPY_DPRINTF("VERIFY command\n");
1858
/* 8 parameters cmd */
1859
fdctrl->data_len = 9;
1862
/* SCAN_LOW_OR_EQUAL variants */
1863
FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1864
/* 8 parameters cmd */
1865
fdctrl->data_len = 9;
1868
/* SCAN_HIGH_OR_EQUAL variants */
1869
FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1870
/* 8 parameters cmd */
1871
fdctrl->data_len = 9;
1876
switch (value & 0x7F) {
1878
/* WRITE variants */
1879
FLOPPY_DPRINTF("WRITE command\n");
1880
/* 8 parameters cmd */
1881
fdctrl->data_len = 9;
1884
/* WRITE_DELETED variants */
1885
FLOPPY_DPRINTF("WRITE_DELETED command\n");
1886
/* 8 parameters cmd */
1887
fdctrl->data_len = 9;
1895
FLOPPY_DPRINTF("SPECIFY command\n");
1896
/* 1 parameter cmd */
1897
fdctrl->data_len = 3;
1900
/* SENSE_DRIVE_STATUS */
1901
FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1902
/* 1 parameter cmd */
1903
fdctrl->data_len = 2;
1907
FLOPPY_DPRINTF("RECALIBRATE command\n");
1908
/* 1 parameter cmd */
1909
fdctrl->data_len = 2;
1912
/* SENSE_INTERRUPT_STATUS */
1913
FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1914
fdctrl->int_status);
1915
/* No parameters cmd: returns status if no interrupt */
1918
fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1920
/* XXX: int_status handling is broken for read/write
1921
commands, so we do this hack. It should be suppressed
1924
0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1926
fdctrl->fifo[1] = cur_drv->track;
1927
fdctrl_set_fifo(fdctrl, 2, 0);
1928
fdctrl_reset_irq(fdctrl);
1929
fdctrl->int_status = 0xC0;
1933
FLOPPY_DPRINTF("DUMPREG command\n");
1934
/* Drives position */
1935
fdctrl->fifo[0] = drv0(fdctrl)->track;
1936
fdctrl->fifo[1] = drv1(fdctrl)->track;
1937
fdctrl->fifo[2] = 0;
1938
fdctrl->fifo[3] = 0;
1940
fdctrl->fifo[4] = fdctrl->timer0;
1941
fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1942
fdctrl->fifo[6] = cur_drv->last_sect;
1943
fdctrl->fifo[7] = (fdctrl->lock << 7) |
1944
(cur_drv->perpendicular << 2);
1945
fdctrl->fifo[8] = fdctrl->config;
1946
fdctrl->fifo[9] = fdctrl->precomp_trk;
1947
fdctrl_set_fifo(fdctrl, 10, 0);
1951
FLOPPY_DPRINTF("SEEK command\n");
1952
/* 2 parameters cmd */
1953
fdctrl->data_len = 3;
1957
FLOPPY_DPRINTF("VERSION command\n");
1958
/* No parameters cmd */
1959
/* Controller's version */
1960
fdctrl->fifo[0] = fdctrl->version;
1961
fdctrl_set_fifo(fdctrl, 1, 1);
1964
/* PERPENDICULAR_MODE */
1965
FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1966
/* 1 parameter cmd */
1967
fdctrl->data_len = 2;
1971
FLOPPY_DPRINTF("CONFIGURE command\n");
1972
/* 3 parameters cmd */
1973
fdctrl->data_len = 4;
1977
FLOPPY_DPRINTF("UNLOCK command\n");
1978
/* No parameters cmd */
1980
fdctrl->fifo[0] = 0;
1981
fdctrl_set_fifo(fdctrl, 1, 0);
1984
/* POWERDOWN_MODE */
1985
FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1986
/* 2 parameters cmd */
1987
fdctrl->data_len = 3;
1991
FLOPPY_DPRINTF("PART_ID command\n");
1992
/* No parameters cmd */
1993
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1994
fdctrl_set_fifo(fdctrl, 1, 0);
1998
FLOPPY_DPRINTF("SAVE command\n");
1999
/* No parameters cmd */
2000
fdctrl->fifo[0] = 0;
2001
fdctrl->fifo[1] = 0;
2002
/* Drives position */
2003
fdctrl->fifo[2] = drv0(fdctrl)->track;
2004
fdctrl->fifo[3] = drv1(fdctrl)->track;
2005
fdctrl->fifo[4] = 0;
2006
fdctrl->fifo[5] = 0;
2008
fdctrl->fifo[6] = fdctrl->timer0;
2009
fdctrl->fifo[7] = fdctrl->timer1;
2010
fdctrl->fifo[8] = cur_drv->last_sect;
2011
fdctrl->fifo[9] = (fdctrl->lock << 7) |
2012
(cur_drv->perpendicular << 2);
2013
fdctrl->fifo[10] = fdctrl->config;
2014
fdctrl->fifo[11] = fdctrl->precomp_trk;
2015
fdctrl->fifo[12] = fdctrl->pwrd;
2016
fdctrl->fifo[13] = 0;
2017
fdctrl->fifo[14] = 0;
2018
fdctrl_set_fifo(fdctrl, 15, 1);
2022
FLOPPY_DPRINTF("OPTION command\n");
2023
/* 1 parameter cmd */
2024
fdctrl->data_len = 2;
2028
FLOPPY_DPRINTF("READ_TRACK command\n");
2029
/* 8 parameters cmd */
2030
fdctrl->data_len = 9;
2034
FLOPPY_DPRINTF("READ_ID command\n");
2035
/* 1 parameter cmd */
2036
fdctrl->data_len = 2;
2040
FLOPPY_DPRINTF("RESTORE command\n");
2041
/* 17 parameters cmd */
2042
fdctrl->data_len = 18;
2046
FLOPPY_DPRINTF("FORMAT_TRACK command\n");
2047
/* 5 parameters cmd */
2048
fdctrl->data_len = 6;
2051
/* DRIVE_SPECIFICATION_COMMAND */
2052
FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
2053
/* 5 parameters cmd */
2054
fdctrl->data_len = 6;
2057
/* RELATIVE_SEEK_OUT */
2058
FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
2059
/* 2 parameters cmd */
2060
fdctrl->data_len = 3;
2064
FLOPPY_DPRINTF("LOCK command\n");
2065
/* No parameters cmd */
2067
fdctrl->fifo[0] = 0x10;
2068
fdctrl_set_fifo(fdctrl, 1, 1);
2071
/* FORMAT_AND_WRITE */
2072
FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
2073
/* 10 parameters cmd */
2074
fdctrl->data_len = 11;
2077
/* RELATIVE_SEEK_IN */
2078
FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
2079
/* 2 parameters cmd */
2080
fdctrl->data_len = 3;
2083
/* Unknown command */
2084
FLOPPY_ERROR("unknown command: 0x%02x\n", value);
2085
fdctrl_unimplemented(fdctrl);
2090
FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
2091
fdctrl->fifo[fdctrl->data_pos] = value;
2092
if (++fdctrl->data_pos == fdctrl->data_len) {
2093
/* We now have all parameters
2094
* and will be able to treat the command
2096
if (fdctrl->data_state & FD_STATE_FORMAT) {
2097
fdctrl_format_sector(fdctrl);
2100
switch (fdctrl->fifo[0] & 0x1F) {
2104
FLOPPY_DPRINTF("treat READ command\n");
2105
fdctrl_start_transfer(fdctrl, FD_DIR_READ);
2109
/* READ_DELETED variants */
2110
/* // FLOPPY_DPRINTF("treat READ_DELETED command\n"); */
2111
FLOPPY_ERROR("treat READ_DELETED command\n");
2112
fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
2115
/* VERIFY variants */
2116
/* // FLOPPY_DPRINTF("treat VERIFY command\n"); */
2117
FLOPPY_ERROR("treat VERIFY command\n");
2118
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
2121
/* SCAN_EQUAL variants */
2122
/* // FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); */
2123
FLOPPY_ERROR("treat SCAN_EQUAL command\n");
2124
fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
2127
/* SCAN_LOW_OR_EQUAL variants */
2128
/* // FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); */
2129
FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
2130
fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
2133
/* SCAN_HIGH_OR_EQUAL variants */
2134
/* // FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); */
2135
FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
2136
fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
2141
switch (fdctrl->fifo[0] & 0x3F) {
2143
/* WRITE variants */
2144
FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
2145
fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
2148
/* WRITE_DELETED variants */
2149
/* // FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); */
2150
FLOPPY_ERROR("treat WRITE_DELETED command\n");
2151
fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
2156
switch (fdctrl->fifo[0]) {
2159
FLOPPY_DPRINTF("treat SPECIFY command\n");
2160
fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
2161
fdctrl->timer1 = fdctrl->fifo[2] >> 1;
2162
fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
2163
/* No result back */
2164
fdctrl_reset_fifo(fdctrl);
2167
/* SENSE_DRIVE_STATUS */
2168
FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
2169
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2170
cur_drv = get_cur_drv(fdctrl);
2171
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2172
/* 1 Byte status back */
2173
fdctrl->fifo[0] = (cur_drv->ro << 6) |
2174
(cur_drv->track == 0 ? 0x10 : 0x00) |
2175
(cur_drv->head << 2) |
2178
fdctrl_set_fifo(fdctrl, 1, 0);
2182
FLOPPY_DPRINTF("treat RECALIBRATE command\n");
2183
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2184
cur_drv = get_cur_drv(fdctrl);
2185
fd_recalibrate(cur_drv);
2186
fdctrl_reset_fifo(fdctrl);
2187
/* Raise Interrupt */
2188
fdctrl_raise_irq(fdctrl, 0x20);
2192
FLOPPY_DPRINTF("treat SEEK command\n");
2193
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2194
cur_drv = get_cur_drv(fdctrl);
2196
if (fdctrl->fifo[2] <= cur_drv->track)
2200
fdctrl_reset_fifo(fdctrl);
2202
if (fdctrl->fifo[2] > cur_drv->max_track) {
2204
if ( fdctrl->fifo[2] > cur_drv->max_track
2205
&& cur_drv->fMediaPresent) {
2207
fdctrl_raise_irq(fdctrl, 0x60);
2209
cur_drv->track = fdctrl->fifo[2];
2210
/* Raise Interrupt */
2211
fdctrl_raise_irq(fdctrl, 0x20);
2215
/* PERPENDICULAR_MODE */
2216
FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
2217
if (fdctrl->fifo[1] & 0x80)
2218
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
2219
/* No result back */
2220
fdctrl_reset_fifo(fdctrl);
2224
FLOPPY_DPRINTF("treat CONFIGURE command\n");
2225
fdctrl->config = fdctrl->fifo[2];
2226
fdctrl->precomp_trk = fdctrl->fifo[3];
2227
/* No result back */
2228
fdctrl_reset_fifo(fdctrl);
2231
/* POWERDOWN_MODE */
2232
FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
2233
fdctrl->pwrd = fdctrl->fifo[1];
2234
fdctrl->fifo[0] = fdctrl->fifo[1];
2235
fdctrl_set_fifo(fdctrl, 1, 1);
2239
FLOPPY_DPRINTF("treat OPTION command\n");
2240
/* No result back */
2241
fdctrl_reset_fifo(fdctrl);
2245
/* // FLOPPY_DPRINTF("treat READ_TRACK command\n"); */
2246
FLOPPY_ERROR("treat READ_TRACK command\n");
2247
fdctrl_start_transfer(fdctrl, FD_DIR_READ);
2251
FLOPPY_DPRINTF("treat READ_ID command\n");
2252
/* XXX: should set main status register to busy */
2253
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2255
TMTimerSetMillies(fdctrl->result_timer, 1000 / 50);
2257
qemu_mod_timer(fdctrl->result_timer,
2258
qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
2263
FLOPPY_DPRINTF("treat RESTORE command\n");
2264
/* Drives position */
2265
drv0(fdctrl)->track = fdctrl->fifo[3];
2266
drv1(fdctrl)->track = fdctrl->fifo[4];
2268
fdctrl->timer0 = fdctrl->fifo[7];
2269
fdctrl->timer1 = fdctrl->fifo[8];
2270
cur_drv->last_sect = fdctrl->fifo[9];
2271
fdctrl->lock = fdctrl->fifo[10] >> 7;
2272
cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
2273
fdctrl->config = fdctrl->fifo[11];
2274
fdctrl->precomp_trk = fdctrl->fifo[12];
2275
fdctrl->pwrd = fdctrl->fifo[13];
2276
fdctrl_reset_fifo(fdctrl);
2280
FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
2281
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2282
cur_drv = get_cur_drv(fdctrl);
2283
fdctrl->data_state |= FD_STATE_FORMAT;
2284
if (fdctrl->fifo[0] & 0x80)
2285
fdctrl->data_state |= FD_STATE_MULTI;
2287
fdctrl->data_state &= ~FD_STATE_MULTI;
2288
fdctrl->data_state &= ~FD_STATE_SEEK;
2290
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
2292
cur_drv->last_sect =
2293
cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
2294
fdctrl->fifo[3] / 2;
2296
cur_drv->last_sect = fdctrl->fifo[3];
2298
/* Bochs BIOS is buggy and don't send format informations
2299
* for each sector. So, pretend all's done right now...
2301
fdctrl->data_state &= ~FD_STATE_FORMAT;
2302
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2305
/* DRIVE_SPECIFICATION_COMMAND */
2306
FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
2307
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
2308
/* Command parameters done */
2309
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
2310
fdctrl->fifo[0] = fdctrl->fifo[1];
2311
fdctrl->fifo[2] = 0;
2312
fdctrl->fifo[3] = 0;
2313
fdctrl_set_fifo(fdctrl, 4, 1);
2315
fdctrl_reset_fifo(fdctrl);
2317
} else if (fdctrl->data_len > 7) {
2319
fdctrl->fifo[0] = 0x80 |
2320
(cur_drv->head << 2) | fdctrl->cur_drv;
2321
fdctrl_set_fifo(fdctrl, 1, 1);
2325
/* RELATIVE_SEEK_OUT */
2326
FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
2327
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2328
cur_drv = get_cur_drv(fdctrl);
2331
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
2332
cur_drv->track = cur_drv->max_track - 1;
2334
cur_drv->track += fdctrl->fifo[2];
2336
fdctrl_reset_fifo(fdctrl);
2337
fdctrl_raise_irq(fdctrl, 0x20);
2340
/* FORMAT_AND_WRITE */
2341
/* // FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); */
2342
FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
2343
fdctrl_unimplemented(fdctrl);
2346
/* RELATIVE_SEEK_IN */
2347
FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
2348
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2349
cur_drv = get_cur_drv(fdctrl);
2352
if (fdctrl->fifo[2] > cur_drv->track) {
2355
cur_drv->track -= fdctrl->fifo[2];
2357
fdctrl_reset_fifo(fdctrl);
2358
/* Raise Interrupt */
2359
fdctrl_raise_irq(fdctrl, 0x20);
2365
static void fdctrl_result_timer(void *opaque)
2367
fdctrl_t *fdctrl = opaque;
2368
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2373
static DECLCALLBACK(void) fdc_timer (PPDMDEVINS pDevIns, PTMTIMER pTimer)
2375
fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2376
fdctrl_result_timer (fdctrl);
2379
static DECLCALLBACK(int) fdc_io_write (PPDMDEVINS pDevIns,
2386
fdctrl_write (pvUser, Port, u32);
2389
AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2391
return VINF_SUCCESS;
2394
static DECLCALLBACK(int) fdc_io_read (PPDMDEVINS pDevIns,
2401
*pu32 = fdctrl_read (pvUser, Port);
2402
return VINF_SUCCESS;
2405
return VERR_IOM_IOPORT_UNUSED;
2409
static DECLCALLBACK(int) SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2411
fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
2412
QEMUFile *f = pSSMHandle;
2415
qemu_put_8s (f, &s->version);
2416
qemu_put_8s (f, &s->irq_lvl);
2417
qemu_put_8s (f, &s->dma_chann);
2418
qemu_put_be32s (f, &s->io_base);
2419
qemu_put_8s (f, &s->state);
2420
qemu_put_8s (f, &s->dma_en);
2421
qemu_put_8s (f, &s->cur_drv);
2422
qemu_put_8s (f, &s->bootsel);
2423
qemu_put_buffer (f, s->fifo, FD_SECTOR_LEN);
2424
qemu_put_be32s (f, &s->data_pos);
2425
qemu_put_be32s (f, &s->data_len);
2426
qemu_put_8s (f, &s->data_state);
2427
qemu_put_8s (f, &s->data_dir);
2428
qemu_put_8s (f, &s->int_status);
2429
qemu_put_8s (f, &s->eot);
2430
qemu_put_8s (f, &s->timer0);
2431
qemu_put_8s (f, &s->timer1);
2432
qemu_put_8s (f, &s->precomp_trk);
2433
qemu_put_8s (f, &s->config);
2434
qemu_put_8s (f, &s->lock);
2435
qemu_put_8s (f, &s->pwrd);
2437
for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
2438
fdrive_t *d = &s->drives[i];
2440
SSMR3PutMem (pSSMHandle, &d->Led, sizeof (d->Led));
2441
qemu_put_be32s (f, &d->drive);
2442
qemu_put_be32s (f, &d->drflags);
2443
qemu_put_8s (f, &d->perpendicular);
2444
qemu_put_8s (f, &d->head);
2445
qemu_put_8s (f, &d->track);
2446
qemu_put_8s (f, &d->sect);
2447
qemu_put_8s (f, &d->dir);
2448
qemu_put_8s (f, &d->rw);
2449
qemu_put_be32s (f, &d->flags);
2450
qemu_put_8s (f, &d->last_sect);
2451
qemu_put_8s (f, &d->max_track);
2452
qemu_put_be16s (f, &d->bps);
2453
qemu_put_8s (f, &d->ro);
2455
return TMR3TimerSave (s->result_timer, pSSMHandle);
2458
static DECLCALLBACK(int) LoadExec (PPDMDEVINS pDevIns,
2459
PSSMHANDLE pSSMHandle,
2460
uint32_t u32Version)
2462
fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
2463
QEMUFile *f = pSSMHandle;
2466
if (u32Version != 1) {
2467
AssertMsgFailed(("u32Version=%d\n", u32Version));
2468
return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2471
qemu_get_8s (f, &s->version);
2472
qemu_get_8s (f, &s->irq_lvl);
2473
qemu_get_8s (f, &s->dma_chann);
2474
qemu_get_be32s (f, &s->io_base);
2475
qemu_get_8s (f, &s->state);
2476
qemu_get_8s (f, &s->dma_en);
2477
qemu_get_8s (f, &s->cur_drv);
2478
qemu_get_8s (f, &s->bootsel);
2479
qemu_get_buffer (f, s->fifo, FD_SECTOR_LEN);
2480
qemu_get_be32s (f, &s->data_pos);
2481
qemu_get_be32s (f, &s->data_len);
2482
qemu_get_8s (f, &s->data_state);
2483
qemu_get_8s (f, &s->data_dir);
2484
qemu_get_8s (f, &s->int_status);
2485
qemu_get_8s (f, &s->eot);
2486
qemu_get_8s (f, &s->timer0);
2487
qemu_get_8s (f, &s->timer1);
2488
qemu_get_8s (f, &s->precomp_trk);
2489
qemu_get_8s (f, &s->config);
2490
qemu_get_8s (f, &s->lock);
2491
qemu_get_8s (f, &s->pwrd);
2493
for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
2494
fdrive_t *d = &s->drives[i];
2496
SSMR3GetMem (pSSMHandle, &d->Led, sizeof (d->Led));
2497
qemu_get_be32s (f, &d->drive);
2498
qemu_get_be32s (f, &d->drflags);
2499
qemu_get_8s (f, &d->perpendicular);
2500
qemu_get_8s (f, &d->head);
2501
qemu_get_8s (f, &d->track);
2502
qemu_get_8s (f, &d->sect);
2503
qemu_get_8s (f, &d->dir);
2504
qemu_get_8s (f, &d->rw);
2505
qemu_get_be32s (f, &d->flags);
2506
qemu_get_8s (f, &d->last_sect);
2507
qemu_get_8s (f, &d->max_track);
2508
qemu_get_be16s (f, &d->bps);
2509
qemu_get_8s (f, &d->ro);
2511
return TMR3TimerLoad (s->result_timer, pSSMHandle);
2515
* Queries an interface to the driver.
2517
* @returns Pointer to interface.
2518
* @returns NULL if the interface was not supported by the device.
2519
* @param pInterface Pointer to IDEState::IBase.
2520
* @param enmInterface The requested interface identification.
2522
static DECLCALLBACK(void *) fdQueryInterface (PPDMIBASE pInterface,
2523
PDMINTERFACE enmInterface)
2525
fdrive_t *drv = PDMIBASE_2_FDRIVE(pInterface);
2526
switch (enmInterface) {
2527
case PDMINTERFACE_BASE:
2529
case PDMINTERFACE_BLOCK_PORT:
2531
case PDMINTERFACE_MOUNT_NOTIFY:
2532
return &drv->IMountNotify;
2539
* Gets the pointer to the status LED of a unit.
2541
* @returns VBox status code.
2542
* @param pInterface Pointer to the interface structure containing the called function pointer.
2543
* @param iLUN The unit which status LED we desire.
2544
* @param ppLed Where to store the LED pointer.
2546
static DECLCALLBACK(int) fdcStatusQueryStatusLed (PPDMILEDPORTS pInterface,
2550
fdctrl_t *fdctrl = (fdctrl_t *)
2551
((uintptr_t )pInterface - RT_OFFSETOF (fdctrl_t, ILeds));
2552
if (iLUN < ELEMENTS(fdctrl->drives)) {
2553
*ppLed = &fdctrl->drives[iLUN].Led;
2554
Assert ((*ppLed)->u32Magic == PDMLED_MAGIC);
2555
return VINF_SUCCESS;
2557
return VERR_PDM_LUN_NOT_FOUND;
2562
* Queries an interface to the status LUN.
2564
* @returns Pointer to interface.
2565
* @returns NULL if the interface was not supported by the device.
2566
* @param pInterface Pointer to IDEState::IBase.
2567
* @param enmInterface The requested interface identification.
2569
static DECLCALLBACK(void *) fdcStatusQueryInterface (PPDMIBASE pInterface,
2570
PDMINTERFACE enmInterface)
2572
fdctrl_t *fdctrl = (fdctrl_t *)
2573
((uintptr_t)pInterface - RT_OFFSETOF (fdctrl_t, IBaseStatus));
2574
switch (enmInterface) {
2575
case PDMINTERFACE_BASE:
2576
return &fdctrl->IBaseStatus;
2577
case PDMINTERFACE_LED_PORTS:
2578
return &fdctrl->ILeds;
2586
* Configure a drive.
2588
* @returns VBox status code.
2589
* @param drv The drive in question.
2590
* @param pDevIns The driver instance.
2592
static int fdConfig (fdrive_t *drv, PPDMDEVINS pDevIns)
2594
static const char *descs[] = {"Floppy Drive A:", "Floppy Drive B"};
2598
* Reset the LED just to be on the safe side.
2600
Assert (ELEMENTS(descs) > drv->iLUN);
2601
Assert (drv->Led.u32Magic == PDMLED_MAGIC);
2602
drv->Led.Actual.u32 = 0;
2603
drv->Led.Asserted.u32 = 0;
2606
* Try attach the block device and get the interfaces.
2608
rc = PDMDevHlpDriverAttach (pDevIns, drv->iLUN, &drv->IBase, &drv->pDrvBase, descs[drv->iLUN]);
2609
if (VBOX_SUCCESS (rc))
2611
drv->pDrvBlock = drv->pDrvBase->pfnQueryInterface (
2615
if (drv->pDrvBlock) {
2616
drv->pDrvBlockBios = drv->pDrvBase->pfnQueryInterface (
2618
PDMINTERFACE_BLOCK_BIOS
2620
if (drv->pDrvBlockBios) {
2621
drv->pDrvMount = drv->pDrvBase->pfnQueryInterface (
2625
if (drv->pDrvMount) {
2629
drv->drive = FDRIVE_DRV_NONE;
2631
drv->perpendicular = 0;
2635
drv->fMediaPresent = false;
2638
AssertMsgFailed (("Configuration error: LUN#%d without mountable interface!\n", drv->iLUN));
2639
rc = VERR_PDM_MISSING_INTERFACE;
2644
AssertMsgFailed (("Configuration error: LUN#%d hasn't a block BIOS interface!\n", drv->iLUN));
2645
rc = VERR_PDM_MISSING_INTERFACE;
2650
AssertMsgFailed (("Configuration error: LUN#%d hasn't a block interface!\n", drv->iLUN));
2651
rc = VERR_PDM_MISSING_INTERFACE;
2655
AssertMsg (rc == VERR_PDM_NO_ATTACHED_DRIVER,
2656
("Failed to attach LUN#%d. rc=%Vrc\n", drv->iLUN, rc));
2659
if (VBOX_FAILURE (rc)) {
2660
drv->pDrvBase = NULL;
2661
drv->pDrvBlock = NULL;
2662
drv->pDrvBlockBios = NULL;
2663
drv->pDrvMount = NULL;
2665
LogFlow (("fdConfig: returns %Vrc\n", rc));
2673
* This is called when we change block driver for a floppy drive.
2675
* @returns VBox status code.
2676
* @param pDevIns The device instance.
2677
* @param iLUN The logical unit which is being detached.
2679
static DECLCALLBACK(int) fdcAttach (PPDMDEVINS pDevIns,
2682
fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2685
LogFlow (("ideDetach: iLUN=%u\n", iLUN));
2691
AssertMsgFailed (("Configuration error: cannot attach or detach any but the first two LUNs - iLUN=%u\n",
2693
return VERR_PDM_DEVINS_NO_ATTACH;
2697
* Locate the drive and stuff.
2699
drv = &fdctrl->drives[iLUN];
2701
/* the usual paranoia */
2702
AssertRelease (!drv->pDrvBase);
2703
AssertRelease (!drv->pDrvBlock);
2704
AssertRelease (!drv->pDrvBlockBios);
2705
AssertRelease (!drv->pDrvMount);
2707
rc = fdConfig (drv, pDevIns);
2708
AssertMsg (rc != VERR_PDM_NO_ATTACHED_DRIVER,
2709
("Configuration error: failed to configure drive %d, rc=%Vrc\n", rc));
2710
if (VBOX_SUCCESS(rc)) {
2711
fd_revalidate (drv);
2714
LogFlow (("floppyAttach: returns %Vrc\n", rc));
2720
* Detach notification.
2722
* The floppy drive has been temporarily 'unplugged'.
2724
* @param pDevIns The device instance.
2725
* @param iLUN The logical unit which is being detached.
2727
static DECLCALLBACK(void) fdcDetach (PPDMDEVINS pDevIns,
2730
fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2731
LogFlow (("ideDetach: iLUN=%u\n", iLUN));
2736
fdrive_t *drv = &fdctrl->drives[iLUN];
2737
drv->pDrvBase = NULL;
2738
drv->pDrvBlock = NULL;
2739
drv->pDrvBlockBios = NULL;
2740
drv->pDrvMount = NULL;
2745
AssertMsgFailed (("Cannot detach LUN#%d!\n", iLUN));
2754
* I haven't check the specs on what's supposed to happen on reset, but we
2755
* should get any 'FATAL: floppy recal:f07 ctrl not ready' when resetting
2756
* at wrong time like we do if this was all void.
2758
* @param pDevIns The device instance.
2760
static DECLCALLBACK(void) fdcReset (PPDMDEVINS pDevIns)
2762
fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2764
LogFlow (("fdcReset:\n"));
2766
fdctrl_reset(fdctrl, 0);
2767
fdctrl->state = FD_CTRL_ACTIVE;
2769
for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
2770
fd_revalidate(&fdctrl->drives[i]);
2776
* Construct a device instance for a VM.
2778
* @returns VBox status.
2779
* @param pDevIns The device instance data.
2780
* If the registration structure is needed, pDevIns->pDevReg points to it.
2781
* @param iInstance Instance number. Use this to figure out which registers and such to use.
2782
* The device number is also found in pDevIns->iInstance, but since it's
2783
* likely to be freqently used PDM passes it as parameter.
2784
* @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
2785
* of the device instance. It's also found in pDevIns->pCfgHandle, but like
2786
* iInstance it's expected to be used a bit in this function.
2788
static DECLCALLBACK(int) fdcConstruct (PPDMDEVINS pDevIns,
2790
PCFGMNODE pCfgHandle)
2793
fdctrl_t *fdctrl = PDMINS2DATA(pDevIns, fdctrl_t*);
2797
uint8_t irq_lvl, dma_chann;
2800
Assert(iInstance == 0);
2803
* Validate configuration.
2805
if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0DMA\0MemMapped\0IOBase\0")) {
2806
return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2810
* Read the configuration.
2812
rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
2813
if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2816
else if (VBOX_FAILURE (rc)) {
2817
AssertMsgFailed (("Configuration error: Failed to read U8 IRQ, rc=%Vrc\n", rc));
2821
rc = CFGMR3QueryU8 (pCfgHandle, "DMA", &dma_chann);
2822
if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2825
else if (VBOX_FAILURE (rc)) {
2826
AssertMsgFailed (("Configuration error: Failed to read U8 DMA, rc=%Vrc\n", rc));
2830
rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
2831
if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2834
else if (VBOX_FAILURE (rc)) {
2835
AssertMsgFailed (("Configuration error: Failed to read U16 IOBase, rc=%Vrc\n", rc));
2839
rc = CFGMR3QueryBool (pCfgHandle, "MemMapped", &mem_mapped);
2840
if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2843
else if (VBOX_FAILURE (rc)) {
2844
AssertMsgFailed (("Configuration error: Failed to read bool value MemMapped rc=%Vrc\n", rc));
2851
LogFlow(("fdcConstruct: irq_lvl=%d dma_chann=%d io_base=%#x\n", irq_lvl, dma_chann, io_base));
2852
fdctrl->pDevIns = pDevIns;
2853
fdctrl->version = 0x90; /* Intel 82078 controller */
2854
fdctrl->irq_lvl = irq_lvl;
2855
fdctrl->dma_chann = dma_chann;
2856
fdctrl->io_base = io_base;
2857
fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
2859
fdctrl->IBaseStatus.pfnQueryInterface = fdcStatusQueryInterface;
2860
fdctrl->ILeds.pfnQueryStatusLed = fdcStatusQueryStatusLed;
2862
for (i = 0; i < ELEMENTS(fdctrl->drives); ++i) {
2863
fdrive_t *drv = &fdctrl->drives[i];
2865
drv->drive = FDRIVE_DRV_NONE;
2868
drv->IBase.pfnQueryInterface = fdQueryInterface;
2869
drv->IMountNotify.pfnMountNotify = fdMountNotify;
2870
drv->IMountNotify.pfnUnmountNotify = fdUnmountNotify;
2871
drv->Led.u32Magic = PDMLED_MAGIC;
2875
* Create the FDC timer.
2877
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, fdc_timer, "FDC Timer", &fdctrl->result_timer);
2878
if (VBOX_FAILURE (rc)) {
2883
* Register DMA channel.
2885
if (fdctrl->dma_chann != 0xff) {
2887
rc = pDevIns->pDevHlp->pfnDMARegister (
2890
&fdctrl_transfer_handler,
2892
if (VBOX_FAILURE (rc)) {
2903
AssertMsgFailed (("Memory mapped floppy not support by now\n"));
2904
return VERR_NOT_SUPPORTED;
2906
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
2907
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
2908
cpu_register_physical_memory(base, 0x08, io_mem);
2911
rc = pDevIns->pDevHlp->pfnIOPortRegister (
2921
if (VBOX_FAILURE (rc)) {
2925
rc = pDevIns->pDevHlp->pfnIOPortRegister (
2935
if (VBOX_FAILURE (rc)) {
2941
* Register the saved state data unit.
2943
rc = pDevIns->pDevHlp->pfnSSMRegister (
2944
pDevIns, /* pDevIns */
2945
pDevIns->pDevReg->szDeviceName, /* pszName */
2946
iInstance, /* u32Instance */
2948
sizeof (*fdctrl), /* cbGuess */
2949
NULL, /* pfnSavePrep */
2950
SaveExec, /* pfnSaveExec */
2951
NULL, /* pfnSaveDone */
2952
NULL, /* pfnLoadPrep */
2953
LoadExec, /* pfnLoadExec */
2954
NULL /* pfnLoadDone */
2956
if (VBOX_FAILURE(rc))
2960
* Attach the status port (optional).
2962
rc = PDMDevHlpDriverAttach (pDevIns, PDM_STATUS_LUN, &fdctrl->IBaseStatus, &pBase, "Status Port");
2963
if (VBOX_SUCCESS (rc)) {
2964
fdctrl->pLedsConnector =
2965
pBase->pfnQueryInterface (pBase, PDMINTERFACE_LED_CONNECTORS);
2967
else if (rc != VERR_PDM_NO_ATTACHED_DRIVER) {
2968
AssertMsgFailed (("Failed to attach to status driver. rc=%Vrc\n",
2974
* Initialize drives.
2976
for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
2977
fdrive_t *drv = &fdctrl->drives[i];
2978
rc = fdConfig (drv, pDevIns);
2979
if ( VBOX_FAILURE (rc)
2980
&& rc != VERR_PDM_NO_ATTACHED_DRIVER) {
2981
AssertMsgFailed (("Configuration error: failed to configure drive %d, rc=%Vrc\n", rc));
2986
fdctrl_reset(fdctrl, 0);
2987
fdctrl->state = FD_CTRL_ACTIVE;
2989
for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
2990
fd_revalidate(&fdctrl->drives[i]);
2993
return VINF_SUCCESS;
2997
* The device registration structure.
2999
const PDMDEVREG g_DeviceFloppyController =
3009
/* pszDescription */
3010
"Floppy drive controller (Intel 82078)",
3012
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
3014
PDM_DEVREG_CLASS_STORAGE,
3039
/* pfnQueryInterface. */
3048
* c-file-style: "k&r"
3049
* indent-tabs-mode: nil