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