]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/block/fdc.c
Include migration/vmstate.h less
[thirdparty/qemu.git] / hw / block / fdc.c
CommitLineData
8977f3c1 1/*
890fa6be 2 * QEMU Floppy disk emulator (Intel 82078)
5fafdf24 3 *
3ccacc4a 4 * Copyright (c) 2003, 2007 Jocelyn Mayer
bcc4e41f 5 * Copyright (c) 2008 Hervé Poussineau
5fafdf24 6 *
8977f3c1
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
e80cfcfc
FB
25/*
26 * The controller is used in Sun4m systems in a slightly different
27 * way. There are changes in DOR register and DMA is not available.
28 */
f64ab228 29
80c71a24 30#include "qemu/osdep.h"
83c9f4ca 31#include "hw/hw.h"
0d09e41a 32#include "hw/block/fdc.h"
da34e65c 33#include "qapi/error.h"
1de7afc9
PB
34#include "qemu/error-report.h"
35#include "qemu/timer.h"
64552b6b 36#include "hw/irq.h"
0d09e41a 37#include "hw/isa/isa.h"
83c9f4ca 38#include "hw/sysbus.h"
d6454270 39#include "migration/vmstate.h"
a92bd191 40#include "hw/block/block.h"
fa1d36df 41#include "sysemu/block-backend.h"
9c17d615
PB
42#include "sysemu/blockdev.h"
43#include "sysemu/sysemu.h"
1de7afc9 44#include "qemu/log.h"
0b8fa32f 45#include "qemu/module.h"
1a5396d9 46#include "trace.h"
8977f3c1
FB
47
48/********************************************************/
49/* debug Floppy devices */
8977f3c1 50
c691320f
JS
51#define DEBUG_FLOPPY 0
52
001faf32 53#define FLOPPY_DPRINTF(fmt, ...) \
c691320f
JS
54 do { \
55 if (DEBUG_FLOPPY) { \
56 fprintf(stderr, "FLOPPY: " fmt , ## __VA_ARGS__); \
57 } \
58 } while (0)
8977f3c1 59
51e6e90e
KW
60
61/********************************************************/
62/* qdev floppy bus */
63
64#define TYPE_FLOPPY_BUS "floppy-bus"
65#define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)
66
67typedef struct FDCtrl FDCtrl;
394ea2ca
KW
68typedef struct FDrive FDrive;
69static FDrive *get_drv(FDCtrl *fdctrl, int unit);
51e6e90e
KW
70
71typedef struct FloppyBus {
72 BusState bus;
73 FDCtrl *fdc;
74} FloppyBus;
75
76static const TypeInfo floppy_bus_info = {
77 .name = TYPE_FLOPPY_BUS,
78 .parent = TYPE_BUS,
79 .instance_size = sizeof(FloppyBus),
80};
81
82static void floppy_bus_create(FDCtrl *fdc, FloppyBus *bus, DeviceState *dev)
83{
84 qbus_create_inplace(bus, sizeof(FloppyBus), TYPE_FLOPPY_BUS, dev, NULL);
85 bus->fdc = fdc;
86}
87
88
8977f3c1
FB
89/********************************************************/
90/* Floppy drive emulation */
91
61a8d649
MA
92typedef enum FDriveRate {
93 FDRIVE_RATE_500K = 0x00, /* 500 Kbps */
94 FDRIVE_RATE_300K = 0x01, /* 300 Kbps */
95 FDRIVE_RATE_250K = 0x02, /* 250 Kbps */
96 FDRIVE_RATE_1M = 0x03, /* 1 Mbps */
97} FDriveRate;
98
109c17bc
JS
99typedef enum FDriveSize {
100 FDRIVE_SIZE_UNKNOWN,
101 FDRIVE_SIZE_350,
102 FDRIVE_SIZE_525,
103} FDriveSize;
104
61a8d649 105typedef struct FDFormat {
2da44dd0 106 FloppyDriveType drive;
61a8d649
MA
107 uint8_t last_sect;
108 uint8_t max_track;
109 uint8_t max_head;
110 FDriveRate rate;
111} FDFormat;
112
109c17bc
JS
113/* In many cases, the total sector size of a format is enough to uniquely
114 * identify it. However, there are some total sector collisions between
115 * formats of different physical size, and these are noted below by
116 * highlighting the total sector size for entries with collisions. */
61a8d649
MA
117static const FDFormat fd_formats[] = {
118 /* First entry is default format */
119 /* 1.44 MB 3"1/2 floppy disks */
109c17bc
JS
120 { FLOPPY_DRIVE_TYPE_144, 18, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 2880 */
121 { FLOPPY_DRIVE_TYPE_144, 20, 80, 1, FDRIVE_RATE_500K, }, /* 3.5" 3200 */
2da44dd0
JS
122 { FLOPPY_DRIVE_TYPE_144, 21, 80, 1, FDRIVE_RATE_500K, },
123 { FLOPPY_DRIVE_TYPE_144, 21, 82, 1, FDRIVE_RATE_500K, },
124 { FLOPPY_DRIVE_TYPE_144, 21, 83, 1, FDRIVE_RATE_500K, },
125 { FLOPPY_DRIVE_TYPE_144, 22, 80, 1, FDRIVE_RATE_500K, },
126 { FLOPPY_DRIVE_TYPE_144, 23, 80, 1, FDRIVE_RATE_500K, },
127 { FLOPPY_DRIVE_TYPE_144, 24, 80, 1, FDRIVE_RATE_500K, },
61a8d649 128 /* 2.88 MB 3"1/2 floppy disks */
2da44dd0
JS
129 { FLOPPY_DRIVE_TYPE_288, 36, 80, 1, FDRIVE_RATE_1M, },
130 { FLOPPY_DRIVE_TYPE_288, 39, 80, 1, FDRIVE_RATE_1M, },
131 { FLOPPY_DRIVE_TYPE_288, 40, 80, 1, FDRIVE_RATE_1M, },
132 { FLOPPY_DRIVE_TYPE_288, 44, 80, 1, FDRIVE_RATE_1M, },
133 { FLOPPY_DRIVE_TYPE_288, 48, 80, 1, FDRIVE_RATE_1M, },
61a8d649 134 /* 720 kB 3"1/2 floppy disks */
109c17bc 135 { FLOPPY_DRIVE_TYPE_144, 9, 80, 1, FDRIVE_RATE_250K, }, /* 3.5" 1440 */
2da44dd0
JS
136 { FLOPPY_DRIVE_TYPE_144, 10, 80, 1, FDRIVE_RATE_250K, },
137 { FLOPPY_DRIVE_TYPE_144, 10, 82, 1, FDRIVE_RATE_250K, },
138 { FLOPPY_DRIVE_TYPE_144, 10, 83, 1, FDRIVE_RATE_250K, },
139 { FLOPPY_DRIVE_TYPE_144, 13, 80, 1, FDRIVE_RATE_250K, },
140 { FLOPPY_DRIVE_TYPE_144, 14, 80, 1, FDRIVE_RATE_250K, },
61a8d649 141 /* 1.2 MB 5"1/4 floppy disks */
2da44dd0 142 { FLOPPY_DRIVE_TYPE_120, 15, 80, 1, FDRIVE_RATE_500K, },
109c17bc 143 { FLOPPY_DRIVE_TYPE_120, 18, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 2880 */
2da44dd0
JS
144 { FLOPPY_DRIVE_TYPE_120, 18, 82, 1, FDRIVE_RATE_500K, },
145 { FLOPPY_DRIVE_TYPE_120, 18, 83, 1, FDRIVE_RATE_500K, },
109c17bc 146 { FLOPPY_DRIVE_TYPE_120, 20, 80, 1, FDRIVE_RATE_500K, }, /* 5.25" 3200 */
61a8d649 147 /* 720 kB 5"1/4 floppy disks */
109c17bc 148 { FLOPPY_DRIVE_TYPE_120, 9, 80, 1, FDRIVE_RATE_250K, }, /* 5.25" 1440 */
2da44dd0 149 { FLOPPY_DRIVE_TYPE_120, 11, 80, 1, FDRIVE_RATE_250K, },
61a8d649 150 /* 360 kB 5"1/4 floppy disks */
109c17bc 151 { FLOPPY_DRIVE_TYPE_120, 9, 40, 1, FDRIVE_RATE_300K, }, /* 5.25" 720 */
2da44dd0
JS
152 { FLOPPY_DRIVE_TYPE_120, 9, 40, 0, FDRIVE_RATE_300K, },
153 { FLOPPY_DRIVE_TYPE_120, 10, 41, 1, FDRIVE_RATE_300K, },
154 { FLOPPY_DRIVE_TYPE_120, 10, 42, 1, FDRIVE_RATE_300K, },
61a8d649 155 /* 320 kB 5"1/4 floppy disks */
2da44dd0
JS
156 { FLOPPY_DRIVE_TYPE_120, 8, 40, 1, FDRIVE_RATE_250K, },
157 { FLOPPY_DRIVE_TYPE_120, 8, 40, 0, FDRIVE_RATE_250K, },
61a8d649 158 /* 360 kB must match 5"1/4 better than 3"1/2... */
109c17bc 159 { FLOPPY_DRIVE_TYPE_144, 9, 80, 0, FDRIVE_RATE_250K, }, /* 3.5" 720 */
61a8d649 160 /* end */
2da44dd0 161 { FLOPPY_DRIVE_TYPE_NONE, -1, -1, 0, 0, },
61a8d649
MA
162};
163
109c17bc
JS
164static FDriveSize drive_size(FloppyDriveType drive)
165{
166 switch (drive) {
167 case FLOPPY_DRIVE_TYPE_120:
168 return FDRIVE_SIZE_525;
169 case FLOPPY_DRIVE_TYPE_144:
170 case FLOPPY_DRIVE_TYPE_288:
171 return FDRIVE_SIZE_350;
172 default:
173 return FDRIVE_SIZE_UNKNOWN;
174 }
175}
176
cefec4f5
BS
177#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
178#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
179
8977f3c1 180/* Will always be a fixed parameter for us */
f2d81b33
BS
181#define FD_SECTOR_LEN 512
182#define FD_SECTOR_SC 2 /* Sector size code */
183#define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */
8977f3c1
FB
184
185/* Floppy disk drive emulation */
5c02c033 186typedef enum FDiskFlags {
baca51fa 187 FDISK_DBL_SIDES = 0x01,
5c02c033 188} FDiskFlags;
baca51fa 189
394ea2ca 190struct FDrive {
844f65d6 191 FDCtrl *fdctrl;
4be74634 192 BlockBackend *blk;
a17c17a2 193 BlockConf *conf;
8977f3c1 194 /* Drive status */
2da44dd0 195 FloppyDriveType drive; /* CMOS drive type */
8977f3c1 196 uint8_t perpendicular; /* 2.88 MB access mode */
8977f3c1
FB
197 /* Position */
198 uint8_t head;
199 uint8_t track;
200 uint8_t sect;
8977f3c1 201 /* Media */
16c1e3ec 202 FloppyDriveType disk; /* Current disk type */
5c02c033 203 FDiskFlags flags;
8977f3c1
FB
204 uint8_t last_sect; /* Nb sector per track */
205 uint8_t max_track; /* Nb of tracks */
baca51fa 206 uint16_t bps; /* Bytes per sector */
8977f3c1 207 uint8_t ro; /* Is read-only */
7d905f71 208 uint8_t media_changed; /* Is media changed */
844f65d6 209 uint8_t media_rate; /* Data rate of medium */
2e1280e8 210
d5d47efc 211 bool media_validated; /* Have we validated the media? */
394ea2ca 212};
8977f3c1 213
a73275dd
JS
214
215static FloppyDriveType get_fallback_drive_type(FDrive *drv);
216
fd9bdbd3
JS
217/* Hack: FD_SEEK is expected to work on empty drives. However, QEMU
218 * currently goes through some pains to keep seeks within the bounds
219 * established by last_sect and max_track. Correcting this is difficult,
220 * as refactoring FDC code tends to expose nasty bugs in the Linux kernel.
221 *
222 * For now: allow empty drives to have large bounds so we can seek around,
223 * with the understanding that when a diskette is inserted, the bounds will
224 * properly tighten to match the geometry of that inserted medium.
225 */
226static void fd_empty_seek_hack(FDrive *drv)
227{
228 drv->last_sect = 0xFF;
229 drv->max_track = 0xFF;
230}
231
5c02c033 232static void fd_init(FDrive *drv)
8977f3c1
FB
233{
234 /* Drive */
8977f3c1 235 drv->perpendicular = 0;
8977f3c1 236 /* Disk */
16c1e3ec 237 drv->disk = FLOPPY_DRIVE_TYPE_NONE;
baca51fa 238 drv->last_sect = 0;
8977f3c1 239 drv->max_track = 0;
d5d47efc
JS
240 drv->ro = true;
241 drv->media_changed = 1;
8977f3c1
FB
242}
243
08388273
HP
244#define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)
245
7859cb98 246static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
08388273 247 uint8_t last_sect, uint8_t num_sides)
8977f3c1 248{
08388273 249 return (((track * num_sides) + head) * last_sect) + sect - 1;
8977f3c1
FB
250}
251
252/* Returns current position, in sectors, for given drive */
5c02c033 253static int fd_sector(FDrive *drv)
8977f3c1 254{
08388273
HP
255 return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect,
256 NUM_SIDES(drv));
8977f3c1
FB
257}
258
a7a5b7c0
EB
259/* Returns current position, in bytes, for given drive */
260static int fd_offset(FDrive *drv)
261{
262 g_assert(fd_sector(drv) < INT_MAX >> BDRV_SECTOR_BITS);
263 return fd_sector(drv) << BDRV_SECTOR_BITS;
264}
265
77370520
BS
266/* Seek to a new position:
267 * returns 0 if already on right track
268 * returns 1 if track changed
269 * returns 2 if track is invalid
270 * returns 3 if sector is invalid
271 * returns 4 if seek is disabled
272 */
5c02c033
BS
273static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
274 int enable_seek)
8977f3c1
FB
275{
276 uint32_t sector;
baca51fa
FB
277 int ret;
278
279 if (track > drv->max_track ||
4f431960 280 (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
ed5fd2cc
FB
281 FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
282 head, track, sect, 1,
283 (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
284 drv->max_track, drv->last_sect);
8977f3c1
FB
285 return 2;
286 }
287 if (sect > drv->last_sect) {
ed5fd2cc
FB
288 FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
289 head, track, sect, 1,
290 (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
291 drv->max_track, drv->last_sect);
8977f3c1
FB
292 return 3;
293 }
08388273 294 sector = fd_sector_calc(head, track, sect, drv->last_sect, NUM_SIDES(drv));
baca51fa 295 ret = 0;
8977f3c1
FB
296 if (sector != fd_sector(drv)) {
297#if 0
298 if (!enable_seek) {
cced7a13
BS
299 FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
300 " (max=%d %02x %02x)\n",
301 head, track, sect, 1, drv->max_track,
302 drv->last_sect);
8977f3c1
FB
303 return 4;
304 }
305#endif
306 drv->head = head;
6be01b1e 307 if (drv->track != track) {
abb3e55b 308 if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
6be01b1e
PH
309 drv->media_changed = 0;
310 }
4f431960 311 ret = 1;
6be01b1e 312 }
8977f3c1
FB
313 drv->track = track;
314 drv->sect = sect;
8977f3c1
FB
315 }
316
abb3e55b 317 if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
c52acf60
PH
318 ret = 2;
319 }
320
baca51fa 321 return ret;
8977f3c1
FB
322}
323
324/* Set drive back to track 0 */
5c02c033 325static void fd_recalibrate(FDrive *drv)
8977f3c1
FB
326{
327 FLOPPY_DPRINTF("recalibrate\n");
6be01b1e 328 fd_seek(drv, 0, 0, 1, 1);
8977f3c1
FB
329}
330
d5d47efc
JS
331/**
332 * Determine geometry based on inserted diskette.
333 * Will not operate on an empty drive.
334 *
335 * @return: 0 on success, -1 if the drive is empty.
336 */
337static int pick_geometry(FDrive *drv)
9a972233 338{
21862658 339 BlockBackend *blk = drv->blk;
9a972233
JS
340 const FDFormat *parse;
341 uint64_t nb_sectors, size;
f31937aa
JS
342 int i;
343 int match, size_match, type_match;
344 bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO;
9a972233 345
d5d47efc 346 /* We can only pick a geometry if we have a diskette. */
abb3e55b
HR
347 if (!drv->blk || !blk_is_inserted(drv->blk) ||
348 drv->drive == FLOPPY_DRIVE_TYPE_NONE)
349 {
d5d47efc
JS
350 return -1;
351 }
352
f31937aa
JS
353 /* We need to determine the likely geometry of the inserted medium.
354 * In order of preference, we look for:
355 * (1) The same drive type and number of sectors,
356 * (2) The same diskette size and number of sectors,
357 * (3) The same drive type.
358 *
359 * In all cases, matches that occur higher in the drive table will take
360 * precedence over matches that occur later in the table.
361 */
9a972233 362 blk_get_geometry(blk, &nb_sectors);
f31937aa 363 match = size_match = type_match = -1;
9a972233
JS
364 for (i = 0; ; i++) {
365 parse = &fd_formats[i];
2da44dd0 366 if (parse->drive == FLOPPY_DRIVE_TYPE_NONE) {
9a972233
JS
367 break;
368 }
f31937aa
JS
369 size = (parse->max_head + 1) * parse->max_track * parse->last_sect;
370 if (nb_sectors == size) {
371 if (magic || parse->drive == drv->drive) {
372 /* (1) perfect match -- nb_sectors and drive type */
373 goto out;
374 } else if (drive_size(parse->drive) == drive_size(drv->drive)) {
375 /* (2) size match -- nb_sectors and physical medium size */
376 match = (match == -1) ? i : match;
377 } else {
378 /* This is suspicious -- Did the user misconfigure? */
379 size_match = (size_match == -1) ? i : size_match;
9a972233 380 }
f31937aa
JS
381 } else if (type_match == -1) {
382 if ((parse->drive == drv->drive) ||
383 (magic && (parse->drive == get_fallback_drive_type(drv)))) {
384 /* (3) type match -- nb_sectors mismatch, but matches the type
385 * specified explicitly by the user, or matches the fallback
386 * default type when using the drive autodetect mechanism */
387 type_match = i;
9a972233
JS
388 }
389 }
390 }
f31937aa
JS
391
392 /* No exact match found */
9a972233 393 if (match == -1) {
f31937aa
JS
394 if (size_match != -1) {
395 parse = &fd_formats[size_match];
396 FLOPPY_DPRINTF("User requested floppy drive type '%s', "
397 "but inserted medium appears to be a "
c691320f 398 "%"PRId64" sector '%s' type\n",
977c736f 399 FloppyDriveType_str(drv->drive),
f31937aa 400 nb_sectors,
977c736f 401 FloppyDriveType_str(parse->drive));
9a972233 402 }
329b7291 403 assert(type_match != -1 && "misconfigured fd_format");
f31937aa 404 match = type_match;
9a972233 405 }
f31937aa
JS
406 parse = &(fd_formats[match]);
407
408 out:
21862658
JS
409 if (parse->max_head == 0) {
410 drv->flags &= ~FDISK_DBL_SIDES;
411 } else {
412 drv->flags |= FDISK_DBL_SIDES;
413 }
414 drv->max_track = parse->max_track;
415 drv->last_sect = parse->last_sect;
d5d47efc 416 drv->disk = parse->drive;
21862658 417 drv->media_rate = parse->rate;
d5d47efc
JS
418 return 0;
419}
420
421static void pick_drive_type(FDrive *drv)
422{
fff4687b
JS
423 if (drv->drive != FLOPPY_DRIVE_TYPE_AUTO) {
424 return;
425 }
426
d5d47efc
JS
427 if (pick_geometry(drv) == 0) {
428 drv->drive = drv->disk;
429 } else {
a73275dd 430 drv->drive = get_fallback_drive_type(drv);
d5d47efc 431 }
fff4687b
JS
432
433 g_assert(drv->drive != FLOPPY_DRIVE_TYPE_AUTO);
9a972233
JS
434}
435
8977f3c1 436/* Revalidate a disk drive after a disk change */
5c02c033 437static void fd_revalidate(FDrive *drv)
8977f3c1 438{
d5d47efc
JS
439 int rc;
440
8977f3c1 441 FLOPPY_DPRINTF("revalidate\n");
4be74634 442 if (drv->blk != NULL) {
21862658 443 drv->ro = blk_is_read_only(drv->blk);
abb3e55b 444 if (!blk_is_inserted(drv->blk)) {
cfb08fba 445 FLOPPY_DPRINTF("No disk in drive\n");
d5d47efc 446 drv->disk = FLOPPY_DRIVE_TYPE_NONE;
fd9bdbd3 447 fd_empty_seek_hack(drv);
d5d47efc
JS
448 } else if (!drv->media_validated) {
449 rc = pick_geometry(drv);
450 if (rc) {
451 FLOPPY_DPRINTF("Could not validate floppy drive media");
452 } else {
453 drv->media_validated = true;
454 FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n",
455 (drv->flags & FDISK_DBL_SIDES) ? 2 : 1,
456 drv->max_track, drv->last_sect,
457 drv->ro ? "ro" : "rw");
458 }
4f431960 459 }
8977f3c1 460 } else {
cfb08fba 461 FLOPPY_DPRINTF("No drive connected\n");
baca51fa 462 drv->last_sect = 0;
4f431960
JM
463 drv->max_track = 0;
464 drv->flags &= ~FDISK_DBL_SIDES;
d5d47efc
JS
465 drv->drive = FLOPPY_DRIVE_TYPE_NONE;
466 drv->disk = FLOPPY_DRIVE_TYPE_NONE;
8977f3c1 467 }
caed8802
FB
468}
469
39829a01 470static void fd_change_cb(void *opaque, bool load, Error **errp)
394ea2ca
KW
471{
472 FDrive *drive = opaque;
a17c17a2
KW
473
474 if (!load) {
475 blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
476 } else {
ceff3e1f
MZ
477 if (!blkconf_apply_backend_options(drive->conf,
478 blk_is_read_only(drive->blk), false,
479 errp)) {
a17c17a2
KW
480 return;
481 }
482 }
394ea2ca
KW
483
484 drive->media_changed = 1;
485 drive->media_validated = false;
486 fd_revalidate(drive);
487}
488
489static const BlockDevOps fd_block_ops = {
490 .change_media_cb = fd_change_cb,
491};
492
493
494#define TYPE_FLOPPY_DRIVE "floppy"
495#define FLOPPY_DRIVE(obj) \
496 OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
497
498typedef struct FloppyDrive {
a92bd191
KW
499 DeviceState qdev;
500 uint32_t unit;
501 BlockConf conf;
502 FloppyDriveType type;
394ea2ca
KW
503} FloppyDrive;
504
505static Property floppy_drive_properties[] = {
506 DEFINE_PROP_UINT32("unit", FloppyDrive, unit, -1),
a92bd191 507 DEFINE_BLOCK_PROPERTIES(FloppyDrive, conf),
85bbd1e7 508 DEFINE_PROP_SIGNED("drive-type", FloppyDrive, type,
a92bd191
KW
509 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
510 FloppyDriveType),
394ea2ca
KW
511 DEFINE_PROP_END_OF_LIST(),
512};
513
ae34fce5 514static void floppy_drive_realize(DeviceState *qdev, Error **errp)
394ea2ca
KW
515{
516 FloppyDrive *dev = FLOPPY_DRIVE(qdev);
517 FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus);
518 FDrive *drive;
0b9e918f 519 bool read_only;
a92bd191 520 int ret;
394ea2ca
KW
521
522 if (dev->unit == -1) {
523 for (dev->unit = 0; dev->unit < MAX_FD; dev->unit++) {
524 drive = get_drv(bus->fdc, dev->unit);
525 if (!drive->blk) {
526 break;
527 }
528 }
529 }
530
531 if (dev->unit >= MAX_FD) {
ae34fce5
MZ
532 error_setg(errp, "Can't create floppy unit %d, bus supports "
533 "only %d units", dev->unit, MAX_FD);
534 return;
394ea2ca
KW
535 }
536
394ea2ca 537 drive = get_drv(bus->fdc, dev->unit);
394ea2ca 538 if (drive->blk) {
ae34fce5
MZ
539 error_setg(errp, "Floppy unit %d is in use", dev->unit);
540 return;
a92bd191
KW
541 }
542
543 if (!dev->conf.blk) {
394ea2ca 544 /* Anonymous BlockBackend for an empty drive */
d861ab3a 545 dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
a92bd191
KW
546 ret = blk_attach_dev(dev->conf.blk, qdev);
547 assert(ret == 0);
0b9e918f
KW
548
549 /* Don't take write permissions on an empty drive to allow attaching a
550 * read-only node later */
551 read_only = true;
552 } else {
553 read_only = !blk_bs(dev->conf.blk) || blk_is_read_only(dev->conf.blk);
394ea2ca
KW
554 }
555
a92bd191
KW
556 blkconf_blocksizes(&dev->conf);
557 if (dev->conf.logical_block_size != 512 ||
558 dev->conf.physical_block_size != 512)
559 {
ae34fce5
MZ
560 error_setg(errp, "Physical and logical block size must "
561 "be 512 for floppy");
562 return;
a92bd191
KW
563 }
564
565 /* rerror/werror aren't supported by fdc and therefore not even registered
566 * with qdev. So set the defaults manually before they are used in
567 * blkconf_apply_backend_options(). */
568 dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
569 dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
a17c17a2 570
0b9e918f 571 if (!blkconf_apply_backend_options(&dev->conf, read_only, false, errp)) {
ae34fce5 572 return;
a17c17a2 573 }
a92bd191
KW
574
575 /* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
576 * for empty drives. */
577 if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
578 blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
ae34fce5
MZ
579 error_setg(errp, "fdc doesn't support drive option werror");
580 return;
394ea2ca 581 }
a92bd191 582 if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
ae34fce5
MZ
583 error_setg(errp, "fdc doesn't support drive option rerror");
584 return;
a92bd191
KW
585 }
586
a17c17a2 587 drive->conf = &dev->conf;
a92bd191
KW
588 drive->blk = dev->conf.blk;
589 drive->fdctrl = bus->fdc;
590
591 fd_init(drive);
592 blk_set_dev_ops(drive->blk, &fd_block_ops, drive);
593
594 /* Keep 'type' qdev property and FDrive->drive in sync */
595 drive->drive = dev->type;
596 pick_drive_type(drive);
597 dev->type = drive->drive;
598
394ea2ca 599 fd_revalidate(drive);
394ea2ca
KW
600}
601
602static void floppy_drive_class_init(ObjectClass *klass, void *data)
603{
604 DeviceClass *k = DEVICE_CLASS(klass);
ae34fce5 605 k->realize = floppy_drive_realize;
394ea2ca
KW
606 set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
607 k->bus_type = TYPE_FLOPPY_BUS;
608 k->props = floppy_drive_properties;
609 k->desc = "virtual floppy drive";
610}
611
612static const TypeInfo floppy_drive_info = {
613 .name = TYPE_FLOPPY_DRIVE,
614 .parent = TYPE_DEVICE,
615 .instance_size = sizeof(FloppyDrive),
616 .class_init = floppy_drive_class_init,
617};
618
8977f3c1 619/********************************************************/
4b19ec0c 620/* Intel 82078 floppy disk controller emulation */
8977f3c1 621
5c02c033 622static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
07e415f2 623static void fdctrl_to_command_phase(FDCtrl *fdctrl);
85571bc7 624static int fdctrl_transfer_handler (void *opaque, int nchan,
c227f099 625 int dma_pos, int dma_len);
d497d534 626static void fdctrl_raise_irq(FDCtrl *fdctrl);
a2df5fa3 627static FDrive *get_cur_drv(FDCtrl *fdctrl);
5c02c033
BS
628
629static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
630static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
631static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
632static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
633static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
634static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
635static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
636static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
637static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
638static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
639static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
a758f8f4 640static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
8977f3c1 641
8977f3c1
FB
642enum {
643 FD_DIR_WRITE = 0,
644 FD_DIR_READ = 1,
645 FD_DIR_SCANE = 2,
646 FD_DIR_SCANL = 3,
647 FD_DIR_SCANH = 4,
7ea004ed 648 FD_DIR_VERIFY = 5,
8977f3c1
FB
649};
650
651enum {
b9b3d225
BS
652 FD_STATE_MULTI = 0x01, /* multi track flag */
653 FD_STATE_FORMAT = 0x02, /* format flag */
8977f3c1
FB
654};
655
9fea808a 656enum {
8c6a4d77
BS
657 FD_REG_SRA = 0x00,
658 FD_REG_SRB = 0x01,
9fea808a
BS
659 FD_REG_DOR = 0x02,
660 FD_REG_TDR = 0x03,
661 FD_REG_MSR = 0x04,
662 FD_REG_DSR = 0x04,
663 FD_REG_FIFO = 0x05,
664 FD_REG_DIR = 0x07,
a758f8f4 665 FD_REG_CCR = 0x07,
9fea808a
BS
666};
667
668enum {
65cef780 669 FD_CMD_READ_TRACK = 0x02,
9fea808a
BS
670 FD_CMD_SPECIFY = 0x03,
671 FD_CMD_SENSE_DRIVE_STATUS = 0x04,
65cef780
BS
672 FD_CMD_WRITE = 0x05,
673 FD_CMD_READ = 0x06,
9fea808a
BS
674 FD_CMD_RECALIBRATE = 0x07,
675 FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
65cef780
BS
676 FD_CMD_WRITE_DELETED = 0x09,
677 FD_CMD_READ_ID = 0x0a,
678 FD_CMD_READ_DELETED = 0x0c,
679 FD_CMD_FORMAT_TRACK = 0x0d,
9fea808a
BS
680 FD_CMD_DUMPREG = 0x0e,
681 FD_CMD_SEEK = 0x0f,
682 FD_CMD_VERSION = 0x10,
65cef780 683 FD_CMD_SCAN_EQUAL = 0x11,
9fea808a
BS
684 FD_CMD_PERPENDICULAR_MODE = 0x12,
685 FD_CMD_CONFIGURE = 0x13,
65cef780
BS
686 FD_CMD_LOCK = 0x14,
687 FD_CMD_VERIFY = 0x16,
9fea808a
BS
688 FD_CMD_POWERDOWN_MODE = 0x17,
689 FD_CMD_PART_ID = 0x18,
65cef780
BS
690 FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
691 FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
bb350a5e 692 FD_CMD_SAVE = 0x2e,
9fea808a 693 FD_CMD_OPTION = 0x33,
bb350a5e 694 FD_CMD_RESTORE = 0x4e,
9fea808a
BS
695 FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
696 FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
9fea808a
BS
697 FD_CMD_FORMAT_AND_WRITE = 0xcd,
698 FD_CMD_RELATIVE_SEEK_IN = 0xcf,
699};
700
701enum {
702 FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
703 FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
704 FD_CONFIG_POLL = 0x10, /* Poll enabled */
705 FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
706 FD_CONFIG_EIS = 0x40, /* No implied seeks */
707};
708
709enum {
2fee0088
PH
710 FD_SR0_DS0 = 0x01,
711 FD_SR0_DS1 = 0x02,
712 FD_SR0_HEAD = 0x04,
9fea808a
BS
713 FD_SR0_EQPMT = 0x10,
714 FD_SR0_SEEK = 0x20,
715 FD_SR0_ABNTERM = 0x40,
716 FD_SR0_INVCMD = 0x80,
717 FD_SR0_RDYCHG = 0xc0,
718};
719
77370520 720enum {
844f65d6 721 FD_SR1_MA = 0x01, /* Missing address mark */
8510854e 722 FD_SR1_NW = 0x02, /* Not writable */
77370520
BS
723 FD_SR1_EC = 0x80, /* End of cylinder */
724};
725
726enum {
727 FD_SR2_SNS = 0x04, /* Scan not satisfied */
728 FD_SR2_SEH = 0x08, /* Scan equal hit */
729};
730
8c6a4d77
BS
731enum {
732 FD_SRA_DIR = 0x01,
733 FD_SRA_nWP = 0x02,
734 FD_SRA_nINDX = 0x04,
735 FD_SRA_HDSEL = 0x08,
736 FD_SRA_nTRK0 = 0x10,
737 FD_SRA_STEP = 0x20,
738 FD_SRA_nDRV2 = 0x40,
739 FD_SRA_INTPEND = 0x80,
740};
741
742enum {
743 FD_SRB_MTR0 = 0x01,
744 FD_SRB_MTR1 = 0x02,
745 FD_SRB_WGATE = 0x04,
746 FD_SRB_RDATA = 0x08,
747 FD_SRB_WDATA = 0x10,
748 FD_SRB_DR0 = 0x20,
749};
750
9fea808a 751enum {
78ae820c
BS
752#if MAX_FD == 4
753 FD_DOR_SELMASK = 0x03,
754#else
9fea808a 755 FD_DOR_SELMASK = 0x01,
78ae820c 756#endif
9fea808a
BS
757 FD_DOR_nRESET = 0x04,
758 FD_DOR_DMAEN = 0x08,
759 FD_DOR_MOTEN0 = 0x10,
760 FD_DOR_MOTEN1 = 0x20,
761 FD_DOR_MOTEN2 = 0x40,
762 FD_DOR_MOTEN3 = 0x80,
763};
764
765enum {
78ae820c 766#if MAX_FD == 4
9fea808a 767 FD_TDR_BOOTSEL = 0x0c,
78ae820c
BS
768#else
769 FD_TDR_BOOTSEL = 0x04,
770#endif
9fea808a
BS
771};
772
773enum {
774 FD_DSR_DRATEMASK= 0x03,
775 FD_DSR_PWRDOWN = 0x40,
776 FD_DSR_SWRESET = 0x80,
777};
778
779enum {
780 FD_MSR_DRV0BUSY = 0x01,
781 FD_MSR_DRV1BUSY = 0x02,
782 FD_MSR_DRV2BUSY = 0x04,
783 FD_MSR_DRV3BUSY = 0x08,
784 FD_MSR_CMDBUSY = 0x10,
785 FD_MSR_NONDMA = 0x20,
786 FD_MSR_DIO = 0x40,
787 FD_MSR_RQM = 0x80,
788};
789
790enum {
791 FD_DIR_DSKCHG = 0x80,
792};
793
85d291a0
KW
794/*
795 * See chapter 5.0 "Controller phases" of the spec:
796 *
797 * Command phase:
798 * The host writes a command and its parameters into the FIFO. The command
799 * phase is completed when all parameters for the command have been supplied,
800 * and execution phase is entered.
801 *
802 * Execution phase:
803 * Data transfers, either DMA or non-DMA. For non-DMA transfers, the FIFO
804 * contains the payload now, otherwise it's unused. When all bytes of the
805 * required data have been transferred, the state is switched to either result
806 * phase (if the command produces status bytes) or directly back into the
807 * command phase for the next command.
808 *
809 * Result phase:
810 * The host reads out the FIFO, which contains one or more result bytes now.
811 */
812enum {
813 /* Only for migration: reconstruct phase from registers like qemu 2.3 */
814 FD_PHASE_RECONSTRUCT = 0,
815
816 FD_PHASE_COMMAND = 1,
817 FD_PHASE_EXECUTION = 2,
818 FD_PHASE_RESULT = 3,
819};
820
8977f3c1 821#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
baca51fa 822#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
8977f3c1 823
5c02c033 824struct FDCtrl {
dc6c1b37 825 MemoryRegion iomem;
d537cf6c 826 qemu_irq irq;
4b19ec0c 827 /* Controller state */
ed5fd2cc 828 QEMUTimer *result_timer;
242cca4f 829 int dma_chann;
85d291a0 830 uint8_t phase;
c8a35f1c 831 IsaDma *dma;
242cca4f
BS
832 /* Controller's identification */
833 uint8_t version;
834 /* HW */
8c6a4d77
BS
835 uint8_t sra;
836 uint8_t srb;
368df94d 837 uint8_t dor;
d7a6c270 838 uint8_t dor_vmstate; /* only used as temp during vmstate */
46d3233b 839 uint8_t tdr;
b9b3d225 840 uint8_t dsr;
368df94d 841 uint8_t msr;
8977f3c1 842 uint8_t cur_drv;
77370520
BS
843 uint8_t status0;
844 uint8_t status1;
845 uint8_t status2;
8977f3c1 846 /* Command FIFO */
33f00271 847 uint8_t *fifo;
d7a6c270 848 int32_t fifo_size;
8977f3c1
FB
849 uint32_t data_pos;
850 uint32_t data_len;
851 uint8_t data_state;
852 uint8_t data_dir;
890fa6be 853 uint8_t eot; /* last wanted sector */
8977f3c1 854 /* States kept only to be returned back */
8977f3c1
FB
855 /* precompensation */
856 uint8_t precomp_trk;
857 uint8_t config;
858 uint8_t lock;
859 /* Power down config (also with status regB access mode */
860 uint8_t pwrd;
861 /* Floppy drives */
51e6e90e 862 FloppyBus bus;
d7a6c270 863 uint8_t num_floppies;
5c02c033 864 FDrive drives[MAX_FD];
a92bd191
KW
865 struct {
866 BlockBackend *blk;
867 FloppyDriveType type;
868 } qdev_for_drives[MAX_FD];
f2d81b33 869 int reset_sensei;
09c6d585 870 uint32_t check_media_rate;
a73275dd 871 FloppyDriveType fallback; /* type=auto failure fallback */
242cca4f
BS
872 /* Timers state */
873 uint8_t timer0;
874 uint8_t timer1;
e305a165 875 PortioList portio_list;
baca51fa
FB
876};
877
a73275dd
JS
878static FloppyDriveType get_fallback_drive_type(FDrive *drv)
879{
880 return drv->fdctrl->fallback;
881}
882
19d46d71 883#define TYPE_SYSBUS_FDC "base-sysbus-fdc"
dd3be742
HT
884#define SYSBUS_FDC(obj) OBJECT_CHECK(FDCtrlSysBus, (obj), TYPE_SYSBUS_FDC)
885
5c02c033 886typedef struct FDCtrlSysBus {
dd3be742
HT
887 /*< private >*/
888 SysBusDevice parent_obj;
889 /*< public >*/
890
5c02c033
BS
891 struct FDCtrl state;
892} FDCtrlSysBus;
8baf73ad 893
020c8e76
AF
894#define ISA_FDC(obj) OBJECT_CHECK(FDCtrlISABus, (obj), TYPE_ISA_FDC)
895
5c02c033 896typedef struct FDCtrlISABus {
020c8e76
AF
897 ISADevice parent_obj;
898
c9ae703d
HP
899 uint32_t iobase;
900 uint32_t irq;
901 uint32_t dma;
5c02c033 902 struct FDCtrl state;
1ca4d09a
GN
903 int32_t bootindexA;
904 int32_t bootindexB;
5c02c033 905} FDCtrlISABus;
8baf73ad 906
baca51fa
FB
907static uint32_t fdctrl_read (void *opaque, uint32_t reg)
908{
5c02c033 909 FDCtrl *fdctrl = opaque;
baca51fa
FB
910 uint32_t retval;
911
a18e67f5 912 reg &= 7;
e64d7d59 913 switch (reg) {
8c6a4d77
BS
914 case FD_REG_SRA:
915 retval = fdctrl_read_statusA(fdctrl);
4f431960 916 break;
8c6a4d77 917 case FD_REG_SRB:
4f431960
JM
918 retval = fdctrl_read_statusB(fdctrl);
919 break;
9fea808a 920 case FD_REG_DOR:
4f431960
JM
921 retval = fdctrl_read_dor(fdctrl);
922 break;
9fea808a 923 case FD_REG_TDR:
baca51fa 924 retval = fdctrl_read_tape(fdctrl);
4f431960 925 break;
9fea808a 926 case FD_REG_MSR:
baca51fa 927 retval = fdctrl_read_main_status(fdctrl);
4f431960 928 break;
9fea808a 929 case FD_REG_FIFO:
baca51fa 930 retval = fdctrl_read_data(fdctrl);
4f431960 931 break;
9fea808a 932 case FD_REG_DIR:
baca51fa 933 retval = fdctrl_read_dir(fdctrl);
4f431960 934 break;
a541f297 935 default:
4f431960
JM
936 retval = (uint32_t)(-1);
937 break;
a541f297 938 }
1a5396d9 939 trace_fdc_ioport_read(reg, retval);
baca51fa
FB
940
941 return retval;
942}
943
944static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
945{
5c02c033 946 FDCtrl *fdctrl = opaque;
baca51fa 947
a18e67f5 948 reg &= 7;
1a5396d9 949 trace_fdc_ioport_write(reg, value);
e64d7d59 950 switch (reg) {
9fea808a 951 case FD_REG_DOR:
4f431960
JM
952 fdctrl_write_dor(fdctrl, value);
953 break;
9fea808a 954 case FD_REG_TDR:
baca51fa 955 fdctrl_write_tape(fdctrl, value);
4f431960 956 break;
9fea808a 957 case FD_REG_DSR:
baca51fa 958 fdctrl_write_rate(fdctrl, value);
4f431960 959 break;
9fea808a 960 case FD_REG_FIFO:
baca51fa 961 fdctrl_write_data(fdctrl, value);
4f431960 962 break;
a758f8f4
HP
963 case FD_REG_CCR:
964 fdctrl_write_ccr(fdctrl, value);
965 break;
a541f297 966 default:
4f431960 967 break;
a541f297 968 }
baca51fa
FB
969}
970
a8170e5e 971static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg,
dc6c1b37 972 unsigned ize)
62a46c61 973{
5dcb6b91 974 return fdctrl_read(opaque, (uint32_t)reg);
62a46c61
FB
975}
976
a8170e5e 977static void fdctrl_write_mem (void *opaque, hwaddr reg,
dc6c1b37 978 uint64_t value, unsigned size)
62a46c61 979{
5dcb6b91 980 fdctrl_write(opaque, (uint32_t)reg, value);
62a46c61
FB
981}
982
dc6c1b37
AK
983static const MemoryRegionOps fdctrl_mem_ops = {
984 .read = fdctrl_read_mem,
985 .write = fdctrl_write_mem,
986 .endianness = DEVICE_NATIVE_ENDIAN,
e80cfcfc
FB
987};
988
dc6c1b37
AK
989static const MemoryRegionOps fdctrl_mem_strict_ops = {
990 .read = fdctrl_read_mem,
991 .write = fdctrl_write_mem,
992 .endianness = DEVICE_NATIVE_ENDIAN,
993 .valid = {
994 .min_access_size = 1,
995 .max_access_size = 1,
996 },
7c560456
BS
997};
998
7d905f71
JW
999static bool fdrive_media_changed_needed(void *opaque)
1000{
1001 FDrive *drive = opaque;
1002
abb3e55b 1003 return (drive->blk != NULL && drive->media_changed != 1);
7d905f71
JW
1004}
1005
1006static const VMStateDescription vmstate_fdrive_media_changed = {
1007 .name = "fdrive/media_changed",
1008 .version_id = 1,
1009 .minimum_version_id = 1,
5cd8cada 1010 .needed = fdrive_media_changed_needed,
d49805ae 1011 .fields = (VMStateField[]) {
7d905f71
JW
1012 VMSTATE_UINT8(media_changed, FDrive),
1013 VMSTATE_END_OF_LIST()
1014 }
1015};
1016
844f65d6
HP
1017static bool fdrive_media_rate_needed(void *opaque)
1018{
1019 FDrive *drive = opaque;
1020
1021 return drive->fdctrl->check_media_rate;
1022}
1023
1024static const VMStateDescription vmstate_fdrive_media_rate = {
1025 .name = "fdrive/media_rate",
1026 .version_id = 1,
1027 .minimum_version_id = 1,
5cd8cada 1028 .needed = fdrive_media_rate_needed,
d49805ae 1029 .fields = (VMStateField[]) {
844f65d6
HP
1030 VMSTATE_UINT8(media_rate, FDrive),
1031 VMSTATE_END_OF_LIST()
1032 }
1033};
1034
c0b92f30
PD
1035static bool fdrive_perpendicular_needed(void *opaque)
1036{
1037 FDrive *drive = opaque;
1038
1039 return drive->perpendicular != 0;
1040}
1041
1042static const VMStateDescription vmstate_fdrive_perpendicular = {
1043 .name = "fdrive/perpendicular",
1044 .version_id = 1,
1045 .minimum_version_id = 1,
5cd8cada 1046 .needed = fdrive_perpendicular_needed,
c0b92f30
PD
1047 .fields = (VMStateField[]) {
1048 VMSTATE_UINT8(perpendicular, FDrive),
1049 VMSTATE_END_OF_LIST()
1050 }
1051};
1052
1053static int fdrive_post_load(void *opaque, int version_id)
1054{
1055 fd_revalidate(opaque);
1056 return 0;
1057}
1058
d7a6c270
JQ
1059static const VMStateDescription vmstate_fdrive = {
1060 .name = "fdrive",
1061 .version_id = 1,
1062 .minimum_version_id = 1,
c0b92f30 1063 .post_load = fdrive_post_load,
d49805ae 1064 .fields = (VMStateField[]) {
5c02c033
BS
1065 VMSTATE_UINT8(head, FDrive),
1066 VMSTATE_UINT8(track, FDrive),
1067 VMSTATE_UINT8(sect, FDrive),
d7a6c270 1068 VMSTATE_END_OF_LIST()
7d905f71 1069 },
5cd8cada
JQ
1070 .subsections = (const VMStateDescription*[]) {
1071 &vmstate_fdrive_media_changed,
1072 &vmstate_fdrive_media_rate,
1073 &vmstate_fdrive_perpendicular,
1074 NULL
d7a6c270
JQ
1075 }
1076};
3ccacc4a 1077
85d291a0
KW
1078/*
1079 * Reconstructs the phase from register values according to the logic that was
1080 * implemented in qemu 2.3. This is the default value that is used if the phase
1081 * subsection is not present on migration.
1082 *
1083 * Don't change this function to reflect newer qemu versions, it is part of
1084 * the migration ABI.
1085 */
1086static int reconstruct_phase(FDCtrl *fdctrl)
1087{
1088 if (fdctrl->msr & FD_MSR_NONDMA) {
1089 return FD_PHASE_EXECUTION;
1090 } else if ((fdctrl->msr & FD_MSR_RQM) == 0) {
1091 /* qemu 2.3 disabled RQM only during DMA transfers */
1092 return FD_PHASE_EXECUTION;
1093 } else if (fdctrl->msr & FD_MSR_DIO) {
1094 return FD_PHASE_RESULT;
1095 } else {
1096 return FD_PHASE_COMMAND;
1097 }
1098}
1099
44b1ff31 1100static int fdc_pre_save(void *opaque)
3ccacc4a 1101{
5c02c033 1102 FDCtrl *s = opaque;
3ccacc4a 1103
d7a6c270 1104 s->dor_vmstate = s->dor | GET_CUR_DRV(s);
44b1ff31
DDAG
1105
1106 return 0;
3ccacc4a
BS
1107}
1108
85d291a0
KW
1109static int fdc_pre_load(void *opaque)
1110{
1111 FDCtrl *s = opaque;
1112 s->phase = FD_PHASE_RECONSTRUCT;
1113 return 0;
1114}
1115
e59fb374 1116static int fdc_post_load(void *opaque, int version_id)
3ccacc4a 1117{
5c02c033 1118 FDCtrl *s = opaque;
3ccacc4a 1119
d7a6c270
JQ
1120 SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
1121 s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
85d291a0
KW
1122
1123 if (s->phase == FD_PHASE_RECONSTRUCT) {
1124 s->phase = reconstruct_phase(s);
1125 }
1126
3ccacc4a
BS
1127 return 0;
1128}
1129
c0b92f30
PD
1130static bool fdc_reset_sensei_needed(void *opaque)
1131{
1132 FDCtrl *s = opaque;
1133
1134 return s->reset_sensei != 0;
1135}
1136
1137static const VMStateDescription vmstate_fdc_reset_sensei = {
1138 .name = "fdc/reset_sensei",
1139 .version_id = 1,
1140 .minimum_version_id = 1,
5cd8cada 1141 .needed = fdc_reset_sensei_needed,
c0b92f30
PD
1142 .fields = (VMStateField[]) {
1143 VMSTATE_INT32(reset_sensei, FDCtrl),
1144 VMSTATE_END_OF_LIST()
1145 }
1146};
1147
1148static bool fdc_result_timer_needed(void *opaque)
1149{
1150 FDCtrl *s = opaque;
1151
1152 return timer_pending(s->result_timer);
1153}
1154
1155static const VMStateDescription vmstate_fdc_result_timer = {
1156 .name = "fdc/result_timer",
1157 .version_id = 1,
1158 .minimum_version_id = 1,
5cd8cada 1159 .needed = fdc_result_timer_needed,
c0b92f30 1160 .fields = (VMStateField[]) {
e720677e 1161 VMSTATE_TIMER_PTR(result_timer, FDCtrl),
c0b92f30
PD
1162 VMSTATE_END_OF_LIST()
1163 }
1164};
1165
85d291a0
KW
1166static bool fdc_phase_needed(void *opaque)
1167{
1168 FDCtrl *fdctrl = opaque;
1169
1170 return reconstruct_phase(fdctrl) != fdctrl->phase;
1171}
1172
1173static const VMStateDescription vmstate_fdc_phase = {
1174 .name = "fdc/phase",
1175 .version_id = 1,
1176 .minimum_version_id = 1,
5cd8cada 1177 .needed = fdc_phase_needed,
85d291a0
KW
1178 .fields = (VMStateField[]) {
1179 VMSTATE_UINT8(phase, FDCtrl),
1180 VMSTATE_END_OF_LIST()
1181 }
1182};
1183
d7a6c270 1184static const VMStateDescription vmstate_fdc = {
aef30c3c 1185 .name = "fdc",
d7a6c270
JQ
1186 .version_id = 2,
1187 .minimum_version_id = 2,
d7a6c270 1188 .pre_save = fdc_pre_save,
85d291a0 1189 .pre_load = fdc_pre_load,
d7a6c270 1190 .post_load = fdc_post_load,
d49805ae 1191 .fields = (VMStateField[]) {
d7a6c270 1192 /* Controller State */
5c02c033
BS
1193 VMSTATE_UINT8(sra, FDCtrl),
1194 VMSTATE_UINT8(srb, FDCtrl),
1195 VMSTATE_UINT8(dor_vmstate, FDCtrl),
1196 VMSTATE_UINT8(tdr, FDCtrl),
1197 VMSTATE_UINT8(dsr, FDCtrl),
1198 VMSTATE_UINT8(msr, FDCtrl),
1199 VMSTATE_UINT8(status0, FDCtrl),
1200 VMSTATE_UINT8(status1, FDCtrl),
1201 VMSTATE_UINT8(status2, FDCtrl),
d7a6c270 1202 /* Command FIFO */
8ec68b06
BS
1203 VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
1204 uint8_t),
5c02c033
BS
1205 VMSTATE_UINT32(data_pos, FDCtrl),
1206 VMSTATE_UINT32(data_len, FDCtrl),
1207 VMSTATE_UINT8(data_state, FDCtrl),
1208 VMSTATE_UINT8(data_dir, FDCtrl),
1209 VMSTATE_UINT8(eot, FDCtrl),
d7a6c270 1210 /* States kept only to be returned back */
5c02c033
BS
1211 VMSTATE_UINT8(timer0, FDCtrl),
1212 VMSTATE_UINT8(timer1, FDCtrl),
1213 VMSTATE_UINT8(precomp_trk, FDCtrl),
1214 VMSTATE_UINT8(config, FDCtrl),
1215 VMSTATE_UINT8(lock, FDCtrl),
1216 VMSTATE_UINT8(pwrd, FDCtrl),
d2164ad3 1217 VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl, NULL),
5c02c033
BS
1218 VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
1219 vmstate_fdrive, FDrive),
d7a6c270 1220 VMSTATE_END_OF_LIST()
c0b92f30 1221 },
5cd8cada
JQ
1222 .subsections = (const VMStateDescription*[]) {
1223 &vmstate_fdc_reset_sensei,
1224 &vmstate_fdc_result_timer,
1225 &vmstate_fdc_phase,
1226 NULL
78ae820c 1227 }
d7a6c270 1228};
3ccacc4a 1229
2be37833 1230static void fdctrl_external_reset_sysbus(DeviceState *d)
3ccacc4a 1231{
dd3be742 1232 FDCtrlSysBus *sys = SYSBUS_FDC(d);
5c02c033 1233 FDCtrl *s = &sys->state;
2be37833
BS
1234
1235 fdctrl_reset(s, 0);
1236}
1237
1238static void fdctrl_external_reset_isa(DeviceState *d)
1239{
020c8e76 1240 FDCtrlISABus *isa = ISA_FDC(d);
5c02c033 1241 FDCtrl *s = &isa->state;
3ccacc4a
BS
1242
1243 fdctrl_reset(s, 0);
1244}
1245
2be17ebd
BS
1246static void fdctrl_handle_tc(void *opaque, int irq, int level)
1247{
5c02c033 1248 //FDCtrl *s = opaque;
2be17ebd
BS
1249
1250 if (level) {
1251 // XXX
1252 FLOPPY_DPRINTF("TC pulsed\n");
1253 }
1254}
1255
8977f3c1 1256/* Change IRQ state */
5c02c033 1257static void fdctrl_reset_irq(FDCtrl *fdctrl)
8977f3c1 1258{
d497d534 1259 fdctrl->status0 = 0;
8c6a4d77
BS
1260 if (!(fdctrl->sra & FD_SRA_INTPEND))
1261 return;
ed5fd2cc 1262 FLOPPY_DPRINTF("Reset interrupt\n");
d537cf6c 1263 qemu_set_irq(fdctrl->irq, 0);
8c6a4d77 1264 fdctrl->sra &= ~FD_SRA_INTPEND;
8977f3c1
FB
1265}
1266
d497d534 1267static void fdctrl_raise_irq(FDCtrl *fdctrl)
8977f3c1 1268{
8c6a4d77 1269 if (!(fdctrl->sra & FD_SRA_INTPEND)) {
d537cf6c 1270 qemu_set_irq(fdctrl->irq, 1);
8c6a4d77 1271 fdctrl->sra |= FD_SRA_INTPEND;
8977f3c1 1272 }
21fcf360 1273
f2d81b33 1274 fdctrl->reset_sensei = 0;
77370520 1275 FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
8977f3c1
FB
1276}
1277
4b19ec0c 1278/* Reset controller */
5c02c033 1279static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
8977f3c1
FB
1280{
1281 int i;
1282
4b19ec0c 1283 FLOPPY_DPRINTF("reset controller\n");
baca51fa 1284 fdctrl_reset_irq(fdctrl);
4b19ec0c 1285 /* Initialise controller */
8c6a4d77
BS
1286 fdctrl->sra = 0;
1287 fdctrl->srb = 0xc0;
4be74634 1288 if (!fdctrl->drives[1].blk) {
8c6a4d77 1289 fdctrl->sra |= FD_SRA_nDRV2;
4be74634 1290 }
baca51fa 1291 fdctrl->cur_drv = 0;
1c346df2 1292 fdctrl->dor = FD_DOR_nRESET;
368df94d 1293 fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
b9b3d225 1294 fdctrl->msr = FD_MSR_RQM;
c0b92f30
PD
1295 fdctrl->reset_sensei = 0;
1296 timer_del(fdctrl->result_timer);
8977f3c1 1297 /* FIFO state */
baca51fa
FB
1298 fdctrl->data_pos = 0;
1299 fdctrl->data_len = 0;
b9b3d225 1300 fdctrl->data_state = 0;
baca51fa 1301 fdctrl->data_dir = FD_DIR_WRITE;
8977f3c1 1302 for (i = 0; i < MAX_FD; i++)
1c346df2 1303 fd_recalibrate(&fdctrl->drives[i]);
07e415f2 1304 fdctrl_to_command_phase(fdctrl);
77370520 1305 if (do_irq) {
d497d534
HP
1306 fdctrl->status0 |= FD_SR0_RDYCHG;
1307 fdctrl_raise_irq(fdctrl);
f2d81b33 1308 fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
77370520 1309 }
baca51fa
FB
1310}
1311
5c02c033 1312static inline FDrive *drv0(FDCtrl *fdctrl)
baca51fa 1313{
46d3233b 1314 return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
baca51fa
FB
1315}
1316
5c02c033 1317static inline FDrive *drv1(FDCtrl *fdctrl)
baca51fa 1318{
46d3233b
BS
1319 if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
1320 return &fdctrl->drives[1];
1321 else
1322 return &fdctrl->drives[0];
baca51fa
FB
1323}
1324
78ae820c 1325#if MAX_FD == 4
5c02c033 1326static inline FDrive *drv2(FDCtrl *fdctrl)
78ae820c
BS
1327{
1328 if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
1329 return &fdctrl->drives[2];
1330 else
1331 return &fdctrl->drives[1];
1332}
1333
5c02c033 1334static inline FDrive *drv3(FDCtrl *fdctrl)
78ae820c
BS
1335{
1336 if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
1337 return &fdctrl->drives[3];
1338 else
1339 return &fdctrl->drives[2];
1340}
1341#endif
1342
394ea2ca 1343static FDrive *get_drv(FDCtrl *fdctrl, int unit)
baca51fa 1344{
394ea2ca 1345 switch (unit) {
78ae820c
BS
1346 case 0: return drv0(fdctrl);
1347 case 1: return drv1(fdctrl);
1348#if MAX_FD == 4
1349 case 2: return drv2(fdctrl);
1350 case 3: return drv3(fdctrl);
1351#endif
1352 default: return NULL;
1353 }
8977f3c1
FB
1354}
1355
394ea2ca
KW
1356static FDrive *get_cur_drv(FDCtrl *fdctrl)
1357{
1358 return get_drv(fdctrl, fdctrl->cur_drv);
1359}
1360
8c6a4d77 1361/* Status A register : 0x00 (read-only) */
5c02c033 1362static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
8c6a4d77
BS
1363{
1364 uint32_t retval = fdctrl->sra;
1365
1366 FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
1367
1368 return retval;
1369}
1370
8977f3c1 1371/* Status B register : 0x01 (read-only) */
5c02c033 1372static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
8977f3c1 1373{
8c6a4d77
BS
1374 uint32_t retval = fdctrl->srb;
1375
1376 FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
1377
1378 return retval;
8977f3c1
FB
1379}
1380
1381/* Digital output register : 0x02 */
5c02c033 1382static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
8977f3c1 1383{
1c346df2 1384 uint32_t retval = fdctrl->dor;
8977f3c1 1385
8977f3c1 1386 /* Selected drive */
baca51fa 1387 retval |= fdctrl->cur_drv;
8977f3c1
FB
1388 FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
1389
1390 return retval;
1391}
1392
5c02c033 1393static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
8977f3c1 1394{
8977f3c1 1395 FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
8c6a4d77
BS
1396
1397 /* Motors */
1398 if (value & FD_DOR_MOTEN0)
1399 fdctrl->srb |= FD_SRB_MTR0;
1400 else
1401 fdctrl->srb &= ~FD_SRB_MTR0;
1402 if (value & FD_DOR_MOTEN1)
1403 fdctrl->srb |= FD_SRB_MTR1;
1404 else
1405 fdctrl->srb &= ~FD_SRB_MTR1;
1406
1407 /* Drive */
1408 if (value & 1)
1409 fdctrl->srb |= FD_SRB_DR0;
1410 else
1411 fdctrl->srb &= ~FD_SRB_DR0;
1412
8977f3c1 1413 /* Reset */
9fea808a 1414 if (!(value & FD_DOR_nRESET)) {
1c346df2 1415 if (fdctrl->dor & FD_DOR_nRESET) {
4b19ec0c 1416 FLOPPY_DPRINTF("controller enter RESET state\n");
8977f3c1
FB
1417 }
1418 } else {
1c346df2 1419 if (!(fdctrl->dor & FD_DOR_nRESET)) {
4b19ec0c 1420 FLOPPY_DPRINTF("controller out of RESET state\n");
fb6cf1d0 1421 fdctrl_reset(fdctrl, 1);
b9b3d225 1422 fdctrl->dsr &= ~FD_DSR_PWRDOWN;
8977f3c1
FB
1423 }
1424 }
1425 /* Selected drive */
9fea808a 1426 fdctrl->cur_drv = value & FD_DOR_SELMASK;
368df94d
BS
1427
1428 fdctrl->dor = value;
8977f3c1
FB
1429}
1430
1431/* Tape drive register : 0x03 */
5c02c033 1432static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
8977f3c1 1433{
46d3233b 1434 uint32_t retval = fdctrl->tdr;
8977f3c1 1435
8977f3c1
FB
1436 FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
1437
1438 return retval;
1439}
1440
5c02c033 1441static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
8977f3c1 1442{
8977f3c1 1443 /* Reset mode */
1c346df2 1444 if (!(fdctrl->dor & FD_DOR_nRESET)) {
4b19ec0c 1445 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
8977f3c1
FB
1446 return;
1447 }
1448 FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
1449 /* Disk boot selection indicator */
46d3233b 1450 fdctrl->tdr = value & FD_TDR_BOOTSEL;
8977f3c1
FB
1451 /* Tape indicators: never allow */
1452}
1453
1454/* Main status register : 0x04 (read) */
5c02c033 1455static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
8977f3c1 1456{
b9b3d225 1457 uint32_t retval = fdctrl->msr;
8977f3c1 1458
b9b3d225 1459 fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1c346df2 1460 fdctrl->dor |= FD_DOR_nRESET;
b9b3d225 1461
8977f3c1
FB
1462 FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
1463
1464 return retval;
1465}
1466
1467/* Data select rate register : 0x04 (write) */
5c02c033 1468static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
8977f3c1 1469{
8977f3c1 1470 /* Reset mode */
1c346df2 1471 if (!(fdctrl->dor & FD_DOR_nRESET)) {
4f431960
JM
1472 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1473 return;
1474 }
8977f3c1
FB
1475 FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
1476 /* Reset: autoclear */
9fea808a 1477 if (value & FD_DSR_SWRESET) {
1c346df2 1478 fdctrl->dor &= ~FD_DOR_nRESET;
baca51fa 1479 fdctrl_reset(fdctrl, 1);
1c346df2 1480 fdctrl->dor |= FD_DOR_nRESET;
8977f3c1 1481 }
9fea808a 1482 if (value & FD_DSR_PWRDOWN) {
baca51fa 1483 fdctrl_reset(fdctrl, 1);
8977f3c1 1484 }
b9b3d225 1485 fdctrl->dsr = value;
8977f3c1
FB
1486}
1487
a758f8f4
HP
1488/* Configuration control register: 0x07 (write) */
1489static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value)
1490{
1491 /* Reset mode */
1492 if (!(fdctrl->dor & FD_DOR_nRESET)) {
1493 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1494 return;
1495 }
1496 FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);
1497
1498 /* Only the rate selection bits used in AT mode, and we
1499 * store those in the DSR.
1500 */
1501 fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK) |
1502 (value & FD_DSR_DRATEMASK);
1503}
1504
5c02c033 1505static int fdctrl_media_changed(FDrive *drv)
ea185bbd 1506{
21fcf360 1507 return drv->media_changed;
ea185bbd
FB
1508}
1509
8977f3c1 1510/* Digital input register : 0x07 (read-only) */
5c02c033 1511static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
8977f3c1 1512{
8977f3c1
FB
1513 uint32_t retval = 0;
1514
a2df5fa3 1515 if (fdctrl_media_changed(get_cur_drv(fdctrl))) {
9fea808a 1516 retval |= FD_DIR_DSKCHG;
a2df5fa3 1517 }
3c83eb4f 1518 if (retval != 0) {
baca51fa 1519 FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
3c83eb4f 1520 }
8977f3c1
FB
1521
1522 return retval;
1523}
1524
07e415f2
KW
1525/* Clear the FIFO and update the state for receiving the next command */
1526static void fdctrl_to_command_phase(FDCtrl *fdctrl)
8977f3c1 1527{
85d291a0 1528 fdctrl->phase = FD_PHASE_COMMAND;
baca51fa
FB
1529 fdctrl->data_dir = FD_DIR_WRITE;
1530 fdctrl->data_pos = 0;
6cc8a11c 1531 fdctrl->data_len = 1; /* Accept command byte, adjust for params later */
b9b3d225 1532 fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
6cc8a11c 1533 fdctrl->msr |= FD_MSR_RQM;
8977f3c1
FB
1534}
1535
83a26013
KW
1536/* Update the state to allow the guest to read out the command status.
1537 * @fifo_len is the number of result bytes to be read out. */
1538static void fdctrl_to_result_phase(FDCtrl *fdctrl, int fifo_len)
8977f3c1 1539{
85d291a0 1540 fdctrl->phase = FD_PHASE_RESULT;
baca51fa
FB
1541 fdctrl->data_dir = FD_DIR_READ;
1542 fdctrl->data_len = fifo_len;
1543 fdctrl->data_pos = 0;
b9b3d225 1544 fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
8977f3c1
FB
1545}
1546
1547/* Set an error: unimplemented/unknown command */
5c02c033 1548static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
8977f3c1 1549{
cced7a13
BS
1550 qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
1551 fdctrl->fifo[0]);
9fea808a 1552 fdctrl->fifo[0] = FD_SR0_INVCMD;
83a26013 1553 fdctrl_to_result_phase(fdctrl, 1);
8977f3c1
FB
1554}
1555
6be01b1e
PH
1556/* Seek to next sector
1557 * returns 0 when end of track reached (for DBL_SIDES on head 1)
1558 * otherwise returns 1
1559 */
5c02c033 1560static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
746d6de7
BS
1561{
1562 FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
1563 cur_drv->head, cur_drv->track, cur_drv->sect,
1564 fd_sector(cur_drv));
1565 /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1566 error in fact */
6be01b1e
PH
1567 uint8_t new_head = cur_drv->head;
1568 uint8_t new_track = cur_drv->track;
1569 uint8_t new_sect = cur_drv->sect;
1570
1571 int ret = 1;
1572
1573 if (new_sect >= cur_drv->last_sect ||
1574 new_sect == fdctrl->eot) {
1575 new_sect = 1;
746d6de7 1576 if (FD_MULTI_TRACK(fdctrl->data_state)) {
6be01b1e 1577 if (new_head == 0 &&
746d6de7 1578 (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
6be01b1e 1579 new_head = 1;
746d6de7 1580 } else {
6be01b1e
PH
1581 new_head = 0;
1582 new_track++;
c5139bd9 1583 fdctrl->status0 |= FD_SR0_SEEK;
6be01b1e
PH
1584 if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
1585 ret = 0;
1586 }
746d6de7
BS
1587 }
1588 } else {
c5139bd9 1589 fdctrl->status0 |= FD_SR0_SEEK;
6be01b1e
PH
1590 new_track++;
1591 ret = 0;
1592 }
1593 if (ret == 1) {
1594 FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1595 new_head, new_track, new_sect, fd_sector(cur_drv));
746d6de7 1596 }
746d6de7 1597 } else {
6be01b1e 1598 new_sect++;
746d6de7 1599 }
6be01b1e
PH
1600 fd_seek(cur_drv, new_head, new_track, new_sect, 1);
1601 return ret;
746d6de7
BS
1602}
1603
8977f3c1 1604/* Callback for transfer end (stop or abort) */
5c02c033
BS
1605static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
1606 uint8_t status1, uint8_t status2)
8977f3c1 1607{
5c02c033 1608 FDrive *cur_drv;
baca51fa 1609 cur_drv = get_cur_drv(fdctrl);
075f5532
HP
1610
1611 fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
1612 fdctrl->status0 |= GET_CUR_DRV(fdctrl);
1613 if (cur_drv->head) {
1614 fdctrl->status0 |= FD_SR0_HEAD;
1615 }
1616 fdctrl->status0 |= status0;
2fee0088 1617
8977f3c1 1618 FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
2fee0088
PH
1619 status0, status1, status2, fdctrl->status0);
1620 fdctrl->fifo[0] = fdctrl->status0;
baca51fa
FB
1621 fdctrl->fifo[1] = status1;
1622 fdctrl->fifo[2] = status2;
1623 fdctrl->fifo[3] = cur_drv->track;
1624 fdctrl->fifo[4] = cur_drv->head;
1625 fdctrl->fifo[5] = cur_drv->sect;
1626 fdctrl->fifo[6] = FD_SECTOR_SC;
1627 fdctrl->data_dir = FD_DIR_READ;
441f6692 1628 if (fdctrl->dma_chann != -1 && !(fdctrl->msr & FD_MSR_NONDMA)) {
c8a35f1c
HP
1629 IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
1630 k->release_DREQ(fdctrl->dma, fdctrl->dma_chann);
ed5fd2cc 1631 }
b9b3d225 1632 fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
368df94d 1633 fdctrl->msr &= ~FD_MSR_NONDMA;
34abf9a7 1634
83a26013 1635 fdctrl_to_result_phase(fdctrl, 7);
d497d534 1636 fdctrl_raise_irq(fdctrl);
8977f3c1
FB
1637}
1638
1639/* Prepare a data transfer (either DMA or FIFO) */
5c02c033 1640static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
8977f3c1 1641{
5c02c033 1642 FDrive *cur_drv;
8977f3c1 1643 uint8_t kh, kt, ks;
8977f3c1 1644
cefec4f5 1645 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
baca51fa
FB
1646 cur_drv = get_cur_drv(fdctrl);
1647 kt = fdctrl->fifo[2];
1648 kh = fdctrl->fifo[3];
1649 ks = fdctrl->fifo[4];
4b19ec0c 1650 FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
cefec4f5 1651 GET_CUR_DRV(fdctrl), kh, kt, ks,
08388273
HP
1652 fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
1653 NUM_SIDES(cur_drv)));
77370520 1654 switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
8977f3c1
FB
1655 case 2:
1656 /* sect too big */
9fea808a 1657 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
baca51fa
FB
1658 fdctrl->fifo[3] = kt;
1659 fdctrl->fifo[4] = kh;
1660 fdctrl->fifo[5] = ks;
8977f3c1
FB
1661 return;
1662 case 3:
1663 /* track too big */
77370520 1664 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
baca51fa
FB
1665 fdctrl->fifo[3] = kt;
1666 fdctrl->fifo[4] = kh;
1667 fdctrl->fifo[5] = ks;
8977f3c1
FB
1668 return;
1669 case 4:
1670 /* No seek enabled */
9fea808a 1671 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
baca51fa
FB
1672 fdctrl->fifo[3] = kt;
1673 fdctrl->fifo[4] = kh;
1674 fdctrl->fifo[5] = ks;
8977f3c1
FB
1675 return;
1676 case 1:
d6ed4e21 1677 fdctrl->status0 |= FD_SR0_SEEK;
8977f3c1
FB
1678 break;
1679 default:
1680 break;
1681 }
b9b3d225 1682
844f65d6
HP
1683 /* Check the data rate. If the programmed data rate does not match
1684 * the currently inserted medium, the operation has to fail. */
1685 if (fdctrl->check_media_rate &&
1686 (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
1687 FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n",
1688 fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
1689 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
1690 fdctrl->fifo[3] = kt;
1691 fdctrl->fifo[4] = kh;
1692 fdctrl->fifo[5] = ks;
1693 return;
1694 }
1695
8977f3c1 1696 /* Set the FIFO state */
baca51fa
FB
1697 fdctrl->data_dir = direction;
1698 fdctrl->data_pos = 0;
27c86e24 1699 assert(fdctrl->msr & FD_MSR_CMDBUSY);
baca51fa
FB
1700 if (fdctrl->fifo[0] & 0x80)
1701 fdctrl->data_state |= FD_STATE_MULTI;
1702 else
1703 fdctrl->data_state &= ~FD_STATE_MULTI;
c83f97b5 1704 if (fdctrl->fifo[5] == 0) {
baca51fa
FB
1705 fdctrl->data_len = fdctrl->fifo[8];
1706 } else {
4f431960 1707 int tmp;
3bcb80f1 1708 fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
771effeb 1709 tmp = (fdctrl->fifo[6] - ks + 1);
baca51fa 1710 if (fdctrl->fifo[0] & 0x80)
771effeb 1711 tmp += fdctrl->fifo[6];
4f431960 1712 fdctrl->data_len *= tmp;
baca51fa 1713 }
890fa6be 1714 fdctrl->eot = fdctrl->fifo[6];
368df94d 1715 if (fdctrl->dor & FD_DOR_DMAEN) {
c8a35f1c
HP
1716 IsaDmaTransferMode dma_mode;
1717 IsaDmaClass *k = ISADMA_GET_CLASS(fdctrl->dma);
1718 bool dma_mode_ok;
8977f3c1 1719 /* DMA transfer are enabled. Check if DMA channel is well programmed */
c8a35f1c 1720 dma_mode = k->get_transfer_mode(fdctrl->dma, fdctrl->dma_chann);
baca51fa 1721 FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
4f431960 1722 dma_mode, direction,
baca51fa 1723 (128 << fdctrl->fifo[5]) *
4f431960 1724 (cur_drv->last_sect - ks + 1), fdctrl->data_len);
c8a35f1c
HP
1725 switch (direction) {
1726 case FD_DIR_SCANE:
1727 case FD_DIR_SCANL:
1728 case FD_DIR_SCANH:
1729 dma_mode_ok = (dma_mode == ISADMA_TRANSFER_VERIFY);
1730 break;
1731 case FD_DIR_WRITE:
1732 dma_mode_ok = (dma_mode == ISADMA_TRANSFER_WRITE);
1733 break;
1734 case FD_DIR_READ:
1735 dma_mode_ok = (dma_mode == ISADMA_TRANSFER_READ);
1736 break;
1737 case FD_DIR_VERIFY:
1738 dma_mode_ok = true;
1739 break;
1740 default:
1741 dma_mode_ok = false;
1742 break;
1743 }
1744 if (dma_mode_ok) {
8977f3c1 1745 /* No access is allowed until DMA transfer has completed */
b9b3d225 1746 fdctrl->msr &= ~FD_MSR_RQM;
7ea004ed
HP
1747 if (direction != FD_DIR_VERIFY) {
1748 /* Now, we just have to wait for the DMA controller to
1749 * recall us...
1750 */
c8a35f1c
HP
1751 k->hold_DREQ(fdctrl->dma, fdctrl->dma_chann);
1752 k->schedule(fdctrl->dma);
7ea004ed
HP
1753 } else {
1754 /* Start transfer */
1755 fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
1756 fdctrl->data_len);
1757 }
8977f3c1 1758 return;
baca51fa 1759 } else {
cced7a13
BS
1760 FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
1761 direction);
8977f3c1
FB
1762 }
1763 }
1764 FLOPPY_DPRINTF("start non-DMA transfer\n");
6cc8a11c 1765 fdctrl->msr |= FD_MSR_NONDMA | FD_MSR_RQM;
b9b3d225
BS
1766 if (direction != FD_DIR_WRITE)
1767 fdctrl->msr |= FD_MSR_DIO;
8977f3c1 1768 /* IO based transfer: calculate len */
d497d534 1769 fdctrl_raise_irq(fdctrl);
8977f3c1
FB
1770}
1771
1772/* Prepare a transfer of deleted data */
5c02c033 1773static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
8977f3c1 1774{
cced7a13 1775 qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
77370520 1776
8977f3c1
FB
1777 /* We don't handle deleted data,
1778 * so we don't return *ANYTHING*
1779 */
9fea808a 1780 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
8977f3c1
FB
1781}
1782
1783/* handlers for DMA transfers */
85571bc7
FB
1784static int fdctrl_transfer_handler (void *opaque, int nchan,
1785 int dma_pos, int dma_len)
8977f3c1 1786{
5c02c033
BS
1787 FDCtrl *fdctrl;
1788 FDrive *cur_drv;
baca51fa 1789 int len, start_pos, rel_pos;
8977f3c1 1790 uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
c8a35f1c 1791 IsaDmaClass *k;
8977f3c1 1792
baca51fa 1793 fdctrl = opaque;
b9b3d225 1794 if (fdctrl->msr & FD_MSR_RQM) {
8977f3c1
FB
1795 FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1796 return 0;
1797 }
c8a35f1c 1798 k = ISADMA_GET_CLASS(fdctrl->dma);
baca51fa
FB
1799 cur_drv = get_cur_drv(fdctrl);
1800 if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1801 fdctrl->data_dir == FD_DIR_SCANH)
77370520 1802 status2 = FD_SR2_SNS;
85571bc7
FB
1803 if (dma_len > fdctrl->data_len)
1804 dma_len = fdctrl->data_len;
4be74634 1805 if (cur_drv->blk == NULL) {
4f431960 1806 if (fdctrl->data_dir == FD_DIR_WRITE)
9fea808a 1807 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
4f431960 1808 else
9fea808a 1809 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
4f431960 1810 len = 0;
890fa6be
FB
1811 goto transfer_error;
1812 }
baca51fa 1813 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
85571bc7
FB
1814 for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1815 len = dma_len - fdctrl->data_pos;
baca51fa
FB
1816 if (len + rel_pos > FD_SECTOR_LEN)
1817 len = FD_SECTOR_LEN - rel_pos;
6f7e9aec
FB
1818 FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1819 "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
cefec4f5 1820 fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
baca51fa 1821 cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
9fea808a 1822 fd_sector(cur_drv) * FD_SECTOR_LEN);
baca51fa 1823 if (fdctrl->data_dir != FD_DIR_WRITE ||
4f431960 1824 len < FD_SECTOR_LEN || rel_pos != 0) {
baca51fa 1825 /* READ & SCAN commands and realign to a sector for WRITE */
a7a5b7c0
EB
1826 if (blk_pread(cur_drv->blk, fd_offset(cur_drv),
1827 fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) {
8977f3c1
FB
1828 FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1829 fd_sector(cur_drv));
1830 /* Sure, image size is too small... */
baca51fa 1831 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
8977f3c1 1832 }
890fa6be 1833 }
4f431960
JM
1834 switch (fdctrl->data_dir) {
1835 case FD_DIR_READ:
1836 /* READ commands */
c8a35f1c
HP
1837 k->write_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
1838 fdctrl->data_pos, len);
4f431960
JM
1839 break;
1840 case FD_DIR_WRITE:
baca51fa 1841 /* WRITE commands */
8510854e
HP
1842 if (cur_drv->ro) {
1843 /* Handle readonly medium early, no need to do DMA, touch the
1844 * LED or attempt any writes. A real floppy doesn't attempt
1845 * to write to readonly media either. */
1846 fdctrl_stop_transfer(fdctrl,
1847 FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW,
1848 0x00);
1849 goto transfer_error;
1850 }
1851
c8a35f1c
HP
1852 k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos,
1853 fdctrl->data_pos, len);
a7a5b7c0
EB
1854 if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv),
1855 fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) {
cced7a13
BS
1856 FLOPPY_DPRINTF("error writing sector %d\n",
1857 fd_sector(cur_drv));
9fea808a 1858 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
baca51fa 1859 goto transfer_error;
890fa6be 1860 }
4f431960 1861 break;
7ea004ed
HP
1862 case FD_DIR_VERIFY:
1863 /* VERIFY commands */
1864 break;
4f431960
JM
1865 default:
1866 /* SCAN commands */
baca51fa 1867 {
4f431960 1868 uint8_t tmpbuf[FD_SECTOR_LEN];
baca51fa 1869 int ret;
c8a35f1c
HP
1870 k->read_memory(fdctrl->dma, nchan, tmpbuf, fdctrl->data_pos,
1871 len);
baca51fa 1872 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
8977f3c1 1873 if (ret == 0) {
77370520 1874 status2 = FD_SR2_SEH;
8977f3c1
FB
1875 goto end_transfer;
1876 }
baca51fa
FB
1877 if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1878 (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
8977f3c1
FB
1879 status2 = 0x00;
1880 goto end_transfer;
1881 }
1882 }
4f431960 1883 break;
8977f3c1 1884 }
4f431960
JM
1885 fdctrl->data_pos += len;
1886 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
baca51fa 1887 if (rel_pos == 0) {
8977f3c1 1888 /* Seek to next sector */
746d6de7
BS
1889 if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
1890 break;
8977f3c1
FB
1891 }
1892 }
4f431960 1893 end_transfer:
baca51fa
FB
1894 len = fdctrl->data_pos - start_pos;
1895 FLOPPY_DPRINTF("end transfer %d %d %d\n",
4f431960 1896 fdctrl->data_pos, len, fdctrl->data_len);
baca51fa
FB
1897 if (fdctrl->data_dir == FD_DIR_SCANE ||
1898 fdctrl->data_dir == FD_DIR_SCANL ||
1899 fdctrl->data_dir == FD_DIR_SCANH)
77370520 1900 status2 = FD_SR2_SEH;
baca51fa 1901 fdctrl->data_len -= len;
890fa6be 1902 fdctrl_stop_transfer(fdctrl, status0, status1, status2);
4f431960 1903 transfer_error:
8977f3c1 1904
baca51fa 1905 return len;
8977f3c1
FB
1906}
1907
8977f3c1 1908/* Data register : 0x05 */
5c02c033 1909static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
8977f3c1 1910{
5c02c033 1911 FDrive *cur_drv;
8977f3c1 1912 uint32_t retval = 0;
e9077462 1913 uint32_t pos;
8977f3c1 1914
baca51fa 1915 cur_drv = get_cur_drv(fdctrl);
b9b3d225
BS
1916 fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1917 if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
cced7a13 1918 FLOPPY_DPRINTF("error: controller not ready for reading\n");
8977f3c1
FB
1919 return 0;
1920 }
f6c2d1d8
KW
1921
1922 /* If data_len spans multiple sectors, the current position in the FIFO
1923 * wraps around while fdctrl->data_pos is the real position in the whole
1924 * request. */
baca51fa 1925 pos = fdctrl->data_pos;
e9077462 1926 pos %= FD_SECTOR_LEN;
f6c2d1d8
KW
1927
1928 switch (fdctrl->phase) {
1929 case FD_PHASE_EXECUTION:
1930 assert(fdctrl->msr & FD_MSR_NONDMA);
8977f3c1 1931 if (pos == 0) {
746d6de7
BS
1932 if (fdctrl->data_pos != 0)
1933 if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
1934 FLOPPY_DPRINTF("error seeking to next sector %d\n",
1935 fd_sector(cur_drv));
1936 return 0;
1937 }
a7a5b7c0
EB
1938 if (blk_pread(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
1939 BDRV_SECTOR_SIZE)
4be74634 1940 < 0) {
77370520
BS
1941 FLOPPY_DPRINTF("error getting sector %d\n",
1942 fd_sector(cur_drv));
1943 /* Sure, image size is too small... */
1944 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1945 }
8977f3c1 1946 }
f6c2d1d8
KW
1947
1948 if (++fdctrl->data_pos == fdctrl->data_len) {
6cc8a11c 1949 fdctrl->msr &= ~FD_MSR_RQM;
c5139bd9 1950 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
f6c2d1d8
KW
1951 }
1952 break;
1953
1954 case FD_PHASE_RESULT:
1955 assert(!(fdctrl->msr & FD_MSR_NONDMA));
1956 if (++fdctrl->data_pos == fdctrl->data_len) {
6cc8a11c 1957 fdctrl->msr &= ~FD_MSR_RQM;
07e415f2 1958 fdctrl_to_command_phase(fdctrl);
ed5fd2cc
FB
1959 fdctrl_reset_irq(fdctrl);
1960 }
f6c2d1d8
KW
1961 break;
1962
1963 case FD_PHASE_COMMAND:
1964 default:
1965 abort();
8977f3c1 1966 }
f6c2d1d8
KW
1967
1968 retval = fdctrl->fifo[pos];
8977f3c1
FB
1969 FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1970
1971 return retval;
1972}
1973
5c02c033 1974static void fdctrl_format_sector(FDCtrl *fdctrl)
8977f3c1 1975{
5c02c033 1976 FDrive *cur_drv;
baca51fa 1977 uint8_t kh, kt, ks;
8977f3c1 1978
cefec4f5 1979 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
baca51fa
FB
1980 cur_drv = get_cur_drv(fdctrl);
1981 kt = fdctrl->fifo[6];
1982 kh = fdctrl->fifo[7];
1983 ks = fdctrl->fifo[8];
1984 FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
cefec4f5 1985 GET_CUR_DRV(fdctrl), kh, kt, ks,
08388273
HP
1986 fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
1987 NUM_SIDES(cur_drv)));
9fea808a 1988 switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
baca51fa
FB
1989 case 2:
1990 /* sect too big */
9fea808a 1991 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
baca51fa
FB
1992 fdctrl->fifo[3] = kt;
1993 fdctrl->fifo[4] = kh;
1994 fdctrl->fifo[5] = ks;
1995 return;
1996 case 3:
1997 /* track too big */
77370520 1998 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
baca51fa
FB
1999 fdctrl->fifo[3] = kt;
2000 fdctrl->fifo[4] = kh;
2001 fdctrl->fifo[5] = ks;
2002 return;
2003 case 4:
2004 /* No seek enabled */
9fea808a 2005 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
baca51fa
FB
2006 fdctrl->fifo[3] = kt;
2007 fdctrl->fifo[4] = kh;
2008 fdctrl->fifo[5] = ks;
2009 return;
2010 case 1:
cd30b53d 2011 fdctrl->status0 |= FD_SR0_SEEK;
baca51fa
FB
2012 break;
2013 default:
2014 break;
2015 }
2016 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
4be74634 2017 if (cur_drv->blk == NULL ||
a7a5b7c0
EB
2018 blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
2019 BDRV_SECTOR_SIZE, 0) < 0) {
cced7a13 2020 FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
9fea808a 2021 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
baca51fa 2022 } else {
4f431960
JM
2023 if (cur_drv->sect == cur_drv->last_sect) {
2024 fdctrl->data_state &= ~FD_STATE_FORMAT;
2025 /* Last sector done */
cd30b53d 2026 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
4f431960
JM
2027 } else {
2028 /* More to do */
2029 fdctrl->data_pos = 0;
2030 fdctrl->data_len = 4;
2031 }
baca51fa
FB
2032 }
2033}
2034
5c02c033 2035static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
65cef780
BS
2036{
2037 fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
2038 fdctrl->fifo[0] = fdctrl->lock << 4;
83a26013 2039 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2040}
2041
5c02c033 2042static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
65cef780 2043{
5c02c033 2044 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780
BS
2045
2046 /* Drives position */
2047 fdctrl->fifo[0] = drv0(fdctrl)->track;
2048 fdctrl->fifo[1] = drv1(fdctrl)->track;
78ae820c
BS
2049#if MAX_FD == 4
2050 fdctrl->fifo[2] = drv2(fdctrl)->track;
2051 fdctrl->fifo[3] = drv3(fdctrl)->track;
2052#else
65cef780
BS
2053 fdctrl->fifo[2] = 0;
2054 fdctrl->fifo[3] = 0;
78ae820c 2055#endif
65cef780
BS
2056 /* timers */
2057 fdctrl->fifo[4] = fdctrl->timer0;
368df94d 2058 fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
65cef780
BS
2059 fdctrl->fifo[6] = cur_drv->last_sect;
2060 fdctrl->fifo[7] = (fdctrl->lock << 7) |
2061 (cur_drv->perpendicular << 2);
2062 fdctrl->fifo[8] = fdctrl->config;
2063 fdctrl->fifo[9] = fdctrl->precomp_trk;
83a26013 2064 fdctrl_to_result_phase(fdctrl, 10);
65cef780
BS
2065}
2066
5c02c033 2067static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
65cef780
BS
2068{
2069 /* Controller's version */
2070 fdctrl->fifo[0] = fdctrl->version;
83a26013 2071 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2072}
2073
5c02c033 2074static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
65cef780
BS
2075{
2076 fdctrl->fifo[0] = 0x41; /* Stepping 1 */
83a26013 2077 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2078}
2079
5c02c033 2080static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
65cef780 2081{
5c02c033 2082 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780
BS
2083
2084 /* Drives position */
2085 drv0(fdctrl)->track = fdctrl->fifo[3];
2086 drv1(fdctrl)->track = fdctrl->fifo[4];
78ae820c
BS
2087#if MAX_FD == 4
2088 drv2(fdctrl)->track = fdctrl->fifo[5];
2089 drv3(fdctrl)->track = fdctrl->fifo[6];
2090#endif
65cef780
BS
2091 /* timers */
2092 fdctrl->timer0 = fdctrl->fifo[7];
2093 fdctrl->timer1 = fdctrl->fifo[8];
2094 cur_drv->last_sect = fdctrl->fifo[9];
2095 fdctrl->lock = fdctrl->fifo[10] >> 7;
2096 cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
2097 fdctrl->config = fdctrl->fifo[11];
2098 fdctrl->precomp_trk = fdctrl->fifo[12];
2099 fdctrl->pwrd = fdctrl->fifo[13];
07e415f2 2100 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2101}
2102
5c02c033 2103static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
65cef780 2104{
5c02c033 2105 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780
BS
2106
2107 fdctrl->fifo[0] = 0;
2108 fdctrl->fifo[1] = 0;
2109 /* Drives position */
2110 fdctrl->fifo[2] = drv0(fdctrl)->track;
2111 fdctrl->fifo[3] = drv1(fdctrl)->track;
78ae820c
BS
2112#if MAX_FD == 4
2113 fdctrl->fifo[4] = drv2(fdctrl)->track;
2114 fdctrl->fifo[5] = drv3(fdctrl)->track;
2115#else
65cef780
BS
2116 fdctrl->fifo[4] = 0;
2117 fdctrl->fifo[5] = 0;
78ae820c 2118#endif
65cef780
BS
2119 /* timers */
2120 fdctrl->fifo[6] = fdctrl->timer0;
2121 fdctrl->fifo[7] = fdctrl->timer1;
2122 fdctrl->fifo[8] = cur_drv->last_sect;
2123 fdctrl->fifo[9] = (fdctrl->lock << 7) |
2124 (cur_drv->perpendicular << 2);
2125 fdctrl->fifo[10] = fdctrl->config;
2126 fdctrl->fifo[11] = fdctrl->precomp_trk;
2127 fdctrl->fifo[12] = fdctrl->pwrd;
2128 fdctrl->fifo[13] = 0;
2129 fdctrl->fifo[14] = 0;
83a26013 2130 fdctrl_to_result_phase(fdctrl, 15);
65cef780
BS
2131}
2132
5c02c033 2133static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
65cef780 2134{
5c02c033 2135 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780 2136
65cef780 2137 cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
73bcb24d
RS
2138 timer_mod(fdctrl->result_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
2139 (NANOSECONDS_PER_SECOND / 50));
65cef780
BS
2140}
2141
5c02c033 2142static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
65cef780 2143{
5c02c033 2144 FDrive *cur_drv;
65cef780 2145
cefec4f5 2146 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780
BS
2147 cur_drv = get_cur_drv(fdctrl);
2148 fdctrl->data_state |= FD_STATE_FORMAT;
2149 if (fdctrl->fifo[0] & 0x80)
2150 fdctrl->data_state |= FD_STATE_MULTI;
2151 else
2152 fdctrl->data_state &= ~FD_STATE_MULTI;
65cef780
BS
2153 cur_drv->bps =
2154 fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
2155#if 0
2156 cur_drv->last_sect =
2157 cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
2158 fdctrl->fifo[3] / 2;
2159#else
2160 cur_drv->last_sect = fdctrl->fifo[3];
2161#endif
2162 /* TODO: implement format using DMA expected by the Bochs BIOS
2163 * and Linux fdformat (read 3 bytes per sector via DMA and fill
2164 * the sector with the specified fill byte
2165 */
2166 fdctrl->data_state &= ~FD_STATE_FORMAT;
2167 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2168}
2169
5c02c033 2170static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
65cef780
BS
2171{
2172 fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
2173 fdctrl->timer1 = fdctrl->fifo[2] >> 1;
368df94d
BS
2174 if (fdctrl->fifo[2] & 1)
2175 fdctrl->dor &= ~FD_DOR_DMAEN;
2176 else
2177 fdctrl->dor |= FD_DOR_DMAEN;
65cef780 2178 /* No result back */
07e415f2 2179 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2180}
2181
5c02c033 2182static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
65cef780 2183{
5c02c033 2184 FDrive *cur_drv;
65cef780 2185
cefec4f5 2186 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780
BS
2187 cur_drv = get_cur_drv(fdctrl);
2188 cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2189 /* 1 Byte status back */
2190 fdctrl->fifo[0] = (cur_drv->ro << 6) |
2191 (cur_drv->track == 0 ? 0x10 : 0x00) |
2192 (cur_drv->head << 2) |
cefec4f5 2193 GET_CUR_DRV(fdctrl) |
65cef780 2194 0x28;
83a26013 2195 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2196}
2197
5c02c033 2198static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
65cef780 2199{
5c02c033 2200 FDrive *cur_drv;
65cef780 2201
cefec4f5 2202 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780
BS
2203 cur_drv = get_cur_drv(fdctrl);
2204 fd_recalibrate(cur_drv);
07e415f2 2205 fdctrl_to_command_phase(fdctrl);
65cef780 2206 /* Raise Interrupt */
d497d534
HP
2207 fdctrl->status0 |= FD_SR0_SEEK;
2208 fdctrl_raise_irq(fdctrl);
65cef780
BS
2209}
2210
5c02c033 2211static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
65cef780 2212{
5c02c033 2213 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780 2214
2fee0088 2215 if (fdctrl->reset_sensei > 0) {
f2d81b33
BS
2216 fdctrl->fifo[0] =
2217 FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
2218 fdctrl->reset_sensei--;
2fee0088
PH
2219 } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
2220 fdctrl->fifo[0] = FD_SR0_INVCMD;
83a26013 2221 fdctrl_to_result_phase(fdctrl, 1);
2fee0088 2222 return;
f2d81b33 2223 } else {
f2d81b33 2224 fdctrl->fifo[0] =
2fee0088
PH
2225 (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
2226 | GET_CUR_DRV(fdctrl);
f2d81b33
BS
2227 }
2228
65cef780 2229 fdctrl->fifo[1] = cur_drv->track;
83a26013 2230 fdctrl_to_result_phase(fdctrl, 2);
65cef780 2231 fdctrl_reset_irq(fdctrl);
77370520 2232 fdctrl->status0 = FD_SR0_RDYCHG;
65cef780
BS
2233}
2234
5c02c033 2235static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
65cef780 2236{
5c02c033 2237 FDrive *cur_drv;
65cef780 2238
cefec4f5 2239 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780 2240 cur_drv = get_cur_drv(fdctrl);
07e415f2 2241 fdctrl_to_command_phase(fdctrl);
b072a3c8
HP
2242 /* The seek command just sends step pulses to the drive and doesn't care if
2243 * there is a medium inserted of if it's banging the head against the drive.
2244 */
6be01b1e 2245 fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
b072a3c8 2246 /* Raise Interrupt */
d497d534
HP
2247 fdctrl->status0 |= FD_SR0_SEEK;
2248 fdctrl_raise_irq(fdctrl);
65cef780
BS
2249}
2250
5c02c033 2251static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
65cef780 2252{
5c02c033 2253 FDrive *cur_drv = get_cur_drv(fdctrl);
65cef780
BS
2254
2255 if (fdctrl->fifo[1] & 0x80)
2256 cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
2257 /* No result back */
07e415f2 2258 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2259}
2260
5c02c033 2261static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
65cef780
BS
2262{
2263 fdctrl->config = fdctrl->fifo[2];
2264 fdctrl->precomp_trk = fdctrl->fifo[3];
2265 /* No result back */
07e415f2 2266 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2267}
2268
5c02c033 2269static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
65cef780
BS
2270{
2271 fdctrl->pwrd = fdctrl->fifo[1];
2272 fdctrl->fifo[0] = fdctrl->fifo[1];
83a26013 2273 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2274}
2275
5c02c033 2276static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
65cef780
BS
2277{
2278 /* No result back */
07e415f2 2279 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2280}
2281
5c02c033 2282static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
65cef780 2283{
5c02c033 2284 FDrive *cur_drv = get_cur_drv(fdctrl);
e9077462 2285 uint32_t pos;
65cef780 2286
e9077462
PM
2287 pos = fdctrl->data_pos - 1;
2288 pos %= FD_SECTOR_LEN;
2289 if (fdctrl->fifo[pos] & 0x80) {
65cef780 2290 /* Command parameters done */
e9077462 2291 if (fdctrl->fifo[pos] & 0x40) {
65cef780
BS
2292 fdctrl->fifo[0] = fdctrl->fifo[1];
2293 fdctrl->fifo[2] = 0;
2294 fdctrl->fifo[3] = 0;
83a26013 2295 fdctrl_to_result_phase(fdctrl, 4);
65cef780 2296 } else {
07e415f2 2297 fdctrl_to_command_phase(fdctrl);
65cef780
BS
2298 }
2299 } else if (fdctrl->data_len > 7) {
2300 /* ERROR */
2301 fdctrl->fifo[0] = 0x80 |
cefec4f5 2302 (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
83a26013 2303 fdctrl_to_result_phase(fdctrl, 1);
65cef780
BS
2304 }
2305}
2306
6d013772 2307static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
65cef780 2308{
5c02c033 2309 FDrive *cur_drv;
65cef780 2310
cefec4f5 2311 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780 2312 cur_drv = get_cur_drv(fdctrl);
65cef780 2313 if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
6be01b1e
PH
2314 fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
2315 cur_drv->sect, 1);
65cef780 2316 } else {
6d013772
PH
2317 fd_seek(cur_drv, cur_drv->head,
2318 cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
65cef780 2319 }
07e415f2 2320 fdctrl_to_command_phase(fdctrl);
77370520 2321 /* Raise Interrupt */
d497d534
HP
2322 fdctrl->status0 |= FD_SR0_SEEK;
2323 fdctrl_raise_irq(fdctrl);
65cef780
BS
2324}
2325
6d013772 2326static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
65cef780 2327{
5c02c033 2328 FDrive *cur_drv;
65cef780 2329
cefec4f5 2330 SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
65cef780 2331 cur_drv = get_cur_drv(fdctrl);
65cef780 2332 if (fdctrl->fifo[2] > cur_drv->track) {
6be01b1e 2333 fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
65cef780 2334 } else {
6d013772
PH
2335 fd_seek(cur_drv, cur_drv->head,
2336 cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
65cef780 2337 }
07e415f2 2338 fdctrl_to_command_phase(fdctrl);
65cef780 2339 /* Raise Interrupt */
d497d534
HP
2340 fdctrl->status0 |= FD_SR0_SEEK;
2341 fdctrl_raise_irq(fdctrl);
65cef780
BS
2342}
2343
85d291a0
KW
2344/*
2345 * Handlers for the execution phase of each command
2346 */
d275b33d 2347typedef struct FDCtrlCommand {
678803ab
BS
2348 uint8_t value;
2349 uint8_t mask;
2350 const char* name;
2351 int parameters;
5c02c033 2352 void (*handler)(FDCtrl *fdctrl, int direction);
678803ab 2353 int direction;
d275b33d
KW
2354} FDCtrlCommand;
2355
2356static const FDCtrlCommand handlers[] = {
678803ab
BS
2357 { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
2358 { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
2359 { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
2360 { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
2361 { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
2362 { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
2363 { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
2364 { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
2365 { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
2366 { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
2367 { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
7ea004ed 2368 { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
678803ab
BS
2369 { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
2370 { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
2371 { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
2372 { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
2373 { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
2374 { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
2375 { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
2376 { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
2377 { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
2378 { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
2379 { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
2380 { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
2381 { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
2382 { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
2383 { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
2384 { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
2385 { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
2386 { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
2387 { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
2388 { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
2389};
2390/* Associate command to an index in the 'handlers' array */
2391static uint8_t command_to_handler[256];
2392
d275b33d
KW
2393static const FDCtrlCommand *get_command(uint8_t cmd)
2394{
2395 int idx;
2396
2397 idx = command_to_handler[cmd];
2398 FLOPPY_DPRINTF("%s command\n", handlers[idx].name);
2399 return &handlers[idx];
2400}
2401
5c02c033 2402static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
baca51fa 2403{
5c02c033 2404 FDrive *cur_drv;
d275b33d 2405 const FDCtrlCommand *cmd;
e9077462 2406 uint32_t pos;
baca51fa 2407
8977f3c1 2408 /* Reset mode */
1c346df2 2409 if (!(fdctrl->dor & FD_DOR_nRESET)) {
4b19ec0c 2410 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
8977f3c1
FB
2411 return;
2412 }
b9b3d225 2413 if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
cced7a13 2414 FLOPPY_DPRINTF("error: controller not ready for writing\n");
8977f3c1
FB
2415 return;
2416 }
b9b3d225 2417 fdctrl->dsr &= ~FD_DSR_PWRDOWN;
5b0a25e8 2418
d275b33d
KW
2419 FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
2420
2421 /* If data_len spans multiple sectors, the current position in the FIFO
2422 * wraps around while fdctrl->data_pos is the real position in the whole
2423 * request. */
2424 pos = fdctrl->data_pos++;
2425 pos %= FD_SECTOR_LEN;
2426 fdctrl->fifo[pos] = value;
2427
6cc8a11c
KW
2428 if (fdctrl->data_pos == fdctrl->data_len) {
2429 fdctrl->msr &= ~FD_MSR_RQM;
2430 }
2431
5b0a25e8
KW
2432 switch (fdctrl->phase) {
2433 case FD_PHASE_EXECUTION:
2434 /* For DMA requests, RQM should be cleared during execution phase, so
2435 * we would have errored out above. */
2436 assert(fdctrl->msr & FD_MSR_NONDMA);
d275b33d 2437
8977f3c1 2438 /* FIFO data write */
b3bc1540 2439 if (pos == FD_SECTOR_LEN - 1 ||
baca51fa 2440 fdctrl->data_pos == fdctrl->data_len) {
77370520 2441 cur_drv = get_cur_drv(fdctrl);
a7a5b7c0
EB
2442 if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo,
2443 BDRV_SECTOR_SIZE, 0) < 0) {
cced7a13
BS
2444 FLOPPY_DPRINTF("error writing sector %d\n",
2445 fd_sector(cur_drv));
5b0a25e8 2446 break;
77370520 2447 }
746d6de7
BS
2448 if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
2449 FLOPPY_DPRINTF("error seeking to next sector %d\n",
2450 fd_sector(cur_drv));
5b0a25e8 2451 break;
746d6de7 2452 }
8977f3c1 2453 }
d275b33d
KW
2454
2455 /* Switch to result phase when done with the transfer */
2456 if (fdctrl->data_pos == fdctrl->data_len) {
c5139bd9 2457 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
d275b33d 2458 }
5b0a25e8 2459 break;
678803ab 2460
5b0a25e8
KW
2461 case FD_PHASE_COMMAND:
2462 assert(!(fdctrl->msr & FD_MSR_NONDMA));
d275b33d 2463 assert(fdctrl->data_pos < FD_SECTOR_LEN);
5b0a25e8 2464
d275b33d
KW
2465 if (pos == 0) {
2466 /* The first byte specifies the command. Now we start reading
2467 * as many parameters as this command requires. */
2468 cmd = get_command(value);
2469 fdctrl->data_len = cmd->parameters + 1;
6cc8a11c
KW
2470 if (cmd->parameters) {
2471 fdctrl->msr |= FD_MSR_RQM;
2472 }
5b0a25e8 2473 fdctrl->msr |= FD_MSR_CMDBUSY;
8977f3c1 2474 }
65cef780 2475
5b0a25e8 2476 if (fdctrl->data_pos == fdctrl->data_len) {
d275b33d 2477 /* We have all parameters now, execute the command */
5b0a25e8 2478 fdctrl->phase = FD_PHASE_EXECUTION;
d275b33d 2479
5b0a25e8
KW
2480 if (fdctrl->data_state & FD_STATE_FORMAT) {
2481 fdctrl_format_sector(fdctrl);
2482 break;
2483 }
2484
d275b33d
KW
2485 cmd = get_command(fdctrl->fifo[0]);
2486 FLOPPY_DPRINTF("Calling handler for '%s'\n", cmd->name);
2487 cmd->handler(fdctrl, cmd->direction);
5b0a25e8
KW
2488 }
2489 break;
2490
2491 case FD_PHASE_RESULT:
2492 default:
2493 abort();
8977f3c1
FB
2494 }
2495}
ed5fd2cc
FB
2496
2497static void fdctrl_result_timer(void *opaque)
2498{
5c02c033
BS
2499 FDCtrl *fdctrl = opaque;
2500 FDrive *cur_drv = get_cur_drv(fdctrl);
4f431960 2501
b7ffa3b1
TS
2502 /* Pretend we are spinning.
2503 * This is needed for Coherent, which uses READ ID to check for
2504 * sector interleaving.
2505 */
2506 if (cur_drv->last_sect != 0) {
2507 cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
2508 }
844f65d6
HP
2509 /* READ_ID can't automatically succeed! */
2510 if (fdctrl->check_media_rate &&
2511 (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
2512 FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
2513 fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
2514 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
2515 } else {
2516 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2517 }
ed5fd2cc 2518}
678803ab
BS
2519
2520/* Init functions */
c0ca74f6
FZ
2521static void fdctrl_connect_drives(FDCtrl *fdctrl, DeviceState *fdc_dev,
2522 Error **errp)
678803ab 2523{
12a71a02 2524 unsigned int i;
7d0d6950 2525 FDrive *drive;
394ea2ca 2526 DeviceState *dev;
a92bd191 2527 BlockBackend *blk;
394ea2ca 2528 Error *local_err = NULL;
678803ab 2529
678803ab 2530 for (i = 0; i < MAX_FD; i++) {
7d0d6950 2531 drive = &fdctrl->drives[i];
844f65d6 2532 drive->fdctrl = fdctrl;
7d0d6950 2533
394ea2ca
KW
2534 /* If the drive is not present, we skip creating the qdev device, but
2535 * still have to initialise the controller. */
a92bd191
KW
2536 blk = fdctrl->qdev_for_drives[i].blk;
2537 if (!blk) {
394ea2ca
KW
2538 fd_init(drive);
2539 fd_revalidate(drive);
2540 continue;
b47b3525
MA
2541 }
2542
394ea2ca
KW
2543 dev = qdev_create(&fdctrl->bus.bus, "floppy");
2544 qdev_prop_set_uint32(dev, "unit", i);
a92bd191
KW
2545 qdev_prop_set_enum(dev, "drive-type", fdctrl->qdev_for_drives[i].type);
2546
2547 blk_ref(blk);
2548 blk_detach_dev(blk, fdc_dev);
2549 fdctrl->qdev_for_drives[i].blk = NULL;
2550 qdev_prop_set_drive(dev, "drive", blk, &local_err);
2551 blk_unref(blk);
2552
2553 if (local_err) {
2554 error_propagate(errp, local_err);
2555 return;
2556 }
2557
394ea2ca
KW
2558 object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
2559 if (local_err) {
2560 error_propagate(errp, local_err);
2561 return;
7d0d6950 2562 }
678803ab 2563 }
678803ab
BS
2564}
2565
dfc65f1f
MA
2566ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
2567{
4a17cc4f
AF
2568 DeviceState *dev;
2569 ISADevice *isadev;
dfc65f1f 2570
4a17cc4f
AF
2571 isadev = isa_try_create(bus, TYPE_ISA_FDC);
2572 if (!isadev) {
dfc65f1f
MA
2573 return NULL;
2574 }
4a17cc4f 2575 dev = DEVICE(isadev);
dfc65f1f
MA
2576
2577 if (fds[0]) {
6231a6da
MA
2578 qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
2579 &error_fatal);
dfc65f1f
MA
2580 }
2581 if (fds[1]) {
6231a6da
MA
2582 qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
2583 &error_fatal);
dfc65f1f 2584 }
4a17cc4f 2585 qdev_init_nofail(dev);
dfc65f1f 2586
4a17cc4f 2587 return isadev;
dfc65f1f
MA
2588}
2589
63ffb564 2590void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
a8170e5e 2591 hwaddr mmio_base, DriveInfo **fds)
2091ba23 2592{
5c02c033 2593 FDCtrl *fdctrl;
2091ba23 2594 DeviceState *dev;
dd3be742 2595 SysBusDevice *sbd;
5c02c033 2596 FDCtrlSysBus *sys;
2091ba23 2597
19d46d71 2598 dev = qdev_create(NULL, "sysbus-fdc");
dd3be742 2599 sys = SYSBUS_FDC(dev);
99244fa1
GH
2600 fdctrl = &sys->state;
2601 fdctrl->dma_chann = dma_chann; /* FIXME */
995bf0ca 2602 if (fds[0]) {
6231a6da
MA
2603 qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fds[0]),
2604 &error_fatal);
995bf0ca
GH
2605 }
2606 if (fds[1]) {
6231a6da
MA
2607 qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fds[1]),
2608 &error_fatal);
995bf0ca 2609 }
e23a1b33 2610 qdev_init_nofail(dev);
dd3be742
HT
2611 sbd = SYS_BUS_DEVICE(dev);
2612 sysbus_connect_irq(sbd, 0, irq);
2613 sysbus_mmio_map(sbd, 0, mmio_base);
678803ab
BS
2614}
2615
a8170e5e 2616void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
63ffb564 2617 DriveInfo **fds, qemu_irq *fdc_tc)
678803ab 2618{
f64ab228 2619 DeviceState *dev;
5c02c033 2620 FDCtrlSysBus *sys;
678803ab 2621
12a71a02 2622 dev = qdev_create(NULL, "SUNW,fdtwo");
995bf0ca 2623 if (fds[0]) {
6231a6da
MA
2624 qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(fds[0]),
2625 &error_fatal);
995bf0ca 2626 }
e23a1b33 2627 qdev_init_nofail(dev);
dd3be742
HT
2628 sys = SYSBUS_FDC(dev);
2629 sysbus_connect_irq(SYS_BUS_DEVICE(sys), 0, irq);
2630 sysbus_mmio_map(SYS_BUS_DEVICE(sys), 0, io_base);
f64ab228 2631 *fdc_tc = qdev_get_gpio_in(dev, 0);
678803ab 2632}
f64ab228 2633
51e6e90e
KW
2634static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
2635 Error **errp)
f64ab228 2636{
12a71a02
BS
2637 int i, j;
2638 static int command_tables_inited = 0;
f64ab228 2639
a73275dd
JS
2640 if (fdctrl->fallback == FLOPPY_DRIVE_TYPE_AUTO) {
2641 error_setg(errp, "Cannot choose a fallback FDrive type of 'auto'");
2642 }
2643
12a71a02
BS
2644 /* Fill 'command_to_handler' lookup table */
2645 if (!command_tables_inited) {
2646 command_tables_inited = 1;
2647 for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
2648 for (j = 0; j < sizeof(command_to_handler); j++) {
2649 if ((j & handlers[i].mask) == handlers[i].value) {
2650 command_to_handler[j] = i;
2651 }
2652 }
2653 }
2654 }
2655
2656 FLOPPY_DPRINTF("init controller\n");
2657 fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
6653d131 2658 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
d7a6c270 2659 fdctrl->fifo_size = 512;
bc72ad67 2660 fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
a3ef7a61 2661 fdctrl_result_timer, fdctrl);
12a71a02
BS
2662
2663 fdctrl->version = 0x90; /* Intel 82078 controller */
2664 fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
d7a6c270 2665 fdctrl->num_floppies = MAX_FD;
12a71a02 2666
a3ef7a61 2667 if (fdctrl->dma_chann != -1) {
c8a35f1c
HP
2668 IsaDmaClass *k;
2669 assert(fdctrl->dma);
2670 k = ISADMA_GET_CLASS(fdctrl->dma);
2671 k->register_channel(fdctrl->dma, fdctrl->dma_chann,
2672 &fdctrl_transfer_handler, fdctrl);
a3ef7a61 2673 }
51e6e90e
KW
2674
2675 floppy_bus_create(fdctrl, &fdctrl->bus, dev);
c0ca74f6 2676 fdctrl_connect_drives(fdctrl, dev, errp);
f64ab228
BS
2677}
2678
212ec7ba 2679static const MemoryRegionPortio fdc_portio_list[] = {
2f290a8c 2680 { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
212ec7ba
RH
2681 { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
2682 PORTIO_END_OF_LIST(),
2f290a8c
RH
2683};
2684
db895a1e 2685static void isabus_fdc_realize(DeviceState *dev, Error **errp)
8baf73ad 2686{
db895a1e 2687 ISADevice *isadev = ISA_DEVICE(dev);
020c8e76 2688 FDCtrlISABus *isa = ISA_FDC(dev);
5c02c033 2689 FDCtrl *fdctrl = &isa->state;
a3ef7a61 2690 Error *err = NULL;
8baf73ad 2691
e305a165
MAL
2692 isa_register_portio_list(isadev, &fdctrl->portio_list,
2693 isa->iobase, fdc_portio_list, fdctrl,
db895a1e 2694 "fdc");
dee41d58 2695
db895a1e 2696 isa_init_irq(isadev, &fdctrl->irq, isa->irq);
c9ae703d 2697 fdctrl->dma_chann = isa->dma;
c8a35f1c
HP
2698 if (fdctrl->dma_chann != -1) {
2699 fdctrl->dma = isa_get_dma(isa_bus_from_device(isadev), isa->dma);
b3da5513
AK
2700 if (!fdctrl->dma) {
2701 error_setg(errp, "ISA controller does not support DMA");
2702 return;
2703 }
c8a35f1c 2704 }
8baf73ad 2705
db895a1e 2706 qdev_set_legacy_instance_id(dev, isa->iobase, 2);
51e6e90e 2707 fdctrl_realize_common(dev, fdctrl, &err);
a3ef7a61
AF
2708 if (err != NULL) {
2709 error_propagate(errp, err);
db895a1e
AF
2710 return;
2711 }
8baf73ad
GH
2712}
2713
940194c2 2714static void sysbus_fdc_initfn(Object *obj)
12a71a02 2715{
19d46d71 2716 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
940194c2 2717 FDCtrlSysBus *sys = SYSBUS_FDC(obj);
5c02c033 2718 FDCtrl *fdctrl = &sys->state;
12a71a02 2719
19d46d71
AF
2720 fdctrl->dma_chann = -1;
2721
940194c2 2722 memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_ops, fdctrl,
2d256e6f 2723 "fdc", 0x08);
19d46d71 2724 sysbus_init_mmio(sbd, &fdctrl->iomem);
940194c2
HT
2725}
2726
19d46d71 2727static void sun4m_fdc_initfn(Object *obj)
940194c2 2728{
19d46d71
AF
2729 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
2730 FDCtrlSysBus *sys = SYSBUS_FDC(obj);
940194c2 2731 FDCtrl *fdctrl = &sys->state;
940194c2 2732
dd446051
HP
2733 fdctrl->dma_chann = -1;
2734
19d46d71
AF
2735 memory_region_init_io(&fdctrl->iomem, obj, &fdctrl_mem_strict_ops,
2736 fdctrl, "fdctrl", 0x08);
2737 sysbus_init_mmio(sbd, &fdctrl->iomem);
940194c2 2738}
2be37833 2739
19d46d71 2740static void sysbus_fdc_common_initfn(Object *obj)
940194c2 2741{
19d46d71
AF
2742 DeviceState *dev = DEVICE(obj);
2743 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
940194c2
HT
2744 FDCtrlSysBus *sys = SYSBUS_FDC(obj);
2745 FDCtrl *fdctrl = &sys->state;
2746
19d46d71
AF
2747 qdev_set_legacy_instance_id(dev, 0 /* io */, 2); /* FIXME */
2748
2749 sysbus_init_irq(sbd, &fdctrl->irq);
2750 qdev_init_gpio_in(dev, fdctrl_handle_tc, 1);
12a71a02
BS
2751}
2752
19d46d71 2753static void sysbus_fdc_common_realize(DeviceState *dev, Error **errp)
12a71a02 2754{
dd3be742
HT
2755 FDCtrlSysBus *sys = SYSBUS_FDC(dev);
2756 FDCtrl *fdctrl = &sys->state;
12a71a02 2757
51e6e90e 2758 fdctrl_realize_common(dev, fdctrl, errp);
12a71a02 2759}
f64ab228 2760
2da44dd0 2761FloppyDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
34d4260e 2762{
020c8e76 2763 FDCtrlISABus *isa = ISA_FDC(fdc);
34d4260e 2764
61a8d649 2765 return isa->state.drives[i].drive;
34d4260e
KW
2766}
2767
e08fde0c
RK
2768void isa_fdc_get_drive_max_chs(FloppyDriveType type,
2769 uint8_t *maxc, uint8_t *maxh, uint8_t *maxs)
2770{
2771 const FDFormat *fdf;
2772
2773 *maxc = *maxh = *maxs = 0;
2774 for (fdf = fd_formats; fdf->drive != FLOPPY_DRIVE_TYPE_NONE; fdf++) {
2775 if (fdf->drive != type) {
2776 continue;
2777 }
2778 if (*maxc < fdf->max_track) {
2779 *maxc = fdf->max_track;
2780 }
2781 if (*maxh < fdf->max_head) {
2782 *maxh = fdf->max_head;
2783 }
2784 if (*maxs < fdf->last_sect) {
2785 *maxs = fdf->last_sect;
2786 }
2787 }
2788 (*maxc)--;
2789}
2790
a64405d1
JK
2791static const VMStateDescription vmstate_isa_fdc ={
2792 .name = "fdc",
2793 .version_id = 2,
2794 .minimum_version_id = 2,
d49805ae 2795 .fields = (VMStateField[]) {
a64405d1
JK
2796 VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
2797 VMSTATE_END_OF_LIST()
2798 }
2799};
2800
39bffca2 2801static Property isa_fdc_properties[] = {
c7bcc85d 2802 DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
c9ae703d
HP
2803 DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
2804 DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
a92bd191
KW
2805 DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.qdev_for_drives[0].blk),
2806 DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.qdev_for_drives[1].blk),
09c6d585
HP
2807 DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
2808 0, true),
85bbd1e7 2809 DEFINE_PROP_SIGNED("fdtypeA", FDCtrlISABus, state.qdev_for_drives[0].type,
fff4687b
JS
2810 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
2811 FloppyDriveType),
85bbd1e7 2812 DEFINE_PROP_SIGNED("fdtypeB", FDCtrlISABus, state.qdev_for_drives[1].type,
fff4687b
JS
2813 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
2814 FloppyDriveType),
85bbd1e7 2815 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
4812fa27 2816 FLOPPY_DRIVE_TYPE_288, qdev_prop_fdc_drive_type,
a73275dd 2817 FloppyDriveType),
39bffca2
AL
2818 DEFINE_PROP_END_OF_LIST(),
2819};
2820
020c8e76 2821static void isabus_fdc_class_init(ObjectClass *klass, void *data)
8f04ee08 2822{
39bffca2 2823 DeviceClass *dc = DEVICE_CLASS(klass);
db895a1e
AF
2824
2825 dc->realize = isabus_fdc_realize;
39bffca2 2826 dc->fw_name = "fdc";
39bffca2
AL
2827 dc->reset = fdctrl_external_reset_isa;
2828 dc->vmsd = &vmstate_isa_fdc;
2829 dc->props = isa_fdc_properties;
125ee0ed 2830 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
39bffca2
AL
2831}
2832
81782b6a
GA
2833static void isabus_fdc_instance_init(Object *obj)
2834{
2835 FDCtrlISABus *isa = ISA_FDC(obj);
2836
2837 device_add_bootindex_property(obj, &isa->bootindexA,
2838 "bootindexA", "/floppy@0",
2839 DEVICE(obj), NULL);
2840 device_add_bootindex_property(obj, &isa->bootindexB,
2841 "bootindexB", "/floppy@1",
2842 DEVICE(obj), NULL);
2843}
2844
8c43a6f0 2845static const TypeInfo isa_fdc_info = {
020c8e76 2846 .name = TYPE_ISA_FDC,
39bffca2
AL
2847 .parent = TYPE_ISA_DEVICE,
2848 .instance_size = sizeof(FDCtrlISABus),
020c8e76 2849 .class_init = isabus_fdc_class_init,
81782b6a 2850 .instance_init = isabus_fdc_instance_init,
8baf73ad
GH
2851};
2852
a64405d1
JK
2853static const VMStateDescription vmstate_sysbus_fdc ={
2854 .name = "fdc",
2855 .version_id = 2,
2856 .minimum_version_id = 2,
d49805ae 2857 .fields = (VMStateField[]) {
a64405d1
JK
2858 VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
2859 VMSTATE_END_OF_LIST()
2860 }
2861};
2862
999e12bb 2863static Property sysbus_fdc_properties[] = {
a92bd191
KW
2864 DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.qdev_for_drives[0].blk),
2865 DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.qdev_for_drives[1].blk),
85bbd1e7 2866 DEFINE_PROP_SIGNED("fdtypeA", FDCtrlSysBus, state.qdev_for_drives[0].type,
fff4687b
JS
2867 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
2868 FloppyDriveType),
85bbd1e7 2869 DEFINE_PROP_SIGNED("fdtypeB", FDCtrlSysBus, state.qdev_for_drives[1].type,
fff4687b
JS
2870 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
2871 FloppyDriveType),
85bbd1e7 2872 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
a73275dd
JS
2873 FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
2874 FloppyDriveType),
999e12bb 2875 DEFINE_PROP_END_OF_LIST(),
12a71a02
BS
2876};
2877
999e12bb
AL
2878static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
2879{
39bffca2 2880 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 2881
39bffca2 2882 dc->props = sysbus_fdc_properties;
125ee0ed 2883 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
999e12bb
AL
2884}
2885
8c43a6f0 2886static const TypeInfo sysbus_fdc_info = {
19d46d71
AF
2887 .name = "sysbus-fdc",
2888 .parent = TYPE_SYSBUS_FDC,
940194c2 2889 .instance_init = sysbus_fdc_initfn,
39bffca2 2890 .class_init = sysbus_fdc_class_init,
999e12bb
AL
2891};
2892
2893static Property sun4m_fdc_properties[] = {
a92bd191 2894 DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.qdev_for_drives[0].blk),
85bbd1e7 2895 DEFINE_PROP_SIGNED("fdtype", FDCtrlSysBus, state.qdev_for_drives[0].type,
fff4687b
JS
2896 FLOPPY_DRIVE_TYPE_AUTO, qdev_prop_fdc_drive_type,
2897 FloppyDriveType),
85bbd1e7 2898 DEFINE_PROP_SIGNED("fallback", FDCtrlISABus, state.fallback,
a73275dd
JS
2899 FLOPPY_DRIVE_TYPE_144, qdev_prop_fdc_drive_type,
2900 FloppyDriveType),
999e12bb
AL
2901 DEFINE_PROP_END_OF_LIST(),
2902};
2903
2904static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
2905{
39bffca2 2906 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 2907
39bffca2 2908 dc->props = sun4m_fdc_properties;
125ee0ed 2909 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
999e12bb
AL
2910}
2911
8c43a6f0 2912static const TypeInfo sun4m_fdc_info = {
39bffca2 2913 .name = "SUNW,fdtwo",
19d46d71 2914 .parent = TYPE_SYSBUS_FDC,
940194c2 2915 .instance_init = sun4m_fdc_initfn,
39bffca2 2916 .class_init = sun4m_fdc_class_init,
f64ab228
BS
2917};
2918
19d46d71
AF
2919static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data)
2920{
2921 DeviceClass *dc = DEVICE_CLASS(klass);
2922
2923 dc->realize = sysbus_fdc_common_realize;
2924 dc->reset = fdctrl_external_reset_sysbus;
2925 dc->vmsd = &vmstate_sysbus_fdc;
2926}
2927
2928static const TypeInfo sysbus_fdc_type_info = {
2929 .name = TYPE_SYSBUS_FDC,
2930 .parent = TYPE_SYS_BUS_DEVICE,
2931 .instance_size = sizeof(FDCtrlSysBus),
2932 .instance_init = sysbus_fdc_common_initfn,
2933 .abstract = true,
2934 .class_init = sysbus_fdc_common_class_init,
2935};
2936
83f7d43a 2937static void fdc_register_types(void)
f64ab228 2938{
39bffca2 2939 type_register_static(&isa_fdc_info);
19d46d71 2940 type_register_static(&sysbus_fdc_type_info);
39bffca2
AL
2941 type_register_static(&sysbus_fdc_info);
2942 type_register_static(&sun4m_fdc_info);
51e6e90e 2943 type_register_static(&floppy_bus_info);
394ea2ca 2944 type_register_static(&floppy_drive_info);
f64ab228
BS
2945}
2946
83f7d43a 2947type_init(fdc_register_types)