e5f46d086e5161bcda49f8fa57497410539ab095
[qemu] / hw / fdc.c
1 /*
2  * QEMU Floppy disk emulator (Intel 82078)
3  *
4  * Copyright (c) 2003, 2007 Jocelyn Mayer
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 /*
25  * The controller is used in Sun4m systems in a slightly different
26  * way. There are changes in DOR register and DMA is not available.
27  */
28 #include "hw.h"
29 #include "fdc.h"
30 #include "block.h"
31 #include "qemu-timer.h"
32 #include "isa.h"
33
34 /********************************************************/
35 /* debug Floppy devices */
36 //#define DEBUG_FLOPPY
37
38 #ifdef DEBUG_FLOPPY
39 #define FLOPPY_DPRINTF(fmt, args...) \
40 do { printf("FLOPPY: " fmt , ##args); } while (0)
41 #else
42 #define FLOPPY_DPRINTF(fmt, args...)
43 #endif
44
45 #define FLOPPY_ERROR(fmt, args...) \
46 do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
47
48 /********************************************************/
49 /* Floppy drive emulation                               */
50
51 /* Will always be a fixed parameter for us */
52 #define FD_SECTOR_LEN 512
53 #define FD_SECTOR_SC  2   /* Sector size code */
54
55 /* Floppy disk drive emulation */
56 typedef enum fdisk_type_t {
57     FDRIVE_DISK_288   = 0x01, /* 2.88 MB disk           */
58     FDRIVE_DISK_144   = 0x02, /* 1.44 MB disk           */
59     FDRIVE_DISK_720   = 0x03, /* 720 kB disk            */
60     FDRIVE_DISK_USER  = 0x04, /* User defined geometry  */
61     FDRIVE_DISK_NONE  = 0x05, /* No disk                */
62 } fdisk_type_t;
63
64 typedef enum fdrive_type_t {
65     FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
66     FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
67     FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
68     FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
69 } fdrive_type_t;
70
71 typedef enum fdrive_flags_t {
72     FDRIVE_MOTOR_ON   = 0x01, /* motor on/off           */
73 } fdrive_flags_t;
74
75 typedef enum fdisk_flags_t {
76     FDISK_DBL_SIDES  = 0x01,
77 } fdisk_flags_t;
78
79 typedef struct fdrive_t {
80     BlockDriverState *bs;
81     /* Drive status */
82     fdrive_type_t drive;
83     fdrive_flags_t drflags;
84     uint8_t perpendicular;    /* 2.88 MB access mode    */
85     /* Position */
86     uint8_t head;
87     uint8_t track;
88     uint8_t sect;
89     /* Last operation status */
90     uint8_t dir;              /* Direction              */
91     uint8_t rw;               /* Read/write             */
92     /* Media */
93     fdisk_flags_t flags;
94     uint8_t last_sect;        /* Nb sector per track    */
95     uint8_t max_track;        /* Nb of tracks           */
96     uint16_t bps;             /* Bytes per sector       */
97     uint8_t ro;               /* Is read-only           */
98 } fdrive_t;
99
100 static void fd_init (fdrive_t *drv, BlockDriverState *bs)
101 {
102     /* Drive */
103     drv->bs = bs;
104     drv->drive = FDRIVE_DRV_NONE;
105     drv->drflags = 0;
106     drv->perpendicular = 0;
107     /* Disk */
108     drv->last_sect = 0;
109     drv->max_track = 0;
110 }
111
112 static int _fd_sector (uint8_t head, uint8_t track,
113                        uint8_t sect, uint8_t last_sect)
114 {
115     return (((track * 2) + head) * last_sect) + sect - 1;
116 }
117
118 /* Returns current position, in sectors, for given drive */
119 static int fd_sector (fdrive_t *drv)
120 {
121     return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
122 }
123
124 static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
125                     int enable_seek)
126 {
127     uint32_t sector;
128     int ret;
129
130     if (track > drv->max_track ||
131         (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
132         FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
133                        head, track, sect, 1,
134                        (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
135                        drv->max_track, drv->last_sect);
136         return 2;
137     }
138     if (sect > drv->last_sect) {
139         FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
140                        head, track, sect, 1,
141                        (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
142                        drv->max_track, drv->last_sect);
143         return 3;
144     }
145     sector = _fd_sector(head, track, sect, drv->last_sect);
146     ret = 0;
147     if (sector != fd_sector(drv)) {
148 #if 0
149         if (!enable_seek) {
150             FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
151                          head, track, sect, 1, drv->max_track, drv->last_sect);
152             return 4;
153         }
154 #endif
155         drv->head = head;
156         if (drv->track != track)
157             ret = 1;
158         drv->track = track;
159         drv->sect = sect;
160     }
161
162     return ret;
163 }
164
165 /* Set drive back to track 0 */
166 static void fd_recalibrate (fdrive_t *drv)
167 {
168     FLOPPY_DPRINTF("recalibrate\n");
169     drv->head = 0;
170     drv->track = 0;
171     drv->sect = 1;
172     drv->dir = 1;
173     drv->rw = 0;
174 }
175
176 /* Recognize floppy formats */
177 typedef struct fd_format_t {
178     fdrive_type_t drive;
179     fdisk_type_t  disk;
180     uint8_t last_sect;
181     uint8_t max_track;
182     uint8_t max_head;
183     const char *str;
184 } fd_format_t;
185
186 static const fd_format_t fd_formats[] = {
187     /* First entry is default format */
188     /* 1.44 MB 3"1/2 floppy disks */
189     { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
190     { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1,  "1.6 MB 3\"1/2", },
191     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
192     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
193     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
194     { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
195     { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
196     { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
197     /* 2.88 MB 3"1/2 floppy disks */
198     { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
199     { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
200     { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1,  "3.2 MB 3\"1/2", },
201     { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
202     { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
203     /* 720 kB 3"1/2 floppy disks */
204     { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 1,  "720 kB 3\"1/2", },
205     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1,  "800 kB 3\"1/2", },
206     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1,  "820 kB 3\"1/2", },
207     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1,  "830 kB 3\"1/2", },
208     { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
209     { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
210     /* 1.2 MB 5"1/4 floppy disks */
211     { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1,  "1.2 kB 5\"1/4", },
212     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
213     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
214     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
215     { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1,  "1.6 MB 5\"1/4", },
216     /* 720 kB 5"1/4 floppy disks */
217     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 80, 1,  "720 kB 5\"1/4", },
218     { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1,  "880 kB 5\"1/4", },
219     /* 360 kB 5"1/4 floppy disks */
220     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 1,  "360 kB 5\"1/4", },
221     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 0,  "180 kB 5\"1/4", },
222     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1,  "410 kB 5\"1/4", },
223     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1,  "420 kB 5\"1/4", },
224     /* 320 kB 5"1/4 floppy disks */
225     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 1,  "320 kB 5\"1/4", },
226     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 0,  "160 kB 5\"1/4", },
227     /* 360 kB must match 5"1/4 better than 3"1/2... */
228     { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 0,  "360 kB 3\"1/2", },
229     /* end */
230     { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
231 };
232
233 /* Revalidate a disk drive after a disk change */
234 static void fd_revalidate (fdrive_t *drv)
235 {
236     const fd_format_t *parse;
237     uint64_t nb_sectors, size;
238     int i, first_match, match;
239     int nb_heads, max_track, last_sect, ro;
240
241     FLOPPY_DPRINTF("revalidate\n");
242     if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
243         ro = bdrv_is_read_only(drv->bs);
244         bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
245         if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
246             FLOPPY_DPRINTF("User defined disk (%d %d %d)",
247                            nb_heads - 1, max_track, last_sect);
248         } else {
249             bdrv_get_geometry(drv->bs, &nb_sectors);
250             match = -1;
251             first_match = -1;
252             for (i = 0;; i++) {
253                 parse = &fd_formats[i];
254                 if (parse->drive == FDRIVE_DRV_NONE)
255                     break;
256                 if (drv->drive == parse->drive ||
257                     drv->drive == FDRIVE_DRV_NONE) {
258                     size = (parse->max_head + 1) * parse->max_track *
259                         parse->last_sect;
260                     if (nb_sectors == size) {
261                         match = i;
262                         break;
263                     }
264                     if (first_match == -1)
265                         first_match = i;
266                 }
267             }
268             if (match == -1) {
269                 if (first_match == -1)
270                     match = 1;
271                 else
272                     match = first_match;
273                 parse = &fd_formats[match];
274             }
275             nb_heads = parse->max_head + 1;
276             max_track = parse->max_track;
277             last_sect = parse->last_sect;
278             drv->drive = parse->drive;
279             FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
280                            nb_heads, max_track, last_sect, ro ? "ro" : "rw");
281         }
282         if (nb_heads == 1) {
283             drv->flags &= ~FDISK_DBL_SIDES;
284         } else {
285             drv->flags |= FDISK_DBL_SIDES;
286         }
287         drv->max_track = max_track;
288         drv->last_sect = last_sect;
289         drv->ro = ro;
290     } else {
291         FLOPPY_DPRINTF("No disk in drive\n");
292         drv->last_sect = 0;
293         drv->max_track = 0;
294         drv->flags &= ~FDISK_DBL_SIDES;
295     }
296 }
297
298 /* Motor control */
299 static void fd_start (fdrive_t *drv)
300 {
301     drv->drflags |= FDRIVE_MOTOR_ON;
302 }
303
304 static void fd_stop (fdrive_t *drv)
305 {
306     drv->drflags &= ~FDRIVE_MOTOR_ON;
307 }
308
309 /* Re-initialise a drives (motor off, repositioned) */
310 static void fd_reset (fdrive_t *drv)
311 {
312     fd_stop(drv);
313     fd_recalibrate(drv);
314 }
315
316 /********************************************************/
317 /* Intel 82078 floppy disk controller emulation          */
318
319 static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
320 static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
321 static int fdctrl_transfer_handler (void *opaque, int nchan,
322                                     int dma_pos, int dma_len);
323 static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
324 static void fdctrl_result_timer(void *opaque);
325
326 static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
327 static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
328 static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
329 static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
330 static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
331 static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
332 static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
333 static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
334 static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
335 static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
336
337 enum {
338     FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
339     FD_CTRL_RESET  = 0x02,
340     FD_CTRL_SLEEP  = 0x04, /* XXX: suppress that */
341     FD_CTRL_BUSY   = 0x08, /* dma transfer in progress */
342     FD_CTRL_INTR   = 0x10,
343 };
344
345 enum {
346     FD_DIR_WRITE   = 0,
347     FD_DIR_READ    = 1,
348     FD_DIR_SCANE   = 2,
349     FD_DIR_SCANL   = 3,
350     FD_DIR_SCANH   = 4,
351 };
352
353 enum {
354     FD_STATE_CMD    = 0x00,
355     FD_STATE_STATUS = 0x01,
356     FD_STATE_DATA   = 0x02,
357     FD_STATE_STATE  = 0x03,
358     FD_STATE_MULTI  = 0x10,
359     FD_STATE_SEEK   = 0x20,
360     FD_STATE_FORMAT = 0x40,
361 };
362
363 #define FD_STATE(state) ((state) & FD_STATE_STATE)
364 #define FD_SET_STATE(state, new_state) \
365 do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
366 #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
367 #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
368 #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
369
370 struct fdctrl_t {
371     fdctrl_t *fdctrl;
372     /* Controller's identification */
373     uint8_t version;
374     /* HW */
375     qemu_irq irq;
376     int dma_chann;
377     target_phys_addr_t io_base;
378     /* Controller state */
379     QEMUTimer *result_timer;
380     uint8_t state;
381     uint8_t dma_en;
382     uint8_t cur_drv;
383     uint8_t bootsel;
384     /* Command FIFO */
385     uint8_t fifo[FD_SECTOR_LEN];
386     uint32_t data_pos;
387     uint32_t data_len;
388     uint8_t data_state;
389     uint8_t data_dir;
390     uint8_t int_status;
391     uint8_t eot; /* last wanted sector */
392     /* States kept only to be returned back */
393     /* Timers state */
394     uint8_t timer0;
395     uint8_t timer1;
396     /* precompensation */
397     uint8_t precomp_trk;
398     uint8_t config;
399     uint8_t lock;
400     /* Power down config (also with status regB access mode */
401     uint8_t pwrd;
402     /* Sun4m quirks? */
403     int sun4m;
404     /* Floppy drives */
405     fdrive_t drives[2];
406 };
407
408 static uint32_t fdctrl_read (void *opaque, uint32_t reg)
409 {
410     fdctrl_t *fdctrl = opaque;
411     uint32_t retval;
412
413     switch (reg & 0x07) {
414     case 0x00:
415         if (fdctrl->sun4m) {
416             // Identify to Linux as S82078B
417             retval = fdctrl_read_statusB(fdctrl);
418         } else {
419             retval = (uint32_t)(-1);
420         }
421         break;
422     case 0x01:
423         retval = fdctrl_read_statusB(fdctrl);
424         break;
425     case 0x02:
426         retval = fdctrl_read_dor(fdctrl);
427         break;
428     case 0x03:
429         retval = fdctrl_read_tape(fdctrl);
430         break;
431     case 0x04:
432         retval = fdctrl_read_main_status(fdctrl);
433         break;
434     case 0x05:
435         retval = fdctrl_read_data(fdctrl);
436         break;
437     case 0x07:
438         retval = fdctrl_read_dir(fdctrl);
439         break;
440     default:
441         retval = (uint32_t)(-1);
442         break;
443     }
444     FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
445
446     return retval;
447 }
448
449 static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
450 {
451     fdctrl_t *fdctrl = opaque;
452
453     FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
454
455     switch (reg & 0x07) {
456     case 0x02:
457         fdctrl_write_dor(fdctrl, value);
458         break;
459     case 0x03:
460         fdctrl_write_tape(fdctrl, value);
461         break;
462     case 0x04:
463         fdctrl_write_rate(fdctrl, value);
464         break;
465     case 0x05:
466         fdctrl_write_data(fdctrl, value);
467         break;
468     default:
469         break;
470     }
471 }
472
473 static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
474 {
475     return fdctrl_read(opaque, (uint32_t)reg);
476 }
477
478 static void fdctrl_write_mem (void *opaque,
479                               target_phys_addr_t reg, uint32_t value)
480 {
481     fdctrl_write(opaque, (uint32_t)reg, value);
482 }
483
484 static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
485     fdctrl_read_mem,
486     fdctrl_read_mem,
487     fdctrl_read_mem,
488 };
489
490 static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
491     fdctrl_write_mem,
492     fdctrl_write_mem,
493     fdctrl_write_mem,
494 };
495
496 static void fd_save (QEMUFile *f, fdrive_t *fd)
497 {
498     uint8_t tmp;
499
500     tmp = fd->drflags;
501     qemu_put_8s(f, &tmp);
502     qemu_put_8s(f, &fd->head);
503     qemu_put_8s(f, &fd->track);
504     qemu_put_8s(f, &fd->sect);
505     qemu_put_8s(f, &fd->dir);
506     qemu_put_8s(f, &fd->rw);
507 }
508
509 static void fdc_save (QEMUFile *f, void *opaque)
510 {
511     fdctrl_t *s = opaque;
512
513     qemu_put_8s(f, &s->state);
514     qemu_put_8s(f, &s->dma_en);
515     qemu_put_8s(f, &s->cur_drv);
516     qemu_put_8s(f, &s->bootsel);
517     qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
518     qemu_put_be32s(f, &s->data_pos);
519     qemu_put_be32s(f, &s->data_len);
520     qemu_put_8s(f, &s->data_state);
521     qemu_put_8s(f, &s->data_dir);
522     qemu_put_8s(f, &s->int_status);
523     qemu_put_8s(f, &s->eot);
524     qemu_put_8s(f, &s->timer0);
525     qemu_put_8s(f, &s->timer1);
526     qemu_put_8s(f, &s->precomp_trk);
527     qemu_put_8s(f, &s->config);
528     qemu_put_8s(f, &s->lock);
529     qemu_put_8s(f, &s->pwrd);
530     fd_save(f, &s->drives[0]);
531     fd_save(f, &s->drives[1]);
532 }
533
534 static int fd_load (QEMUFile *f, fdrive_t *fd)
535 {
536     uint8_t tmp;
537
538     qemu_get_8s(f, &tmp);
539     fd->drflags = tmp;
540     qemu_get_8s(f, &fd->head);
541     qemu_get_8s(f, &fd->track);
542     qemu_get_8s(f, &fd->sect);
543     qemu_get_8s(f, &fd->dir);
544     qemu_get_8s(f, &fd->rw);
545
546     return 0;
547 }
548
549 static int fdc_load (QEMUFile *f, void *opaque, int version_id)
550 {
551     fdctrl_t *s = opaque;
552     int ret;
553
554     if (version_id != 1)
555         return -EINVAL;
556
557     qemu_get_8s(f, &s->state);
558     qemu_get_8s(f, &s->dma_en);
559     qemu_get_8s(f, &s->cur_drv);
560     qemu_get_8s(f, &s->bootsel);
561     qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN);
562     qemu_get_be32s(f, &s->data_pos);
563     qemu_get_be32s(f, &s->data_len);
564     qemu_get_8s(f, &s->data_state);
565     qemu_get_8s(f, &s->data_dir);
566     qemu_get_8s(f, &s->int_status);
567     qemu_get_8s(f, &s->eot);
568     qemu_get_8s(f, &s->timer0);
569     qemu_get_8s(f, &s->timer1);
570     qemu_get_8s(f, &s->precomp_trk);
571     qemu_get_8s(f, &s->config);
572     qemu_get_8s(f, &s->lock);
573     qemu_get_8s(f, &s->pwrd);
574
575     ret = fd_load(f, &s->drives[0]);
576     if (ret == 0)
577         ret = fd_load(f, &s->drives[1]);
578
579     return ret;
580 }
581
582 static void fdctrl_external_reset(void *opaque)
583 {
584     fdctrl_t *s = opaque;
585
586     fdctrl_reset(s, 0);
587 }
588
589 fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
590                        target_phys_addr_t io_base,
591                        BlockDriverState **fds)
592 {
593     fdctrl_t *fdctrl;
594     int io_mem;
595     int i;
596
597     FLOPPY_DPRINTF("init controller\n");
598     fdctrl = qemu_mallocz(sizeof(fdctrl_t));
599     if (!fdctrl)
600         return NULL;
601     fdctrl->result_timer = qemu_new_timer(vm_clock,
602                                           fdctrl_result_timer, fdctrl);
603
604     fdctrl->version = 0x90; /* Intel 82078 controller */
605     fdctrl->irq = irq;
606     fdctrl->dma_chann = dma_chann;
607     fdctrl->io_base = io_base;
608     fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
609     fdctrl->sun4m = 0;
610     if (fdctrl->dma_chann != -1) {
611         fdctrl->dma_en = 1;
612         DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
613     } else {
614         fdctrl->dma_en = 0;
615     }
616     for (i = 0; i < 2; i++) {
617         fd_init(&fdctrl->drives[i], fds[i]);
618     }
619     fdctrl_reset(fdctrl, 0);
620     fdctrl->state = FD_CTRL_ACTIVE;
621     if (mem_mapped) {
622         io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write,
623                                         fdctrl);
624         cpu_register_physical_memory(io_base, 0x08, io_mem);
625     } else {
626         register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
627                              fdctrl);
628         register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
629                              fdctrl);
630         register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
631                               fdctrl);
632         register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
633                               fdctrl);
634     }
635     register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
636     qemu_register_reset(fdctrl_external_reset, fdctrl);
637     for (i = 0; i < 2; i++) {
638         fd_revalidate(&fdctrl->drives[i]);
639     }
640
641     return fdctrl;
642 }
643
644 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
645                              BlockDriverState **fds)
646 {
647     fdctrl_t *fdctrl;
648
649     fdctrl = fdctrl_init(irq, 0, 1, io_base, fds);
650     fdctrl->sun4m = 1;
651
652     return fdctrl;
653 }
654
655 /* XXX: may change if moved to bdrv */
656 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
657 {
658     return fdctrl->drives[drive_num].drive;
659 }
660
661 /* Change IRQ state */
662 static void fdctrl_reset_irq (fdctrl_t *fdctrl)
663 {
664     FLOPPY_DPRINTF("Reset interrupt\n");
665     qemu_set_irq(fdctrl->irq, 0);
666     fdctrl->state &= ~FD_CTRL_INTR;
667 }
668
669 static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
670 {
671     // Sparc mutation
672     if (fdctrl->sun4m && !fdctrl->dma_en) {
673         fdctrl->state &= ~FD_CTRL_BUSY;
674         fdctrl->int_status = status;
675         return;
676     }
677     if (~(fdctrl->state & FD_CTRL_INTR)) {
678         qemu_set_irq(fdctrl->irq, 1);
679         fdctrl->state |= FD_CTRL_INTR;
680     }
681     FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
682     fdctrl->int_status = status;
683 }
684
685 /* Reset controller */
686 static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
687 {
688     int i;
689
690     FLOPPY_DPRINTF("reset controller\n");
691     fdctrl_reset_irq(fdctrl);
692     /* Initialise controller */
693     fdctrl->cur_drv = 0;
694     /* FIFO state */
695     fdctrl->data_pos = 0;
696     fdctrl->data_len = 0;
697     fdctrl->data_state = FD_STATE_CMD;
698     fdctrl->data_dir = FD_DIR_WRITE;
699     for (i = 0; i < MAX_FD; i++)
700         fd_reset(&fdctrl->drives[i]);
701     fdctrl_reset_fifo(fdctrl);
702     if (do_irq)
703         fdctrl_raise_irq(fdctrl, 0xc0);
704 }
705
706 static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
707 {
708     return &fdctrl->drives[fdctrl->bootsel];
709 }
710
711 static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
712 {
713     return &fdctrl->drives[1 - fdctrl->bootsel];
714 }
715
716 static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
717 {
718     return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
719 }
720
721 /* Status B register : 0x01 (read-only) */
722 static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
723 {
724     FLOPPY_DPRINTF("status register: 0x00\n");
725     return 0;
726 }
727
728 /* Digital output register : 0x02 */
729 static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
730 {
731     uint32_t retval = 0;
732
733     /* Drive motors state indicators */
734     if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
735         retval |= 1 << 5;
736     if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
737         retval |= 1 << 4;
738     /* DMA enable */
739     retval |= fdctrl->dma_en << 3;
740     /* Reset indicator */
741     retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
742     /* Selected drive */
743     retval |= fdctrl->cur_drv;
744     FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
745
746     return retval;
747 }
748
749 static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
750 {
751     /* Reset mode */
752     if (fdctrl->state & FD_CTRL_RESET) {
753         if (!(value & 0x04)) {
754             FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
755             return;
756         }
757     }
758     FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
759     /* Drive motors state indicators */
760     if (value & 0x20)
761         fd_start(drv1(fdctrl));
762     else
763         fd_stop(drv1(fdctrl));
764     if (value & 0x10)
765         fd_start(drv0(fdctrl));
766     else
767         fd_stop(drv0(fdctrl));
768     /* DMA enable */
769 #if 0
770     if (fdctrl->dma_chann != -1)
771         fdctrl->dma_en = 1 - ((value >> 3) & 1);
772 #endif
773     /* Reset */
774     if (!(value & 0x04)) {
775         if (!(fdctrl->state & FD_CTRL_RESET)) {
776             FLOPPY_DPRINTF("controller enter RESET state\n");
777             fdctrl->state |= FD_CTRL_RESET;
778         }
779     } else {
780         if (fdctrl->state & FD_CTRL_RESET) {
781             FLOPPY_DPRINTF("controller out of RESET state\n");
782             fdctrl_reset(fdctrl, 1);
783             fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
784         }
785     }
786     /* Selected drive */
787     fdctrl->cur_drv = value & 1;
788 }
789
790 /* Tape drive register : 0x03 */
791 static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
792 {
793     uint32_t retval = 0;
794
795     /* Disk boot selection indicator */
796     retval |= fdctrl->bootsel << 2;
797     /* Tape indicators: never allowed */
798     FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
799
800     return retval;
801 }
802
803 static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
804 {
805     /* Reset mode */
806     if (fdctrl->state & FD_CTRL_RESET) {
807         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
808         return;
809     }
810     FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
811     /* Disk boot selection indicator */
812     fdctrl->bootsel = (value >> 2) & 1;
813     /* Tape indicators: never allow */
814 }
815
816 /* Main status register : 0x04 (read) */
817 static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
818 {
819     uint32_t retval = 0;
820
821     fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
822     if (!(fdctrl->state & FD_CTRL_BUSY)) {
823         /* Data transfer allowed */
824         retval |= 0x80;
825         /* Data transfer direction indicator */
826         if (fdctrl->data_dir == FD_DIR_READ)
827             retval |= 0x40;
828     }
829     /* Should handle 0x20 for SPECIFY command */
830     /* Command busy indicator */
831     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
832         FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
833         retval |= 0x10;
834     FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
835
836     return retval;
837 }
838
839 /* Data select rate register : 0x04 (write) */
840 static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
841 {
842     /* Reset mode */
843     if (fdctrl->state & FD_CTRL_RESET) {
844         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
845         return;
846     }
847     FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
848     /* Reset: autoclear */
849     if (value & 0x80) {
850         fdctrl->state |= FD_CTRL_RESET;
851         fdctrl_reset(fdctrl, 1);
852         fdctrl->state &= ~FD_CTRL_RESET;
853     }
854     if (value & 0x40) {
855         fdctrl->state |= FD_CTRL_SLEEP;
856         fdctrl_reset(fdctrl, 1);
857     }
858 //        fdctrl.precomp = (value >> 2) & 0x07;
859 }
860
861 static int fdctrl_media_changed(fdrive_t *drv)
862 {
863     int ret;
864
865     if (!drv->bs)
866         return 0;
867     ret = bdrv_media_changed(drv->bs);
868     if (ret) {
869         fd_revalidate(drv);
870     }
871     return ret;
872 }
873
874 /* Digital input register : 0x07 (read-only) */
875 static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
876 {
877     uint32_t retval = 0;
878
879     if (fdctrl_media_changed(drv0(fdctrl)) ||
880         fdctrl_media_changed(drv1(fdctrl)))
881         retval |= 0x80;
882     if (retval != 0)
883         FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
884
885     return retval;
886 }
887
888 /* FIFO state control */
889 static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
890 {
891     fdctrl->data_dir = FD_DIR_WRITE;
892     fdctrl->data_pos = 0;
893     FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
894 }
895
896 /* Set FIFO status for the host to read */
897 static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
898 {
899     fdctrl->data_dir = FD_DIR_READ;
900     fdctrl->data_len = fifo_len;
901     fdctrl->data_pos = 0;
902     FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
903     if (do_irq)
904         fdctrl_raise_irq(fdctrl, 0x00);
905 }
906
907 /* Set an error: unimplemented/unknown command */
908 static void fdctrl_unimplemented (fdctrl_t *fdctrl)
909 {
910 #if 0
911     fdrive_t *cur_drv;
912
913     cur_drv = get_cur_drv(fdctrl);
914     fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
915     fdctrl->fifo[1] = 0x00;
916     fdctrl->fifo[2] = 0x00;
917     fdctrl_set_fifo(fdctrl, 3, 1);
918 #else
919     //    fdctrl_reset_fifo(fdctrl);
920     fdctrl->fifo[0] = 0x80;
921     fdctrl_set_fifo(fdctrl, 1, 0);
922 #endif
923 }
924
925 /* Callback for transfer end (stop or abort) */
926 static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
927                                   uint8_t status1, uint8_t status2)
928 {
929     fdrive_t *cur_drv;
930
931     cur_drv = get_cur_drv(fdctrl);
932     FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
933                    status0, status1, status2,
934                    status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
935     fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
936     fdctrl->fifo[1] = status1;
937     fdctrl->fifo[2] = status2;
938     fdctrl->fifo[3] = cur_drv->track;
939     fdctrl->fifo[4] = cur_drv->head;
940     fdctrl->fifo[5] = cur_drv->sect;
941     fdctrl->fifo[6] = FD_SECTOR_SC;
942     fdctrl->data_dir = FD_DIR_READ;
943     if (fdctrl->state & FD_CTRL_BUSY) {
944         DMA_release_DREQ(fdctrl->dma_chann);
945         fdctrl->state &= ~FD_CTRL_BUSY;
946     }
947     fdctrl_set_fifo(fdctrl, 7, 1);
948 }
949
950 /* Prepare a data transfer (either DMA or FIFO) */
951 static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
952 {
953     fdrive_t *cur_drv;
954     uint8_t kh, kt, ks;
955     int did_seek;
956
957     fdctrl->cur_drv = fdctrl->fifo[1] & 1;
958     cur_drv = get_cur_drv(fdctrl);
959     kt = fdctrl->fifo[2];
960     kh = fdctrl->fifo[3];
961     ks = fdctrl->fifo[4];
962     FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
963                    fdctrl->cur_drv, kh, kt, ks,
964                    _fd_sector(kh, kt, ks, cur_drv->last_sect));
965     did_seek = 0;
966     switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
967     case 2:
968         /* sect too big */
969         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
970         fdctrl->fifo[3] = kt;
971         fdctrl->fifo[4] = kh;
972         fdctrl->fifo[5] = ks;
973         return;
974     case 3:
975         /* track too big */
976         fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
977         fdctrl->fifo[3] = kt;
978         fdctrl->fifo[4] = kh;
979         fdctrl->fifo[5] = ks;
980         return;
981     case 4:
982         /* No seek enabled */
983         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
984         fdctrl->fifo[3] = kt;
985         fdctrl->fifo[4] = kh;
986         fdctrl->fifo[5] = ks;
987         return;
988     case 1:
989         did_seek = 1;
990         break;
991     default:
992         break;
993     }
994     /* Set the FIFO state */
995     fdctrl->data_dir = direction;
996     fdctrl->data_pos = 0;
997     FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
998     if (fdctrl->fifo[0] & 0x80)
999         fdctrl->data_state |= FD_STATE_MULTI;
1000     else
1001         fdctrl->data_state &= ~FD_STATE_MULTI;
1002     if (did_seek)
1003         fdctrl->data_state |= FD_STATE_SEEK;
1004     else
1005         fdctrl->data_state &= ~FD_STATE_SEEK;
1006     if (fdctrl->fifo[5] == 00) {
1007         fdctrl->data_len = fdctrl->fifo[8];
1008     } else {
1009         int tmp;
1010         fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1011         tmp = (cur_drv->last_sect - ks + 1);
1012         if (fdctrl->fifo[0] & 0x80)
1013             tmp += cur_drv->last_sect;
1014         fdctrl->data_len *= tmp;
1015     }
1016     fdctrl->eot = fdctrl->fifo[6];
1017     if (fdctrl->dma_en) {
1018         int dma_mode;
1019         /* DMA transfer are enabled. Check if DMA channel is well programmed */
1020         dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
1021         dma_mode = (dma_mode >> 2) & 3;
1022         FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1023                        dma_mode, direction,
1024                        (128 << fdctrl->fifo[5]) *
1025                        (cur_drv->last_sect - ks + 1), fdctrl->data_len);
1026         if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
1027               direction == FD_DIR_SCANH) && dma_mode == 0) ||
1028             (direction == FD_DIR_WRITE && dma_mode == 2) ||
1029             (direction == FD_DIR_READ && dma_mode == 1)) {
1030             /* No access is allowed until DMA transfer has completed */
1031             fdctrl->state |= FD_CTRL_BUSY;
1032             /* Now, we just have to wait for the DMA controller to
1033              * recall us...
1034              */
1035             DMA_hold_DREQ(fdctrl->dma_chann);
1036             DMA_schedule(fdctrl->dma_chann);
1037             return;
1038         } else {
1039             FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
1040         }
1041     }
1042     FLOPPY_DPRINTF("start non-DMA transfer\n");
1043     /* IO based transfer: calculate len */
1044     fdctrl_raise_irq(fdctrl, 0x00);
1045
1046     return;
1047 }
1048
1049 /* Prepare a transfer of deleted data */
1050 static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
1051 {
1052     /* We don't handle deleted data,
1053      * so we don't return *ANYTHING*
1054      */
1055     fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1056 }
1057
1058 /* handlers for DMA transfers */
1059 static int fdctrl_transfer_handler (void *opaque, int nchan,
1060                                     int dma_pos, int dma_len)
1061 {
1062     fdctrl_t *fdctrl;
1063     fdrive_t *cur_drv;
1064     int len, start_pos, rel_pos;
1065     uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1066
1067     fdctrl = opaque;
1068     if (!(fdctrl->state & FD_CTRL_BUSY)) {
1069         FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1070         return 0;
1071     }
1072     cur_drv = get_cur_drv(fdctrl);
1073     if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1074         fdctrl->data_dir == FD_DIR_SCANH)
1075         status2 = 0x04;
1076     if (dma_len > fdctrl->data_len)
1077         dma_len = fdctrl->data_len;
1078     if (cur_drv->bs == NULL) {
1079         if (fdctrl->data_dir == FD_DIR_WRITE)
1080             fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1081         else
1082             fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1083         len = 0;
1084         goto transfer_error;
1085     }
1086     rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1087     for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1088         len = dma_len - fdctrl->data_pos;
1089         if (len + rel_pos > FD_SECTOR_LEN)
1090             len = FD_SECTOR_LEN - rel_pos;
1091         FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1092                        "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
1093                        fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1094                        cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1095                        fd_sector(cur_drv) * 512);
1096         if (fdctrl->data_dir != FD_DIR_WRITE ||
1097             len < FD_SECTOR_LEN || rel_pos != 0) {
1098             /* READ & SCAN commands and realign to a sector for WRITE */
1099             if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1100                           fdctrl->fifo, 1) < 0) {
1101                 FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1102                                fd_sector(cur_drv));
1103                 /* Sure, image size is too small... */
1104                 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1105             }
1106         }
1107         switch (fdctrl->data_dir) {
1108         case FD_DIR_READ:
1109             /* READ commands */
1110             DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
1111                               fdctrl->data_pos, len);
1112             break;
1113         case FD_DIR_WRITE:
1114             /* WRITE commands */
1115             DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
1116                              fdctrl->data_pos, len);
1117             if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1118                            fdctrl->fifo, 1) < 0) {
1119                 FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1120                 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1121                 goto transfer_error;
1122             }
1123             break;
1124         default:
1125             /* SCAN commands */
1126             {
1127                 uint8_t tmpbuf[FD_SECTOR_LEN];
1128                 int ret;
1129                 DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1130                 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1131                 if (ret == 0) {
1132                     status2 = 0x08;
1133                     goto end_transfer;
1134                 }
1135                 if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1136                     (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1137                     status2 = 0x00;
1138                     goto end_transfer;
1139                 }
1140             }
1141             break;
1142         }
1143         fdctrl->data_pos += len;
1144         rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1145         if (rel_pos == 0) {
1146             /* Seek to next sector */
1147             FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1148                            cur_drv->head, cur_drv->track, cur_drv->sect,
1149                            fd_sector(cur_drv),
1150                            fdctrl->data_pos - len);
1151             /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1152                error in fact */
1153             if (cur_drv->sect >= cur_drv->last_sect ||
1154                 cur_drv->sect == fdctrl->eot) {
1155                 cur_drv->sect = 1;
1156                 if (FD_MULTI_TRACK(fdctrl->data_state)) {
1157                     if (cur_drv->head == 0 &&
1158                         (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1159                         cur_drv->head = 1;
1160                     } else {
1161                         cur_drv->head = 0;
1162                         cur_drv->track++;
1163                         if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1164                             break;
1165                     }
1166                 } else {
1167                     cur_drv->track++;
1168                     break;
1169                 }
1170                 FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1171                                cur_drv->head, cur_drv->track,
1172                                cur_drv->sect, fd_sector(cur_drv));
1173             } else {
1174                 cur_drv->sect++;
1175             }
1176         }
1177     }
1178  end_transfer:
1179     len = fdctrl->data_pos - start_pos;
1180     FLOPPY_DPRINTF("end transfer %d %d %d\n",
1181                    fdctrl->data_pos, len, fdctrl->data_len);
1182     if (fdctrl->data_dir == FD_DIR_SCANE ||
1183         fdctrl->data_dir == FD_DIR_SCANL ||
1184         fdctrl->data_dir == FD_DIR_SCANH)
1185         status2 = 0x08;
1186     if (FD_DID_SEEK(fdctrl->data_state))
1187         status0 |= 0x20;
1188     fdctrl->data_len -= len;
1189     //    if (fdctrl->data_len == 0)
1190     fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1191  transfer_error:
1192
1193     return len;
1194 }
1195
1196 /* Data register : 0x05 */
1197 static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
1198 {
1199     fdrive_t *cur_drv;
1200     uint32_t retval = 0;
1201     int pos, len;
1202
1203     cur_drv = get_cur_drv(fdctrl);
1204     fdctrl->state &= ~FD_CTRL_SLEEP;
1205     if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
1206         FLOPPY_ERROR("can't read data in CMD state\n");
1207         return 0;
1208     }
1209     pos = fdctrl->data_pos;
1210     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1211         pos %= FD_SECTOR_LEN;
1212         if (pos == 0) {
1213             len = fdctrl->data_len - fdctrl->data_pos;
1214             if (len > FD_SECTOR_LEN)
1215                 len = FD_SECTOR_LEN;
1216             bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1);
1217         }
1218     }
1219     retval = fdctrl->fifo[pos];
1220     if (++fdctrl->data_pos == fdctrl->data_len) {
1221         fdctrl->data_pos = 0;
1222         /* Switch from transfer mode to status mode
1223          * then from status mode to command mode
1224          */
1225         if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1226             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1227         } else {
1228             fdctrl_reset_fifo(fdctrl);
1229             fdctrl_reset_irq(fdctrl);
1230         }
1231     }
1232     FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1233
1234     return retval;
1235 }
1236
1237 static void fdctrl_format_sector (fdctrl_t *fdctrl)
1238 {
1239     fdrive_t *cur_drv;
1240     uint8_t kh, kt, ks;
1241     int did_seek;
1242
1243     fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1244     cur_drv = get_cur_drv(fdctrl);
1245     kt = fdctrl->fifo[6];
1246     kh = fdctrl->fifo[7];
1247     ks = fdctrl->fifo[8];
1248     FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1249                    fdctrl->cur_drv, kh, kt, ks,
1250                    _fd_sector(kh, kt, ks, cur_drv->last_sect));
1251     did_seek = 0;
1252     switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1253     case 2:
1254         /* sect too big */
1255         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1256         fdctrl->fifo[3] = kt;
1257         fdctrl->fifo[4] = kh;
1258         fdctrl->fifo[5] = ks;
1259         return;
1260     case 3:
1261         /* track too big */
1262         fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1263         fdctrl->fifo[3] = kt;
1264         fdctrl->fifo[4] = kh;
1265         fdctrl->fifo[5] = ks;
1266         return;
1267     case 4:
1268         /* No seek enabled */
1269         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1270         fdctrl->fifo[3] = kt;
1271         fdctrl->fifo[4] = kh;
1272         fdctrl->fifo[5] = ks;
1273         return;
1274     case 1:
1275         did_seek = 1;
1276         fdctrl->data_state |= FD_STATE_SEEK;
1277         break;
1278     default:
1279         break;
1280     }
1281     memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1282     if (cur_drv->bs == NULL ||
1283         bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1284         FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
1285         fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1286     } else {
1287         if (cur_drv->sect == cur_drv->last_sect) {
1288             fdctrl->data_state &= ~FD_STATE_FORMAT;
1289             /* Last sector done */
1290             if (FD_DID_SEEK(fdctrl->data_state))
1291                 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1292             else
1293                 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1294         } else {
1295             /* More to do */
1296             fdctrl->data_pos = 0;
1297             fdctrl->data_len = 4;
1298         }
1299     }
1300 }
1301
1302 static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1303 {
1304     fdrive_t *cur_drv;
1305
1306     cur_drv = get_cur_drv(fdctrl);
1307     /* Reset mode */
1308     if (fdctrl->state & FD_CTRL_RESET) {
1309         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1310         return;
1311     }
1312     fdctrl->state &= ~FD_CTRL_SLEEP;
1313     if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1314         FLOPPY_ERROR("can't write data in status mode\n");
1315         return;
1316     }
1317     /* Is it write command time ? */
1318     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1319         /* FIFO data write */
1320         fdctrl->fifo[fdctrl->data_pos++] = value;
1321         if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1322             fdctrl->data_pos == fdctrl->data_len) {
1323             bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1);
1324         }
1325         /* Switch from transfer mode to status mode
1326          * then from status mode to command mode
1327          */
1328         if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1329             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1330         return;
1331     }
1332     if (fdctrl->data_pos == 0) {
1333         /* Command */
1334         switch (value & 0x5F) {
1335         case 0x46:
1336             /* READ variants */
1337             FLOPPY_DPRINTF("READ command\n");
1338             /* 8 parameters cmd */
1339             fdctrl->data_len = 9;
1340             goto enqueue;
1341         case 0x4C:
1342             /* READ_DELETED variants */
1343             FLOPPY_DPRINTF("READ_DELETED command\n");
1344             /* 8 parameters cmd */
1345             fdctrl->data_len = 9;
1346             goto enqueue;
1347         case 0x50:
1348             /* SCAN_EQUAL variants */
1349             FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1350             /* 8 parameters cmd */
1351             fdctrl->data_len = 9;
1352             goto enqueue;
1353         case 0x56:
1354             /* VERIFY variants */
1355             FLOPPY_DPRINTF("VERIFY command\n");
1356             /* 8 parameters cmd */
1357             fdctrl->data_len = 9;
1358             goto enqueue;
1359         case 0x59:
1360             /* SCAN_LOW_OR_EQUAL variants */
1361             FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1362             /* 8 parameters cmd */
1363             fdctrl->data_len = 9;
1364             goto enqueue;
1365         case 0x5D:
1366             /* SCAN_HIGH_OR_EQUAL variants */
1367             FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1368             /* 8 parameters cmd */
1369             fdctrl->data_len = 9;
1370             goto enqueue;
1371         default:
1372             break;
1373         }
1374         switch (value & 0x7F) {
1375         case 0x45:
1376             /* WRITE variants */
1377             FLOPPY_DPRINTF("WRITE command\n");
1378             /* 8 parameters cmd */
1379             fdctrl->data_len = 9;
1380             goto enqueue;
1381         case 0x49:
1382             /* WRITE_DELETED variants */
1383             FLOPPY_DPRINTF("WRITE_DELETED command\n");
1384             /* 8 parameters cmd */
1385             fdctrl->data_len = 9;
1386             goto enqueue;
1387         default:
1388             break;
1389         }
1390         switch (value) {
1391         case 0x03:
1392             /* SPECIFY */
1393             FLOPPY_DPRINTF("SPECIFY command\n");
1394             /* 1 parameter cmd */
1395             fdctrl->data_len = 3;
1396             goto enqueue;
1397         case 0x04:
1398             /* SENSE_DRIVE_STATUS */
1399             FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1400             /* 1 parameter cmd */
1401             fdctrl->data_len = 2;
1402             goto enqueue;
1403         case 0x07:
1404             /* RECALIBRATE */
1405             FLOPPY_DPRINTF("RECALIBRATE command\n");
1406             /* 1 parameter cmd */
1407             fdctrl->data_len = 2;
1408             goto enqueue;
1409         case 0x08:
1410             /* SENSE_INTERRUPT_STATUS */
1411             FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1412                            fdctrl->int_status);
1413             /* No parameters cmd: returns status if no interrupt */
1414 #if 0
1415             fdctrl->fifo[0] =
1416                 fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1417 #else
1418             /* XXX: int_status handling is broken for read/write
1419                commands, so we do this hack. It should be suppressed
1420                ASAP */
1421             fdctrl->fifo[0] =
1422                 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1423 #endif
1424             fdctrl->fifo[1] = cur_drv->track;
1425             fdctrl_set_fifo(fdctrl, 2, 0);
1426             fdctrl_reset_irq(fdctrl);
1427             fdctrl->int_status = 0xC0;
1428             return;
1429         case 0x0E:
1430             /* DUMPREG */
1431             FLOPPY_DPRINTF("DUMPREG command\n");
1432             /* Drives position */
1433             fdctrl->fifo[0] = drv0(fdctrl)->track;
1434             fdctrl->fifo[1] = drv1(fdctrl)->track;
1435             fdctrl->fifo[2] = 0;
1436             fdctrl->fifo[3] = 0;
1437             /* timers */
1438             fdctrl->fifo[4] = fdctrl->timer0;
1439             fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1440             fdctrl->fifo[6] = cur_drv->last_sect;
1441             fdctrl->fifo[7] = (fdctrl->lock << 7) |
1442                 (cur_drv->perpendicular << 2);
1443             fdctrl->fifo[8] = fdctrl->config;
1444             fdctrl->fifo[9] = fdctrl->precomp_trk;
1445             fdctrl_set_fifo(fdctrl, 10, 0);
1446             return;
1447         case 0x0F:
1448             /* SEEK */
1449             FLOPPY_DPRINTF("SEEK command\n");
1450             /* 2 parameters cmd */
1451             fdctrl->data_len = 3;
1452             goto enqueue;
1453         case 0x10:
1454             /* VERSION */
1455             FLOPPY_DPRINTF("VERSION command\n");
1456             /* No parameters cmd */
1457             /* Controller's version */
1458             fdctrl->fifo[0] = fdctrl->version;
1459             fdctrl_set_fifo(fdctrl, 1, 1);
1460             return;
1461         case 0x12:
1462             /* PERPENDICULAR_MODE */
1463             FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1464             /* 1 parameter cmd */
1465             fdctrl->data_len = 2;
1466             goto enqueue;
1467         case 0x13:
1468             /* CONFIGURE */
1469             FLOPPY_DPRINTF("CONFIGURE command\n");
1470             /* 3 parameters cmd */
1471             fdctrl->data_len = 4;
1472             goto enqueue;
1473         case 0x14:
1474             /* UNLOCK */
1475             FLOPPY_DPRINTF("UNLOCK command\n");
1476             /* No parameters cmd */
1477             fdctrl->lock = 0;
1478             fdctrl->fifo[0] = 0;
1479             fdctrl_set_fifo(fdctrl, 1, 0);
1480             return;
1481         case 0x17:
1482             /* POWERDOWN_MODE */
1483             FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1484             /* 2 parameters cmd */
1485             fdctrl->data_len = 3;
1486             goto enqueue;
1487         case 0x18:
1488             /* PART_ID */
1489             FLOPPY_DPRINTF("PART_ID command\n");
1490             /* No parameters cmd */
1491             fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1492             fdctrl_set_fifo(fdctrl, 1, 0);
1493             return;
1494         case 0x2C:
1495             /* SAVE */
1496             FLOPPY_DPRINTF("SAVE command\n");
1497             /* No parameters cmd */
1498             fdctrl->fifo[0] = 0;
1499             fdctrl->fifo[1] = 0;
1500             /* Drives position */
1501             fdctrl->fifo[2] = drv0(fdctrl)->track;
1502             fdctrl->fifo[3] = drv1(fdctrl)->track;
1503             fdctrl->fifo[4] = 0;
1504             fdctrl->fifo[5] = 0;
1505             /* timers */
1506             fdctrl->fifo[6] = fdctrl->timer0;
1507             fdctrl->fifo[7] = fdctrl->timer1;
1508             fdctrl->fifo[8] = cur_drv->last_sect;
1509             fdctrl->fifo[9] = (fdctrl->lock << 7) |
1510                 (cur_drv->perpendicular << 2);
1511             fdctrl->fifo[10] = fdctrl->config;
1512             fdctrl->fifo[11] = fdctrl->precomp_trk;
1513             fdctrl->fifo[12] = fdctrl->pwrd;
1514             fdctrl->fifo[13] = 0;
1515             fdctrl->fifo[14] = 0;
1516             fdctrl_set_fifo(fdctrl, 15, 1);
1517             return;
1518         case 0x33:
1519             /* OPTION */
1520             FLOPPY_DPRINTF("OPTION command\n");
1521             /* 1 parameter cmd */
1522             fdctrl->data_len = 2;
1523             goto enqueue;
1524         case 0x42:
1525             /* READ_TRACK */
1526             FLOPPY_DPRINTF("READ_TRACK command\n");
1527             /* 8 parameters cmd */
1528             fdctrl->data_len = 9;
1529             goto enqueue;
1530         case 0x4A:
1531             /* READ_ID */
1532             FLOPPY_DPRINTF("READ_ID command\n");
1533             /* 1 parameter cmd */
1534             fdctrl->data_len = 2;
1535             goto enqueue;
1536         case 0x4C:
1537             /* RESTORE */
1538             FLOPPY_DPRINTF("RESTORE command\n");
1539             /* 17 parameters cmd */
1540             fdctrl->data_len = 18;
1541             goto enqueue;
1542         case 0x4D:
1543             /* FORMAT_TRACK */
1544             FLOPPY_DPRINTF("FORMAT_TRACK command\n");
1545             /* 5 parameters cmd */
1546             fdctrl->data_len = 6;
1547             goto enqueue;
1548         case 0x8E:
1549             /* DRIVE_SPECIFICATION_COMMAND */
1550             FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
1551             /* 5 parameters cmd */
1552             fdctrl->data_len = 6;
1553             goto enqueue;
1554         case 0x8F:
1555             /* RELATIVE_SEEK_OUT */
1556             FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
1557             /* 2 parameters cmd */
1558             fdctrl->data_len = 3;
1559             goto enqueue;
1560         case 0x94:
1561             /* LOCK */
1562             FLOPPY_DPRINTF("LOCK command\n");
1563             /* No parameters cmd */
1564             fdctrl->lock = 1;
1565             fdctrl->fifo[0] = 0x10;
1566             fdctrl_set_fifo(fdctrl, 1, 1);
1567             return;
1568         case 0xCD:
1569             /* FORMAT_AND_WRITE */
1570             FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
1571             /* 10 parameters cmd */
1572             fdctrl->data_len = 11;
1573             goto enqueue;
1574         case 0xCF:
1575             /* RELATIVE_SEEK_IN */
1576             FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
1577             /* 2 parameters cmd */
1578             fdctrl->data_len = 3;
1579             goto enqueue;
1580         default:
1581             /* Unknown command */
1582             FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1583             fdctrl_unimplemented(fdctrl);
1584             return;
1585         }
1586     }
1587  enqueue:
1588     FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1589     fdctrl->fifo[fdctrl->data_pos] = value;
1590     if (++fdctrl->data_pos == fdctrl->data_len) {
1591         /* We now have all parameters
1592          * and will be able to treat the command
1593          */
1594         if (fdctrl->data_state & FD_STATE_FORMAT) {
1595             fdctrl_format_sector(fdctrl);
1596             return;
1597         }
1598         switch (fdctrl->fifo[0] & 0x1F) {
1599         case 0x06:
1600             {
1601                 /* READ variants */
1602                 FLOPPY_DPRINTF("treat READ command\n");
1603                 fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1604                 return;
1605             }
1606         case 0x0C:
1607             /* READ_DELETED variants */
1608 //            FLOPPY_DPRINTF("treat READ_DELETED command\n");
1609             FLOPPY_ERROR("treat READ_DELETED command\n");
1610             fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
1611             return;
1612         case 0x16:
1613             /* VERIFY variants */
1614 //            FLOPPY_DPRINTF("treat VERIFY command\n");
1615             FLOPPY_ERROR("treat VERIFY command\n");
1616             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1617             return;
1618         case 0x10:
1619             /* SCAN_EQUAL variants */
1620 //            FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
1621             FLOPPY_ERROR("treat SCAN_EQUAL command\n");
1622             fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
1623             return;
1624         case 0x19:
1625             /* SCAN_LOW_OR_EQUAL variants */
1626 //            FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
1627             FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
1628             fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
1629             return;
1630         case 0x1D:
1631             /* SCAN_HIGH_OR_EQUAL variants */
1632 //            FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
1633             FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
1634             fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
1635             return;
1636         default:
1637             break;
1638         }
1639         switch (fdctrl->fifo[0] & 0x3F) {
1640         case 0x05:
1641             /* WRITE variants */
1642             FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
1643             fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
1644             return;
1645         case 0x09:
1646             /* WRITE_DELETED variants */
1647 //            FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
1648             FLOPPY_ERROR("treat WRITE_DELETED command\n");
1649             fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
1650             return;
1651         default:
1652             break;
1653         }
1654         switch (fdctrl->fifo[0]) {
1655         case 0x03:
1656             /* SPECIFY */
1657             FLOPPY_DPRINTF("treat SPECIFY command\n");
1658             fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1659             fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1660             fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
1661             /* No result back */
1662             fdctrl_reset_fifo(fdctrl);
1663             break;
1664         case 0x04:
1665             /* SENSE_DRIVE_STATUS */
1666             FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
1667             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1668             cur_drv = get_cur_drv(fdctrl);
1669             cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1670             /* 1 Byte status back */
1671             fdctrl->fifo[0] = (cur_drv->ro << 6) |
1672                 (cur_drv->track == 0 ? 0x10 : 0x00) |
1673                 (cur_drv->head << 2) |
1674                 fdctrl->cur_drv |
1675                 0x28;
1676             fdctrl_set_fifo(fdctrl, 1, 0);
1677             break;
1678         case 0x07:
1679             /* RECALIBRATE */
1680             FLOPPY_DPRINTF("treat RECALIBRATE command\n");
1681             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1682             cur_drv = get_cur_drv(fdctrl);
1683             fd_recalibrate(cur_drv);
1684             fdctrl_reset_fifo(fdctrl);
1685             /* Raise Interrupt */
1686             fdctrl_raise_irq(fdctrl, 0x20);
1687             break;
1688         case 0x0F:
1689             /* SEEK */
1690             FLOPPY_DPRINTF("treat SEEK command\n");
1691             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1692             cur_drv = get_cur_drv(fdctrl);
1693             fd_start(cur_drv);
1694             if (fdctrl->fifo[2] <= cur_drv->track)
1695                 cur_drv->dir = 1;
1696             else
1697                 cur_drv->dir = 0;
1698             fdctrl_reset_fifo(fdctrl);
1699             if (fdctrl->fifo[2] > cur_drv->max_track) {
1700                 fdctrl_raise_irq(fdctrl, 0x60);
1701             } else {
1702                 cur_drv->track = fdctrl->fifo[2];
1703                 /* Raise Interrupt */
1704                 fdctrl_raise_irq(fdctrl, 0x20);
1705             }
1706             break;
1707         case 0x12:
1708             /* PERPENDICULAR_MODE */
1709             FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
1710             if (fdctrl->fifo[1] & 0x80)
1711                 cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1712             /* No result back */
1713             fdctrl_reset_fifo(fdctrl);
1714             break;
1715         case 0x13:
1716             /* CONFIGURE */
1717             FLOPPY_DPRINTF("treat CONFIGURE command\n");
1718             fdctrl->config = fdctrl->fifo[2];
1719             fdctrl->precomp_trk =  fdctrl->fifo[3];
1720             /* No result back */
1721             fdctrl_reset_fifo(fdctrl);
1722             break;
1723         case 0x17:
1724             /* POWERDOWN_MODE */
1725             FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
1726             fdctrl->pwrd = fdctrl->fifo[1];
1727             fdctrl->fifo[0] = fdctrl->fifo[1];
1728             fdctrl_set_fifo(fdctrl, 1, 1);
1729             break;
1730         case 0x33:
1731             /* OPTION */
1732             FLOPPY_DPRINTF("treat OPTION command\n");
1733             /* No result back */
1734             fdctrl_reset_fifo(fdctrl);
1735             break;
1736         case 0x42:
1737             /* READ_TRACK */
1738 //            FLOPPY_DPRINTF("treat READ_TRACK command\n");
1739             FLOPPY_ERROR("treat READ_TRACK command\n");
1740             fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1741             break;
1742         case 0x4A:
1743             /* READ_ID */
1744             FLOPPY_DPRINTF("treat READ_ID command\n");
1745             /* XXX: should set main status register to busy */
1746             cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1747             qemu_mod_timer(fdctrl->result_timer,
1748                            qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1749             break;
1750         case 0x4C:
1751             /* RESTORE */
1752             FLOPPY_DPRINTF("treat RESTORE command\n");
1753             /* Drives position */
1754             drv0(fdctrl)->track = fdctrl->fifo[3];
1755             drv1(fdctrl)->track = fdctrl->fifo[4];
1756             /* timers */
1757             fdctrl->timer0 = fdctrl->fifo[7];
1758             fdctrl->timer1 = fdctrl->fifo[8];
1759             cur_drv->last_sect = fdctrl->fifo[9];
1760             fdctrl->lock = fdctrl->fifo[10] >> 7;
1761             cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1762             fdctrl->config = fdctrl->fifo[11];
1763             fdctrl->precomp_trk = fdctrl->fifo[12];
1764             fdctrl->pwrd = fdctrl->fifo[13];
1765             fdctrl_reset_fifo(fdctrl);
1766             break;
1767         case 0x4D:
1768             /* FORMAT_TRACK */
1769             FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
1770             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1771             cur_drv = get_cur_drv(fdctrl);
1772             fdctrl->data_state |= FD_STATE_FORMAT;
1773             if (fdctrl->fifo[0] & 0x80)
1774                 fdctrl->data_state |= FD_STATE_MULTI;
1775             else
1776                 fdctrl->data_state &= ~FD_STATE_MULTI;
1777             fdctrl->data_state &= ~FD_STATE_SEEK;
1778             cur_drv->bps =
1779                 fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1780 #if 0
1781             cur_drv->last_sect =
1782                 cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1783                 fdctrl->fifo[3] / 2;
1784 #else
1785             cur_drv->last_sect = fdctrl->fifo[3];
1786 #endif
1787             /* TODO: implement format using DMA expected by the Bochs BIOS
1788              * and Linux fdformat (read 3 bytes per sector via DMA and fill
1789              * the sector with the specified fill byte
1790              */
1791             fdctrl->data_state &= ~FD_STATE_FORMAT;
1792             fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1793             break;
1794         case 0x8E:
1795             /* DRIVE_SPECIFICATION_COMMAND */
1796             FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
1797             if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1798                 /* Command parameters done */
1799                 if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1800                     fdctrl->fifo[0] = fdctrl->fifo[1];
1801                     fdctrl->fifo[2] = 0;
1802                     fdctrl->fifo[3] = 0;
1803                     fdctrl_set_fifo(fdctrl, 4, 1);
1804                 } else {
1805                     fdctrl_reset_fifo(fdctrl);
1806                 }
1807             } else if (fdctrl->data_len > 7) {
1808                 /* ERROR */
1809                 fdctrl->fifo[0] = 0x80 |
1810                     (cur_drv->head << 2) | fdctrl->cur_drv;
1811                 fdctrl_set_fifo(fdctrl, 1, 1);
1812             }
1813             break;
1814         case 0x8F:
1815             /* RELATIVE_SEEK_OUT */
1816             FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
1817             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1818             cur_drv = get_cur_drv(fdctrl);
1819             fd_start(cur_drv);
1820             cur_drv->dir = 0;
1821             if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1822                 cur_drv->track = cur_drv->max_track - 1;
1823             } else {
1824                 cur_drv->track += fdctrl->fifo[2];
1825             }
1826             fdctrl_reset_fifo(fdctrl);
1827             fdctrl_raise_irq(fdctrl, 0x20);
1828             break;
1829         case 0xCD:
1830             /* FORMAT_AND_WRITE */
1831 //                FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
1832             FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
1833             fdctrl_unimplemented(fdctrl);
1834             break;
1835         case 0xCF:
1836             /* RELATIVE_SEEK_IN */
1837             FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
1838             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1839             cur_drv = get_cur_drv(fdctrl);
1840             fd_start(cur_drv);
1841             cur_drv->dir = 1;
1842             if (fdctrl->fifo[2] > cur_drv->track) {
1843                 cur_drv->track = 0;
1844             } else {
1845                 cur_drv->track -= fdctrl->fifo[2];
1846             }
1847             fdctrl_reset_fifo(fdctrl);
1848             /* Raise Interrupt */
1849             fdctrl_raise_irq(fdctrl, 0x20);
1850             break;
1851         }
1852     }
1853 }
1854
1855 static void fdctrl_result_timer(void *opaque)
1856 {
1857     fdctrl_t *fdctrl = opaque;
1858     fdrive_t *cur_drv = get_cur_drv(fdctrl);
1859
1860     /* Pretend we are spinning.
1861      * This is needed for Coherent, which uses READ ID to check for
1862      * sector interleaving.
1863      */
1864     if (cur_drv->last_sect != 0) {
1865         cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
1866     }
1867     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1868 }