Add "cache" parameter to "-drive" (Laurent Vivier).
[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;
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->fifo = qemu_memalign(512, FD_SECTOR_LEN);
602     if (fdctrl->fifo == NULL) {
603         qemu_free(fdctrl);
604         return NULL;
605     }
606     fdctrl->result_timer = qemu_new_timer(vm_clock,
607                                           fdctrl_result_timer, fdctrl);
608
609     fdctrl->version = 0x90; /* Intel 82078 controller */
610     fdctrl->irq = irq;
611     fdctrl->dma_chann = dma_chann;
612     fdctrl->io_base = io_base;
613     fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
614     fdctrl->sun4m = 0;
615     if (fdctrl->dma_chann != -1) {
616         fdctrl->dma_en = 1;
617         DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
618     } else {
619         fdctrl->dma_en = 0;
620     }
621     for (i = 0; i < 2; i++) {
622         fd_init(&fdctrl->drives[i], fds[i]);
623     }
624     fdctrl_reset(fdctrl, 0);
625     fdctrl->state = FD_CTRL_ACTIVE;
626     if (mem_mapped) {
627         io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write,
628                                         fdctrl);
629         cpu_register_physical_memory(io_base, 0x08, io_mem);
630     } else {
631         register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
632                              fdctrl);
633         register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
634                              fdctrl);
635         register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
636                               fdctrl);
637         register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
638                               fdctrl);
639     }
640     register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
641     qemu_register_reset(fdctrl_external_reset, fdctrl);
642     for (i = 0; i < 2; i++) {
643         fd_revalidate(&fdctrl->drives[i]);
644     }
645
646     return fdctrl;
647 }
648
649 fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
650                              BlockDriverState **fds)
651 {
652     fdctrl_t *fdctrl;
653
654     fdctrl = fdctrl_init(irq, 0, 1, io_base, fds);
655     fdctrl->sun4m = 1;
656
657     return fdctrl;
658 }
659
660 /* XXX: may change if moved to bdrv */
661 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
662 {
663     return fdctrl->drives[drive_num].drive;
664 }
665
666 /* Change IRQ state */
667 static void fdctrl_reset_irq (fdctrl_t *fdctrl)
668 {
669     FLOPPY_DPRINTF("Reset interrupt\n");
670     qemu_set_irq(fdctrl->irq, 0);
671     fdctrl->state &= ~FD_CTRL_INTR;
672 }
673
674 static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
675 {
676     // Sparc mutation
677     if (fdctrl->sun4m && !fdctrl->dma_en) {
678         fdctrl->state &= ~FD_CTRL_BUSY;
679         fdctrl->int_status = status;
680         return;
681     }
682     if (~(fdctrl->state & FD_CTRL_INTR)) {
683         qemu_set_irq(fdctrl->irq, 1);
684         fdctrl->state |= FD_CTRL_INTR;
685     }
686     FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
687     fdctrl->int_status = status;
688 }
689
690 /* Reset controller */
691 static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
692 {
693     int i;
694
695     FLOPPY_DPRINTF("reset controller\n");
696     fdctrl_reset_irq(fdctrl);
697     /* Initialise controller */
698     fdctrl->cur_drv = 0;
699     /* FIFO state */
700     fdctrl->data_pos = 0;
701     fdctrl->data_len = 0;
702     fdctrl->data_state = FD_STATE_CMD;
703     fdctrl->data_dir = FD_DIR_WRITE;
704     for (i = 0; i < MAX_FD; i++)
705         fd_reset(&fdctrl->drives[i]);
706     fdctrl_reset_fifo(fdctrl);
707     if (do_irq)
708         fdctrl_raise_irq(fdctrl, 0xc0);
709 }
710
711 static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
712 {
713     return &fdctrl->drives[fdctrl->bootsel];
714 }
715
716 static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
717 {
718     return &fdctrl->drives[1 - fdctrl->bootsel];
719 }
720
721 static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
722 {
723     return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
724 }
725
726 /* Status B register : 0x01 (read-only) */
727 static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
728 {
729     FLOPPY_DPRINTF("status register: 0x00\n");
730     return 0;
731 }
732
733 /* Digital output register : 0x02 */
734 static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
735 {
736     uint32_t retval = 0;
737
738     /* Drive motors state indicators */
739     if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
740         retval |= 1 << 5;
741     if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
742         retval |= 1 << 4;
743     /* DMA enable */
744     retval |= fdctrl->dma_en << 3;
745     /* Reset indicator */
746     retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
747     /* Selected drive */
748     retval |= fdctrl->cur_drv;
749     FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
750
751     return retval;
752 }
753
754 static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
755 {
756     /* Reset mode */
757     if (fdctrl->state & FD_CTRL_RESET) {
758         if (!(value & 0x04)) {
759             FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
760             return;
761         }
762     }
763     FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
764     /* Drive motors state indicators */
765     if (value & 0x20)
766         fd_start(drv1(fdctrl));
767     else
768         fd_stop(drv1(fdctrl));
769     if (value & 0x10)
770         fd_start(drv0(fdctrl));
771     else
772         fd_stop(drv0(fdctrl));
773     /* DMA enable */
774 #if 0
775     if (fdctrl->dma_chann != -1)
776         fdctrl->dma_en = 1 - ((value >> 3) & 1);
777 #endif
778     /* Reset */
779     if (!(value & 0x04)) {
780         if (!(fdctrl->state & FD_CTRL_RESET)) {
781             FLOPPY_DPRINTF("controller enter RESET state\n");
782             fdctrl->state |= FD_CTRL_RESET;
783         }
784     } else {
785         if (fdctrl->state & FD_CTRL_RESET) {
786             FLOPPY_DPRINTF("controller out of RESET state\n");
787             fdctrl_reset(fdctrl, 1);
788             fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
789         }
790     }
791     /* Selected drive */
792     fdctrl->cur_drv = value & 1;
793 }
794
795 /* Tape drive register : 0x03 */
796 static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
797 {
798     uint32_t retval = 0;
799
800     /* Disk boot selection indicator */
801     retval |= fdctrl->bootsel << 2;
802     /* Tape indicators: never allowed */
803     FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
804
805     return retval;
806 }
807
808 static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
809 {
810     /* Reset mode */
811     if (fdctrl->state & FD_CTRL_RESET) {
812         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
813         return;
814     }
815     FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
816     /* Disk boot selection indicator */
817     fdctrl->bootsel = (value >> 2) & 1;
818     /* Tape indicators: never allow */
819 }
820
821 /* Main status register : 0x04 (read) */
822 static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
823 {
824     uint32_t retval = 0;
825
826     fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
827     if (!(fdctrl->state & FD_CTRL_BUSY)) {
828         /* Data transfer allowed */
829         retval |= 0x80;
830         /* Data transfer direction indicator */
831         if (fdctrl->data_dir == FD_DIR_READ)
832             retval |= 0x40;
833     }
834     /* Should handle 0x20 for SPECIFY command */
835     /* Command busy indicator */
836     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
837         FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
838         retval |= 0x10;
839     FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
840
841     return retval;
842 }
843
844 /* Data select rate register : 0x04 (write) */
845 static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
846 {
847     /* Reset mode */
848     if (fdctrl->state & FD_CTRL_RESET) {
849         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
850         return;
851     }
852     FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
853     /* Reset: autoclear */
854     if (value & 0x80) {
855         fdctrl->state |= FD_CTRL_RESET;
856         fdctrl_reset(fdctrl, 1);
857         fdctrl->state &= ~FD_CTRL_RESET;
858     }
859     if (value & 0x40) {
860         fdctrl->state |= FD_CTRL_SLEEP;
861         fdctrl_reset(fdctrl, 1);
862     }
863 //        fdctrl.precomp = (value >> 2) & 0x07;
864 }
865
866 static int fdctrl_media_changed(fdrive_t *drv)
867 {
868     int ret;
869
870     if (!drv->bs)
871         return 0;
872     ret = bdrv_media_changed(drv->bs);
873     if (ret) {
874         fd_revalidate(drv);
875     }
876     return ret;
877 }
878
879 /* Digital input register : 0x07 (read-only) */
880 static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
881 {
882     uint32_t retval = 0;
883
884     if (fdctrl_media_changed(drv0(fdctrl)) ||
885         fdctrl_media_changed(drv1(fdctrl)))
886         retval |= 0x80;
887     if (retval != 0)
888         FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
889
890     return retval;
891 }
892
893 /* FIFO state control */
894 static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
895 {
896     fdctrl->data_dir = FD_DIR_WRITE;
897     fdctrl->data_pos = 0;
898     FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
899 }
900
901 /* Set FIFO status for the host to read */
902 static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
903 {
904     fdctrl->data_dir = FD_DIR_READ;
905     fdctrl->data_len = fifo_len;
906     fdctrl->data_pos = 0;
907     FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
908     if (do_irq)
909         fdctrl_raise_irq(fdctrl, 0x00);
910 }
911
912 /* Set an error: unimplemented/unknown command */
913 static void fdctrl_unimplemented (fdctrl_t *fdctrl)
914 {
915 #if 0
916     fdrive_t *cur_drv;
917
918     cur_drv = get_cur_drv(fdctrl);
919     fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
920     fdctrl->fifo[1] = 0x00;
921     fdctrl->fifo[2] = 0x00;
922     fdctrl_set_fifo(fdctrl, 3, 1);
923 #else
924     //    fdctrl_reset_fifo(fdctrl);
925     fdctrl->fifo[0] = 0x80;
926     fdctrl_set_fifo(fdctrl, 1, 0);
927 #endif
928 }
929
930 /* Callback for transfer end (stop or abort) */
931 static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
932                                   uint8_t status1, uint8_t status2)
933 {
934     fdrive_t *cur_drv;
935
936     cur_drv = get_cur_drv(fdctrl);
937     FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
938                    status0, status1, status2,
939                    status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
940     fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
941     fdctrl->fifo[1] = status1;
942     fdctrl->fifo[2] = status2;
943     fdctrl->fifo[3] = cur_drv->track;
944     fdctrl->fifo[4] = cur_drv->head;
945     fdctrl->fifo[5] = cur_drv->sect;
946     fdctrl->fifo[6] = FD_SECTOR_SC;
947     fdctrl->data_dir = FD_DIR_READ;
948     if (fdctrl->state & FD_CTRL_BUSY) {
949         DMA_release_DREQ(fdctrl->dma_chann);
950         fdctrl->state &= ~FD_CTRL_BUSY;
951     }
952     fdctrl_set_fifo(fdctrl, 7, 1);
953 }
954
955 /* Prepare a data transfer (either DMA or FIFO) */
956 static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
957 {
958     fdrive_t *cur_drv;
959     uint8_t kh, kt, ks;
960     int did_seek;
961
962     fdctrl->cur_drv = fdctrl->fifo[1] & 1;
963     cur_drv = get_cur_drv(fdctrl);
964     kt = fdctrl->fifo[2];
965     kh = fdctrl->fifo[3];
966     ks = fdctrl->fifo[4];
967     FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
968                    fdctrl->cur_drv, kh, kt, ks,
969                    _fd_sector(kh, kt, ks, cur_drv->last_sect));
970     did_seek = 0;
971     switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
972     case 2:
973         /* sect too big */
974         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
975         fdctrl->fifo[3] = kt;
976         fdctrl->fifo[4] = kh;
977         fdctrl->fifo[5] = ks;
978         return;
979     case 3:
980         /* track too big */
981         fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
982         fdctrl->fifo[3] = kt;
983         fdctrl->fifo[4] = kh;
984         fdctrl->fifo[5] = ks;
985         return;
986     case 4:
987         /* No seek enabled */
988         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
989         fdctrl->fifo[3] = kt;
990         fdctrl->fifo[4] = kh;
991         fdctrl->fifo[5] = ks;
992         return;
993     case 1:
994         did_seek = 1;
995         break;
996     default:
997         break;
998     }
999     /* Set the FIFO state */
1000     fdctrl->data_dir = direction;
1001     fdctrl->data_pos = 0;
1002     FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
1003     if (fdctrl->fifo[0] & 0x80)
1004         fdctrl->data_state |= FD_STATE_MULTI;
1005     else
1006         fdctrl->data_state &= ~FD_STATE_MULTI;
1007     if (did_seek)
1008         fdctrl->data_state |= FD_STATE_SEEK;
1009     else
1010         fdctrl->data_state &= ~FD_STATE_SEEK;
1011     if (fdctrl->fifo[5] == 00) {
1012         fdctrl->data_len = fdctrl->fifo[8];
1013     } else {
1014         int tmp;
1015         fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1016         tmp = (cur_drv->last_sect - ks + 1);
1017         if (fdctrl->fifo[0] & 0x80)
1018             tmp += cur_drv->last_sect;
1019         fdctrl->data_len *= tmp;
1020     }
1021     fdctrl->eot = fdctrl->fifo[6];
1022     if (fdctrl->dma_en) {
1023         int dma_mode;
1024         /* DMA transfer are enabled. Check if DMA channel is well programmed */
1025         dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
1026         dma_mode = (dma_mode >> 2) & 3;
1027         FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1028                        dma_mode, direction,
1029                        (128 << fdctrl->fifo[5]) *
1030                        (cur_drv->last_sect - ks + 1), fdctrl->data_len);
1031         if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
1032               direction == FD_DIR_SCANH) && dma_mode == 0) ||
1033             (direction == FD_DIR_WRITE && dma_mode == 2) ||
1034             (direction == FD_DIR_READ && dma_mode == 1)) {
1035             /* No access is allowed until DMA transfer has completed */
1036             fdctrl->state |= FD_CTRL_BUSY;
1037             /* Now, we just have to wait for the DMA controller to
1038              * recall us...
1039              */
1040             DMA_hold_DREQ(fdctrl->dma_chann);
1041             DMA_schedule(fdctrl->dma_chann);
1042             return;
1043         } else {
1044             FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
1045         }
1046     }
1047     FLOPPY_DPRINTF("start non-DMA transfer\n");
1048     /* IO based transfer: calculate len */
1049     fdctrl_raise_irq(fdctrl, 0x00);
1050
1051     return;
1052 }
1053
1054 /* Prepare a transfer of deleted data */
1055 static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
1056 {
1057     /* We don't handle deleted data,
1058      * so we don't return *ANYTHING*
1059      */
1060     fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1061 }
1062
1063 /* handlers for DMA transfers */
1064 static int fdctrl_transfer_handler (void *opaque, int nchan,
1065                                     int dma_pos, int dma_len)
1066 {
1067     fdctrl_t *fdctrl;
1068     fdrive_t *cur_drv;
1069     int len, start_pos, rel_pos;
1070     uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1071
1072     fdctrl = opaque;
1073     if (!(fdctrl->state & FD_CTRL_BUSY)) {
1074         FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1075         return 0;
1076     }
1077     cur_drv = get_cur_drv(fdctrl);
1078     if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1079         fdctrl->data_dir == FD_DIR_SCANH)
1080         status2 = 0x04;
1081     if (dma_len > fdctrl->data_len)
1082         dma_len = fdctrl->data_len;
1083     if (cur_drv->bs == NULL) {
1084         if (fdctrl->data_dir == FD_DIR_WRITE)
1085             fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1086         else
1087             fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1088         len = 0;
1089         goto transfer_error;
1090     }
1091     rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1092     for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1093         len = dma_len - fdctrl->data_pos;
1094         if (len + rel_pos > FD_SECTOR_LEN)
1095             len = FD_SECTOR_LEN - rel_pos;
1096         FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1097                        "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
1098                        fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1099                        cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1100                        fd_sector(cur_drv) * 512);
1101         if (fdctrl->data_dir != FD_DIR_WRITE ||
1102             len < FD_SECTOR_LEN || rel_pos != 0) {
1103             /* READ & SCAN commands and realign to a sector for WRITE */
1104             if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1105                           fdctrl->fifo, 1) < 0) {
1106                 FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1107                                fd_sector(cur_drv));
1108                 /* Sure, image size is too small... */
1109                 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1110             }
1111         }
1112         switch (fdctrl->data_dir) {
1113         case FD_DIR_READ:
1114             /* READ commands */
1115             DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
1116                               fdctrl->data_pos, len);
1117             break;
1118         case FD_DIR_WRITE:
1119             /* WRITE commands */
1120             DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
1121                              fdctrl->data_pos, len);
1122             if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1123                            fdctrl->fifo, 1) < 0) {
1124                 FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1125                 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1126                 goto transfer_error;
1127             }
1128             break;
1129         default:
1130             /* SCAN commands */
1131             {
1132                 uint8_t tmpbuf[FD_SECTOR_LEN];
1133                 int ret;
1134                 DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1135                 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1136                 if (ret == 0) {
1137                     status2 = 0x08;
1138                     goto end_transfer;
1139                 }
1140                 if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1141                     (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1142                     status2 = 0x00;
1143                     goto end_transfer;
1144                 }
1145             }
1146             break;
1147         }
1148         fdctrl->data_pos += len;
1149         rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1150         if (rel_pos == 0) {
1151             /* Seek to next sector */
1152             FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1153                            cur_drv->head, cur_drv->track, cur_drv->sect,
1154                            fd_sector(cur_drv),
1155                            fdctrl->data_pos - len);
1156             /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1157                error in fact */
1158             if (cur_drv->sect >= cur_drv->last_sect ||
1159                 cur_drv->sect == fdctrl->eot) {
1160                 cur_drv->sect = 1;
1161                 if (FD_MULTI_TRACK(fdctrl->data_state)) {
1162                     if (cur_drv->head == 0 &&
1163                         (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1164                         cur_drv->head = 1;
1165                     } else {
1166                         cur_drv->head = 0;
1167                         cur_drv->track++;
1168                         if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1169                             break;
1170                     }
1171                 } else {
1172                     cur_drv->track++;
1173                     break;
1174                 }
1175                 FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1176                                cur_drv->head, cur_drv->track,
1177                                cur_drv->sect, fd_sector(cur_drv));
1178             } else {
1179                 cur_drv->sect++;
1180             }
1181         }
1182     }
1183  end_transfer:
1184     len = fdctrl->data_pos - start_pos;
1185     FLOPPY_DPRINTF("end transfer %d %d %d\n",
1186                    fdctrl->data_pos, len, fdctrl->data_len);
1187     if (fdctrl->data_dir == FD_DIR_SCANE ||
1188         fdctrl->data_dir == FD_DIR_SCANL ||
1189         fdctrl->data_dir == FD_DIR_SCANH)
1190         status2 = 0x08;
1191     if (FD_DID_SEEK(fdctrl->data_state))
1192         status0 |= 0x20;
1193     fdctrl->data_len -= len;
1194     //    if (fdctrl->data_len == 0)
1195     fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1196  transfer_error:
1197
1198     return len;
1199 }
1200
1201 /* Data register : 0x05 */
1202 static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
1203 {
1204     fdrive_t *cur_drv;
1205     uint32_t retval = 0;
1206     int pos, len;
1207
1208     cur_drv = get_cur_drv(fdctrl);
1209     fdctrl->state &= ~FD_CTRL_SLEEP;
1210     if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
1211         FLOPPY_ERROR("can't read data in CMD state\n");
1212         return 0;
1213     }
1214     pos = fdctrl->data_pos;
1215     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1216         pos %= FD_SECTOR_LEN;
1217         if (pos == 0) {
1218             len = fdctrl->data_len - fdctrl->data_pos;
1219             if (len > FD_SECTOR_LEN)
1220                 len = FD_SECTOR_LEN;
1221             bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1);
1222         }
1223     }
1224     retval = fdctrl->fifo[pos];
1225     if (++fdctrl->data_pos == fdctrl->data_len) {
1226         fdctrl->data_pos = 0;
1227         /* Switch from transfer mode to status mode
1228          * then from status mode to command mode
1229          */
1230         if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1231             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1232         } else {
1233             fdctrl_reset_fifo(fdctrl);
1234             fdctrl_reset_irq(fdctrl);
1235         }
1236     }
1237     FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1238
1239     return retval;
1240 }
1241
1242 static void fdctrl_format_sector (fdctrl_t *fdctrl)
1243 {
1244     fdrive_t *cur_drv;
1245     uint8_t kh, kt, ks;
1246     int did_seek;
1247
1248     fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1249     cur_drv = get_cur_drv(fdctrl);
1250     kt = fdctrl->fifo[6];
1251     kh = fdctrl->fifo[7];
1252     ks = fdctrl->fifo[8];
1253     FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1254                    fdctrl->cur_drv, kh, kt, ks,
1255                    _fd_sector(kh, kt, ks, cur_drv->last_sect));
1256     did_seek = 0;
1257     switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1258     case 2:
1259         /* sect too big */
1260         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1261         fdctrl->fifo[3] = kt;
1262         fdctrl->fifo[4] = kh;
1263         fdctrl->fifo[5] = ks;
1264         return;
1265     case 3:
1266         /* track too big */
1267         fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1268         fdctrl->fifo[3] = kt;
1269         fdctrl->fifo[4] = kh;
1270         fdctrl->fifo[5] = ks;
1271         return;
1272     case 4:
1273         /* No seek enabled */
1274         fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1275         fdctrl->fifo[3] = kt;
1276         fdctrl->fifo[4] = kh;
1277         fdctrl->fifo[5] = ks;
1278         return;
1279     case 1:
1280         did_seek = 1;
1281         fdctrl->data_state |= FD_STATE_SEEK;
1282         break;
1283     default:
1284         break;
1285     }
1286     memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1287     if (cur_drv->bs == NULL ||
1288         bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1289         FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
1290         fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1291     } else {
1292         if (cur_drv->sect == cur_drv->last_sect) {
1293             fdctrl->data_state &= ~FD_STATE_FORMAT;
1294             /* Last sector done */
1295             if (FD_DID_SEEK(fdctrl->data_state))
1296                 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1297             else
1298                 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1299         } else {
1300             /* More to do */
1301             fdctrl->data_pos = 0;
1302             fdctrl->data_len = 4;
1303         }
1304     }
1305 }
1306
1307 static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1308 {
1309     fdrive_t *cur_drv;
1310
1311     cur_drv = get_cur_drv(fdctrl);
1312     /* Reset mode */
1313     if (fdctrl->state & FD_CTRL_RESET) {
1314         FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1315         return;
1316     }
1317     fdctrl->state &= ~FD_CTRL_SLEEP;
1318     if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1319         FLOPPY_ERROR("can't write data in status mode\n");
1320         return;
1321     }
1322     /* Is it write command time ? */
1323     if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1324         /* FIFO data write */
1325         fdctrl->fifo[fdctrl->data_pos++] = value;
1326         if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1327             fdctrl->data_pos == fdctrl->data_len) {
1328             bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1);
1329         }
1330         /* Switch from transfer mode to status mode
1331          * then from status mode to command mode
1332          */
1333         if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1334             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1335         return;
1336     }
1337     if (fdctrl->data_pos == 0) {
1338         /* Command */
1339         switch (value & 0x5F) {
1340         case 0x46:
1341             /* READ variants */
1342             FLOPPY_DPRINTF("READ command\n");
1343             /* 8 parameters cmd */
1344             fdctrl->data_len = 9;
1345             goto enqueue;
1346         case 0x4C:
1347             /* READ_DELETED variants */
1348             FLOPPY_DPRINTF("READ_DELETED command\n");
1349             /* 8 parameters cmd */
1350             fdctrl->data_len = 9;
1351             goto enqueue;
1352         case 0x50:
1353             /* SCAN_EQUAL variants */
1354             FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1355             /* 8 parameters cmd */
1356             fdctrl->data_len = 9;
1357             goto enqueue;
1358         case 0x56:
1359             /* VERIFY variants */
1360             FLOPPY_DPRINTF("VERIFY command\n");
1361             /* 8 parameters cmd */
1362             fdctrl->data_len = 9;
1363             goto enqueue;
1364         case 0x59:
1365             /* SCAN_LOW_OR_EQUAL variants */
1366             FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1367             /* 8 parameters cmd */
1368             fdctrl->data_len = 9;
1369             goto enqueue;
1370         case 0x5D:
1371             /* SCAN_HIGH_OR_EQUAL variants */
1372             FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1373             /* 8 parameters cmd */
1374             fdctrl->data_len = 9;
1375             goto enqueue;
1376         default:
1377             break;
1378         }
1379         switch (value & 0x7F) {
1380         case 0x45:
1381             /* WRITE variants */
1382             FLOPPY_DPRINTF("WRITE command\n");
1383             /* 8 parameters cmd */
1384             fdctrl->data_len = 9;
1385             goto enqueue;
1386         case 0x49:
1387             /* WRITE_DELETED variants */
1388             FLOPPY_DPRINTF("WRITE_DELETED command\n");
1389             /* 8 parameters cmd */
1390             fdctrl->data_len = 9;
1391             goto enqueue;
1392         default:
1393             break;
1394         }
1395         switch (value) {
1396         case 0x03:
1397             /* SPECIFY */
1398             FLOPPY_DPRINTF("SPECIFY command\n");
1399             /* 1 parameter cmd */
1400             fdctrl->data_len = 3;
1401             goto enqueue;
1402         case 0x04:
1403             /* SENSE_DRIVE_STATUS */
1404             FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1405             /* 1 parameter cmd */
1406             fdctrl->data_len = 2;
1407             goto enqueue;
1408         case 0x07:
1409             /* RECALIBRATE */
1410             FLOPPY_DPRINTF("RECALIBRATE command\n");
1411             /* 1 parameter cmd */
1412             fdctrl->data_len = 2;
1413             goto enqueue;
1414         case 0x08:
1415             /* SENSE_INTERRUPT_STATUS */
1416             FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1417                            fdctrl->int_status);
1418             /* No parameters cmd: returns status if no interrupt */
1419 #if 0
1420             fdctrl->fifo[0] =
1421                 fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1422 #else
1423             /* XXX: int_status handling is broken for read/write
1424                commands, so we do this hack. It should be suppressed
1425                ASAP */
1426             fdctrl->fifo[0] =
1427                 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1428 #endif
1429             fdctrl->fifo[1] = cur_drv->track;
1430             fdctrl_set_fifo(fdctrl, 2, 0);
1431             fdctrl_reset_irq(fdctrl);
1432             fdctrl->int_status = 0xC0;
1433             return;
1434         case 0x0E:
1435             /* DUMPREG */
1436             FLOPPY_DPRINTF("DUMPREG command\n");
1437             /* Drives position */
1438             fdctrl->fifo[0] = drv0(fdctrl)->track;
1439             fdctrl->fifo[1] = drv1(fdctrl)->track;
1440             fdctrl->fifo[2] = 0;
1441             fdctrl->fifo[3] = 0;
1442             /* timers */
1443             fdctrl->fifo[4] = fdctrl->timer0;
1444             fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1445             fdctrl->fifo[6] = cur_drv->last_sect;
1446             fdctrl->fifo[7] = (fdctrl->lock << 7) |
1447                 (cur_drv->perpendicular << 2);
1448             fdctrl->fifo[8] = fdctrl->config;
1449             fdctrl->fifo[9] = fdctrl->precomp_trk;
1450             fdctrl_set_fifo(fdctrl, 10, 0);
1451             return;
1452         case 0x0F:
1453             /* SEEK */
1454             FLOPPY_DPRINTF("SEEK command\n");
1455             /* 2 parameters cmd */
1456             fdctrl->data_len = 3;
1457             goto enqueue;
1458         case 0x10:
1459             /* VERSION */
1460             FLOPPY_DPRINTF("VERSION command\n");
1461             /* No parameters cmd */
1462             /* Controller's version */
1463             fdctrl->fifo[0] = fdctrl->version;
1464             fdctrl_set_fifo(fdctrl, 1, 1);
1465             return;
1466         case 0x12:
1467             /* PERPENDICULAR_MODE */
1468             FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1469             /* 1 parameter cmd */
1470             fdctrl->data_len = 2;
1471             goto enqueue;
1472         case 0x13:
1473             /* CONFIGURE */
1474             FLOPPY_DPRINTF("CONFIGURE command\n");
1475             /* 3 parameters cmd */
1476             fdctrl->data_len = 4;
1477             goto enqueue;
1478         case 0x14:
1479             /* UNLOCK */
1480             FLOPPY_DPRINTF("UNLOCK command\n");
1481             /* No parameters cmd */
1482             fdctrl->lock = 0;
1483             fdctrl->fifo[0] = 0;
1484             fdctrl_set_fifo(fdctrl, 1, 0);
1485             return;
1486         case 0x17:
1487             /* POWERDOWN_MODE */
1488             FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1489             /* 2 parameters cmd */
1490             fdctrl->data_len = 3;
1491             goto enqueue;
1492         case 0x18:
1493             /* PART_ID */
1494             FLOPPY_DPRINTF("PART_ID command\n");
1495             /* No parameters cmd */
1496             fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1497             fdctrl_set_fifo(fdctrl, 1, 0);
1498             return;
1499         case 0x2C:
1500             /* SAVE */
1501             FLOPPY_DPRINTF("SAVE command\n");
1502             /* No parameters cmd */
1503             fdctrl->fifo[0] = 0;
1504             fdctrl->fifo[1] = 0;
1505             /* Drives position */
1506             fdctrl->fifo[2] = drv0(fdctrl)->track;
1507             fdctrl->fifo[3] = drv1(fdctrl)->track;
1508             fdctrl->fifo[4] = 0;
1509             fdctrl->fifo[5] = 0;
1510             /* timers */
1511             fdctrl->fifo[6] = fdctrl->timer0;
1512             fdctrl->fifo[7] = fdctrl->timer1;
1513             fdctrl->fifo[8] = cur_drv->last_sect;
1514             fdctrl->fifo[9] = (fdctrl->lock << 7) |
1515                 (cur_drv->perpendicular << 2);
1516             fdctrl->fifo[10] = fdctrl->config;
1517             fdctrl->fifo[11] = fdctrl->precomp_trk;
1518             fdctrl->fifo[12] = fdctrl->pwrd;
1519             fdctrl->fifo[13] = 0;
1520             fdctrl->fifo[14] = 0;
1521             fdctrl_set_fifo(fdctrl, 15, 1);
1522             return;
1523         case 0x33:
1524             /* OPTION */
1525             FLOPPY_DPRINTF("OPTION command\n");
1526             /* 1 parameter cmd */
1527             fdctrl->data_len = 2;
1528             goto enqueue;
1529         case 0x42:
1530             /* READ_TRACK */
1531             FLOPPY_DPRINTF("READ_TRACK command\n");
1532             /* 8 parameters cmd */
1533             fdctrl->data_len = 9;
1534             goto enqueue;
1535         case 0x4A:
1536             /* READ_ID */
1537             FLOPPY_DPRINTF("READ_ID command\n");
1538             /* 1 parameter cmd */
1539             fdctrl->data_len = 2;
1540             goto enqueue;
1541         case 0x4C:
1542             /* RESTORE */
1543             FLOPPY_DPRINTF("RESTORE command\n");
1544             /* 17 parameters cmd */
1545             fdctrl->data_len = 18;
1546             goto enqueue;
1547         case 0x4D:
1548             /* FORMAT_TRACK */
1549             FLOPPY_DPRINTF("FORMAT_TRACK command\n");
1550             /* 5 parameters cmd */
1551             fdctrl->data_len = 6;
1552             goto enqueue;
1553         case 0x8E:
1554             /* DRIVE_SPECIFICATION_COMMAND */
1555             FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
1556             /* 5 parameters cmd */
1557             fdctrl->data_len = 6;
1558             goto enqueue;
1559         case 0x8F:
1560             /* RELATIVE_SEEK_OUT */
1561             FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
1562             /* 2 parameters cmd */
1563             fdctrl->data_len = 3;
1564             goto enqueue;
1565         case 0x94:
1566             /* LOCK */
1567             FLOPPY_DPRINTF("LOCK command\n");
1568             /* No parameters cmd */
1569             fdctrl->lock = 1;
1570             fdctrl->fifo[0] = 0x10;
1571             fdctrl_set_fifo(fdctrl, 1, 1);
1572             return;
1573         case 0xCD:
1574             /* FORMAT_AND_WRITE */
1575             FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
1576             /* 10 parameters cmd */
1577             fdctrl->data_len = 11;
1578             goto enqueue;
1579         case 0xCF:
1580             /* RELATIVE_SEEK_IN */
1581             FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
1582             /* 2 parameters cmd */
1583             fdctrl->data_len = 3;
1584             goto enqueue;
1585         default:
1586             /* Unknown command */
1587             FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1588             fdctrl_unimplemented(fdctrl);
1589             return;
1590         }
1591     }
1592  enqueue:
1593     FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1594     fdctrl->fifo[fdctrl->data_pos] = value;
1595     if (++fdctrl->data_pos == fdctrl->data_len) {
1596         /* We now have all parameters
1597          * and will be able to treat the command
1598          */
1599         if (fdctrl->data_state & FD_STATE_FORMAT) {
1600             fdctrl_format_sector(fdctrl);
1601             return;
1602         }
1603         switch (fdctrl->fifo[0] & 0x1F) {
1604         case 0x06:
1605             {
1606                 /* READ variants */
1607                 FLOPPY_DPRINTF("treat READ command\n");
1608                 fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1609                 return;
1610             }
1611         case 0x0C:
1612             /* READ_DELETED variants */
1613 //            FLOPPY_DPRINTF("treat READ_DELETED command\n");
1614             FLOPPY_ERROR("treat READ_DELETED command\n");
1615             fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
1616             return;
1617         case 0x16:
1618             /* VERIFY variants */
1619 //            FLOPPY_DPRINTF("treat VERIFY command\n");
1620             FLOPPY_ERROR("treat VERIFY command\n");
1621             fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1622             return;
1623         case 0x10:
1624             /* SCAN_EQUAL variants */
1625 //            FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
1626             FLOPPY_ERROR("treat SCAN_EQUAL command\n");
1627             fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
1628             return;
1629         case 0x19:
1630             /* SCAN_LOW_OR_EQUAL variants */
1631 //            FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
1632             FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
1633             fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
1634             return;
1635         case 0x1D:
1636             /* SCAN_HIGH_OR_EQUAL variants */
1637 //            FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
1638             FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
1639             fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
1640             return;
1641         default:
1642             break;
1643         }
1644         switch (fdctrl->fifo[0] & 0x3F) {
1645         case 0x05:
1646             /* WRITE variants */
1647             FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
1648             fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
1649             return;
1650         case 0x09:
1651             /* WRITE_DELETED variants */
1652 //            FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
1653             FLOPPY_ERROR("treat WRITE_DELETED command\n");
1654             fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
1655             return;
1656         default:
1657             break;
1658         }
1659         switch (fdctrl->fifo[0]) {
1660         case 0x03:
1661             /* SPECIFY */
1662             FLOPPY_DPRINTF("treat SPECIFY command\n");
1663             fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1664             fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1665             fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
1666             /* No result back */
1667             fdctrl_reset_fifo(fdctrl);
1668             break;
1669         case 0x04:
1670             /* SENSE_DRIVE_STATUS */
1671             FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
1672             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1673             cur_drv = get_cur_drv(fdctrl);
1674             cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1675             /* 1 Byte status back */
1676             fdctrl->fifo[0] = (cur_drv->ro << 6) |
1677                 (cur_drv->track == 0 ? 0x10 : 0x00) |
1678                 (cur_drv->head << 2) |
1679                 fdctrl->cur_drv |
1680                 0x28;
1681             fdctrl_set_fifo(fdctrl, 1, 0);
1682             break;
1683         case 0x07:
1684             /* RECALIBRATE */
1685             FLOPPY_DPRINTF("treat RECALIBRATE command\n");
1686             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1687             cur_drv = get_cur_drv(fdctrl);
1688             fd_recalibrate(cur_drv);
1689             fdctrl_reset_fifo(fdctrl);
1690             /* Raise Interrupt */
1691             fdctrl_raise_irq(fdctrl, 0x20);
1692             break;
1693         case 0x0F:
1694             /* SEEK */
1695             FLOPPY_DPRINTF("treat SEEK command\n");
1696             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1697             cur_drv = get_cur_drv(fdctrl);
1698             fd_start(cur_drv);
1699             if (fdctrl->fifo[2] <= cur_drv->track)
1700                 cur_drv->dir = 1;
1701             else
1702                 cur_drv->dir = 0;
1703             fdctrl_reset_fifo(fdctrl);
1704             if (fdctrl->fifo[2] > cur_drv->max_track) {
1705                 fdctrl_raise_irq(fdctrl, 0x60);
1706             } else {
1707                 cur_drv->track = fdctrl->fifo[2];
1708                 /* Raise Interrupt */
1709                 fdctrl_raise_irq(fdctrl, 0x20);
1710             }
1711             break;
1712         case 0x12:
1713             /* PERPENDICULAR_MODE */
1714             FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
1715             if (fdctrl->fifo[1] & 0x80)
1716                 cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1717             /* No result back */
1718             fdctrl_reset_fifo(fdctrl);
1719             break;
1720         case 0x13:
1721             /* CONFIGURE */
1722             FLOPPY_DPRINTF("treat CONFIGURE command\n");
1723             fdctrl->config = fdctrl->fifo[2];
1724             fdctrl->precomp_trk =  fdctrl->fifo[3];
1725             /* No result back */
1726             fdctrl_reset_fifo(fdctrl);
1727             break;
1728         case 0x17:
1729             /* POWERDOWN_MODE */
1730             FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
1731             fdctrl->pwrd = fdctrl->fifo[1];
1732             fdctrl->fifo[0] = fdctrl->fifo[1];
1733             fdctrl_set_fifo(fdctrl, 1, 1);
1734             break;
1735         case 0x33:
1736             /* OPTION */
1737             FLOPPY_DPRINTF("treat OPTION command\n");
1738             /* No result back */
1739             fdctrl_reset_fifo(fdctrl);
1740             break;
1741         case 0x42:
1742             /* READ_TRACK */
1743 //            FLOPPY_DPRINTF("treat READ_TRACK command\n");
1744             FLOPPY_ERROR("treat READ_TRACK command\n");
1745             fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1746             break;
1747         case 0x4A:
1748             /* READ_ID */
1749             FLOPPY_DPRINTF("treat READ_ID command\n");
1750             /* XXX: should set main status register to busy */
1751             cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1752             qemu_mod_timer(fdctrl->result_timer,
1753                            qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1754             break;
1755         case 0x4C:
1756             /* RESTORE */
1757             FLOPPY_DPRINTF("treat RESTORE command\n");
1758             /* Drives position */
1759             drv0(fdctrl)->track = fdctrl->fifo[3];
1760             drv1(fdctrl)->track = fdctrl->fifo[4];
1761             /* timers */
1762             fdctrl->timer0 = fdctrl->fifo[7];
1763             fdctrl->timer1 = fdctrl->fifo[8];
1764             cur_drv->last_sect = fdctrl->fifo[9];
1765             fdctrl->lock = fdctrl->fifo[10] >> 7;
1766             cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1767             fdctrl->config = fdctrl->fifo[11];
1768             fdctrl->precomp_trk = fdctrl->fifo[12];
1769             fdctrl->pwrd = fdctrl->fifo[13];
1770             fdctrl_reset_fifo(fdctrl);
1771             break;
1772         case 0x4D:
1773             /* FORMAT_TRACK */
1774             FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
1775             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1776             cur_drv = get_cur_drv(fdctrl);
1777             fdctrl->data_state |= FD_STATE_FORMAT;
1778             if (fdctrl->fifo[0] & 0x80)
1779                 fdctrl->data_state |= FD_STATE_MULTI;
1780             else
1781                 fdctrl->data_state &= ~FD_STATE_MULTI;
1782             fdctrl->data_state &= ~FD_STATE_SEEK;
1783             cur_drv->bps =
1784                 fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1785 #if 0
1786             cur_drv->last_sect =
1787                 cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1788                 fdctrl->fifo[3] / 2;
1789 #else
1790             cur_drv->last_sect = fdctrl->fifo[3];
1791 #endif
1792             /* TODO: implement format using DMA expected by the Bochs BIOS
1793              * and Linux fdformat (read 3 bytes per sector via DMA and fill
1794              * the sector with the specified fill byte
1795              */
1796             fdctrl->data_state &= ~FD_STATE_FORMAT;
1797             fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1798             break;
1799         case 0x8E:
1800             /* DRIVE_SPECIFICATION_COMMAND */
1801             FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
1802             if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1803                 /* Command parameters done */
1804                 if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1805                     fdctrl->fifo[0] = fdctrl->fifo[1];
1806                     fdctrl->fifo[2] = 0;
1807                     fdctrl->fifo[3] = 0;
1808                     fdctrl_set_fifo(fdctrl, 4, 1);
1809                 } else {
1810                     fdctrl_reset_fifo(fdctrl);
1811                 }
1812             } else if (fdctrl->data_len > 7) {
1813                 /* ERROR */
1814                 fdctrl->fifo[0] = 0x80 |
1815                     (cur_drv->head << 2) | fdctrl->cur_drv;
1816                 fdctrl_set_fifo(fdctrl, 1, 1);
1817             }
1818             break;
1819         case 0x8F:
1820             /* RELATIVE_SEEK_OUT */
1821             FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
1822             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1823             cur_drv = get_cur_drv(fdctrl);
1824             fd_start(cur_drv);
1825             cur_drv->dir = 0;
1826             if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1827                 cur_drv->track = cur_drv->max_track - 1;
1828             } else {
1829                 cur_drv->track += fdctrl->fifo[2];
1830             }
1831             fdctrl_reset_fifo(fdctrl);
1832             fdctrl_raise_irq(fdctrl, 0x20);
1833             break;
1834         case 0xCD:
1835             /* FORMAT_AND_WRITE */
1836 //                FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
1837             FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
1838             fdctrl_unimplemented(fdctrl);
1839             break;
1840         case 0xCF:
1841             /* RELATIVE_SEEK_IN */
1842             FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
1843             fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1844             cur_drv = get_cur_drv(fdctrl);
1845             fd_start(cur_drv);
1846             cur_drv->dir = 1;
1847             if (fdctrl->fifo[2] > cur_drv->track) {
1848                 cur_drv->track = 0;
1849             } else {
1850                 cur_drv->track -= fdctrl->fifo[2];
1851             }
1852             fdctrl_reset_fifo(fdctrl);
1853             /* Raise Interrupt */
1854             fdctrl_raise_irq(fdctrl, 0x20);
1855             break;
1856         }
1857     }
1858 }
1859
1860 static void fdctrl_result_timer(void *opaque)
1861 {
1862     fdctrl_t *fdctrl = opaque;
1863     fdrive_t *cur_drv = get_cur_drv(fdctrl);
1864
1865     /* Pretend we are spinning.
1866      * This is needed for Coherent, which uses READ ID to check for
1867      * sector interleaving.
1868      */
1869     if (cur_drv->last_sect != 0) {
1870         cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
1871     }
1872     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1873 }