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