migration: Move update_compress_threads_counts() to ram-compress.c
[qemu/kevin.git] / hw / block / swim.c
blobfd65c59f8a10dfb9371f5ca20baf86f2fff3e450
1 /*
2 * QEMU Macintosh floppy disk controller emulator (SWIM)
4 * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
6 * This work is licensed under the terms of the GNU GPL, version 2. See
7 * the COPYING file in the top-level directory.
9 * Only the basic support: it allows to switch from IWM (Integrated WOZ
10 * Machine) mode to the SWIM mode and makes the linux driver happy.
13 #include "qemu/osdep.h"
14 #include "qemu/main-loop.h"
15 #include "qapi/error.h"
16 #include "sysemu/block-backend.h"
17 #include "hw/sysbus.h"
18 #include "migration/vmstate.h"
19 #include "hw/block/block.h"
20 #include "hw/block/swim.h"
21 #include "hw/qdev-properties.h"
22 #include "trace.h"
25 /* IWM latch bits */
27 #define IWMLB_PHASE0 0
28 #define IWMLB_PHASE1 1
29 #define IWMLB_PHASE2 2
30 #define IWMLB_PHASE3 3
31 #define IWMLB_MOTORON 4
32 #define IWMLB_DRIVESEL 5
33 #define IWMLB_L6 6
34 #define IWMLB_L7 7
36 /* IWM registers */
38 #define IWM_READALLONES 0
39 #define IWM_READDATA 1
40 #define IWM_READSTATUS0 2
41 #define IWM_READSTATUS1 3
42 #define IWM_READWHANDSHAKE0 4
43 #define IWM_READWHANDSHAKE1 5
44 #define IWM_WRITESETMODE 6
45 #define IWM_WRITEDATA 7
47 /* SWIM registers */
49 #define SWIM_WRITE_DATA 0
50 #define SWIM_WRITE_MARK 1
51 #define SWIM_WRITE_CRC 2
52 #define SWIM_WRITE_PARAMETER 3
53 #define SWIM_WRITE_PHASE 4
54 #define SWIM_WRITE_SETUP 5
55 #define SWIM_WRITE_MODE0 6
56 #define SWIM_WRITE_MODE1 7
58 #define SWIM_READ_DATA 8
59 #define SWIM_READ_MARK 9
60 #define SWIM_READ_ERROR 10
61 #define SWIM_READ_PARAMETER 11
62 #define SWIM_READ_PHASE 12
63 #define SWIM_READ_SETUP 13
64 #define SWIM_READ_STATUS 14
65 #define SWIM_READ_HANDSHAKE 15
67 #define REG_SHIFT 9
69 #define SWIM_MODE_STATUS_BIT 6
70 #define SWIM_MODE_IWM 0
71 #define SWIM_MODE_ISM 1
73 /* bits in phase register */
75 #define SWIM_SEEK_NEGATIVE 0x074
76 #define SWIM_STEP 0x071
77 #define SWIM_MOTOR_ON 0x072
78 #define SWIM_MOTOR_OFF 0x076
79 #define SWIM_INDEX 0x073
80 #define SWIM_EJECT 0x077
81 #define SWIM_SETMFM 0x171
82 #define SWIM_SETGCR 0x175
83 #define SWIM_RELAX 0x033
84 #define SWIM_LSTRB 0x008
85 #define SWIM_CA_MASK 0x077
87 /* Select values for swim_select and swim_readbit */
89 #define SWIM_READ_DATA_0 0x074
90 #define SWIM_TWOMEG_DRIVE 0x075
91 #define SWIM_SINGLE_SIDED 0x076
92 #define SWIM_DRIVE_PRESENT 0x077
93 #define SWIM_DISK_IN 0x170
94 #define SWIM_WRITE_PROT 0x171
95 #define SWIM_TRACK_ZERO 0x172
96 #define SWIM_TACHO 0x173
97 #define SWIM_READ_DATA_1 0x174
98 #define SWIM_MFM_MODE 0x175
99 #define SWIM_SEEK_COMPLETE 0x176
100 #define SWIM_ONEMEG_MEDIA 0x177
102 /* Bits in handshake register */
104 #define SWIM_MARK_BYTE 0x01
105 #define SWIM_CRC_ZERO 0x02
106 #define SWIM_RDDATA 0x04
107 #define SWIM_SENSE 0x08
108 #define SWIM_MOTEN 0x10
109 #define SWIM_ERROR 0x20
110 #define SWIM_DAT2BYTE 0x40
111 #define SWIM_DAT1BYTE 0x80
113 /* bits in setup register */
115 #define SWIM_S_INV_WDATA 0x01
116 #define SWIM_S_3_5_SELECT 0x02
117 #define SWIM_S_GCR 0x04
118 #define SWIM_S_FCLK_DIV2 0x08
119 #define SWIM_S_ERROR_CORR 0x10
120 #define SWIM_S_IBM_DRIVE 0x20
121 #define SWIM_S_GCR_WRITE 0x40
122 #define SWIM_S_TIMEOUT 0x80
124 /* bits in mode register */
126 #define SWIM_CLFIFO 0x01
127 #define SWIM_ENBL1 0x02
128 #define SWIM_ENBL2 0x04
129 #define SWIM_ACTION 0x08
130 #define SWIM_WRITE_MODE 0x10
131 #define SWIM_HEDSEL 0x20
132 #define SWIM_MOTON 0x80
134 static const char *iwm_reg_names[] = {
135 "READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
136 "READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
139 static const char *ism_reg_names[] = {
140 "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER",
141 "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1",
142 "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER",
143 "READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE"
146 static void fd_recalibrate(FDrive *drive)
150 static void swim_change_cb(void *opaque, bool load, Error **errp)
152 FDrive *drive = opaque;
154 if (!load) {
155 blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
156 } else {
157 if (!blkconf_apply_backend_options(drive->conf,
158 !blk_supports_write_perm(drive->blk),
159 false, errp)) {
160 return;
165 static const BlockDevOps swim_block_ops = {
166 .change_media_cb = swim_change_cb,
169 static Property swim_drive_properties[] = {
170 DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
171 DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
172 DEFINE_PROP_END_OF_LIST(),
175 static void swim_drive_realize(DeviceState *qdev, Error **errp)
177 SWIMDrive *dev = SWIM_DRIVE(qdev);
178 SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
179 FDrive *drive;
180 int ret;
182 if (dev->unit == -1) {
183 for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
184 drive = &bus->ctrl->drives[dev->unit];
185 if (!drive->blk) {
186 break;
191 if (dev->unit >= SWIM_MAX_FD) {
192 error_setg(errp, "Can't create floppy unit %d, bus supports "
193 "only %d units", dev->unit, SWIM_MAX_FD);
194 return;
197 drive = &bus->ctrl->drives[dev->unit];
198 if (drive->blk) {
199 error_setg(errp, "Floppy unit %d is in use", dev->unit);
200 return;
203 if (!dev->conf.blk) {
204 /* Anonymous BlockBackend for an empty drive */
205 dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
206 ret = blk_attach_dev(dev->conf.blk, qdev);
207 assert(ret == 0);
210 if (!blkconf_blocksizes(&dev->conf, errp)) {
211 return;
214 if (dev->conf.logical_block_size != 512 ||
215 dev->conf.physical_block_size != 512)
217 error_setg(errp, "Physical and logical block size must "
218 "be 512 for floppy");
219 return;
223 * rerror/werror aren't supported by fdc and therefore not even registered
224 * with qdev. So set the defaults manually before they are used in
225 * blkconf_apply_backend_options().
227 dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
228 dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
230 if (!blkconf_apply_backend_options(&dev->conf,
231 !blk_supports_write_perm(dev->conf.blk),
232 false, errp)) {
233 return;
237 * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
238 * for empty drives.
240 if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
241 blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
242 error_setg(errp, "fdc doesn't support drive option werror");
243 return;
245 if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
246 error_setg(errp, "fdc doesn't support drive option rerror");
247 return;
250 drive->conf = &dev->conf;
251 drive->blk = dev->conf.blk;
252 drive->swimctrl = bus->ctrl;
254 blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
257 static void swim_drive_class_init(ObjectClass *klass, void *data)
259 DeviceClass *k = DEVICE_CLASS(klass);
260 k->realize = swim_drive_realize;
261 set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
262 k->bus_type = TYPE_SWIM_BUS;
263 device_class_set_props(k, swim_drive_properties);
264 k->desc = "virtual SWIM drive";
267 static const TypeInfo swim_drive_info = {
268 .name = TYPE_SWIM_DRIVE,
269 .parent = TYPE_DEVICE,
270 .instance_size = sizeof(SWIMDrive),
271 .class_init = swim_drive_class_init,
274 static const TypeInfo swim_bus_info = {
275 .name = TYPE_SWIM_BUS,
276 .parent = TYPE_BUS,
277 .instance_size = sizeof(SWIMBus),
280 static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
281 unsigned size)
283 SWIMCtrl *swimctrl = opaque;
284 uint8_t latch, reg, ism_bit;
286 addr >>= REG_SHIFT;
288 /* A3-A1 select a latch, A0 specifies the value */
289 latch = (addr >> 1) & 7;
290 if (addr & 1) {
291 swimctrl->iwm_latches |= (1 << latch);
292 } else {
293 swimctrl->iwm_latches &= ~(1 << latch);
296 reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
297 (swimctrl->iwm_latches & 0x10) >> 4;
299 swimctrl->iwmregs[reg] = value;
300 trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);
302 switch (reg) {
303 case IWM_WRITESETMODE:
304 /* detect sequence to switch from IWM mode to SWIM mode */
305 ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));
307 switch (swimctrl->iwm_switch) {
308 case 0:
309 if (ism_bit) { /* 1 */
310 swimctrl->iwm_switch++;
312 break;
313 case 1:
314 if (!ism_bit) { /* 0 */
315 swimctrl->iwm_switch++;
317 break;
318 case 2:
319 if (ism_bit) { /* 1 */
320 swimctrl->iwm_switch++;
322 break;
323 case 3:
324 if (ism_bit) { /* 1 */
325 swimctrl->iwm_switch++;
327 swimctrl->mode = SWIM_MODE_ISM;
328 swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
329 swimctrl->iwm_switch = 0;
330 trace_swim_switch_to_ism();
332 /* Switch to ISM registers */
333 memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
334 memory_region_add_subregion(&swimctrl->swim, 0x0,
335 &swimctrl->ism);
337 break;
339 break;
340 default:
341 break;
345 static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
347 SWIMCtrl *swimctrl = opaque;
348 uint8_t latch, reg, value;
350 addr >>= REG_SHIFT;
352 /* A3-A1 select a latch, A0 specifies the value */
353 latch = (addr >> 1) & 7;
354 if (addr & 1) {
355 swimctrl->iwm_latches |= (1 << latch);
356 } else {
357 swimctrl->iwm_latches &= ~(1 << latch);
360 reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
361 (swimctrl->iwm_latches & 0x10) >> 4;
363 switch (reg) {
364 case IWM_READALLONES:
365 value = 0xff;
366 break;
367 default:
368 value = 0;
369 break;
372 trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
373 return value;
376 static const MemoryRegionOps swimctrl_iwm_ops = {
377 .write = iwmctrl_write,
378 .read = iwmctrl_read,
379 .endianness = DEVICE_BIG_ENDIAN,
382 static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,
383 unsigned size)
385 SWIMCtrl *swimctrl = opaque;
387 reg >>= REG_SHIFT;
389 trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);
391 switch (reg) {
392 case SWIM_WRITE_PHASE:
393 swimctrl->swim_phase = value;
394 break;
395 case SWIM_WRITE_MODE0:
396 swimctrl->swim_mode &= ~value;
397 /* Any access to MODE0 register resets PRAM index */
398 swimctrl->pram_idx = 0;
400 if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
401 /* Clearing the mode bit switches to IWM mode */
402 swimctrl->mode = SWIM_MODE_IWM;
403 swimctrl->iwm_latches = 0;
404 trace_swim_switch_to_iwm();
406 /* Switch to IWM registers */
407 memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
408 memory_region_add_subregion(&swimctrl->swim, 0x0,
409 &swimctrl->iwm);
411 break;
412 case SWIM_WRITE_MODE1:
413 swimctrl->swim_mode |= value;
414 break;
415 case SWIM_WRITE_PARAMETER:
416 swimctrl->pram[swimctrl->pram_idx++] = value;
417 swimctrl->pram_idx &= 0xf;
418 break;
419 case SWIM_WRITE_DATA:
420 case SWIM_WRITE_MARK:
421 case SWIM_WRITE_CRC:
422 case SWIM_WRITE_SETUP:
423 break;
427 static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
429 SWIMCtrl *swimctrl = opaque;
430 uint32_t value = 0;
432 reg >>= REG_SHIFT;
434 switch (reg) {
435 case SWIM_READ_PHASE:
436 value = swimctrl->swim_phase;
437 break;
438 case SWIM_READ_HANDSHAKE:
439 if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
440 /* always answer "no drive present" */
441 value = SWIM_SENSE;
443 break;
444 case SWIM_READ_PARAMETER:
445 value = swimctrl->pram[swimctrl->pram_idx++];
446 swimctrl->pram_idx &= 0xf;
447 break;
448 case SWIM_READ_STATUS:
449 value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
450 if (swimctrl->swim_mode == SWIM_MODE_ISM) {
451 value |= (1 << SWIM_MODE_STATUS_BIT);
453 break;
454 case SWIM_READ_DATA:
455 case SWIM_READ_MARK:
456 case SWIM_READ_ERROR:
457 case SWIM_READ_SETUP:
458 break;
461 trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
462 return value;
465 static const MemoryRegionOps swimctrl_ism_ops = {
466 .write = ismctrl_write,
467 .read = ismctrl_read,
468 .endianness = DEVICE_BIG_ENDIAN,
471 static void sysbus_swim_reset(DeviceState *d)
473 Swim *sys = SWIM(d);
474 SWIMCtrl *ctrl = &sys->ctrl;
475 int i;
477 ctrl->mode = 0;
478 ctrl->iwm_switch = 0;
479 memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));
481 ctrl->swim_phase = 0;
482 ctrl->swim_mode = 0;
483 memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
484 for (i = 0; i < SWIM_MAX_FD; i++) {
485 fd_recalibrate(&ctrl->drives[i]);
489 static void sysbus_swim_init(Object *obj)
491 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
492 Swim *sbs = SWIM(obj);
493 SWIMCtrl *swimctrl = &sbs->ctrl;
495 memory_region_init(&swimctrl->swim, obj, "swim", 0x2000);
496 memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl,
497 "iwm", 0x2000);
498 memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl,
499 "ism", 0x2000);
500 sysbus_init_mmio(sbd, &swimctrl->swim);
503 static void sysbus_swim_realize(DeviceState *dev, Error **errp)
505 Swim *sys = SWIM(dev);
506 SWIMCtrl *swimctrl = &sys->ctrl;
508 qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
509 swimctrl->bus.ctrl = swimctrl;
511 /* Default register set is IWM */
512 memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm);
515 static const VMStateDescription vmstate_fdrive = {
516 .name = "fdrive",
517 .version_id = 1,
518 .minimum_version_id = 1,
519 .fields = (VMStateField[]) {
520 VMSTATE_END_OF_LIST()
524 static const VMStateDescription vmstate_swim = {
525 .name = "swim",
526 .version_id = 1,
527 .minimum_version_id = 1,
528 .fields = (VMStateField[]) {
529 VMSTATE_INT32(mode, SWIMCtrl),
530 /* IWM mode */
531 VMSTATE_INT32(iwm_switch, SWIMCtrl),
532 VMSTATE_UINT8(iwm_latches, SWIMCtrl),
533 VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
534 /* SWIM mode */
535 VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
536 VMSTATE_UINT8(swim_phase, SWIMCtrl),
537 VMSTATE_UINT8(swim_mode, SWIMCtrl),
538 /* Drives */
539 VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
540 vmstate_fdrive, FDrive),
541 VMSTATE_END_OF_LIST()
545 static const VMStateDescription vmstate_sysbus_swim = {
546 .name = "SWIM",
547 .version_id = 1,
548 .fields = (VMStateField[]) {
549 VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
550 VMSTATE_END_OF_LIST()
554 static void sysbus_swim_class_init(ObjectClass *oc, void *data)
556 DeviceClass *dc = DEVICE_CLASS(oc);
558 dc->realize = sysbus_swim_realize;
559 dc->reset = sysbus_swim_reset;
560 dc->vmsd = &vmstate_sysbus_swim;
563 static const TypeInfo sysbus_swim_info = {
564 .name = TYPE_SWIM,
565 .parent = TYPE_SYS_BUS_DEVICE,
566 .instance_size = sizeof(Swim),
567 .instance_init = sysbus_swim_init,
568 .class_init = sysbus_swim_class_init,
571 static void swim_register_types(void)
573 type_register_static(&sysbus_swim_info);
574 type_register_static(&swim_bus_info);
575 type_register_static(&swim_drive_info);
578 type_init(swim_register_types)