VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/fdc.c@ 2557

Last change on this file since 2557 was 2557, checked in by vboxsync, 18 years ago

Fixed and simplified BIOS int15 mouse service. Avoids spurious
scancode generation.

  • Property svn:eol-style set to native
File size: 99.4 KB
Line 
1#ifdef VBOX
2/** @file
3 *
4 * VBox storage devices:
5 * Floppy disk controller
6 */
7
8/*
9 * Copyright (C) 2006 InnoTek Systemberatung GmbH
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * If you received this file as part of a commercial VirtualBox
20 * distribution, then only the terms of your commercial VirtualBox
21 * license agreement apply instead of the previous paragraph.
22 *
23 * --------------------------------------------------------------------
24 *
25 * This code is based on:
26 *
27 * QEMU Floppy disk emulator (Intel 82078)
28 *
29 * Copyright (c) 2003 Jocelyn Mayer
30 *
31 * Permission is hereby granted, free of charge, to any person obtaining a copy
32 * of this software and associated documentation files (the "Software"), to deal
33 * in the Software without restriction, including without limitation the rights
34 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35 * copies of the Software, and to permit persons to whom the Software is
36 * furnished to do so, subject to the following conditions:
37 *
38 * The above copyright notice and this permission notice shall be included in
39 * all copies or substantial portions of the Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
44 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47 * THE SOFTWARE.
48 *
49 */
50
51
52/*******************************************************************************
53* Header Files *
54*******************************************************************************/
55#define LOG_GROUP LOG_GROUP_DEV_FDC
56#include <VBox/pdm.h>
57#include <VBox/err.h>
58
59#include <VBox/log.h>
60#include <iprt/assert.h>
61#include <iprt/uuid.h>
62#include <iprt/string.h>
63
64#include "Builtins.h"
65#include "../vl_vbox.h"
66
67#define MAX_FD 2
68
69#define PDMIBASE_2_FDRIVE(pInterface) \
70 ((fdrive_t *)((uintptr_t)(pInterface) - RT_OFFSETOF(fdrive_t, IBase)))
71
72#define PDMIMOUNTNOTIFY_2_FDRIVE(p) \
73 ((fdrive_t *)((uintptr_t)(p) - RT_OFFSETOF(fdrive_t, IMountNotify)))
74
75#endif /* VBOX */
76
77#ifndef VBOX
78#include "vl.h"
79#endif /* !VBOX */
80
81/********************************************************/
82/* debug Floppy devices */
83/* #define DEBUG_FLOPPY */
84
85#ifndef VBOX
86 #ifdef DEBUG_FLOPPY
87 #define FLOPPY_DPRINTF(fmt, args...) \
88 do { printf("FLOPPY: " fmt , ##args); } while (0)
89 #endif
90#else /* !VBOX */
91 # ifdef LOG_ENABLED
92 static void FLOPPY_DPRINTF (const char *fmt, ...)
93 {
94 if (LogIsEnabled ()) {
95 va_list args;
96 va_start (args, fmt);
97 RTLogLogger (NULL, NULL, "floppy: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
98 va_end (args);
99 }
100 }
101 # else
102 DECLINLINE(void) FLOPPY_DPRINTF(const char *pszFmt, ...) {}
103 # endif
104#endif /* !VBOX */
105
106#ifndef VBOX
107#define FLOPPY_ERROR(fmt, args...) \
108 do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
109#else /* VBOX */
110# define FLOPPY_ERROR RTLogPrintf
111#endif /* VBOX */
112
113#ifdef VBOX
114typedef struct fdctrl_t fdctrl_t;
115#endif /* VBOX */
116
117/********************************************************/
118/* Floppy drive emulation */
119
120/* Will always be a fixed parameter for us */
121#define FD_SECTOR_LEN 512
122#define FD_SECTOR_SC 2 /* Sector size code */
123
124/* Floppy disk drive emulation */
125typedef enum fdisk_type_t {
126 FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */
127 FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */
128 FDRIVE_DISK_720 = 0x03, /* 720 kB disk */
129 FDRIVE_DISK_USER = 0x04, /* User defined geometry */
130 FDRIVE_DISK_NONE = 0x05 /* No disk */
131} fdisk_type_t;
132
133typedef enum fdrive_type_t {
134 FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
135 FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
136 FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
137 FDRIVE_DRV_NONE = 0x03 /* No drive connected */
138} fdrive_type_t;
139
140typedef enum fdrive_flags_t {
141 FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
142 FDRIVE_REVALIDATE = 0x02 /* Revalidated */
143} fdrive_flags_t;
144
145typedef enum fdisk_flags_t {
146 FDISK_DBL_SIDES = 0x01
147} fdisk_flags_t;
148
149#ifdef VBOX
150typedef enum fdrive_drate_t {
151 FDRIVE_RATE_500K = 0x00, /* 500 Kbps */
152 FDRIVE_RATE_300K = 0x01, /* 300 Kbps */
153 FDRIVE_RATE_250K = 0x02, /* 250 Kbps */
154 FDRIVE_RATE_1M = 0x03 /* 1 Mbps */
155} fdrive_drate_t;
156#endif
157
158typedef struct fdrive_t {
159#ifndef VBOX
160 BlockDriverState *bs;
161#else /* VBOX */
162 /** Pointer to the attached driver's base interface. */
163 HCPTRTYPE(PPDMIBASE) pDrvBase;
164 /** Pointer to the attached driver's block interface. */
165 HCPTRTYPE(PPDMIBLOCK) pDrvBlock;
166 /** Pointer to the attached driver's block bios interface. */
167 HCPTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
168 /** Pointer to the attached driver's mount interface.
169 * This is NULL if the driver isn't a removable unit. */
170 HCPTRTYPE(PPDMIMOUNT) pDrvMount;
171 /** The base interface. */
172 PDMIBASE IBase;
173 /** The block port interface. */
174 PDMIBLOCKPORT IPort;
175 /** The mount notify interface. */
176 PDMIMOUNTNOTIFY IMountNotify;
177 /** The LUN #. */
178 RTUINT iLUN;
179 /** The LED for this LUN. */
180 PDMLED Led;
181 /** The Diskette present/missing flag. */
182 bool fMediaPresent;
183 /** Data rate required by media. */
184 fdrive_drate_t media_rate;
185#endif
186 /* Drive status */
187 fdrive_type_t drive;
188 fdrive_flags_t drflags;
189 uint8_t perpendicular; /* 2.88 MB access mode */
190 /* Position */
191 uint8_t head;
192 uint8_t track;
193 uint8_t sect;
194 /* Last operation status */
195 uint8_t dir; /* Direction */
196 uint8_t rw; /* Read/write */
197 /* Media */
198 fdisk_flags_t flags;
199 uint8_t last_sect; /* Nb sector per track */
200 uint8_t max_track; /* Nb of tracks */
201 uint16_t bps; /* Bytes per sector */
202 uint8_t ro; /* Is read-only */
203} fdrive_t;
204
205#ifndef VBOX
206static void fd_init (fdrive_t *drv, BlockDriverState *bs)
207{
208 /* Drive */
209 drv->bs = bs;
210 drv->drive = FDRIVE_DRV_NONE;
211 drv->drflags = 0;
212 drv->perpendicular = 0;
213 /* Disk */
214 drv->last_sect = 0;
215 drv->max_track = 0;
216}
217#endif
218
219static int _fd_sector (uint8_t head, uint8_t track,
220 uint8_t sect, uint8_t last_sect)
221{
222 return (((track * 2) + head) * last_sect) + sect - 1;
223}
224
225/* Returns current position, in sectors, for given drive */
226static int fd_sector (fdrive_t *drv)
227{
228 return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
229}
230
231static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
232 int enable_seek)
233{
234 uint32_t sector;
235 int ret;
236
237 if (track > drv->max_track ||
238 (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
239 FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
240 head, track, sect, 1,
241 (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
242 drv->max_track, drv->last_sect);
243 return 2;
244 }
245 if (sect > drv->last_sect) {
246 FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
247 head, track, sect, 1,
248 (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
249 drv->max_track, drv->last_sect);
250 return 3;
251 }
252 sector = _fd_sector(head, track, sect, drv->last_sect);
253 ret = 0;
254 if (sector != fd_sector(drv)) {
255#if 0
256 if (!enable_seek) {
257 FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
258 head, track, sect, 1, drv->max_track, drv->last_sect);
259 return 4;
260 }
261#endif
262 drv->head = head;
263 if (drv->track != track)
264 ret = 1;
265 drv->track = track;
266 drv->sect = sect;
267 }
268
269 return ret;
270}
271
272/* Set drive back to track 0 */
273static void fd_recalibrate (fdrive_t *drv)
274{
275 FLOPPY_DPRINTF("recalibrate\n");
276 drv->head = 0;
277 drv->track = 0;
278 drv->sect = 1;
279 drv->dir = 1;
280 drv->rw = 0;
281}
282
283/* Recognize floppy formats */
284typedef struct fd_format_t {
285 fdrive_type_t drive;
286 fdisk_type_t disk;
287 fdrive_drate_t rate;
288 uint8_t last_sect;
289 uint8_t max_track;
290 uint8_t max_head;
291 const char *str;
292} fd_format_t;
293
294static fd_format_t fd_formats[] = {
295 /* First entry is default format */
296 /* 1.44 MB 3"1/2 floppy disks */
297 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 18, 80, 1, "1.44 MB 3\"1/2", },
298 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 20, 80, 1, "1.6 MB 3\"1/2", },
299 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 21, 80, 1, "1.68 MB 3\"1/2", },
300 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 21, 82, 1, "1.72 MB 3\"1/2", },
301 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 21, 83, 1, "1.74 MB 3\"1/2", },
302 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 22, 80, 1, "1.76 MB 3\"1/2", },
303 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 23, 80, 1, "1.84 MB 3\"1/2", },
304 { FDRIVE_DRV_144, FDRIVE_DISK_144, FDRIVE_RATE_500K, 24, 80, 1, "1.92 MB 3\"1/2", },
305 /* 2.88 MB 3"1/2 floppy disks */
306 { FDRIVE_DRV_288, FDRIVE_DISK_288, FDRIVE_RATE_500K, 36, 80, 1, "2.88 MB 3\"1/2", },
307 { FDRIVE_DRV_288, FDRIVE_DISK_288, FDRIVE_RATE_500K, 39, 80, 1, "3.12 MB 3\"1/2", },
308 { FDRIVE_DRV_288, FDRIVE_DISK_288, FDRIVE_RATE_500K, 40, 80, 1, "3.2 MB 3\"1/2", },
309 { FDRIVE_DRV_288, FDRIVE_DISK_288, FDRIVE_RATE_500K, 44, 80, 1, "3.52 MB 3\"1/2", },
310 { FDRIVE_DRV_288, FDRIVE_DISK_288, FDRIVE_RATE_500K, 48, 80, 1, "3.84 MB 3\"1/2", },
311 /* 720 kB 3"1/2 floppy disks */
312 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 9, 80, 1, "720 kB 3\"1/2", },
313 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 10, 80, 1, "800 kB 3\"1/2", },
314 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 10, 82, 1, "820 kB 3\"1/2", },
315 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 10, 83, 1, "830 kB 3\"1/2", },
316 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 13, 80, 1, "1.04 MB 3\"1/2", },
317 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 14, 80, 1, "1.12 MB 3\"1/2", },
318 /* 1.2 MB 5"1/4 floppy disks */
319 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_500K, 15, 80, 1, "1.2 kB 5\"1/4", },
320 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_500K, 18, 80, 1, "1.44 MB 5\"1/4", },
321 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_500K, 18, 82, 1, "1.48 MB 5\"1/4", },
322 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_500K, 18, 83, 1, "1.49 MB 5\"1/4", },
323 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_500K, 20, 80, 1, "1.6 MB 5\"1/4", },
324 /* 720 kB 5"1/4 floppy disks */
325 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_250K, 9, 80, 1, "720 kB 5\"1/4", },
326 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_250K, 11, 80, 1, "880 kB 5\"1/4", },
327 /* 360 kB 5"1/4 floppy disks */
328 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_300K, 9, 40, 1, "360 kB 5\"1/4", },
329 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_300K, 9, 40, 0, "180 kB 5\"1/4", },
330 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_300K, 10, 41, 1, "410 kB 5\"1/4", },
331 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_300K, 10, 42, 1, "420 kB 5\"1/4", },
332 /* 320 kB 5"1/4 floppy disks */
333 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_250K, 8, 40, 1, "320 kB 5\"1/4", },
334 { FDRIVE_DRV_120, FDRIVE_DISK_288, FDRIVE_RATE_250K, 8, 40, 0, "160 kB 5\"1/4", },
335 /* 360 kB must match 5"1/4 better than 3"1/2... */
336 { FDRIVE_DRV_144, FDRIVE_DISK_720, FDRIVE_RATE_250K, 9, 80, 0, "360 kB 3\"1/2", },
337 /* end */
338 { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, FDRIVE_RATE_1M, -1, -1, 0, NULL, },
339};
340
341/* Revalidate a disk drive after a disk change */
342static void fd_revalidate (fdrive_t *drv)
343{
344 fd_format_t *parse;
345 int64_t nb_sectors, size;
346 int i, first_match, match;
347 int nb_heads, max_track, last_sect, ro;
348
349 FLOPPY_DPRINTF("revalidate\n");
350 drv->drflags &= ~FDRIVE_REVALIDATE;
351#ifndef VBOX
352 if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
353 ro = bdrv_is_read_only(drv->bs);
354 bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
355#else /* VBOX */
356 /** @todo */ /** @todo r=bird: todo what exactly? */
357 if (drv->pDrvBlock
358 && drv->pDrvMount
359 && drv->pDrvMount->pfnIsMounted (drv->pDrvMount)) {
360 ro = drv->pDrvBlock->pfnIsReadOnly (drv->pDrvBlock);
361 nb_heads = 0;
362 max_track = 0;
363 last_sect = 0;
364#endif /* VBOX */
365 if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
366 FLOPPY_DPRINTF("User defined disk (%d %d %d)",
367 nb_heads - 1, max_track, last_sect);
368 } else {
369#ifndef VBOX
370 bdrv_get_geometry(drv->bs, &nb_sectors);
371#else /* VBOX */
372 /* @todo */ /** @todo r=bird: todo what exactly?!?!? */
373 {
374 uint64_t size = drv->pDrvBlock->pfnGetSize (drv->pDrvBlock);
375 nb_sectors = size / 512;
376 }
377#endif /* VBOX */
378 match = -1;
379 first_match = -1;
380 for (i = 0;; i++) {
381 parse = &fd_formats[i];
382 if (parse->drive == FDRIVE_DRV_NONE)
383 break;
384 if (drv->drive == parse->drive ||
385 drv->drive == FDRIVE_DRV_NONE) {
386 size = (parse->max_head + 1) * parse->max_track *
387 parse->last_sect;
388 if (nb_sectors == size) {
389 match = i;
390 break;
391 }
392 if (first_match == -1)
393 first_match = i;
394 }
395 }
396 if (match == -1) {
397 if (first_match == -1)
398 match = 1;
399 else
400 match = first_match;
401 parse = &fd_formats[match];
402 }
403 nb_heads = parse->max_head + 1;
404 max_track = parse->max_track;
405 last_sect = parse->last_sect;
406 drv->drive = parse->drive;
407 FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
408 nb_heads, max_track, last_sect, ro ? "ro" : "rw");
409 }
410 if (nb_heads == 1) {
411 drv->flags &= ~FDISK_DBL_SIDES;
412 } else {
413 drv->flags |= FDISK_DBL_SIDES;
414 }
415 drv->max_track = max_track;
416 drv->last_sect = last_sect;
417 drv->ro = ro;
418#ifdef VBOX
419 drv->media_rate = parse->rate;
420 drv->fMediaPresent = true;
421#endif
422 } else {
423 FLOPPY_DPRINTF("No disk in drive\n");
424 drv->last_sect = 0;
425 drv->max_track = 0;
426 drv->flags &= ~FDISK_DBL_SIDES;
427#ifdef VBOX
428 drv->fMediaPresent = false;
429#endif
430 }
431 drv->drflags |= FDRIVE_REVALIDATE;
432}
433
434/* Motor control */
435static void fd_start (fdrive_t *drv)
436{
437 drv->drflags |= FDRIVE_MOTOR_ON;
438}
439
440static void fd_stop (fdrive_t *drv)
441{
442 drv->drflags &= ~FDRIVE_MOTOR_ON;
443}
444
445/* Re-initialise a drives (motor off, repositioned) */
446static void fd_reset (fdrive_t *drv)
447{
448 fd_stop(drv);
449 fd_recalibrate(drv);
450}
451
452/********************************************************/
453/* Intel 82078 floppy disk controller emulation */
454
455#define target_ulong uint32_t
456static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
457static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
458#ifndef VBOX
459static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len);
460#else /* VBOX: */
461static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
462 void *opaque,
463 unsigned nchan,
464 uint32_t dma_pos,
465 uint32_t dma_len);
466#endif /* VBOX */
467static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
468static void fdctrl_result_timer(void *opaque);
469
470static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
471static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
472static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
473static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
474static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
475static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
476static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
477static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
478static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
479static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
480#ifdef VBOX
481static void fdctrl_write_ccr (fdctrl_t *fdctrl, uint32_t value);
482#endif
483
484enum {
485 FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
486 FD_CTRL_RESET = 0x02,
487 FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */
488 FD_CTRL_BUSY = 0x08, /* dma transfer in progress */
489 FD_CTRL_INTR = 0x10
490};
491
492enum {
493 FD_DIR_WRITE = 0,
494 FD_DIR_READ = 1,
495 FD_DIR_SCANE = 2,
496 FD_DIR_SCANL = 3,
497 FD_DIR_SCANH = 4
498};
499
500enum {
501 FD_STATE_CMD = 0x00,
502 FD_STATE_STATUS = 0x01,
503 FD_STATE_DATA = 0x02,
504 FD_STATE_STATE = 0x03,
505 FD_STATE_MULTI = 0x10,
506 FD_STATE_SEEK = 0x20,
507 FD_STATE_FORMAT = 0x40
508};
509
510#define FD_STATE(state) ((state) & FD_STATE_STATE)
511#define FD_SET_STATE(state, new_state) \
512do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
513#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
514#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
515#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
516
517struct fdctrl_t {
518#ifndef VBOX
519 fdctrl_t *fdctrl;
520#endif
521 /* Controller's identification */
522 uint8_t version;
523 /* HW */
524#ifndef VBOX
525 int irq_lvl;
526 int dma_chann;
527#else
528 uint8_t irq_lvl;
529 uint8_t dma_chann;
530#endif
531 uint32_t io_base;
532 /* Controller state */
533 QEMUTimer *result_timer;
534 uint8_t state;
535 uint8_t dma_en;
536 uint8_t cur_drv;
537 uint8_t bootsel;
538 /* Command FIFO */
539 uint8_t fifo[FD_SECTOR_LEN];
540 uint32_t data_pos;
541 uint32_t data_len;
542 uint8_t data_state;
543 uint8_t data_dir;
544 uint8_t int_status;
545 uint8_t eot; /* last wanted sector */
546 /* States kept only to be returned back */
547 /* Timers state */
548 uint8_t timer0;
549 uint8_t timer1;
550 /* precompensation */
551 uint8_t precomp_trk;
552#ifdef VBOX
553 /* data rate */
554 uint8_t drate;
555#endif
556 uint8_t config;
557 uint8_t lock;
558 /* Power down config (also with status regB access mode */
559 uint8_t pwrd;
560 /* Floppy drives */
561 fdrive_t drives[2];
562#ifdef VBOX
563 /** Pointer to device instance. */
564 PPDMDEVINS pDevIns;
565
566 /** Status Port - The base interface. */
567 PDMIBASE IBaseStatus;
568 /** Status Port - The Leds interface. */
569 PDMILEDPORTS ILeds;
570 /** Status Port - The Partner of ILeds. */
571 PPDMILEDCONNECTORS pLedsConnector;
572#endif
573};
574
575static uint32_t fdctrl_read (void *opaque, uint32_t reg)
576{
577 fdctrl_t *fdctrl = opaque;
578 uint32_t retval;
579
580 switch (reg & 0x07) {
581 case 0x01:
582 retval = fdctrl_read_statusB(fdctrl);
583 break;
584 case 0x02:
585 retval = fdctrl_read_dor(fdctrl);
586 break;
587 case 0x03:
588 retval = fdctrl_read_tape(fdctrl);
589 break;
590 case 0x04:
591 retval = fdctrl_read_main_status(fdctrl);
592 break;
593 case 0x05:
594 retval = fdctrl_read_data(fdctrl);
595 break;
596 case 0x07:
597 retval = fdctrl_read_dir(fdctrl);
598 break;
599 default:
600 retval = (uint32_t)(-1);
601 break;
602 }
603 FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
604
605 return retval;
606}
607
608static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
609{
610 fdctrl_t *fdctrl = opaque;
611
612 FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
613
614 switch (reg & 0x07) {
615 case 0x02:
616 fdctrl_write_dor(fdctrl, value);
617 break;
618 case 0x03:
619 fdctrl_write_tape(fdctrl, value);
620 break;
621 case 0x04:
622 fdctrl_write_rate(fdctrl, value);
623 break;
624 case 0x05:
625 fdctrl_write_data(fdctrl, value);
626 break;
627#ifdef VBOX
628 case 0x07:
629 fdctrl_write_ccr(fdctrl, value);
630 break;
631#endif
632 default:
633 break;
634 }
635}
636
637#ifndef VBOX
638static void fd_change_cb (void *opaque)
639{
640 fdrive_t *drv = opaque;
641
642 FLOPPY_DPRINTF("disk change\n");
643 fd_revalidate(drv);
644#if 0
645 fd_recalibrate(drv);
646 fdctrl_reset_fifo(drv->fdctrl);
647 fdctrl_raise_irq(drv->fdctrl, 0x20);
648#endif
649}
650
651#else /* VBOX */
652/**
653 * Called when a media is mounted.
654 *
655 * @param pInterface Pointer to the interface structure
656 * containing the called function pointer.
657 */
658static DECLCALLBACK(void) fdMountNotify(PPDMIMOUNTNOTIFY pInterface)
659{
660 fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
661 LogFlow(("fdMountNotify:\n"));
662 fd_revalidate (drv);
663}
664
665/**
666 * Called when a media is unmounted
667 * @param pInterface Pointer to the interface structure containing the called function pointer.
668 */
669static DECLCALLBACK(void) fdUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
670{
671 fdrive_t *drv = PDMIMOUNTNOTIFY_2_FDRIVE (pInterface);
672 LogFlow(("fdUnmountNotify:\n"));
673 fd_revalidate (drv);
674}
675#endif
676
677#ifndef VBOX
678fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
679 uint32_t io_base,
680 BlockDriverState **fds)
681{
682 fdctrl_t *fdctrl;
683/* // int io_mem; */
684 int i;
685
686 FLOPPY_DPRINTF("init controller\n");
687 fdctrl = qemu_mallocz(sizeof(fdctrl_t));
688 if (!fdctrl)
689 return NULL;
690 fdctrl->result_timer = qemu_new_timer(vm_clock,
691 fdctrl_result_timer, fdctrl);
692
693 fdctrl->version = 0x90; /* Intel 82078 controller */
694 fdctrl->irq_lvl = irq_lvl;
695 fdctrl->dma_chann = dma_chann;
696 fdctrl->io_base = io_base;
697 fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
698 if (fdctrl->dma_chann != -1) {
699 fdctrl->dma_en = 1;
700 DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
701 } else {
702 fdctrl->dma_en = 0;
703 }
704 for (i = 0; i < 2; i++) {
705 fd_init(&fdctrl->drives[i], fds[i]);
706 if (fds[i]) {
707 bdrv_set_change_cb(fds[i],
708 &fd_change_cb, &fdctrl->drives[i]);
709 }
710 }
711 fdctrl_reset(fdctrl, 0);
712 fdctrl->state = FD_CTRL_ACTIVE;
713 if (mem_mapped) {
714 FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
715#if 0
716 io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
717 cpu_register_physical_memory(base, 0x08, io_mem);
718#endif
719 } else {
720 register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
721 register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
722 register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
723 register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
724 }
725 for (i = 0; i < 2; i++) {
726 fd_revalidate(&fdctrl->drives[i]);
727 }
728
729 return fdctrl;
730}
731
732/* XXX: may change if moved to bdrv */
733int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
734{
735 return fdctrl->drives[drive_num].drive;
736}
737#endif
738
739/* Change IRQ state */
740static void fdctrl_reset_irq (fdctrl_t *fdctrl)
741{
742 FLOPPY_DPRINTF("Reset interrupt\n");
743#ifdef VBOX
744 fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
745 fdctrl->irq_lvl, 0);
746#else
747 pic_set_irq(fdctrl->irq_lvl, 0);
748#endif
749 fdctrl->state &= ~FD_CTRL_INTR;
750}
751
752static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
753{
754 if (~(fdctrl->state & FD_CTRL_INTR)) {
755#ifdef VBOX
756 fdctrl->pDevIns->pDevHlp->pfnISASetIrq (fdctrl->pDevIns,
757 fdctrl->irq_lvl, 1);
758#else
759 pic_set_irq(fdctrl->irq_lvl, 1);
760#endif
761 fdctrl->state |= FD_CTRL_INTR;
762 }
763 FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
764 fdctrl->int_status = status;
765}
766
767/* Reset controller */
768static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
769{
770 int i;
771
772 FLOPPY_DPRINTF("reset controller\n");
773 fdctrl_reset_irq(fdctrl);
774 /* Initialise controller */
775 fdctrl->cur_drv = 0;
776#ifdef VBOX
777 fdctrl->drate = 2; /* Default to 250 Kbps*/
778#endif
779 /* FIFO state */
780 fdctrl->data_pos = 0;
781 fdctrl->data_len = 0;
782 fdctrl->data_state = FD_STATE_CMD;
783 fdctrl->data_dir = FD_DIR_WRITE;
784 for (i = 0; i < MAX_FD; i++)
785 fd_reset(&fdctrl->drives[i]);
786 fdctrl_reset_fifo(fdctrl);
787 if (do_irq)
788 fdctrl_raise_irq(fdctrl, 0xc0);
789}
790
791static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
792{
793 return &fdctrl->drives[fdctrl->bootsel];
794}
795
796static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
797{
798 return &fdctrl->drives[1 - fdctrl->bootsel];
799}
800
801static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
802{
803 return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
804}
805
806/* Status B register : 0x01 (read-only) */
807static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
808{
809 FLOPPY_DPRINTF("status register: 0x00\n");
810 return 0;
811}
812
813/* Digital output register : 0x02 */
814static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
815{
816 uint32_t retval = 0;
817
818 /* Drive motors state indicators */
819#ifndef VBOX
820 if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
821 retval |= 1 << 5;
822 if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
823 retval |= 1 << 4;
824#else
825 /* bit4: 0 = drive 0 motor off/1 = on */
826 if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
827 retval |= BIT(4);
828 /* bit5: 0 = drive 1 motor off/1 = on */
829 if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
830 retval |= BIT(5);
831#endif
832 /* DMA enable */
833 retval |= fdctrl->dma_en << 3;
834 /* Reset indicator */
835 retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
836 /* Selected drive */
837 retval |= fdctrl->cur_drv;
838 FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
839
840 return retval;
841}
842
843static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
844{
845 /* Reset mode */
846 if (fdctrl->state & FD_CTRL_RESET) {
847 if (!(value & 0x04)) {
848 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
849 return;
850 }
851 }
852 FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
853 /* Drive motors state indicators */
854 if (value & 0x20)
855 fd_start(drv1(fdctrl));
856 else
857 fd_stop(drv1(fdctrl));
858 if (value & 0x10)
859 fd_start(drv0(fdctrl));
860 else
861 fd_stop(drv0(fdctrl));
862 /* DMA enable */
863#if 0
864 if (fdctrl->dma_chann != -1)
865 fdctrl->dma_en = 1 - ((value >> 3) & 1);
866#endif
867 /* Reset */
868 if (!(value & 0x04)) {
869 if (!(fdctrl->state & FD_CTRL_RESET)) {
870 FLOPPY_DPRINTF("controller enter RESET state\n");
871 fdctrl->state |= FD_CTRL_RESET;
872 }
873 } else {
874 if (fdctrl->state & FD_CTRL_RESET) {
875 FLOPPY_DPRINTF("controller out of RESET state\n");
876 fdctrl_reset(fdctrl, 1);
877 fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
878 }
879 }
880 /* Selected drive */
881 fdctrl->cur_drv = value & 1;
882}
883
884/* Tape drive register : 0x03 */
885static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
886{
887 uint32_t retval = 0;
888
889 /* Disk boot selection indicator */
890 retval |= fdctrl->bootsel << 2;
891 /* Tape indicators: never allowed */
892 FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
893
894 return retval;
895}
896
897static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
898{
899 /* Reset mode */
900 if (fdctrl->state & FD_CTRL_RESET) {
901 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
902 return;
903 }
904 FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
905 /* Disk boot selection indicator */
906 fdctrl->bootsel = (value >> 2) & 1;
907 /* Tape indicators: never allow */
908}
909
910/* Main status register : 0x04 (read) */
911static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
912{
913 uint32_t retval = 0;
914
915 fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
916 if (!(fdctrl->state & FD_CTRL_BUSY)) {
917 /* Data transfer allowed */
918 retval |= 0x80;
919 /* Data transfer direction indicator */
920 if (fdctrl->data_dir == FD_DIR_READ)
921 retval |= 0x40;
922 }
923 /* Should handle 0x20 for SPECIFY command */
924 /* Command busy indicator */
925 if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
926 FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
927 retval |= 0x10;
928 FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
929
930 return retval;
931}
932
933/* Data select rate register : 0x04 (write) */
934static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
935{
936 /* Reset mode */
937 if (fdctrl->state & FD_CTRL_RESET) {
938 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
939 return;
940 }
941 FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
942 /* Reset: autoclear */
943 if (value & 0x80) {
944 fdctrl->state |= FD_CTRL_RESET;
945 fdctrl_reset(fdctrl, 1);
946 fdctrl->state &= ~FD_CTRL_RESET;
947 }
948 if (value & 0x40) {
949 fdctrl->state |= FD_CTRL_SLEEP;
950 fdctrl_reset(fdctrl, 1);
951 }
952/* // fdctrl.precomp = (value >> 2) & 0x07; */
953#ifdef VBOX
954 fdctrl->drate = value & 0x03;
955#endif
956}
957
958/* Digital input register : 0x07 (read-only) */
959static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
960{
961 uint32_t retval = 0;
962
963#ifndef VBOX
964 if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
965 drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
966#else
967 fdrive_t *cur_drv = get_cur_drv(fdctrl);
968 if ( drv0(fdctrl)->drflags & FDRIVE_REVALIDATE
969 || drv1(fdctrl)->drflags & FDRIVE_REVALIDATE
970 || !cur_drv->fMediaPresent)
971#endif
972 retval |= 0x80;
973 if (retval != 0)
974 FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
975 drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
976 drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
977
978 return retval;
979}
980
981#ifdef VBOX
982/* Configuration control register : 0x07 (write) */
983static void fdctrl_write_ccr (fdctrl_t *fdctrl, uint32_t value)
984{
985 FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);
986 fdctrl->drate = value & 0x03;
987}
988#endif
989
990/* FIFO state control */
991static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
992{
993 fdctrl->data_dir = FD_DIR_WRITE;
994 fdctrl->data_pos = 0;
995 FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
996}
997
998/* Set FIFO status for the host to read */
999static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
1000{
1001 fdctrl->data_dir = FD_DIR_READ;
1002 fdctrl->data_len = fifo_len;
1003 fdctrl->data_pos = 0;
1004 FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
1005 if (do_irq)
1006 fdctrl_raise_irq(fdctrl, 0x00);
1007}
1008
1009/* Set an error: unimplemented/unknown command */
1010static void fdctrl_unimplemented (fdctrl_t *fdctrl)
1011{
1012#if 0
1013 fdrive_t *cur_drv;
1014
1015 cur_drv = get_cur_drv(fdctrl);
1016 fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
1017 fdctrl->fifo[1] = 0x00;
1018 fdctrl->fifo[2] = 0x00;
1019 fdctrl_set_fifo(fdctrl, 3, 1);
1020#else
1021 /* // fdctrl_reset_fifo(fdctrl); */
1022 fdctrl->fifo[0] = 0x80;
1023 fdctrl_set_fifo(fdctrl, 1, 0);
1024#endif
1025}
1026
1027/* Callback for transfer end (stop or abort) */
1028static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
1029 uint8_t status1, uint8_t status2)
1030{
1031 fdrive_t *cur_drv;
1032
1033 cur_drv = get_cur_drv(fdctrl);
1034 FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
1035 status0, status1, status2,
1036 status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
1037 fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
1038 fdctrl->fifo[1] = status1;
1039 fdctrl->fifo[2] = status2;
1040 fdctrl->fifo[3] = cur_drv->track;
1041 fdctrl->fifo[4] = cur_drv->head;
1042 fdctrl->fifo[5] = cur_drv->sect;
1043 fdctrl->fifo[6] = FD_SECTOR_SC;
1044 fdctrl->data_dir = FD_DIR_READ;
1045 if (fdctrl->state & FD_CTRL_BUSY) {
1046#ifdef VBOX
1047 fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
1048 fdctrl->dma_chann,
1049 0);
1050#else
1051 DMA_release_DREQ(fdctrl->dma_chann);
1052#endif
1053 fdctrl->state &= ~FD_CTRL_BUSY;
1054 }
1055 fdctrl_set_fifo(fdctrl, 7, 1);
1056}
1057
1058/* Prepare a data transfer (either DMA or FIFO) */
1059static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
1060{
1061 fdrive_t *cur_drv;
1062 uint8_t kh, kt, ks;
1063 int did_seek;
1064
1065 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1066 cur_drv = get_cur_drv(fdctrl);
1067 kt = fdctrl->fifo[2];
1068 kh = fdctrl->fifo[3];
1069 ks = fdctrl->fifo[4];
1070 FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
1071 fdctrl->cur_drv, kh, kt, ks,
1072 _fd_sector(kh, kt, ks, cur_drv->last_sect));
1073 did_seek = 0;
1074 switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1075 case 2:
1076 /* sect too big */
1077 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1078 fdctrl->fifo[3] = kt;
1079 fdctrl->fifo[4] = kh;
1080 fdctrl->fifo[5] = ks;
1081 return;
1082 case 3:
1083 /* track too big */
1084 fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1085 fdctrl->fifo[3] = kt;
1086 fdctrl->fifo[4] = kh;
1087 fdctrl->fifo[5] = ks;
1088 return;
1089 case 4:
1090 /* No seek enabled */
1091 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1092 fdctrl->fifo[3] = kt;
1093 fdctrl->fifo[4] = kh;
1094 fdctrl->fifo[5] = ks;
1095 return;
1096 case 1:
1097 did_seek = 1;
1098 break;
1099 default:
1100 break;
1101 }
1102#ifdef VBOX
1103 /* Check that selected data rate is correct.
1104 * NB: Software may deduce media type from selected data rate, eg. 250Kbps
1105 * in a 3.5" drive implies 720KB media, while 500Kbps implies 1.44MB.
1106 */
1107 if (fdctrl->drate != cur_drv->media_rate) {
1108 FLOPPY_DPRINTF("Data rate mismatch (controller 0x%02x, media 0x%02x)\n", fdctrl->drate, cur_drv->media_rate);
1109 fdctrl_stop_transfer(fdctrl, 0x40, 0x04, 0x00);
1110 fdctrl->fifo[3] = kt;
1111 fdctrl->fifo[4] = kh;
1112 fdctrl->fifo[5] = ks;
1113 return;
1114 }
1115#endif
1116 /* Set the FIFO state */
1117 fdctrl->data_dir = direction;
1118 fdctrl->data_pos = 0;
1119 FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
1120 if (fdctrl->fifo[0] & 0x80)
1121 fdctrl->data_state |= FD_STATE_MULTI;
1122 else
1123 fdctrl->data_state &= ~FD_STATE_MULTI;
1124 if (did_seek)
1125 fdctrl->data_state |= FD_STATE_SEEK;
1126 else
1127 fdctrl->data_state &= ~FD_STATE_SEEK;
1128 if (fdctrl->fifo[5] == 00) {
1129 fdctrl->data_len = fdctrl->fifo[8];
1130 } else {
1131 int tmp;
1132 fdctrl->data_len = 128 << fdctrl->fifo[5];
1133 tmp = (cur_drv->last_sect - ks + 1);
1134 if (fdctrl->fifo[0] & 0x80)
1135 tmp += cur_drv->last_sect;
1136 fdctrl->data_len *= tmp;
1137 }
1138 fdctrl->eot = fdctrl->fifo[6];
1139 if (fdctrl->dma_en) {
1140 int dma_mode;
1141 /* DMA transfer are enabled. Check if DMA channel is well programmed */
1142#ifndef VBOX
1143 dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
1144#else
1145 dma_mode = fdctrl->pDevIns->pDevHlp->pfnDMAGetChannelMode (
1146 fdctrl->pDevIns,
1147 fdctrl->dma_chann
1148 );
1149#endif
1150 dma_mode = (dma_mode >> 2) & 3;
1151 FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1152 dma_mode, direction,
1153 (128 << fdctrl->fifo[5]) *
1154 (cur_drv->last_sect - ks + 1), fdctrl->data_len);
1155 if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
1156 direction == FD_DIR_SCANH) && dma_mode == 0) ||
1157 (direction == FD_DIR_WRITE && dma_mode == 2) ||
1158 (direction == FD_DIR_READ && dma_mode == 1)) {
1159 /* No access is allowed until DMA transfer has completed */
1160 fdctrl->state |= FD_CTRL_BUSY;
1161 /* Now, we just have to wait for the DMA controller to
1162 * recall us...
1163 */
1164#ifndef VBOX
1165 DMA_hold_DREQ(fdctrl->dma_chann);
1166 DMA_schedule(fdctrl->dma_chann);
1167#else
1168 fdctrl->pDevIns->pDevHlp->pfnDMASetDREQ (fdctrl->pDevIns,
1169 fdctrl->dma_chann,
1170 1);
1171 fdctrl->pDevIns->pDevHlp->pfnDMASchedule (fdctrl->pDevIns);
1172#endif
1173 return;
1174 } else {
1175 FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
1176 }
1177 }
1178 FLOPPY_DPRINTF("start non-DMA transfer\n");
1179 /* IO based transfer: calculate len */
1180 fdctrl_raise_irq(fdctrl, 0x00);
1181
1182 return;
1183}
1184
1185/* Prepare a transfer of deleted data */
1186static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
1187{
1188 /* We don't handle deleted data,
1189 * so we don't return *ANYTHING*
1190 */
1191 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1192}
1193
1194#if 0
1195#include <stdio.h>
1196#include <stdlib.h>
1197
1198static FILE * f;
1199static void dump (void *p, size_t len)
1200{
1201 size_t n;
1202
1203 if (!f) {
1204 f = fopen ("dump", "wb");
1205 if (!f)
1206 exit (0);
1207 }
1208
1209 n = fwrite (p, len, 1, f);
1210 if (n != 1) {
1211 AssertMsgFailed (("failed to dump\n"));
1212 exit (0);
1213 }
1214}
1215#else
1216#define dump(a,b) do { } while (0)
1217#endif
1218
1219/* handlers for DMA transfers */
1220#ifdef VBOX
1221static DECLCALLBACK(uint32_t) fdctrl_transfer_handler (PPDMDEVINS pDevIns,
1222 void *opaque,
1223 unsigned nchan,
1224 uint32_t dma_pos,
1225 uint32_t dma_len)
1226#else
1227static int fdctrl_transfer_handler (void *opaque, int nchan,
1228 int dma_pos, int dma_len)
1229#endif
1230{
1231 fdctrl_t *fdctrl;
1232 fdrive_t *cur_drv;
1233#ifdef VBOX
1234 int rc;
1235 uint32_t len, start_pos, rel_pos;
1236#else
1237 int len, start_pos, rel_pos;
1238#endif
1239 uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1240
1241 fdctrl = opaque;
1242 if (!(fdctrl->state & FD_CTRL_BUSY)) {
1243 FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1244 return 0;
1245 }
1246 cur_drv = get_cur_drv(fdctrl);
1247 if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1248 fdctrl->data_dir == FD_DIR_SCANH)
1249 status2 = 0x04;
1250 if (dma_len > fdctrl->data_len)
1251 dma_len = fdctrl->data_len;
1252#ifndef VBOX
1253 if (cur_drv->bs == NULL) {
1254#else /* !VBOX */
1255 if (cur_drv->pDrvBlock == NULL) {
1256#endif
1257 if (fdctrl->data_dir == FD_DIR_WRITE)
1258 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1259 else
1260 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1261 len = 0;
1262 goto transfer_error;
1263 }
1264 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1265 for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1266 len = dma_len - fdctrl->data_pos;
1267 if (len + rel_pos > FD_SECTOR_LEN)
1268 len = FD_SECTOR_LEN - rel_pos;
1269 FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1270 "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
1271 fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1272 cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1273 fd_sector(cur_drv) * 512);
1274 if (fdctrl->data_dir != FD_DIR_WRITE ||
1275 len < FD_SECTOR_LEN || rel_pos != 0) {
1276 /* READ & SCAN commands and realign to a sector for WRITE */
1277#ifndef VBOX
1278 if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1279 fdctrl->fifo, 1) < 0) {
1280 FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1281 fd_sector(cur_drv));
1282 /* Sure, image size is too small... */
1283 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1284 }
1285#else
1286 cur_drv->Led.Asserted.s.fReading
1287 = cur_drv->Led.Actual.s.fReading = 1;
1288
1289 rc = cur_drv->pDrvBlock->pfnRead (
1290 cur_drv->pDrvBlock,
1291 fd_sector (cur_drv) * 512,
1292 fdctrl->fifo,
1293 1 * 512
1294 );
1295
1296 cur_drv->Led.Actual.s.fReading = 0;
1297
1298 if (VBOX_FAILURE (rc)) {
1299 AssertMsgFailed (
1300 ("Floppy: error getting sector %d, rc = %Vrc",
1301 fd_sector (cur_drv), rc));
1302 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1303 }
1304#endif
1305 }
1306 switch (fdctrl->data_dir) {
1307 case FD_DIR_READ:
1308 /* READ commands */
1309#ifdef VBOX
1310 {
1311 uint32_t read;
1312 int rc = fdctrl->pDevIns->pDevHlp->pfnDMAWriteMemory(
1313 fdctrl->pDevIns,
1314 nchan,
1315 fdctrl->fifo + rel_pos,
1316 fdctrl->data_pos,
1317 len,
1318 &read);
1319 dump (fdctrl->fifo + rel_pos, len);
1320 AssertMsgRC (rc,
1321 ("DMAWriteMemory -> %Vrc\n", rc));
1322 }
1323#else
1324 DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
1325 fdctrl->data_pos, len);
1326#endif
1327/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
1328/* fdctrl->fifo + rel_pos, len); */
1329 break;
1330 case FD_DIR_WRITE:
1331 /* WRITE commands */
1332#ifdef VBOX
1333 {
1334 uint32_t written;
1335 int rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory(
1336 fdctrl->pDevIns,
1337 nchan,
1338 fdctrl->fifo + rel_pos,
1339 fdctrl->data_pos,
1340 len,
1341 &written);
1342 AssertMsgRC (rc,
1343 ("DMAReadMemory -> %Vrc\n", rc));
1344 }
1345#else
1346 DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
1347 fdctrl->data_pos, len);
1348#endif
1349/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1350/* fdctrl->fifo + rel_pos, len); */
1351#ifndef VBOX
1352 if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1353 fdctrl->fifo, 1) < 0) {
1354 FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1355 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1356 goto transfer_error;
1357 }
1358#else /* VBOX */
1359 cur_drv->Led.Asserted.s.fWriting
1360 = cur_drv->Led.Actual.s.fWriting = 1;
1361
1362 rc = cur_drv->pDrvBlock->pfnWrite (
1363 cur_drv->pDrvBlock,
1364 fd_sector (cur_drv) * 512,
1365 fdctrl->fifo,
1366 1 * 512
1367 );
1368
1369 cur_drv->Led.Actual.s.fWriting = 0;
1370
1371 if (VBOX_FAILURE (rc)) {
1372 AssertMsgFailed (("Floppy: error writing sector %d. rc=%Vrc",
1373 fd_sector (cur_drv), rc));
1374 fdctrl_stop_transfer (fdctrl, 0x60, 0x00, 0x00);
1375 goto transfer_error;
1376 }
1377#endif
1378 break;
1379 default:
1380 /* SCAN commands */
1381 {
1382 uint8_t tmpbuf[FD_SECTOR_LEN];
1383 int ret;
1384#ifdef VBOX
1385 int rc;
1386 uint32_t read;
1387
1388 rc = fdctrl->pDevIns->pDevHlp->pfnDMAReadMemory (
1389 fdctrl->pDevIns,
1390 nchan,
1391 tmpbuf,
1392 fdctrl->data_pos,
1393 len,
1394 &read);
1395 AssertMsg (VBOX_SUCCESS (rc),
1396 ("DMAReadMemory -> %Vrc\n", rc));
1397#else
1398 DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1399#endif
1400/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
1401/* tmpbuf, len); */
1402 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1403 if (ret == 0) {
1404 status2 = 0x08;
1405 goto end_transfer;
1406 }
1407 if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1408 (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1409 status2 = 0x00;
1410 goto end_transfer;
1411 }
1412 }
1413 break;
1414 }
1415 fdctrl->data_pos += len;
1416 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1417 if (rel_pos == 0) {
1418 /* Seek to next sector */
1419 FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1420 cur_drv->head, cur_drv->track, cur_drv->sect,
1421 fd_sector(cur_drv),
1422 fdctrl->data_pos - len);
1423 /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1424 error in fact */
1425 if (cur_drv->sect >= cur_drv->last_sect ||
1426 cur_drv->sect == fdctrl->eot) {
1427 cur_drv->sect = 1;
1428 if (FD_MULTI_TRACK(fdctrl->data_state)) {
1429 if (cur_drv->head == 0 &&
1430 (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1431 cur_drv->head = 1;
1432 } else {
1433 cur_drv->head = 0;
1434 cur_drv->track++;
1435 if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1436 break;
1437 }
1438 } else {
1439 cur_drv->track++;
1440 break;
1441 }
1442 FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1443 cur_drv->head, cur_drv->track,
1444 cur_drv->sect, fd_sector(cur_drv));
1445 } else {
1446 cur_drv->sect++;
1447 }
1448 }
1449 }
1450end_transfer:
1451 len = fdctrl->data_pos - start_pos;
1452 FLOPPY_DPRINTF("end transfer %d %d %d\n",
1453 fdctrl->data_pos, len, fdctrl->data_len);
1454 if (fdctrl->data_dir == FD_DIR_SCANE ||
1455 fdctrl->data_dir == FD_DIR_SCANL ||
1456 fdctrl->data_dir == FD_DIR_SCANH)
1457 status2 = 0x08;
1458 if (FD_DID_SEEK(fdctrl->data_state))
1459 status0 |= 0x20;
1460 fdctrl->data_len -= len;
1461 /* if (fdctrl->data_len == 0) */
1462 fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1463transfer_error:
1464
1465 return len;
1466}
1467
1468#if 0
1469{
1470 fdctrl_t *fdctrl;
1471 fdrive_t *cur_drv;
1472 int len, start_pos, rel_pos;
1473 uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1474
1475 fdctrl = opaque;
1476 if (!(fdctrl->state & FD_CTRL_BUSY)) {
1477 FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1478 return 0;
1479 }
1480 cur_drv = get_cur_drv(fdctrl);
1481 if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1482 fdctrl->data_dir == FD_DIR_SCANH)
1483 status2 = 0x04;
1484 if (size > fdctrl->data_len)
1485 size = fdctrl->data_len;
1486#ifndef VBOX
1487 if (cur_drv->bs == NULL) {
1488#else
1489 if (cur_drv->pDrvBase == NULL) {
1490#endif
1491 if (fdctrl->data_dir == FD_DIR_WRITE)
1492 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1493 else
1494 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1495 len = 0;
1496 goto transfer_error;
1497 }
1498 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1499 for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) {
1500 len = size - fdctrl->data_pos;
1501 if (len + rel_pos > FD_SECTOR_LEN)
1502 len = FD_SECTOR_LEN - rel_pos;
1503 FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
1504 "(%d-0x%08x 0x%08x)\n", len, size, fdctrl->data_pos,
1505 fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
1506 cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1507 fd_sector(cur_drv) * 512, addr);
1508 if (fdctrl->data_dir != FD_DIR_WRITE ||
1509 len < FD_SECTOR_LEN || rel_pos != 0) {
1510 /* READ & SCAN commands and realign to a sector for WRITE */
1511#ifndef VBOX
1512 if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1513 fdctrl->fifo, 1) < 0) {
1514 FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1515 fd_sector(cur_drv));
1516 /* Sure, image size is too small... */
1517 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1518 }
1519#else
1520 int rc;
1521
1522 cur_drv->Led.Asserted.s.fReading
1523 = cur_drv->Led.Actual.s.fReading = 1;
1524
1525 rc = cur_drv->pDrvBlock->pfnRead (
1526 cur_drv->pDrvBlock,
1527 fd_sector (cur_drv) * 512,
1528 fdctrl->fifo,
1529 1 * 512
1530 );
1531
1532 cur_drv->Led.Actual.s.fReading = 0;
1533
1534 if (VBOX_FAILURE (rc)) {
1535 AssertMsgFailed (
1536 ("Floppy: error getting sector %d. rc=%Vrc\n",
1537 fd_sector(cur_drv), rc));
1538 /* Sure, image size is too small... */
1539 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1540 }
1541 /* *p_fd_activity = 1; */
1542#endif
1543 }
1544 switch (fdctrl->data_dir) {
1545 case FD_DIR_READ:
1546 /* READ commands */
1547#ifdef VBOX
1548 fdctrl->pDevIns->pDevHlp->pfnPhysWrite (
1549 fdctrl->pDevIns,
1550 addr + fdctrl->data_pos,
1551 fdctrl->fifo + rel_pos,
1552 len);
1553#else
1554 cpu_physical_memory_write(addr + fdctrl->data_pos,
1555 fdctrl->fifo + rel_pos, len);
1556#endif
1557 break;
1558 case FD_DIR_WRITE:
1559 /* WRITE commands */
1560#ifdef VBOX
1561 {
1562 int rc;
1563
1564 fdctrl->pDevIns->pDevHlp->pfnPhysRead (
1565 fdctrl->pDevIns,
1566 addr + fdctrl->data_pos,
1567 fdctrl->fifo + rel_pos,
1568 len);
1569
1570 cur_drv->Led.Asserted.s.fWriting
1571 = cur_drv->Led.Actual.s.fWriting = 1;
1572
1573 rc = cur_drv->pDrvBlock->pfnWrite (
1574 cur_drv->pDrvBlock,
1575 fd_sector (cur_drv) * 512,
1576 fdctrl->fifo,
1577 1 * 512
1578 );
1579
1580 cur_drv->Led.Actual.s.fWriting = 0;
1581
1582 if (VBOX_FAILURE (rc)) {
1583 AssertMsgFailed (
1584 ("Floppy: error writting sector %d. rc=%Vrc\n",
1585 fd_sector(cur_drv), rc));
1586 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1587 goto transfer_error;
1588 }
1589 }
1590 /* *p_fd_activity = 2; */
1591#else /* !VBOX */
1592 cpu_physical_memory_read(addr + fdctrl->data_pos,
1593 fdctrl->fifo + rel_pos, len);
1594 if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1595 fdctrl->fifo, 1) < 0) {
1596 FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
1597 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1598 goto transfer_error;
1599 }
1600#endif
1601 break;
1602 default:
1603 /* SCAN commands */
1604 {
1605 uint8_t tmpbuf[FD_SECTOR_LEN];
1606 int ret;
1607#ifdef VBOX
1608 fdctrl->pDevIns->pDevHlp->pfnPhysRead (
1609 fdctrl->pDevIns,
1610 addr + fdctrl->data_pos,
1611 tmpbuf,
1612 len);
1613#else
1614 cpu_physical_memory_read(addr + fdctrl->data_pos,
1615 tmpbuf, len);
1616#endif
1617 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1618 if (ret == 0) {
1619 status2 = 0x08;
1620 goto end_transfer;
1621 }
1622 if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1623 (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1624 status2 = 0x00;
1625 goto end_transfer;
1626 }
1627 }
1628 break;
1629 }
1630 fdctrl->data_pos += len;
1631 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1632 if (rel_pos == 0) {
1633 /* Seek to next sector */
1634 FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
1635 cur_drv->head, cur_drv->track, cur_drv->sect,
1636 fd_sector(cur_drv),
1637 fdctrl->data_pos - size);
1638 /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
1639 error in fact */
1640 if (cur_drv->sect >= cur_drv->last_sect ||
1641 cur_drv->sect == fdctrl->eot) {
1642 cur_drv->sect = 1;
1643 if (FD_MULTI_TRACK(fdctrl->data_state)) {
1644 if (cur_drv->head == 0 &&
1645 (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
1646 cur_drv->head = 1;
1647 } else {
1648 cur_drv->head = 0;
1649 cur_drv->track++;
1650 if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
1651 break;
1652 }
1653 } else {
1654 cur_drv->track++;
1655 break;
1656 }
1657 FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
1658 cur_drv->head, cur_drv->track,
1659 cur_drv->sect, fd_sector(cur_drv));
1660 } else {
1661 cur_drv->sect++;
1662 }
1663 }
1664 }
1665end_transfer:
1666 len = fdctrl->data_pos - start_pos;
1667 FLOPPY_DPRINTF("end transfer %d %d %d\n",
1668 fdctrl->data_pos, len, fdctrl->data_len);
1669 if (fdctrl->data_dir == FD_DIR_SCANE ||
1670 fdctrl->data_dir == FD_DIR_SCANL ||
1671 fdctrl->data_dir == FD_DIR_SCANH)
1672 status2 = 0x08;
1673 if (FD_DID_SEEK(fdctrl->data_state))
1674 status0 |= 0x20;
1675 fdctrl->data_len -= len;
1676 /* // if (fdctrl->data_len == 0) */
1677 fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1678transfer_error:
1679
1680 return len;
1681}
1682#endif
1683
1684/* Data register : 0x05 */
1685static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
1686{
1687 fdrive_t *cur_drv;
1688 uint32_t retval = 0;
1689 int pos, len;
1690#ifdef VBOX
1691 int rc;
1692#endif
1693
1694 cur_drv = get_cur_drv(fdctrl);
1695 fdctrl->state &= ~FD_CTRL_SLEEP;
1696 if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
1697 FLOPPY_ERROR("can't read data in CMD state\n");
1698 return 0;
1699 }
1700 pos = fdctrl->data_pos;
1701 if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1702 pos %= FD_SECTOR_LEN;
1703 if (pos == 0) {
1704 len = fdctrl->data_len - fdctrl->data_pos;
1705 if (len > FD_SECTOR_LEN)
1706 len = FD_SECTOR_LEN;
1707#ifdef VBOX
1708 cur_drv->Led.Asserted.s.fReading
1709 = cur_drv->Led.Actual.s.fReading = 1;
1710
1711 rc = cur_drv->pDrvBlock->pfnRead (
1712 cur_drv->pDrvBlock,
1713 fd_sector (cur_drv) * 512,
1714 fdctrl->fifo,
1715 len * 512
1716 );
1717
1718 cur_drv->Led.Actual.s.fReading = 0;
1719
1720 if (VBOX_FAILURE (rc)) {
1721 AssertMsgFailed (
1722 ("Floppy: Failure to read sector %d. rc=%Vrc",
1723 fd_sector (cur_drv), rc));
1724 }
1725#else
1726 bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1727 fdctrl->fifo, len);
1728#endif
1729 }
1730 }
1731 retval = fdctrl->fifo[pos];
1732 if (++fdctrl->data_pos == fdctrl->data_len) {
1733 fdctrl->data_pos = 0;
1734 /* Switch from transfer mode to status mode
1735 * then from status mode to command mode
1736 */
1737 if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1738 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1739 } else {
1740 fdctrl_reset_fifo(fdctrl);
1741 fdctrl_reset_irq(fdctrl);
1742 }
1743 }
1744 FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1745
1746 return retval;
1747}
1748
1749static void fdctrl_format_sector (fdctrl_t *fdctrl)
1750{
1751 fdrive_t *cur_drv;
1752 uint8_t kh, kt, ks;
1753 int did_seek;
1754#ifdef VBOX
1755 int ok = 0, rc;
1756#endif
1757
1758 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1759 cur_drv = get_cur_drv(fdctrl);
1760 kt = fdctrl->fifo[6];
1761 kh = fdctrl->fifo[7];
1762 ks = fdctrl->fifo[8];
1763 FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1764 fdctrl->cur_drv, kh, kt, ks,
1765 _fd_sector(kh, kt, ks, cur_drv->last_sect));
1766 did_seek = 0;
1767 switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
1768 case 2:
1769 /* sect too big */
1770 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1771 fdctrl->fifo[3] = kt;
1772 fdctrl->fifo[4] = kh;
1773 fdctrl->fifo[5] = ks;
1774 return;
1775 case 3:
1776 /* track too big */
1777 fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
1778 fdctrl->fifo[3] = kt;
1779 fdctrl->fifo[4] = kh;
1780 fdctrl->fifo[5] = ks;
1781 return;
1782 case 4:
1783 /* No seek enabled */
1784 fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
1785 fdctrl->fifo[3] = kt;
1786 fdctrl->fifo[4] = kh;
1787 fdctrl->fifo[5] = ks;
1788 return;
1789 case 1:
1790 did_seek = 1;
1791 fdctrl->data_state |= FD_STATE_SEEK;
1792 break;
1793 default:
1794 break;
1795 }
1796 memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1797#ifdef VBOX
1798 /* *p_fd_activity = 2; */
1799 if (cur_drv->pDrvBlock) {
1800 cur_drv->Led.Asserted.s.fWriting = cur_drv->Led.Actual.s.fWriting = 1;
1801
1802 rc = cur_drv->pDrvBlock->pfnWrite (
1803 cur_drv->pDrvBlock,
1804 fd_sector (cur_drv) * 512,
1805 fdctrl->fifo,
1806 1 * 512
1807 );
1808
1809 cur_drv->Led.Actual.s.fWriting = 0;
1810
1811 if (VBOX_FAILURE (rc)) {
1812 AssertMsgFailed (("Floppy: error formating sector %d. rc=%Vrc\n",
1813 fd_sector (cur_drv), rc));
1814 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1815 }
1816 else {
1817 ok = 1;
1818 }
1819 }
1820 if (ok) {
1821#else
1822 if (cur_drv->bs == NULL ||
1823 bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1824 FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));
1825 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1826 } else {
1827#endif
1828 if (cur_drv->sect == cur_drv->last_sect) {
1829 fdctrl->data_state &= ~FD_STATE_FORMAT;
1830 /* Last sector done */
1831 if (FD_DID_SEEK(fdctrl->data_state))
1832 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1833 else
1834 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1835 } else {
1836 /* More to do */
1837 fdctrl->data_pos = 0;
1838 fdctrl->data_len = 4;
1839 }
1840 }
1841}
1842
1843static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1844{
1845 fdrive_t *cur_drv;
1846
1847 cur_drv = get_cur_drv(fdctrl);
1848 /* Reset mode */
1849 if (fdctrl->state & FD_CTRL_RESET) {
1850 FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1851 return;
1852 }
1853 fdctrl->state &= ~FD_CTRL_SLEEP;
1854 if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1855 FLOPPY_ERROR("can't write data in status mode\n");
1856 return;
1857 }
1858 /* Is it write command time ? */
1859 if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1860 /* FIFO data write */
1861 fdctrl->fifo[fdctrl->data_pos++] = value;
1862 if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1863 fdctrl->data_pos == fdctrl->data_len) {
1864#ifdef VBOX
1865 int rc;
1866 /* *p_fd_activity = 2; */
1867 cur_drv->Led.Asserted.s.fWriting
1868 = cur_drv->Led.Actual.s.fWriting = 1;
1869
1870 rc = cur_drv->pDrvBlock->pfnWrite (
1871 cur_drv->pDrvBlock,
1872 fd_sector (cur_drv) * 512,
1873 fdctrl->fifo,
1874 FD_SECTOR_LEN * 512
1875 );
1876
1877 cur_drv->Led.Actual.s.fWriting = 0;
1878
1879 if (VBOX_FAILURE (rc)) {
1880 AssertMsgFailed (
1881 ("Floppy: failed to write sector %d. rc=%Vrc\n",
1882 fd_sector (cur_drv), rc));
1883 }
1884#else
1885 bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1886 fdctrl->fifo, FD_SECTOR_LEN);
1887#endif
1888 }
1889 /* Switch from transfer mode to status mode
1890 * then from status mode to command mode
1891 */
1892 if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1893 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1894 return;
1895 }
1896 if (fdctrl->data_pos == 0) {
1897 /* Command */
1898 switch (value & 0x5F) {
1899 case 0x46:
1900 /* READ variants */
1901 FLOPPY_DPRINTF("READ command\n");
1902 /* 8 parameters cmd */
1903 fdctrl->data_len = 9;
1904 goto enqueue;
1905 case 0x4C:
1906 /* READ_DELETED variants */
1907 FLOPPY_DPRINTF("READ_DELETED command\n");
1908 /* 8 parameters cmd */
1909 fdctrl->data_len = 9;
1910 goto enqueue;
1911 case 0x50:
1912 /* SCAN_EQUAL variants */
1913 FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1914 /* 8 parameters cmd */
1915 fdctrl->data_len = 9;
1916 goto enqueue;
1917 case 0x56:
1918 /* VERIFY variants */
1919 FLOPPY_DPRINTF("VERIFY command\n");
1920 /* 8 parameters cmd */
1921 fdctrl->data_len = 9;
1922 goto enqueue;
1923 case 0x59:
1924 /* SCAN_LOW_OR_EQUAL variants */
1925 FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1926 /* 8 parameters cmd */
1927 fdctrl->data_len = 9;
1928 goto enqueue;
1929 case 0x5D:
1930 /* SCAN_HIGH_OR_EQUAL variants */
1931 FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1932 /* 8 parameters cmd */
1933 fdctrl->data_len = 9;
1934 goto enqueue;
1935 default:
1936 break;
1937 }
1938 switch (value & 0x7F) {
1939 case 0x45:
1940 /* WRITE variants */
1941 FLOPPY_DPRINTF("WRITE command\n");
1942 /* 8 parameters cmd */
1943 fdctrl->data_len = 9;
1944 goto enqueue;
1945 case 0x49:
1946 /* WRITE_DELETED variants */
1947 FLOPPY_DPRINTF("WRITE_DELETED command\n");
1948 /* 8 parameters cmd */
1949 fdctrl->data_len = 9;
1950 goto enqueue;
1951 default:
1952 break;
1953 }
1954 switch (value) {
1955 case 0x03:
1956 /* SPECIFY */
1957 FLOPPY_DPRINTF("SPECIFY command\n");
1958 /* 1 parameter cmd */
1959 fdctrl->data_len = 3;
1960 goto enqueue;
1961 case 0x04:
1962 /* SENSE_DRIVE_STATUS */
1963 FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1964 /* 1 parameter cmd */
1965 fdctrl->data_len = 2;
1966 goto enqueue;
1967 case 0x07:
1968 /* RECALIBRATE */
1969 FLOPPY_DPRINTF("RECALIBRATE command\n");
1970 /* 1 parameter cmd */
1971 fdctrl->data_len = 2;
1972 goto enqueue;
1973 case 0x08:
1974 /* SENSE_INTERRUPT_STATUS */
1975 FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1976 fdctrl->int_status);
1977 /* No parameters cmd: returns status if no interrupt */
1978#if 0
1979 fdctrl->fifo[0] =
1980 fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1981#else
1982 /* XXX: int_status handling is broken for read/write
1983 commands, so we do this hack. It should be suppressed
1984 ASAP */
1985 fdctrl->fifo[0] =
1986 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1987#endif
1988 fdctrl->fifo[1] = cur_drv->track;
1989 fdctrl_set_fifo(fdctrl, 2, 0);
1990 fdctrl_reset_irq(fdctrl);
1991 fdctrl->int_status = 0xC0;
1992 return;
1993 case 0x0E:
1994 /* DUMPREG */
1995 FLOPPY_DPRINTF("DUMPREG command\n");
1996 /* Drives position */
1997 fdctrl->fifo[0] = drv0(fdctrl)->track;
1998 fdctrl->fifo[1] = drv1(fdctrl)->track;
1999 fdctrl->fifo[2] = 0;
2000 fdctrl->fifo[3] = 0;
2001 /* timers */
2002 fdctrl->fifo[4] = fdctrl->timer0;
2003 fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
2004 fdctrl->fifo[6] = cur_drv->last_sect;
2005 fdctrl->fifo[7] = (fdctrl->lock << 7) |
2006 (cur_drv->perpendicular << 2);
2007 fdctrl->fifo[8] = fdctrl->config;
2008 fdctrl->fifo[9] = fdctrl->precomp_trk;
2009 fdctrl_set_fifo(fdctrl, 10, 0);
2010 return;
2011 case 0x0F:
2012 /* SEEK */
2013 FLOPPY_DPRINTF("SEEK command\n");
2014 /* 2 parameters cmd */
2015 fdctrl->data_len = 3;
2016 goto enqueue;
2017 case 0x10:
2018 /* VERSION */
2019 FLOPPY_DPRINTF("VERSION command\n");
2020 /* No parameters cmd */
2021 /* Controller's version */
2022 fdctrl->fifo[0] = fdctrl->version;
2023 fdctrl_set_fifo(fdctrl, 1, 1);
2024 return;
2025 case 0x12:
2026 /* PERPENDICULAR_MODE */
2027 FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
2028 /* 1 parameter cmd */
2029 fdctrl->data_len = 2;
2030 goto enqueue;
2031 case 0x13:
2032 /* CONFIGURE */
2033 FLOPPY_DPRINTF("CONFIGURE command\n");
2034 /* 3 parameters cmd */
2035 fdctrl->data_len = 4;
2036 goto enqueue;
2037 case 0x14:
2038 /* UNLOCK */
2039 FLOPPY_DPRINTF("UNLOCK command\n");
2040 /* No parameters cmd */
2041 fdctrl->lock = 0;
2042 fdctrl->fifo[0] = 0;
2043 fdctrl_set_fifo(fdctrl, 1, 0);
2044 return;
2045 case 0x17:
2046 /* POWERDOWN_MODE */
2047 FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
2048 /* 2 parameters cmd */
2049 fdctrl->data_len = 3;
2050 goto enqueue;
2051 case 0x18:
2052 /* PART_ID */
2053 FLOPPY_DPRINTF("PART_ID command\n");
2054 /* No parameters cmd */
2055 fdctrl->fifo[0] = 0x41; /* Stepping 1 */
2056 fdctrl_set_fifo(fdctrl, 1, 0);
2057 return;
2058 case 0x2C:
2059 /* SAVE */
2060 FLOPPY_DPRINTF("SAVE command\n");
2061 /* No parameters cmd */
2062 fdctrl->fifo[0] = 0;
2063 fdctrl->fifo[1] = 0;
2064 /* Drives position */
2065 fdctrl->fifo[2] = drv0(fdctrl)->track;
2066 fdctrl->fifo[3] = drv1(fdctrl)->track;
2067 fdctrl->fifo[4] = 0;
2068 fdctrl->fifo[5] = 0;
2069 /* timers */
2070 fdctrl->fifo[6] = fdctrl->timer0;
2071 fdctrl->fifo[7] = fdctrl->timer1;
2072 fdctrl->fifo[8] = cur_drv->last_sect;
2073 fdctrl->fifo[9] = (fdctrl->lock << 7) |
2074 (cur_drv->perpendicular << 2);
2075 fdctrl->fifo[10] = fdctrl->config;
2076 fdctrl->fifo[11] = fdctrl->precomp_trk;
2077 fdctrl->fifo[12] = fdctrl->pwrd;
2078 fdctrl->fifo[13] = 0;
2079 fdctrl->fifo[14] = 0;
2080 fdctrl_set_fifo(fdctrl, 15, 1);
2081 return;
2082 case 0x33:
2083 /* OPTION */
2084 FLOPPY_DPRINTF("OPTION command\n");
2085 /* 1 parameter cmd */
2086 fdctrl->data_len = 2;
2087 goto enqueue;
2088 case 0x42:
2089 /* READ_TRACK */
2090 FLOPPY_DPRINTF("READ_TRACK command\n");
2091 /* 8 parameters cmd */
2092 fdctrl->data_len = 9;
2093 goto enqueue;
2094 case 0x4A:
2095 /* READ_ID */
2096 FLOPPY_DPRINTF("READ_ID command\n");
2097 /* 1 parameter cmd */
2098 fdctrl->data_len = 2;
2099 goto enqueue;
2100 case 0x4C:
2101 /* RESTORE */
2102 FLOPPY_DPRINTF("RESTORE command\n");
2103 /* 17 parameters cmd */
2104 fdctrl->data_len = 18;
2105 goto enqueue;
2106 case 0x4D:
2107 /* FORMAT_TRACK */
2108 FLOPPY_DPRINTF("FORMAT_TRACK command\n");
2109 /* 5 parameters cmd */
2110 fdctrl->data_len = 6;
2111 goto enqueue;
2112 case 0x8E:
2113 /* DRIVE_SPECIFICATION_COMMAND */
2114 FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
2115 /* 5 parameters cmd */
2116 fdctrl->data_len = 6;
2117 goto enqueue;
2118 case 0x8F:
2119 /* RELATIVE_SEEK_OUT */
2120 FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
2121 /* 2 parameters cmd */
2122 fdctrl->data_len = 3;
2123 goto enqueue;
2124 case 0x94:
2125 /* LOCK */
2126 FLOPPY_DPRINTF("LOCK command\n");
2127 /* No parameters cmd */
2128 fdctrl->lock = 1;
2129 fdctrl->fifo[0] = 0x10;
2130 fdctrl_set_fifo(fdctrl, 1, 1);
2131 return;
2132 case 0xCD:
2133 /* FORMAT_AND_WRITE */
2134 FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
2135 /* 10 parameters cmd */
2136 fdctrl->data_len = 11;
2137 goto enqueue;
2138 case 0xCF:
2139 /* RELATIVE_SEEK_IN */
2140 FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
2141 /* 2 parameters cmd */
2142 fdctrl->data_len = 3;
2143 goto enqueue;
2144 default:
2145 /* Unknown command */
2146 FLOPPY_ERROR("unknown command: 0x%02x\n", value);
2147 fdctrl_unimplemented(fdctrl);
2148 return;
2149 }
2150 }
2151enqueue:
2152 FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
2153 fdctrl->fifo[fdctrl->data_pos] = value;
2154 if (++fdctrl->data_pos == fdctrl->data_len) {
2155 /* We now have all parameters
2156 * and will be able to treat the command
2157 */
2158 if (fdctrl->data_state & FD_STATE_FORMAT) {
2159 fdctrl_format_sector(fdctrl);
2160 return;
2161 }
2162 switch (fdctrl->fifo[0] & 0x1F) {
2163 case 0x06:
2164 {
2165 /* READ variants */
2166 FLOPPY_DPRINTF("treat READ command\n");
2167 fdctrl_start_transfer(fdctrl, FD_DIR_READ);
2168 return;
2169 }
2170 case 0x0C:
2171 /* READ_DELETED variants */
2172/* // FLOPPY_DPRINTF("treat READ_DELETED command\n"); */
2173 FLOPPY_ERROR("treat READ_DELETED command\n");
2174 fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
2175 return;
2176 case 0x16:
2177 /* VERIFY variants */
2178/* // FLOPPY_DPRINTF("treat VERIFY command\n"); */
2179 FLOPPY_ERROR("treat VERIFY command\n");
2180 fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
2181 return;
2182 case 0x10:
2183 /* SCAN_EQUAL variants */
2184/* // FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); */
2185 FLOPPY_ERROR("treat SCAN_EQUAL command\n");
2186 fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
2187 return;
2188 case 0x19:
2189 /* SCAN_LOW_OR_EQUAL variants */
2190/* // FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); */
2191 FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
2192 fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
2193 return;
2194 case 0x1D:
2195 /* SCAN_HIGH_OR_EQUAL variants */
2196/* // FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); */
2197 FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
2198 fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
2199 return;
2200 default:
2201 break;
2202 }
2203 switch (fdctrl->fifo[0] & 0x3F) {
2204 case 0x05:
2205 /* WRITE variants */
2206 FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
2207 fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
2208 return;
2209 case 0x09:
2210 /* WRITE_DELETED variants */
2211/* // FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); */
2212 FLOPPY_ERROR("treat WRITE_DELETED command\n");
2213 fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
2214 return;
2215 default:
2216 break;
2217 }
2218 switch (fdctrl->fifo[0]) {
2219 case 0x03:
2220 /* SPECIFY */
2221 FLOPPY_DPRINTF("treat SPECIFY command\n");
2222 fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
2223 fdctrl->timer1 = fdctrl->fifo[2] >> 1;
2224 fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
2225 /* No result back */
2226 fdctrl_reset_fifo(fdctrl);
2227 break;
2228 case 0x04:
2229 /* SENSE_DRIVE_STATUS */
2230 FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
2231 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2232 cur_drv = get_cur_drv(fdctrl);
2233 cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2234 /* 1 Byte status back */
2235 fdctrl->fifo[0] = (cur_drv->ro << 6) |
2236 (cur_drv->track == 0 ? 0x10 : 0x00) |
2237 (cur_drv->head << 2) |
2238 fdctrl->cur_drv |
2239 0x28;
2240 fdctrl_set_fifo(fdctrl, 1, 0);
2241 break;
2242 case 0x07:
2243 /* RECALIBRATE */
2244 FLOPPY_DPRINTF("treat RECALIBRATE command\n");
2245 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2246 cur_drv = get_cur_drv(fdctrl);
2247 fd_recalibrate(cur_drv);
2248 fdctrl_reset_fifo(fdctrl);
2249 /* Raise Interrupt */
2250 fdctrl_raise_irq(fdctrl, 0x20);
2251 break;
2252 case 0x0F:
2253 /* SEEK */
2254 FLOPPY_DPRINTF("treat SEEK command\n");
2255 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2256 cur_drv = get_cur_drv(fdctrl);
2257 fd_start(cur_drv);
2258 if (fdctrl->fifo[2] <= cur_drv->track)
2259 cur_drv->dir = 1;
2260 else
2261 cur_drv->dir = 0;
2262 fdctrl_reset_fifo(fdctrl);
2263#ifndef VBOX
2264 if (fdctrl->fifo[2] > cur_drv->max_track) {
2265#else
2266 if ( fdctrl->fifo[2] > cur_drv->max_track
2267 && cur_drv->fMediaPresent) {
2268#endif
2269 fdctrl_raise_irq(fdctrl, 0x60);
2270 } else {
2271 cur_drv->track = fdctrl->fifo[2];
2272 /* Raise Interrupt */
2273 fdctrl_raise_irq(fdctrl, 0x20);
2274 }
2275 break;
2276 case 0x12:
2277 /* PERPENDICULAR_MODE */
2278 FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
2279 if (fdctrl->fifo[1] & 0x80)
2280 cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
2281 /* No result back */
2282 fdctrl_reset_fifo(fdctrl);
2283 break;
2284 case 0x13:
2285 /* CONFIGURE */
2286 FLOPPY_DPRINTF("treat CONFIGURE command\n");
2287 fdctrl->config = fdctrl->fifo[2];
2288 fdctrl->precomp_trk = fdctrl->fifo[3];
2289 /* No result back */
2290 fdctrl_reset_fifo(fdctrl);
2291 break;
2292 case 0x17:
2293 /* POWERDOWN_MODE */
2294 FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
2295 fdctrl->pwrd = fdctrl->fifo[1];
2296 fdctrl->fifo[0] = fdctrl->fifo[1];
2297 fdctrl_set_fifo(fdctrl, 1, 1);
2298 break;
2299 case 0x33:
2300 /* OPTION */
2301 FLOPPY_DPRINTF("treat OPTION command\n");
2302 /* No result back */
2303 fdctrl_reset_fifo(fdctrl);
2304 break;
2305 case 0x42:
2306 /* READ_TRACK */
2307/* // FLOPPY_DPRINTF("treat READ_TRACK command\n"); */
2308 FLOPPY_ERROR("treat READ_TRACK command\n");
2309 fdctrl_start_transfer(fdctrl, FD_DIR_READ);
2310 break;
2311 case 0x4A:
2312 /* READ_ID */
2313 FLOPPY_DPRINTF("treat READ_ID command\n");
2314 /* XXX: should set main status register to busy */
2315 cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
2316#ifdef VBOX
2317 TMTimerSetMillies(fdctrl->result_timer, 1000 / 50);
2318#else
2319 qemu_mod_timer(fdctrl->result_timer,
2320 qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
2321#endif
2322 break;
2323 case 0x4C:
2324 /* RESTORE */
2325 FLOPPY_DPRINTF("treat RESTORE command\n");
2326 /* Drives position */
2327 drv0(fdctrl)->track = fdctrl->fifo[3];
2328 drv1(fdctrl)->track = fdctrl->fifo[4];
2329 /* timers */
2330 fdctrl->timer0 = fdctrl->fifo[7];
2331 fdctrl->timer1 = fdctrl->fifo[8];
2332 cur_drv->last_sect = fdctrl->fifo[9];
2333 fdctrl->lock = fdctrl->fifo[10] >> 7;
2334 cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
2335 fdctrl->config = fdctrl->fifo[11];
2336 fdctrl->precomp_trk = fdctrl->fifo[12];
2337 fdctrl->pwrd = fdctrl->fifo[13];
2338 fdctrl_reset_fifo(fdctrl);
2339 break;
2340 case 0x4D:
2341 /* FORMAT_TRACK */
2342 FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
2343 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2344 cur_drv = get_cur_drv(fdctrl);
2345 fdctrl->data_state |= FD_STATE_FORMAT;
2346 if (fdctrl->fifo[0] & 0x80)
2347 fdctrl->data_state |= FD_STATE_MULTI;
2348 else
2349 fdctrl->data_state &= ~FD_STATE_MULTI;
2350 fdctrl->data_state &= ~FD_STATE_SEEK;
2351 cur_drv->bps =
2352 fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
2353#if 0
2354 cur_drv->last_sect =
2355 cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
2356 fdctrl->fifo[3] / 2;
2357#else
2358 cur_drv->last_sect = fdctrl->fifo[3];
2359#endif
2360 /* Bochs BIOS is buggy and don't send format informations
2361 * for each sector. So, pretend all's done right now...
2362 */
2363 fdctrl->data_state &= ~FD_STATE_FORMAT;
2364 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2365 break;
2366 case 0x8E:
2367 /* DRIVE_SPECIFICATION_COMMAND */
2368 FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
2369 if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
2370 /* Command parameters done */
2371 if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
2372 fdctrl->fifo[0] = fdctrl->fifo[1];
2373 fdctrl->fifo[2] = 0;
2374 fdctrl->fifo[3] = 0;
2375 fdctrl_set_fifo(fdctrl, 4, 1);
2376 } else {
2377 fdctrl_reset_fifo(fdctrl);
2378 }
2379 } else if (fdctrl->data_len > 7) {
2380 /* ERROR */
2381 fdctrl->fifo[0] = 0x80 |
2382 (cur_drv->head << 2) | fdctrl->cur_drv;
2383 fdctrl_set_fifo(fdctrl, 1, 1);
2384 }
2385 break;
2386 case 0x8F:
2387 /* RELATIVE_SEEK_OUT */
2388 FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
2389 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2390 cur_drv = get_cur_drv(fdctrl);
2391 fd_start(cur_drv);
2392 cur_drv->dir = 0;
2393 if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
2394 cur_drv->track = cur_drv->max_track - 1;
2395 } else {
2396 cur_drv->track += fdctrl->fifo[2];
2397 }
2398 fdctrl_reset_fifo(fdctrl);
2399 fdctrl_raise_irq(fdctrl, 0x20);
2400 break;
2401 case 0xCD:
2402 /* FORMAT_AND_WRITE */
2403/* // FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); */
2404 FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
2405 fdctrl_unimplemented(fdctrl);
2406 break;
2407 case 0xCF:
2408 /* RELATIVE_SEEK_IN */
2409 FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
2410 fdctrl->cur_drv = fdctrl->fifo[1] & 1;
2411 cur_drv = get_cur_drv(fdctrl);
2412 fd_start(cur_drv);
2413 cur_drv->dir = 1;
2414 if (fdctrl->fifo[2] > cur_drv->track) {
2415 cur_drv->track = 0;
2416 } else {
2417 cur_drv->track -= fdctrl->fifo[2];
2418 }
2419 fdctrl_reset_fifo(fdctrl);
2420 /* Raise Interrupt */
2421 fdctrl_raise_irq(fdctrl, 0x20);
2422 break;
2423 }
2424 }
2425}
2426
2427static void fdctrl_result_timer(void *opaque)
2428{
2429 fdctrl_t *fdctrl = opaque;
2430 fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
2431}
2432
2433
2434#ifdef VBOX
2435static DECLCALLBACK(void) fdc_timer (PPDMDEVINS pDevIns, PTMTIMER pTimer)
2436{
2437 fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2438 fdctrl_result_timer (fdctrl);
2439}
2440
2441static DECLCALLBACK(int) fdc_io_write (PPDMDEVINS pDevIns,
2442 void *pvUser,
2443 RTIOPORT Port,
2444 uint32_t u32,
2445 unsigned cb)
2446{
2447 if (cb == 1) {
2448 fdctrl_write (pvUser, Port, u32);
2449 }
2450 else {
2451 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2452 }
2453 return VINF_SUCCESS;
2454}
2455
2456static DECLCALLBACK(int) fdc_io_read (PPDMDEVINS pDevIns,
2457 void *pvUser,
2458 RTIOPORT Port,
2459 uint32_t *pu32,
2460 unsigned cb)
2461{
2462 if (cb == 1) {
2463 *pu32 = fdctrl_read (pvUser, Port);
2464 return VINF_SUCCESS;
2465 }
2466 else {
2467 return VERR_IOM_IOPORT_UNUSED;
2468 }
2469}
2470
2471static DECLCALLBACK(int) SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2472{
2473 fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
2474 QEMUFile *f = pSSMHandle;
2475 unsigned int i;
2476
2477 qemu_put_8s (f, &s->version);
2478 qemu_put_8s (f, &s->irq_lvl);
2479 qemu_put_8s (f, &s->dma_chann);
2480 qemu_put_be32s (f, &s->io_base);
2481 qemu_put_8s (f, &s->state);
2482 qemu_put_8s (f, &s->dma_en);
2483 qemu_put_8s (f, &s->cur_drv);
2484 qemu_put_8s (f, &s->bootsel);
2485 qemu_put_buffer (f, s->fifo, FD_SECTOR_LEN);
2486 qemu_put_be32s (f, &s->data_pos);
2487 qemu_put_be32s (f, &s->data_len);
2488 qemu_put_8s (f, &s->data_state);
2489 qemu_put_8s (f, &s->data_dir);
2490 qemu_put_8s (f, &s->int_status);
2491 qemu_put_8s (f, &s->eot);
2492 qemu_put_8s (f, &s->timer0);
2493 qemu_put_8s (f, &s->timer1);
2494 qemu_put_8s (f, &s->precomp_trk);
2495 qemu_put_8s (f, &s->drate);
2496 qemu_put_8s (f, &s->config);
2497 qemu_put_8s (f, &s->lock);
2498 qemu_put_8s (f, &s->pwrd);
2499
2500 for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
2501 fdrive_t *d = &s->drives[i];
2502
2503 SSMR3PutMem (pSSMHandle, &d->Led, sizeof (d->Led));
2504 qemu_put_be32s (f, &d->drive);
2505 qemu_put_be32s (f, &d->drflags);
2506 qemu_put_8s (f, &d->perpendicular);
2507 qemu_put_8s (f, &d->head);
2508 qemu_put_8s (f, &d->track);
2509 qemu_put_8s (f, &d->sect);
2510 qemu_put_8s (f, &d->dir);
2511 qemu_put_8s (f, &d->rw);
2512 qemu_put_be32s (f, &d->flags);
2513 qemu_put_8s (f, &d->last_sect);
2514 qemu_put_8s (f, &d->max_track);
2515 qemu_put_be16s (f, &d->bps);
2516 qemu_put_8s (f, &d->ro);
2517 }
2518 return TMR3TimerSave (s->result_timer, pSSMHandle);
2519}
2520
2521static DECLCALLBACK(int) LoadExec (PPDMDEVINS pDevIns,
2522 PSSMHANDLE pSSMHandle,
2523 uint32_t u32Version)
2524{
2525 fdctrl_t *s = PDMINS2DATA (pDevIns, fdctrl_t *);
2526 QEMUFile *f = pSSMHandle;
2527 unsigned int i;
2528
2529 if (u32Version != 1) {
2530 AssertMsgFailed(("u32Version=%d\n", u32Version));
2531 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2532 }
2533
2534 qemu_get_8s (f, &s->version);
2535 qemu_get_8s (f, &s->irq_lvl);
2536 qemu_get_8s (f, &s->dma_chann);
2537 qemu_get_be32s (f, &s->io_base);
2538 qemu_get_8s (f, &s->state);
2539 qemu_get_8s (f, &s->dma_en);
2540 qemu_get_8s (f, &s->cur_drv);
2541 qemu_get_8s (f, &s->bootsel);
2542 qemu_get_buffer (f, s->fifo, FD_SECTOR_LEN);
2543 qemu_get_be32s (f, &s->data_pos);
2544 qemu_get_be32s (f, &s->data_len);
2545 qemu_get_8s (f, &s->data_state);
2546 qemu_get_8s (f, &s->data_dir);
2547 qemu_get_8s (f, &s->int_status);
2548 qemu_get_8s (f, &s->eot);
2549 qemu_get_8s (f, &s->timer0);
2550 qemu_get_8s (f, &s->timer1);
2551 qemu_get_8s (f, &s->precomp_trk);
2552 qemu_get_8s (f, &s->drate);
2553 qemu_get_8s (f, &s->config);
2554 qemu_get_8s (f, &s->lock);
2555 qemu_get_8s (f, &s->pwrd);
2556
2557 for (i = 0; i < sizeof (s->drives) / sizeof (s->drives[0]); ++i) {
2558 fdrive_t *d = &s->drives[i];
2559
2560 SSMR3GetMem (pSSMHandle, &d->Led, sizeof (d->Led));
2561 qemu_get_be32s (f, &d->drive);
2562 qemu_get_be32s (f, &d->drflags);
2563 qemu_get_8s (f, &d->perpendicular);
2564 qemu_get_8s (f, &d->head);
2565 qemu_get_8s (f, &d->track);
2566 qemu_get_8s (f, &d->sect);
2567 qemu_get_8s (f, &d->dir);
2568 qemu_get_8s (f, &d->rw);
2569 qemu_get_be32s (f, &d->flags);
2570 qemu_get_8s (f, &d->last_sect);
2571 qemu_get_8s (f, &d->max_track);
2572 qemu_get_be16s (f, &d->bps);
2573 qemu_get_8s (f, &d->ro);
2574 }
2575 return TMR3TimerLoad (s->result_timer, pSSMHandle);
2576}
2577
2578/**
2579 * Queries an interface to the driver.
2580 *
2581 * @returns Pointer to interface.
2582 * @returns NULL if the interface was not supported by the device.
2583 * @param pInterface Pointer to IDEState::IBase.
2584 * @param enmInterface The requested interface identification.
2585 */
2586static DECLCALLBACK(void *) fdQueryInterface (PPDMIBASE pInterface,
2587 PDMINTERFACE enmInterface)
2588{
2589 fdrive_t *drv = PDMIBASE_2_FDRIVE(pInterface);
2590 switch (enmInterface) {
2591 case PDMINTERFACE_BASE:
2592 return &drv->IBase;
2593 case PDMINTERFACE_BLOCK_PORT:
2594 return &drv->IPort;
2595 case PDMINTERFACE_MOUNT_NOTIFY:
2596 return &drv->IMountNotify;
2597 default:
2598 return NULL;
2599 }
2600}
2601
2602/**
2603 * Gets the pointer to the status LED of a unit.
2604 *
2605 * @returns VBox status code.
2606 * @param pInterface Pointer to the interface structure containing the called function pointer.
2607 * @param iLUN The unit which status LED we desire.
2608 * @param ppLed Where to store the LED pointer.
2609 */
2610static DECLCALLBACK(int) fdcStatusQueryStatusLed (PPDMILEDPORTS pInterface,
2611 unsigned iLUN,
2612 PPDMLED *ppLed)
2613{
2614 fdctrl_t *fdctrl = (fdctrl_t *)
2615 ((uintptr_t )pInterface - RT_OFFSETOF (fdctrl_t, ILeds));
2616 if (iLUN < ELEMENTS(fdctrl->drives)) {
2617 *ppLed = &fdctrl->drives[iLUN].Led;
2618 Assert ((*ppLed)->u32Magic == PDMLED_MAGIC);
2619 return VINF_SUCCESS;
2620 }
2621 return VERR_PDM_LUN_NOT_FOUND;
2622}
2623
2624
2625/**
2626 * Queries an interface to the status LUN.
2627 *
2628 * @returns Pointer to interface.
2629 * @returns NULL if the interface was not supported by the device.
2630 * @param pInterface Pointer to IDEState::IBase.
2631 * @param enmInterface The requested interface identification.
2632 */
2633static DECLCALLBACK(void *) fdcStatusQueryInterface (PPDMIBASE pInterface,
2634 PDMINTERFACE enmInterface)
2635{
2636 fdctrl_t *fdctrl = (fdctrl_t *)
2637 ((uintptr_t)pInterface - RT_OFFSETOF (fdctrl_t, IBaseStatus));
2638 switch (enmInterface) {
2639 case PDMINTERFACE_BASE:
2640 return &fdctrl->IBaseStatus;
2641 case PDMINTERFACE_LED_PORTS:
2642 return &fdctrl->ILeds;
2643 default:
2644 return NULL;
2645 }
2646}
2647
2648
2649/**
2650 * Configure a drive.
2651 *
2652 * @returns VBox status code.
2653 * @param drv The drive in question.
2654 * @param pDevIns The driver instance.
2655 */
2656static int fdConfig (fdrive_t *drv, PPDMDEVINS pDevIns)
2657{
2658 static const char *descs[] = {"Floppy Drive A:", "Floppy Drive B"};
2659 int rc;
2660
2661 /*
2662 * Reset the LED just to be on the safe side.
2663 */
2664 Assert (ELEMENTS(descs) > drv->iLUN);
2665 Assert (drv->Led.u32Magic == PDMLED_MAGIC);
2666 drv->Led.Actual.u32 = 0;
2667 drv->Led.Asserted.u32 = 0;
2668
2669 /*
2670 * Try attach the block device and get the interfaces.
2671 */
2672 rc = PDMDevHlpDriverAttach (pDevIns, drv->iLUN, &drv->IBase, &drv->pDrvBase, descs[drv->iLUN]);
2673 if (VBOX_SUCCESS (rc))
2674 {
2675 drv->pDrvBlock = drv->pDrvBase->pfnQueryInterface (
2676 drv->pDrvBase,
2677 PDMINTERFACE_BLOCK
2678 );
2679 if (drv->pDrvBlock) {
2680 drv->pDrvBlockBios = drv->pDrvBase->pfnQueryInterface (
2681 drv->pDrvBase,
2682 PDMINTERFACE_BLOCK_BIOS
2683 );
2684 if (drv->pDrvBlockBios) {
2685 drv->pDrvMount = drv->pDrvBase->pfnQueryInterface (
2686 drv->pDrvBase,
2687 PDMINTERFACE_MOUNT
2688 );
2689 if (drv->pDrvMount) {
2690 /*
2691 * Init the state.
2692 */
2693 drv->drive = FDRIVE_DRV_NONE;
2694 drv->drflags = 0;
2695 drv->perpendicular = 0;
2696 /* Disk */
2697 drv->last_sect = 0;
2698 drv->max_track = 0;
2699 drv->fMediaPresent = false;
2700 }
2701 else {
2702 AssertMsgFailed (("Configuration error: LUN#%d without mountable interface!\n", drv->iLUN));
2703 rc = VERR_PDM_MISSING_INTERFACE;
2704 }
2705
2706 }
2707 else {
2708 AssertMsgFailed (("Configuration error: LUN#%d hasn't a block BIOS interface!\n", drv->iLUN));
2709 rc = VERR_PDM_MISSING_INTERFACE;
2710 }
2711
2712 }
2713 else {
2714 AssertMsgFailed (("Configuration error: LUN#%d hasn't a block interface!\n", drv->iLUN));
2715 rc = VERR_PDM_MISSING_INTERFACE;
2716 }
2717 }
2718 else {
2719 AssertMsg (rc == VERR_PDM_NO_ATTACHED_DRIVER,
2720 ("Failed to attach LUN#%d. rc=%Vrc\n", drv->iLUN, rc));
2721 }
2722
2723 if (VBOX_FAILURE (rc)) {
2724 drv->pDrvBase = NULL;
2725 drv->pDrvBlock = NULL;
2726 drv->pDrvBlockBios = NULL;
2727 drv->pDrvMount = NULL;
2728 }
2729 LogFlow (("fdConfig: returns %Vrc\n", rc));
2730 return rc;
2731}
2732
2733
2734/**
2735 * Attach command.
2736 *
2737 * This is called when we change block driver for a floppy drive.
2738 *
2739 * @returns VBox status code.
2740 * @param pDevIns The device instance.
2741 * @param iLUN The logical unit which is being detached.
2742 */
2743static DECLCALLBACK(int) fdcAttach (PPDMDEVINS pDevIns,
2744 unsigned iLUN)
2745{
2746 fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2747 fdrive_t *drv;
2748 int rc;
2749 LogFlow (("ideDetach: iLUN=%u\n", iLUN));
2750
2751 /*
2752 * Validate.
2753 */
2754 if (iLUN > 2) {
2755 AssertMsgFailed (("Configuration error: cannot attach or detach any but the first two LUNs - iLUN=%u\n",
2756 iLUN));
2757 return VERR_PDM_DEVINS_NO_ATTACH;
2758 }
2759
2760 /*
2761 * Locate the drive and stuff.
2762 */
2763 drv = &fdctrl->drives[iLUN];
2764
2765 /* the usual paranoia */
2766 AssertRelease (!drv->pDrvBase);
2767 AssertRelease (!drv->pDrvBlock);
2768 AssertRelease (!drv->pDrvBlockBios);
2769 AssertRelease (!drv->pDrvMount);
2770
2771 rc = fdConfig (drv, pDevIns);
2772 AssertMsg (rc != VERR_PDM_NO_ATTACHED_DRIVER,
2773 ("Configuration error: failed to configure drive %d, rc=%Vrc\n", rc));
2774 if (VBOX_SUCCESS(rc)) {
2775 fd_revalidate (drv);
2776 }
2777
2778 LogFlow (("floppyAttach: returns %Vrc\n", rc));
2779 return rc;
2780}
2781
2782
2783/**
2784 * Detach notification.
2785 *
2786 * The floppy drive has been temporarily 'unplugged'.
2787 *
2788 * @param pDevIns The device instance.
2789 * @param iLUN The logical unit which is being detached.
2790 */
2791static DECLCALLBACK(void) fdcDetach (PPDMDEVINS pDevIns,
2792 unsigned iLUN)
2793{
2794 fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2795 LogFlow (("ideDetach: iLUN=%u\n", iLUN));
2796
2797 switch (iLUN) {
2798 case 0:
2799 case 1: {
2800 fdrive_t *drv = &fdctrl->drives[iLUN];
2801 drv->pDrvBase = NULL;
2802 drv->pDrvBlock = NULL;
2803 drv->pDrvBlockBios = NULL;
2804 drv->pDrvMount = NULL;
2805 break;
2806 }
2807
2808 default:
2809 AssertMsgFailed (("Cannot detach LUN#%d!\n", iLUN));
2810 break;
2811 }
2812}
2813
2814
2815/**
2816 * Handle reset.
2817 *
2818 * I haven't check the specs on what's supposed to happen on reset, but we
2819 * should get any 'FATAL: floppy recal:f07 ctrl not ready' when resetting
2820 * at wrong time like we do if this was all void.
2821 *
2822 * @param pDevIns The device instance.
2823 */
2824static DECLCALLBACK(void) fdcReset (PPDMDEVINS pDevIns)
2825{
2826 fdctrl_t *fdctrl = PDMINS2DATA (pDevIns, fdctrl_t *);
2827 int i;
2828 LogFlow (("fdcReset:\n"));
2829
2830 fdctrl_reset(fdctrl, 0);
2831 fdctrl->state = FD_CTRL_ACTIVE;
2832
2833 for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
2834 fd_revalidate(&fdctrl->drives[i]);
2835 }
2836}
2837
2838
2839/**
2840 * Construct a device instance for a VM.
2841 *
2842 * @returns VBox status.
2843 * @param pDevIns The device instance data.
2844 * If the registration structure is needed, pDevIns->pDevReg points to it.
2845 * @param iInstance Instance number. Use this to figure out which registers and such to use.
2846 * The device number is also found in pDevIns->iInstance, but since it's
2847 * likely to be freqently used PDM passes it as parameter.
2848 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
2849 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
2850 * iInstance it's expected to be used a bit in this function.
2851 */
2852static DECLCALLBACK(int) fdcConstruct (PPDMDEVINS pDevIns,
2853 int iInstance,
2854 PCFGMNODE pCfgHandle)
2855{
2856 int rc;
2857 fdctrl_t *fdctrl = PDMINS2DATA(pDevIns, fdctrl_t*);
2858 int i;
2859 bool mem_mapped;
2860 uint16_t io_base;
2861 uint8_t irq_lvl, dma_chann;
2862 PPDMIBASE pBase;
2863
2864 Assert(iInstance == 0);
2865
2866 /*
2867 * Validate configuration.
2868 */
2869 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0DMA\0MemMapped\0IOBase\0")) {
2870 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2871 }
2872
2873 /*
2874 * Read the configuration.
2875 */
2876 rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
2877 if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2878 irq_lvl = 6;
2879 }
2880 else if (VBOX_FAILURE (rc)) {
2881 AssertMsgFailed (("Configuration error: Failed to read U8 IRQ, rc=%Vrc\n", rc));
2882 return rc;
2883 }
2884
2885 rc = CFGMR3QueryU8 (pCfgHandle, "DMA", &dma_chann);
2886 if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2887 dma_chann = 2;
2888 }
2889 else if (VBOX_FAILURE (rc)) {
2890 AssertMsgFailed (("Configuration error: Failed to read U8 DMA, rc=%Vrc\n", rc));
2891 return rc;
2892 }
2893
2894 rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
2895 if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2896 io_base = 0x3f0;
2897 }
2898 else if (VBOX_FAILURE (rc)) {
2899 AssertMsgFailed (("Configuration error: Failed to read U16 IOBase, rc=%Vrc\n", rc));
2900 return rc;
2901 }
2902
2903 rc = CFGMR3QueryBool (pCfgHandle, "MemMapped", &mem_mapped);
2904 if (rc == VERR_CFGM_VALUE_NOT_FOUND) {
2905 mem_mapped = false;
2906 }
2907 else if (VBOX_FAILURE (rc)) {
2908 AssertMsgFailed (("Configuration error: Failed to read bool value MemMapped rc=%Vrc\n", rc));
2909 return rc;
2910 }
2911
2912 /*
2913 * Initialize data.
2914 */
2915 LogFlow(("fdcConstruct: irq_lvl=%d dma_chann=%d io_base=%#x\n", irq_lvl, dma_chann, io_base));
2916 fdctrl->pDevIns = pDevIns;
2917 fdctrl->version = 0x90; /* Intel 82078 controller */
2918 fdctrl->irq_lvl = irq_lvl;
2919 fdctrl->dma_chann = dma_chann;
2920 fdctrl->io_base = io_base;
2921 fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
2922
2923 fdctrl->IBaseStatus.pfnQueryInterface = fdcStatusQueryInterface;
2924 fdctrl->ILeds.pfnQueryStatusLed = fdcStatusQueryStatusLed;
2925
2926 for (i = 0; i < ELEMENTS(fdctrl->drives); ++i) {
2927 fdrive_t *drv = &fdctrl->drives[i];
2928
2929 drv->drive = FDRIVE_DRV_NONE;
2930 drv->iLUN = i;
2931
2932 drv->IBase.pfnQueryInterface = fdQueryInterface;
2933 drv->IMountNotify.pfnMountNotify = fdMountNotify;
2934 drv->IMountNotify.pfnUnmountNotify = fdUnmountNotify;
2935 drv->Led.u32Magic = PDMLED_MAGIC;
2936 }
2937
2938 /*
2939 * Create the FDC timer.
2940 */
2941 rc = pDevIns->pDevHlp->pfnTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL,
2942 fdc_timer,
2943 "FDC Timer",
2944 &fdctrl->result_timer);
2945 if (VBOX_FAILURE (rc)) {
2946 return rc;
2947 }
2948
2949 /*
2950 * Register DMA channel.
2951 */
2952 if (fdctrl->dma_chann != 0xff) {
2953 fdctrl->dma_en = 1;
2954 rc = pDevIns->pDevHlp->pfnDMARegister (
2955 pDevIns,
2956 dma_chann,
2957 &fdctrl_transfer_handler,
2958 fdctrl);
2959 if (VBOX_FAILURE (rc)) {
2960 return rc;
2961 }
2962 } else {
2963 fdctrl->dma_en = 0;
2964 }
2965
2966 /*
2967 * IO / MMIO.
2968 */
2969 if (mem_mapped) {
2970 AssertMsgFailed (("Memory mapped floppy not support by now\n"));
2971 return VERR_NOT_SUPPORTED;
2972#if 0
2973 FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
2974 io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
2975 cpu_register_physical_memory(base, 0x08, io_mem);
2976#endif
2977 } else {
2978 rc = pDevIns->pDevHlp->pfnIOPortRegister (
2979 pDevIns,
2980 io_base + 0x1,
2981 5,
2982 fdctrl,
2983 fdc_io_write,
2984 fdc_io_read,
2985 NULL, NULL,
2986 "FDC#1"
2987 );
2988 if (VBOX_FAILURE (rc)) {
2989 return rc;
2990 }
2991
2992 rc = pDevIns->pDevHlp->pfnIOPortRegister (
2993 pDevIns,
2994 io_base + 0x7,
2995 1,
2996 fdctrl,
2997 fdc_io_write,
2998 fdc_io_read,
2999 NULL, NULL,
3000 "FDC#2"
3001 );
3002 if (VBOX_FAILURE (rc)) {
3003 return rc;
3004 }
3005 }
3006
3007 /*
3008 * Register the saved state data unit.
3009 */
3010 rc = pDevIns->pDevHlp->pfnSSMRegister (
3011 pDevIns, /* pDevIns */
3012 pDevIns->pDevReg->szDeviceName, /* pszName */
3013 iInstance, /* u32Instance */
3014 1 /* u32Version */,
3015 sizeof (*fdctrl), /* cbGuess */
3016 NULL, /* pfnSavePrep */
3017 SaveExec, /* pfnSaveExec */
3018 NULL, /* pfnSaveDone */
3019 NULL, /* pfnLoadPrep */
3020 LoadExec, /* pfnLoadExec */
3021 NULL /* pfnLoadDone */
3022 );
3023 if (VBOX_FAILURE(rc))
3024 return rc;
3025
3026 /*
3027 * Attach the status port (optional).
3028 */
3029 rc = PDMDevHlpDriverAttach (pDevIns, PDM_STATUS_LUN, &fdctrl->IBaseStatus, &pBase, "Status Port");
3030 if (VBOX_SUCCESS (rc)) {
3031 fdctrl->pLedsConnector =
3032 pBase->pfnQueryInterface (pBase, PDMINTERFACE_LED_CONNECTORS);
3033 }
3034 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER) {
3035 AssertMsgFailed (("Failed to attach to status driver. rc=%Vrc\n",
3036 rc));
3037 return rc;
3038 }
3039
3040 /*
3041 * Initialize drives.
3042 */
3043 for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
3044 fdrive_t *drv = &fdctrl->drives[i];
3045 rc = fdConfig (drv, pDevIns);
3046 if ( VBOX_FAILURE (rc)
3047 && rc != VERR_PDM_NO_ATTACHED_DRIVER) {
3048 AssertMsgFailed (("Configuration error: failed to configure drive %d, rc=%Vrc\n", rc));
3049 return rc;
3050 }
3051 }
3052
3053 fdctrl_reset(fdctrl, 0);
3054 fdctrl->state = FD_CTRL_ACTIVE;
3055
3056 for (i = 0; i < ELEMENTS(fdctrl->drives); i++) {
3057 fd_revalidate(&fdctrl->drives[i]);
3058 }
3059
3060 return VINF_SUCCESS;
3061}
3062
3063/**
3064 * The device registration structure.
3065 */
3066const PDMDEVREG g_DeviceFloppyController =
3067{
3068 /* u32Version */
3069 PDM_DEVREG_VERSION,
3070 /* szDeviceName */
3071 "i82078",
3072 /* szGCMod */
3073 "",
3074 /* szR0Mod */
3075 "",
3076 /* pszDescription */
3077 "Floppy drive controller (Intel 82078)",
3078 /* fFlags */
3079 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
3080 /* fClass */
3081 PDM_DEVREG_CLASS_STORAGE,
3082 /* cMaxInstances */
3083 1,
3084 /* cbInstance */
3085 sizeof(fdctrl_t),
3086 /* pfnConstruct */
3087 fdcConstruct,
3088 /* pfnDestruct */
3089 NULL,
3090 /* pfnRelocate */
3091 NULL,
3092 /* pfnIOCtl */
3093 NULL,
3094 /* pfnPowerOn */
3095 NULL,
3096 /* pfnReset */
3097 fdcReset,
3098 /* pfnSuspend */
3099 NULL,
3100 /* pfnResume */
3101 NULL,
3102 /* pfnAttach */
3103 fdcAttach,
3104 /* pfnDetach */
3105 fdcDetach,
3106 /* pfnQueryInterface. */
3107 NULL
3108};
3109
3110#endif /* VBOX */
3111
3112/*
3113 * Local Variables:
3114 * mode: c
3115 * c-file-style: "k&r"
3116 * indent-tabs-mode: nil
3117 * End:
3118 */
3119
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette