fdc.c 88.7 KB
Newer Older
B
bellard 已提交
1
/*
2
 * QEMU Floppy disk emulator (Intel 82078)
3
 *
4
 * Copyright (c) 2003, 2007 Jocelyn Mayer
5
 * Copyright (c) 2008 Hervé Poussineau
6
 *
B
bellard 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
B
bellard 已提交
25 26 27 28
/*
 * The controller is used in Sun4m systems in a slightly different
 * way. There are changes in DOR register and DMA is not available.
 */
B
Blue Swirl 已提交
29

P
Peter Maydell 已提交
30
#include "qemu/osdep.h"
P
Paolo Bonzini 已提交
31
#include "hw/block/fdc.h"
32
#include "qapi/error.h"
33 34
#include "qemu/error-report.h"
#include "qemu/timer.h"
M
Markus Armbruster 已提交
35
#include "hw/irq.h"
P
Paolo Bonzini 已提交
36
#include "hw/isa/isa.h"
37
#include "hw/qdev-properties.h"
38
#include "hw/sysbus.h"
39
#include "migration/vmstate.h"
40
#include "hw/block/block.h"
41
#include "sysemu/block-backend.h"
42 43
#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
44
#include "qemu/log.h"
45
#include "qemu/main-loop.h"
46
#include "qemu/module.h"
47
#include "trace.h"
B
bellard 已提交
48 49 50 51

/********************************************************/
/* debug Floppy devices */

52 53
#define DEBUG_FLOPPY 0

54
#define FLOPPY_DPRINTF(fmt, ...)                                \
55 56 57 58 59
    do {                                                        \
        if (DEBUG_FLOPPY) {                                     \
            fprintf(stderr, "FLOPPY: " fmt , ## __VA_ARGS__);   \
        }                                                       \
    } while (0)
B
bellard 已提交
60

K
Kevin Wolf 已提交
61 62 63 64 65 66 67 68

/********************************************************/
/* qdev floppy bus                                      */

#define TYPE_FLOPPY_BUS "floppy-bus"
#define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)

typedef struct FDCtrl FDCtrl;
K
Kevin Wolf 已提交
69 70
typedef struct FDrive FDrive;
static FDrive *get_drv(FDCtrl *fdctrl, int unit);
K
Kevin Wolf 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

typedef struct FloppyBus {
    BusState bus;
    FDCtrl *fdc;
} FloppyBus;

static const TypeInfo floppy_bus_info = {
    .name = TYPE_FLOPPY_BUS,
    .parent = TYPE_BUS,
    .instance_size = sizeof(FloppyBus),
};

static void floppy_bus_create(FDCtrl *fdc, FloppyBus *bus, DeviceState *dev)
{
    qbus_create_inplace(bus, sizeof(FloppyBus), TYPE_FLOPPY_BUS, dev, NULL);
    bus->fdc = fdc;
}


B
bellard 已提交
90 91 92
/********************************************************/
/* Floppy drive emulation                               */

93 94 95 96 97 98 99
typedef enum FDriveRate {
    FDRIVE_RATE_500K = 0x00,  /* 500 Kbps */
    FDRIVE_RATE_300K = 0x01,  /* 300 Kbps */
    FDRIVE_RATE_250K = 0x02,  /* 250 Kbps */
    FDRIVE_RATE_1M   = 0x03,  /*   1 Mbps */
} FDriveRate;

J
John Snow 已提交
100 101 102 103 104 105
typedef enum FDriveSize {
    FDRIVE_SIZE_UNKNOWN,
    FDRIVE_SIZE_350,
    FDRIVE_SIZE_525,
} FDriveSize;

106
typedef struct FDFormat {
J
John Snow 已提交
107
    FloppyDriveType drive;
108 109 110 111 112 113
    uint8_t last_sect;
    uint8_t max_track;
    uint8_t max_head;
    FDriveRate rate;
} FDFormat;

J
John Snow 已提交
114 115 116 117
/* In many cases, the total sector size of a format is enough to uniquely
 * identify it. However, there are some total sector collisions between
 * formats of different physical size, and these are noted below by
 * highlighting the total sector size for entries with collisions. */
118 119 120
static const FDFormat fd_formats[] = {
    /* First entry is default format */
    /* 1.44 MB 3"1/2 floppy disks */
J
John Snow 已提交
121 122
    { FLOPPY_DRIVE_TYPE_144, 18, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 2880 */
    { FLOPPY_DRIVE_TYPE_144, 20, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 3200 */
J
John Snow 已提交
123 124 125 126 127 128
    { FLOPPY_DRIVE_TYPE_144, 21, 80, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_144, 21, 82, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_144, 21, 83, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_144, 22, 80, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_144, 23, 80, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_144, 24, 80, 1, FDRIVE_RATE_500K, },
129
    /* 2.88 MB 3"1/2 floppy disks */
J
John Snow 已提交
130 131 132 133 134
    { FLOPPY_DRIVE_TYPE_288, 36, 80, 1, FDRIVE_RATE_1M, },
    { FLOPPY_DRIVE_TYPE_288, 39, 80, 1, FDRIVE_RATE_1M, },
    { FLOPPY_DRIVE_TYPE_288, 40, 80, 1, FDRIVE_RATE_1M, },
    { FLOPPY_DRIVE_TYPE_288, 44, 80, 1, FDRIVE_RATE_1M, },
    { FLOPPY_DRIVE_TYPE_288, 48, 80, 1, FDRIVE_RATE_1M, },
135
    /* 720 kB 3"1/2 floppy disks */
J
John Snow 已提交
136
    { FLOPPY_DRIVE_TYPE_144,  9, 80, 1, FDRIVE_RATE_250K, }, /* 3.5" 1440 */
J
John Snow 已提交
137 138 139 140 141
    { FLOPPY_DRIVE_TYPE_144, 10, 80, 1, FDRIVE_RATE_250K, },
    { FLOPPY_DRIVE_TYPE_144, 10, 82, 1, FDRIVE_RATE_250K, },
    { FLOPPY_DRIVE_TYPE_144, 10, 83, 1, FDRIVE_RATE_250K, },
    { FLOPPY_DRIVE_TYPE_144, 13, 80, 1, FDRIVE_RATE_250K, },
    { FLOPPY_DRIVE_TYPE_144, 14, 80, 1, FDRIVE_RATE_250K, },
142
    /* 1.2 MB 5"1/4 floppy disks */
J
John Snow 已提交
143
    { FLOPPY_DRIVE_TYPE_120, 15, 80, 1, FDRIVE_RATE_500K, },
J
John Snow 已提交
144
    { FLOPPY_DRIVE_TYPE_120, 18, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 2880 */
J
John Snow 已提交
145 146
    { FLOPPY_DRIVE_TYPE_120, 18, 82, 1, FDRIVE_RATE_500K, },
    { FLOPPY_DRIVE_TYPE_120, 18, 83, 1, FDRIVE_RATE_500K, },
J
John Snow 已提交
147
    { FLOPPY_DRIVE_TYPE_120, 20, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 3200 */
148
    /* 720 kB 5"1/4 floppy disks */
J
John Snow 已提交
149
    { FLOPPY_DRIVE_TYPE_120,  9, 80, 1, FDRIVE_RATE_250K, }, /* 5.25" 1440 */
J
John Snow 已提交
150
    { FLOPPY_DRIVE_TYPE_120, 11, 80, 1, FDRIVE_RATE_250K, },
151
    /* 360 kB 5"1/4 floppy disks */
J
John Snow 已提交
152
    { FLOPPY_DRIVE_TYPE_120,  9, 40, 1, FDRIVE_RATE_300K, }, /* 5.25" 720 */
J
John Snow 已提交
153 154 155
    { FLOPPY_DRIVE_TYPE_120,  9, 40, 0, FDRIVE_RATE_300K, },
    { FLOPPY_DRIVE_TYPE_120, 10, 41, 1, FDRIVE_RATE_300K, },
    { FLOPPY_DRIVE_TYPE_120, 10, 42, 1, FDRIVE_RATE_300K, },
156
    /* 320 kB 5"1/4 floppy disks */
J
John Snow 已提交
157 158
    { FLOPPY_DRIVE_TYPE_120,  8, 40, 1, FDRIVE_RATE_250K, },
    { FLOPPY_DRIVE_TYPE_120,  8, 40, 0, FDRIVE_RATE_250K, },
159
    /* 360 kB must match 5"1/4 better than 3"1/2... */
J
John Snow 已提交
160
    { FLOPPY_DRIVE_TYPE_144,  9, 80, 0, FDRIVE_RATE_250K, }, /* 3.5" 720 */
161
    /* end */
J
John Snow 已提交
162
    { FLOPPY_DRIVE_TYPE_NONE, -1, -1, 0, 0, },
163 164
};

J
John Snow 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177
static FDriveSize drive_size(FloppyDriveType drive)
{
    switch (drive) {
    case FLOPPY_DRIVE_TYPE_120:
        return FDRIVE_SIZE_525;
    case FLOPPY_DRIVE_TYPE_144:
    case FLOPPY_DRIVE_TYPE_288:
        return FDRIVE_SIZE_350;
    default:
        return FDRIVE_SIZE_UNKNOWN;
    }
}

B
blueswir1 已提交
178 179 180
#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))

B
bellard 已提交
181
/* Will always be a fixed parameter for us */
182 183 184
#define FD_SECTOR_LEN          512
#define FD_SECTOR_SC           2   /* Sector size code */
#define FD_RESET_SENSEI_COUNT  4   /* Number of sense interrupts on RESET */
B
bellard 已提交
185 186

/* Floppy disk drive emulation */
B
Blue Swirl 已提交
187
typedef enum FDiskFlags {
188
    FDISK_DBL_SIDES  = 0x01,
B
Blue Swirl 已提交
189
} FDiskFlags;
190

K
Kevin Wolf 已提交
191
struct FDrive {
192
    FDCtrl *fdctrl;
193
    BlockBackend *blk;
K
Kevin Wolf 已提交
194
    BlockConf *conf;
B
bellard 已提交
195
    /* Drive status */
J
John Snow 已提交
196
    FloppyDriveType drive;    /* CMOS drive type        */
B
bellard 已提交
197 198 199 200 201 202
    uint8_t perpendicular;    /* 2.88 MB access mode    */
    /* Position */
    uint8_t head;
    uint8_t track;
    uint8_t sect;
    /* Media */
J
John Snow 已提交
203
    FloppyDriveType disk;     /* Current disk type      */
B
Blue Swirl 已提交
204
    FDiskFlags flags;
B
bellard 已提交
205 206
    uint8_t last_sect;        /* Nb sector per track    */
    uint8_t max_track;        /* Nb of tracks           */
207
    uint16_t bps;             /* Bytes per sector       */
B
bellard 已提交
208
    uint8_t ro;               /* Is read-only           */
209
    uint8_t media_changed;    /* Is media changed       */
210
    uint8_t media_rate;       /* Data rate of medium    */
M
Max Reitz 已提交
211

J
John Snow 已提交
212
    bool media_validated;     /* Have we validated the media? */
K
Kevin Wolf 已提交
213
};
B
bellard 已提交
214

J
John Snow 已提交
215 216 217

static FloppyDriveType get_fallback_drive_type(FDrive *drv);

J
John Snow 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
/* Hack: FD_SEEK is expected to work on empty drives. However, QEMU
 * currently goes through some pains to keep seeks within the bounds
 * established by last_sect and max_track. Correcting this is difficult,
 * as refactoring FDC code tends to expose nasty bugs in the Linux kernel.
 *
 * For now: allow empty drives to have large bounds so we can seek around,
 * with the understanding that when a diskette is inserted, the bounds will
 * properly tighten to match the geometry of that inserted medium.
 */
static void fd_empty_seek_hack(FDrive *drv)
{
    drv->last_sect = 0xFF;
    drv->max_track = 0xFF;
}

B
Blue Swirl 已提交
233
static void fd_init(FDrive *drv)
B
bellard 已提交
234 235 236 237
{
    /* Drive */
    drv->perpendicular = 0;
    /* Disk */
J
John Snow 已提交
238
    drv->disk = FLOPPY_DRIVE_TYPE_NONE;
239
    drv->last_sect = 0;
B
bellard 已提交
240
    drv->max_track = 0;
J
John Snow 已提交
241 242
    drv->ro = true;
    drv->media_changed = 1;
B
bellard 已提交
243 244
}

245 246
#define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)

B
Blue Swirl 已提交
247
static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
248
                          uint8_t last_sect, uint8_t num_sides)
B
bellard 已提交
249
{
250
    return (((track * num_sides) + head) * last_sect) + sect - 1;
B
bellard 已提交
251 252 253
}

/* Returns current position, in sectors, for given drive */
B
Blue Swirl 已提交
254
static int fd_sector(FDrive *drv)
B
bellard 已提交
255
{
256 257
    return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect,
                          NUM_SIDES(drv));
B
bellard 已提交
258 259
}

260 261 262 263 264 265 266
/* Returns current position, in bytes, for given drive */
static int fd_offset(FDrive *drv)
{
    g_assert(fd_sector(drv) < INT_MAX >> BDRV_SECTOR_BITS);
    return fd_sector(drv) << BDRV_SECTOR_BITS;
}

B
blueswir1 已提交
267 268 269 270 271 272 273
/* Seek to a new position:
 * returns 0 if already on right track
 * returns 1 if track changed
 * returns 2 if track is invalid
 * returns 3 if sector is invalid
 * returns 4 if seek is disabled
 */
B
Blue Swirl 已提交
274 275
static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
                   int enable_seek)
B
bellard 已提交
276 277
{
    uint32_t sector;
278 279 280
    int ret;

    if (track > drv->max_track ||
281
        (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
282 283 284 285
        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
                       head, track, sect, 1,
                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
                       drv->max_track, drv->last_sect);
B
bellard 已提交
286 287 288
        return 2;
    }
    if (sect > drv->last_sect) {
289 290 291 292
        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
                       head, track, sect, 1,
                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
                       drv->max_track, drv->last_sect);
B
bellard 已提交
293 294
        return 3;
    }
295
    sector = fd_sector_calc(head, track, sect, drv->last_sect, NUM_SIDES(drv));
296
    ret = 0;
B
bellard 已提交
297 298 299
    if (sector != fd_sector(drv)) {
#if 0
        if (!enable_seek) {
B
Blue Swirl 已提交
300 301 302 303
            FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
                           " (max=%d %02x %02x)\n",
                           head, track, sect, 1, drv->max_track,
                           drv->last_sect);
B
bellard 已提交
304 305 306 307
            return 4;
        }
#endif
        drv->head = head;
308
        if (drv->track != track) {
309
            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
310 311
                drv->media_changed = 0;
            }
312
            ret = 1;
313
        }
B
bellard 已提交
314 315 316 317
        drv->track = track;
        drv->sect = sect;
    }

318
    if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
319 320 321
        ret = 2;
    }

322
    return ret;
B
bellard 已提交
323 324 325
}

/* Set drive back to track 0 */
B
Blue Swirl 已提交
326
static void fd_recalibrate(FDrive *drv)
B
bellard 已提交
327 328
{
    FLOPPY_DPRINTF("recalibrate\n");
329
    fd_seek(drv, 0, 0, 1, 1);
B
bellard 已提交
330 331
}

J
John Snow 已提交
332 333 334 335 336 337 338
/**
 * Determine geometry based on inserted diskette.
 * Will not operate on an empty drive.
 *
 * @return: 0 on success, -1 if the drive is empty.
 */
static int pick_geometry(FDrive *drv)
J
John Snow 已提交
339
{
340
    BlockBackend *blk = drv->blk;
J
John Snow 已提交
341 342
    const FDFormat *parse;
    uint64_t nb_sectors, size;
J
John Snow 已提交
343 344 345
    int i;
    int match, size_match, type_match;
    bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO;
J
John Snow 已提交
346

J
John Snow 已提交
347
    /* We can only pick a geometry if we have a diskette. */
348 349 350
    if (!drv->blk || !blk_is_inserted(drv->blk) ||
        drv->drive == FLOPPY_DRIVE_TYPE_NONE)
    {
J
John Snow 已提交
351 352 353
        return -1;
    }

J
John Snow 已提交
354 355 356 357 358 359 360 361 362
    /* We need to determine the likely geometry of the inserted medium.
     * In order of preference, we look for:
     * (1) The same drive type and number of sectors,
     * (2) The same diskette size and number of sectors,
     * (3) The same drive type.
     *
     * In all cases, matches that occur higher in the drive table will take
     * precedence over matches that occur later in the table.
     */
J
John Snow 已提交
363
    blk_get_geometry(blk, &nb_sectors);
J
John Snow 已提交
364
    match = size_match = type_match = -1;
J
John Snow 已提交
365 366
    for (i = 0; ; i++) {
        parse = &fd_formats[i];
J
John Snow 已提交
367
        if (parse->drive == FLOPPY_DRIVE_TYPE_NONE) {
J
John Snow 已提交
368 369
            break;
        }
J
John Snow 已提交
370 371 372 373 374 375 376 377 378 379 380
        size = (parse->max_head + 1) * parse->max_track * parse->last_sect;
        if (nb_sectors == size) {
            if (magic || parse->drive == drv->drive) {
                /* (1) perfect match -- nb_sectors and drive type */
                goto out;
            } else if (drive_size(parse->drive) == drive_size(drv->drive)) {
                /* (2) size match -- nb_sectors and physical medium size */
                match = (match == -1) ? i : match;
            } else {
                /* This is suspicious -- Did the user misconfigure? */
                size_match = (size_match == -1) ? i : size_match;
J
John Snow 已提交
381
            }
J
John Snow 已提交
382 383 384 385 386 387 388
        } else if (type_match == -1) {
            if ((parse->drive == drv->drive) ||
                (magic && (parse->drive == get_fallback_drive_type(drv)))) {
                /* (3) type match -- nb_sectors mismatch, but matches the type
                 *     specified explicitly by the user, or matches the fallback
                 *     default type when using the drive autodetect mechanism */
                type_match = i;
J
John Snow 已提交
389 390 391
            }
        }
    }
J
John Snow 已提交
392 393

    /* No exact match found */
J
John Snow 已提交
394
    if (match == -1) {
J
John Snow 已提交
395 396 397 398
        if (size_match != -1) {
            parse = &fd_formats[size_match];
            FLOPPY_DPRINTF("User requested floppy drive type '%s', "
                           "but inserted medium appears to be a "
399
                           "%"PRId64" sector '%s' type\n",
400
                           FloppyDriveType_str(drv->drive),
J
John Snow 已提交
401
                           nb_sectors,
402
                           FloppyDriveType_str(parse->drive));
J
John Snow 已提交
403
        }
404
        assert(type_match != -1 && "misconfigured fd_format");
J
John Snow 已提交
405
        match = type_match;
J
John Snow 已提交
406
    }
J
John Snow 已提交
407 408 409
    parse = &(fd_formats[match]);

 out:
410 411 412 413 414 415 416
    if (parse->max_head == 0) {
        drv->flags &= ~FDISK_DBL_SIDES;
    } else {
        drv->flags |= FDISK_DBL_SIDES;
    }
    drv->max_track = parse->max_track;
    drv->last_sect = parse->last_sect;
J
John Snow 已提交
417
    drv->disk = parse->drive;
418
    drv->media_rate = parse->rate;
J
John Snow 已提交
419 420 421 422 423
    return 0;
}

static void pick_drive_type(FDrive *drv)
{
J
John Snow 已提交
424 425 426 427
    if (drv->drive != FLOPPY_DRIVE_TYPE_AUTO) {
        return;
    }

J
John Snow 已提交
428 429 430
    if (pick_geometry(drv) == 0) {
        drv->drive = drv->disk;
    } else {
J
John Snow 已提交
431
        drv->drive = get_fallback_drive_type(drv);
J
John Snow 已提交
432
    }
J
John Snow 已提交
433 434

    g_assert(drv->drive != FLOPPY_DRIVE_TYPE_AUTO);
J
John Snow 已提交
435 436
}

B
bellard 已提交
437
/* Revalidate a disk drive after a disk change */
B
Blue Swirl 已提交
438
static void fd_revalidate(FDrive *drv)
B
bellard 已提交
439
{
J
John Snow 已提交
440 441
    int rc;

B
bellard 已提交
442
    FLOPPY_DPRINTF("revalidate\n");
443
    if (drv->blk != NULL) {
444
        drv->ro = blk_is_read_only(drv->blk);
445
        if (!blk_is_inserted(drv->blk)) {
P
Pavel Hrdina 已提交
446
            FLOPPY_DPRINTF("No disk in drive\n");
J
John Snow 已提交
447
            drv->disk = FLOPPY_DRIVE_TYPE_NONE;
J
John Snow 已提交
448
            fd_empty_seek_hack(drv);
J
John Snow 已提交
449 450 451 452 453 454 455 456 457 458 459
        } else if (!drv->media_validated) {
            rc = pick_geometry(drv);
            if (rc) {
                FLOPPY_DPRINTF("Could not validate floppy drive media");
            } else {
                drv->media_validated = true;
                FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n",
                               (drv->flags & FDISK_DBL_SIDES) ? 2 : 1,
                               drv->max_track, drv->last_sect,
                               drv->ro ? "ro" : "rw");
            }
460
        }
B
bellard 已提交
461
    } else {
P
Pavel Hrdina 已提交
462
        FLOPPY_DPRINTF("No drive connected\n");
463
        drv->last_sect = 0;
464 465
        drv->max_track = 0;
        drv->flags &= ~FDISK_DBL_SIDES;
J
John Snow 已提交
466 467
        drv->drive = FLOPPY_DRIVE_TYPE_NONE;
        drv->disk = FLOPPY_DRIVE_TYPE_NONE;
B
bellard 已提交
468
    }
469 470
}

471
static void fd_change_cb(void *opaque, bool load, Error **errp)
K
Kevin Wolf 已提交
472 473
{
    FDrive *drive = opaque;
K
Kevin Wolf 已提交
474 475 476 477

    if (!load) {
        blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
    } else {
478 479 480
        if (!blkconf_apply_backend_options(drive->conf,
                                           blk_is_read_only(drive->blk), false,
                                           errp)) {
K
Kevin Wolf 已提交
481 482 483
            return;
        }
    }
K
Kevin Wolf 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499

    drive->media_changed = 1;
    drive->media_validated = false;
    fd_revalidate(drive);
}

static const BlockDevOps fd_block_ops = {
    .change_media_cb = fd_change_cb,
};


#define TYPE_FLOPPY_DRIVE "floppy"
#define FLOPPY_DRIVE(obj) \
     OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)

typedef struct FloppyDrive {
500 501 502 503
    DeviceState     qdev;
    uint32_t        unit;
    BlockConf       conf;
    FloppyDriveType type;
K
Kevin Wolf 已提交
504 505 506 507
} FloppyDrive;

static Property floppy_drive_properties[] = {
    DEFINE_PROP_UINT32("unit", FloppyDrive, unit, -1),
508
    DEFINE_BLOCK_PROPERTIES(FloppyDrive, conf),
509
    DEFINE_PROP_SIGNED("drive-type", FloppyDrive, type,
510 511
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
K
Kevin Wolf 已提交
512 513 514
    DEFINE_PROP_END_OF_LIST(),
};

M
Mao Zhongyi 已提交
515
static void floppy_drive_realize(DeviceState *qdev, Error **errp)
K
Kevin Wolf 已提交
516 517 518 519
{
    FloppyDrive *dev = FLOPPY_DRIVE(qdev);
    FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
    FDrive *drive;
520
    bool read_only;
521
    int ret;
K
Kevin Wolf 已提交
522 523 524 525 526 527 528 529 530 531 532

    if (dev->unit == -1) {
        for (dev->unit = 0; dev->unit < MAX_FD; dev->unit++) {
            drive = get_drv(bus->fdc, dev->unit);
            if (!drive->blk) {
                break;
            }
        }
    }

    if (dev->unit >= MAX_FD) {
M
Mao Zhongyi 已提交
533 534 535
        error_setg(errp, "Can't create floppy unit %d, bus supports "
                   "only %d units", dev->unit, MAX_FD);
        return;
K
Kevin Wolf 已提交
536 537 538 539
    }

    drive = get_drv(bus->fdc, dev->unit);
    if (drive->blk) {
M
Mao Zhongyi 已提交
540 541
        error_setg(errp, "Floppy unit %d is in use", dev->unit);
        return;
542 543 544
    }

    if (!dev->conf.blk) {
K
Kevin Wolf 已提交
545
        /* Anonymous BlockBackend for an empty drive */
K
Kevin Wolf 已提交
546
        dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
547 548
        ret = blk_attach_dev(dev->conf.blk, qdev);
        assert(ret == 0);
549 550 551 552 553 554

        /* Don't take write permissions on an empty drive to allow attaching a
         * read-only node later */
        read_only = true;
    } else {
        read_only = !blk_bs(dev->conf.blk) || blk_is_read_only(dev->conf.blk);
K
Kevin Wolf 已提交
555 556
    }

557 558 559 560
    if (!blkconf_blocksizes(&dev->conf, errp)) {
        return;
    }

561 562 563
    if (dev->conf.logical_block_size != 512 ||
        dev->conf.physical_block_size != 512)
    {
M
Mao Zhongyi 已提交
564 565 566
        error_setg(errp, "Physical and logical block size must "
                   "be 512 for floppy");
        return;
567 568 569 570 571 572 573
    }

    /* rerror/werror aren't supported by fdc and therefore not even registered
     * with qdev. So set the defaults manually before they are used in
     * blkconf_apply_backend_options(). */
    dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
    dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
K
Kevin Wolf 已提交
574

575
    if (!blkconf_apply_backend_options(&dev->conf, read_only, false, errp)) {
M
Mao Zhongyi 已提交
576
        return;
K
Kevin Wolf 已提交
577
    }
578 579 580 581 582

    /* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
     * for empty drives. */
    if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
        blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
M
Mao Zhongyi 已提交
583 584
        error_setg(errp, "fdc doesn't support drive option werror");
        return;
K
Kevin Wolf 已提交
585
    }
586
    if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
M
Mao Zhongyi 已提交
587 588
        error_setg(errp, "fdc doesn't support drive option rerror");
        return;
589 590
    }

K
Kevin Wolf 已提交
591
    drive->conf = &dev->conf;
592 593 594 595 596 597 598 599 600 601 602
    drive->blk = dev->conf.blk;
    drive->fdctrl = bus->fdc;

    fd_init(drive);
    blk_set_dev_ops(drive->blk, &fd_block_ops, drive);

    /* Keep 'type' qdev property and FDrive->drive in sync */
    drive->drive = dev->type;
    pick_drive_type(drive);
    dev->type = drive->drive;

K
Kevin Wolf 已提交
603 604 605 606 607 608
    fd_revalidate(drive);
}

static void floppy_drive_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
M
Mao Zhongyi 已提交
609
    k->realize = floppy_drive_realize;
K
Kevin Wolf 已提交
610 611
    set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
    k->bus_type = TYPE_FLOPPY_BUS;
612
    device_class_set_props(k, floppy_drive_properties);
K
Kevin Wolf 已提交
613 614 615 616 617 618 619 620 621 622
    k->desc = "virtual floppy drive";
}

static const TypeInfo floppy_drive_info = {
    .name = TYPE_FLOPPY_DRIVE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(FloppyDrive),
    .class_init = floppy_drive_class_init,
};

B
bellard 已提交
623
/********************************************************/
B
bellard 已提交
624
/* Intel 82078 floppy disk controller emulation          */
B
bellard 已提交
625

B
Blue Swirl 已提交
626
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
627
static void fdctrl_to_command_phase(FDCtrl *fdctrl);
B
bellard 已提交
628
static int fdctrl_transfer_handler (void *opaque, int nchan,
A
Anthony Liguori 已提交
629
                                    int dma_pos, int dma_len);
630
static void fdctrl_raise_irq(FDCtrl *fdctrl);
631
static FDrive *get_cur_drv(FDCtrl *fdctrl);
B
Blue Swirl 已提交
632 633 634 635 636 637 638 639 640 641 642 643

static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
644
static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
B
bellard 已提交
645 646 647 648 649 650 651

enum {
    FD_DIR_WRITE   = 0,
    FD_DIR_READ    = 1,
    FD_DIR_SCANE   = 2,
    FD_DIR_SCANL   = 3,
    FD_DIR_SCANH   = 4,
H
Hervé Poussineau 已提交
652
    FD_DIR_VERIFY  = 5,
B
bellard 已提交
653 654 655
};

enum {
B
blueswir1 已提交
656 657
    FD_STATE_MULTI  = 0x01,	/* multi track flag */
    FD_STATE_FORMAT = 0x02,	/* format flag */
B
bellard 已提交
658 659
};

660
enum {
B
blueswir1 已提交
661 662
    FD_REG_SRA = 0x00,
    FD_REG_SRB = 0x01,
663 664 665 666 667 668
    FD_REG_DOR = 0x02,
    FD_REG_TDR = 0x03,
    FD_REG_MSR = 0x04,
    FD_REG_DSR = 0x04,
    FD_REG_FIFO = 0x05,
    FD_REG_DIR = 0x07,
669
    FD_REG_CCR = 0x07,
670 671 672
};

enum {
673
    FD_CMD_READ_TRACK = 0x02,
674 675
    FD_CMD_SPECIFY = 0x03,
    FD_CMD_SENSE_DRIVE_STATUS = 0x04,
676 677
    FD_CMD_WRITE = 0x05,
    FD_CMD_READ = 0x06,
678 679
    FD_CMD_RECALIBRATE = 0x07,
    FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
680 681 682 683
    FD_CMD_WRITE_DELETED = 0x09,
    FD_CMD_READ_ID = 0x0a,
    FD_CMD_READ_DELETED = 0x0c,
    FD_CMD_FORMAT_TRACK = 0x0d,
684 685 686
    FD_CMD_DUMPREG = 0x0e,
    FD_CMD_SEEK = 0x0f,
    FD_CMD_VERSION = 0x10,
687
    FD_CMD_SCAN_EQUAL = 0x11,
688 689
    FD_CMD_PERPENDICULAR_MODE = 0x12,
    FD_CMD_CONFIGURE = 0x13,
690 691
    FD_CMD_LOCK = 0x14,
    FD_CMD_VERIFY = 0x16,
692 693
    FD_CMD_POWERDOWN_MODE = 0x17,
    FD_CMD_PART_ID = 0x18,
694 695
    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
696
    FD_CMD_SAVE = 0x2e,
697
    FD_CMD_OPTION = 0x33,
698
    FD_CMD_RESTORE = 0x4e,
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
    FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
    FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
    FD_CMD_FORMAT_AND_WRITE = 0xcd,
    FD_CMD_RELATIVE_SEEK_IN = 0xcf,
};

enum {
    FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
    FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
    FD_CONFIG_POLL  = 0x10, /* Poll enabled */
    FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
    FD_CONFIG_EIS   = 0x40, /* No implied seeks */
};

enum {
P
Pavel Hrdina 已提交
714 715 716
    FD_SR0_DS0      = 0x01,
    FD_SR0_DS1      = 0x02,
    FD_SR0_HEAD     = 0x04,
717 718 719 720 721 722 723
    FD_SR0_EQPMT    = 0x10,
    FD_SR0_SEEK     = 0x20,
    FD_SR0_ABNTERM  = 0x40,
    FD_SR0_INVCMD   = 0x80,
    FD_SR0_RDYCHG   = 0xc0,
};

B
blueswir1 已提交
724
enum {
725
    FD_SR1_MA       = 0x01, /* Missing address mark */
726
    FD_SR1_NW       = 0x02, /* Not writable */
B
blueswir1 已提交
727 728 729 730 731 732 733 734
    FD_SR1_EC       = 0x80, /* End of cylinder */
};

enum {
    FD_SR2_SNS      = 0x04, /* Scan not satisfied */
    FD_SR2_SEH      = 0x08, /* Scan equal hit */
};

B
blueswir1 已提交
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
enum {
    FD_SRA_DIR      = 0x01,
    FD_SRA_nWP      = 0x02,
    FD_SRA_nINDX    = 0x04,
    FD_SRA_HDSEL    = 0x08,
    FD_SRA_nTRK0    = 0x10,
    FD_SRA_STEP     = 0x20,
    FD_SRA_nDRV2    = 0x40,
    FD_SRA_INTPEND  = 0x80,
};

enum {
    FD_SRB_MTR0     = 0x01,
    FD_SRB_MTR1     = 0x02,
    FD_SRB_WGATE    = 0x04,
    FD_SRB_RDATA    = 0x08,
    FD_SRB_WDATA    = 0x10,
    FD_SRB_DR0      = 0x20,
};

755
enum {
B
blueswir1 已提交
756 757 758
#if MAX_FD == 4
    FD_DOR_SELMASK  = 0x03,
#else
759
    FD_DOR_SELMASK  = 0x01,
B
blueswir1 已提交
760
#endif
761 762 763 764 765 766 767 768 769
    FD_DOR_nRESET   = 0x04,
    FD_DOR_DMAEN    = 0x08,
    FD_DOR_MOTEN0   = 0x10,
    FD_DOR_MOTEN1   = 0x20,
    FD_DOR_MOTEN2   = 0x40,
    FD_DOR_MOTEN3   = 0x80,
};

enum {
B
blueswir1 已提交
770
#if MAX_FD == 4
771
    FD_TDR_BOOTSEL  = 0x0c,
B
blueswir1 已提交
772 773 774
#else
    FD_TDR_BOOTSEL  = 0x04,
#endif
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
};

enum {
    FD_DSR_DRATEMASK= 0x03,
    FD_DSR_PWRDOWN  = 0x40,
    FD_DSR_SWRESET  = 0x80,
};

enum {
    FD_MSR_DRV0BUSY = 0x01,
    FD_MSR_DRV1BUSY = 0x02,
    FD_MSR_DRV2BUSY = 0x04,
    FD_MSR_DRV3BUSY = 0x08,
    FD_MSR_CMDBUSY  = 0x10,
    FD_MSR_NONDMA   = 0x20,
    FD_MSR_DIO      = 0x40,
    FD_MSR_RQM      = 0x80,
};

enum {
    FD_DIR_DSKCHG   = 0x80,
};

K
Kevin Wolf 已提交
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
/*
 * See chapter 5.0 "Controller phases" of the spec:
 *
 * Command phase:
 * The host writes a command and its parameters into the FIFO. The command
 * phase is completed when all parameters for the command have been supplied,
 * and execution phase is entered.
 *
 * Execution phase:
 * Data transfers, either DMA or non-DMA. For non-DMA transfers, the FIFO
 * contains the payload now, otherwise it's unused. When all bytes of the
 * required data have been transferred, the state is switched to either result
 * phase (if the command produces status bytes) or directly back into the
 * command phase for the next command.
 *
 * Result phase:
 * The host reads out the FIFO, which contains one or more result bytes now.
 */
enum {
    /* Only for migration: reconstruct phase from registers like qemu 2.3 */
    FD_PHASE_RECONSTRUCT    = 0,

    FD_PHASE_COMMAND        = 1,
    FD_PHASE_EXECUTION      = 2,
    FD_PHASE_RESULT         = 3,
};

B
bellard 已提交
825
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
826
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
B
bellard 已提交
827

B
Blue Swirl 已提交
828
struct FDCtrl {
A
Avi Kivity 已提交
829
    MemoryRegion iomem;
P
pbrook 已提交
830
    qemu_irq irq;
B
bellard 已提交
831
    /* Controller state */
832
    QEMUTimer *result_timer;
833
    int dma_chann;
K
Kevin Wolf 已提交
834
    uint8_t phase;
835
    IsaDma *dma;
836 837 838
    /* Controller's identification */
    uint8_t version;
    /* HW */
B
blueswir1 已提交
839 840
    uint8_t sra;
    uint8_t srb;
B
blueswir1 已提交
841
    uint8_t dor;
J
Juan Quintela 已提交
842
    uint8_t dor_vmstate; /* only used as temp during vmstate */
B
blueswir1 已提交
843
    uint8_t tdr;
B
blueswir1 已提交
844
    uint8_t dsr;
B
blueswir1 已提交
845
    uint8_t msr;
B
bellard 已提交
846
    uint8_t cur_drv;
B
blueswir1 已提交
847 848 849
    uint8_t status0;
    uint8_t status1;
    uint8_t status2;
B
bellard 已提交
850
    /* Command FIFO */
851
    uint8_t *fifo;
J
Juan Quintela 已提交
852
    int32_t fifo_size;
B
bellard 已提交
853 854 855 856
    uint32_t data_pos;
    uint32_t data_len;
    uint8_t data_state;
    uint8_t data_dir;
857
    uint8_t eot; /* last wanted sector */
B
bellard 已提交
858 859 860 861 862 863 864 865
    /* States kept only to be returned back */
    /* precompensation */
    uint8_t precomp_trk;
    uint8_t config;
    uint8_t lock;
    /* Power down config (also with status regB access mode */
    uint8_t pwrd;
    /* Floppy drives */
K
Kevin Wolf 已提交
866
    FloppyBus bus;
J
Juan Quintela 已提交
867
    uint8_t num_floppies;
B
Blue Swirl 已提交
868
    FDrive drives[MAX_FD];
869 870 871 872
    struct {
        BlockBackend *blk;
        FloppyDriveType type;
    } qdev_for_drives[MAX_FD];
873
    int reset_sensei;
874
    uint32_t check_media_rate;
J
John Snow 已提交
875
    FloppyDriveType fallback; /* type=auto failure fallback */
876 877 878
    /* Timers state */
    uint8_t timer0;
    uint8_t timer1;
879
    PortioList portio_list;
880 881
};

J
John Snow 已提交
882 883 884 885 886
static FloppyDriveType get_fallback_drive_type(FDrive *drv)
{
    return drv->fdctrl->fallback;
}

887
#define TYPE_SYSBUS_FDC "base-sysbus-fdc"
H
Hu Tao 已提交
888 889
#define SYSBUS_FDC(obj) OBJECT_CHECK(FDCtrlSysBus, (obj), TYPE_SYSBUS_FDC)

B
Blue Swirl 已提交
890
typedef struct FDCtrlSysBus {
H
Hu Tao 已提交
891 892 893 894
    /*< private >*/
    SysBusDevice parent_obj;
    /*< public >*/

B
Blue Swirl 已提交
895 896
    struct FDCtrl state;
} FDCtrlSysBus;
G
Gerd Hoffmann 已提交
897

898 899
#define ISA_FDC(obj) OBJECT_CHECK(FDCtrlISABus, (obj), TYPE_ISA_FDC)

B
Blue Swirl 已提交
900
typedef struct FDCtrlISABus {
901 902
    ISADevice parent_obj;

903 904 905
    uint32_t iobase;
    uint32_t irq;
    uint32_t dma;
B
Blue Swirl 已提交
906
    struct FDCtrl state;
907 908
    int32_t bootindexA;
    int32_t bootindexB;
B
Blue Swirl 已提交
909
} FDCtrlISABus;
G
Gerd Hoffmann 已提交
910

911 912
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
{
B
Blue Swirl 已提交
913
    FDCtrl *fdctrl = opaque;
914 915
    uint32_t retval;

K
Kevin Wolf 已提交
916
    reg &= 7;
B
blueswir1 已提交
917
    switch (reg) {
B
blueswir1 已提交
918 919
    case FD_REG_SRA:
        retval = fdctrl_read_statusA(fdctrl);
920
        break;
B
blueswir1 已提交
921
    case FD_REG_SRB:
922 923
        retval = fdctrl_read_statusB(fdctrl);
        break;
924
    case FD_REG_DOR:
925 926
        retval = fdctrl_read_dor(fdctrl);
        break;
927
    case FD_REG_TDR:
928
        retval = fdctrl_read_tape(fdctrl);
929
        break;
930
    case FD_REG_MSR:
931
        retval = fdctrl_read_main_status(fdctrl);
932
        break;
933
    case FD_REG_FIFO:
934
        retval = fdctrl_read_data(fdctrl);
935
        break;
936
    case FD_REG_DIR:
937
        retval = fdctrl_read_dir(fdctrl);
938
        break;
939
    default:
940 941
        retval = (uint32_t)(-1);
        break;
942
    }
943
    trace_fdc_ioport_read(reg, retval);
944 945 946 947 948 949

    return retval;
}

static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
{
B
Blue Swirl 已提交
950
    FDCtrl *fdctrl = opaque;
951

K
Kevin Wolf 已提交
952
    reg &= 7;
953
    trace_fdc_ioport_write(reg, value);
B
blueswir1 已提交
954
    switch (reg) {
955
    case FD_REG_DOR:
956 957
        fdctrl_write_dor(fdctrl, value);
        break;
958
    case FD_REG_TDR:
959
        fdctrl_write_tape(fdctrl, value);
960
        break;
961
    case FD_REG_DSR:
962
        fdctrl_write_rate(fdctrl, value);
963
        break;
964
    case FD_REG_FIFO:
965
        fdctrl_write_data(fdctrl, value);
966
        break;
967 968 969
    case FD_REG_CCR:
        fdctrl_write_ccr(fdctrl, value);
        break;
970
    default:
971
        break;
972
    }
973 974
}

A
Avi Kivity 已提交
975
static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg,
A
Avi Kivity 已提交
976
                                 unsigned ize)
B
bellard 已提交
977
{
978
    return fdctrl_read(opaque, (uint32_t)reg);
B
bellard 已提交
979 980
}

A
Avi Kivity 已提交
981
static void fdctrl_write_mem (void *opaque, hwaddr reg,
A
Avi Kivity 已提交
982
                              uint64_t value, unsigned size)
B
bellard 已提交
983
{
984
    fdctrl_write(opaque, (uint32_t)reg, value);
B
bellard 已提交
985 986
}

A
Avi Kivity 已提交
987 988 989 990
static const MemoryRegionOps fdctrl_mem_ops = {
    .read = fdctrl_read_mem,
    .write = fdctrl_write_mem,
    .endianness = DEVICE_NATIVE_ENDIAN,
B
bellard 已提交
991 992
};

A
Avi Kivity 已提交
993 994 995 996 997 998 999 1000
static const MemoryRegionOps fdctrl_mem_strict_ops = {
    .read = fdctrl_read_mem,
    .write = fdctrl_write_mem,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 1,
        .max_access_size = 1,
    },
1001 1002
};

1003 1004 1005 1006
static bool fdrive_media_changed_needed(void *opaque)
{
    FDrive *drive = opaque;

1007
    return (drive->blk != NULL && drive->media_changed != 1);
1008 1009 1010 1011 1012 1013
}

static const VMStateDescription vmstate_fdrive_media_changed = {
    .name = "fdrive/media_changed",
    .version_id = 1,
    .minimum_version_id = 1,
1014
    .needed = fdrive_media_changed_needed,
1015
    .fields = (VMStateField[]) {
1016 1017 1018 1019 1020
        VMSTATE_UINT8(media_changed, FDrive),
        VMSTATE_END_OF_LIST()
    }
};

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
static bool fdrive_media_rate_needed(void *opaque)
{
    FDrive *drive = opaque;

    return drive->fdctrl->check_media_rate;
}

static const VMStateDescription vmstate_fdrive_media_rate = {
    .name = "fdrive/media_rate",
    .version_id = 1,
    .minimum_version_id = 1,
1032
    .needed = fdrive_media_rate_needed,
1033
    .fields = (VMStateField[]) {
1034 1035 1036 1037 1038
        VMSTATE_UINT8(media_rate, FDrive),
        VMSTATE_END_OF_LIST()
    }
};

1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
static bool fdrive_perpendicular_needed(void *opaque)
{
    FDrive *drive = opaque;

    return drive->perpendicular != 0;
}

static const VMStateDescription vmstate_fdrive_perpendicular = {
    .name = "fdrive/perpendicular",
    .version_id = 1,
    .minimum_version_id = 1,
1050
    .needed = fdrive_perpendicular_needed,
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
    .fields = (VMStateField[]) {
        VMSTATE_UINT8(perpendicular, FDrive),
        VMSTATE_END_OF_LIST()
    }
};

static int fdrive_post_load(void *opaque, int version_id)
{
    fd_revalidate(opaque);
    return 0;
}

J
Juan Quintela 已提交
1063 1064 1065 1066
static const VMStateDescription vmstate_fdrive = {
    .name = "fdrive",
    .version_id = 1,
    .minimum_version_id = 1,
1067
    .post_load = fdrive_post_load,
1068
    .fields = (VMStateField[]) {
B
Blue Swirl 已提交
1069 1070 1071
        VMSTATE_UINT8(head, FDrive),
        VMSTATE_UINT8(track, FDrive),
        VMSTATE_UINT8(sect, FDrive),
J
Juan Quintela 已提交
1072
        VMSTATE_END_OF_LIST()
1073
    },
1074 1075 1076 1077 1078
    .subsections = (const VMStateDescription*[]) {
        &vmstate_fdrive_media_changed,
        &vmstate_fdrive_media_rate,
        &vmstate_fdrive_perpendicular,
        NULL
J
Juan Quintela 已提交
1079 1080
    }
};
1081

K
Kevin Wolf 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
/*
 * Reconstructs the phase from register values according to the logic that was
 * implemented in qemu 2.3. This is the default value that is used if the phase
 * subsection is not present on migration.
 *
 * Don't change this function to reflect newer qemu versions, it is part of
 * the migration ABI.
 */
static int reconstruct_phase(FDCtrl *fdctrl)
{
    if (fdctrl->msr & FD_MSR_NONDMA) {
        return FD_PHASE_EXECUTION;
    } else if ((fdctrl->msr & FD_MSR_RQM) == 0) {
        /* qemu 2.3 disabled RQM only during DMA transfers */
        return FD_PHASE_EXECUTION;
    } else if (fdctrl->msr & FD_MSR_DIO) {
        return FD_PHASE_RESULT;
    } else {
        return FD_PHASE_COMMAND;
    }
}

1104
static int fdc_pre_save(void *opaque)
1105
{
B
Blue Swirl 已提交
1106
    FDCtrl *s = opaque;
1107

J
Juan Quintela 已提交
1108
    s->dor_vmstate = s->dor | GET_CUR_DRV(s);
1109 1110

    return 0;
1111 1112
}

K
Kevin Wolf 已提交
1113 1114 1115 1116 1117 1118 1119
static int fdc_pre_load(void *opaque)
{
    FDCtrl *s = opaque;
    s->phase = FD_PHASE_RECONSTRUCT;
    return 0;
}

1120
static int fdc_post_load(void *opaque, int version_id)
1121
{
B
Blue Swirl 已提交
1122
    FDCtrl *s = opaque;
1123

J
Juan Quintela 已提交
1124 1125
    SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
    s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
K
Kevin Wolf 已提交
1126 1127 1128 1129 1130

    if (s->phase == FD_PHASE_RECONSTRUCT) {
        s->phase = reconstruct_phase(s);
    }

1131 1132 1133
    return 0;
}

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
static bool fdc_reset_sensei_needed(void *opaque)
{
    FDCtrl *s = opaque;

    return s->reset_sensei != 0;
}

static const VMStateDescription vmstate_fdc_reset_sensei = {
    .name = "fdc/reset_sensei",
    .version_id = 1,
    .minimum_version_id = 1,
1145
    .needed = fdc_reset_sensei_needed,
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
    .fields = (VMStateField[]) {
        VMSTATE_INT32(reset_sensei, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

static bool fdc_result_timer_needed(void *opaque)
{
    FDCtrl *s = opaque;

    return timer_pending(s->result_timer);
}

static const VMStateDescription vmstate_fdc_result_timer = {
    .name = "fdc/result_timer",
    .version_id = 1,
    .minimum_version_id = 1,
1163
    .needed = fdc_result_timer_needed,
1164
    .fields = (VMStateField[]) {
1165
        VMSTATE_TIMER_PTR(result_timer, FDCtrl),
1166 1167 1168 1169
        VMSTATE_END_OF_LIST()
    }
};

K
Kevin Wolf 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
static bool fdc_phase_needed(void *opaque)
{
    FDCtrl *fdctrl = opaque;

    return reconstruct_phase(fdctrl) != fdctrl->phase;
}

static const VMStateDescription vmstate_fdc_phase = {
    .name = "fdc/phase",
    .version_id = 1,
    .minimum_version_id = 1,
1181
    .needed = fdc_phase_needed,
K
Kevin Wolf 已提交
1182 1183 1184 1185 1186 1187
    .fields = (VMStateField[]) {
        VMSTATE_UINT8(phase, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

J
Juan Quintela 已提交
1188
static const VMStateDescription vmstate_fdc = {
1189
    .name = "fdc",
J
Juan Quintela 已提交
1190 1191 1192
    .version_id = 2,
    .minimum_version_id = 2,
    .pre_save = fdc_pre_save,
K
Kevin Wolf 已提交
1193
    .pre_load = fdc_pre_load,
J
Juan Quintela 已提交
1194
    .post_load = fdc_post_load,
1195
    .fields = (VMStateField[]) {
J
Juan Quintela 已提交
1196
        /* Controller State */
B
Blue Swirl 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205
        VMSTATE_UINT8(sra, FDCtrl),
        VMSTATE_UINT8(srb, FDCtrl),
        VMSTATE_UINT8(dor_vmstate, FDCtrl),
        VMSTATE_UINT8(tdr, FDCtrl),
        VMSTATE_UINT8(dsr, FDCtrl),
        VMSTATE_UINT8(msr, FDCtrl),
        VMSTATE_UINT8(status0, FDCtrl),
        VMSTATE_UINT8(status1, FDCtrl),
        VMSTATE_UINT8(status2, FDCtrl),
J
Juan Quintela 已提交
1206
        /* Command FIFO */
B
Blue Swirl 已提交
1207 1208
        VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
                             uint8_t),
B
Blue Swirl 已提交
1209 1210 1211 1212 1213
        VMSTATE_UINT32(data_pos, FDCtrl),
        VMSTATE_UINT32(data_len, FDCtrl),
        VMSTATE_UINT8(data_state, FDCtrl),
        VMSTATE_UINT8(data_dir, FDCtrl),
        VMSTATE_UINT8(eot, FDCtrl),
J
Juan Quintela 已提交
1214
        /* States kept only to be returned back */
B
Blue Swirl 已提交
1215 1216 1217 1218 1219 1220
        VMSTATE_UINT8(timer0, FDCtrl),
        VMSTATE_UINT8(timer1, FDCtrl),
        VMSTATE_UINT8(precomp_trk, FDCtrl),
        VMSTATE_UINT8(config, FDCtrl),
        VMSTATE_UINT8(lock, FDCtrl),
        VMSTATE_UINT8(pwrd, FDCtrl),
1221
        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl, NULL),
B
Blue Swirl 已提交
1222 1223
        VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
                             vmstate_fdrive, FDrive),
J
Juan Quintela 已提交
1224
        VMSTATE_END_OF_LIST()
1225
    },
1226 1227 1228 1229 1230
    .subsections = (const VMStateDescription*[]) {
        &vmstate_fdc_reset_sensei,
        &vmstate_fdc_result_timer,
        &vmstate_fdc_phase,
        NULL
B
blueswir1 已提交
1231
    }
J
Juan Quintela 已提交
1232
};
1233

B
Blue Swirl 已提交
1234
static void fdctrl_external_reset_sysbus(DeviceState *d)
1235
{
H
Hu Tao 已提交
1236
    FDCtrlSysBus *sys = SYSBUS_FDC(d);
B
Blue Swirl 已提交
1237
    FDCtrl *s = &sys->state;
B
Blue Swirl 已提交
1238 1239 1240 1241 1242 1243

    fdctrl_reset(s, 0);
}

static void fdctrl_external_reset_isa(DeviceState *d)
{
1244
    FDCtrlISABus *isa = ISA_FDC(d);
B
Blue Swirl 已提交
1245
    FDCtrl *s = &isa->state;
1246 1247 1248 1249

    fdctrl_reset(s, 0);
}

B
blueswir1 已提交
1250 1251
static void fdctrl_handle_tc(void *opaque, int irq, int level)
{
B
Blue Swirl 已提交
1252
    //FDCtrl *s = opaque;
B
blueswir1 已提交
1253 1254 1255 1256 1257 1258 1259

    if (level) {
        // XXX
        FLOPPY_DPRINTF("TC pulsed\n");
    }
}

B
bellard 已提交
1260
/* Change IRQ state */
B
Blue Swirl 已提交
1261
static void fdctrl_reset_irq(FDCtrl *fdctrl)
B
bellard 已提交
1262
{
1263
    fdctrl->status0 = 0;
B
blueswir1 已提交
1264 1265
    if (!(fdctrl->sra & FD_SRA_INTPEND))
        return;
1266
    FLOPPY_DPRINTF("Reset interrupt\n");
P
pbrook 已提交
1267
    qemu_set_irq(fdctrl->irq, 0);
B
blueswir1 已提交
1268
    fdctrl->sra &= ~FD_SRA_INTPEND;
B
bellard 已提交
1269 1270
}

1271
static void fdctrl_raise_irq(FDCtrl *fdctrl)
B
bellard 已提交
1272
{
B
blueswir1 已提交
1273
    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
P
pbrook 已提交
1274
        qemu_set_irq(fdctrl->irq, 1);
B
blueswir1 已提交
1275
        fdctrl->sra |= FD_SRA_INTPEND;
B
bellard 已提交
1276
    }
1277

1278
    fdctrl->reset_sensei = 0;
B
blueswir1 已提交
1279
    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
B
bellard 已提交
1280 1281
}

B
bellard 已提交
1282
/* Reset controller */
B
Blue Swirl 已提交
1283
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
B
bellard 已提交
1284 1285 1286
{
    int i;

B
bellard 已提交
1287
    FLOPPY_DPRINTF("reset controller\n");
1288
    fdctrl_reset_irq(fdctrl);
B
bellard 已提交
1289
    /* Initialise controller */
B
blueswir1 已提交
1290 1291
    fdctrl->sra = 0;
    fdctrl->srb = 0xc0;
1292
    if (!fdctrl->drives[1].blk) {
B
blueswir1 已提交
1293
        fdctrl->sra |= FD_SRA_nDRV2;
1294
    }
1295
    fdctrl->cur_drv = 0;
B
blueswir1 已提交
1296
    fdctrl->dor = FD_DOR_nRESET;
B
blueswir1 已提交
1297
    fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
B
blueswir1 已提交
1298
    fdctrl->msr = FD_MSR_RQM;
1299 1300
    fdctrl->reset_sensei = 0;
    timer_del(fdctrl->result_timer);
B
bellard 已提交
1301
    /* FIFO state */
1302 1303
    fdctrl->data_pos = 0;
    fdctrl->data_len = 0;
B
blueswir1 已提交
1304
    fdctrl->data_state = 0;
1305
    fdctrl->data_dir = FD_DIR_WRITE;
B
bellard 已提交
1306
    for (i = 0; i < MAX_FD; i++)
B
blueswir1 已提交
1307
        fd_recalibrate(&fdctrl->drives[i]);
1308
    fdctrl_to_command_phase(fdctrl);
B
blueswir1 已提交
1309
    if (do_irq) {
1310 1311
        fdctrl->status0 |= FD_SR0_RDYCHG;
        fdctrl_raise_irq(fdctrl);
1312
        fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
B
blueswir1 已提交
1313
    }
1314 1315
}

B
Blue Swirl 已提交
1316
static inline FDrive *drv0(FDCtrl *fdctrl)
1317
{
B
blueswir1 已提交
1318
    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
1319 1320
}

B
Blue Swirl 已提交
1321
static inline FDrive *drv1(FDCtrl *fdctrl)
1322
{
B
blueswir1 已提交
1323 1324 1325 1326
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
        return &fdctrl->drives[1];
    else
        return &fdctrl->drives[0];
1327 1328
}

B
blueswir1 已提交
1329
#if MAX_FD == 4
B
Blue Swirl 已提交
1330
static inline FDrive *drv2(FDCtrl *fdctrl)
B
blueswir1 已提交
1331 1332 1333 1334 1335 1336 1337
{
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
        return &fdctrl->drives[2];
    else
        return &fdctrl->drives[1];
}

B
Blue Swirl 已提交
1338
static inline FDrive *drv3(FDCtrl *fdctrl)
B
blueswir1 已提交
1339 1340 1341 1342 1343 1344 1345 1346
{
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
        return &fdctrl->drives[3];
    else
        return &fdctrl->drives[2];
}
#endif

K
Kevin Wolf 已提交
1347
static FDrive *get_drv(FDCtrl *fdctrl, int unit)
1348
{
K
Kevin Wolf 已提交
1349
    switch (unit) {
B
blueswir1 已提交
1350 1351 1352 1353 1354 1355 1356 1357
        case 0: return drv0(fdctrl);
        case 1: return drv1(fdctrl);
#if MAX_FD == 4
        case 2: return drv2(fdctrl);
        case 3: return drv3(fdctrl);
#endif
        default: return NULL;
    }
B
bellard 已提交
1358 1359
}

K
Kevin Wolf 已提交
1360 1361 1362 1363 1364
static FDrive *get_cur_drv(FDCtrl *fdctrl)
{
    return get_drv(fdctrl, fdctrl->cur_drv);
}

B
blueswir1 已提交
1365
/* Status A register : 0x00 (read-only) */
B
Blue Swirl 已提交
1366
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
B
blueswir1 已提交
1367 1368 1369 1370 1371 1372 1373 1374
{
    uint32_t retval = fdctrl->sra;

    FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);

    return retval;
}

B
bellard 已提交
1375
/* Status B register : 0x01 (read-only) */
B
Blue Swirl 已提交
1376
static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
B
bellard 已提交
1377
{
B
blueswir1 已提交
1378 1379 1380 1381 1382
    uint32_t retval = fdctrl->srb;

    FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);

    return retval;
B
bellard 已提交
1383 1384 1385
}

/* Digital output register : 0x02 */
B
Blue Swirl 已提交
1386
static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
B
bellard 已提交
1387
{
B
blueswir1 已提交
1388
    uint32_t retval = fdctrl->dor;
B
bellard 已提交
1389 1390

    /* Selected drive */
1391
    retval |= fdctrl->cur_drv;
B
bellard 已提交
1392 1393 1394 1395 1396
    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);

    return retval;
}

B
Blue Swirl 已提交
1397
static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
1398 1399
{
    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
B
blueswir1 已提交
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416

    /* Motors */
    if (value & FD_DOR_MOTEN0)
        fdctrl->srb |= FD_SRB_MTR0;
    else
        fdctrl->srb &= ~FD_SRB_MTR0;
    if (value & FD_DOR_MOTEN1)
        fdctrl->srb |= FD_SRB_MTR1;
    else
        fdctrl->srb &= ~FD_SRB_MTR1;

    /* Drive */
    if (value & 1)
        fdctrl->srb |= FD_SRB_DR0;
    else
        fdctrl->srb &= ~FD_SRB_DR0;

B
bellard 已提交
1417
    /* Reset */
1418
    if (!(value & FD_DOR_nRESET)) {
B
blueswir1 已提交
1419
        if (fdctrl->dor & FD_DOR_nRESET) {
B
bellard 已提交
1420
            FLOPPY_DPRINTF("controller enter RESET state\n");
B
bellard 已提交
1421 1422
        }
    } else {
B
blueswir1 已提交
1423
        if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
1424
            FLOPPY_DPRINTF("controller out of RESET state\n");
1425
            fdctrl_reset(fdctrl, 1);
B
blueswir1 已提交
1426
            fdctrl->dsr &= ~FD_DSR_PWRDOWN;
B
bellard 已提交
1427 1428 1429
        }
    }
    /* Selected drive */
1430
    fdctrl->cur_drv = value & FD_DOR_SELMASK;
B
blueswir1 已提交
1431 1432

    fdctrl->dor = value;
B
bellard 已提交
1433 1434 1435
}

/* Tape drive register : 0x03 */
B
Blue Swirl 已提交
1436
static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
B
bellard 已提交
1437
{
B
blueswir1 已提交
1438
    uint32_t retval = fdctrl->tdr;
B
bellard 已提交
1439 1440 1441 1442 1443 1444

    FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);

    return retval;
}

B
Blue Swirl 已提交
1445
static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
1446 1447
{
    /* Reset mode */
B
blueswir1 已提交
1448
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
1449
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
B
bellard 已提交
1450 1451 1452 1453
        return;
    }
    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
    /* Disk boot selection indicator */
B
blueswir1 已提交
1454
    fdctrl->tdr = value & FD_TDR_BOOTSEL;
B
bellard 已提交
1455 1456 1457 1458
    /* Tape indicators: never allow */
}

/* Main status register : 0x04 (read) */
B
Blue Swirl 已提交
1459
static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
B
bellard 已提交
1460
{
B
blueswir1 已提交
1461
    uint32_t retval = fdctrl->msr;
B
bellard 已提交
1462

B
blueswir1 已提交
1463
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
B
blueswir1 已提交
1464
    fdctrl->dor |= FD_DOR_nRESET;
B
blueswir1 已提交
1465

B
bellard 已提交
1466 1467 1468 1469 1470 1471
    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);

    return retval;
}

/* Data select rate register : 0x04 (write) */
B
Blue Swirl 已提交
1472
static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
1473 1474
{
    /* Reset mode */
B
blueswir1 已提交
1475
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
1476 1477 1478
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
        return;
    }
B
bellard 已提交
1479 1480
    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
    /* Reset: autoclear */
1481
    if (value & FD_DSR_SWRESET) {
B
blueswir1 已提交
1482
        fdctrl->dor &= ~FD_DOR_nRESET;
1483
        fdctrl_reset(fdctrl, 1);
B
blueswir1 已提交
1484
        fdctrl->dor |= FD_DOR_nRESET;
B
bellard 已提交
1485
    }
1486
    if (value & FD_DSR_PWRDOWN) {
1487
        fdctrl_reset(fdctrl, 1);
B
bellard 已提交
1488
    }
B
blueswir1 已提交
1489
    fdctrl->dsr = value;
B
bellard 已提交
1490 1491
}

1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
/* Configuration control register: 0x07 (write) */
static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value)
{
    /* Reset mode */
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
        return;
    }
    FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);

    /* Only the rate selection bits used in AT mode, and we
     * store those in the DSR.
     */
    fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK) |
                  (value & FD_DSR_DRATEMASK);
}

B
Blue Swirl 已提交
1509
static int fdctrl_media_changed(FDrive *drv)
B
bellard 已提交
1510
{
1511
    return drv->media_changed;
B
bellard 已提交
1512 1513
}

B
bellard 已提交
1514
/* Digital input register : 0x07 (read-only) */
B
Blue Swirl 已提交
1515
static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
B
bellard 已提交
1516 1517 1518
{
    uint32_t retval = 0;

1519
    if (fdctrl_media_changed(get_cur_drv(fdctrl))) {
1520
        retval |= FD_DIR_DSKCHG;
1521
    }
1522
    if (retval != 0) {
1523
        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
1524
    }
B
bellard 已提交
1525 1526 1527 1528

    return retval;
}

1529 1530
/* Clear the FIFO and update the state for receiving the next command */
static void fdctrl_to_command_phase(FDCtrl *fdctrl)
B
bellard 已提交
1531
{
K
Kevin Wolf 已提交
1532
    fdctrl->phase = FD_PHASE_COMMAND;
1533 1534
    fdctrl->data_dir = FD_DIR_WRITE;
    fdctrl->data_pos = 0;
K
Kevin Wolf 已提交
1535
    fdctrl->data_len = 1; /* Accept command byte, adjust for params later */
B
blueswir1 已提交
1536
    fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
K
Kevin Wolf 已提交
1537
    fdctrl->msr |= FD_MSR_RQM;
B
bellard 已提交
1538 1539
}

1540 1541 1542
/* Update the state to allow the guest to read out the command status.
 * @fifo_len is the number of result bytes to be read out. */
static void fdctrl_to_result_phase(FDCtrl *fdctrl, int fifo_len)
B
bellard 已提交
1543
{
K
Kevin Wolf 已提交
1544
    fdctrl->phase = FD_PHASE_RESULT;
1545 1546 1547
    fdctrl->data_dir = FD_DIR_READ;
    fdctrl->data_len = fifo_len;
    fdctrl->data_pos = 0;
B
blueswir1 已提交
1548
    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
B
bellard 已提交
1549 1550 1551
}

/* Set an error: unimplemented/unknown command */
B
Blue Swirl 已提交
1552
static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
B
bellard 已提交
1553
{
B
Blue Swirl 已提交
1554 1555
    qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
                  fdctrl->fifo[0]);
1556
    fdctrl->fifo[0] = FD_SR0_INVCMD;
1557
    fdctrl_to_result_phase(fdctrl, 1);
B
bellard 已提交
1558 1559
}

1560 1561 1562 1563
/* Seek to next sector
 * returns 0 when end of track reached (for DBL_SIDES on head 1)
 * otherwise returns 1
 */
B
Blue Swirl 已提交
1564
static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
B
blueswir1 已提交
1565 1566 1567 1568 1569 1570
{
    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
                   cur_drv->head, cur_drv->track, cur_drv->sect,
                   fd_sector(cur_drv));
    /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
       error in fact */
1571 1572 1573 1574 1575 1576 1577 1578 1579
    uint8_t new_head = cur_drv->head;
    uint8_t new_track = cur_drv->track;
    uint8_t new_sect = cur_drv->sect;

    int ret = 1;

    if (new_sect >= cur_drv->last_sect ||
        new_sect == fdctrl->eot) {
        new_sect = 1;
B
blueswir1 已提交
1580
        if (FD_MULTI_TRACK(fdctrl->data_state)) {
1581
            if (new_head == 0 &&
B
blueswir1 已提交
1582
                (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1583
                new_head = 1;
B
blueswir1 已提交
1584
            } else {
1585 1586
                new_head = 0;
                new_track++;
1587
                fdctrl->status0 |= FD_SR0_SEEK;
1588 1589 1590
                if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
                    ret = 0;
                }
B
blueswir1 已提交
1591 1592
            }
        } else {
1593
            fdctrl->status0 |= FD_SR0_SEEK;
1594 1595 1596 1597 1598 1599
            new_track++;
            ret = 0;
        }
        if (ret == 1) {
            FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
                    new_head, new_track, new_sect, fd_sector(cur_drv));
B
blueswir1 已提交
1600 1601
        }
    } else {
1602
        new_sect++;
B
blueswir1 已提交
1603
    }
1604 1605
    fd_seek(cur_drv, new_head, new_track, new_sect, 1);
    return ret;
B
blueswir1 已提交
1606 1607
}

B
bellard 已提交
1608
/* Callback for transfer end (stop or abort) */
B
Blue Swirl 已提交
1609 1610
static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
                                 uint8_t status1, uint8_t status2)
B
bellard 已提交
1611
{
B
Blue Swirl 已提交
1612
    FDrive *cur_drv;
1613
    cur_drv = get_cur_drv(fdctrl);
H
Hervé Poussineau 已提交
1614 1615 1616 1617 1618 1619 1620

    fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
    fdctrl->status0 |= GET_CUR_DRV(fdctrl);
    if (cur_drv->head) {
        fdctrl->status0 |= FD_SR0_HEAD;
    }
    fdctrl->status0 |= status0;
P
Pavel Hrdina 已提交
1621

B
bellard 已提交
1622
    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
P
Pavel Hrdina 已提交
1623 1624
                   status0, status1, status2, fdctrl->status0);
    fdctrl->fifo[0] = fdctrl->status0;
1625 1626 1627 1628 1629 1630 1631
    fdctrl->fifo[1] = status1;
    fdctrl->fifo[2] = status2;
    fdctrl->fifo[3] = cur_drv->track;
    fdctrl->fifo[4] = cur_drv->head;
    fdctrl->fifo[5] = cur_drv->sect;
    fdctrl->fifo[6] = FD_SECTOR_SC;
    fdctrl->data_dir = FD_DIR_READ;
1632
    if (fdctrl->dma_chann != -1 && !(fdctrl->msr & FD_MSR_NONDMA)) {
1633 1634
        IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
        k->release_DREQ(fdctrl->dma, fdctrl->dma_chann);
1635
    }
B
blueswir1 已提交
1636
    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
B
blueswir1 已提交
1637
    fdctrl->msr &= ~FD_MSR_NONDMA;
1638

1639
    fdctrl_to_result_phase(fdctrl, 7);
1640
    fdctrl_raise_irq(fdctrl);
B
bellard 已提交
1641 1642 1643
}

/* Prepare a data transfer (either DMA or FIFO) */
B
Blue Swirl 已提交
1644
static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
B
bellard 已提交
1645
{
B
Blue Swirl 已提交
1646
    FDrive *cur_drv;
B
bellard 已提交
1647 1648
    uint8_t kh, kt, ks;

B
blueswir1 已提交
1649
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1650 1651 1652 1653
    cur_drv = get_cur_drv(fdctrl);
    kt = fdctrl->fifo[2];
    kh = fdctrl->fifo[3];
    ks = fdctrl->fifo[4];
B
bellard 已提交
1654
    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
B
blueswir1 已提交
1655
                   GET_CUR_DRV(fdctrl), kh, kt, ks,
1656 1657
                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
                                  NUM_SIDES(cur_drv)));
B
blueswir1 已提交
1658
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
B
bellard 已提交
1659 1660
    case 2:
        /* sect too big */
1661
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1662 1663 1664
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1665 1666 1667
        return;
    case 3:
        /* track too big */
B
blueswir1 已提交
1668
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1669 1670 1671
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1672 1673 1674
        return;
    case 4:
        /* No seek enabled */
1675
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1676 1677 1678
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1679 1680
        return;
    case 1:
1681
        fdctrl->status0 |= FD_SR0_SEEK;
B
bellard 已提交
1682 1683 1684 1685
        break;
    default:
        break;
    }
B
blueswir1 已提交
1686

1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
    /* Check the data rate. If the programmed data rate does not match
     * the currently inserted medium, the operation has to fail. */
    if (fdctrl->check_media_rate &&
        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
        FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n",
                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    }

B
bellard 已提交
1700
    /* Set the FIFO state */
1701 1702
    fdctrl->data_dir = direction;
    fdctrl->data_pos = 0;
1703
    assert(fdctrl->msr & FD_MSR_CMDBUSY);
1704 1705 1706 1707
    if (fdctrl->fifo[0] & 0x80)
        fdctrl->data_state |= FD_STATE_MULTI;
    else
        fdctrl->data_state &= ~FD_STATE_MULTI;
H
Hervé Poussineau 已提交
1708
    if (fdctrl->fifo[5] == 0) {
1709 1710
        fdctrl->data_len = fdctrl->fifo[8];
    } else {
1711
        int tmp;
T
ths 已提交
1712
        fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1713
        tmp = (fdctrl->fifo[6] - ks + 1);
1714
        if (fdctrl->fifo[0] & 0x80)
1715
            tmp += fdctrl->fifo[6];
1716
        fdctrl->data_len *= tmp;
1717
    }
1718
    fdctrl->eot = fdctrl->fifo[6];
B
blueswir1 已提交
1719
    if (fdctrl->dor & FD_DOR_DMAEN) {
1720
        /* DMA transfer is enabled. */
1721
        IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
1722 1723 1724

        FLOPPY_DPRINTF("direction=%d (%d - %d)\n",
                       direction, (128 << fdctrl->fifo[5]) *
1725
                       (cur_drv->last_sect - ks + 1), fdctrl->data_len);
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735

        /* No access is allowed until DMA transfer has completed */
        fdctrl->msr &= ~FD_MSR_RQM;
        if (direction != FD_DIR_VERIFY) {
            /*
             * Now, we just have to wait for the DMA controller to
             * recall us...
             */
            k->hold_DREQ(fdctrl->dma, fdctrl->dma_chann);
            k->schedule(fdctrl->dma);
1736
        } else {
1737 1738 1739
            /* Start transfer */
            fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
                    fdctrl->data_len);
B
bellard 已提交
1740
        }
1741
        return;
B
bellard 已提交
1742 1743
    }
    FLOPPY_DPRINTF("start non-DMA transfer\n");
K
Kevin Wolf 已提交
1744
    fdctrl->msr |= FD_MSR_NONDMA | FD_MSR_RQM;
B
blueswir1 已提交
1745 1746
    if (direction != FD_DIR_WRITE)
        fdctrl->msr |= FD_MSR_DIO;
B
bellard 已提交
1747
    /* IO based transfer: calculate len */
1748
    fdctrl_raise_irq(fdctrl);
B
bellard 已提交
1749 1750 1751
}

/* Prepare a transfer of deleted data */
B
Blue Swirl 已提交
1752
static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
B
bellard 已提交
1753
{
B
Blue Swirl 已提交
1754
    qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
B
blueswir1 已提交
1755

B
bellard 已提交
1756 1757 1758
    /* We don't handle deleted data,
     * so we don't return *ANYTHING*
     */
1759
    fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
B
bellard 已提交
1760 1761 1762
}

/* handlers for DMA transfers */
B
bellard 已提交
1763 1764
static int fdctrl_transfer_handler (void *opaque, int nchan,
                                    int dma_pos, int dma_len)
B
bellard 已提交
1765
{
B
Blue Swirl 已提交
1766 1767
    FDCtrl *fdctrl;
    FDrive *cur_drv;
1768
    int len, start_pos, rel_pos;
B
bellard 已提交
1769
    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1770
    IsaDmaClass *k;
B
bellard 已提交
1771

1772
    fdctrl = opaque;
B
blueswir1 已提交
1773
    if (fdctrl->msr & FD_MSR_RQM) {
B
bellard 已提交
1774 1775 1776
        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
        return 0;
    }
1777
    k = ISADMA_GET_CLASS(fdctrl->dma);
1778 1779 1780
    cur_drv = get_cur_drv(fdctrl);
    if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
        fdctrl->data_dir == FD_DIR_SCANH)
B
blueswir1 已提交
1781
        status2 = FD_SR2_SNS;
B
bellard 已提交
1782 1783
    if (dma_len > fdctrl->data_len)
        dma_len = fdctrl->data_len;
1784
    if (cur_drv->blk == NULL) {
1785
        if (fdctrl->data_dir == FD_DIR_WRITE)
1786
            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1787
        else
1788
            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1789
        len = 0;
1790 1791
        goto transfer_error;
    }
1792
    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
B
bellard 已提交
1793 1794
    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
        len = dma_len - fdctrl->data_pos;
1795 1796
        if (len + rel_pos > FD_SECTOR_LEN)
            len = FD_SECTOR_LEN - rel_pos;
B
bellard 已提交
1797 1798
        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
B
blueswir1 已提交
1799
                       fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
1800
                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1801
                       fd_sector(cur_drv) * FD_SECTOR_LEN);
1802
        if (fdctrl->data_dir != FD_DIR_WRITE ||
1803
            len < FD_SECTOR_LEN || rel_pos != 0) {
1804
            /* READ & SCAN commands and realign to a sector for WRITE */
1805 1806
            if (blk_pread(cur_drv->blk, fd_offset(cur_drv),
                          fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) {
B
bellard 已提交
1807 1808 1809
                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
                               fd_sector(cur_drv));
                /* Sure, image size is too small... */
1810
                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
B
bellard 已提交
1811
            }
1812
        }
1813 1814 1815
        switch (fdctrl->data_dir) {
        case FD_DIR_READ:
            /* READ commands */
1816 1817
            k->write_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
                            fdctrl->data_pos, len);
1818 1819
            break;
        case FD_DIR_WRITE:
1820
            /* WRITE commands */
1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
            if (cur_drv->ro) {
                /* Handle readonly medium early, no need to do DMA, touch the
                 * LED or attempt any writes. A real floppy doesn't attempt
                 * to write to readonly media either. */
                fdctrl_stop_transfer(fdctrl,
                                     FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW,
                                     0x00);
                goto transfer_error;
            }

1831 1832
            k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
                           fdctrl->data_pos, len);
1833 1834
            if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv),
                           fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) {
B
Blue Swirl 已提交
1835 1836
                FLOPPY_DPRINTF("error writing sector %d\n",
                               fd_sector(cur_drv));
1837
                fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1838
                goto transfer_error;
1839
            }
1840
            break;
H
Hervé Poussineau 已提交
1841 1842 1843
        case FD_DIR_VERIFY:
            /* VERIFY commands */
            break;
1844 1845
        default:
            /* SCAN commands */
1846
            {
1847
                uint8_t tmpbuf[FD_SECTOR_LEN];
1848
                int ret;
1849 1850
                k->read_memory(fdctrl->dma, nchan, tmpbuf, fdctrl->data_pos,
                               len);
1851
                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
B
bellard 已提交
1852
                if (ret == 0) {
B
blueswir1 已提交
1853
                    status2 = FD_SR2_SEH;
B
bellard 已提交
1854 1855
                    goto end_transfer;
                }
1856 1857
                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
B
bellard 已提交
1858 1859 1860 1861
                    status2 = 0x00;
                    goto end_transfer;
                }
            }
1862
            break;
B
bellard 已提交
1863
        }
1864 1865
        fdctrl->data_pos += len;
        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1866
        if (rel_pos == 0) {
B
bellard 已提交
1867
            /* Seek to next sector */
B
blueswir1 已提交
1868 1869
            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
                break;
B
bellard 已提交
1870 1871
        }
    }
1872
 end_transfer:
1873 1874
    len = fdctrl->data_pos - start_pos;
    FLOPPY_DPRINTF("end transfer %d %d %d\n",
1875
                   fdctrl->data_pos, len, fdctrl->data_len);
1876 1877 1878
    if (fdctrl->data_dir == FD_DIR_SCANE ||
        fdctrl->data_dir == FD_DIR_SCANL ||
        fdctrl->data_dir == FD_DIR_SCANH)
B
blueswir1 已提交
1879
        status2 = FD_SR2_SEH;
1880
    fdctrl->data_len -= len;
1881
    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1882
 transfer_error:
B
bellard 已提交
1883

1884
    return len;
B
bellard 已提交
1885 1886 1887
}

/* Data register : 0x05 */
B
Blue Swirl 已提交
1888
static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
B
bellard 已提交
1889
{
B
Blue Swirl 已提交
1890
    FDrive *cur_drv;
B
bellard 已提交
1891
    uint32_t retval = 0;
1892
    uint32_t pos;
B
bellard 已提交
1893

1894
    cur_drv = get_cur_drv(fdctrl);
B
blueswir1 已提交
1895 1896
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
    if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
B
Blue Swirl 已提交
1897
        FLOPPY_DPRINTF("error: controller not ready for reading\n");
B
bellard 已提交
1898 1899
        return 0;
    }
1900 1901 1902 1903

    /* If data_len spans multiple sectors, the current position in the FIFO
     * wraps around while fdctrl->data_pos is the real position in the whole
     * request. */
1904
    pos = fdctrl->data_pos;
1905
    pos %= FD_SECTOR_LEN;
1906 1907 1908 1909

    switch (fdctrl->phase) {
    case FD_PHASE_EXECUTION:
        assert(fdctrl->msr & FD_MSR_NONDMA);
B
bellard 已提交
1910
        if (pos == 0) {
B
blueswir1 已提交
1911 1912 1913 1914 1915 1916
            if (fdctrl->data_pos != 0)
                if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
                    FLOPPY_DPRINTF("error seeking to next sector %d\n",
                                   fd_sector(cur_drv));
                    return 0;
                }
1917 1918
            if (blk_pread(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
                          BDRV_SECTOR_SIZE)
1919
                < 0) {
B
blueswir1 已提交
1920 1921 1922 1923 1924
                FLOPPY_DPRINTF("error getting sector %d\n",
                               fd_sector(cur_drv));
                /* Sure, image size is too small... */
                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
            }
B
bellard 已提交
1925
        }
1926 1927

        if (++fdctrl->data_pos == fdctrl->data_len) {
K
Kevin Wolf 已提交
1928
            fdctrl->msr &= ~FD_MSR_RQM;
1929
            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1930 1931 1932 1933 1934 1935
        }
        break;

    case FD_PHASE_RESULT:
        assert(!(fdctrl->msr & FD_MSR_NONDMA));
        if (++fdctrl->data_pos == fdctrl->data_len) {
K
Kevin Wolf 已提交
1936
            fdctrl->msr &= ~FD_MSR_RQM;
1937
            fdctrl_to_command_phase(fdctrl);
1938 1939
            fdctrl_reset_irq(fdctrl);
        }
1940 1941 1942 1943 1944
        break;

    case FD_PHASE_COMMAND:
    default:
        abort();
B
bellard 已提交
1945
    }
1946 1947

    retval = fdctrl->fifo[pos];
B
bellard 已提交
1948 1949 1950 1951 1952
    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);

    return retval;
}

B
Blue Swirl 已提交
1953
static void fdctrl_format_sector(FDCtrl *fdctrl)
B
bellard 已提交
1954
{
B
Blue Swirl 已提交
1955
    FDrive *cur_drv;
1956
    uint8_t kh, kt, ks;
B
bellard 已提交
1957

B
blueswir1 已提交
1958
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1959 1960 1961 1962 1963
    cur_drv = get_cur_drv(fdctrl);
    kt = fdctrl->fifo[6];
    kh = fdctrl->fifo[7];
    ks = fdctrl->fifo[8];
    FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
B
blueswir1 已提交
1964
                   GET_CUR_DRV(fdctrl), kh, kt, ks,
1965 1966
                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
                                  NUM_SIDES(cur_drv)));
1967
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
1968 1969
    case 2:
        /* sect too big */
1970
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1971 1972 1973 1974 1975 1976
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 3:
        /* track too big */
B
blueswir1 已提交
1977
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1978 1979 1980 1981 1982 1983
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 4:
        /* No seek enabled */
1984
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1985 1986 1987 1988 1989
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 1:
1990
        fdctrl->status0 |= FD_SR0_SEEK;
1991 1992 1993 1994 1995
        break;
    default:
        break;
    }
    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1996
    if (cur_drv->blk == NULL ||
1997 1998
        blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
                   BDRV_SECTOR_SIZE, 0) < 0) {
B
Blue Swirl 已提交
1999
        FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
2000
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
2001
    } else {
2002 2003 2004
        if (cur_drv->sect == cur_drv->last_sect) {
            fdctrl->data_state &= ~FD_STATE_FORMAT;
            /* Last sector done */
2005
            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2006 2007 2008 2009 2010
        } else {
            /* More to do */
            fdctrl->data_pos = 0;
            fdctrl->data_len = 4;
        }
2011 2012 2013
    }
}

B
Blue Swirl 已提交
2014
static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
2015 2016 2017
{
    fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
    fdctrl->fifo[0] = fdctrl->lock << 4;
2018
    fdctrl_to_result_phase(fdctrl, 1);
2019 2020
}

B
Blue Swirl 已提交
2021
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
2022
{
B
Blue Swirl 已提交
2023
    FDrive *cur_drv = get_cur_drv(fdctrl);
2024 2025 2026 2027

    /* Drives position */
    fdctrl->fifo[0] = drv0(fdctrl)->track;
    fdctrl->fifo[1] = drv1(fdctrl)->track;
B
blueswir1 已提交
2028 2029 2030 2031
#if MAX_FD == 4
    fdctrl->fifo[2] = drv2(fdctrl)->track;
    fdctrl->fifo[3] = drv3(fdctrl)->track;
#else
2032 2033
    fdctrl->fifo[2] = 0;
    fdctrl->fifo[3] = 0;
B
blueswir1 已提交
2034
#endif
2035 2036
    /* timers */
    fdctrl->fifo[4] = fdctrl->timer0;
B
blueswir1 已提交
2037
    fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
2038 2039 2040 2041 2042
    fdctrl->fifo[6] = cur_drv->last_sect;
    fdctrl->fifo[7] = (fdctrl->lock << 7) |
        (cur_drv->perpendicular << 2);
    fdctrl->fifo[8] = fdctrl->config;
    fdctrl->fifo[9] = fdctrl->precomp_trk;
2043
    fdctrl_to_result_phase(fdctrl, 10);
2044 2045
}

B
Blue Swirl 已提交
2046
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
2047 2048 2049
{
    /* Controller's version */
    fdctrl->fifo[0] = fdctrl->version;
2050
    fdctrl_to_result_phase(fdctrl, 1);
2051 2052
}

B
Blue Swirl 已提交
2053
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
2054 2055
{
    fdctrl->fifo[0] = 0x41; /* Stepping 1 */
2056
    fdctrl_to_result_phase(fdctrl, 1);
2057 2058
}

B
Blue Swirl 已提交
2059
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
2060
{
B
Blue Swirl 已提交
2061
    FDrive *cur_drv = get_cur_drv(fdctrl);
2062 2063 2064 2065

    /* Drives position */
    drv0(fdctrl)->track = fdctrl->fifo[3];
    drv1(fdctrl)->track = fdctrl->fifo[4];
B
blueswir1 已提交
2066 2067 2068 2069
#if MAX_FD == 4
    drv2(fdctrl)->track = fdctrl->fifo[5];
    drv3(fdctrl)->track = fdctrl->fifo[6];
#endif
2070 2071 2072 2073 2074 2075 2076 2077 2078
    /* timers */
    fdctrl->timer0 = fdctrl->fifo[7];
    fdctrl->timer1 = fdctrl->fifo[8];
    cur_drv->last_sect = fdctrl->fifo[9];
    fdctrl->lock = fdctrl->fifo[10] >> 7;
    cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
    fdctrl->config = fdctrl->fifo[11];
    fdctrl->precomp_trk = fdctrl->fifo[12];
    fdctrl->pwrd = fdctrl->fifo[13];
2079
    fdctrl_to_command_phase(fdctrl);
2080 2081
}

B
Blue Swirl 已提交
2082
static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
2083
{
B
Blue Swirl 已提交
2084
    FDrive *cur_drv = get_cur_drv(fdctrl);
2085 2086 2087 2088 2089 2090

    fdctrl->fifo[0] = 0;
    fdctrl->fifo[1] = 0;
    /* Drives position */
    fdctrl->fifo[2] = drv0(fdctrl)->track;
    fdctrl->fifo[3] = drv1(fdctrl)->track;
B
blueswir1 已提交
2091 2092 2093 2094
#if MAX_FD == 4
    fdctrl->fifo[4] = drv2(fdctrl)->track;
    fdctrl->fifo[5] = drv3(fdctrl)->track;
#else
2095 2096
    fdctrl->fifo[4] = 0;
    fdctrl->fifo[5] = 0;
B
blueswir1 已提交
2097
#endif
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
    /* timers */
    fdctrl->fifo[6] = fdctrl->timer0;
    fdctrl->fifo[7] = fdctrl->timer1;
    fdctrl->fifo[8] = cur_drv->last_sect;
    fdctrl->fifo[9] = (fdctrl->lock << 7) |
        (cur_drv->perpendicular << 2);
    fdctrl->fifo[10] = fdctrl->config;
    fdctrl->fifo[11] = fdctrl->precomp_trk;
    fdctrl->fifo[12] = fdctrl->pwrd;
    fdctrl->fifo[13] = 0;
    fdctrl->fifo[14] = 0;
2109
    fdctrl_to_result_phase(fdctrl, 15);
2110 2111
}

B
Blue Swirl 已提交
2112
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
2113
{
B
Blue Swirl 已提交
2114
    FDrive *cur_drv = get_cur_drv(fdctrl);
2115 2116

    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2117 2118
    timer_mod(fdctrl->result_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
             (NANOSECONDS_PER_SECOND / 50));
2119 2120
}

B
Blue Swirl 已提交
2121
static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
2122
{
B
Blue Swirl 已提交
2123
    FDrive *cur_drv;
2124

B
blueswir1 已提交
2125
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
    cur_drv = get_cur_drv(fdctrl);
    fdctrl->data_state |= FD_STATE_FORMAT;
    if (fdctrl->fifo[0] & 0x80)
        fdctrl->data_state |= FD_STATE_MULTI;
    else
        fdctrl->data_state &= ~FD_STATE_MULTI;
    cur_drv->bps =
        fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
#if 0
    cur_drv->last_sect =
        cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
        fdctrl->fifo[3] / 2;
#else
    cur_drv->last_sect = fdctrl->fifo[3];
#endif
    /* TODO: implement format using DMA expected by the Bochs BIOS
     * and Linux fdformat (read 3 bytes per sector via DMA and fill
     * the sector with the specified fill byte
     */
    fdctrl->data_state &= ~FD_STATE_FORMAT;
    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
}

B
Blue Swirl 已提交
2149
static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
2150 2151 2152
{
    fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
    fdctrl->timer1 = fdctrl->fifo[2] >> 1;
B
blueswir1 已提交
2153 2154 2155 2156
    if (fdctrl->fifo[2] & 1)
        fdctrl->dor &= ~FD_DOR_DMAEN;
    else
        fdctrl->dor |= FD_DOR_DMAEN;
2157
    /* No result back */
2158
    fdctrl_to_command_phase(fdctrl);
2159 2160
}

B
Blue Swirl 已提交
2161
static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
2162
{
B
Blue Swirl 已提交
2163
    FDrive *cur_drv;
2164

B
blueswir1 已提交
2165
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2166 2167 2168 2169 2170 2171
    cur_drv = get_cur_drv(fdctrl);
    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
    /* 1 Byte status back */
    fdctrl->fifo[0] = (cur_drv->ro << 6) |
        (cur_drv->track == 0 ? 0x10 : 0x00) |
        (cur_drv->head << 2) |
B
blueswir1 已提交
2172
        GET_CUR_DRV(fdctrl) |
2173
        0x28;
2174
    fdctrl_to_result_phase(fdctrl, 1);
2175 2176
}

B
Blue Swirl 已提交
2177
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
2178
{
B
Blue Swirl 已提交
2179
    FDrive *cur_drv;
2180

B
blueswir1 已提交
2181
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2182 2183
    cur_drv = get_cur_drv(fdctrl);
    fd_recalibrate(cur_drv);
2184
    fdctrl_to_command_phase(fdctrl);
2185
    /* Raise Interrupt */
2186 2187
    fdctrl->status0 |= FD_SR0_SEEK;
    fdctrl_raise_irq(fdctrl);
2188 2189
}

B
Blue Swirl 已提交
2190
static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
2191
{
B
Blue Swirl 已提交
2192
    FDrive *cur_drv = get_cur_drv(fdctrl);
2193

P
Pavel Hrdina 已提交
2194
    if (fdctrl->reset_sensei > 0) {
2195 2196 2197
        fdctrl->fifo[0] =
            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
        fdctrl->reset_sensei--;
P
Pavel Hrdina 已提交
2198 2199
    } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
        fdctrl->fifo[0] = FD_SR0_INVCMD;
2200
        fdctrl_to_result_phase(fdctrl, 1);
P
Pavel Hrdina 已提交
2201
        return;
2202 2203
    } else {
        fdctrl->fifo[0] =
P
Pavel Hrdina 已提交
2204 2205
                (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
                | GET_CUR_DRV(fdctrl);
2206 2207
    }

2208
    fdctrl->fifo[1] = cur_drv->track;
2209
    fdctrl_to_result_phase(fdctrl, 2);
2210
    fdctrl_reset_irq(fdctrl);
B
blueswir1 已提交
2211
    fdctrl->status0 = FD_SR0_RDYCHG;
2212 2213
}

B
Blue Swirl 已提交
2214
static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
2215
{
B
Blue Swirl 已提交
2216
    FDrive *cur_drv;
2217

B
blueswir1 已提交
2218
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2219
    cur_drv = get_cur_drv(fdctrl);
2220
    fdctrl_to_command_phase(fdctrl);
2221 2222 2223
    /* The seek command just sends step pulses to the drive and doesn't care if
     * there is a medium inserted of if it's banging the head against the drive.
     */
2224
    fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
2225
    /* Raise Interrupt */
2226 2227
    fdctrl->status0 |= FD_SR0_SEEK;
    fdctrl_raise_irq(fdctrl);
2228 2229
}

B
Blue Swirl 已提交
2230
static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
2231
{
B
Blue Swirl 已提交
2232
    FDrive *cur_drv = get_cur_drv(fdctrl);
2233 2234 2235 2236

    if (fdctrl->fifo[1] & 0x80)
        cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
    /* No result back */
2237
    fdctrl_to_command_phase(fdctrl);
2238 2239
}

B
Blue Swirl 已提交
2240
static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
2241 2242 2243 2244
{
    fdctrl->config = fdctrl->fifo[2];
    fdctrl->precomp_trk =  fdctrl->fifo[3];
    /* No result back */
2245
    fdctrl_to_command_phase(fdctrl);
2246 2247
}

B
Blue Swirl 已提交
2248
static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
2249 2250 2251
{
    fdctrl->pwrd = fdctrl->fifo[1];
    fdctrl->fifo[0] = fdctrl->fifo[1];
2252
    fdctrl_to_result_phase(fdctrl, 1);
2253 2254
}

B
Blue Swirl 已提交
2255
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
2256 2257
{
    /* No result back */
2258
    fdctrl_to_command_phase(fdctrl);
2259 2260
}

B
Blue Swirl 已提交
2261
static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
2262
{
B
Blue Swirl 已提交
2263
    FDrive *cur_drv = get_cur_drv(fdctrl);
2264
    uint32_t pos;
2265

2266 2267 2268
    pos = fdctrl->data_pos - 1;
    pos %= FD_SECTOR_LEN;
    if (fdctrl->fifo[pos] & 0x80) {
2269
        /* Command parameters done */
2270
        if (fdctrl->fifo[pos] & 0x40) {
2271 2272 2273
            fdctrl->fifo[0] = fdctrl->fifo[1];
            fdctrl->fifo[2] = 0;
            fdctrl->fifo[3] = 0;
2274
            fdctrl_to_result_phase(fdctrl, 4);
2275
        } else {
2276
            fdctrl_to_command_phase(fdctrl);
2277 2278 2279 2280
        }
    } else if (fdctrl->data_len > 7) {
        /* ERROR */
        fdctrl->fifo[0] = 0x80 |
B
blueswir1 已提交
2281
            (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
2282
        fdctrl_to_result_phase(fdctrl, 1);
2283 2284 2285
    }
}

P
Pavel Hrdina 已提交
2286
static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
2287
{
B
Blue Swirl 已提交
2288
    FDrive *cur_drv;
2289

B
blueswir1 已提交
2290
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2291 2292
    cur_drv = get_cur_drv(fdctrl);
    if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
2293 2294
        fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
                cur_drv->sect, 1);
2295
    } else {
P
Pavel Hrdina 已提交
2296 2297
        fd_seek(cur_drv, cur_drv->head,
                cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
2298
    }
2299
    fdctrl_to_command_phase(fdctrl);
B
blueswir1 已提交
2300
    /* Raise Interrupt */
2301 2302
    fdctrl->status0 |= FD_SR0_SEEK;
    fdctrl_raise_irq(fdctrl);
2303 2304
}

P
Pavel Hrdina 已提交
2305
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
2306
{
B
Blue Swirl 已提交
2307
    FDrive *cur_drv;
2308

B
blueswir1 已提交
2309
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
2310 2311
    cur_drv = get_cur_drv(fdctrl);
    if (fdctrl->fifo[2] > cur_drv->track) {
2312
        fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
2313
    } else {
P
Pavel Hrdina 已提交
2314 2315
        fd_seek(cur_drv, cur_drv->head,
                cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
2316
    }
2317
    fdctrl_to_command_phase(fdctrl);
2318
    /* Raise Interrupt */
2319 2320
    fdctrl->status0 |= FD_SR0_SEEK;
    fdctrl_raise_irq(fdctrl);
2321 2322
}

K
Kevin Wolf 已提交
2323 2324 2325
/*
 * Handlers for the execution phase of each command
 */
2326
typedef struct FDCtrlCommand {
B
blueswir1 已提交
2327 2328 2329 2330
    uint8_t value;
    uint8_t mask;
    const char* name;
    int parameters;
B
Blue Swirl 已提交
2331
    void (*handler)(FDCtrl *fdctrl, int direction);
B
blueswir1 已提交
2332
    int direction;
2333 2334 2335
} FDCtrlCommand;

static const FDCtrlCommand handlers[] = {
B
blueswir1 已提交
2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346
    { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
    { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
    { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
    { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
    { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
    { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
    { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
    { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
    { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
    { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
    { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
H
Hervé Poussineau 已提交
2347
    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
B
blueswir1 已提交
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371
    { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
    { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
    { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
    { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
    { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
    { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
    { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
    { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
    { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
    { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
    { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
    { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
    { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
    { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
    { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
    { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
    { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
    { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
    { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
    { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
};
/* Associate command to an index in the 'handlers' array */
static uint8_t command_to_handler[256];

2372 2373 2374 2375 2376 2377 2378 2379 2380
static const FDCtrlCommand *get_command(uint8_t cmd)
{
    int idx;

    idx = command_to_handler[cmd];
    FLOPPY_DPRINTF("%s command\n", handlers[idx].name);
    return &handlers[idx];
}

B
Blue Swirl 已提交
2381
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
2382
{
B
Blue Swirl 已提交
2383
    FDrive *cur_drv;
2384
    const FDCtrlCommand *cmd;
2385
    uint32_t pos;
2386

B
bellard 已提交
2387
    /* Reset mode */
B
blueswir1 已提交
2388
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
2389
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
B
bellard 已提交
2390 2391
        return;
    }
B
blueswir1 已提交
2392
    if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
B
Blue Swirl 已提交
2393
        FLOPPY_DPRINTF("error: controller not ready for writing\n");
B
bellard 已提交
2394 2395
        return;
    }
B
blueswir1 已提交
2396
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
2397

2398 2399 2400 2401 2402 2403 2404 2405 2406
    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);

    /* If data_len spans multiple sectors, the current position in the FIFO
     * wraps around while fdctrl->data_pos is the real position in the whole
     * request. */
    pos = fdctrl->data_pos++;
    pos %= FD_SECTOR_LEN;
    fdctrl->fifo[pos] = value;

K
Kevin Wolf 已提交
2407 2408 2409 2410
    if (fdctrl->data_pos == fdctrl->data_len) {
        fdctrl->msr &= ~FD_MSR_RQM;
    }

2411 2412 2413 2414 2415
    switch (fdctrl->phase) {
    case FD_PHASE_EXECUTION:
        /* For DMA requests, RQM should be cleared during execution phase, so
         * we would have errored out above. */
        assert(fdctrl->msr & FD_MSR_NONDMA);
2416

B
bellard 已提交
2417
        /* FIFO data write */
2418
        if (pos == FD_SECTOR_LEN - 1 ||
2419
            fdctrl->data_pos == fdctrl->data_len) {
B
blueswir1 已提交
2420
            cur_drv = get_cur_drv(fdctrl);
2421 2422
            if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
                           BDRV_SECTOR_SIZE, 0) < 0) {
B
Blue Swirl 已提交
2423 2424
                FLOPPY_DPRINTF("error writing sector %d\n",
                               fd_sector(cur_drv));
2425
                break;
B
blueswir1 已提交
2426
            }
B
blueswir1 已提交
2427 2428 2429
            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
                FLOPPY_DPRINTF("error seeking to next sector %d\n",
                               fd_sector(cur_drv));
2430
                break;
B
blueswir1 已提交
2431
            }
B
bellard 已提交
2432
        }
2433 2434 2435

        /* Switch to result phase when done with the transfer */
        if (fdctrl->data_pos == fdctrl->data_len) {
2436
            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2437
        }
2438
        break;
B
blueswir1 已提交
2439

2440 2441
    case FD_PHASE_COMMAND:
        assert(!(fdctrl->msr & FD_MSR_NONDMA));
2442
        assert(fdctrl->data_pos < FD_SECTOR_LEN);
2443

2444 2445 2446 2447 2448
        if (pos == 0) {
            /* The first byte specifies the command. Now we start reading
             * as many parameters as this command requires. */
            cmd = get_command(value);
            fdctrl->data_len = cmd->parameters + 1;
K
Kevin Wolf 已提交
2449 2450 2451
            if (cmd->parameters) {
                fdctrl->msr |= FD_MSR_RQM;
            }
2452
            fdctrl->msr |= FD_MSR_CMDBUSY;
B
bellard 已提交
2453
        }
2454

2455
        if (fdctrl->data_pos == fdctrl->data_len) {
2456
            /* We have all parameters now, execute the command */
2457
            fdctrl->phase = FD_PHASE_EXECUTION;
2458

2459 2460 2461 2462 2463
            if (fdctrl->data_state & FD_STATE_FORMAT) {
                fdctrl_format_sector(fdctrl);
                break;
            }

2464 2465 2466
            cmd = get_command(fdctrl->fifo[0]);
            FLOPPY_DPRINTF("Calling handler for '%s'\n", cmd->name);
            cmd->handler(fdctrl, cmd->direction);
2467 2468 2469 2470 2471 2472
        }
        break;

    case FD_PHASE_RESULT:
    default:
        abort();
B
bellard 已提交
2473 2474
    }
}
2475 2476 2477

static void fdctrl_result_timer(void *opaque)
{
B
Blue Swirl 已提交
2478 2479
    FDCtrl *fdctrl = opaque;
    FDrive *cur_drv = get_cur_drv(fdctrl);
2480

2481 2482 2483 2484 2485 2486 2487
    /* Pretend we are spinning.
     * This is needed for Coherent, which uses READ ID to check for
     * sector interleaving.
     */
    if (cur_drv->last_sect != 0) {
        cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
    }
2488 2489 2490 2491 2492 2493 2494 2495 2496
    /* READ_ID can't automatically succeed! */
    if (fdctrl->check_media_rate &&
        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
        FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
    } else {
        fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
    }
2497
}
B
blueswir1 已提交
2498 2499

/* Init functions */
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522

static void fdctrl_init_drives(FloppyBus *bus, DriveInfo **fds)
{
    DeviceState *dev;
    int i;

    for (i = 0; i < MAX_FD; i++) {
        if (fds[i]) {
            dev = qdev_new("floppy");
            qdev_prop_set_uint32(dev, "unit", i);
            qdev_prop_set_enum(dev, "drive-type", FLOPPY_DRIVE_TYPE_AUTO);
            qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[i]),
                                &error_fatal);
            qdev_realize_and_unref(dev, &bus->bus, &error_fatal);
        }
    }
}

void isa_fdc_init_drives(ISADevice *fdc, DriveInfo **fds)
{
    fdctrl_init_drives(&ISA_FDC(fdc)->state.bus, fds);
}

2523 2524
static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev,
                                  Error **errp)
B
blueswir1 已提交
2525
{
B
Blue Swirl 已提交
2526
    unsigned int i;
2527
    FDrive *drive;
K
Kevin Wolf 已提交
2528
    DeviceState *dev;
2529
    BlockBackend *blk;
K
Kevin Wolf 已提交
2530
    Error *local_err = NULL;
B
blueswir1 已提交
2531 2532

    for (i = 0; i < MAX_FD; i++) {
2533
        drive = &fdctrl->drives[i];
2534
        drive->fdctrl = fdctrl;
2535

K
Kevin Wolf 已提交
2536 2537
        /* If the drive is not present, we skip creating the qdev device, but
         * still have to initialise the controller. */
2538 2539
        blk = fdctrl->qdev_for_drives[i].blk;
        if (!blk) {
K
Kevin Wolf 已提交
2540 2541 2542
            fd_init(drive);
            fd_revalidate(drive);
            continue;
2543 2544
        }

2545
        dev = qdev_new("floppy");
K
Kevin Wolf 已提交
2546
        qdev_prop_set_uint32(dev, "unit", i);
2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559
        qdev_prop_set_enum(dev, "drive-type", fdctrl->qdev_for_drives[i].type);

        blk_ref(blk);
        blk_detach_dev(blk, fdc_dev);
        fdctrl->qdev_for_drives[i].blk = NULL;
        qdev_prop_set_drive(dev, "drive", blk, &local_err);
        blk_unref(blk);

        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }

2560
        qdev_realize_and_unref(dev, &fdctrl->bus.bus, &local_err);
K
Kevin Wolf 已提交
2561 2562 2563
        if (local_err) {
            error_propagate(errp, local_err);
            return;
2564
        }
B
blueswir1 已提交
2565 2566 2567
    }
}

M
Markus Armbruster 已提交
2568 2569
ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
{
A
Andreas Färber 已提交
2570
    ISADevice *isadev;
M
Markus Armbruster 已提交
2571

2572
    isadev = isa_try_new(TYPE_ISA_FDC);
A
Andreas Färber 已提交
2573
    if (!isadev) {
M
Markus Armbruster 已提交
2574 2575
        return NULL;
    }
2576
    isa_realize_and_unref(isadev, bus, &error_fatal);
M
Markus Armbruster 已提交
2577

2578
    isa_fdc_init_drives(isadev, fds);
A
Andreas Färber 已提交
2579
    return isadev;
M
Markus Armbruster 已提交
2580 2581
}

B
Blue Swirl 已提交
2582
void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
A
Avi Kivity 已提交
2583
                        hwaddr mmio_base, DriveInfo **fds)
G
Gerd Hoffmann 已提交
2584
{
B
Blue Swirl 已提交
2585
    FDCtrl *fdctrl;
G
Gerd Hoffmann 已提交
2586
    DeviceState *dev;
H
Hu Tao 已提交
2587
    SysBusDevice *sbd;
B
Blue Swirl 已提交
2588
    FDCtrlSysBus *sys;
G
Gerd Hoffmann 已提交
2589

2590
    dev = qdev_new("sysbus-fdc");
H
Hu Tao 已提交
2591
    sys = SYSBUS_FDC(dev);
2592 2593
    fdctrl = &sys->state;
    fdctrl->dma_chann = dma_chann; /* FIXME */
H
Hu Tao 已提交
2594
    sbd = SYS_BUS_DEVICE(dev);
2595
    sysbus_realize_and_unref(sbd, &error_fatal);
H
Hu Tao 已提交
2596 2597
    sysbus_connect_irq(sbd, 0, irq);
    sysbus_mmio_map(sbd, 0, mmio_base);
2598 2599

    fdctrl_init_drives(&sys->state.bus, fds);
B
blueswir1 已提交
2600 2601
}

A
Avi Kivity 已提交
2602
void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
B
Blue Swirl 已提交
2603
                       DriveInfo **fds, qemu_irq *fdc_tc)
B
blueswir1 已提交
2604
{
B
Blue Swirl 已提交
2605
    DeviceState *dev;
B
Blue Swirl 已提交
2606
    FDCtrlSysBus *sys;
B
blueswir1 已提交
2607

2608
    dev = qdev_new("SUNW,fdtwo");
2609
    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
H
Hu Tao 已提交
2610 2611 2612
    sys = SYSBUS_FDC(dev);
    sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq);
    sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base);
B
Blue Swirl 已提交
2613
    *fdc_tc = qdev_get_gpio_in(dev, 0);
2614 2615

    fdctrl_init_drives(&sys->state.bus, fds);
B
blueswir1 已提交
2616
}
B
Blue Swirl 已提交
2617

K
Kevin Wolf 已提交
2618 2619
static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
                                  Error **errp)
B
Blue Swirl 已提交
2620
{
B
Blue Swirl 已提交
2621 2622
    int i, j;
    static int command_tables_inited = 0;
B
Blue Swirl 已提交
2623

J
John Snow 已提交
2624 2625
    if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) {
        error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'");
2626
        return;
J
John Snow 已提交
2627 2628
    }

B
Blue Swirl 已提交
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
    /* Fill 'command_to_handler' lookup table */
    if (!command_tables_inited) {
        command_tables_inited = 1;
        for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
            for (j = 0; j < sizeof(command_to_handler); j++) {
                if ((j & handlers[i].mask) == handlers[i].value) {
                    command_to_handler[j] = i;
                }
            }
        }
    }

    FLOPPY_DPRINTF("init controller\n");
    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
2643
    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
J
Juan Quintela 已提交
2644
    fdctrl->fifo_size = 512;
2645
    fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
2646
                                             fdctrl_result_timer, fdctrl);
B
Blue Swirl 已提交
2647 2648 2649

    fdctrl->version = 0x90; /* Intel 82078 controller */
    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
J
Juan Quintela 已提交
2650
    fdctrl->num_floppies = MAX_FD;
B
Blue Swirl 已提交
2651

2652
    if (fdctrl->dma_chann != -1) {
2653 2654 2655 2656 2657
        IsaDmaClass *k;
        assert(fdctrl->dma);
        k = ISADMA_GET_CLASS(fdctrl->dma);
        k->register_channel(fdctrl->dma, fdctrl->dma_chann,
                            &fdctrl_transfer_handler, fdctrl);
2658
    }
K
Kevin Wolf 已提交
2659 2660

    floppy_bus_create(fdctrl, &fdctrl->bus, dev);
2661
    fdctrl_connect_drives(fdctrl, dev, errp);
B
Blue Swirl 已提交
2662 2663
}

2664
static const MemoryRegionPortio fdc_portio_list[] = {
2665
    { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
2666 2667
    { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
    PORTIO_END_OF_LIST(),
2668 2669
};

2670
static void isabus_fdc_realize(DeviceState *dev, Error **errp)
G
Gerd Hoffmann 已提交
2671
{
2672
    ISADevice *isadev = ISA_DEVICE(dev);
2673
    FDCtrlISABus *isa = ISA_FDC(dev);
B
Blue Swirl 已提交
2674
    FDCtrl *fdctrl = &isa->state;
2675
    Error *err = NULL;
G
Gerd Hoffmann 已提交
2676

2677 2678
    isa_register_portio_list(isadev, &fdctrl->portio_list,
                             isa->iobase, fdc_portio_list, fdctrl,
2679
                             "fdc");
2680

2681
    isa_init_irq(isadev, &fdctrl->irq, isa->irq);
2682
    fdctrl->dma_chann = isa->dma;
2683 2684
    if (fdctrl->dma_chann != -1) {
        fdctrl->dma = isa_get_dma(isa_bus_from_device(isadev), isa->dma);
2685 2686 2687 2688
        if (!fdctrl->dma) {
            error_setg(errp, "ISA controller does not support DMA");
            return;
        }
2689
    }
G
Gerd Hoffmann 已提交
2690

2691
    qdev_set_legacy_instance_id(dev, isa->iobase, 2);
K
Kevin Wolf 已提交
2692
    fdctrl_realize_common(dev, fdctrl, &err);
2693 2694
    if (err != NULL) {
        error_propagate(errp, err);
2695 2696
        return;
    }
G
Gerd Hoffmann 已提交
2697 2698
}

H
Hu Tao 已提交
2699
static void sysbus_fdc_initfn(Object *obj)
B
Blue Swirl 已提交
2700
{
2701
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
H
Hu Tao 已提交
2702
    FDCtrlSysBus *sys = SYSBUS_FDC(obj);
B
Blue Swirl 已提交
2703
    FDCtrl *fdctrl = &sys->state;
B
Blue Swirl 已提交
2704

2705 2706
    fdctrl->dma_chann = -1;

H
Hu Tao 已提交
2707
    memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_ops, fdctrl,
2708
                          "fdc", 0x08);
2709
    sysbus_init_mmio(sbd, &fdctrl->iomem);
H
Hu Tao 已提交
2710 2711
}

2712
static void sun4m_fdc_initfn(Object *obj)
H
Hu Tao 已提交
2713
{
2714 2715
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    FDCtrlSysBus *sys = SYSBUS_FDC(obj);
H
Hu Tao 已提交
2716 2717
    FDCtrl *fdctrl = &sys->state;

H
Hervé Poussineau 已提交
2718 2719
    fdctrl->dma_chann = -1;

2720 2721 2722
    memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
                          fdctrl, "fdctrl", 0x08);
    sysbus_init_mmio(sbd, &fdctrl->iomem);
H
Hu Tao 已提交
2723
}
B
Blue Swirl 已提交
2724

2725
static void sysbus_fdc_common_initfn(Object *obj)
H
Hu Tao 已提交
2726
{
2727 2728
    DeviceState *dev = DEVICE(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
H
Hu Tao 已提交
2729 2730 2731
    FDCtrlSysBus *sys = SYSBUS_FDC(obj);
    FDCtrl *fdctrl = &sys->state;

2732 2733 2734 2735
    qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */

    sysbus_init_irq(sbd, &fdctrl->irq);
    qdev_init_gpio_in(dev, fdctrl_handle_tc, 1);
B
Blue Swirl 已提交
2736 2737
}

2738
static void sysbus_fdc_common_realize(DeviceState *dev, Error **errp)
B
Blue Swirl 已提交
2739
{
H
Hu Tao 已提交
2740 2741
    FDCtrlSysBus *sys = SYSBUS_FDC(dev);
    FDCtrl *fdctrl = &sys->state;
B
Blue Swirl 已提交
2742

K
Kevin Wolf 已提交
2743
    fdctrl_realize_common(dev, fdctrl, errp);
B
Blue Swirl 已提交
2744
}
B
Blue Swirl 已提交
2745

J
John Snow 已提交
2746
FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
K
Kevin Wolf 已提交
2747
{
2748
    FDCtrlISABus *isa = ISA_FDC(fdc);
K
Kevin Wolf 已提交
2749

2750
    return isa->state.drives[i].drive;
K
Kevin Wolf 已提交
2751 2752
}

2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775
void isa_fdc_get_drive_max_chs(FloppyDriveType type,
                               uint8_t *maxc, uint8_t *maxh, uint8_t *maxs)
{
    const FDFormat *fdf;

    *maxc = *maxh = *maxs = 0;
    for (fdf = fd_formats; fdf->drive != FLOPPY_DRIVE_TYPE_NONE; fdf++) {
        if (fdf->drive != type) {
            continue;
        }
        if (*maxc < fdf->max_track) {
            *maxc = fdf->max_track;
        }
        if (*maxh < fdf->max_head) {
            *maxh = fdf->max_head;
        }
        if (*maxs < fdf->last_sect) {
            *maxs = fdf->last_sect;
        }
    }
    (*maxc)--;
}

J
Jan Kiszka 已提交
2776 2777 2778 2779
static const VMStateDescription vmstate_isa_fdc ={
    .name = "fdc",
    .version_id = 2,
    .minimum_version_id = 2,
2780
    .fields = (VMStateField[]) {
J
Jan Kiszka 已提交
2781 2782 2783 2784 2785
        VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

2786
static Property isa_fdc_properties[] = {
2787
    DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
2788 2789
    DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
    DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
2790 2791
    DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.qdev_for_drives[0].blk),
    DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.qdev_for_drives[1].blk),
2792 2793
    DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
                    0, true),
2794
    DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
J
John Snow 已提交
2795 2796
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2797
    DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
J
John Snow 已提交
2798 2799
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2800
    DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
2801
                        FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
J
John Snow 已提交
2802
                        FloppyDriveType),
2803 2804 2805
    DEFINE_PROP_END_OF_LIST(),
};

2806
static void isabus_fdc_class_init(ObjectClass *klass, void *data)
2807
{
2808
    DeviceClass *dc = DEVICE_CLASS(klass);
2809 2810

    dc->realize = isabus_fdc_realize;
2811 2812 2813
    dc->fw_name = "fdc";
    dc->reset = fdctrl_external_reset_isa;
    dc->vmsd = &vmstate_isa_fdc;
2814
    device_class_set_props(dc, isa_fdc_properties);
2815
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
2816 2817
}

2818 2819 2820 2821 2822 2823
static void isabus_fdc_instance_init(Object *obj)
{
    FDCtrlISABus *isa = ISA_FDC(obj);

    device_add_bootindex_property(obj, &isa->bootindexA,
                                  "bootindexA", "/floppy@0",
2824
                                  DEVICE(obj));
2825 2826
    device_add_bootindex_property(obj, &isa->bootindexB,
                                  "bootindexB", "/floppy@1",
2827
                                  DEVICE(obj));
2828 2829
}

2830
static const TypeInfo isa_fdc_info = {
2831
    .name          = TYPE_ISA_FDC,
2832 2833
    .parent        = TYPE_ISA_DEVICE,
    .instance_size = sizeof(FDCtrlISABus),
2834
    .class_init    = isabus_fdc_class_init,
2835
    .instance_init = isabus_fdc_instance_init,
G
Gerd Hoffmann 已提交
2836 2837
};

J
Jan Kiszka 已提交
2838 2839 2840 2841
static const VMStateDescription vmstate_sysbus_fdc ={
    .name = "fdc",
    .version_id = 2,
    .minimum_version_id = 2,
2842
    .fields = (VMStateField[]) {
J
Jan Kiszka 已提交
2843 2844 2845 2846 2847
        VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

2848
static Property sysbus_fdc_properties[] = {
2849 2850
    DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.qdev_for_drives[0].blk),
    DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.qdev_for_drives[1].blk),
2851
    DEFINE_PROP_SIGNED("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type,
J
John Snow 已提交
2852 2853
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2854
    DEFINE_PROP_SIGNED("fdtypeB", FDCtrlSysBus, state.qdev_for_drives[1].type,
J
John Snow 已提交
2855 2856
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2857
    DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
J
John Snow 已提交
2858 2859
                        FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2860
    DEFINE_PROP_END_OF_LIST(),
B
Blue Swirl 已提交
2861 2862
};

2863 2864
static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
{
2865
    DeviceClass *dc = DEVICE_CLASS(klass);
2866

2867
    device_class_set_props(dc, sysbus_fdc_properties);
2868
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
2869 2870
}

2871
static const TypeInfo sysbus_fdc_info = {
2872 2873
    .name          = "sysbus-fdc",
    .parent        = TYPE_SYSBUS_FDC,
H
Hu Tao 已提交
2874
    .instance_init = sysbus_fdc_initfn,
2875
    .class_init    = sysbus_fdc_class_init,
2876 2877 2878
};

static Property sun4m_fdc_properties[] = {
2879
    DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.qdev_for_drives[0].blk),
2880
    DEFINE_PROP_SIGNED("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type,
J
John Snow 已提交
2881 2882
                        FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2883
    DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
J
John Snow 已提交
2884 2885
                        FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
                        FloppyDriveType),
2886 2887 2888 2889 2890
    DEFINE_PROP_END_OF_LIST(),
};

static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
{
2891
    DeviceClass *dc = DEVICE_CLASS(klass);
2892

2893
    device_class_set_props(dc, sun4m_fdc_properties);
2894
    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
2895 2896
}

2897
static const TypeInfo sun4m_fdc_info = {
2898
    .name          = "SUNW,fdtwo",
2899
    .parent        = TYPE_SYSBUS_FDC,
H
Hu Tao 已提交
2900
    .instance_init = sun4m_fdc_initfn,
2901
    .class_init    = sun4m_fdc_class_init,
B
Blue Swirl 已提交
2902 2903
};

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921
static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->realize = sysbus_fdc_common_realize;
    dc->reset = fdctrl_external_reset_sysbus;
    dc->vmsd = &vmstate_sysbus_fdc;
}

static const TypeInfo sysbus_fdc_type_info = {
    .name          = TYPE_SYSBUS_FDC,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(FDCtrlSysBus),
    .instance_init = sysbus_fdc_common_initfn,
    .abstract      = true,
    .class_init    = sysbus_fdc_common_class_init,
};

A
Andreas Färber 已提交
2922
static void fdc_register_types(void)
B
Blue Swirl 已提交
2923
{
2924
    type_register_static(&isa_fdc_info);
2925
    type_register_static(&sysbus_fdc_type_info);
2926 2927
    type_register_static(&sysbus_fdc_info);
    type_register_static(&sun4m_fdc_info);
K
Kevin Wolf 已提交
2928
    type_register_static(&floppy_bus_info);
K
Kevin Wolf 已提交
2929
    type_register_static(&floppy_drive_info);
B
Blue Swirl 已提交
2930 2931
}

A
Andreas Färber 已提交
2932
type_init(fdc_register_types)