~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Storage/fdc.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef VBOX
 
2
/** @file
 
3
 *
 
4
 * VBox storage devices:
 
5
 * Floppy disk controller
 
6
 */
 
7
 
 
8
/*
 
9
 * Copyright (C) 2006-2007 innotek GmbH
 
10
 *
 
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
 * --------------------------------------------------------------------
 
19
 *
 
20
 * This code is based on:
 
21
 *
 
22
 * QEMU Floppy disk emulator (Intel 82078)
 
23
 *
 
24
 * Copyright (c) 2003 Jocelyn Mayer
 
25
 *
 
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:
 
32
 *
 
33
 * The above copyright notice and this permission notice shall be included in
 
34
 * all copies or substantial portions of the Software.
 
35
 *
 
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
 
42
 * THE SOFTWARE.
 
43
 *
 
44
 */
 
45
 
 
46
 
 
47
/*******************************************************************************
 
48
*   Header Files                                                               *
 
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>
 
55
 
 
56
#include "Builtins.h"
 
57
#include "../vl_vbox.h"
 
58
 
 
59
#define MAX_FD 2
 
60
 
 
61
#define PDMIBASE_2_FDRIVE(pInterface) \
 
62
    ((fdrive_t *)((uintptr_t)(pInterface) - RT_OFFSETOF(fdrive_t, IBase)))
 
63
 
 
64
#define PDMIMOUNTNOTIFY_2_FDRIVE(p)  \
 
65
    ((fdrive_t *)((uintptr_t)(p) - RT_OFFSETOF(fdrive_t, IMountNotify)))
 
66
 
 
67
#endif /* VBOX */
 
68
 
 
69
#ifndef VBOX
 
70
#include "vl.h"
 
71
#endif /* !VBOX */
 
72
 
 
73
/********************************************************/
 
74
/* debug Floppy devices */
 
75
/* #define DEBUG_FLOPPY */
 
76
 
 
77
#ifndef VBOX
 
78
    #ifdef DEBUG_FLOPPY
 
79
    #define FLOPPY_DPRINTF(fmt, args...) \
 
80
        do { printf("FLOPPY: " fmt , ##args); } while (0)
 
81
    #endif
 
82
#else /* !VBOX */
 
83
    # ifdef LOG_ENABLED
 
84
        static void FLOPPY_DPRINTF (const char *fmt, ...)
 
85
        {
 
86
            if (LogIsEnabled ()) {
 
87
                va_list args;
 
88
                va_start (args, fmt);
 
89
                RTLogLogger (NULL, NULL, "floppy: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
 
90
                va_end (args);
 
91
            }
 
92
        }
 
93
    # else
 
94
      DECLINLINE(void) FLOPPY_DPRINTF(const char *pszFmt, ...) {}
 
95
    # endif
 
96
#endif /* !VBOX */
 
97
 
 
98
#ifndef VBOX
 
99
#define FLOPPY_ERROR(fmt, args...) \
 
100
    do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
 
101
#else /* VBOX */
 
102
#   define FLOPPY_ERROR RTLogPrintf
 
103
#endif /* VBOX */
 
104
 
 
105
#ifdef VBOX
 
106
typedef struct fdctrl_t fdctrl_t;
 
107
#endif /* VBOX */
 
108
 
 
109
/********************************************************/
 
110
/* Floppy drive emulation                               */
 
111
 
 
112
/* Will always be a fixed parameter for us */
 
113
#define FD_SECTOR_LEN 512
 
114
#define FD_SECTOR_SC  2   /* Sector size code */
 
115
 
 
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                */
 
123
} fdisk_type_t;
 
124
 
 
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     */
 
130
} fdrive_type_t;
 
131
 
 
132
typedef enum fdrive_flags_t {
 
133
    FDRIVE_MOTOR_ON   = 0x01, /* motor on/off           */
 
134
    FDRIVE_REVALIDATE = 0x02  /* Revalidated            */
 
135
} fdrive_flags_t;
 
136
 
 
137
typedef enum fdisk_flags_t {
 
138
    FDISK_DBL_SIDES  = 0x01
 
139
} fdisk_flags_t;
 
140
 
 
141
typedef struct fdrive_t {
 
142
#ifndef VBOX
 
143
    BlockDriverState *bs;
 
144
#else /* VBOX */
 
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. */
 
155
    PDMIBASE                        IBase;
 
156
    /** The block port interface. */
 
157
    PDMIBLOCKPORT                   IPort;
 
158
    /** The mount notify interface. */
 
159
    PDMIMOUNTNOTIFY                 IMountNotify;
 
160
    /** The LUN #. */
 
161
    RTUINT                          iLUN;
 
162
    /** The LED for this LUN. */
 
163
    PDMLED                          Led;
 
164
    /** The Diskette present/missing flag. */
 
165
    bool                            fMediaPresent;
 
166
#endif
 
167
    /* Drive status */
 
168
    fdrive_type_t drive;
 
169
    fdrive_flags_t drflags;
 
170
    uint8_t perpendicular;    /* 2.88 MB access mode    */
 
171
    /* Position */
 
172
    uint8_t head;
 
173
    uint8_t track;
 
174
    uint8_t sect;
 
175
    /* Last operation status */
 
176
    uint8_t dir;              /* Direction              */
 
177
    uint8_t rw;               /* Read/write             */
 
178
    /* Media */
 
179
    fdisk_flags_t flags;
 
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           */
 
184
} fdrive_t;
 
185
 
 
186
#ifndef VBOX
 
187
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
 
188
{
 
189
    /* Drive */
 
190
    drv->bs = bs;
 
191
    drv->drive = FDRIVE_DRV_NONE;
 
192
    drv->drflags = 0;
 
193
    drv->perpendicular = 0;
 
194
    /* Disk */
 
195
    drv->last_sect = 0;
 
196
    drv->max_track = 0;
 
197
}
 
198
#endif
 
199
 
 
200
static int _fd_sector (uint8_t head, uint8_t track,
 
201
                        uint8_t sect, uint8_t last_sect)
 
202
{
 
203
    return (((track * 2) + head) * last_sect) + sect - 1;
 
204
}
 
205
 
 
206
/* Returns current position, in sectors, for given drive */
 
207
static int fd_sector (fdrive_t *drv)
 
208
{
 
209
    return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
 
210
}
 
211
 
 
212
static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
 
213
                    int enable_seek)
 
214
{
 
215
    uint32_t sector;
 
216
    int ret;
 
217
 
 
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);
 
224
        return 2;
 
225
    }
 
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);
 
231
        return 3;
 
232
    }
 
233
    sector = _fd_sector(head, track, sect, drv->last_sect);
 
234
    ret = 0;
 
235
    if (sector != fd_sector(drv)) {
 
236
#if 0
 
237
        if (!enable_seek) {
 
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);
 
240
            return 4;
 
241
        }
 
242
#endif
 
243
        drv->head = head;
 
244
        if (drv->track != track)
 
245
            ret = 1;
 
246
        drv->track = track;
 
247
        drv->sect = sect;
 
248
    }
 
249
 
 
250
    return ret;
 
251
}
 
252
 
 
253
/* Set drive back to track 0 */
 
254
static void fd_recalibrate (fdrive_t *drv)
 
255
{
 
256
    FLOPPY_DPRINTF("recalibrate\n");
 
257
    drv->head = 0;
 
258
    drv->track = 0;
 
259
    drv->sect = 1;
 
260
    drv->dir = 1;
 
261
    drv->rw = 0;
 
262
}
 
263
 
 
264
/* Recognize floppy formats */
 
265
typedef struct fd_format_t {
 
266
    fdrive_type_t drive;
 
267
    fdisk_type_t  disk;
 
268
    uint8_t last_sect;
 
269
    uint8_t max_track;
 
270
    uint8_t max_head;
 
271
    const char *str;
 
272
} fd_format_t;
 
273
 
 
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", },
 
317
    /* end */
 
318
    { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
 
319
};
 
320
 
 
321
/* Revalidate a disk drive after a disk change */
 
322
static void fd_revalidate (fdrive_t *drv)
 
323
{
 
324
    fd_format_t *parse;
 
325
    int64_t nb_sectors, size;
 
326
    int i, first_match, match;
 
327
    int nb_heads, max_track, last_sect, ro;
 
328
 
 
329
    FLOPPY_DPRINTF("revalidate\n");
 
330
    drv->drflags &= ~FDRIVE_REVALIDATE;
 
331
#ifndef VBOX
 
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);
 
335
#else /* VBOX */
 
336
        /** @todo */ /** @todo r=bird: todo what exactly? */
 
337
    if (drv->pDrvBlock
 
338
        && drv->pDrvMount
 
339
        && drv->pDrvMount->pfnIsMounted (drv->pDrvMount)) {
 
340
        ro = drv->pDrvBlock->pfnIsReadOnly (drv->pDrvBlock);
 
341
        nb_heads = 0;
 
342
        max_track = 0;
 
343
        last_sect = 0;
 
344
#endif /* VBOX */
 
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);
 
348
        } else {
 
349
#ifndef VBOX
 
350
            bdrv_get_geometry(drv->bs, &nb_sectors);
 
351
#else /* VBOX */
 
352
            /* @todo */ /** @todo r=bird: todo what exactly?!?!? */
 
353
            {
 
354
                uint64_t size =  drv->pDrvBlock->pfnGetSize (drv->pDrvBlock);
 
355
                nb_sectors = size / 512;
 
356
            }
 
357
#endif /* VBOX */
 
358
            match = -1;
 
359
            first_match = -1;
 
360
            for (i = 0;; i++) {
 
361
                parse = &fd_formats[i];
 
362
                if (parse->drive == FDRIVE_DRV_NONE)
 
363
                    break;
 
364
                if (drv->drive == parse->drive ||
 
365
                    drv->drive == FDRIVE_DRV_NONE) {
 
366
                    size = (parse->max_head + 1) * parse->max_track *
 
367
                        parse->last_sect;
 
368
                    if (nb_sectors == size) {
 
369
                        match = i;
 
370
                        break;
 
371
                    }
 
372
                    if (first_match == -1)
 
373
                        first_match = i;
 
374
                }
 
375
            }
 
376
            if (match == -1) {
 
377
                if (first_match == -1)
 
378
                    match = 1;
 
379
                else
 
380
                    match = first_match;
 
381
                parse = &fd_formats[match];
 
382
            }
 
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");
 
389
        }
 
390
        if (nb_heads == 1) {
 
391
            drv->flags &= ~FDISK_DBL_SIDES;
 
392
        } else {
 
393
            drv->flags |= FDISK_DBL_SIDES;
 
394
        }
 
395
        drv->max_track = max_track;
 
396
        drv->last_sect = last_sect;
 
397
        drv->ro = ro;
 
398
#ifdef VBOX
 
399
        drv->fMediaPresent = true;
 
400
#endif
 
401
    } else {
 
402
        FLOPPY_DPRINTF("No disk in drive\n");
 
403
        drv->last_sect = 0;
 
404
        drv->max_track = 0;
 
405
        drv->flags &= ~FDISK_DBL_SIDES;
 
406
#ifdef VBOX
 
407
        drv->fMediaPresent = false;
 
408
#endif
 
409
    }
 
410
    drv->drflags |= FDRIVE_REVALIDATE;
 
411
}
 
412
 
 
413
/* Motor control */
 
414
static void fd_start (fdrive_t *drv)
 
415
{
 
416
    drv->drflags |= FDRIVE_MOTOR_ON;
 
417
}
 
418
 
 
419
static void fd_stop (fdrive_t *drv)
 
420
{
 
421
    drv->drflags &= ~FDRIVE_MOTOR_ON;
 
422
}
 
423
 
 
424
/* Re-initialise a drives (motor off, repositioned) */
 
425
static void fd_reset (fdrive_t *drv)
 
426
{
 
427
    fd_stop(drv);
 
428
    fd_recalibrate(drv);
 
429
}
 
430
 
 
431
/********************************************************/
 
432
/* Intel 82078 floppy disk controller emulation          */
 
433
 
 
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);
 
437
#ifndef VBOX
 
438
static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len);
 
439
#else /* VBOX: */
 
440
static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
 
441
                                                       void *opaque,
 
442
                                                       unsigned nchan,
 
443
                                                       uint32_t dma_pos,
 
444
                                                       uint32_t dma_len);
 
445
#endif /* VBOX */
 
446
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
 
447
static void fdctrl_result_timer(void *opaque);
 
448
 
 
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);
 
459
 
 
460
enum {
 
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 */
 
465
    FD_CTRL_INTR   = 0x10
 
466
};
 
467
 
 
468
enum {
 
469
    FD_DIR_WRITE   = 0,
 
470
    FD_DIR_READ    = 1,
 
471
    FD_DIR_SCANE   = 2,
 
472
    FD_DIR_SCANL   = 3,
 
473
    FD_DIR_SCANH   = 4
 
474
};
 
475
 
 
476
enum {
 
477
    FD_STATE_CMD    = 0x00,
 
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
 
484
};
 
485
 
 
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)
 
492
 
 
493
struct fdctrl_t {
 
494
#ifndef VBOX
 
495
    fdctrl_t *fdctrl;
 
496
#endif
 
497
    /* Controller's identification */
 
498
    uint8_t version;
 
499
    /* HW */
 
500
#ifndef VBOX
 
501
    int irq_lvl;
 
502
    int dma_chann;
 
503
#else
 
504
    uint8_t irq_lvl;
 
505
    uint8_t dma_chann;
 
506
#endif
 
507
    uint32_t io_base;
 
508
    /* Controller state */
 
509
    QEMUTimer *result_timer;
 
510
    uint8_t state;
 
511
    uint8_t dma_en;
 
512
    uint8_t cur_drv;
 
513
    uint8_t bootsel;
 
514
    /* Command FIFO */
 
515
    uint8_t fifo[FD_SECTOR_LEN];
 
516
    uint32_t data_pos;
 
517
    uint32_t data_len;
 
518
    uint8_t data_state;
 
519
    uint8_t data_dir;
 
520
    uint8_t int_status;
 
521
    uint8_t eot; /* last wanted sector */
 
522
    /* States kept only to be returned back */
 
523
    /* Timers state */
 
524
    uint8_t timer0;
 
525
    uint8_t timer1;
 
526
    /* precompensation */
 
527
    uint8_t precomp_trk;
 
528
    uint8_t config;
 
529
    uint8_t lock;
 
530
    /* Power down config (also with status regB access mode */
 
531
    uint8_t pwrd;
 
532
    /* Floppy drives */
 
533
    fdrive_t drives[2];
 
534
#ifdef VBOX
 
535
    /** Pointer to device instance. */
 
536
    PPDMDEVINS pDevIns;
 
537
 
 
538
    /** Status Port - The base interface. */
 
539
    PDMIBASE IBaseStatus;
 
540
    /** Status Port - The Leds interface. */
 
541
    PDMILEDPORTS ILeds;
 
542
    /** Status Port - The Partner of ILeds. */
 
543
    PPDMILEDCONNECTORS pLedsConnector;
 
544
#endif
 
545
};
 
546
 
 
547
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
 
548
{
 
549
    fdctrl_t *fdctrl = opaque;
 
550
    uint32_t retval;
 
551
 
 
552
    switch (reg & 0x07) {
 
553
    case 0x01:
 
554
        retval = fdctrl_read_statusB(fdctrl);
 
555
        break;
 
556
    case 0x02:
 
557
        retval = fdctrl_read_dor(fdctrl);
 
558
        break;
 
559
    case 0x03:
 
560
        retval = fdctrl_read_tape(fdctrl);
 
561
        break;
 
562
    case 0x04:
 
563
        retval = fdctrl_read_main_status(fdctrl);
 
564
        break;
 
565
    case 0x05:
 
566
        retval = fdctrl_read_data(fdctrl);
 
567
        break;
 
568
    case 0x07:
 
569
        retval = fdctrl_read_dir(fdctrl);
 
570
        break;
 
571
    default:
 
572
        retval = (uint32_t)(-1);
 
573
        break;
 
574
    }
 
575
    FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
 
576
 
 
577
    return retval;
 
578
}
 
579
 
 
580
static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
 
581
{
 
582
    fdctrl_t *fdctrl = opaque;
 
583
 
 
584
    FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
 
585
 
 
586
    switch (reg & 0x07) {
 
587
    case 0x02:
 
588
        fdctrl_write_dor(fdctrl, value);
 
589
        break;
 
590
    case 0x03:
 
591
        fdctrl_write_tape(fdctrl, value);
 
592
        break;
 
593
    case 0x04:
 
594
        fdctrl_write_rate(fdctrl, value);
 
595
        break;
 
596
    case 0x05:
 
597
        fdctrl_write_data(fdctrl, value);
 
598
        break;
 
599
    default:
 
600
        break;
 
601
    }
 
602
}
 
603
 
 
604
#ifndef VBOX
 
605
static void fd_change_cb (void *opaque)
 
606
{
 
607
    fdrive_t *drv = opaque;
 
608
 
 
609
    FLOPPY_DPRINTF("disk change\n");
 
610
    fd_revalidate(drv);
 
611
#if 0
 
612
    fd_recalibrate(drv);
 
613
    fdctrl_reset_fifo(drv->fdctrl);
 
614
    fdctrl_raise_irq(drv->fdctrl, 0x20);
 
615
#endif
 
616
}
 
617
 
 
618
#else  /* VBOX */
 
619
/**
 
620
 * Called when a media is mounted.
 
621
 *
 
622
 * @param   pInterface      Pointer to the interface structure
 
623
 *                          containing the called function pointer.
 
624
 */
 
625
static DECLCALLBACK(void) fdMountNotify(PPDMIMOUNTNOTIFY pInterface)
 
626
{
 
627
    fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
 
628
    LogFlow(("fdMountNotify:\n"));
 
629
    fd_revalidate (drv);
 
630
}
 
631
 
 
632
/**
 
633
 * Called when a media is unmounted
 
634
 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
 
635
 */
 
636
static DECLCALLBACK(void) fdUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
 
637
{
 
638
    fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
 
639
    LogFlow(("fdUnmountNotify:\n"));
 
640
    fd_revalidate (drv);
 
641
}
 
642
#endif
 
643
 
 
644
#ifndef VBOX
 
645
fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
 
646
                       uint32_t io_base,
 
647
                       BlockDriverState **fds)
 
648
{
 
649
    fdctrl_t *fdctrl;
 
650
/* //    int io_mem; */
 
651
    int i;
 
652
 
 
653
    FLOPPY_DPRINTF("init controller\n");
 
654
    fdctrl = qemu_mallocz(sizeof(fdctrl_t));
 
655
    if (!fdctrl)
 
656
        return NULL;
 
657
    fdctrl->result_timer = qemu_new_timer(vm_clock,
 
658
                                          fdctrl_result_timer, fdctrl);
 
659
 
 
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) {
 
666
        fdctrl->dma_en = 1;
 
667
        DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
 
668
    } else {
 
669
        fdctrl->dma_en = 0;
 
670
    }
 
671
    for (i = 0; i < 2; i++) {
 
672
        fd_init(&fdctrl->drives[i], fds[i]);
 
673
        if (fds[i]) {
 
674
            bdrv_set_change_cb(fds[i],
 
675
                               &fd_change_cb, &fdctrl->drives[i]);
 
676
        }
 
677
    }
 
678
    fdctrl_reset(fdctrl, 0);
 
679
    fdctrl->state = FD_CTRL_ACTIVE;
 
680
    if (mem_mapped) {
 
681
        FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
 
682
#if 0
 
683
        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
 
684
        cpu_register_physical_memory(base, 0x08, io_mem);
 
685
#endif
 
686
    } else {
 
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);
 
691
    }
 
692
    for (i = 0; i < 2; i++) {
 
693
        fd_revalidate(&fdctrl->drives[i]);
 
694
    }
 
695
 
 
696
    return fdctrl;
 
697
}
 
698
 
 
699
/* XXX: may change if moved to bdrv */
 
700
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
 
701
{
 
702
    return fdctrl->drives[drive_num].drive;
 
703
}
 
704
#endif
 
705
 
 
706
/* Change IRQ state */
 
707
static void fdctrl_reset_irq (fdctrl_t *fdctrl)
 
708
{
 
709
    FLOPPY_DPRINTF("Reset interrupt\n");
 
710
#ifdef VBOX
 
711
    fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
 
712
                                            fdctrl->irq_lvl, 0);
 
713
#else
 
714
    pic_set_irq(fdctrl->irq_lvl, 0);
 
715
#endif
 
716
    fdctrl->state &= ~FD_CTRL_INTR;
 
717
}
 
718
 
 
719
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
 
720
{
 
721
    if (~(fdctrl->state & FD_CTRL_INTR)) {
 
722
#ifdef VBOX
 
723
        fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
 
724
                                                fdctrl->irq_lvl, 1);
 
725
#else
 
726
        pic_set_irq(fdctrl->irq_lvl, 1);
 
727
#endif
 
728
        fdctrl->state |= FD_CTRL_INTR;
 
729
    }
 
730
    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
 
731
    fdctrl->int_status = status;
 
732
}
 
733
 
 
734
/* Reset controller */
 
735
static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
 
736
{
 
737
    int i;
 
738
 
 
739
    FLOPPY_DPRINTF("reset controller\n");
 
740
    fdctrl_reset_irq(fdctrl);
 
741
    /* Initialise controller */
 
742
    fdctrl->cur_drv = 0;
 
743
    /* FIFO state */
 
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);
 
751
    if (do_irq)
 
752
        fdctrl_raise_irq(fdctrl, 0xc0);
 
753
}
 
754
 
 
755
static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
 
756
{
 
757
    return &fdctrl->drives[fdctrl->bootsel];
 
758
}
 
759
 
 
760
static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
 
761
{
 
762
    return &fdctrl->drives[1 - fdctrl->bootsel];
 
763
}
 
764
 
 
765
static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
 
766
{
 
767
    return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
 
768
}
 
769
 
 
770
/* Status B register : 0x01 (read-only) */
 
771
static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
 
772
{
 
773
    FLOPPY_DPRINTF("status register: 0x00\n");
 
774
    return 0;
 
775
}
 
776
 
 
777
/* Digital output register : 0x02 */
 
778
static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
 
779
{
 
780
    uint32_t retval = 0;
 
781
 
 
782
    /* Drive motors state indicators */
 
783
#ifndef VBOX
 
784
    if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
 
785
        retval |= 1 << 5;
 
786
    if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
 
787
        retval |= 1 << 4;
 
788
#else
 
789
    /* bit4: 0 = drive 0 motor off/1 = on */
 
790
    if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
 
791
        retval |= BIT(4);
 
792
    /* bit5: 0 = drive 1 motor off/1 = on */
 
793
    if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
 
794
        retval |= BIT(5);
 
795
#endif
 
796
    /* DMA enable */
 
797
    retval |= fdctrl->dma_en << 3;
 
798
    /* Reset indicator */
 
799
    retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
 
800
    /* Selected drive */
 
801
    retval |= fdctrl->cur_drv;
 
802
    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
 
803
 
 
804
    return retval;
 
805
}
 
806
 
 
807
static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
 
808
{
 
809
    /* Reset mode */
 
810
    if (fdctrl->state & FD_CTRL_RESET) {
 
811
        if (!(value & 0x04)) {
 
812
            FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
 
813
            return;
 
814
        }
 
815
    }
 
816
    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
 
817
    /* Drive motors state indicators */
 
818
    if (value & 0x20)
 
819
        fd_start(drv1(fdctrl));
 
820
    else
 
821
        fd_stop(drv1(fdctrl));
 
822
    if (value & 0x10)
 
823
        fd_start(drv0(fdctrl));
 
824
    else
 
825
        fd_stop(drv0(fdctrl));
 
826
    /* DMA enable */
 
827
#if 0
 
828
    if (fdctrl->dma_chann != -1)
 
829
        fdctrl->dma_en = 1 - ((value >> 3) & 1);
 
830
#endif
 
831
    /* Reset */
 
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;
 
836
        }
 
837
    } else {
 
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);
 
842
        }
 
843
    }
 
844
    /* Selected drive */
 
845
    fdctrl->cur_drv = value & 1;
 
846
}
 
847
 
 
848
/* Tape drive register : 0x03 */
 
849
static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
 
850
{
 
851
    uint32_t retval = 0;
 
852
 
 
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);
 
857
 
 
858
    return retval;
 
859
}
 
860
 
 
861
static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
 
862
{
 
863
    /* Reset mode */
 
864
    if (fdctrl->state & FD_CTRL_RESET) {
 
865
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
 
866
        return;
 
867
    }
 
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 */
 
872
}
 
873
 
 
874
/* Main status register : 0x04 (read) */
 
875
static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
 
876
{
 
877
    uint32_t retval = 0;
 
878
 
 
879
    fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
 
880
    if (!(fdctrl->state & FD_CTRL_BUSY)) {
 
881
        /* Data transfer allowed */
 
882
        retval |= 0x80;
 
883
        /* Data transfer direction indicator */
 
884
        if (fdctrl->data_dir == FD_DIR_READ)
 
885
            retval |= 0x40;
 
886
    }
 
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)
 
891
        retval |= 0x10;
 
892
    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
 
893
 
 
894
    return retval;
 
895
}
 
896
 
 
897
/* Data select rate register : 0x04 (write) */
 
898
static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
 
899
{
 
900
    /* Reset mode */
 
901
    if (fdctrl->state & FD_CTRL_RESET) {
 
902
            FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
 
903
            return;
 
904
        }
 
905
    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
 
906
    /* Reset: autoclear */
 
907
    if (value & 0x80) {
 
908
        fdctrl->state |= FD_CTRL_RESET;
 
909
        fdctrl_reset(fdctrl, 1);
 
910
        fdctrl->state &= ~FD_CTRL_RESET;
 
911
    }
 
912
    if (value & 0x40) {
 
913
        fdctrl->state |= FD_CTRL_SLEEP;
 
914
        fdctrl_reset(fdctrl, 1);
 
915
    }
 
916
/* //        fdctrl.precomp = (value >> 2) & 0x07; */
 
917
}
 
918
 
 
919
/* Digital input register : 0x07 (read-only) */
 
920
static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
 
921
{
 
922
    uint32_t retval = 0;
 
923
 
 
924
#ifndef VBOX
 
925
    if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
 
926
        drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
 
927
#else
 
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)
 
932
#endif
 
933
        retval |= 0x80;
 
934
    if (retval != 0)
 
935
        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
 
936
    drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
 
937
    drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
 
938
 
 
939
    return retval;
 
940
}
 
941
 
 
942
/* FIFO state control */
 
943
static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
 
944
{
 
945
    fdctrl->data_dir = FD_DIR_WRITE;
 
946
    fdctrl->data_pos = 0;
 
947
    FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
 
948
}
 
949
 
 
950
/* Set FIFO status for the host to read */
 
951
static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
 
952
{
 
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);
 
957
    if (do_irq)
 
958
        fdctrl_raise_irq(fdctrl, 0x00);
 
959
}
 
960
 
 
961
/* Set an error: unimplemented/unknown command */
 
962
static void fdctrl_unimplemented (fdctrl_t *fdctrl)
 
963
{
 
964
#if 0
 
965
    fdrive_t *cur_drv;
 
966
 
 
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);
 
972
#else
 
973
    /* //    fdctrl_reset_fifo(fdctrl); */
 
974
    fdctrl->fifo[0] = 0x80;
 
975
    fdctrl_set_fifo(fdctrl, 1, 0);
 
976
#endif
 
977
}
 
978
 
 
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)
 
982
{
 
983
    fdrive_t *cur_drv;
 
984
 
 
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) {
 
998
#ifdef VBOX
 
999
        fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
 
1000
                                                 fdctrl->dma_chann,
 
1001
                                                 0);
 
1002
#else
 
1003
        DMA_release_DREQ(fdctrl->dma_chann);
 
1004
#endif
 
1005
        fdctrl->state &= ~FD_CTRL_BUSY;
 
1006
    }
 
1007
    fdctrl_set_fifo(fdctrl, 7, 1);
 
1008
}
 
1009
 
 
1010
/* Prepare a data transfer (either DMA or FIFO) */
 
1011
static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
 
1012
{
 
1013
    fdrive_t *cur_drv;
 
1014
    uint8_t kh, kt, ks;
 
1015
    int did_seek;
 
1016
 
 
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));
 
1025
    did_seek = 0;
 
1026
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
 
1027
    case 2:
 
1028
        /* sect too big */
 
1029
        fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
 
1030
        fdctrl->fifo[3] = kt;
 
1031
        fdctrl->fifo[4] = kh;
 
1032
        fdctrl->fifo[5] = ks;
 
1033
        return;
 
1034
    case 3:
 
1035
        /* track too big */
 
1036
        fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
 
1037
        fdctrl->fifo[3] = kt;
 
1038
        fdctrl->fifo[4] = kh;
 
1039
        fdctrl->fifo[5] = ks;
 
1040
        return;
 
1041
    case 4:
 
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;
 
1047
        return;
 
1048
    case 1:
 
1049
        did_seek = 1;
 
1050
        break;
 
1051
    default:
 
1052
        break;
 
1053
    }
 
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;
 
1060
    else
 
1061
        fdctrl->data_state &= ~FD_STATE_MULTI;
 
1062
    if (did_seek)
 
1063
        fdctrl->data_state |= FD_STATE_SEEK;
 
1064
    else
 
1065
        fdctrl->data_state &= ~FD_STATE_SEEK;
 
1066
    if (fdctrl->fifo[5] == 00) {
 
1067
        fdctrl->data_len = fdctrl->fifo[8];
 
1068
    } else {
 
1069
        int tmp;
 
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;
 
1075
    }
 
1076
    fdctrl->eot = fdctrl->fifo[6];
 
1077
    if (fdctrl->dma_en) {
 
1078
        int dma_mode;
 
1079
        /* DMA transfer are enabled. Check if DMA channel is well programmed */
 
1080
#ifndef VBOX
 
1081
        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
 
1082
#else
 
1083
        dma_mode = fdctrl->pDevIns->pDevHlp->pfnDMAGetChannelMode (
 
1084
            fdctrl->pDevIns,
 
1085
            fdctrl->dma_chann
 
1086
            );
 
1087
#endif
 
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
 
1100
             * recall us...
 
1101
             */
 
1102
#ifndef VBOX
 
1103
            DMA_hold_DREQ(fdctrl->dma_chann);
 
1104
            DMA_schedule(fdctrl->dma_chann);
 
1105
#else
 
1106
            fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
 
1107
                                                     fdctrl->dma_chann,
 
1108
                                                     1);
 
1109
            fdctrl->pDevIns->pDevHlp->pfnDMASchedule (fdctrl->pDevIns);
 
1110
#endif
 
1111
            return;
 
1112
        } else {
 
1113
            FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
 
1114
        }
 
1115
    }
 
1116
    FLOPPY_DPRINTF("start non-DMA transfer\n");
 
1117
    /* IO based transfer: calculate len */
 
1118
    fdctrl_raise_irq(fdctrl, 0x00);
 
1119
 
 
1120
    return;
 
1121
}
 
1122
 
 
1123
/* Prepare a transfer of deleted data */
 
1124
static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
 
1125
{
 
1126
    /* We don't handle deleted data,
 
1127
     * so we don't return *ANYTHING*
 
1128
     */
 
1129
    fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
 
1130
}
 
1131
 
 
1132
#if 0
 
1133
#include <stdio.h>
 
1134
#include <stdlib.h>
 
1135
 
 
1136
static FILE * f;
 
1137
static void dump (void *p, size_t len)
 
1138
{
 
1139
    size_t n;
 
1140
 
 
1141
    if (!f) {
 
1142
        f = fopen ("dump", "wb");
 
1143
        if (!f)
 
1144
            exit (0);
 
1145
    }
 
1146
 
 
1147
    n = fwrite (p, len, 1, f);
 
1148
    if (n != 1) {
 
1149
        AssertMsgFailed (("failed to dump\n"));
 
1150
        exit (0);
 
1151
    }
 
1152
}
 
1153
#else
 
1154
#define dump(a,b) do { } while (0)
 
1155
#endif
 
1156
 
 
1157
/* handlers for DMA transfers */
 
1158
#ifdef VBOX
 
1159
static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
 
1160
                                                       void *opaque,
 
1161
                                                       unsigned nchan,
 
1162
                                                       uint32_t dma_pos,
 
1163
                                                       uint32_t dma_len)
 
1164
#else
 
1165
static int fdctrl_transfer_handler (void *opaque, int nchan,
 
1166
                                    int dma_pos, int dma_len)
 
1167
#endif
 
1168
{
 
1169
    fdctrl_t *fdctrl;
 
1170
    fdrive_t *cur_drv;
 
1171
#ifdef VBOX
 
1172
    int rc;
 
1173
    uint32_t len, start_pos, rel_pos;
 
1174
#else
 
1175
    int len, start_pos, rel_pos;
 
1176
#endif
 
1177
    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
 
1178
 
 
1179
    fdctrl = opaque;
 
1180
    if (!(fdctrl->state & FD_CTRL_BUSY)) {
 
1181
        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
 
1182
        return 0;
 
1183
    }
 
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)
 
1187
        status2 = 0x04;
 
1188
    if (dma_len > fdctrl->data_len)
 
1189
        dma_len = fdctrl->data_len;
 
1190
#ifndef VBOX
 
1191
    if (cur_drv->bs == NULL) {
 
1192
#else  /* !VBOX */
 
1193
    if (cur_drv->pDrvBlock == NULL) {
 
1194
#endif
 
1195
        if (fdctrl->data_dir == FD_DIR_WRITE)
 
1196
            fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
 
1197
        else
 
1198
            fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
 
1199
        len = 0;
 
1200
        goto transfer_error;
 
1201
    }
 
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 */
 
1215
#ifndef VBOX
 
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);
 
1222
            }
 
1223
#else
 
1224
            cur_drv->Led.Asserted.s.fReading
 
1225
                = cur_drv->Led.Actual.s.fReading = 1;
 
1226
 
 
1227
            rc = cur_drv->pDrvBlock->pfnRead (
 
1228
                cur_drv->pDrvBlock,
 
1229
                fd_sector (cur_drv) * 512,
 
1230
                fdctrl->fifo,
 
1231
                1 * 512
 
1232
                );
 
1233
 
 
1234
            cur_drv->Led.Actual.s.fReading = 0;
 
1235
 
 
1236
            if (VBOX_FAILURE (rc)) {
 
1237
                AssertMsgFailed (
 
1238
                    ("Floppy: error getting sector %d, rc = %Vrc",
 
1239
                     fd_sector (cur_drv), rc));
 
1240
                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
 
1241
            }
 
1242
#endif
 
1243
        }
 
1244
        switch (fdctrl->data_dir) {
 
1245
        case FD_DIR_READ:
 
1246
            /* READ commands */
 
1247
#ifdef VBOX
 
1248
            {
 
1249
                uint32_t read;
 
1250
                int rc = fdctrl->pDevIns->pDevHlp->pfnDMAWriteMemory(
 
1251
                    fdctrl->pDevIns,
 
1252
                    nchan,
 
1253
                    fdctrl->fifo + rel_pos,
 
1254
                    fdctrl->data_pos,
 
1255
                    len,
 
1256
                    &read);
 
1257
                dump (fdctrl->fifo + rel_pos, len);
 
1258
                AssertMsgRC (rc,
 
1259
                             ("DMAWriteMemory -> %Vrc\n", rc));
 
1260
            }
 
1261
#else
 
1262
            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
 
1263
                              fdctrl->data_pos, len);
 
1264
#endif
 
1265
/*          cpu_physical_memory_write(addr + fdctrl->data_pos, */
 
1266
/*                                    fdctrl->fifo + rel_pos, len); */
 
1267
            break;
 
1268
        case FD_DIR_WRITE:
 
1269
            /* WRITE commands */
 
1270
#ifdef VBOX
 
1271
            {
 
1272
                uint32_t written;
 
1273
                int rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory(
 
1274
                    fdctrl->pDevIns,
 
1275
                    nchan,
 
1276
                    fdctrl->fifo + rel_pos,
 
1277
                    fdctrl->data_pos,
 
1278
                    len,
 
1279
                    &written);
 
1280
                AssertMsgRC (rc,
 
1281
                             ("DMAReadMemory -> %Vrc\n", rc));
 
1282
            }
 
1283
#else
 
1284
            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
 
1285
                             fdctrl->data_pos, len);
 
1286
#endif
 
1287
/*             cpu_physical_memory_read(addr + fdctrl->data_pos, */
 
1288
/*                                   fdctrl->fifo + rel_pos, len); */
 
1289
#ifndef VBOX
 
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;
 
1295
            }
 
1296
#else  /* VBOX */
 
1297
            cur_drv->Led.Asserted.s.fWriting
 
1298
                = cur_drv->Led.Actual.s.fWriting = 1;
 
1299
 
 
1300
            rc = cur_drv->pDrvBlock->pfnWrite (
 
1301
                cur_drv->pDrvBlock,
 
1302
                fd_sector (cur_drv) * 512,
 
1303
                fdctrl->fifo,
 
1304
                1 * 512
 
1305
                );
 
1306
 
 
1307
            cur_drv->Led.Actual.s.fWriting = 0;
 
1308
 
 
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;
 
1314
            }
 
1315
#endif
 
1316
            break;
 
1317
        default:
 
1318
            /* SCAN commands */
 
1319
            {
 
1320
                uint8_t tmpbuf[FD_SECTOR_LEN];
 
1321
                int ret;
 
1322
#ifdef VBOX
 
1323
                int rc;
 
1324
                uint32_t read;
 
1325
 
 
1326
                rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory (
 
1327
                    fdctrl->pDevIns,
 
1328
                    nchan,
 
1329
                    tmpbuf,
 
1330
                    fdctrl->data_pos,
 
1331
                    len,
 
1332
                    &read);
 
1333
                AssertMsg (VBOX_SUCCESS (rc),
 
1334
                           ("DMAReadMemory -> %Vrc\n", rc));
 
1335
#else
 
1336
                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
 
1337
#endif
 
1338
/*                 cpu_physical_memory_read(addr + fdctrl->data_pos, */
 
1339
/*                                          tmpbuf, len); */
 
1340
                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
 
1341
                if (ret == 0) {
 
1342
                    status2 = 0x08;
 
1343
                    goto end_transfer;
 
1344
                }
 
1345
                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
 
1346
                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
 
1347
                    status2 = 0x00;
 
1348
                    goto end_transfer;
 
1349
                }
 
1350
            }
 
1351
            break;
 
1352
        }
 
1353
        fdctrl->data_pos += len;
 
1354
        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
 
1355
        if (rel_pos == 0) {
 
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,
 
1359
                           fd_sector(cur_drv),
 
1360
                           fdctrl->data_pos - len);
 
1361
            /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
 
1362
               error in fact */
 
1363
            if (cur_drv->sect >= cur_drv->last_sect ||
 
1364
                cur_drv->sect == fdctrl->eot) {
 
1365
                cur_drv->sect = 1;
 
1366
                if (FD_MULTI_TRACK(fdctrl->data_state)) {
 
1367
                    if (cur_drv->head == 0 &&
 
1368
                        (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
 
1369
                        cur_drv->head = 1;
 
1370
                    } else {
 
1371
                        cur_drv->head = 0;
 
1372
                        cur_drv->track++;
 
1373
                        if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
 
1374
                            break;
 
1375
                    }
 
1376
                } else {
 
1377
                    cur_drv->track++;
 
1378
                    break;
 
1379
                }
 
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));
 
1383
            } else {
 
1384
                cur_drv->sect++;
 
1385
            }
 
1386
        }
 
1387
    }
 
1388
end_transfer:
 
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)
 
1395
        status2 = 0x08;
 
1396
    if (FD_DID_SEEK(fdctrl->data_state))
 
1397
        status0 |= 0x20;
 
1398
    fdctrl->data_len -= len;
 
1399
    /* if (fdctrl->data_len == 0) */
 
1400
    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
 
1401
transfer_error:
 
1402
 
 
1403
    return len;
 
1404
}
 
1405
 
 
1406
#if 0
 
1407
{
 
1408
    fdctrl_t *fdctrl;
 
1409
    fdrive_t *cur_drv;
 
1410
    int len, start_pos, rel_pos;
 
1411
    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
 
1412
 
 
1413
    fdctrl = opaque;
 
1414
    if (!(fdctrl->state & FD_CTRL_BUSY)) {
 
1415
        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
 
1416
        return 0;
 
1417
    }
 
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)
 
1421
        status2 = 0x04;
 
1422
    if (size > fdctrl->data_len)
 
1423
        size = fdctrl->data_len;
 
1424
#ifndef VBOX
 
1425
    if (cur_drv->bs == NULL) {
 
1426
#else
 
1427
    if (cur_drv->pDrvBase == NULL) {
 
1428
#endif
 
1429
        if (fdctrl->data_dir == FD_DIR_WRITE)
 
1430
            fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
 
1431
        else
 
1432
            fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
 
1433
        len = 0;
 
1434
        goto transfer_error;
 
1435
    }
 
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 */
 
1449
#ifndef VBOX
 
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);
 
1456
            }
 
1457
#else
 
1458
            int rc;
 
1459
 
 
1460
            cur_drv->Led.Asserted.s.fReading
 
1461
                = cur_drv->Led.Actual.s.fReading = 1;
 
1462
 
 
1463
            rc = cur_drv->pDrvBlock->pfnRead (
 
1464
                cur_drv->pDrvBlock,
 
1465
                fd_sector (cur_drv) * 512,
 
1466
                fdctrl->fifo,
 
1467
                1 * 512
 
1468
                );
 
1469
 
 
1470
            cur_drv->Led.Actual.s.fReading = 0;
 
1471
 
 
1472
            if (VBOX_FAILURE (rc)) {
 
1473
                AssertMsgFailed (
 
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);
 
1478
            }
 
1479
            /* *p_fd_activity = 1; */
 
1480
#endif
 
1481
        }
 
1482
        switch (fdctrl->data_dir) {
 
1483
        case FD_DIR_READ:
 
1484
            /* READ commands */
 
1485
#ifdef VBOX
 
1486
            fdctrl->pDevIns->pDevHlp->pfnPhysWrite (
 
1487
                fdctrl->pDevIns,
 
1488
                addr + fdctrl->data_pos,
 
1489
                fdctrl->fifo + rel_pos,
 
1490
                len);
 
1491
#else
 
1492
            cpu_physical_memory_write(addr + fdctrl->data_pos,
 
1493
                                      fdctrl->fifo + rel_pos, len);
 
1494
#endif
 
1495
            break;
 
1496
        case FD_DIR_WRITE:
 
1497
            /* WRITE commands */
 
1498
#ifdef VBOX
 
1499
            {
 
1500
                int rc;
 
1501
 
 
1502
                fdctrl->pDevIns->pDevHlp->pfnPhysRead (
 
1503
                    fdctrl->pDevIns,
 
1504
                    addr + fdctrl->data_pos,
 
1505
                    fdctrl->fifo + rel_pos,
 
1506
                    len);
 
1507
 
 
1508
                cur_drv->Led.Asserted.s.fWriting
 
1509
                    = cur_drv->Led.Actual.s.fWriting = 1;
 
1510
 
 
1511
                rc = cur_drv->pDrvBlock->pfnWrite (
 
1512
                    cur_drv->pDrvBlock,
 
1513
                    fd_sector (cur_drv) * 512,
 
1514
                    fdctrl->fifo,
 
1515
                    1 * 512
 
1516
                    );
 
1517
 
 
1518
                cur_drv->Led.Actual.s.fWriting = 0;
 
1519
 
 
1520
                if (VBOX_FAILURE (rc)) {
 
1521
                    AssertMsgFailed (
 
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;
 
1526
                }
 
1527
            }
 
1528
            /* *p_fd_activity = 2; */
 
1529
#else  /* !VBOX */
 
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;
 
1537
            }
 
1538
#endif
 
1539
            break;
 
1540
        default:
 
1541
            /* SCAN commands */
 
1542
            {
 
1543
                uint8_t tmpbuf[FD_SECTOR_LEN];
 
1544
                int ret;
 
1545
#ifdef VBOX
 
1546
                fdctrl->pDevIns->pDevHlp->pfnPhysRead (
 
1547
                    fdctrl->pDevIns,
 
1548
                    addr + fdctrl->data_pos,
 
1549
                    tmpbuf,
 
1550
                    len);
 
1551
#else
 
1552
                cpu_physical_memory_read(addr + fdctrl->data_pos,
 
1553
                                         tmpbuf, len);
 
1554
#endif
 
1555
                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
 
1556
                if (ret == 0) {
 
1557
                    status2 = 0x08;
 
1558
                    goto end_transfer;
 
1559
                }
 
1560
                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
 
1561
                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
 
1562
                    status2 = 0x00;
 
1563
                    goto end_transfer;
 
1564
                }
 
1565
            }
 
1566
            break;
 
1567
        }
 
1568
        fdctrl->data_pos += len;
 
1569
        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
 
1570
        if (rel_pos == 0) {
 
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,
 
1574
                           fd_sector(cur_drv),
 
1575
                           fdctrl->data_pos - size);
 
1576
            /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
 
1577
               error in fact */
 
1578
            if (cur_drv->sect >= cur_drv->last_sect ||
 
1579
                cur_drv->sect == fdctrl->eot) {
 
1580
                cur_drv->sect = 1;
 
1581
                if (FD_MULTI_TRACK(fdctrl->data_state)) {
 
1582
                    if (cur_drv->head == 0 &&
 
1583
                        (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
 
1584
                        cur_drv->head = 1;
 
1585
                    } else {
 
1586
                        cur_drv->head = 0;
 
1587
                        cur_drv->track++;
 
1588
                        if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
 
1589
                            break;
 
1590
                    }
 
1591
                } else {
 
1592
                    cur_drv->track++;
 
1593
                    break;
 
1594
                }
 
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));
 
1598
            } else {
 
1599
                cur_drv->sect++;
 
1600
            }
 
1601
        }
 
1602
    }
 
1603
end_transfer:
 
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)
 
1610
        status2 = 0x08;
 
1611
    if (FD_DID_SEEK(fdctrl->data_state))
 
1612
        status0 |= 0x20;
 
1613
    fdctrl->data_len -= len;
 
1614
    /* //    if (fdctrl->data_len == 0) */
 
1615
    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
 
1616
transfer_error:
 
1617
 
 
1618
    return len;
 
1619
}
 
1620
#endif
 
1621
 
 
1622
/* Data register : 0x05 */
 
1623
static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
 
1624
{
 
1625
    fdrive_t *cur_drv;
 
1626
    uint32_t retval = 0;
 
1627
    int pos, len;
 
1628
#ifdef VBOX
 
1629
    int rc;
 
1630
#endif
 
1631
 
 
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");
 
1636
        return 0;
 
1637
    }
 
1638
    pos = fdctrl->data_pos;
 
1639
    if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
 
1640
        pos %= FD_SECTOR_LEN;
 
1641
        if (pos == 0) {
 
1642
            len = fdctrl->data_len - fdctrl->data_pos;
 
1643
            if (len > FD_SECTOR_LEN)
 
1644
                len = FD_SECTOR_LEN;
 
1645
#ifdef VBOX
 
1646
            cur_drv->Led.Asserted.s.fReading
 
1647
                = cur_drv->Led.Actual.s.fReading = 1;
 
1648
 
 
1649
            rc = cur_drv->pDrvBlock->pfnRead (
 
1650
                cur_drv->pDrvBlock,
 
1651
                fd_sector (cur_drv) * 512,
 
1652
                fdctrl->fifo,
 
1653
                len * 512
 
1654
                );
 
1655
 
 
1656
            cur_drv->Led.Actual.s.fReading = 0;
 
1657
 
 
1658
            if (VBOX_FAILURE (rc)) {
 
1659
                AssertMsgFailed (
 
1660
                    ("Floppy: Failure to read sector %d. rc=%Vrc",
 
1661
                     fd_sector (cur_drv), rc));
 
1662
            }
 
1663
#else
 
1664
            bdrv_read(cur_drv->bs, fd_sector(cur_drv),
 
1665
                      fdctrl->fifo, len);
 
1666
#endif
 
1667
        }
 
1668
    }
 
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
 
1674
         */
 
1675
        if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
 
1676
            fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
 
1677
        } else {
 
1678
            fdctrl_reset_fifo(fdctrl);
 
1679
            fdctrl_reset_irq(fdctrl);
 
1680
        }
 
1681
    }
 
1682
    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
 
1683
 
 
1684
    return retval;
 
1685
}
 
1686
 
 
1687
static void fdctrl_format_sector (fdctrl_t *fdctrl)
 
1688
{
 
1689
    fdrive_t *cur_drv;
 
1690
    uint8_t kh, kt, ks;
 
1691
    int did_seek;
 
1692
#ifdef VBOX
 
1693
    int ok = 0, rc;
 
1694
#endif
 
1695
 
 
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));
 
1704
    did_seek = 0;
 
1705
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
 
1706
    case 2:
 
1707
        /* sect too big */
 
1708
        fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
 
1709
        fdctrl->fifo[3] = kt;
 
1710
        fdctrl->fifo[4] = kh;
 
1711
        fdctrl->fifo[5] = ks;
 
1712
        return;
 
1713
    case 3:
 
1714
        /* track too big */
 
1715
        fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
 
1716
        fdctrl->fifo[3] = kt;
 
1717
        fdctrl->fifo[4] = kh;
 
1718
        fdctrl->fifo[5] = ks;
 
1719
        return;
 
1720
    case 4:
 
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;
 
1726
        return;
 
1727
    case 1:
 
1728
        did_seek = 1;
 
1729
        fdctrl->data_state |= FD_STATE_SEEK;
 
1730
        break;
 
1731
    default:
 
1732
        break;
 
1733
    }
 
1734
    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
 
1735
#ifdef VBOX
 
1736
    /* *p_fd_activity = 2; */
 
1737
    if (cur_drv->pDrvBlock) {
 
1738
        cur_drv->Led.Asserted.s.fWriting = cur_drv->Led.Actual.s.fWriting = 1;
 
1739
 
 
1740
        rc = cur_drv->pDrvBlock->pfnWrite (
 
1741
            cur_drv->pDrvBlock,
 
1742
            fd_sector (cur_drv) * 512,
 
1743
            fdctrl->fifo,
 
1744
            1 * 512
 
1745
            );
 
1746
 
 
1747
        cur_drv->Led.Actual.s.fWriting = 0;
 
1748
 
 
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);
 
1753
        }
 
1754
        else {
 
1755
            ok = 1;
 
1756
        }
 
1757
    }
 
1758
    if (ok) {
 
1759
#else
 
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);
 
1764
    } else {
 
1765
#endif
 
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);
 
1771
            else
 
1772
                fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 
1773
        } else {
 
1774
            /* More to do */
 
1775
            fdctrl->data_pos = 0;
 
1776
            fdctrl->data_len = 4;
 
1777
        }
 
1778
    }
 
1779
}
 
1780
 
 
1781
static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
 
1782
{
 
1783
    fdrive_t *cur_drv;
 
1784
 
 
1785
    cur_drv = get_cur_drv(fdctrl);
 
1786
    /* Reset mode */
 
1787
    if (fdctrl->state & FD_CTRL_RESET) {
 
1788
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
 
1789
        return;
 
1790
    }
 
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");
 
1794
        return;
 
1795
    }
 
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) {
 
1802
#ifdef VBOX
 
1803
            int rc;
 
1804
            /* *p_fd_activity = 2; */
 
1805
            cur_drv->Led.Asserted.s.fWriting
 
1806
                = cur_drv->Led.Actual.s.fWriting = 1;
 
1807
 
 
1808
            rc = cur_drv->pDrvBlock->pfnWrite (
 
1809
                cur_drv->pDrvBlock,
 
1810
                fd_sector (cur_drv) * 512,
 
1811
                fdctrl->fifo,
 
1812
                FD_SECTOR_LEN * 512
 
1813
                );
 
1814
 
 
1815
            cur_drv->Led.Actual.s.fWriting = 0;
 
1816
 
 
1817
            if (VBOX_FAILURE (rc)) {
 
1818
                AssertMsgFailed (
 
1819
                    ("Floppy: failed to write sector %d. rc=%Vrc\n",
 
1820
                     fd_sector (cur_drv), rc));
 
1821
            }
 
1822
#else
 
1823
            bdrv_write(cur_drv->bs, fd_sector(cur_drv),
 
1824
                       fdctrl->fifo, FD_SECTOR_LEN);
 
1825
#endif
 
1826
        }
 
1827
        /* Switch from transfer mode to status mode
 
1828
         * then from status mode to command mode
 
1829
         */
 
1830
        if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
 
1831
            fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
 
1832
        return;
 
1833
    }
 
1834
    if (fdctrl->data_pos == 0) {
 
1835
        /* Command */
 
1836
        switch (value & 0x5F) {
 
1837
        case 0x46:
 
1838
            /* READ variants */
 
1839
            FLOPPY_DPRINTF("READ command\n");
 
1840
            /* 8 parameters cmd */
 
1841
            fdctrl->data_len = 9;
 
1842
            goto enqueue;
 
1843
        case 0x4C:
 
1844
            /* READ_DELETED variants */
 
1845
            FLOPPY_DPRINTF("READ_DELETED command\n");
 
1846
            /* 8 parameters cmd */
 
1847
            fdctrl->data_len = 9;
 
1848
            goto enqueue;
 
1849
        case 0x50:
 
1850
            /* SCAN_EQUAL variants */
 
1851
            FLOPPY_DPRINTF("SCAN_EQUAL command\n");
 
1852
            /* 8 parameters cmd */
 
1853
            fdctrl->data_len = 9;
 
1854
            goto enqueue;
 
1855
        case 0x56:
 
1856
            /* VERIFY variants */
 
1857
            FLOPPY_DPRINTF("VERIFY command\n");
 
1858
            /* 8 parameters cmd */
 
1859
            fdctrl->data_len = 9;
 
1860
            goto enqueue;
 
1861
        case 0x59:
 
1862
            /* SCAN_LOW_OR_EQUAL variants */
 
1863
            FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
 
1864
            /* 8 parameters cmd */
 
1865
            fdctrl->data_len = 9;
 
1866
            goto enqueue;
 
1867
        case 0x5D:
 
1868
            /* SCAN_HIGH_OR_EQUAL variants */
 
1869
            FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
 
1870
            /* 8 parameters cmd */
 
1871
            fdctrl->data_len = 9;
 
1872
            goto enqueue;
 
1873
        default:
 
1874
            break;
 
1875
        }
 
1876
        switch (value & 0x7F) {
 
1877
        case 0x45:
 
1878
            /* WRITE variants */
 
1879
            FLOPPY_DPRINTF("WRITE command\n");
 
1880
            /* 8 parameters cmd */
 
1881
            fdctrl->data_len = 9;
 
1882
            goto enqueue;
 
1883
        case 0x49:
 
1884
            /* WRITE_DELETED variants */
 
1885
            FLOPPY_DPRINTF("WRITE_DELETED command\n");
 
1886
            /* 8 parameters cmd */
 
1887
            fdctrl->data_len = 9;
 
1888
            goto enqueue;
 
1889
        default:
 
1890
            break;
 
1891
        }
 
1892
        switch (value) {
 
1893
        case 0x03:
 
1894
            /* SPECIFY */
 
1895
            FLOPPY_DPRINTF("SPECIFY command\n");
 
1896
            /* 1 parameter cmd */
 
1897
            fdctrl->data_len = 3;
 
1898
            goto enqueue;
 
1899
        case 0x04:
 
1900
            /* SENSE_DRIVE_STATUS */
 
1901
            FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
 
1902
            /* 1 parameter cmd */
 
1903
            fdctrl->data_len = 2;
 
1904
            goto enqueue;
 
1905
        case 0x07:
 
1906
            /* RECALIBRATE */
 
1907
            FLOPPY_DPRINTF("RECALIBRATE command\n");
 
1908
            /* 1 parameter cmd */
 
1909
            fdctrl->data_len = 2;
 
1910
            goto enqueue;
 
1911
        case 0x08:
 
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 */
 
1916
#if 0
 
1917
            fdctrl->fifo[0] =
 
1918
                fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
 
1919
#else
 
1920
            /* XXX: int_status handling is broken for read/write
 
1921
               commands, so we do this hack. It should be suppressed
 
1922
               ASAP */
 
1923
            fdctrl->fifo[0] =
 
1924
                0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
 
1925
#endif
 
1926
            fdctrl->fifo[1] = cur_drv->track;
 
1927
            fdctrl_set_fifo(fdctrl, 2, 0);
 
1928
            fdctrl_reset_irq(fdctrl);
 
1929
            fdctrl->int_status = 0xC0;
 
1930
            return;
 
1931
        case 0x0E:
 
1932
            /* DUMPREG */
 
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;
 
1939
            /* timers */
 
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);
 
1948
            return;
 
1949
        case 0x0F:
 
1950
            /* SEEK */
 
1951
            FLOPPY_DPRINTF("SEEK command\n");
 
1952
            /* 2 parameters cmd */
 
1953
            fdctrl->data_len = 3;
 
1954
            goto enqueue;
 
1955
        case 0x10:
 
1956
            /* VERSION */
 
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);
 
1962
            return;
 
1963
        case 0x12:
 
1964
            /* PERPENDICULAR_MODE */
 
1965
            FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
 
1966
            /* 1 parameter cmd */
 
1967
            fdctrl->data_len = 2;
 
1968
            goto enqueue;
 
1969
        case 0x13:
 
1970
            /* CONFIGURE */
 
1971
            FLOPPY_DPRINTF("CONFIGURE command\n");
 
1972
            /* 3 parameters cmd */
 
1973
            fdctrl->data_len = 4;
 
1974
            goto enqueue;
 
1975
        case 0x14:
 
1976
            /* UNLOCK */
 
1977
            FLOPPY_DPRINTF("UNLOCK command\n");
 
1978
            /* No parameters cmd */
 
1979
            fdctrl->lock = 0;
 
1980
            fdctrl->fifo[0] = 0;
 
1981
            fdctrl_set_fifo(fdctrl, 1, 0);
 
1982
            return;
 
1983
        case 0x17:
 
1984
            /* POWERDOWN_MODE */
 
1985
            FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
 
1986
            /* 2 parameters cmd */
 
1987
            fdctrl->data_len = 3;
 
1988
            goto enqueue;
 
1989
        case 0x18:
 
1990
            /* PART_ID */
 
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);
 
1995
            return;
 
1996
        case 0x2C:
 
1997
            /* SAVE */
 
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;
 
2007
            /* timers */
 
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);
 
2019
            return;
 
2020
        case 0x33:
 
2021
            /* OPTION */
 
2022
            FLOPPY_DPRINTF("OPTION command\n");
 
2023
            /* 1 parameter cmd */
 
2024
            fdctrl->data_len = 2;
 
2025
            goto enqueue;
 
2026
        case 0x42:
 
2027
            /* READ_TRACK */
 
2028
            FLOPPY_DPRINTF("READ_TRACK command\n");
 
2029
            /* 8 parameters cmd */
 
2030
            fdctrl->data_len = 9;
 
2031
            goto enqueue;
 
2032
        case 0x4A:
 
2033
            /* READ_ID */
 
2034
            FLOPPY_DPRINTF("READ_ID command\n");
 
2035
            /* 1 parameter cmd */
 
2036
            fdctrl->data_len = 2;
 
2037
            goto enqueue;
 
2038
        case 0x4C:
 
2039
            /* RESTORE */
 
2040
            FLOPPY_DPRINTF("RESTORE command\n");
 
2041
            /* 17 parameters cmd */
 
2042
            fdctrl->data_len = 18;
 
2043
            goto enqueue;
 
2044
        case 0x4D:
 
2045
            /* FORMAT_TRACK */
 
2046
            FLOPPY_DPRINTF("FORMAT_TRACK command\n");
 
2047
            /* 5 parameters cmd */
 
2048
            fdctrl->data_len = 6;
 
2049
            goto enqueue;
 
2050
        case 0x8E:
 
2051
            /* DRIVE_SPECIFICATION_COMMAND */
 
2052
            FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
 
2053
            /* 5 parameters cmd */
 
2054
            fdctrl->data_len = 6;
 
2055
            goto enqueue;
 
2056
        case 0x8F:
 
2057
            /* RELATIVE_SEEK_OUT */
 
2058
            FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
 
2059
            /* 2 parameters cmd */
 
2060
            fdctrl->data_len = 3;
 
2061
            goto enqueue;
 
2062
        case 0x94:
 
2063
            /* LOCK */
 
2064
            FLOPPY_DPRINTF("LOCK command\n");
 
2065
            /* No parameters cmd */
 
2066
            fdctrl->lock = 1;
 
2067
            fdctrl->fifo[0] = 0x10;
 
2068
            fdctrl_set_fifo(fdctrl, 1, 1);
 
2069
            return;
 
2070
        case 0xCD:
 
2071
            /* FORMAT_AND_WRITE */
 
2072
            FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
 
2073
            /* 10 parameters cmd */
 
2074
            fdctrl->data_len = 11;
 
2075
            goto enqueue;
 
2076
        case 0xCF:
 
2077
            /* RELATIVE_SEEK_IN */
 
2078
            FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
 
2079
            /* 2 parameters cmd */
 
2080
            fdctrl->data_len = 3;
 
2081
            goto enqueue;
 
2082
        default:
 
2083
            /* Unknown command */
 
2084
            FLOPPY_ERROR("unknown command: 0x%02x\n", value);
 
2085
            fdctrl_unimplemented(fdctrl);
 
2086
            return;
 
2087
        }
 
2088
    }
 
2089
enqueue:
 
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
 
2095
         */
 
2096
        if (fdctrl->data_state & FD_STATE_FORMAT) {
 
2097
            fdctrl_format_sector(fdctrl);
 
2098
            return;
 
2099
        }
 
2100
        switch (fdctrl->fifo[0] & 0x1F) {
 
2101
        case 0x06:
 
2102
        {
 
2103
            /* READ variants */
 
2104
            FLOPPY_DPRINTF("treat READ command\n");
 
2105
            fdctrl_start_transfer(fdctrl, FD_DIR_READ);
 
2106
            return;
 
2107
        }
 
2108
        case 0x0C:
 
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);
 
2113
            return;
 
2114
        case 0x16:
 
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);
 
2119
            return;
 
2120
        case 0x10:
 
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);
 
2125
            return;
 
2126
        case 0x19:
 
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);
 
2131
            return;
 
2132
        case 0x1D:
 
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);
 
2137
            return;
 
2138
        default:
 
2139
            break;
 
2140
        }
 
2141
        switch (fdctrl->fifo[0] & 0x3F) {
 
2142
        case 0x05:
 
2143
            /* WRITE variants */
 
2144
            FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
 
2145
            fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
 
2146
            return;
 
2147
        case 0x09:
 
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);
 
2152
            return;
 
2153
        default:
 
2154
            break;
 
2155
        }
 
2156
        switch (fdctrl->fifo[0]) {
 
2157
        case 0x03:
 
2158
            /* SPECIFY */
 
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);
 
2165
            break;
 
2166
        case 0x04:
 
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) |
 
2176
                fdctrl->cur_drv |
 
2177
                0x28;
 
2178
            fdctrl_set_fifo(fdctrl, 1, 0);
 
2179
            break;
 
2180
        case 0x07:
 
2181
            /* RECALIBRATE */
 
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);
 
2189
            break;
 
2190
        case 0x0F:
 
2191
            /* SEEK */
 
2192
            FLOPPY_DPRINTF("treat SEEK command\n");
 
2193
            fdctrl->cur_drv = fdctrl->fifo[1] & 1;
 
2194
            cur_drv = get_cur_drv(fdctrl);
 
2195
            fd_start(cur_drv);
 
2196
            if (fdctrl->fifo[2] <= cur_drv->track)
 
2197
                cur_drv->dir = 1;
 
2198
            else
 
2199
                cur_drv->dir = 0;
 
2200
            fdctrl_reset_fifo(fdctrl);
 
2201
#ifndef VBOX
 
2202
            if (fdctrl->fifo[2] > cur_drv->max_track) {
 
2203
#else
 
2204
            if (    fdctrl->fifo[2] > cur_drv->max_track
 
2205
                &&  cur_drv->fMediaPresent) {
 
2206
#endif
 
2207
                fdctrl_raise_irq(fdctrl, 0x60);
 
2208
            } else {
 
2209
                cur_drv->track = fdctrl->fifo[2];
 
2210
                /* Raise Interrupt */
 
2211
                fdctrl_raise_irq(fdctrl, 0x20);
 
2212
            }
 
2213
            break;
 
2214
        case 0x12:
 
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);
 
2221
            break;
 
2222
        case 0x13:
 
2223
            /* CONFIGURE */
 
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);
 
2229
            break;
 
2230
        case 0x17:
 
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);
 
2236
            break;
 
2237
        case 0x33:
 
2238
            /* OPTION */
 
2239
            FLOPPY_DPRINTF("treat OPTION command\n");
 
2240
            /* No result back */
 
2241
            fdctrl_reset_fifo(fdctrl);
 
2242
            break;
 
2243
        case 0x42:
 
2244
            /* READ_TRACK */
 
2245
/* //            FLOPPY_DPRINTF("treat READ_TRACK command\n"); */
 
2246
            FLOPPY_ERROR("treat READ_TRACK command\n");
 
2247
            fdctrl_start_transfer(fdctrl, FD_DIR_READ);
 
2248
            break;
 
2249
        case 0x4A:
 
2250
                /* READ_ID */
 
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;
 
2254
#ifdef VBOX
 
2255
            TMTimerSetMillies(fdctrl->result_timer, 1000 / 50);
 
2256
#else
 
2257
            qemu_mod_timer(fdctrl->result_timer,
 
2258
                           qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
 
2259
#endif
 
2260
            break;
 
2261
        case 0x4C:
 
2262
            /* RESTORE */
 
2263
            FLOPPY_DPRINTF("treat RESTORE command\n");
 
2264
            /* Drives position */
 
2265
            drv0(fdctrl)->track = fdctrl->fifo[3];
 
2266
            drv1(fdctrl)->track = fdctrl->fifo[4];
 
2267
            /* timers */
 
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);
 
2277
            break;
 
2278
        case 0x4D:
 
2279
            /* FORMAT_TRACK */
 
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;
 
2286
            else
 
2287
                fdctrl->data_state &= ~FD_STATE_MULTI;
 
2288
            fdctrl->data_state &= ~FD_STATE_SEEK;
 
2289
            cur_drv->bps =
 
2290
                fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
 
2291
#if 0
 
2292
            cur_drv->last_sect =
 
2293
                cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
 
2294
                fdctrl->fifo[3] / 2;
 
2295
#else
 
2296
            cur_drv->last_sect = fdctrl->fifo[3];
 
2297
#endif
 
2298
            /* Bochs BIOS is buggy and don't send format informations
 
2299
             * for each sector. So, pretend all's done right now...
 
2300
             */
 
2301
            fdctrl->data_state &= ~FD_STATE_FORMAT;
 
2302
            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 
2303
            break;
 
2304
        case 0x8E:
 
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);
 
2314
                } else {
 
2315
                    fdctrl_reset_fifo(fdctrl);
 
2316
                }
 
2317
            } else if (fdctrl->data_len > 7) {
 
2318
                /* ERROR */
 
2319
                fdctrl->fifo[0] = 0x80 |
 
2320
                    (cur_drv->head << 2) | fdctrl->cur_drv;
 
2321
                fdctrl_set_fifo(fdctrl, 1, 1);
 
2322
            }
 
2323
            break;
 
2324
        case 0x8F:
 
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);
 
2329
            fd_start(cur_drv);
 
2330
                cur_drv->dir = 0;
 
2331
            if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
 
2332
                cur_drv->track = cur_drv->max_track - 1;
 
2333
            } else {
 
2334
                cur_drv->track += fdctrl->fifo[2];
 
2335
            }
 
2336
            fdctrl_reset_fifo(fdctrl);
 
2337
            fdctrl_raise_irq(fdctrl, 0x20);
 
2338
            break;
 
2339
        case 0xCD:
 
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);
 
2344
            break;
 
2345
        case 0xCF:
 
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);
 
2350
            fd_start(cur_drv);
 
2351
                cur_drv->dir = 1;
 
2352
            if (fdctrl->fifo[2] > cur_drv->track) {
 
2353
                cur_drv->track = 0;
 
2354
            } else {
 
2355
                cur_drv->track -= fdctrl->fifo[2];
 
2356
            }
 
2357
            fdctrl_reset_fifo(fdctrl);
 
2358
            /* Raise Interrupt */
 
2359
            fdctrl_raise_irq(fdctrl, 0x20);
 
2360
            break;
 
2361
        }
 
2362
    }
 
2363
}
 
2364
 
 
2365
static void fdctrl_result_timer(void *opaque)
 
2366
{
 
2367
    fdctrl_t *fdctrl = opaque;
 
2368
    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 
2369
}
 
2370
 
 
2371
 
 
2372
#ifdef VBOX
 
2373
static DECLCALLBACK(void) fdc_timer (PPDMDEVINS pDevIns, PTMTIMER pTimer)
 
2374
{
 
2375
    fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2376
    fdctrl_result_timer (fdctrl);
 
2377
}
 
2378
 
 
2379
static DECLCALLBACK(int) fdc_io_write (PPDMDEVINS pDevIns,
 
2380
                                       void *pvUser,
 
2381
                                       RTIOPORT Port,
 
2382
                                       uint32_t u32,
 
2383
                                       unsigned cb)
 
2384
{
 
2385
    if (cb == 1) {
 
2386
        fdctrl_write (pvUser, Port, u32);
 
2387
    }
 
2388
    else {
 
2389
        AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
 
2390
    }
 
2391
    return VINF_SUCCESS;
 
2392
}
 
2393
 
 
2394
static DECLCALLBACK(int) fdc_io_read (PPDMDEVINS pDevIns,
 
2395
                                      void *pvUser,
 
2396
                                      RTIOPORT Port,
 
2397
                                      uint32_t *pu32,
 
2398
                                      unsigned cb)
 
2399
{
 
2400
    if (cb == 1) {
 
2401
        *pu32 = fdctrl_read (pvUser, Port);
 
2402
        return VINF_SUCCESS;
 
2403
    }
 
2404
    else {
 
2405
        return VERR_IOM_IOPORT_UNUSED;
 
2406
    }
 
2407
}
 
2408
 
 
2409
static DECLCALLBACK(int) SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
 
2410
{
 
2411
    fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2412
    QEMUFile *f = pSSMHandle;
 
2413
    unsigned int i;
 
2414
 
 
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);
 
2436
 
 
2437
    for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
 
2438
        fdrive_t *d = &s->drives[i];
 
2439
 
 
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);
 
2454
    }
 
2455
    return TMR3TimerSave (s->result_timer, pSSMHandle);
 
2456
}
 
2457
 
 
2458
static DECLCALLBACK(int) LoadExec (PPDMDEVINS pDevIns,
 
2459
                                   PSSMHANDLE pSSMHandle,
 
2460
                                   uint32_t u32Version)
 
2461
{
 
2462
    fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2463
    QEMUFile *f = pSSMHandle;
 
2464
    unsigned int i;
 
2465
 
 
2466
    if (u32Version != 1) {
 
2467
        AssertMsgFailed(("u32Version=%d\n", u32Version));
 
2468
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
2469
    }
 
2470
 
 
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);
 
2492
 
 
2493
    for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
 
2494
        fdrive_t *d = &s->drives[i];
 
2495
 
 
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);
 
2510
    }
 
2511
    return TMR3TimerLoad (s->result_timer, pSSMHandle);
 
2512
}
 
2513
 
 
2514
/**
 
2515
 * Queries an interface to the driver.
 
2516
 *
 
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.
 
2521
 */
 
2522
static DECLCALLBACK(void *) fdQueryInterface (PPDMIBASE pInterface,
 
2523
                                              PDMINTERFACE enmInterface)
 
2524
{
 
2525
    fdrive_t *drv = PDMIBASE_2_FDRIVE(pInterface);
 
2526
    switch (enmInterface) {
 
2527
    case PDMINTERFACE_BASE:
 
2528
        return &drv->IBase;
 
2529
    case PDMINTERFACE_BLOCK_PORT:
 
2530
        return &drv->IPort;
 
2531
    case PDMINTERFACE_MOUNT_NOTIFY:
 
2532
        return &drv->IMountNotify;
 
2533
    default:
 
2534
        return NULL;
 
2535
    }
 
2536
}
 
2537
 
 
2538
/**
 
2539
 * Gets the pointer to the status LED of a unit.
 
2540
 *
 
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.
 
2545
 */
 
2546
static DECLCALLBACK(int) fdcStatusQueryStatusLed (PPDMILEDPORTS pInterface,
 
2547
                                                  unsigned iLUN,
 
2548
                                                  PPDMLED *ppLed)
 
2549
{
 
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;
 
2556
    }
 
2557
    return VERR_PDM_LUN_NOT_FOUND;
 
2558
}
 
2559
 
 
2560
 
 
2561
/**
 
2562
 * Queries an interface to the status LUN.
 
2563
 *
 
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.
 
2568
 */
 
2569
static DECLCALLBACK(void *) fdcStatusQueryInterface (PPDMIBASE pInterface,
 
2570
                                                     PDMINTERFACE enmInterface)
 
2571
{
 
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;
 
2579
    default:
 
2580
        return NULL;
 
2581
    }
 
2582
}
 
2583
 
 
2584
 
 
2585
/**
 
2586
 * Configure a drive.
 
2587
 *
 
2588
 * @returns VBox status code.
 
2589
 * @param   drv         The drive in question.
 
2590
 * @param   pDevIns     The driver instance.
 
2591
 */
 
2592
static int fdConfig (fdrive_t *drv, PPDMDEVINS pDevIns)
 
2593
{
 
2594
    static const char *descs[] = {"Floppy Drive A:", "Floppy Drive B"};
 
2595
    int rc;
 
2596
 
 
2597
    /*
 
2598
     * Reset the LED just to be on the safe side.
 
2599
     */
 
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;
 
2604
 
 
2605
    /*
 
2606
     * Try attach the block device and get the interfaces.
 
2607
     */
 
2608
    rc = PDMDevHlpDriverAttach (pDevIns, drv->iLUN, &drv->IBase, &drv->pDrvBase, descs[drv->iLUN]);
 
2609
    if (VBOX_SUCCESS (rc))
 
2610
    {
 
2611
        drv->pDrvBlock = drv->pDrvBase->pfnQueryInterface (
 
2612
            drv->pDrvBase,
 
2613
            PDMINTERFACE_BLOCK
 
2614
            );
 
2615
        if (drv->pDrvBlock) {
 
2616
            drv->pDrvBlockBios = drv->pDrvBase->pfnQueryInterface (
 
2617
                drv->pDrvBase,
 
2618
                PDMINTERFACE_BLOCK_BIOS
 
2619
                );
 
2620
            if (drv->pDrvBlockBios) {
 
2621
                drv->pDrvMount = drv->pDrvBase->pfnQueryInterface (
 
2622
                    drv->pDrvBase,
 
2623
                    PDMINTERFACE_MOUNT
 
2624
                    );
 
2625
                if (drv->pDrvMount) {
 
2626
                    /*
 
2627
                     * Init the state.
 
2628
                     */
 
2629
                    drv->drive = FDRIVE_DRV_NONE;
 
2630
                    drv->drflags = 0;
 
2631
                    drv->perpendicular = 0;
 
2632
                    /* Disk */
 
2633
                    drv->last_sect = 0;
 
2634
                    drv->max_track = 0;
 
2635
                    drv->fMediaPresent = false;
 
2636
                }
 
2637
                else {
 
2638
                    AssertMsgFailed (("Configuration error: LUN#%d without mountable interface!\n", drv->iLUN));
 
2639
                    rc = VERR_PDM_MISSING_INTERFACE;
 
2640
                }
 
2641
 
 
2642
            }
 
2643
            else {
 
2644
                AssertMsgFailed (("Configuration error: LUN#%d hasn't a block BIOS interface!\n", drv->iLUN));
 
2645
                rc = VERR_PDM_MISSING_INTERFACE;
 
2646
            }
 
2647
 
 
2648
        }
 
2649
        else {
 
2650
            AssertMsgFailed (("Configuration error: LUN#%d hasn't a block interface!\n", drv->iLUN));
 
2651
            rc = VERR_PDM_MISSING_INTERFACE;
 
2652
        }
 
2653
    }
 
2654
    else {
 
2655
        AssertMsg (rc == VERR_PDM_NO_ATTACHED_DRIVER,
 
2656
                   ("Failed to attach LUN#%d. rc=%Vrc\n", drv->iLUN, rc));
 
2657
    }
 
2658
 
 
2659
    if (VBOX_FAILURE (rc)) {
 
2660
        drv->pDrvBase = NULL;
 
2661
        drv->pDrvBlock = NULL;
 
2662
        drv->pDrvBlockBios = NULL;
 
2663
        drv->pDrvMount = NULL;
 
2664
    }
 
2665
    LogFlow (("fdConfig: returns %Vrc\n", rc));
 
2666
    return rc;
 
2667
}
 
2668
 
 
2669
 
 
2670
/**
 
2671
 * Attach command.
 
2672
 *
 
2673
 * This is called when we change block driver for a floppy drive.
 
2674
 *
 
2675
 * @returns VBox status code.
 
2676
 * @param   pDevIns     The device instance.
 
2677
 * @param   iLUN        The logical unit which is being detached.
 
2678
 */
 
2679
static DECLCALLBACK(int)  fdcAttach (PPDMDEVINS pDevIns,
 
2680
                                     unsigned iLUN)
 
2681
{
 
2682
    fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2683
    fdrive_t *drv;
 
2684
    int rc;
 
2685
    LogFlow (("ideDetach: iLUN=%u\n", iLUN));
 
2686
 
 
2687
    /*
 
2688
     * Validate.
 
2689
     */
 
2690
    if (iLUN > 2) {
 
2691
        AssertMsgFailed (("Configuration error: cannot attach or detach any but the first two LUNs - iLUN=%u\n",
 
2692
                          iLUN));
 
2693
        return VERR_PDM_DEVINS_NO_ATTACH;
 
2694
    }
 
2695
 
 
2696
    /*
 
2697
     * Locate the drive and stuff.
 
2698
     */
 
2699
    drv = &fdctrl->drives[iLUN];
 
2700
 
 
2701
    /* the usual paranoia */
 
2702
    AssertRelease (!drv->pDrvBase);
 
2703
    AssertRelease (!drv->pDrvBlock);
 
2704
    AssertRelease (!drv->pDrvBlockBios);
 
2705
    AssertRelease (!drv->pDrvMount);
 
2706
 
 
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);
 
2712
    }
 
2713
 
 
2714
    LogFlow (("floppyAttach: returns %Vrc\n", rc));
 
2715
    return rc;
 
2716
}
 
2717
 
 
2718
 
 
2719
/**
 
2720
 * Detach notification.
 
2721
 *
 
2722
 * The floppy drive has been temporarily 'unplugged'.
 
2723
 *
 
2724
 * @param   pDevIns     The device instance.
 
2725
 * @param   iLUN        The logical unit which is being detached.
 
2726
 */
 
2727
static DECLCALLBACK(void) fdcDetach (PPDMDEVINS pDevIns,
 
2728
                                     unsigned iLUN)
 
2729
{
 
2730
    fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2731
    LogFlow (("ideDetach: iLUN=%u\n", iLUN));
 
2732
 
 
2733
    switch (iLUN) {
 
2734
    case 0:
 
2735
    case 1: {
 
2736
        fdrive_t *drv = &fdctrl->drives[iLUN];
 
2737
        drv->pDrvBase = NULL;
 
2738
        drv->pDrvBlock = NULL;
 
2739
        drv->pDrvBlockBios = NULL;
 
2740
        drv->pDrvMount = NULL;
 
2741
        break;
 
2742
    }
 
2743
 
 
2744
    default:
 
2745
        AssertMsgFailed (("Cannot detach LUN#%d!\n", iLUN));
 
2746
        break;
 
2747
    }
 
2748
}
 
2749
 
 
2750
 
 
2751
/**
 
2752
 * Handle reset.
 
2753
 *
 
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.
 
2757
 *
 
2758
 * @param   pDevIns     The device instance.
 
2759
 */
 
2760
static DECLCALLBACK(void) fdcReset (PPDMDEVINS pDevIns)
 
2761
{
 
2762
    fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
 
2763
    int i;
 
2764
    LogFlow (("fdcReset:\n"));
 
2765
 
 
2766
    fdctrl_reset(fdctrl, 0);
 
2767
    fdctrl->state = FD_CTRL_ACTIVE;
 
2768
 
 
2769
    for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
 
2770
        fd_revalidate(&fdctrl->drives[i]);
 
2771
    }
 
2772
}
 
2773
 
 
2774
 
 
2775
/**
 
2776
 * Construct a device instance for a VM.
 
2777
 *
 
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.
 
2787
 */
 
2788
static DECLCALLBACK(int) fdcConstruct (PPDMDEVINS pDevIns,
 
2789
                                       int iInstance,
 
2790
                                       PCFGMNODE pCfgHandle)
 
2791
{
 
2792
    int            rc;
 
2793
    fdctrl_t       *fdctrl = PDMINS2DATA(pDevIns, fdctrl_t*);
 
2794
    int            i;
 
2795
    bool           mem_mapped;
 
2796
    uint16_t       io_base;
 
2797
    uint8_t        irq_lvl, dma_chann;
 
2798
    PPDMIBASE      pBase;
 
2799
 
 
2800
    Assert(iInstance == 0);
 
2801
 
 
2802
    /*
 
2803
     * Validate configuration.
 
2804
     */
 
2805
    if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0DMA\0MemMapped\0IOBase\0")) {
 
2806
        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
 
2807
    }
 
2808
 
 
2809
    /*
 
2810
     * Read the configuration.
 
2811
     */
 
2812
    rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
 
2813
    if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
 
2814
        irq_lvl = 6;
 
2815
    }
 
2816
    else if (VBOX_FAILURE (rc)) {
 
2817
        AssertMsgFailed (("Configuration error: Failed to read U8 IRQ, rc=%Vrc\n", rc));
 
2818
        return rc;
 
2819
    }
 
2820
 
 
2821
    rc = CFGMR3QueryU8 (pCfgHandle, "DMA", &dma_chann);
 
2822
    if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
 
2823
        dma_chann = 2;
 
2824
    }
 
2825
    else if (VBOX_FAILURE (rc)) {
 
2826
        AssertMsgFailed (("Configuration error: Failed to read U8 DMA, rc=%Vrc\n", rc));
 
2827
        return rc;
 
2828
    }
 
2829
 
 
2830
    rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
 
2831
    if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
 
2832
        io_base = 0x3f0;
 
2833
    }
 
2834
    else if (VBOX_FAILURE (rc)) {
 
2835
        AssertMsgFailed (("Configuration error: Failed to read U16 IOBase, rc=%Vrc\n", rc));
 
2836
        return rc;
 
2837
    }
 
2838
 
 
2839
    rc = CFGMR3QueryBool (pCfgHandle, "MemMapped", &mem_mapped);
 
2840
    if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
 
2841
        mem_mapped = false;
 
2842
    }
 
2843
    else if (VBOX_FAILURE (rc)) {
 
2844
        AssertMsgFailed (("Configuration error: Failed to read bool value MemMapped rc=%Vrc\n", rc));
 
2845
        return rc;
 
2846
    }
 
2847
 
 
2848
    /*
 
2849
     * Initialize data.
 
2850
     */
 
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 */
 
2858
 
 
2859
    fdctrl->IBaseStatus.pfnQueryInterface = fdcStatusQueryInterface;
 
2860
    fdctrl->ILeds.pfnQueryStatusLed = fdcStatusQueryStatusLed;
 
2861
 
 
2862
    for (i = 0; i < ELEMENTS(fdctrl->drives); ++i) {
 
2863
        fdrive_t *drv = &fdctrl->drives[i];
 
2864
 
 
2865
        drv->drive = FDRIVE_DRV_NONE;
 
2866
        drv->iLUN = i;
 
2867
 
 
2868
        drv->IBase.pfnQueryInterface = fdQueryInterface;
 
2869
        drv->IMountNotify.pfnMountNotify = fdMountNotify;
 
2870
        drv->IMountNotify.pfnUnmountNotify = fdUnmountNotify;
 
2871
        drv->Led.u32Magic = PDMLED_MAGIC;
 
2872
    }
 
2873
 
 
2874
    /*
 
2875
     * Create the FDC timer.
 
2876
     */
 
2877
    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, fdc_timer, "FDC Timer", &fdctrl->result_timer);
 
2878
    if (VBOX_FAILURE (rc)) {
 
2879
        return rc;
 
2880
    }
 
2881
 
 
2882
    /*
 
2883
     * Register DMA channel.
 
2884
     */
 
2885
    if (fdctrl->dma_chann != 0xff) {
 
2886
        fdctrl->dma_en = 1;
 
2887
        rc = pDevIns->pDevHlp->pfnDMARegister (
 
2888
            pDevIns,
 
2889
            dma_chann,
 
2890
            &fdctrl_transfer_handler,
 
2891
            fdctrl);
 
2892
        if (VBOX_FAILURE (rc)) {
 
2893
            return rc;
 
2894
        }
 
2895
    } else {
 
2896
        fdctrl->dma_en = 0;
 
2897
    }
 
2898
 
 
2899
    /*
 
2900
     * IO / MMIO.
 
2901
     */
 
2902
    if (mem_mapped) {
 
2903
        AssertMsgFailed (("Memory mapped floppy not support by now\n"));
 
2904
        return VERR_NOT_SUPPORTED;
 
2905
#if 0
 
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);
 
2909
#endif
 
2910
    } else {
 
2911
        rc = pDevIns->pDevHlp->pfnIOPortRegister (
 
2912
            pDevIns,
 
2913
            io_base + 0x1,
 
2914
            5,
 
2915
            fdctrl,
 
2916
            fdc_io_write,
 
2917
            fdc_io_read,
 
2918
            NULL, NULL,
 
2919
            "FDC#1"
 
2920
            );
 
2921
        if (VBOX_FAILURE (rc)) {
 
2922
            return rc;
 
2923
        }
 
2924
 
 
2925
        rc = pDevIns->pDevHlp->pfnIOPortRegister (
 
2926
            pDevIns,
 
2927
            io_base + 0x7,
 
2928
            1,
 
2929
            fdctrl,
 
2930
            fdc_io_write,
 
2931
            fdc_io_read,
 
2932
            NULL, NULL,
 
2933
            "FDC#2"
 
2934
            );
 
2935
        if (VBOX_FAILURE (rc)) {
 
2936
            return rc;
 
2937
        }
 
2938
    }
 
2939
 
 
2940
    /*
 
2941
     * Register the saved state data unit.
 
2942
     */
 
2943
    rc = pDevIns->pDevHlp->pfnSSMRegister (
 
2944
        pDevIns,                /* pDevIns */
 
2945
        pDevIns->pDevReg->szDeviceName, /* pszName */
 
2946
        iInstance,              /* u32Instance */
 
2947
        1                       /* u32Version */,
 
2948
        sizeof (*fdctrl),       /* cbGuess */
 
2949
        NULL,                   /* pfnSavePrep */
 
2950
        SaveExec,               /* pfnSaveExec */
 
2951
        NULL,                   /* pfnSaveDone */
 
2952
        NULL,                   /* pfnLoadPrep */
 
2953
        LoadExec,               /* pfnLoadExec */
 
2954
        NULL                    /* pfnLoadDone */
 
2955
        );
 
2956
    if (VBOX_FAILURE(rc))
 
2957
        return rc;
 
2958
 
 
2959
    /*
 
2960
     * Attach the status port (optional).
 
2961
     */
 
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);
 
2966
    }
 
2967
    else if (rc != VERR_PDM_NO_ATTACHED_DRIVER) {
 
2968
        AssertMsgFailed (("Failed to attach to status driver. rc=%Vrc\n",
 
2969
                          rc));
 
2970
        return rc;
 
2971
    }
 
2972
 
 
2973
    /*
 
2974
     * Initialize drives.
 
2975
     */
 
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));
 
2982
            return rc;
 
2983
        }
 
2984
    }
 
2985
 
 
2986
    fdctrl_reset(fdctrl, 0);
 
2987
    fdctrl->state = FD_CTRL_ACTIVE;
 
2988
 
 
2989
    for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
 
2990
        fd_revalidate(&fdctrl->drives[i]);
 
2991
    }
 
2992
 
 
2993
    return VINF_SUCCESS;
 
2994
}
 
2995
 
 
2996
/**
 
2997
 * The device registration structure.
 
2998
 */
 
2999
const PDMDEVREG g_DeviceFloppyController =
 
3000
{
 
3001
    /* u32Version */
 
3002
    PDM_DEVREG_VERSION,
 
3003
    /* szDeviceName */
 
3004
    "i82078",
 
3005
    /* szGCMod */
 
3006
    "",
 
3007
    /* szR0Mod */
 
3008
    "",
 
3009
    /* pszDescription */
 
3010
    "Floppy drive controller (Intel 82078)",
 
3011
    /* fFlags */
 
3012
    PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
 
3013
    /* fClass */
 
3014
    PDM_DEVREG_CLASS_STORAGE,
 
3015
    /* cMaxInstances */
 
3016
    1,
 
3017
    /* cbInstance */
 
3018
    sizeof(fdctrl_t),
 
3019
    /* pfnConstruct */
 
3020
    fdcConstruct,
 
3021
    /* pfnDestruct */
 
3022
    NULL,
 
3023
    /* pfnRelocate */
 
3024
    NULL,
 
3025
    /* pfnIOCtl */
 
3026
    NULL,
 
3027
    /* pfnPowerOn */
 
3028
    NULL,
 
3029
    /* pfnReset */
 
3030
    fdcReset,
 
3031
    /* pfnSuspend */
 
3032
    NULL,
 
3033
    /* pfnResume */
 
3034
    NULL,
 
3035
    /* pfnAttach */
 
3036
    fdcAttach,
 
3037
    /* pfnDetach */
 
3038
    fdcDetach,
 
3039
    /* pfnQueryInterface. */
 
3040
    NULL
 
3041
};
 
3042
 
 
3043
#endif /* VBOX */
 
3044
 
 
3045
/*
 
3046
 * Local Variables:
 
3047
 *  mode: c
 
3048
 *  c-file-style: "k&r"
 
3049
 *  indent-tabs-mode: nil
 
3050
 * End:
 
3051
 */
 
3052