1
2
3
4
5
6
7
8
9
10
11
12
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
23
24
25#define IWM_PH0L 0
26#define IWM_PH0H 1
27#define IWM_PH1L 2
28#define IWM_PH1H 3
29#define IWM_PH2L 4
30#define IWM_PH2H 5
31#define IWM_PH3L 6
32#define IWM_PH3H 7
33#define IWM_MTROFF 8
34#define IWM_MTRON 9
35#define IWM_INTDRIVE 10
36#define IWM_EXTDRIVE 11
37#define IWM_Q6L 12
38#define IWM_Q6H 13
39#define IWM_Q7L 14
40#define IWM_Q7H 15
41
42
43
44#define SWIM_WRITE_DATA 0
45#define SWIM_WRITE_MARK 1
46#define SWIM_WRITE_CRC 2
47#define SWIM_WRITE_PARAMETER 3
48#define SWIM_WRITE_PHASE 4
49#define SWIM_WRITE_SETUP 5
50#define SWIM_WRITE_MODE0 6
51#define SWIM_WRITE_MODE1 7
52
53#define SWIM_READ_DATA 8
54#define SWIM_READ_MARK 9
55#define SWIM_READ_ERROR 10
56#define SWIM_READ_PARAMETER 11
57#define SWIM_READ_PHASE 12
58#define SWIM_READ_SETUP 13
59#define SWIM_READ_STATUS 14
60#define SWIM_READ_HANDSHAKE 15
61
62#define REG_SHIFT 9
63
64#define SWIM_MODE_IWM 0
65#define SWIM_MODE_SWIM 1
66
67
68
69#define SWIM_SEEK_NEGATIVE 0x074
70#define SWIM_STEP 0x071
71#define SWIM_MOTOR_ON 0x072
72#define SWIM_MOTOR_OFF 0x076
73#define SWIM_INDEX 0x073
74#define SWIM_EJECT 0x077
75#define SWIM_SETMFM 0x171
76#define SWIM_SETGCR 0x175
77#define SWIM_RELAX 0x033
78#define SWIM_LSTRB 0x008
79#define SWIM_CA_MASK 0x077
80
81
82
83#define SWIM_READ_DATA_0 0x074
84#define SWIM_TWOMEG_DRIVE 0x075
85#define SWIM_SINGLE_SIDED 0x076
86#define SWIM_DRIVE_PRESENT 0x077
87#define SWIM_DISK_IN 0x170
88#define SWIM_WRITE_PROT 0x171
89#define SWIM_TRACK_ZERO 0x172
90#define SWIM_TACHO 0x173
91#define SWIM_READ_DATA_1 0x174
92#define SWIM_MFM_MODE 0x175
93#define SWIM_SEEK_COMPLETE 0x176
94#define SWIM_ONEMEG_MEDIA 0x177
95
96
97
98#define SWIM_MARK_BYTE 0x01
99#define SWIM_CRC_ZERO 0x02
100#define SWIM_RDDATA 0x04
101#define SWIM_SENSE 0x08
102#define SWIM_MOTEN 0x10
103#define SWIM_ERROR 0x20
104#define SWIM_DAT2BYTE 0x40
105#define SWIM_DAT1BYTE 0x80
106
107
108
109#define SWIM_S_INV_WDATA 0x01
110#define SWIM_S_3_5_SELECT 0x02
111#define SWIM_S_GCR 0x04
112#define SWIM_S_FCLK_DIV2 0x08
113#define SWIM_S_ERROR_CORR 0x10
114#define SWIM_S_IBM_DRIVE 0x20
115#define SWIM_S_GCR_WRITE 0x40
116#define SWIM_S_TIMEOUT 0x80
117
118
119
120#define SWIM_CLFIFO 0x01
121#define SWIM_ENBL1 0x02
122#define SWIM_ENBL2 0x04
123#define SWIM_ACTION 0x08
124#define SWIM_WRITE_MODE 0x10
125#define SWIM_HEDSEL 0x20
126#define SWIM_MOTON 0x80
127
128static void fd_recalibrate(FDrive *drive)
129{
130}
131
132static void swim_change_cb(void *opaque, bool load, Error **errp)
133{
134 FDrive *drive = opaque;
135
136 if (!load) {
137 blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
138 } else {
139 if (!blkconf_apply_backend_options(drive->conf,
140 blk_is_read_only(drive->blk), false,
141 errp)) {
142 return;
143 }
144 }
145}
146
147static const BlockDevOps swim_block_ops = {
148 .change_media_cb = swim_change_cb,
149};
150
151static Property swim_drive_properties[] = {
152 DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
153 DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
154 DEFINE_PROP_END_OF_LIST(),
155};
156
157static void swim_drive_realize(DeviceState *qdev, Error **errp)
158{
159 SWIMDrive *dev = SWIM_DRIVE(qdev);
160 SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
161 FDrive *drive;
162 int ret;
163
164 if (dev->unit == -1) {
165 for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
166 drive = &bus->ctrl->drives[dev->unit];
167 if (!drive->blk) {
168 break;
169 }
170 }
171 }
172
173 if (dev->unit >= SWIM_MAX_FD) {
174 error_setg(errp, "Can't create floppy unit %d, bus supports "
175 "only %d units", dev->unit, SWIM_MAX_FD);
176 return;
177 }
178
179 drive = &bus->ctrl->drives[dev->unit];
180 if (drive->blk) {
181 error_setg(errp, "Floppy unit %d is in use", dev->unit);
182 return;
183 }
184
185 if (!dev->conf.blk) {
186
187 dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
188 ret = blk_attach_dev(dev->conf.blk, qdev);
189 assert(ret == 0);
190 }
191
192 blkconf_blocksizes(&dev->conf);
193 if (dev->conf.logical_block_size != 512 ||
194 dev->conf.physical_block_size != 512)
195 {
196 error_setg(errp, "Physical and logical block size must "
197 "be 512 for floppy");
198 return;
199 }
200
201
202
203
204
205
206 dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
207 dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
208
209 if (!blkconf_apply_backend_options(&dev->conf,
210 blk_is_read_only(dev->conf.blk),
211 false, errp)) {
212 return;
213 }
214
215
216
217
218
219 if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
220 blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
221 error_setg(errp, "fdc doesn't support drive option werror");
222 return;
223 }
224 if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
225 error_setg(errp, "fdc doesn't support drive option rerror");
226 return;
227 }
228
229 drive->conf = &dev->conf;
230 drive->blk = dev->conf.blk;
231 drive->swimctrl = bus->ctrl;
232
233 blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
234}
235
236static void swim_drive_class_init(ObjectClass *klass, void *data)
237{
238 DeviceClass *k = DEVICE_CLASS(klass);
239 k->realize = swim_drive_realize;
240 set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
241 k->bus_type = TYPE_SWIM_BUS;
242 device_class_set_props(k, swim_drive_properties);
243 k->desc = "virtual SWIM drive";
244}
245
246static const TypeInfo swim_drive_info = {
247 .name = TYPE_SWIM_DRIVE,
248 .parent = TYPE_DEVICE,
249 .instance_size = sizeof(SWIMDrive),
250 .class_init = swim_drive_class_init,
251};
252
253static const TypeInfo swim_bus_info = {
254 .name = TYPE_SWIM_BUS,
255 .parent = TYPE_BUS,
256 .instance_size = sizeof(SWIMBus),
257};
258
259static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
260 unsigned size)
261{
262 SWIMCtrl *swimctrl = opaque;
263
264 reg >>= REG_SHIFT;
265
266 swimctrl->regs[reg >> 1] = reg & 1;
267
268 if (swimctrl->regs[IWM_Q6] &&
269 swimctrl->regs[IWM_Q7]) {
270 if (swimctrl->regs[IWM_MTR]) {
271
272 swimctrl->iwm_data = value;
273 } else {
274
275 swimctrl->iwm_mode = value;
276
277 switch (swimctrl->iwm_switch) {
278 case 0:
279 if (value == 0x57) {
280 swimctrl->iwm_switch++;
281 }
282 break;
283 case 1:
284 if (value == 0x17) {
285 swimctrl->iwm_switch++;
286 }
287 break;
288 case 2:
289 if (value == 0x57) {
290 swimctrl->iwm_switch++;
291 }
292 break;
293 case 3:
294 if (value == 0x57) {
295 swimctrl->mode = SWIM_MODE_SWIM;
296 swimctrl->iwm_switch = 0;
297 }
298 break;
299 }
300 }
301 }
302}
303
304static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
305{
306 SWIMCtrl *swimctrl = opaque;
307
308 reg >>= REG_SHIFT;
309
310 swimctrl->regs[reg >> 1] = reg & 1;
311
312 return 0;
313}
314
315static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
316 unsigned size)
317{
318 SWIMCtrl *swimctrl = opaque;
319
320 if (swimctrl->mode == SWIM_MODE_IWM) {
321 iwmctrl_write(opaque, reg, value, size);
322 return;
323 }
324
325 reg >>= REG_SHIFT;
326
327 switch (reg) {
328 case SWIM_WRITE_PHASE:
329 swimctrl->swim_phase = value;
330 break;
331 case SWIM_WRITE_MODE0:
332 swimctrl->swim_mode &= ~value;
333 break;
334 case SWIM_WRITE_MODE1:
335 swimctrl->swim_mode |= value;
336 break;
337 case SWIM_WRITE_DATA:
338 case SWIM_WRITE_MARK:
339 case SWIM_WRITE_CRC:
340 case SWIM_WRITE_PARAMETER:
341 case SWIM_WRITE_SETUP:
342 break;
343 }
344}
345
346static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
347{
348 SWIMCtrl *swimctrl = opaque;
349 uint32_t value = 0;
350
351 if (swimctrl->mode == SWIM_MODE_IWM) {
352 return iwmctrl_read(opaque, reg, size);
353 }
354
355 reg >>= REG_SHIFT;
356
357 switch (reg) {
358 case SWIM_READ_PHASE:
359 value = swimctrl->swim_phase;
360 break;
361 case SWIM_READ_HANDSHAKE:
362 if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
363
364 value = SWIM_SENSE;
365 }
366 break;
367 case SWIM_READ_DATA:
368 case SWIM_READ_MARK:
369 case SWIM_READ_ERROR:
370 case SWIM_READ_PARAMETER:
371 case SWIM_READ_SETUP:
372 case SWIM_READ_STATUS:
373 break;
374 }
375
376 return value;
377}
378
379static const MemoryRegionOps swimctrl_mem_ops = {
380 .write = swimctrl_write,
381 .read = swimctrl_read,
382 .endianness = DEVICE_NATIVE_ENDIAN,
383};
384
385static void sysbus_swim_reset(DeviceState *d)
386{
387 SWIM *sys = SWIM(d);
388 SWIMCtrl *ctrl = &sys->ctrl;
389 int i;
390
391 ctrl->mode = 0;
392 ctrl->iwm_switch = 0;
393 for (i = 0; i < 8; i++) {
394 ctrl->regs[i] = 0;
395 }
396 ctrl->iwm_data = 0;
397 ctrl->iwm_mode = 0;
398 ctrl->swim_phase = 0;
399 ctrl->swim_mode = 0;
400 for (i = 0; i < SWIM_MAX_FD; i++) {
401 fd_recalibrate(&ctrl->drives[i]);
402 }
403}
404
405static void sysbus_swim_init(Object *obj)
406{
407 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
408 SWIM *sbs = SWIM(obj);
409 SWIMCtrl *swimctrl = &sbs->ctrl;
410
411 memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
412 "swim", 0x2000);
413 sysbus_init_mmio(sbd, &swimctrl->iomem);
414}
415
416static void sysbus_swim_realize(DeviceState *dev, Error **errp)
417{
418 SWIM *sys = SWIM(dev);
419 SWIMCtrl *swimctrl = &sys->ctrl;
420
421 qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev,
422 NULL);
423 swimctrl->bus.ctrl = swimctrl;
424}
425
426static const VMStateDescription vmstate_fdrive = {
427 .name = "fdrive",
428 .version_id = 1,
429 .minimum_version_id = 1,
430 .fields = (VMStateField[]) {
431 VMSTATE_END_OF_LIST()
432 },
433};
434
435static const VMStateDescription vmstate_swim = {
436 .name = "swim",
437 .version_id = 1,
438 .minimum_version_id = 1,
439 .fields = (VMStateField[]) {
440 VMSTATE_INT32(mode, SWIMCtrl),
441
442 VMSTATE_INT32(iwm_switch, SWIMCtrl),
443 VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8),
444 VMSTATE_UINT8(iwm_data, SWIMCtrl),
445 VMSTATE_UINT8(iwm_mode, SWIMCtrl),
446
447 VMSTATE_UINT8(swim_phase, SWIMCtrl),
448 VMSTATE_UINT8(swim_mode, SWIMCtrl),
449
450 VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
451 vmstate_fdrive, FDrive),
452 VMSTATE_END_OF_LIST()
453 },
454};
455
456static const VMStateDescription vmstate_sysbus_swim = {
457 .name = "SWIM",
458 .version_id = 1,
459 .fields = (VMStateField[]) {
460 VMSTATE_STRUCT(ctrl, SWIM, 0, vmstate_swim, SWIMCtrl),
461 VMSTATE_END_OF_LIST()
462 }
463};
464
465static void sysbus_swim_class_init(ObjectClass *oc, void *data)
466{
467 DeviceClass *dc = DEVICE_CLASS(oc);
468
469 dc->realize = sysbus_swim_realize;
470 dc->reset = sysbus_swim_reset;
471 dc->vmsd = &vmstate_sysbus_swim;
472}
473
474static const TypeInfo sysbus_swim_info = {
475 .name = TYPE_SWIM,
476 .parent = TYPE_SYS_BUS_DEVICE,
477 .instance_size = sizeof(SWIM),
478 .instance_init = sysbus_swim_init,
479 .class_init = sysbus_swim_class_init,
480};
481
482static void swim_register_types(void)
483{
484 type_register_static(&sysbus_swim_info);
485 type_register_static(&swim_bus_info);
486 type_register_static(&swim_drive_info);
487}
488
489type_init(swim_register_types)
490