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