fdc.c 60.2 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
pbrook 已提交
30 31
#include "hw.h"
#include "fdc.h"
32
#include "qemu-error.h"
P
pbrook 已提交
33 34
#include "qemu-timer.h"
#include "isa.h"
B
Blue Swirl 已提交
35
#include "sysbus.h"
B
Blue Swirl 已提交
36
#include "qdev-addr.h"
B
Blue Swirl 已提交
37
#include "blockdev.h"
38
#include "sysemu.h"
39
#include "block_int.h"
B
bellard 已提交
40 41 42 43 44 45

/********************************************************/
/* debug Floppy devices */
//#define DEBUG_FLOPPY

#ifdef DEBUG_FLOPPY
46 47
#define FLOPPY_DPRINTF(fmt, ...)                                \
    do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
B
bellard 已提交
48
#else
49
#define FLOPPY_DPRINTF(fmt, ...)
B
bellard 已提交
50 51
#endif

52 53
#define FLOPPY_ERROR(fmt, ...)                                          \
    do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
B
bellard 已提交
54 55 56 57

/********************************************************/
/* Floppy drive emulation                               */

B
blueswir1 已提交
58 59 60
#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))

B
bellard 已提交
61
/* Will always be a fixed parameter for us */
62 63 64
#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 已提交
65 66

/* Floppy disk drive emulation */
B
Blue Swirl 已提交
67
typedef enum FDiskFlags {
68
    FDISK_DBL_SIDES  = 0x01,
B
Blue Swirl 已提交
69
} FDiskFlags;
70

B
Blue Swirl 已提交
71
typedef struct FDrive {
B
bellard 已提交
72 73
    BlockDriverState *bs;
    /* Drive status */
B
Blue Swirl 已提交
74
    FDriveType drive;
B
bellard 已提交
75 76 77 78 79 80
    uint8_t perpendicular;    /* 2.88 MB access mode    */
    /* Position */
    uint8_t head;
    uint8_t track;
    uint8_t sect;
    /* Media */
B
Blue Swirl 已提交
81
    FDiskFlags flags;
B
bellard 已提交
82 83
    uint8_t last_sect;        /* Nb sector per track    */
    uint8_t max_track;        /* Nb of tracks           */
84
    uint16_t bps;             /* Bytes per sector       */
B
bellard 已提交
85
    uint8_t ro;               /* Is read-only           */
86
    uint8_t media_changed;    /* Is media changed       */
B
Blue Swirl 已提交
87
} FDrive;
B
bellard 已提交
88

B
Blue Swirl 已提交
89
static void fd_init(FDrive *drv)
B
bellard 已提交
90 91
{
    /* Drive */
B
bellard 已提交
92
    drv->drive = FDRIVE_DRV_NONE;
B
bellard 已提交
93 94
    drv->perpendicular = 0;
    /* Disk */
95
    drv->last_sect = 0;
B
bellard 已提交
96 97 98
    drv->max_track = 0;
}

B
Blue Swirl 已提交
99 100
static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
                          uint8_t last_sect)
B
bellard 已提交
101 102 103 104 105
{
    return (((track * 2) + head) * last_sect) + sect - 1;
}

/* Returns current position, in sectors, for given drive */
B
Blue Swirl 已提交
106
static int fd_sector(FDrive *drv)
B
bellard 已提交
107
{
B
Blue Swirl 已提交
108
    return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect);
B
bellard 已提交
109 110
}

B
blueswir1 已提交
111 112 113 114 115 116 117
/* 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 已提交
118 119
static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
                   int enable_seek)
B
bellard 已提交
120 121
{
    uint32_t sector;
122 123 124
    int ret;

    if (track > drv->max_track ||
125
        (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
126 127 128 129
        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 已提交
130 131 132
        return 2;
    }
    if (sect > drv->last_sect) {
133 134 135 136
        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 已提交
137 138
        return 3;
    }
B
Blue Swirl 已提交
139
    sector = fd_sector_calc(head, track, sect, drv->last_sect);
140
    ret = 0;
B
bellard 已提交
141 142 143 144 145 146 147 148 149
    if (sector != fd_sector(drv)) {
#if 0
        if (!enable_seek) {
            FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
                         head, track, sect, 1, drv->max_track, drv->last_sect);
            return 4;
        }
#endif
        drv->head = head;
150 151
        if (drv->track != track)
            ret = 1;
B
bellard 已提交
152 153 154 155
        drv->track = track;
        drv->sect = sect;
    }

156
    return ret;
B
bellard 已提交
157 158 159
}

/* Set drive back to track 0 */
B
Blue Swirl 已提交
160
static void fd_recalibrate(FDrive *drv)
B
bellard 已提交
161 162 163 164 165 166 167 168
{
    FLOPPY_DPRINTF("recalibrate\n");
    drv->head = 0;
    drv->track = 0;
    drv->sect = 1;
}

/* Revalidate a disk drive after a disk change */
B
Blue Swirl 已提交
169
static void fd_revalidate(FDrive *drv)
B
bellard 已提交
170
{
171
    int nb_heads, max_track, last_sect, ro;
172
    FDriveType drive;
B
bellard 已提交
173 174

    FLOPPY_DPRINTF("revalidate\n");
175
    if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
176
        ro = bdrv_is_read_only(drv->bs);
177 178
        bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
                                      &last_sect, drv->drive, &drive);
179 180
        if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
            FLOPPY_DPRINTF("User defined disk (%d %d %d)",
181
                           nb_heads - 1, max_track, last_sect);
182
        } else {
183 184
            FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
                           max_track, last_sect, ro ? "ro" : "rw");
185 186 187 188 189 190 191 192 193
        }
        if (nb_heads == 1) {
            drv->flags &= ~FDISK_DBL_SIDES;
        } else {
            drv->flags |= FDISK_DBL_SIDES;
        }
        drv->max_track = max_track;
        drv->last_sect = last_sect;
        drv->ro = ro;
194
        drv->drive = drive;
B
bellard 已提交
195
    } else {
196
        FLOPPY_DPRINTF("No disk in drive\n");
197
        drv->last_sect = 0;
198 199
        drv->max_track = 0;
        drv->flags &= ~FDISK_DBL_SIDES;
B
bellard 已提交
200
    }
201 202
}

B
bellard 已提交
203
/********************************************************/
B
bellard 已提交
204
/* Intel 82078 floppy disk controller emulation          */
B
bellard 已提交
205

B
Blue Swirl 已提交
206 207
typedef struct FDCtrl FDCtrl;

B
Blue Swirl 已提交
208 209
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
static void fdctrl_reset_fifo(FDCtrl *fdctrl);
B
bellard 已提交
210
static int fdctrl_transfer_handler (void *opaque, int nchan,
A
Anthony Liguori 已提交
211
                                    int dma_pos, int dma_len);
B
Blue Swirl 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0);

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);
B
bellard 已提交
225 226 227 228 229 230 231 232 233 234

enum {
    FD_DIR_WRITE   = 0,
    FD_DIR_READ    = 1,
    FD_DIR_SCANE   = 2,
    FD_DIR_SCANL   = 3,
    FD_DIR_SCANH   = 4,
};

enum {
B
blueswir1 已提交
235 236 237
    FD_STATE_MULTI  = 0x01,	/* multi track flag */
    FD_STATE_FORMAT = 0x02,	/* format flag */
    FD_STATE_SEEK   = 0x04,	/* seek flag */
B
bellard 已提交
238 239
};

240
enum {
B
blueswir1 已提交
241 242
    FD_REG_SRA = 0x00,
    FD_REG_SRB = 0x01,
243 244 245 246 247 248 249 250 251
    FD_REG_DOR = 0x02,
    FD_REG_TDR = 0x03,
    FD_REG_MSR = 0x04,
    FD_REG_DSR = 0x04,
    FD_REG_FIFO = 0x05,
    FD_REG_DIR = 0x07,
};

enum {
252
    FD_CMD_READ_TRACK = 0x02,
253 254
    FD_CMD_SPECIFY = 0x03,
    FD_CMD_SENSE_DRIVE_STATUS = 0x04,
255 256
    FD_CMD_WRITE = 0x05,
    FD_CMD_READ = 0x06,
257 258
    FD_CMD_RECALIBRATE = 0x07,
    FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
259 260 261 262
    FD_CMD_WRITE_DELETED = 0x09,
    FD_CMD_READ_ID = 0x0a,
    FD_CMD_READ_DELETED = 0x0c,
    FD_CMD_FORMAT_TRACK = 0x0d,
263 264 265
    FD_CMD_DUMPREG = 0x0e,
    FD_CMD_SEEK = 0x0f,
    FD_CMD_VERSION = 0x10,
266
    FD_CMD_SCAN_EQUAL = 0x11,
267 268
    FD_CMD_PERPENDICULAR_MODE = 0x12,
    FD_CMD_CONFIGURE = 0x13,
269 270
    FD_CMD_LOCK = 0x14,
    FD_CMD_VERIFY = 0x16,
271 272
    FD_CMD_POWERDOWN_MODE = 0x17,
    FD_CMD_PART_ID = 0x18,
273 274
    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
275
    FD_CMD_SAVE = 0x2e,
276
    FD_CMD_OPTION = 0x33,
277
    FD_CMD_RESTORE = 0x4e,
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    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 {
    FD_SR0_EQPMT    = 0x10,
    FD_SR0_SEEK     = 0x20,
    FD_SR0_ABNTERM  = 0x40,
    FD_SR0_INVCMD   = 0x80,
    FD_SR0_RDYCHG   = 0xc0,
};

B
blueswir1 已提交
300 301 302 303 304 305 306 307 308
enum {
    FD_SR1_EC       = 0x80, /* End of cylinder */
};

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

B
blueswir1 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
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,
};

329
enum {
B
blueswir1 已提交
330 331 332
#if MAX_FD == 4
    FD_DOR_SELMASK  = 0x03,
#else
333
    FD_DOR_SELMASK  = 0x01,
B
blueswir1 已提交
334
#endif
335 336 337 338 339 340 341 342 343
    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 已提交
344
#if MAX_FD == 4
345
    FD_TDR_BOOTSEL  = 0x0c,
B
blueswir1 已提交
346 347 348
#else
    FD_TDR_BOOTSEL  = 0x04,
#endif
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
};

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,
};

B
bellard 已提交
372 373
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
374
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
B
bellard 已提交
375

B
Blue Swirl 已提交
376
struct FDCtrl {
P
pbrook 已提交
377
    qemu_irq irq;
B
bellard 已提交
378
    /* Controller state */
379
    QEMUTimer *result_timer;
380 381 382 383
    int dma_chann;
    /* Controller's identification */
    uint8_t version;
    /* HW */
B
blueswir1 已提交
384 385
    uint8_t sra;
    uint8_t srb;
B
blueswir1 已提交
386
    uint8_t dor;
J
Juan Quintela 已提交
387
    uint8_t dor_vmstate; /* only used as temp during vmstate */
B
blueswir1 已提交
388
    uint8_t tdr;
B
blueswir1 已提交
389
    uint8_t dsr;
B
blueswir1 已提交
390
    uint8_t msr;
B
bellard 已提交
391
    uint8_t cur_drv;
B
blueswir1 已提交
392 393 394
    uint8_t status0;
    uint8_t status1;
    uint8_t status2;
B
bellard 已提交
395
    /* Command FIFO */
396
    uint8_t *fifo;
J
Juan Quintela 已提交
397
    int32_t fifo_size;
B
bellard 已提交
398 399 400 401
    uint32_t data_pos;
    uint32_t data_len;
    uint8_t data_state;
    uint8_t data_dir;
402
    uint8_t eot; /* last wanted sector */
B
bellard 已提交
403 404 405 406 407 408 409 410
    /* 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 */
J
Juan Quintela 已提交
411
    uint8_t num_floppies;
412 413
    /* Sun4m quirks? */
    int sun4m;
B
Blue Swirl 已提交
414
    FDrive drives[MAX_FD];
415
    int reset_sensei;
416 417 418
    /* Timers state */
    uint8_t timer0;
    uint8_t timer1;
419 420
};

B
Blue Swirl 已提交
421
typedef struct FDCtrlSysBus {
G
Gerd Hoffmann 已提交
422
    SysBusDevice busdev;
B
Blue Swirl 已提交
423 424
    struct FDCtrl state;
} FDCtrlSysBus;
G
Gerd Hoffmann 已提交
425

B
Blue Swirl 已提交
426
typedef struct FDCtrlISABus {
G
Gerd Hoffmann 已提交
427
    ISADevice busdev;
B
Blue Swirl 已提交
428
    struct FDCtrl state;
429 430
    int32_t bootindexA;
    int32_t bootindexB;
B
Blue Swirl 已提交
431
} FDCtrlISABus;
G
Gerd Hoffmann 已提交
432

433 434
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
{
B
Blue Swirl 已提交
435
    FDCtrl *fdctrl = opaque;
436 437
    uint32_t retval;

B
blueswir1 已提交
438
    switch (reg) {
B
blueswir1 已提交
439 440
    case FD_REG_SRA:
        retval = fdctrl_read_statusA(fdctrl);
441
        break;
B
blueswir1 已提交
442
    case FD_REG_SRB:
443 444
        retval = fdctrl_read_statusB(fdctrl);
        break;
445
    case FD_REG_DOR:
446 447
        retval = fdctrl_read_dor(fdctrl);
        break;
448
    case FD_REG_TDR:
449
        retval = fdctrl_read_tape(fdctrl);
450
        break;
451
    case FD_REG_MSR:
452
        retval = fdctrl_read_main_status(fdctrl);
453
        break;
454
    case FD_REG_FIFO:
455
        retval = fdctrl_read_data(fdctrl);
456
        break;
457
    case FD_REG_DIR:
458
        retval = fdctrl_read_dir(fdctrl);
459
        break;
460
    default:
461 462
        retval = (uint32_t)(-1);
        break;
463
    }
464
    FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
465 466 467 468 469 470

    return retval;
}

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

473 474
    FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);

B
blueswir1 已提交
475
    switch (reg) {
476
    case FD_REG_DOR:
477 478
        fdctrl_write_dor(fdctrl, value);
        break;
479
    case FD_REG_TDR:
480
        fdctrl_write_tape(fdctrl, value);
481
        break;
482
    case FD_REG_DSR:
483
        fdctrl_write_rate(fdctrl, value);
484
        break;
485
    case FD_REG_FIFO:
486
        fdctrl_write_data(fdctrl, value);
487
        break;
488
    default:
489
        break;
490
    }
491 492
}

B
blueswir1 已提交
493 494 495 496 497 498 499 500 501 502
static uint32_t fdctrl_read_port (void *opaque, uint32_t reg)
{
    return fdctrl_read(opaque, reg & 7);
}

static void fdctrl_write_port (void *opaque, uint32_t reg, uint32_t value)
{
    fdctrl_write(opaque, reg & 7, value);
}

A
Anthony Liguori 已提交
503
static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
B
bellard 已提交
504
{
505
    return fdctrl_read(opaque, (uint32_t)reg);
B
bellard 已提交
506 507
}

508
static void fdctrl_write_mem (void *opaque,
A
Anthony Liguori 已提交
509
                              target_phys_addr_t reg, uint32_t value)
B
bellard 已提交
510
{
511
    fdctrl_write(opaque, (uint32_t)reg, value);
B
bellard 已提交
512 513
}

514
static CPUReadMemoryFunc * const fdctrl_mem_read[3] = {
B
bellard 已提交
515 516 517
    fdctrl_read_mem,
    fdctrl_read_mem,
    fdctrl_read_mem,
B
bellard 已提交
518 519
};

520
static CPUWriteMemoryFunc * const fdctrl_mem_write[3] = {
B
bellard 已提交
521 522 523
    fdctrl_write_mem,
    fdctrl_write_mem,
    fdctrl_write_mem,
B
bellard 已提交
524 525
};

526
static CPUReadMemoryFunc * const fdctrl_mem_read_strict[3] = {
527 528 529 530 531
    fdctrl_read_mem,
    NULL,
    NULL,
};

532
static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
533 534 535 536 537
    fdctrl_write_mem,
    NULL,
    NULL,
};

538 539 540 541
static bool fdrive_media_changed_needed(void *opaque)
{
    FDrive *drive = opaque;

542
    return (drive->bs != NULL && drive->media_changed != 1);
543 544 545 546 547 548 549 550 551 552 553 554 555
}

static const VMStateDescription vmstate_fdrive_media_changed = {
    .name = "fdrive/media_changed",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .fields      = (VMStateField[]) {
        VMSTATE_UINT8(media_changed, FDrive),
        VMSTATE_END_OF_LIST()
    }
};

J
Juan Quintela 已提交
556 557 558 559 560
static const VMStateDescription vmstate_fdrive = {
    .name = "fdrive",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
561
    .fields      = (VMStateField[]) {
B
Blue Swirl 已提交
562 563 564
        VMSTATE_UINT8(head, FDrive),
        VMSTATE_UINT8(track, FDrive),
        VMSTATE_UINT8(sect, FDrive),
J
Juan Quintela 已提交
565
        VMSTATE_END_OF_LIST()
566 567 568 569 570 571 572 573
    },
    .subsections = (VMStateSubsection[]) {
        {
            .vmsd = &vmstate_fdrive_media_changed,
            .needed = &fdrive_media_changed_needed,
        } , {
            /* empty */
        }
J
Juan Quintela 已提交
574 575
    }
};
576

577
static void fdc_pre_save(void *opaque)
578
{
B
Blue Swirl 已提交
579
    FDCtrl *s = opaque;
580

J
Juan Quintela 已提交
581
    s->dor_vmstate = s->dor | GET_CUR_DRV(s);
582 583
}

584
static int fdc_post_load(void *opaque, int version_id)
585
{
B
Blue Swirl 已提交
586
    FDCtrl *s = opaque;
587

J
Juan Quintela 已提交
588 589
    SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
    s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
590 591 592
    return 0;
}

J
Juan Quintela 已提交
593
static const VMStateDescription vmstate_fdc = {
594
    .name = "fdc",
J
Juan Quintela 已提交
595 596 597 598 599 600 601
    .version_id = 2,
    .minimum_version_id = 2,
    .minimum_version_id_old = 2,
    .pre_save = fdc_pre_save,
    .post_load = fdc_post_load,
    .fields      = (VMStateField []) {
        /* Controller State */
B
Blue Swirl 已提交
602 603 604 605 606 607 608 609 610
        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 已提交
611
        /* Command FIFO */
B
Blue Swirl 已提交
612 613
        VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
                             uint8_t),
B
Blue Swirl 已提交
614 615 616 617 618
        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 已提交
619
        /* States kept only to be returned back */
B
Blue Swirl 已提交
620 621 622 623 624 625 626 627 628
        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),
        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
        VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
                             vmstate_fdrive, FDrive),
J
Juan Quintela 已提交
629
        VMSTATE_END_OF_LIST()
B
blueswir1 已提交
630
    }
J
Juan Quintela 已提交
631
};
632

B
Blue Swirl 已提交
633
static void fdctrl_external_reset_sysbus(DeviceState *d)
634
{
B
Blue Swirl 已提交
635 636
    FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
    FDCtrl *s = &sys->state;
B
Blue Swirl 已提交
637 638 639 640 641 642

    fdctrl_reset(s, 0);
}

static void fdctrl_external_reset_isa(DeviceState *d)
{
B
Blue Swirl 已提交
643 644
    FDCtrlISABus *isa = container_of(d, FDCtrlISABus, busdev.qdev);
    FDCtrl *s = &isa->state;
645 646 647 648

    fdctrl_reset(s, 0);
}

B
blueswir1 已提交
649 650
static void fdctrl_handle_tc(void *opaque, int irq, int level)
{
B
Blue Swirl 已提交
651
    //FDCtrl *s = opaque;
B
blueswir1 已提交
652 653 654 655 656 657 658

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

B
bellard 已提交
659
/* Change IRQ state */
B
Blue Swirl 已提交
660
static void fdctrl_reset_irq(FDCtrl *fdctrl)
B
bellard 已提交
661
{
B
blueswir1 已提交
662 663
    if (!(fdctrl->sra & FD_SRA_INTPEND))
        return;
664
    FLOPPY_DPRINTF("Reset interrupt\n");
P
pbrook 已提交
665
    qemu_set_irq(fdctrl->irq, 0);
B
blueswir1 已提交
666
    fdctrl->sra &= ~FD_SRA_INTPEND;
B
bellard 已提交
667 668
}

B
Blue Swirl 已提交
669
static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
B
bellard 已提交
670
{
B
blueswir1 已提交
671 672 673 674 675
    /* Sparc mutation */
    if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
        /* XXX: not sure */
        fdctrl->msr &= ~FD_MSR_CMDBUSY;
        fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
B
blueswir1 已提交
676
        fdctrl->status0 = status0;
677
        return;
B
bellard 已提交
678
    }
B
blueswir1 已提交
679
    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
P
pbrook 已提交
680
        qemu_set_irq(fdctrl->irq, 1);
B
blueswir1 已提交
681
        fdctrl->sra |= FD_SRA_INTPEND;
B
bellard 已提交
682
    }
683
    fdctrl->reset_sensei = 0;
B
blueswir1 已提交
684 685
    fdctrl->status0 = status0;
    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
B
bellard 已提交
686 687
}

B
bellard 已提交
688
/* Reset controller */
B
Blue Swirl 已提交
689
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
B
bellard 已提交
690 691 692
{
    int i;

B
bellard 已提交
693
    FLOPPY_DPRINTF("reset controller\n");
694
    fdctrl_reset_irq(fdctrl);
B
bellard 已提交
695
    /* Initialise controller */
B
blueswir1 已提交
696 697 698 699
    fdctrl->sra = 0;
    fdctrl->srb = 0xc0;
    if (!fdctrl->drives[1].bs)
        fdctrl->sra |= FD_SRA_nDRV2;
700
    fdctrl->cur_drv = 0;
B
blueswir1 已提交
701
    fdctrl->dor = FD_DOR_nRESET;
B
blueswir1 已提交
702
    fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
B
blueswir1 已提交
703
    fdctrl->msr = FD_MSR_RQM;
B
bellard 已提交
704
    /* FIFO state */
705 706
    fdctrl->data_pos = 0;
    fdctrl->data_len = 0;
B
blueswir1 已提交
707
    fdctrl->data_state = 0;
708
    fdctrl->data_dir = FD_DIR_WRITE;
B
bellard 已提交
709
    for (i = 0; i < MAX_FD; i++)
B
blueswir1 已提交
710
        fd_recalibrate(&fdctrl->drives[i]);
711
    fdctrl_reset_fifo(fdctrl);
B
blueswir1 已提交
712
    if (do_irq) {
713
        fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
714
        fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
B
blueswir1 已提交
715
    }
716 717
}

B
Blue Swirl 已提交
718
static inline FDrive *drv0(FDCtrl *fdctrl)
719
{
B
blueswir1 已提交
720
    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
721 722
}

B
Blue Swirl 已提交
723
static inline FDrive *drv1(FDCtrl *fdctrl)
724
{
B
blueswir1 已提交
725 726 727 728
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
        return &fdctrl->drives[1];
    else
        return &fdctrl->drives[0];
729 730
}

B
blueswir1 已提交
731
#if MAX_FD == 4
B
Blue Swirl 已提交
732
static inline FDrive *drv2(FDCtrl *fdctrl)
B
blueswir1 已提交
733 734 735 736 737 738 739
{
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
        return &fdctrl->drives[2];
    else
        return &fdctrl->drives[1];
}

B
Blue Swirl 已提交
740
static inline FDrive *drv3(FDCtrl *fdctrl)
B
blueswir1 已提交
741 742 743 744 745 746 747 748
{
    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
        return &fdctrl->drives[3];
    else
        return &fdctrl->drives[2];
}
#endif

B
Blue Swirl 已提交
749
static FDrive *get_cur_drv(FDCtrl *fdctrl)
750
{
B
blueswir1 已提交
751 752 753 754 755 756 757 758 759
    switch (fdctrl->cur_drv) {
        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 已提交
760 761
}

B
blueswir1 已提交
762
/* Status A register : 0x00 (read-only) */
B
Blue Swirl 已提交
763
static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
B
blueswir1 已提交
764 765 766 767 768 769 770 771
{
    uint32_t retval = fdctrl->sra;

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

    return retval;
}

B
bellard 已提交
772
/* Status B register : 0x01 (read-only) */
B
Blue Swirl 已提交
773
static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
B
bellard 已提交
774
{
B
blueswir1 已提交
775 776 777 778 779
    uint32_t retval = fdctrl->srb;

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

    return retval;
B
bellard 已提交
780 781 782
}

/* Digital output register : 0x02 */
B
Blue Swirl 已提交
783
static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
B
bellard 已提交
784
{
B
blueswir1 已提交
785
    uint32_t retval = fdctrl->dor;
B
bellard 已提交
786 787

    /* Selected drive */
788
    retval |= fdctrl->cur_drv;
B
bellard 已提交
789 790 791 792 793
    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);

    return retval;
}

B
Blue Swirl 已提交
794
static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
795 796
{
    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
B
blueswir1 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813

    /* 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 已提交
814
    /* Reset */
815
    if (!(value & FD_DOR_nRESET)) {
B
blueswir1 已提交
816
        if (fdctrl->dor & FD_DOR_nRESET) {
B
bellard 已提交
817
            FLOPPY_DPRINTF("controller enter RESET state\n");
B
bellard 已提交
818 819
        }
    } else {
B
blueswir1 已提交
820
        if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
821
            FLOPPY_DPRINTF("controller out of RESET state\n");
822
            fdctrl_reset(fdctrl, 1);
B
blueswir1 已提交
823
            fdctrl->dsr &= ~FD_DSR_PWRDOWN;
B
bellard 已提交
824 825 826
        }
    }
    /* Selected drive */
827
    fdctrl->cur_drv = value & FD_DOR_SELMASK;
B
blueswir1 已提交
828 829

    fdctrl->dor = value;
B
bellard 已提交
830 831 832
}

/* Tape drive register : 0x03 */
B
Blue Swirl 已提交
833
static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
B
bellard 已提交
834
{
B
blueswir1 已提交
835
    uint32_t retval = fdctrl->tdr;
B
bellard 已提交
836 837 838 839 840 841

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

    return retval;
}

B
Blue Swirl 已提交
842
static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
843 844
{
    /* Reset mode */
B
blueswir1 已提交
845
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
846
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
B
bellard 已提交
847 848 849 850
        return;
    }
    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
    /* Disk boot selection indicator */
B
blueswir1 已提交
851
    fdctrl->tdr = value & FD_TDR_BOOTSEL;
B
bellard 已提交
852 853 854 855
    /* Tape indicators: never allow */
}

/* Main status register : 0x04 (read) */
B
Blue Swirl 已提交
856
static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
B
bellard 已提交
857
{
B
blueswir1 已提交
858
    uint32_t retval = fdctrl->msr;
B
bellard 已提交
859

B
blueswir1 已提交
860
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
B
blueswir1 已提交
861
    fdctrl->dor |= FD_DOR_nRESET;
B
blueswir1 已提交
862

863 864 865 866 867 868
    /* Sparc mutation */
    if (fdctrl->sun4m) {
        retval |= FD_MSR_DIO;
        fdctrl_reset_irq(fdctrl);
    };

B
bellard 已提交
869 870 871 872 873 874
    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);

    return retval;
}

/* Data select rate register : 0x04 (write) */
B
Blue Swirl 已提交
875
static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
B
bellard 已提交
876 877
{
    /* Reset mode */
B
blueswir1 已提交
878
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
879 880 881
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
        return;
    }
B
bellard 已提交
882 883
    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
    /* Reset: autoclear */
884
    if (value & FD_DSR_SWRESET) {
B
blueswir1 已提交
885
        fdctrl->dor &= ~FD_DOR_nRESET;
886
        fdctrl_reset(fdctrl, 1);
B
blueswir1 已提交
887
        fdctrl->dor |= FD_DOR_nRESET;
B
bellard 已提交
888
    }
889
    if (value & FD_DSR_PWRDOWN) {
890
        fdctrl_reset(fdctrl, 1);
B
bellard 已提交
891
    }
B
blueswir1 已提交
892
    fdctrl->dsr = value;
B
bellard 已提交
893 894
}

B
Blue Swirl 已提交
895
static int fdctrl_media_changed(FDrive *drv)
B
bellard 已提交
896 897
{
    int ret;
898

899
    if (!drv->bs)
B
bellard 已提交
900 901
        return 0;
    ret = bdrv_media_changed(drv->bs);
902 903 904 905
    if (ret < 0) {
        ret = drv->media_changed;
    }
    drv->media_changed = 0;
B
bellard 已提交
906 907 908 909 910 911
    if (ret) {
        fd_revalidate(drv);
    }
    return ret;
}

B
bellard 已提交
912
/* Digital input register : 0x07 (read-only) */
B
Blue Swirl 已提交
913
static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
B
bellard 已提交
914 915 916
{
    uint32_t retval = 0;

B
blueswir1 已提交
917 918 919 920 921 922 923
    if (fdctrl_media_changed(drv0(fdctrl))
     || fdctrl_media_changed(drv1(fdctrl))
#if MAX_FD == 4
     || fdctrl_media_changed(drv2(fdctrl))
     || fdctrl_media_changed(drv3(fdctrl))
#endif
        )
924
        retval |= FD_DIR_DSKCHG;
925
    if (retval != 0) {
926
        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
927
    }
B
bellard 已提交
928 929 930 931 932

    return retval;
}

/* FIFO state control */
B
Blue Swirl 已提交
933
static void fdctrl_reset_fifo(FDCtrl *fdctrl)
B
bellard 已提交
934
{
935 936
    fdctrl->data_dir = FD_DIR_WRITE;
    fdctrl->data_pos = 0;
B
blueswir1 已提交
937
    fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
B
bellard 已提交
938 939 940
}

/* Set FIFO status for the host to read */
B
Blue Swirl 已提交
941
static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, int do_irq)
B
bellard 已提交
942
{
943 944 945
    fdctrl->data_dir = FD_DIR_READ;
    fdctrl->data_len = fifo_len;
    fdctrl->data_pos = 0;
B
blueswir1 已提交
946
    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
B
bellard 已提交
947
    if (do_irq)
948
        fdctrl_raise_irq(fdctrl, 0x00);
B
bellard 已提交
949 950 951
}

/* Set an error: unimplemented/unknown command */
B
Blue Swirl 已提交
952
static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
B
bellard 已提交
953
{
B
blueswir1 已提交
954
    FLOPPY_ERROR("unimplemented command 0x%02x\n", fdctrl->fifo[0]);
955
    fdctrl->fifo[0] = FD_SR0_INVCMD;
956
    fdctrl_set_fifo(fdctrl, 1, 0);
B
bellard 已提交
957 958
}

B
blueswir1 已提交
959
/* Seek to next sector */
B
Blue Swirl 已提交
960
static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
B
blueswir1 已提交
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
{
    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 */
    if (cur_drv->sect >= cur_drv->last_sect ||
        cur_drv->sect == fdctrl->eot) {
        cur_drv->sect = 1;
        if (FD_MULTI_TRACK(fdctrl->data_state)) {
            if (cur_drv->head == 0 &&
                (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
                cur_drv->head = 1;
            } else {
                cur_drv->head = 0;
                cur_drv->track++;
                if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
                    return 0;
            }
        } else {
            cur_drv->track++;
            return 0;
        }
        FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
                       cur_drv->head, cur_drv->track,
                       cur_drv->sect, fd_sector(cur_drv));
    } else {
        cur_drv->sect++;
    }
    return 1;
}

B
bellard 已提交
993
/* Callback for transfer end (stop or abort) */
B
Blue Swirl 已提交
994 995
static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
                                 uint8_t status1, uint8_t status2)
B
bellard 已提交
996
{
B
Blue Swirl 已提交
997
    FDrive *cur_drv;
B
bellard 已提交
998

999
    cur_drv = get_cur_drv(fdctrl);
B
bellard 已提交
1000 1001
    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
                   status0, status1, status2,
B
blueswir1 已提交
1002 1003
                   status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl));
    fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1004 1005 1006 1007 1008 1009 1010
    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;
B
blueswir1 已提交
1011
    if (!(fdctrl->msr & FD_MSR_NONDMA)) {
1012
        DMA_release_DREQ(fdctrl->dma_chann);
1013
    }
B
blueswir1 已提交
1014
    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
B
blueswir1 已提交
1015
    fdctrl->msr &= ~FD_MSR_NONDMA;
1016
    fdctrl_set_fifo(fdctrl, 7, 1);
B
bellard 已提交
1017 1018 1019
}

/* Prepare a data transfer (either DMA or FIFO) */
B
Blue Swirl 已提交
1020
static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
B
bellard 已提交
1021
{
B
Blue Swirl 已提交
1022
    FDrive *cur_drv;
B
bellard 已提交
1023
    uint8_t kh, kt, ks;
B
blueswir1 已提交
1024
    int did_seek = 0;
B
bellard 已提交
1025

B
blueswir1 已提交
1026
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1027 1028 1029 1030
    cur_drv = get_cur_drv(fdctrl);
    kt = fdctrl->fifo[2];
    kh = fdctrl->fifo[3];
    ks = fdctrl->fifo[4];
B
bellard 已提交
1031
    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
B
blueswir1 已提交
1032
                   GET_CUR_DRV(fdctrl), kh, kt, ks,
B
Blue Swirl 已提交
1033
                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
B
blueswir1 已提交
1034
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
B
bellard 已提交
1035 1036
    case 2:
        /* sect too big */
1037
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1038 1039 1040
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1041 1042 1043
        return;
    case 3:
        /* track too big */
B
blueswir1 已提交
1044
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1045 1046 1047
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1048 1049 1050
        return;
    case 4:
        /* No seek enabled */
1051
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1052 1053 1054
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
B
bellard 已提交
1055 1056 1057 1058 1059 1060 1061
        return;
    case 1:
        did_seek = 1;
        break;
    default:
        break;
    }
B
blueswir1 已提交
1062

B
bellard 已提交
1063
    /* Set the FIFO state */
1064 1065
    fdctrl->data_dir = direction;
    fdctrl->data_pos = 0;
B
blueswir1 已提交
1066
    fdctrl->msr |= FD_MSR_CMDBUSY;
1067 1068 1069 1070
    if (fdctrl->fifo[0] & 0x80)
        fdctrl->data_state |= FD_STATE_MULTI;
    else
        fdctrl->data_state &= ~FD_STATE_MULTI;
B
bellard 已提交
1071
    if (did_seek)
1072 1073 1074 1075 1076 1077
        fdctrl->data_state |= FD_STATE_SEEK;
    else
        fdctrl->data_state &= ~FD_STATE_SEEK;
    if (fdctrl->fifo[5] == 00) {
        fdctrl->data_len = fdctrl->fifo[8];
    } else {
1078
        int tmp;
T
ths 已提交
1079
        fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1080
        tmp = (fdctrl->fifo[6] - ks + 1);
1081
        if (fdctrl->fifo[0] & 0x80)
1082
            tmp += fdctrl->fifo[6];
1083
        fdctrl->data_len *= tmp;
1084
    }
1085
    fdctrl->eot = fdctrl->fifo[6];
B
blueswir1 已提交
1086
    if (fdctrl->dor & FD_DOR_DMAEN) {
B
bellard 已提交
1087 1088
        int dma_mode;
        /* DMA transfer are enabled. Check if DMA channel is well programmed */
1089
        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
B
bellard 已提交
1090
        dma_mode = (dma_mode >> 2) & 3;
1091
        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1092
                       dma_mode, direction,
1093
                       (128 << fdctrl->fifo[5]) *
1094
                       (cur_drv->last_sect - ks + 1), fdctrl->data_len);
B
bellard 已提交
1095 1096 1097 1098 1099
        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
              direction == FD_DIR_SCANH) && dma_mode == 0) ||
            (direction == FD_DIR_WRITE && dma_mode == 2) ||
            (direction == FD_DIR_READ && dma_mode == 1)) {
            /* No access is allowed until DMA transfer has completed */
B
blueswir1 已提交
1100
            fdctrl->msr &= ~FD_MSR_RQM;
B
bellard 已提交
1101
            /* Now, we just have to wait for the DMA controller to
B
bellard 已提交
1102 1103
             * recall us...
             */
1104 1105
            DMA_hold_DREQ(fdctrl->dma_chann);
            DMA_schedule(fdctrl->dma_chann);
B
bellard 已提交
1106
            return;
1107
        } else {
1108
            FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
B
bellard 已提交
1109 1110 1111
        }
    }
    FLOPPY_DPRINTF("start non-DMA transfer\n");
B
blueswir1 已提交
1112
    fdctrl->msr |= FD_MSR_NONDMA;
B
blueswir1 已提交
1113 1114
    if (direction != FD_DIR_WRITE)
        fdctrl->msr |= FD_MSR_DIO;
B
bellard 已提交
1115
    /* IO based transfer: calculate len */
1116
    fdctrl_raise_irq(fdctrl, 0x00);
B
bellard 已提交
1117 1118 1119 1120 1121

    return;
}

/* Prepare a transfer of deleted data */
B
Blue Swirl 已提交
1122
static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
B
bellard 已提交
1123
{
B
blueswir1 已提交
1124 1125
    FLOPPY_ERROR("fdctrl_start_transfer_del() unimplemented\n");

B
bellard 已提交
1126 1127 1128
    /* We don't handle deleted data,
     * so we don't return *ANYTHING*
     */
1129
    fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
B
bellard 已提交
1130 1131 1132
}

/* handlers for DMA transfers */
B
bellard 已提交
1133 1134
static int fdctrl_transfer_handler (void *opaque, int nchan,
                                    int dma_pos, int dma_len)
B
bellard 已提交
1135
{
B
Blue Swirl 已提交
1136 1137
    FDCtrl *fdctrl;
    FDrive *cur_drv;
1138
    int len, start_pos, rel_pos;
B
bellard 已提交
1139 1140
    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;

1141
    fdctrl = opaque;
B
blueswir1 已提交
1142
    if (fdctrl->msr & FD_MSR_RQM) {
B
bellard 已提交
1143 1144 1145
        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
        return 0;
    }
1146 1147 1148
    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 已提交
1149
        status2 = FD_SR2_SNS;
B
bellard 已提交
1150 1151
    if (dma_len > fdctrl->data_len)
        dma_len = fdctrl->data_len;
1152
    if (cur_drv->bs == NULL) {
1153
        if (fdctrl->data_dir == FD_DIR_WRITE)
1154
            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1155
        else
1156
            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1157
        len = 0;
1158 1159
        goto transfer_error;
    }
1160
    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
B
bellard 已提交
1161 1162
    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
        len = dma_len - fdctrl->data_pos;
1163 1164
        if (len + rel_pos > FD_SECTOR_LEN)
            len = FD_SECTOR_LEN - rel_pos;
B
bellard 已提交
1165 1166
        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 已提交
1167
                       fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
1168
                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1169
                       fd_sector(cur_drv) * FD_SECTOR_LEN);
1170
        if (fdctrl->data_dir != FD_DIR_WRITE ||
1171
            len < FD_SECTOR_LEN || rel_pos != 0) {
1172 1173
            /* READ & SCAN commands and realign to a sector for WRITE */
            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1174
                          fdctrl->fifo, 1) < 0) {
B
bellard 已提交
1175 1176 1177
                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
                               fd_sector(cur_drv));
                /* Sure, image size is too small... */
1178
                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
B
bellard 已提交
1179
            }
1180
        }
1181 1182 1183
        switch (fdctrl->data_dir) {
        case FD_DIR_READ:
            /* READ commands */
B
bellard 已提交
1184 1185
            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
                              fdctrl->data_pos, len);
1186 1187
            break;
        case FD_DIR_WRITE:
1188
            /* WRITE commands */
B
bellard 已提交
1189 1190
            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
                             fdctrl->data_pos, len);
1191
            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1192
                           fdctrl->fifo, 1) < 0) {
B
blueswir1 已提交
1193
                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
1194
                fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1195
                goto transfer_error;
1196
            }
1197 1198 1199
            break;
        default:
            /* SCAN commands */
1200
            {
1201
                uint8_t tmpbuf[FD_SECTOR_LEN];
1202
                int ret;
B
bellard 已提交
1203
                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1204
                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
B
bellard 已提交
1205
                if (ret == 0) {
B
blueswir1 已提交
1206
                    status2 = FD_SR2_SEH;
B
bellard 已提交
1207 1208
                    goto end_transfer;
                }
1209 1210
                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
B
bellard 已提交
1211 1212 1213 1214
                    status2 = 0x00;
                    goto end_transfer;
                }
            }
1215
            break;
B
bellard 已提交
1216
        }
1217 1218
        fdctrl->data_pos += len;
        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1219
        if (rel_pos == 0) {
B
bellard 已提交
1220
            /* Seek to next sector */
B
blueswir1 已提交
1221 1222
            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
                break;
B
bellard 已提交
1223 1224
        }
    }
1225
 end_transfer:
1226 1227
    len = fdctrl->data_pos - start_pos;
    FLOPPY_DPRINTF("end transfer %d %d %d\n",
1228
                   fdctrl->data_pos, len, fdctrl->data_len);
1229 1230 1231
    if (fdctrl->data_dir == FD_DIR_SCANE ||
        fdctrl->data_dir == FD_DIR_SCANL ||
        fdctrl->data_dir == FD_DIR_SCANH)
B
blueswir1 已提交
1232
        status2 = FD_SR2_SEH;
1233
    if (FD_DID_SEEK(fdctrl->data_state))
1234
        status0 |= FD_SR0_SEEK;
1235
    fdctrl->data_len -= len;
1236
    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1237
 transfer_error:
B
bellard 已提交
1238

1239
    return len;
B
bellard 已提交
1240 1241 1242
}

/* Data register : 0x05 */
B
Blue Swirl 已提交
1243
static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
B
bellard 已提交
1244
{
B
Blue Swirl 已提交
1245
    FDrive *cur_drv;
B
bellard 已提交
1246
    uint32_t retval = 0;
B
blueswir1 已提交
1247
    int pos;
B
bellard 已提交
1248

1249
    cur_drv = get_cur_drv(fdctrl);
B
blueswir1 已提交
1250 1251 1252
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
    if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
        FLOPPY_ERROR("controller not ready for reading\n");
B
bellard 已提交
1253 1254
        return 0;
    }
1255
    pos = fdctrl->data_pos;
B
blueswir1 已提交
1256
    if (fdctrl->msr & FD_MSR_NONDMA) {
B
bellard 已提交
1257 1258
        pos %= FD_SECTOR_LEN;
        if (pos == 0) {
B
blueswir1 已提交
1259 1260 1261 1262 1263 1264
            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;
                }
B
blueswir1 已提交
1265 1266 1267 1268 1269 1270
            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
                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 已提交
1271 1272
        }
    }
1273 1274 1275
    retval = fdctrl->fifo[pos];
    if (++fdctrl->data_pos == fdctrl->data_len) {
        fdctrl->data_pos = 0;
1276
        /* Switch from transfer mode to status mode
B
bellard 已提交
1277 1278
         * then from status mode to command mode
         */
B
blueswir1 已提交
1279
        if (fdctrl->msr & FD_MSR_NONDMA) {
1280
            fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1281
        } else {
1282
            fdctrl_reset_fifo(fdctrl);
1283 1284
            fdctrl_reset_irq(fdctrl);
        }
B
bellard 已提交
1285 1286 1287 1288 1289 1290
    }
    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);

    return retval;
}

B
Blue Swirl 已提交
1291
static void fdctrl_format_sector(FDCtrl *fdctrl)
B
bellard 已提交
1292
{
B
Blue Swirl 已提交
1293
    FDrive *cur_drv;
1294
    uint8_t kh, kt, ks;
B
bellard 已提交
1295

B
blueswir1 已提交
1296
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1297 1298 1299 1300 1301
    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 已提交
1302
                   GET_CUR_DRV(fdctrl), kh, kt, ks,
B
Blue Swirl 已提交
1303
                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
1304
    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
1305 1306
    case 2:
        /* sect too big */
1307
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1308 1309 1310 1311 1312 1313
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 3:
        /* track too big */
B
blueswir1 已提交
1314
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1315 1316 1317 1318 1319 1320
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 4:
        /* No seek enabled */
1321
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
        fdctrl->fifo[3] = kt;
        fdctrl->fifo[4] = kh;
        fdctrl->fifo[5] = ks;
        return;
    case 1:
        fdctrl->data_state |= FD_STATE_SEEK;
        break;
    default:
        break;
    }
    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
    if (cur_drv->bs == NULL ||
        bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
T
ths 已提交
1335
        FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
1336
        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1337
    } else {
1338 1339 1340 1341
        if (cur_drv->sect == cur_drv->last_sect) {
            fdctrl->data_state &= ~FD_STATE_FORMAT;
            /* Last sector done */
            if (FD_DID_SEEK(fdctrl->data_state))
1342
                fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1343 1344 1345 1346 1347 1348 1349
            else
                fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
        } else {
            /* More to do */
            fdctrl->data_pos = 0;
            fdctrl->data_len = 4;
        }
1350 1351 1352
    }
}

B
Blue Swirl 已提交
1353
static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
1354 1355 1356 1357 1358 1359
{
    fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
    fdctrl->fifo[0] = fdctrl->lock << 4;
    fdctrl_set_fifo(fdctrl, 1, fdctrl->lock);
}

B
Blue Swirl 已提交
1360
static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
1361
{
B
Blue Swirl 已提交
1362
    FDrive *cur_drv = get_cur_drv(fdctrl);
1363 1364 1365 1366

    /* Drives position */
    fdctrl->fifo[0] = drv0(fdctrl)->track;
    fdctrl->fifo[1] = drv1(fdctrl)->track;
B
blueswir1 已提交
1367 1368 1369 1370
#if MAX_FD == 4
    fdctrl->fifo[2] = drv2(fdctrl)->track;
    fdctrl->fifo[3] = drv3(fdctrl)->track;
#else
1371 1372
    fdctrl->fifo[2] = 0;
    fdctrl->fifo[3] = 0;
B
blueswir1 已提交
1373
#endif
1374 1375
    /* timers */
    fdctrl->fifo[4] = fdctrl->timer0;
B
blueswir1 已提交
1376
    fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
1377 1378 1379 1380 1381 1382 1383 1384
    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;
    fdctrl_set_fifo(fdctrl, 10, 0);
}

B
Blue Swirl 已提交
1385
static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
1386 1387 1388 1389 1390 1391
{
    /* Controller's version */
    fdctrl->fifo[0] = fdctrl->version;
    fdctrl_set_fifo(fdctrl, 1, 1);
}

B
Blue Swirl 已提交
1392
static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
1393 1394 1395 1396 1397
{
    fdctrl->fifo[0] = 0x41; /* Stepping 1 */
    fdctrl_set_fifo(fdctrl, 1, 0);
}

B
Blue Swirl 已提交
1398
static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
1399
{
B
Blue Swirl 已提交
1400
    FDrive *cur_drv = get_cur_drv(fdctrl);
1401 1402 1403 1404

    /* Drives position */
    drv0(fdctrl)->track = fdctrl->fifo[3];
    drv1(fdctrl)->track = fdctrl->fifo[4];
B
blueswir1 已提交
1405 1406 1407 1408
#if MAX_FD == 4
    drv2(fdctrl)->track = fdctrl->fifo[5];
    drv3(fdctrl)->track = fdctrl->fifo[6];
#endif
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
    /* 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];
    fdctrl_reset_fifo(fdctrl);
}

B
Blue Swirl 已提交
1421
static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
1422
{
B
Blue Swirl 已提交
1423
    FDrive *cur_drv = get_cur_drv(fdctrl);
1424 1425 1426 1427 1428 1429

    fdctrl->fifo[0] = 0;
    fdctrl->fifo[1] = 0;
    /* Drives position */
    fdctrl->fifo[2] = drv0(fdctrl)->track;
    fdctrl->fifo[3] = drv1(fdctrl)->track;
B
blueswir1 已提交
1430 1431 1432 1433
#if MAX_FD == 4
    fdctrl->fifo[4] = drv2(fdctrl)->track;
    fdctrl->fifo[5] = drv3(fdctrl)->track;
#else
1434 1435
    fdctrl->fifo[4] = 0;
    fdctrl->fifo[5] = 0;
B
blueswir1 已提交
1436
#endif
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
    /* 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;
    fdctrl_set_fifo(fdctrl, 15, 1);
}

B
Blue Swirl 已提交
1451
static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
1452
{
B
Blue Swirl 已提交
1453
    FDrive *cur_drv = get_cur_drv(fdctrl);
1454 1455 1456 1457

    /* XXX: should set main status register to busy */
    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
    qemu_mod_timer(fdctrl->result_timer,
1458
                   qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
1459 1460
}

B
Blue Swirl 已提交
1461
static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
1462
{
B
Blue Swirl 已提交
1463
    FDrive *cur_drv;
1464

B
blueswir1 已提交
1465
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
    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;
    fdctrl->data_state &= ~FD_STATE_SEEK;
    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 已提交
1490
static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
1491 1492 1493
{
    fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
    fdctrl->timer1 = fdctrl->fifo[2] >> 1;
B
blueswir1 已提交
1494 1495 1496 1497
    if (fdctrl->fifo[2] & 1)
        fdctrl->dor &= ~FD_DOR_DMAEN;
    else
        fdctrl->dor |= FD_DOR_DMAEN;
1498 1499 1500 1501
    /* No result back */
    fdctrl_reset_fifo(fdctrl);
}

B
Blue Swirl 已提交
1502
static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
1503
{
B
Blue Swirl 已提交
1504
    FDrive *cur_drv;
1505

B
blueswir1 已提交
1506
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1507 1508 1509 1510 1511 1512
    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 已提交
1513
        GET_CUR_DRV(fdctrl) |
1514 1515 1516 1517
        0x28;
    fdctrl_set_fifo(fdctrl, 1, 0);
}

B
Blue Swirl 已提交
1518
static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
1519
{
B
Blue Swirl 已提交
1520
    FDrive *cur_drv;
1521

B
blueswir1 已提交
1522
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1523 1524 1525 1526 1527 1528 1529
    cur_drv = get_cur_drv(fdctrl);
    fd_recalibrate(cur_drv);
    fdctrl_reset_fifo(fdctrl);
    /* Raise Interrupt */
    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
}

B
Blue Swirl 已提交
1530
static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
1531
{
B
Blue Swirl 已提交
1532
    FDrive *cur_drv = get_cur_drv(fdctrl);
1533

1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
    if(fdctrl->reset_sensei > 0) {
        fdctrl->fifo[0] =
            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
        fdctrl->reset_sensei--;
    } else {
        /* XXX: status0 handling is broken for read/write
           commands, so we do this hack. It should be suppressed
           ASAP */
        fdctrl->fifo[0] =
            FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
    }

1546 1547 1548
    fdctrl->fifo[1] = cur_drv->track;
    fdctrl_set_fifo(fdctrl, 2, 0);
    fdctrl_reset_irq(fdctrl);
B
blueswir1 已提交
1549
    fdctrl->status0 = FD_SR0_RDYCHG;
1550 1551
}

B
Blue Swirl 已提交
1552
static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
1553
{
B
Blue Swirl 已提交
1554
    FDrive *cur_drv;
1555

B
blueswir1 已提交
1556
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
    cur_drv = get_cur_drv(fdctrl);
    fdctrl_reset_fifo(fdctrl);
    if (fdctrl->fifo[2] > cur_drv->max_track) {
        fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
    } else {
        cur_drv->track = fdctrl->fifo[2];
        /* Raise Interrupt */
        fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
    }
}

B
Blue Swirl 已提交
1568
static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
1569
{
B
Blue Swirl 已提交
1570
    FDrive *cur_drv = get_cur_drv(fdctrl);
1571 1572 1573 1574

    if (fdctrl->fifo[1] & 0x80)
        cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
    /* No result back */
B
blueswir1 已提交
1575
    fdctrl_reset_fifo(fdctrl);
1576 1577
}

B
Blue Swirl 已提交
1578
static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
1579 1580 1581 1582 1583 1584 1585
{
    fdctrl->config = fdctrl->fifo[2];
    fdctrl->precomp_trk =  fdctrl->fifo[3];
    /* No result back */
    fdctrl_reset_fifo(fdctrl);
}

B
Blue Swirl 已提交
1586
static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
1587 1588 1589 1590 1591 1592
{
    fdctrl->pwrd = fdctrl->fifo[1];
    fdctrl->fifo[0] = fdctrl->fifo[1];
    fdctrl_set_fifo(fdctrl, 1, 1);
}

B
Blue Swirl 已提交
1593
static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
1594 1595 1596 1597 1598
{
    /* No result back */
    fdctrl_reset_fifo(fdctrl);
}

B
Blue Swirl 已提交
1599
static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
1600
{
B
Blue Swirl 已提交
1601
    FDrive *cur_drv = get_cur_drv(fdctrl);
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615

    if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
        /* Command parameters done */
        if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
            fdctrl->fifo[0] = fdctrl->fifo[1];
            fdctrl->fifo[2] = 0;
            fdctrl->fifo[3] = 0;
            fdctrl_set_fifo(fdctrl, 4, 1);
        } else {
            fdctrl_reset_fifo(fdctrl);
        }
    } else if (fdctrl->data_len > 7) {
        /* ERROR */
        fdctrl->fifo[0] = 0x80 |
B
blueswir1 已提交
1616
            (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1617 1618 1619 1620
        fdctrl_set_fifo(fdctrl, 1, 1);
    }
}

B
Blue Swirl 已提交
1621
static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
1622
{
B
Blue Swirl 已提交
1623
    FDrive *cur_drv;
1624

B
blueswir1 已提交
1625
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1626 1627 1628 1629 1630 1631 1632
    cur_drv = get_cur_drv(fdctrl);
    if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
        cur_drv->track = cur_drv->max_track - 1;
    } else {
        cur_drv->track += fdctrl->fifo[2];
    }
    fdctrl_reset_fifo(fdctrl);
B
blueswir1 已提交
1633
    /* Raise Interrupt */
1634 1635 1636
    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
}

B
Blue Swirl 已提交
1637
static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
1638
{
B
Blue Swirl 已提交
1639
    FDrive *cur_drv;
1640

B
blueswir1 已提交
1641
    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
    cur_drv = get_cur_drv(fdctrl);
    if (fdctrl->fifo[2] > cur_drv->track) {
        cur_drv->track = 0;
    } else {
        cur_drv->track -= fdctrl->fifo[2];
    }
    fdctrl_reset_fifo(fdctrl);
    /* Raise Interrupt */
    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
}

B
blueswir1 已提交
1653 1654 1655 1656 1657
static const struct {
    uint8_t value;
    uint8_t mask;
    const char* name;
    int parameters;
B
Blue Swirl 已提交
1658
    void (*handler)(FDCtrl *fdctrl, int direction);
B
blueswir1 已提交
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
    int direction;
} handlers[] = {
    { 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 },
    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
    { 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];

B
Blue Swirl 已提交
1697
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
1698
{
B
Blue Swirl 已提交
1699
    FDrive *cur_drv;
1700
    int pos;
1701

B
bellard 已提交
1702
    /* Reset mode */
B
blueswir1 已提交
1703
    if (!(fdctrl->dor & FD_DOR_nRESET)) {
B
bellard 已提交
1704
        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
B
bellard 已提交
1705 1706
        return;
    }
B
blueswir1 已提交
1707 1708
    if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
        FLOPPY_ERROR("controller not ready for writing\n");
B
bellard 已提交
1709 1710
        return;
    }
B
blueswir1 已提交
1711
    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
B
bellard 已提交
1712
    /* Is it write command time ? */
B
blueswir1 已提交
1713
    if (fdctrl->msr & FD_MSR_NONDMA) {
B
bellard 已提交
1714
        /* FIFO data write */
1715 1716 1717 1718
        pos = fdctrl->data_pos++;
        pos %= FD_SECTOR_LEN;
        fdctrl->fifo[pos] = value;
        if (pos == FD_SECTOR_LEN - 1 ||
1719
            fdctrl->data_pos == fdctrl->data_len) {
B
blueswir1 已提交
1720 1721 1722 1723 1724
            cur_drv = get_cur_drv(fdctrl);
            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
                return;
            }
B
blueswir1 已提交
1725 1726 1727 1728 1729
            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
                FLOPPY_DPRINTF("error seeking to next sector %d\n",
                               fd_sector(cur_drv));
                return;
            }
B
bellard 已提交
1730
        }
1731
        /* Switch from transfer mode to status mode
B
bellard 已提交
1732 1733
         * then from status mode to command mode
         */
B
blueswir1 已提交
1734
        if (fdctrl->data_pos == fdctrl->data_len)
1735
            fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
B
bellard 已提交
1736 1737
        return;
    }
1738
    if (fdctrl->data_pos == 0) {
B
bellard 已提交
1739
        /* Command */
B
blueswir1 已提交
1740 1741 1742
        pos = command_to_handler[value & 0xff];
        FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
        fdctrl->data_len = handlers[pos].parameters + 1;
B
bellard 已提交
1743
    }
B
blueswir1 已提交
1744

1745
    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
B
blueswir1 已提交
1746 1747
    fdctrl->fifo[fdctrl->data_pos++] = value;
    if (fdctrl->data_pos == fdctrl->data_len) {
B
bellard 已提交
1748 1749 1750
        /* We now have all parameters
         * and will be able to treat the command
         */
1751 1752
        if (fdctrl->data_state & FD_STATE_FORMAT) {
            fdctrl_format_sector(fdctrl);
B
bellard 已提交
1753 1754
            return;
        }
1755

B
blueswir1 已提交
1756 1757 1758
        pos = command_to_handler[fdctrl->fifo[0] & 0xff];
        FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
        (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
B
bellard 已提交
1759 1760
    }
}
1761 1762 1763

static void fdctrl_result_timer(void *opaque)
{
B
Blue Swirl 已提交
1764 1765
    FDCtrl *fdctrl = opaque;
    FDrive *cur_drv = get_cur_drv(fdctrl);
1766

1767 1768 1769 1770 1771 1772 1773
    /* 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;
    }
1774 1775
    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
}
B
blueswir1 已提交
1776

1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
static void fdctrl_change_cb(void *opaque)
{
    FDrive *drive = opaque;

    drive->media_changed = 1;
}

static const BlockDevOps fdctrl_block_ops = {
    .change_media_cb = fdctrl_change_cb,
};

B
blueswir1 已提交
1788
/* Init functions */
1789
static int fdctrl_connect_drives(FDCtrl *fdctrl)
B
blueswir1 已提交
1790
{
B
Blue Swirl 已提交
1791
    unsigned int i;
1792
    FDrive *drive;
B
blueswir1 已提交
1793 1794

    for (i = 0; i < MAX_FD; i++) {
1795 1796
        drive = &fdctrl->drives[i];

1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
        if (drive->bs) {
            if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
                error_report("fdc doesn't support drive option werror");
                return -1;
            }
            if (bdrv_get_on_error(drive->bs, 1) != BLOCK_ERR_REPORT) {
                error_report("fdc doesn't support drive option rerror");
                return -1;
            }
        }

1808 1809 1810
        fd_init(drive);
        fd_revalidate(drive);
        if (drive->bs) {
1811
            drive->media_changed = 1;
1812
            bdrv_set_removable(drive->bs, 1);
1813
            bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
1814
        }
B
blueswir1 已提交
1815
    }
1816
    return 0;
B
blueswir1 已提交
1817 1818
}

B
Blue Swirl 已提交
1819 1820
void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                        target_phys_addr_t mmio_base, DriveInfo **fds)
G
Gerd Hoffmann 已提交
1821
{
B
Blue Swirl 已提交
1822
    FDCtrl *fdctrl;
G
Gerd Hoffmann 已提交
1823
    DeviceState *dev;
B
Blue Swirl 已提交
1824
    FDCtrlSysBus *sys;
G
Gerd Hoffmann 已提交
1825 1826

    dev = qdev_create(NULL, "sysbus-fdc");
B
Blue Swirl 已提交
1827
    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
1828 1829
    fdctrl = &sys->state;
    fdctrl->dma_chann = dma_chann; /* FIXME */
1830
    if (fds[0]) {
1831
        qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
1832 1833
    }
    if (fds[1]) {
1834
        qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
1835
    }
M
Markus Armbruster 已提交
1836
    qdev_init_nofail(dev);
G
Gerd Hoffmann 已提交
1837 1838
    sysbus_connect_irq(&sys->busdev, 0, irq);
    sysbus_mmio_map(&sys->busdev, 0, mmio_base);
B
blueswir1 已提交
1839 1840
}

B
Blue Swirl 已提交
1841 1842
void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
                       DriveInfo **fds, qemu_irq *fdc_tc)
B
blueswir1 已提交
1843
{
B
Blue Swirl 已提交
1844
    DeviceState *dev;
B
Blue Swirl 已提交
1845
    FDCtrlSysBus *sys;
B
blueswir1 已提交
1846

B
Blue Swirl 已提交
1847
    dev = qdev_create(NULL, "SUNW,fdtwo");
1848
    if (fds[0]) {
1849
        qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
1850
    }
M
Markus Armbruster 已提交
1851
    qdev_init_nofail(dev);
B
Blue Swirl 已提交
1852
    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
G
Gerd Hoffmann 已提交
1853 1854
    sysbus_connect_irq(&sys->busdev, 0, irq);
    sysbus_mmio_map(&sys->busdev, 0, io_base);
B
Blue Swirl 已提交
1855
    *fdc_tc = qdev_get_gpio_in(dev, 0);
B
blueswir1 已提交
1856
}
B
Blue Swirl 已提交
1857

J
Jan Kiszka 已提交
1858
static int fdctrl_init_common(FDCtrl *fdctrl)
B
Blue Swirl 已提交
1859
{
B
Blue Swirl 已提交
1860 1861
    int i, j;
    static int command_tables_inited = 0;
B
Blue Swirl 已提交
1862

B
Blue Swirl 已提交
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
    /* 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);
J
Juan Quintela 已提交
1877
    fdctrl->fifo_size = 512;
1878
    fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
B
Blue Swirl 已提交
1879 1880 1881 1882
                                          fdctrl_result_timer, fdctrl);

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

1885 1886
    if (fdctrl->dma_chann != -1)
        DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
1887
    return fdctrl_connect_drives(fdctrl);
B
Blue Swirl 已提交
1888 1889
}

1890
static int isabus_fdc_init1(ISADevice *dev)
G
Gerd Hoffmann 已提交
1891
{
B
Blue Swirl 已提交
1892 1893
    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
    FDCtrl *fdctrl = &isa->state;
1894
    int iobase = 0x3f0;
1895
    int isairq = 6;
1896
    int dma_chann = 2;
B
Blue Swirl 已提交
1897
    int ret;
G
Gerd Hoffmann 已提交
1898

1899
    register_ioport_read(iobase + 0x01, 5, 1,
G
Gerd Hoffmann 已提交
1900
                         &fdctrl_read_port, fdctrl);
1901
    register_ioport_read(iobase + 0x07, 1, 1,
G
Gerd Hoffmann 已提交
1902
                         &fdctrl_read_port, fdctrl);
1903
    register_ioport_write(iobase + 0x01, 5, 1,
G
Gerd Hoffmann 已提交
1904
                          &fdctrl_write_port, fdctrl);
1905
    register_ioport_write(iobase + 0x07, 1, 1,
G
Gerd Hoffmann 已提交
1906
                          &fdctrl_write_port, fdctrl);
1907 1908 1909
    isa_init_ioport_range(dev, iobase, 6);
    isa_init_ioport(dev, iobase + 7);

1910
    isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
1911
    fdctrl->dma_chann = dma_chann;
G
Gerd Hoffmann 已提交
1912

J
Jan Kiszka 已提交
1913 1914
    qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
    ret = fdctrl_init_common(fdctrl);
B
Blue Swirl 已提交
1915

1916 1917 1918
    add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0");
    add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy@1");

B
Blue Swirl 已提交
1919
    return ret;
G
Gerd Hoffmann 已提交
1920 1921
}

1922
static int sysbus_fdc_init1(SysBusDevice *dev)
B
Blue Swirl 已提交
1923
{
B
Blue Swirl 已提交
1924 1925
    FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
    FDCtrl *fdctrl = &sys->state;
B
Blue Swirl 已提交
1926
    int io;
B
Blue Swirl 已提交
1927
    int ret;
B
Blue Swirl 已提交
1928

1929 1930
    io = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl,
                                DEVICE_NATIVE_ENDIAN);
G
Gerd Hoffmann 已提交
1931 1932 1933
    sysbus_init_mmio(dev, 0x08, io);
    sysbus_init_irq(dev, &fdctrl->irq);
    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
1934
    fdctrl->dma_chann = -1;
G
Gerd Hoffmann 已提交
1935

J
Jan Kiszka 已提交
1936 1937
    qdev_set_legacy_instance_id(&dev->qdev, io, 2);
    ret = fdctrl_init_common(fdctrl);
B
Blue Swirl 已提交
1938 1939

    return ret;
B
Blue Swirl 已提交
1940 1941
}

1942
static int sun4m_fdc_init1(SysBusDevice *dev)
B
Blue Swirl 已提交
1943
{
B
Blue Swirl 已提交
1944
    FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
B
Blue Swirl 已提交
1945 1946 1947
    int io;

    io = cpu_register_io_memory(fdctrl_mem_read_strict,
1948 1949
                                fdctrl_mem_write_strict, fdctrl,
                                DEVICE_NATIVE_ENDIAN);
G
Gerd Hoffmann 已提交
1950 1951 1952 1953 1954
    sysbus_init_mmio(dev, 0x08, io);
    sysbus_init_irq(dev, &fdctrl->irq);
    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);

    fdctrl->sun4m = 1;
J
Jan Kiszka 已提交
1955 1956
    qdev_set_legacy_instance_id(&dev->qdev, io, 2);
    return fdctrl_init_common(fdctrl);
B
Blue Swirl 已提交
1957
}
B
Blue Swirl 已提交
1958

J
Jan Kiszka 已提交
1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
static const VMStateDescription vmstate_isa_fdc ={
    .name = "fdc",
    .version_id = 2,
    .minimum_version_id = 2,
    .fields = (VMStateField []) {
        VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

G
Gerd Hoffmann 已提交
1969 1970 1971
static ISADeviceInfo isa_fdc_info = {
    .init = isabus_fdc_init1,
    .qdev.name  = "isa-fdc",
1972
    .qdev.fw_name  = "fdc",
B
Blue Swirl 已提交
1973
    .qdev.size  = sizeof(FDCtrlISABus),
1974
    .qdev.no_user = 1,
J
Jan Kiszka 已提交
1975
    .qdev.vmsd  = &vmstate_isa_fdc,
B
Blue Swirl 已提交
1976
    .qdev.reset = fdctrl_external_reset_isa,
G
Gerd Hoffmann 已提交
1977
    .qdev.props = (Property[]) {
1978 1979
        DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
        DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
1980 1981
        DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
        DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
G
Gerd Hoffmann 已提交
1982 1983
        DEFINE_PROP_END_OF_LIST(),
    },
G
Gerd Hoffmann 已提交
1984 1985
};

J
Jan Kiszka 已提交
1986 1987 1988 1989 1990 1991 1992 1993 1994 1995
static const VMStateDescription vmstate_sysbus_fdc ={
    .name = "fdc",
    .version_id = 2,
    .minimum_version_id = 2,
    .fields = (VMStateField []) {
        VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
        VMSTATE_END_OF_LIST()
    }
};

G
Gerd Hoffmann 已提交
1996 1997 1998
static SysBusDeviceInfo sysbus_fdc_info = {
    .init = sysbus_fdc_init1,
    .qdev.name  = "sysbus-fdc",
B
Blue Swirl 已提交
1999
    .qdev.size  = sizeof(FDCtrlSysBus),
J
Jan Kiszka 已提交
2000
    .qdev.vmsd  = &vmstate_sysbus_fdc,
B
Blue Swirl 已提交
2001
    .qdev.reset = fdctrl_external_reset_sysbus,
G
Gerd Hoffmann 已提交
2002
    .qdev.props = (Property[]) {
2003 2004
        DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
        DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
G
Gerd Hoffmann 已提交
2005 2006
        DEFINE_PROP_END_OF_LIST(),
    },
B
Blue Swirl 已提交
2007 2008 2009 2010 2011
};

static SysBusDeviceInfo sun4m_fdc_info = {
    .init = sun4m_fdc_init1,
    .qdev.name  = "SUNW,fdtwo",
B
Blue Swirl 已提交
2012
    .qdev.size  = sizeof(FDCtrlSysBus),
J
Jan Kiszka 已提交
2013
    .qdev.vmsd  = &vmstate_sysbus_fdc,
B
Blue Swirl 已提交
2014
    .qdev.reset = fdctrl_external_reset_sysbus,
G
Gerd Hoffmann 已提交
2015
    .qdev.props = (Property[]) {
2016
        DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
G
Gerd Hoffmann 已提交
2017 2018
        DEFINE_PROP_END_OF_LIST(),
    },
B
Blue Swirl 已提交
2019 2020 2021 2022
};

static void fdc_register_devices(void)
{
G
Gerd Hoffmann 已提交
2023 2024
    isa_qdev_register(&isa_fdc_info);
    sysbus_register_withprop(&sysbus_fdc_info);
B
Blue Swirl 已提交
2025
    sysbus_register_withprop(&sun4m_fdc_info);
B
Blue Swirl 已提交
2026 2027 2028
}

device_init(fdc_register_devices)