(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/fdc.c

    1: /*
    2:  * QEMU Floppy disk emulator (Intel 82078)
    3:  *
    4:  * Copyright (c) 2003, 2007 Jocelyn Mayer
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: /*
   25:  * The controller is used in Sun4m systems in a slightly different
   26:  * way. There are changes in DOR register and DMA is not available.
   27:  */
   28: #include "hw.h"
   29: #include "fdc.h"
   30: #include "block.h"
   31: #include "qemu-timer.h"
   32: #include "isa.h"
   33: 
   34: /********************************************************/
   35: /* debug Floppy devices */
   36: //#define DEBUG_FLOPPY
   37: 
   38: #ifdef DEBUG_FLOPPY
   39: #define FLOPPY_DPRINTF(fmt, args...) \
   40: do { printf("FLOPPY: " fmt , ##args); } while (0)
   41: #else
   42: #define FLOPPY_DPRINTF(fmt, args...)
   43: #endif
   44: 
   45: #define FLOPPY_ERROR(fmt, args...) \
   46: do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
   47: 
   48: /********************************************************/
   49: /* Floppy drive emulation                               */
   50: 
   51: /* Will always be a fixed parameter for us */
   52: #define FD_SECTOR_LEN 512
   53: #define FD_SECTOR_SC  2   /* Sector size code */
   54: 
   55: /* Floppy disk drive emulation */
   56: typedef enum fdisk_type_t {
   57:     FDRIVE_DISK_288   = 0x01, /* 2.88 MB disk           */
   58:     FDRIVE_DISK_144   = 0x02, /* 1.44 MB disk           */
   59:     FDRIVE_DISK_720   = 0x03, /* 720 kB disk            */
   60:     FDRIVE_DISK_USER  = 0x04, /* User defined geometry  */
   61:     FDRIVE_DISK_NONE  = 0x05, /* No disk                */
   62: } fdisk_type_t;
   63: 
   64: typedef enum fdrive_type_t {
   65:     FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
   66:     FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
   67:     FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
   68:     FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
   69: } fdrive_type_t;
   70: 
   71: typedef enum fdrive_flags_t {
   72:     FDRIVE_MOTOR_ON   = 0x01, /* motor on/off           */
   73: } fdrive_flags_t;
   74: 
   75: typedef enum fdisk_flags_t {
   76:     FDISK_DBL_SIDES  = 0x01,
   77: } fdisk_flags_t;
   78: 
   79: typedef struct fdrive_t {
   80:     BlockDriverState *bs;
   81:     /* Drive status */
   82:     fdrive_type_t drive;
   83:     fdrive_flags_t drflags;
   84:     uint8_t perpendicular;    /* 2.88 MB access mode    */
   85:     /* Position */
   86:     uint8_t head;
   87:     uint8_t track;
   88:     uint8_t sect;
   89:     /* Last operation status */
   90:     uint8_t dir;              /* Direction              */
   91:     uint8_t rw;               /* Read/write             */
   92:     /* Media */
   93:     fdisk_flags_t flags;
   94:     uint8_t last_sect;        /* Nb sector per track    */
   95:     uint8_t max_track;        /* Nb of tracks           */
   96:     uint16_t bps;             /* Bytes per sector       */
   97:     uint8_t ro;               /* Is read-only           */
   98: } fdrive_t;
   99: 
  100: static void fd_init (fdrive_t *drv, BlockDriverState *bs)
  101: {
  102:     /* Drive */
  103:     drv->bs = bs;
  104:     drv->drive = FDRIVE_DRV_NONE;
  105:     drv->drflags = 0;
  106:     drv->perpendicular = 0;
  107:     /* Disk */
  108:     drv->last_sect = 0;
  109:     drv->max_track = 0;
  110: }
  111: 
  112: static int _fd_sector (uint8_t head, uint8_t track,
  113:                        uint8_t sect, uint8_t last_sect)
  114: {
  115:     return (((track * 2) + head) * last_sect) + sect - 1;
  116: }
  117: 
  118: /* Returns current position, in sectors, for given drive */
  119: static int fd_sector (fdrive_t *drv)
  120: {
  121:     return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
  122: }
  123: 
  124: static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
  125:                     int enable_seek)
  126: {
  127:     uint32_t sector;
  128:     int ret;
  129: 
  130:     if (track > drv->max_track ||
  131:         (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
  132:         FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
  133:                        head, track, sect, 1,
  134:                        (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
  135:                        drv->max_track, drv->last_sect);
  136:         return 2;
  137:     }
  138:     if (sect > drv->last_sect) {
  139:         FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
  140:                        head, track, sect, 1,
  141:                        (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
  142:                        drv->max_track, drv->last_sect);
  143:         return 3;
  144:     }
  145:     sector = _fd_sector(head, track, sect, drv->last_sect);
  146:     ret = 0;
  147:     if (sector != fd_sector(drv)) {
  148: #if 0
  149:         if (!enable_seek) {
  150:             FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
  151:                          head, track, sect, 1, drv->max_track, drv->last_sect);
  152:             return 4;
  153:         }
  154: #endif
  155:         drv->head = head;
  156:         if (drv->track != track)
  157:             ret = 1;
  158:         drv->track = track;
  159:         drv->sect = sect;
  160:     }
  161: 
  162:     return ret;
  163: }
  164: 
  165: /* Set drive back to track 0 */
  166: static void fd_recalibrate (fdrive_t *drv)
  167: {
  168:     FLOPPY_DPRINTF("recalibrate\n");
  169:     drv->head = 0;
  170:     drv->track = 0;
  171:     drv->sect = 1;
  172:     drv->dir = 1;
  173:     drv->rw = 0;
  174: }
  175: 
  176: /* Recognize floppy formats */
  177: typedef struct fd_format_t {
  178:     fdrive_type_t drive;
  179:     fdisk_type_t  disk;
  180:     uint8_t last_sect;
  181:     uint8_t max_track;
  182:     uint8_t max_head;
  183:     const char *str;
  184: } fd_format_t;
  185: 
  186: static const fd_format_t fd_formats[] = {
  187:     /* First entry is default format */
  188:     /* 1.44 MB 3"1/2 floppy disks */
  189:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
  190:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1,  "1.6 MB 3\"1/2", },
  191:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
  192:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
  193:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
  194:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
  195:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
  196:     { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
  197:     /* 2.88 MB 3"1/2 floppy disks */
  198:     { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
  199:     { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
  200:     { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1,  "3.2 MB 3\"1/2", },
  201:     { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
  202:     { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
  203:     /* 720 kB 3"1/2 floppy disks */
  204:     { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 1,  "720 kB 3\"1/2", },
  205:     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1,  "800 kB 3\"1/2", },
  206:     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1,  "820 kB 3\"1/2", },
  207:     { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1,  "830 kB 3\"1/2", },
  208:     { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
  209:     { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
  210:     /* 1.2 MB 5"1/4 floppy disks */
  211:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1,  "1.2 kB 5\"1/4", },
  212:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
  213:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
  214:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
  215:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1,  "1.6 MB 5\"1/4", },
  216:     /* 720 kB 5"1/4 floppy disks */
  217:     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 80, 1,  "720 kB 5\"1/4", },
  218:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1,  "880 kB 5\"1/4", },
  219:     /* 360 kB 5"1/4 floppy disks */
  220:     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 1,  "360 kB 5\"1/4", },
  221:     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 0,  "180 kB 5\"1/4", },
  222:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1,  "410 kB 5\"1/4", },
  223:     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1,  "420 kB 5\"1/4", },
  224:     /* 320 kB 5"1/4 floppy disks */
  225:     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 1,  "320 kB 5\"1/4", },
  226:     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 0,  "160 kB 5\"1/4", },
  227:     /* 360 kB must match 5"1/4 better than 3"1/2... */
  228:     { FDRIVE_DRV_144, FDRIVE_DISK_720,  9, 80, 0,  "360 kB 3\"1/2", },
  229:     /* end */
  230:     { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
  231: };
  232: 
  233: /* Revalidate a disk drive after a disk change */
  234: static void fd_revalidate (fdrive_t *drv)
  235: {
  236:     const fd_format_t *parse;
  237:     uint64_t nb_sectors, size;
  238:     int i, first_match, match;
  239:     int nb_heads, max_track, last_sect, ro;
  240: 
  241:     FLOPPY_DPRINTF("revalidate\n");
  242:     if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
  243:         ro = bdrv_is_read_only(drv->bs);
  244:         bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
  245:         if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
  246:             FLOPPY_DPRINTF("User defined disk (%d %d %d)",
  247:                            nb_heads - 1, max_track, last_sect);
  248:         } else {
  249:             bdrv_get_geometry(drv->bs, &nb_sectors);
  250:             match = -1;
  251:             first_match = -1;
  252:             for (i = 0;; i++) {
  253:                 parse = &fd_formats[i];
  254:                 if (parse->drive == FDRIVE_DRV_NONE)
  255:                     break;
  256:                 if (drv->drive == parse->drive ||
  257:                     drv->drive == FDRIVE_DRV_NONE) {
  258:                     size = (parse->max_head + 1) * parse->max_track *
  259:                         parse->last_sect;
  260:                     if (nb_sectors == size) {
  261:                         match = i;
  262:                         break;
  263:                     }
  264:                     if (first_match == -1)
  265:                         first_match = i;
  266:                 }
  267:             }
  268:             if (match == -1) {
  269:                 if (first_match == -1)
  270:                     match = 1;
  271:                 else
  272:                     match = first_match;
  273:                 parse = &fd_formats[match];
  274:             }
  275:             nb_heads = parse->max_head + 1;
  276:             max_track = parse->max_track;
  277:             last_sect = parse->last_sect;
  278:             drv->drive = parse->drive;
  279:             FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
  280:                            nb_heads, max_track, last_sect, ro ? "ro" : "rw");
  281:         }
  282:         if (nb_heads == 1) {
  283:             drv->flags &= ~FDISK_DBL_SIDES;
  284:         } else {
  285:             drv->flags |= FDISK_DBL_SIDES;
  286:         }
  287:         drv->max_track = max_track;
  288:         drv->last_sect = last_sect;
  289:         drv->ro = ro;
  290:     } else {
  291:         FLOPPY_DPRINTF("No disk in drive\n");
  292:         drv->last_sect = 0;
  293:         drv->max_track = 0;
  294:         drv->flags &= ~FDISK_DBL_SIDES;
  295:     }
  296: }
  297: 
  298: /* Motor control */
  299: static void fd_start (fdrive_t *drv)
  300: {
  301:     drv->drflags |= FDRIVE_MOTOR_ON;
  302: }
  303: 
  304: static void fd_stop (fdrive_t *drv)
  305: {
  306:     drv->drflags &= ~FDRIVE_MOTOR_ON;
  307: }
  308: 
  309: /* Re-initialise a drives (motor off, repositioned) */
  310: static void fd_reset (fdrive_t *drv)
  311: {
  312:     fd_stop(drv);
  313:     fd_recalibrate(drv);
  314: }
  315: 
  316: /********************************************************/
  317: /* Intel 82078 floppy disk controller emulation          */
  318: 
  319: static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
  320: static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
  321: static int fdctrl_transfer_handler (void *opaque, int nchan,
  322:                                     int dma_pos, int dma_len);
  323: static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
  324: static void fdctrl_result_timer(void *opaque);
  325: 
  326: static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
  327: static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
  328: static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
  329: static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
  330: static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
  331: static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
  332: static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
  333: static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
  334: static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
  335: static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
  336: 
  337: enum {
  338:     FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
  339:     FD_CTRL_RESET  = 0x02,
  340:     FD_CTRL_SLEEP  = 0x04, /* XXX: suppress that */
  341:     FD_CTRL_BUSY   = 0x08, /* dma transfer in progress */
  342:     FD_CTRL_INTR   = 0x10,
  343: };
  344: 
  345: enum {
  346:     FD_DIR_WRITE   = 0,
  347:     FD_DIR_READ    = 1,
  348:     FD_DIR_SCANE   = 2,
  349:     FD_DIR_SCANL   = 3,
  350:     FD_DIR_SCANH   = 4,
  351: };
  352: 
  353: enum {
  354:     FD_STATE_CMD    = 0x00,
  355:     FD_STATE_STATUS = 0x01,
  356:     FD_STATE_DATA   = 0x02,
  357:     FD_STATE_STATE  = 0x03,
  358:     FD_STATE_MULTI  = 0x10,
  359:     FD_STATE_SEEK   = 0x20,
  360:     FD_STATE_FORMAT = 0x40,
  361: };
  362: 
  363: #define FD_STATE(state) ((state) & FD_STATE_STATE)
  364: #define FD_SET_STATE(state, new_state) \
  365: do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
  366: #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
  367: #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
  368: #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
  369: 
  370: struct fdctrl_t {
  371:     fdctrl_t *fdctrl;
  372:     /* Controller's identification */
  373:     uint8_t version;
  374:     /* HW */
  375:     qemu_irq irq;
  376:     int dma_chann;
  377:     target_phys_addr_t io_base;
  378:     /* Controller state */
  379:     QEMUTimer *result_timer;
  380:     uint8_t state;
  381:     uint8_t dma_en;
  382:     uint8_t cur_drv;
  383:     uint8_t bootsel;
  384:     /* Command FIFO */
  385:     uint8_t *fifo;
  386:     uint32_t data_pos;
  387:     uint32_t data_len;
  388:     uint8_t data_state;
  389:     uint8_t data_dir;
  390:     uint8_t int_status;
  391:     uint8_t eot; /* last wanted sector */
  392:     /* States kept only to be returned back */
  393:     /* Timers state */
  394:     uint8_t timer0;
  395:     uint8_t timer1;
  396:     /* precompensation */
  397:     uint8_t precomp_trk;
  398:     uint8_t config;
  399:     uint8_t lock;
  400:     /* Power down config (also with status regB access mode */
  401:     uint8_t pwrd;
  402:     /* Sun4m quirks? */
  403:     int sun4m;
  404:     /* Floppy drives */
  405:     fdrive_t drives[2];
  406: };
  407: 
  408: static uint32_t fdctrl_read (void *opaque, uint32_t reg)
  409: {
  410:     fdctrl_t *fdctrl = opaque;
  411:     uint32_t retval;
  412: 
  413:     switch (reg & 0x07) {
  414:     case 0x00:
  415:         if (fdctrl->sun4m) {
  416:             // Identify to Linux as S82078B
  417:             retval = fdctrl_read_statusB(fdctrl);
  418:         } else {
  419:             retval = (uint32_t)(-1);
  420:         }
  421:         break;
  422:     case 0x01:
  423:         retval = fdctrl_read_statusB(fdctrl);
  424:         break;
  425:     case 0x02:
  426:         retval = fdctrl_read_dor(fdctrl);
  427:         break;
  428:     case 0x03:
  429:         retval = fdctrl_read_tape(fdctrl);
  430:         break;
  431:     case 0x04:
  432:         retval = fdctrl_read_main_status(fdctrl);
  433:         break;
  434:     case 0x05:
  435:         retval = fdctrl_read_data(fdctrl);
  436:         break;
  437:     case 0x07:
  438:         retval = fdctrl_read_dir(fdctrl);
  439:         break;
  440:     default:
  441:         retval = (uint32_t)(-1);
  442:         break;
  443:     }
  444:     FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
  445: 
  446:     return retval;
  447: }
  448: 
  449: static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
  450: {
  451:     fdctrl_t *fdctrl = opaque;
  452: 
  453:     FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
  454: 
  455:     switch (reg & 0x07) {
  456:     case 0x02:
  457:         fdctrl_write_dor(fdctrl, value);
  458:         break;
  459:     case 0x03:
  460:         fdctrl_write_tape(fdctrl, value);
  461:         break;
  462:     case 0x04:
  463:         fdctrl_write_rate(fdctrl, value);
  464:         break;
  465:     case 0x05:
  466:         fdctrl_write_data(fdctrl, value);
  467:         break;
  468:     default:
  469:         break;
  470:     }
  471: }
  472: 
  473: static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
  474: {
  475:     return fdctrl_read(opaque, (uint32_t)reg);
  476: }
  477: 
  478: static void fdctrl_write_mem (void *opaque,
  479:                               target_phys_addr_t reg, uint32_t value)
  480: {
  481:     fdctrl_write(opaque, (uint32_t)reg, value);
  482: }
  483: 
  484: static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
  485:     fdctrl_read_mem,
  486:     fdctrl_read_mem,
  487:     fdctrl_read_mem,
  488: };
  489: 
  490: static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
  491:     fdctrl_write_mem,
  492:     fdctrl_write_mem,
  493:     fdctrl_write_mem,
  494: };
  495: 
  496: static CPUReadMemoryFunc *fdctrl_mem_read_strict[3] = {
  497:     fdctrl_read_mem,
  498:     NULL,
  499:     NULL,
  500: };
  501: 
  502: static CPUWriteMemoryFunc *fdctrl_mem_write_strict[3] = {
  503:     fdctrl_write_mem,
  504:     NULL,
  505:     NULL,
  506: };
  507: 
  508: static void fd_save (QEMUFile *f, fdrive_t *fd)
  509: {
  510:     uint8_t tmp;
  511: 
  512:     tmp = fd->drflags;
  513:     qemu_put_8s(f, &tmp);
  514:     qemu_put_8s(f, &fd->head);
  515:     qemu_put_8s(f, &fd->track);
  516:     qemu_put_8s(f, &fd->sect);
  517:     qemu_put_8s(f, &fd->dir);
  518:     qemu_put_8s(f, &fd->rw);
  519: }
  520: 
  521: static void fdc_save (QEMUFile *f, void *opaque)
  522: {
  523:     fdctrl_t *s = opaque;
  524: 
  525:     qemu_put_8s(f, &s->state);
  526:     qemu_put_8s(f, &s->dma_en);
  527:     qemu_put_8s(f, &s->cur_drv);
  528:     qemu_put_8s(f, &s->bootsel);
  529:     qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
  530:     qemu_put_be32s(f, &s->data_pos);
  531:     qemu_put_be32s(f, &s->data_len);
  532:     qemu_put_8s(f, &s->data_state);
  533:     qemu_put_8s(f, &s->data_dir);
  534:     qemu_put_8s(f, &s->int_status);
  535:     qemu_put_8s(f, &s->eot);
  536:     qemu_put_8s(f, &s->timer0);
  537:     qemu_put_8s(f, &s->timer1);
  538:     qemu_put_8s(f, &s->precomp_trk);
  539:     qemu_put_8s(f, &s->config);
  540:     qemu_put_8s(f, &s->lock);
  541:     qemu_put_8s(f, &s->pwrd);
  542:     fd_save(f, &s->drives[0]);
  543:     fd_save(f, &s->drives[1]);
  544: }
  545: 
  546: static int fd_load (QEMUFile *f, fdrive_t *fd)
  547: {
  548:     uint8_t tmp;
  549: 
  550:     qemu_get_8s(f, &tmp);
  551:     fd->drflags = tmp;
  552:     qemu_get_8s(f, &fd->head);
  553:     qemu_get_8s(f, &fd->track);
  554:     qemu_get_8s(f, &fd->sect);
  555:     qemu_get_8s(f, &fd->dir);
  556:     qemu_get_8s(f, &fd->rw);
  557: 
  558:     return 0;
  559: }
  560: 
  561: static int fdc_load (QEMUFile *f, void *opaque, int version_id)
  562: {
  563:     fdctrl_t *s = opaque;
  564:     int ret;
  565: 
  566:     if (version_id != 1)
  567:         return -EINVAL;
  568: 
  569:     qemu_get_8s(f, &s->state);
  570:     qemu_get_8s(f, &s->dma_en);
  571: