|
|
1.1 root 1: /*
2: * QEMU Floppy disk emulator (Intel 82078)
1.1.1.3 root 3: *
4: * Copyright (c) 2003, 2007 Jocelyn Mayer
1.1.1.4 root 5: * Copyright (c) 2008 Herv� Poussineau
1.1.1.3 root 6: *
1.1 root 7: * Permission is hereby granted, free of charge, to any person obtaining a copy
8: * of this software and associated documentation files (the "Software"), to deal
9: * in the Software without restriction, including without limitation the rights
10: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11: * copies of the Software, and to permit persons to whom the Software is
12: * furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included in
15: * all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23: * THE SOFTWARE.
24: */
25: /*
26: * The controller is used in Sun4m systems in a slightly different
27: * way. There are changes in DOR register and DMA is not available.
28: */
1.1.1.5 root 29:
1.1.1.3 root 30: #include "hw.h"
31: #include "fdc.h"
1.1.1.10 root 32: #include "qemu-error.h"
1.1.1.3 root 33: #include "qemu-timer.h"
34: #include "isa.h"
1.1.1.5 root 35: #include "sysbus.h"
36: #include "qdev-addr.h"
1.1.1.11 root 37: #include "blockdev.h"
38: #include "sysemu.h"
1.1 root 39:
40: /********************************************************/
41: /* debug Floppy devices */
42: //#define DEBUG_FLOPPY
43:
44: #ifdef DEBUG_FLOPPY
1.1.1.5 root 45: #define FLOPPY_DPRINTF(fmt, ...) \
46: do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
1.1 root 47: #else
1.1.1.5 root 48: #define FLOPPY_DPRINTF(fmt, ...)
1.1 root 49: #endif
50:
1.1.1.5 root 51: #define FLOPPY_ERROR(fmt, ...) \
52: do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
1.1 root 53:
54: /********************************************************/
55: /* Floppy drive emulation */
56:
1.1.1.4 root 57: #define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
58: #define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
59:
1.1 root 60: /* Will always be a fixed parameter for us */
1.1.1.4 root 61: #define FD_SECTOR_LEN 512
62: #define FD_SECTOR_SC 2 /* Sector size code */
63: #define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */
1.1 root 64:
65: /* Floppy disk drive emulation */
1.1.1.10 root 66: typedef enum FDiskFlags {
1.1 root 67: FDISK_DBL_SIDES = 0x01,
1.1.1.10 root 68: } FDiskFlags;
1.1 root 69:
1.1.1.10 root 70: typedef struct FDrive {
1.1 root 71: BlockDriverState *bs;
72: /* Drive status */
1.1.1.10 root 73: FDriveType drive;
1.1 root 74: uint8_t perpendicular; /* 2.88 MB access mode */
75: /* Position */
76: uint8_t head;
77: uint8_t track;
78: uint8_t sect;
79: /* Media */
1.1.1.10 root 80: FDiskFlags flags;
1.1 root 81: uint8_t last_sect; /* Nb sector per track */
82: uint8_t max_track; /* Nb of tracks */
83: uint16_t bps; /* Bytes per sector */
84: uint8_t ro; /* Is read-only */
1.1.1.13! root 85: uint8_t media_changed; /* Is media changed */
1.1.1.10 root 86: } FDrive;
1.1 root 87:
1.1.1.10 root 88: static void fd_init(FDrive *drv)
1.1 root 89: {
90: /* Drive */
91: drv->drive = FDRIVE_DRV_NONE;
92: drv->perpendicular = 0;
93: /* Disk */
94: drv->last_sect = 0;
95: drv->max_track = 0;
96: }
97:
1.1.1.10 root 98: static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
99: uint8_t last_sect)
1.1 root 100: {
101: return (((track * 2) + head) * last_sect) + sect - 1;
102: }
103:
104: /* Returns current position, in sectors, for given drive */
1.1.1.10 root 105: static int fd_sector(FDrive *drv)
1.1 root 106: {
1.1.1.10 root 107: return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect);
1.1 root 108: }
109:
1.1.1.4 root 110: /* Seek to a new position:
111: * returns 0 if already on right track
112: * returns 1 if track changed
113: * returns 2 if track is invalid
114: * returns 3 if sector is invalid
115: * returns 4 if seek is disabled
116: */
1.1.1.10 root 117: static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
118: int enable_seek)
1.1 root 119: {
120: uint32_t sector;
121: int ret;
122:
123: if (track > drv->max_track ||
1.1.1.3 root 124: (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
1.1 root 125: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
126: head, track, sect, 1,
127: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
128: drv->max_track, drv->last_sect);
129: return 2;
130: }
131: if (sect > drv->last_sect) {
132: FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
133: head, track, sect, 1,
134: (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
135: drv->max_track, drv->last_sect);
136: return 3;
137: }
1.1.1.10 root 138: sector = fd_sector_calc(head, track, sect, drv->last_sect);
1.1 root 139: ret = 0;
140: if (sector != fd_sector(drv)) {
141: #if 0
142: if (!enable_seek) {
143: FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
144: head, track, sect, 1, drv->max_track, drv->last_sect);
145: return 4;
146: }
147: #endif
148: drv->head = head;
1.1.1.3 root 149: if (drv->track != track)
150: ret = 1;
1.1 root 151: drv->track = track;
152: drv->sect = sect;
153: }
154:
155: return ret;
156: }
157:
158: /* Set drive back to track 0 */
1.1.1.10 root 159: static void fd_recalibrate(FDrive *drv)
1.1 root 160: {
161: FLOPPY_DPRINTF("recalibrate\n");
162: drv->head = 0;
163: drv->track = 0;
164: drv->sect = 1;
165: }
166:
167: /* Revalidate a disk drive after a disk change */
1.1.1.10 root 168: static void fd_revalidate(FDrive *drv)
1.1 root 169: {
170: int nb_heads, max_track, last_sect, ro;
1.1.1.12 root 171: FDriveType drive;
1.1 root 172:
173: FLOPPY_DPRINTF("revalidate\n");
174: if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
1.1.1.3 root 175: ro = bdrv_is_read_only(drv->bs);
1.1.1.12 root 176: bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
177: &last_sect, drv->drive, &drive);
1.1.1.3 root 178: if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
179: FLOPPY_DPRINTF("User defined disk (%d %d %d)",
1.1 root 180: nb_heads - 1, max_track, last_sect);
1.1.1.3 root 181: } else {
1.1.1.12 root 182: FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
183: max_track, last_sect, ro ? "ro" : "rw");
1.1.1.3 root 184: }
185: if (nb_heads == 1) {
186: drv->flags &= ~FDISK_DBL_SIDES;
187: } else {
188: drv->flags |= FDISK_DBL_SIDES;
189: }
190: drv->max_track = max_track;
191: drv->last_sect = last_sect;
192: drv->ro = ro;
1.1.1.12 root 193: drv->drive = drive;
1.1 root 194: } else {
1.1.1.3 root 195: FLOPPY_DPRINTF("No disk in drive\n");
1.1 root 196: drv->last_sect = 0;
1.1.1.3 root 197: drv->max_track = 0;
198: drv->flags &= ~FDISK_DBL_SIDES;
1.1 root 199: }
200: }
201:
202: /********************************************************/
203: /* Intel 82078 floppy disk controller emulation */
204:
1.1.1.12 root 205: typedef struct FDCtrl FDCtrl;
206:
1.1.1.10 root 207: static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
208: static void fdctrl_reset_fifo(FDCtrl *fdctrl);
1.1 root 209: static int fdctrl_transfer_handler (void *opaque, int nchan,
210: int dma_pos, int dma_len);
1.1.1.10 root 211: static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0);
1.1 root 212:
1.1.1.10 root 213: static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
214: static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
215: static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
216: static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
217: static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
218: static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
219: static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
220: static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
221: static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
222: static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
223: static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
1.1 root 224:
225: enum {
226: FD_DIR_WRITE = 0,
227: FD_DIR_READ = 1,
228: FD_DIR_SCANE = 2,
229: FD_DIR_SCANL = 3,
230: FD_DIR_SCANH = 4,
231: };
232:
233: enum {
1.1.1.4 root 234: FD_STATE_MULTI = 0x01, /* multi track flag */
235: FD_STATE_FORMAT = 0x02, /* format flag */
236: FD_STATE_SEEK = 0x04, /* seek flag */
237: };
238:
239: enum {
240: FD_REG_SRA = 0x00,
241: FD_REG_SRB = 0x01,
242: FD_REG_DOR = 0x02,
243: FD_REG_TDR = 0x03,
244: FD_REG_MSR = 0x04,
245: FD_REG_DSR = 0x04,
246: FD_REG_FIFO = 0x05,
247: FD_REG_DIR = 0x07,
248: };
249:
250: enum {
251: FD_CMD_READ_TRACK = 0x02,
252: FD_CMD_SPECIFY = 0x03,
253: FD_CMD_SENSE_DRIVE_STATUS = 0x04,
254: FD_CMD_WRITE = 0x05,
255: FD_CMD_READ = 0x06,
256: FD_CMD_RECALIBRATE = 0x07,
257: FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
258: FD_CMD_WRITE_DELETED = 0x09,
259: FD_CMD_READ_ID = 0x0a,
260: FD_CMD_READ_DELETED = 0x0c,
261: FD_CMD_FORMAT_TRACK = 0x0d,
262: FD_CMD_DUMPREG = 0x0e,
263: FD_CMD_SEEK = 0x0f,
264: FD_CMD_VERSION = 0x10,
265: FD_CMD_SCAN_EQUAL = 0x11,
266: FD_CMD_PERPENDICULAR_MODE = 0x12,
267: FD_CMD_CONFIGURE = 0x13,
268: FD_CMD_LOCK = 0x14,
269: FD_CMD_VERIFY = 0x16,
270: FD_CMD_POWERDOWN_MODE = 0x17,
271: FD_CMD_PART_ID = 0x18,
272: FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
273: FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
1.1.1.9 root 274: FD_CMD_SAVE = 0x2e,
1.1.1.4 root 275: FD_CMD_OPTION = 0x33,
1.1.1.9 root 276: FD_CMD_RESTORE = 0x4e,
1.1.1.4 root 277: FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
278: FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
279: FD_CMD_FORMAT_AND_WRITE = 0xcd,
280: FD_CMD_RELATIVE_SEEK_IN = 0xcf,
281: };
282:
283: enum {
284: FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
285: FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
286: FD_CONFIG_POLL = 0x10, /* Poll enabled */
287: FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
288: FD_CONFIG_EIS = 0x40, /* No implied seeks */
289: };
290:
291: enum {
292: FD_SR0_EQPMT = 0x10,
293: FD_SR0_SEEK = 0x20,
294: FD_SR0_ABNTERM = 0x40,
295: FD_SR0_INVCMD = 0x80,
296: FD_SR0_RDYCHG = 0xc0,
297: };
298:
299: enum {
300: FD_SR1_EC = 0x80, /* End of cylinder */
301: };
302:
303: enum {
304: FD_SR2_SNS = 0x04, /* Scan not satisfied */
305: FD_SR2_SEH = 0x08, /* Scan equal hit */
306: };
307:
308: enum {
309: FD_SRA_DIR = 0x01,
310: FD_SRA_nWP = 0x02,
311: FD_SRA_nINDX = 0x04,
312: FD_SRA_HDSEL = 0x08,
313: FD_SRA_nTRK0 = 0x10,
314: FD_SRA_STEP = 0x20,
315: FD_SRA_nDRV2 = 0x40,
316: FD_SRA_INTPEND = 0x80,
317: };
318:
319: enum {
320: FD_SRB_MTR0 = 0x01,
321: FD_SRB_MTR1 = 0x02,
322: FD_SRB_WGATE = 0x04,
323: FD_SRB_RDATA = 0x08,
324: FD_SRB_WDATA = 0x10,
325: FD_SRB_DR0 = 0x20,
326: };
327:
328: enum {
329: #if MAX_FD == 4
330: FD_DOR_SELMASK = 0x03,
331: #else
332: FD_DOR_SELMASK = 0x01,
333: #endif
334: FD_DOR_nRESET = 0x04,
335: FD_DOR_DMAEN = 0x08,
336: FD_DOR_MOTEN0 = 0x10,
337: FD_DOR_MOTEN1 = 0x20,
338: FD_DOR_MOTEN2 = 0x40,
339: FD_DOR_MOTEN3 = 0x80,
340: };
341:
342: enum {
343: #if MAX_FD == 4
344: FD_TDR_BOOTSEL = 0x0c,
345: #else
346: FD_TDR_BOOTSEL = 0x04,
347: #endif
348: };
349:
350: enum {
351: FD_DSR_DRATEMASK= 0x03,
352: FD_DSR_PWRDOWN = 0x40,
353: FD_DSR_SWRESET = 0x80,
354: };
355:
356: enum {
357: FD_MSR_DRV0BUSY = 0x01,
358: FD_MSR_DRV1BUSY = 0x02,
359: FD_MSR_DRV2BUSY = 0x04,
360: FD_MSR_DRV3BUSY = 0x08,
361: FD_MSR_CMDBUSY = 0x10,
362: FD_MSR_NONDMA = 0x20,
363: FD_MSR_DIO = 0x40,
364: FD_MSR_RQM = 0x80,
365: };
366:
367: enum {
368: FD_DIR_DSKCHG = 0x80,
1.1 root 369: };
370:
371: #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
372: #define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
373: #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
374:
1.1.1.10 root 375: struct FDCtrl {
1.1.1.3 root 376: qemu_irq irq;
1.1 root 377: /* Controller state */
378: QEMUTimer *result_timer;
1.1.1.13! root 379: int dma_chann;
! 380: /* Controller's identification */
! 381: uint8_t version;
! 382: /* HW */
1.1.1.4 root 383: uint8_t sra;
384: uint8_t srb;
385: uint8_t dor;
1.1.1.6 root 386: uint8_t dor_vmstate; /* only used as temp during vmstate */
1.1.1.4 root 387: uint8_t tdr;
388: uint8_t dsr;
389: uint8_t msr;
1.1 root 390: uint8_t cur_drv;
1.1.1.4 root 391: uint8_t status0;
392: uint8_t status1;
393: uint8_t status2;
1.1 root 394: /* Command FIFO */
1.1.1.3 root 395: uint8_t *fifo;
1.1.1.6 root 396: int32_t fifo_size;
1.1 root 397: uint32_t data_pos;
398: uint32_t data_len;
399: uint8_t data_state;
400: uint8_t data_dir;
401: uint8_t eot; /* last wanted sector */
402: /* States kept only to be returned back */
403: /* precompensation */
404: uint8_t precomp_trk;
405: uint8_t config;
406: uint8_t lock;
407: /* Power down config (also with status regB access mode */
408: uint8_t pwrd;
409: /* Floppy drives */
1.1.1.6 root 410: uint8_t num_floppies;
1.1.1.13! root 411: /* Sun4m quirks? */
! 412: int sun4m;
1.1.1.10 root 413: FDrive drives[MAX_FD];
1.1.1.4 root 414: int reset_sensei;
1.1.1.13! root 415: /* Timers state */
! 416: uint8_t timer0;
! 417: uint8_t timer1;
1.1 root 418: };
419:
1.1.1.10 root 420: typedef struct FDCtrlSysBus {
1.1.1.6 root 421: SysBusDevice busdev;
1.1.1.10 root 422: struct FDCtrl state;
423: } FDCtrlSysBus;
1.1.1.6 root 424:
1.1.1.10 root 425: typedef struct FDCtrlISABus {
1.1.1.6 root 426: ISADevice busdev;
1.1.1.10 root 427: struct FDCtrl state;
1.1.1.11 root 428: int32_t bootindexA;
429: int32_t bootindexB;
1.1.1.10 root 430: } FDCtrlISABus;
1.1.1.6 root 431:
1.1 root 432: static uint32_t fdctrl_read (void *opaque, uint32_t reg)
433: {
1.1.1.10 root 434: FDCtrl *fdctrl = opaque;
1.1 root 435: uint32_t retval;
436:
1.1.1.13! root 437: reg &= 7;
1.1.1.4 root 438: switch (reg) {
439: case FD_REG_SRA:
440: retval = fdctrl_read_statusA(fdctrl);
1.1.1.3 root 441: break;
1.1.1.4 root 442: case FD_REG_SRB:
1.1.1.3 root 443: retval = fdctrl_read_statusB(fdctrl);
444: break;
1.1.1.4 root 445: case FD_REG_DOR:
1.1.1.3 root 446: retval = fdctrl_read_dor(fdctrl);
447: break;
1.1.1.4 root 448: case FD_REG_TDR:
1.1 root 449: retval = fdctrl_read_tape(fdctrl);
1.1.1.3 root 450: break;
1.1.1.4 root 451: case FD_REG_MSR:
1.1 root 452: retval = fdctrl_read_main_status(fdctrl);
1.1.1.3 root 453: break;
1.1.1.4 root 454: case FD_REG_FIFO:
1.1 root 455: retval = fdctrl_read_data(fdctrl);
1.1.1.3 root 456: break;
1.1.1.4 root 457: case FD_REG_DIR:
1.1 root 458: retval = fdctrl_read_dir(fdctrl);
1.1.1.3 root 459: break;
1.1 root 460: default:
1.1.1.3 root 461: retval = (uint32_t)(-1);
462: break;
1.1 root 463: }
464: FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
465:
466: return retval;
467: }
468:
469: static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
470: {
1.1.1.10 root 471: FDCtrl *fdctrl = opaque;
1.1 root 472:
473: FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
474:
1.1.1.13! root 475: reg &= 7;
1.1.1.4 root 476: switch (reg) {
477: case FD_REG_DOR:
1.1.1.3 root 478: fdctrl_write_dor(fdctrl, value);
479: break;
1.1.1.4 root 480: case FD_REG_TDR:
1.1 root 481: fdctrl_write_tape(fdctrl, value);
1.1.1.3 root 482: break;
1.1.1.4 root 483: case FD_REG_DSR:
1.1 root 484: fdctrl_write_rate(fdctrl, value);
1.1.1.3 root 485: break;
1.1.1.4 root 486: case FD_REG_FIFO:
1.1 root 487: fdctrl_write_data(fdctrl, value);
1.1.1.3 root 488: break;
1.1 root 489: default:
1.1.1.3 root 490: break;
1.1 root 491: }
492: }
493:
494: static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
495: {
1.1.1.3 root 496: return fdctrl_read(opaque, (uint32_t)reg);
1.1 root 497: }
498:
1.1.1.3 root 499: static void fdctrl_write_mem (void *opaque,
1.1 root 500: target_phys_addr_t reg, uint32_t value)
501: {
1.1.1.3 root 502: fdctrl_write(opaque, (uint32_t)reg, value);
1.1 root 503: }
504:
1.1.1.6 root 505: static CPUReadMemoryFunc * const fdctrl_mem_read[3] = {
1.1 root 506: fdctrl_read_mem,
507: fdctrl_read_mem,
508: fdctrl_read_mem,
509: };
510:
1.1.1.6 root 511: static CPUWriteMemoryFunc * const fdctrl_mem_write[3] = {
1.1 root 512: fdctrl_write_mem,
513: fdctrl_write_mem,
514: fdctrl_write_mem,
515: };
516:
1.1.1.6 root 517: static CPUReadMemoryFunc * const fdctrl_mem_read_strict[3] = {
1.1.1.3 root 518: fdctrl_read_mem,
519: NULL,
520: NULL,
521: };
522:
1.1.1.6 root 523: static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
1.1.1.3 root 524: fdctrl_write_mem,
525: NULL,
526: NULL,
527: };
528:
1.1.1.13! root 529: static bool fdrive_media_changed_needed(void *opaque)
! 530: {
! 531: FDrive *drive = opaque;
! 532:
! 533: return (drive->bs != NULL && drive->media_changed != 1);
! 534: }
! 535:
! 536: static const VMStateDescription vmstate_fdrive_media_changed = {
! 537: .name = "fdrive/media_changed",
! 538: .version_id = 1,
! 539: .minimum_version_id = 1,
! 540: .minimum_version_id_old = 1,
! 541: .fields = (VMStateField[]) {
! 542: VMSTATE_UINT8(media_changed, FDrive),
! 543: VMSTATE_END_OF_LIST()
! 544: }
! 545: };
! 546:
1.1.1.6 root 547: static const VMStateDescription vmstate_fdrive = {
548: .name = "fdrive",
549: .version_id = 1,
550: .minimum_version_id = 1,
551: .minimum_version_id_old = 1,
1.1.1.13! root 552: .fields = (VMStateField[]) {
1.1.1.10 root 553: VMSTATE_UINT8(head, FDrive),
554: VMSTATE_UINT8(track, FDrive),
555: VMSTATE_UINT8(sect, FDrive),
1.1.1.6 root 556: VMSTATE_END_OF_LIST()
1.1.1.13! root 557: },
! 558: .subsections = (VMStateSubsection[]) {
! 559: {
! 560: .vmsd = &vmstate_fdrive_media_changed,
! 561: .needed = &fdrive_media_changed_needed,
! 562: } , {
! 563: /* empty */
! 564: }
1.1.1.6 root 565: }
566: };
1.1.1.3 root 567:
1.1.1.6 root 568: static void fdc_pre_save(void *opaque)
1.1.1.3 root 569: {
1.1.1.10 root 570: FDCtrl *s = opaque;
1.1.1.4 root 571:
1.1.1.6 root 572: s->dor_vmstate = s->dor | GET_CUR_DRV(s);
1.1.1.3 root 573: }
574:
1.1.1.6 root 575: static int fdc_post_load(void *opaque, int version_id)
1.1.1.3 root 576: {
1.1.1.10 root 577: FDCtrl *s = opaque;
1.1.1.3 root 578:
1.1.1.6 root 579: SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
580: s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
1.1.1.3 root 581: return 0;
582: }
583:
1.1.1.6 root 584: static const VMStateDescription vmstate_fdc = {
585: .name = "fdc",
586: .version_id = 2,
587: .minimum_version_id = 2,
588: .minimum_version_id_old = 2,
589: .pre_save = fdc_pre_save,
590: .post_load = fdc_post_load,
591: .fields = (VMStateField []) {
592: /* Controller State */
1.1.1.10 root 593: VMSTATE_UINT8(sra, FDCtrl),
594: VMSTATE_UINT8(srb, FDCtrl),
595: VMSTATE_UINT8(dor_vmstate, FDCtrl),
596: VMSTATE_UINT8(tdr, FDCtrl),
597: VMSTATE_UINT8(dsr, FDCtrl),
598: VMSTATE_UINT8(msr, FDCtrl),
599: VMSTATE_UINT8(status0, FDCtrl),
600: VMSTATE_UINT8(status1, FDCtrl),
601: VMSTATE_UINT8(status2, FDCtrl),
1.1.1.6 root 602: /* Command FIFO */
1.1.1.10 root 603: VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
604: uint8_t),
605: VMSTATE_UINT32(data_pos, FDCtrl),
606: VMSTATE_UINT32(data_len, FDCtrl),
607: VMSTATE_UINT8(data_state, FDCtrl),
608: VMSTATE_UINT8(data_dir, FDCtrl),
609: VMSTATE_UINT8(eot, FDCtrl),
1.1.1.6 root 610: /* States kept only to be returned back */
1.1.1.10 root 611: VMSTATE_UINT8(timer0, FDCtrl),
612: VMSTATE_UINT8(timer1, FDCtrl),
613: VMSTATE_UINT8(precomp_trk, FDCtrl),
614: VMSTATE_UINT8(config, FDCtrl),
615: VMSTATE_UINT8(lock, FDCtrl),
616: VMSTATE_UINT8(pwrd, FDCtrl),
617: VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
618: VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
619: vmstate_fdrive, FDrive),
1.1.1.6 root 620: VMSTATE_END_OF_LIST()
1.1.1.4 root 621: }
1.1.1.6 root 622: };
1.1.1.3 root 623:
1.1.1.6 root 624: static void fdctrl_external_reset_sysbus(DeviceState *d)
625: {
1.1.1.10 root 626: FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
627: FDCtrl *s = &sys->state;
1.1.1.6 root 628:
629: fdctrl_reset(s, 0);
1.1.1.3 root 630: }
631:
1.1.1.6 root 632: static void fdctrl_external_reset_isa(DeviceState *d)
1.1.1.3 root 633: {
1.1.1.10 root 634: FDCtrlISABus *isa = container_of(d, FDCtrlISABus, busdev.qdev);
635: FDCtrl *s = &isa->state;
1.1.1.3 root 636:
637: fdctrl_reset(s, 0);
638: }
639:
1.1.1.4 root 640: static void fdctrl_handle_tc(void *opaque, int irq, int level)
1.1.1.3 root 641: {
1.1.1.10 root 642: //FDCtrl *s = opaque;
1.1.1.3 root 643:
1.1.1.4 root 644: if (level) {
645: // XXX
646: FLOPPY_DPRINTF("TC pulsed\n");
1.1 root 647: }
1.1.1.3 root 648: }
649:
1.1 root 650: /* Change IRQ state */
1.1.1.10 root 651: static void fdctrl_reset_irq(FDCtrl *fdctrl)
1.1 root 652: {
1.1.1.4 root 653: if (!(fdctrl->sra & FD_SRA_INTPEND))
654: return;
1.1 root 655: FLOPPY_DPRINTF("Reset interrupt\n");
1.1.1.3 root 656: qemu_set_irq(fdctrl->irq, 0);
1.1.1.4 root 657: fdctrl->sra &= ~FD_SRA_INTPEND;
1.1 root 658: }
659:
1.1.1.10 root 660: static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
1.1 root 661: {
1.1.1.4 root 662: /* Sparc mutation */
663: if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
664: /* XXX: not sure */
665: fdctrl->msr &= ~FD_MSR_CMDBUSY;
666: fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
667: fdctrl->status0 = status0;
1.1.1.3 root 668: return;
1.1 root 669: }
1.1.1.4 root 670: if (!(fdctrl->sra & FD_SRA_INTPEND)) {
1.1.1.3 root 671: qemu_set_irq(fdctrl->irq, 1);
1.1.1.4 root 672: fdctrl->sra |= FD_SRA_INTPEND;
1.1 root 673: }
1.1.1.4 root 674: fdctrl->reset_sensei = 0;
675: fdctrl->status0 = status0;
676: FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
1.1 root 677: }
678:
679: /* Reset controller */
1.1.1.10 root 680: static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
1.1 root 681: {
682: int i;
683:
684: FLOPPY_DPRINTF("reset controller\n");
685: fdctrl_reset_irq(fdctrl);
686: /* Initialise controller */
1.1.1.4 root 687: fdctrl->sra = 0;
688: fdctrl->srb = 0xc0;
689: if (!fdctrl->drives[1].bs)
690: fdctrl->sra |= FD_SRA_nDRV2;
1.1 root 691: fdctrl->cur_drv = 0;
1.1.1.4 root 692: fdctrl->dor = FD_DOR_nRESET;
693: fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
694: fdctrl->msr = FD_MSR_RQM;
1.1 root 695: /* FIFO state */
696: fdctrl->data_pos = 0;
697: fdctrl->data_len = 0;
1.1.1.4 root 698: fdctrl->data_state = 0;
1.1 root 699: fdctrl->data_dir = FD_DIR_WRITE;
700: for (i = 0; i < MAX_FD; i++)
1.1.1.4 root 701: fd_recalibrate(&fdctrl->drives[i]);
1.1 root 702: fdctrl_reset_fifo(fdctrl);
1.1.1.4 root 703: if (do_irq) {
704: fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
705: fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
706: }
1.1 root 707: }
708:
1.1.1.10 root 709: static inline FDrive *drv0(FDCtrl *fdctrl)
1.1 root 710: {
1.1.1.4 root 711: return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
1.1 root 712: }
713:
1.1.1.10 root 714: static inline FDrive *drv1(FDCtrl *fdctrl)
1.1 root 715: {
1.1.1.4 root 716: if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
717: return &fdctrl->drives[1];
718: else
719: return &fdctrl->drives[0];
720: }
721:
722: #if MAX_FD == 4
1.1.1.10 root 723: static inline FDrive *drv2(FDCtrl *fdctrl)
1.1.1.4 root 724: {
725: if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
726: return &fdctrl->drives[2];
727: else
728: return &fdctrl->drives[1];
729: }
730:
1.1.1.10 root 731: static inline FDrive *drv3(FDCtrl *fdctrl)
1.1.1.4 root 732: {
733: if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
734: return &fdctrl->drives[3];
735: else
736: return &fdctrl->drives[2];
1.1 root 737: }
1.1.1.4 root 738: #endif
1.1 root 739:
1.1.1.10 root 740: static FDrive *get_cur_drv(FDCtrl *fdctrl)
1.1 root 741: {
1.1.1.4 root 742: switch (fdctrl->cur_drv) {
743: case 0: return drv0(fdctrl);
744: case 1: return drv1(fdctrl);
745: #if MAX_FD == 4
746: case 2: return drv2(fdctrl);
747: case 3: return drv3(fdctrl);
748: #endif
749: default: return NULL;
750: }
751: }
752:
753: /* Status A register : 0x00 (read-only) */
1.1.1.10 root 754: static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
1.1.1.4 root 755: {
756: uint32_t retval = fdctrl->sra;
757:
758: FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
759:
760: return retval;
1.1 root 761: }
762:
763: /* Status B register : 0x01 (read-only) */
1.1.1.10 root 764: static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
1.1 root 765: {
1.1.1.4 root 766: uint32_t retval = fdctrl->srb;
767:
768: FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
769:
770: return retval;
1.1 root 771: }
772:
773: /* Digital output register : 0x02 */
1.1.1.10 root 774: static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
1.1 root 775: {
1.1.1.4 root 776: uint32_t retval = fdctrl->dor;
1.1 root 777:
778: /* Selected drive */
779: retval |= fdctrl->cur_drv;
780: FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
781:
782: return retval;
783: }
784:
1.1.1.10 root 785: static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
1.1 root 786: {
787: FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
1.1.1.4 root 788:
789: /* Motors */
790: if (value & FD_DOR_MOTEN0)
791: fdctrl->srb |= FD_SRB_MTR0;
1.1 root 792: else
1.1.1.4 root 793: fdctrl->srb &= ~FD_SRB_MTR0;
794: if (value & FD_DOR_MOTEN1)
795: fdctrl->srb |= FD_SRB_MTR1;
1.1 root 796: else
1.1.1.4 root 797: fdctrl->srb &= ~FD_SRB_MTR1;
798:
799: /* Drive */
800: if (value & 1)
801: fdctrl->srb |= FD_SRB_DR0;
802: else
803: fdctrl->srb &= ~FD_SRB_DR0;
804:
1.1 root 805: /* Reset */
1.1.1.4 root 806: if (!(value & FD_DOR_nRESET)) {
807: if (fdctrl->dor & FD_DOR_nRESET) {
1.1 root 808: FLOPPY_DPRINTF("controller enter RESET state\n");
809: }
810: } else {
1.1.1.4 root 811: if (!(fdctrl->dor & FD_DOR_nRESET)) {
1.1 root 812: FLOPPY_DPRINTF("controller out of RESET state\n");
813: fdctrl_reset(fdctrl, 1);
1.1.1.4 root 814: fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1.1 root 815: }
816: }
817: /* Selected drive */
1.1.1.4 root 818: fdctrl->cur_drv = value & FD_DOR_SELMASK;
819:
820: fdctrl->dor = value;
1.1 root 821: }
822:
823: /* Tape drive register : 0x03 */
1.1.1.10 root 824: static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
1.1 root 825: {
1.1.1.4 root 826: uint32_t retval = fdctrl->tdr;
1.1 root 827:
828: FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
829:
830: return retval;
831: }
832:
1.1.1.10 root 833: static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
1.1 root 834: {
835: /* Reset mode */
1.1.1.4 root 836: if (!(fdctrl->dor & FD_DOR_nRESET)) {
1.1 root 837: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
838: return;
839: }
840: FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
841: /* Disk boot selection indicator */
1.1.1.4 root 842: fdctrl->tdr = value & FD_TDR_BOOTSEL;
1.1 root 843: /* Tape indicators: never allow */
844: }
845:
846: /* Main status register : 0x04 (read) */
1.1.1.10 root 847: static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
1.1 root 848: {
1.1.1.4 root 849: uint32_t retval = fdctrl->msr;
850:
851: fdctrl->dsr &= ~FD_DSR_PWRDOWN;
852: fdctrl->dor |= FD_DOR_nRESET;
1.1 root 853:
1.1.1.7 root 854: /* Sparc mutation */
855: if (fdctrl->sun4m) {
856: retval |= FD_MSR_DIO;
857: fdctrl_reset_irq(fdctrl);
858: };
859:
1.1 root 860: FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
861:
862: return retval;
863: }
864:
865: /* Data select rate register : 0x04 (write) */
1.1.1.10 root 866: static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
1.1 root 867: {
868: /* Reset mode */
1.1.1.4 root 869: if (!(fdctrl->dor & FD_DOR_nRESET)) {
1.1.1.3 root 870: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
871: return;
872: }
1.1 root 873: FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
874: /* Reset: autoclear */
1.1.1.4 root 875: if (value & FD_DSR_SWRESET) {
876: fdctrl->dor &= ~FD_DOR_nRESET;
1.1 root 877: fdctrl_reset(fdctrl, 1);
1.1.1.4 root 878: fdctrl->dor |= FD_DOR_nRESET;
1.1 root 879: }
1.1.1.4 root 880: if (value & FD_DSR_PWRDOWN) {
1.1 root 881: fdctrl_reset(fdctrl, 1);
882: }
1.1.1.4 root 883: fdctrl->dsr = value;
1.1 root 884: }
885:
1.1.1.10 root 886: static int fdctrl_media_changed(FDrive *drv)
1.1.1.2 root 887: {
888: int ret;
1.1.1.3 root 889:
890: if (!drv->bs)
1.1.1.2 root 891: return 0;
1.1.1.13! root 892: if (drv->media_changed) {
! 893: drv->media_changed = 0;
! 894: ret = 1;
! 895: } else {
! 896: ret = bdrv_media_changed(drv->bs);
! 897: if (ret < 0) {
! 898: ret = 0; /* we don't know, assume no */
! 899: }
! 900: }
1.1.1.2 root 901: if (ret) {
902: fd_revalidate(drv);
903: }
904: return ret;
905: }
906:
1.1 root 907: /* Digital input register : 0x07 (read-only) */
1.1.1.10 root 908: static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
1.1 root 909: {
910: uint32_t retval = 0;
911:
1.1.1.4 root 912: if (fdctrl_media_changed(drv0(fdctrl))
913: || fdctrl_media_changed(drv1(fdctrl))
914: #if MAX_FD == 4
915: || fdctrl_media_changed(drv2(fdctrl))
916: || fdctrl_media_changed(drv3(fdctrl))
917: #endif
918: )
919: retval |= FD_DIR_DSKCHG;
1.1.1.10 root 920: if (retval != 0) {
1.1 root 921: FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
1.1.1.10 root 922: }
1.1 root 923:
924: return retval;
925: }
926:
927: /* FIFO state control */
1.1.1.10 root 928: static void fdctrl_reset_fifo(FDCtrl *fdctrl)
1.1 root 929: {
930: fdctrl->data_dir = FD_DIR_WRITE;
931: fdctrl->data_pos = 0;
1.1.1.4 root 932: fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
1.1 root 933: }
934:
935: /* Set FIFO status for the host to read */
1.1.1.10 root 936: static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, int do_irq)
1.1 root 937: {
938: fdctrl->data_dir = FD_DIR_READ;
939: fdctrl->data_len = fifo_len;
940: fdctrl->data_pos = 0;
1.1.1.4 root 941: fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
1.1 root 942: if (do_irq)
943: fdctrl_raise_irq(fdctrl, 0x00);
944: }
945:
946: /* Set an error: unimplemented/unknown command */
1.1.1.10 root 947: static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
1.1 root 948: {
1.1.1.4 root 949: FLOPPY_ERROR("unimplemented command 0x%02x\n", fdctrl->fifo[0]);
950: fdctrl->fifo[0] = FD_SR0_INVCMD;
1.1 root 951: fdctrl_set_fifo(fdctrl, 1, 0);
1.1.1.4 root 952: }
953:
954: /* Seek to next sector */
1.1.1.10 root 955: static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
1.1.1.4 root 956: {
957: FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
958: cur_drv->head, cur_drv->track, cur_drv->sect,
959: fd_sector(cur_drv));
960: /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
961: error in fact */
962: if (cur_drv->sect >= cur_drv->last_sect ||
963: cur_drv->sect == fdctrl->eot) {
964: cur_drv->sect = 1;
965: if (FD_MULTI_TRACK(fdctrl->data_state)) {
966: if (cur_drv->head == 0 &&
967: (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
968: cur_drv->head = 1;
969: } else {
970: cur_drv->head = 0;
971: cur_drv->track++;
972: if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
973: return 0;
974: }
975: } else {
976: cur_drv->track++;
977: return 0;
978: }
979: FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
980: cur_drv->head, cur_drv->track,
981: cur_drv->sect, fd_sector(cur_drv));
982: } else {
983: cur_drv->sect++;
984: }
985: return 1;
1.1 root 986: }
987:
988: /* Callback for transfer end (stop or abort) */
1.1.1.10 root 989: static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
990: uint8_t status1, uint8_t status2)
1.1 root 991: {
1.1.1.10 root 992: FDrive *cur_drv;
1.1 root 993:
994: cur_drv = get_cur_drv(fdctrl);
995: FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
996: status0, status1, status2,
1.1.1.4 root 997: status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl));
998: fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1.1 root 999: fdctrl->fifo[1] = status1;
1000: fdctrl->fifo[2] = status2;
1001: fdctrl->fifo[3] = cur_drv->track;
1002: fdctrl->fifo[4] = cur_drv->head;
1003: fdctrl->fifo[5] = cur_drv->sect;
1004: fdctrl->fifo[6] = FD_SECTOR_SC;
1005: fdctrl->data_dir = FD_DIR_READ;
1.1.1.4 root 1006: if (!(fdctrl->msr & FD_MSR_NONDMA)) {
1.1 root 1007: DMA_release_DREQ(fdctrl->dma_chann);
1008: }
1.1.1.4 root 1009: fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
1010: fdctrl->msr &= ~FD_MSR_NONDMA;
1.1 root 1011: fdctrl_set_fifo(fdctrl, 7, 1);
1012: }
1013:
1014: /* Prepare a data transfer (either DMA or FIFO) */
1.1.1.10 root 1015: static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
1.1 root 1016: {
1.1.1.10 root 1017: FDrive *cur_drv;
1.1 root 1018: uint8_t kh, kt, ks;
1.1.1.4 root 1019: int did_seek = 0;
1.1 root 1020:
1.1.1.4 root 1021: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1.1 root 1022: cur_drv = get_cur_drv(fdctrl);
1023: kt = fdctrl->fifo[2];
1024: kh = fdctrl->fifo[3];
1025: ks = fdctrl->fifo[4];
1026: FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
1.1.1.4 root 1027: GET_CUR_DRV(fdctrl), kh, kt, ks,
1.1.1.10 root 1028: fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
1.1.1.4 root 1029: switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
1.1 root 1030: case 2:
1031: /* sect too big */
1.1.1.4 root 1032: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1.1 root 1033: fdctrl->fifo[3] = kt;
1034: fdctrl->fifo[4] = kh;
1035: fdctrl->fifo[5] = ks;
1036: return;
1037: case 3:
1038: /* track too big */
1.1.1.4 root 1039: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1.1 root 1040: fdctrl->fifo[3] = kt;
1041: fdctrl->fifo[4] = kh;
1042: fdctrl->fifo[5] = ks;
1043: return;
1044: case 4:
1045: /* No seek enabled */
1.1.1.4 root 1046: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1.1 root 1047: fdctrl->fifo[3] = kt;
1048: fdctrl->fifo[4] = kh;
1049: fdctrl->fifo[5] = ks;
1050: return;
1051: case 1:
1052: did_seek = 1;
1053: break;
1054: default:
1055: break;
1056: }
1.1.1.4 root 1057:
1.1 root 1058: /* Set the FIFO state */
1059: fdctrl->data_dir = direction;
1060: fdctrl->data_pos = 0;
1.1.1.4 root 1061: fdctrl->msr |= FD_MSR_CMDBUSY;
1.1 root 1062: if (fdctrl->fifo[0] & 0x80)
1063: fdctrl->data_state |= FD_STATE_MULTI;
1064: else
1065: fdctrl->data_state &= ~FD_STATE_MULTI;
1066: if (did_seek)
1067: fdctrl->data_state |= FD_STATE_SEEK;
1068: else
1069: fdctrl->data_state &= ~FD_STATE_SEEK;
1070: if (fdctrl->fifo[5] == 00) {
1071: fdctrl->data_len = fdctrl->fifo[8];
1072: } else {
1.1.1.3 root 1073: int tmp;
1.1.1.2 root 1074: fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
1.1.1.4 root 1075: tmp = (fdctrl->fifo[6] - ks + 1);
1.1 root 1076: if (fdctrl->fifo[0] & 0x80)
1.1.1.4 root 1077: tmp += fdctrl->fifo[6];
1.1.1.3 root 1078: fdctrl->data_len *= tmp;
1.1 root 1079: }
1080: fdctrl->eot = fdctrl->fifo[6];
1.1.1.4 root 1081: if (fdctrl->dor & FD_DOR_DMAEN) {
1.1 root 1082: int dma_mode;
1083: /* DMA transfer are enabled. Check if DMA channel is well programmed */
1084: dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
1085: dma_mode = (dma_mode >> 2) & 3;
1086: FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
1.1.1.3 root 1087: dma_mode, direction,
1.1 root 1088: (128 << fdctrl->fifo[5]) *
1.1.1.3 root 1089: (cur_drv->last_sect - ks + 1), fdctrl->data_len);
1.1 root 1090: if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
1091: direction == FD_DIR_SCANH) && dma_mode == 0) ||
1092: (direction == FD_DIR_WRITE && dma_mode == 2) ||
1093: (direction == FD_DIR_READ && dma_mode == 1)) {
1094: /* No access is allowed until DMA transfer has completed */
1.1.1.4 root 1095: fdctrl->msr &= ~FD_MSR_RQM;
1.1 root 1096: /* Now, we just have to wait for the DMA controller to
1097: * recall us...
1098: */
1099: DMA_hold_DREQ(fdctrl->dma_chann);
1100: DMA_schedule(fdctrl->dma_chann);
1101: return;
1102: } else {
1.1.1.3 root 1103: FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
1.1 root 1104: }
1105: }
1106: FLOPPY_DPRINTF("start non-DMA transfer\n");
1.1.1.4 root 1107: fdctrl->msr |= FD_MSR_NONDMA;
1108: if (direction != FD_DIR_WRITE)
1109: fdctrl->msr |= FD_MSR_DIO;
1.1 root 1110: /* IO based transfer: calculate len */
1111: fdctrl_raise_irq(fdctrl, 0x00);
1112:
1113: return;
1114: }
1115:
1116: /* Prepare a transfer of deleted data */
1.1.1.10 root 1117: static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
1.1 root 1118: {
1.1.1.4 root 1119: FLOPPY_ERROR("fdctrl_start_transfer_del() unimplemented\n");
1120:
1.1 root 1121: /* We don't handle deleted data,
1122: * so we don't return *ANYTHING*
1123: */
1.1.1.4 root 1124: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1.1 root 1125: }
1126:
1127: /* handlers for DMA transfers */
1128: static int fdctrl_transfer_handler (void *opaque, int nchan,
1129: int dma_pos, int dma_len)
1130: {
1.1.1.10 root 1131: FDCtrl *fdctrl;
1132: FDrive *cur_drv;
1.1 root 1133: int len, start_pos, rel_pos;
1134: uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
1135:
1136: fdctrl = opaque;
1.1.1.4 root 1137: if (fdctrl->msr & FD_MSR_RQM) {
1.1 root 1138: FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
1139: return 0;
1140: }
1141: cur_drv = get_cur_drv(fdctrl);
1142: if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
1143: fdctrl->data_dir == FD_DIR_SCANH)
1.1.1.4 root 1144: status2 = FD_SR2_SNS;
1.1 root 1145: if (dma_len > fdctrl->data_len)
1146: dma_len = fdctrl->data_len;
1147: if (cur_drv->bs == NULL) {
1.1.1.3 root 1148: if (fdctrl->data_dir == FD_DIR_WRITE)
1.1.1.4 root 1149: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1.1.1.3 root 1150: else
1.1.1.4 root 1151: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1.1.1.3 root 1152: len = 0;
1.1 root 1153: goto transfer_error;
1154: }
1155: rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1156: for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
1157: len = dma_len - fdctrl->data_pos;
1158: if (len + rel_pos > FD_SECTOR_LEN)
1159: len = FD_SECTOR_LEN - rel_pos;
1160: FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
1161: "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
1.1.1.4 root 1162: fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
1.1 root 1163: cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
1.1.1.4 root 1164: fd_sector(cur_drv) * FD_SECTOR_LEN);
1.1 root 1165: if (fdctrl->data_dir != FD_DIR_WRITE ||
1.1.1.3 root 1166: len < FD_SECTOR_LEN || rel_pos != 0) {
1.1 root 1167: /* READ & SCAN commands and realign to a sector for WRITE */
1168: if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
1.1.1.3 root 1169: fdctrl->fifo, 1) < 0) {
1.1 root 1170: FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
1171: fd_sector(cur_drv));
1172: /* Sure, image size is too small... */
1173: memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1174: }
1175: }
1.1.1.3 root 1176: switch (fdctrl->data_dir) {
1177: case FD_DIR_READ:
1178: /* READ commands */
1.1 root 1179: DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
1180: fdctrl->data_pos, len);
1.1.1.3 root 1181: break;
1182: case FD_DIR_WRITE:
1.1 root 1183: /* WRITE commands */
1184: DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
1185: fdctrl->data_pos, len);
1186: if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1.1.1.3 root 1187: fdctrl->fifo, 1) < 0) {
1.1.1.4 root 1188: FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
1189: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1.1 root 1190: goto transfer_error;
1191: }
1.1.1.3 root 1192: break;
1193: default:
1194: /* SCAN commands */
1.1 root 1195: {
1.1.1.3 root 1196: uint8_t tmpbuf[FD_SECTOR_LEN];
1.1 root 1197: int ret;
1198: DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
1199: ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
1200: if (ret == 0) {
1.1.1.4 root 1201: status2 = FD_SR2_SEH;
1.1 root 1202: goto end_transfer;
1203: }
1204: if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
1205: (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
1206: status2 = 0x00;
1207: goto end_transfer;
1208: }
1209: }
1.1.1.3 root 1210: break;
1.1 root 1211: }
1.1.1.3 root 1212: fdctrl->data_pos += len;
1213: rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
1.1 root 1214: if (rel_pos == 0) {
1215: /* Seek to next sector */
1.1.1.4 root 1216: if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
1217: break;
1.1 root 1218: }
1219: }
1.1.1.3 root 1220: end_transfer:
1.1 root 1221: len = fdctrl->data_pos - start_pos;
1222: FLOPPY_DPRINTF("end transfer %d %d %d\n",
1.1.1.3 root 1223: fdctrl->data_pos, len, fdctrl->data_len);
1.1 root 1224: if (fdctrl->data_dir == FD_DIR_SCANE ||
1225: fdctrl->data_dir == FD_DIR_SCANL ||
1226: fdctrl->data_dir == FD_DIR_SCANH)
1.1.1.4 root 1227: status2 = FD_SR2_SEH;
1.1 root 1228: if (FD_DID_SEEK(fdctrl->data_state))
1.1.1.4 root 1229: status0 |= FD_SR0_SEEK;
1.1 root 1230: fdctrl->data_len -= len;
1231: fdctrl_stop_transfer(fdctrl, status0, status1, status2);
1.1.1.3 root 1232: transfer_error:
1.1 root 1233:
1234: return len;
1235: }
1236:
1237: /* Data register : 0x05 */
1.1.1.10 root 1238: static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
1.1 root 1239: {
1.1.1.10 root 1240: FDrive *cur_drv;
1.1 root 1241: uint32_t retval = 0;
1.1.1.4 root 1242: int pos;
1.1 root 1243:
1244: cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1245: fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1246: if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
1247: FLOPPY_ERROR("controller not ready for reading\n");
1.1 root 1248: return 0;
1249: }
1250: pos = fdctrl->data_pos;
1.1.1.4 root 1251: if (fdctrl->msr & FD_MSR_NONDMA) {
1.1 root 1252: pos %= FD_SECTOR_LEN;
1253: if (pos == 0) {
1.1.1.4 root 1254: if (fdctrl->data_pos != 0)
1255: if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
1256: FLOPPY_DPRINTF("error seeking to next sector %d\n",
1257: fd_sector(cur_drv));
1258: return 0;
1259: }
1260: if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1261: FLOPPY_DPRINTF("error getting sector %d\n",
1262: fd_sector(cur_drv));
1263: /* Sure, image size is too small... */
1264: memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1265: }
1.1 root 1266: }
1267: }
1268: retval = fdctrl->fifo[pos];
1269: if (++fdctrl->data_pos == fdctrl->data_len) {
1270: fdctrl->data_pos = 0;
1271: /* Switch from transfer mode to status mode
1272: * then from status mode to command mode
1273: */
1.1.1.4 root 1274: if (fdctrl->msr & FD_MSR_NONDMA) {
1275: fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1.1 root 1276: } else {
1277: fdctrl_reset_fifo(fdctrl);
1278: fdctrl_reset_irq(fdctrl);
1279: }
1280: }
1281: FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
1282:
1283: return retval;
1284: }
1285:
1.1.1.10 root 1286: static void fdctrl_format_sector(FDCtrl *fdctrl)
1.1 root 1287: {
1.1.1.10 root 1288: FDrive *cur_drv;
1.1 root 1289: uint8_t kh, kt, ks;
1290:
1.1.1.4 root 1291: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1.1 root 1292: cur_drv = get_cur_drv(fdctrl);
1293: kt = fdctrl->fifo[6];
1294: kh = fdctrl->fifo[7];
1295: ks = fdctrl->fifo[8];
1296: FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
1.1.1.4 root 1297: GET_CUR_DRV(fdctrl), kh, kt, ks,
1.1.1.10 root 1298: fd_sector_calc(kh, kt, ks, cur_drv->last_sect));
1.1.1.4 root 1299: switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
1.1 root 1300: case 2:
1301: /* sect too big */
1.1.1.4 root 1302: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1.1 root 1303: fdctrl->fifo[3] = kt;
1304: fdctrl->fifo[4] = kh;
1305: fdctrl->fifo[5] = ks;
1306: return;
1307: case 3:
1308: /* track too big */
1.1.1.4 root 1309: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
1.1 root 1310: fdctrl->fifo[3] = kt;
1311: fdctrl->fifo[4] = kh;
1312: fdctrl->fifo[5] = ks;
1313: return;
1314: case 4:
1315: /* No seek enabled */
1.1.1.4 root 1316: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
1.1 root 1317: fdctrl->fifo[3] = kt;
1318: fdctrl->fifo[4] = kh;
1319: fdctrl->fifo[5] = ks;
1320: return;
1321: case 1:
1322: fdctrl->data_state |= FD_STATE_SEEK;
1323: break;
1324: default:
1325: break;
1326: }
1327: memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
1328: if (cur_drv->bs == NULL ||
1329: bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1.1.1.3 root 1330: FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
1.1.1.4 root 1331: fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1.1 root 1332: } else {
1.1.1.3 root 1333: if (cur_drv->sect == cur_drv->last_sect) {
1334: fdctrl->data_state &= ~FD_STATE_FORMAT;
1335: /* Last sector done */
1336: if (FD_DID_SEEK(fdctrl->data_state))
1.1.1.4 root 1337: fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1.1.1.3 root 1338: else
1339: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1340: } else {
1341: /* More to do */
1342: fdctrl->data_pos = 0;
1343: fdctrl->data_len = 4;
1344: }
1.1 root 1345: }
1346: }
1347:
1.1.1.10 root 1348: static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
1.1 root 1349: {
1.1.1.4 root 1350: fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
1351: fdctrl->fifo[0] = fdctrl->lock << 4;
1352: fdctrl_set_fifo(fdctrl, 1, fdctrl->lock);
1353: }
1.1 root 1354:
1.1.1.10 root 1355: static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1356: {
1.1.1.10 root 1357: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1358:
1359: /* Drives position */
1360: fdctrl->fifo[0] = drv0(fdctrl)->track;
1361: fdctrl->fifo[1] = drv1(fdctrl)->track;
1362: #if MAX_FD == 4
1363: fdctrl->fifo[2] = drv2(fdctrl)->track;
1364: fdctrl->fifo[3] = drv3(fdctrl)->track;
1.1 root 1365: #else
1.1.1.4 root 1366: fdctrl->fifo[2] = 0;
1367: fdctrl->fifo[3] = 0;
1.1 root 1368: #endif
1.1.1.4 root 1369: /* timers */
1370: fdctrl->fifo[4] = fdctrl->timer0;
1371: fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
1372: fdctrl->fifo[6] = cur_drv->last_sect;
1373: fdctrl->fifo[7] = (fdctrl->lock << 7) |
1374: (cur_drv->perpendicular << 2);
1375: fdctrl->fifo[8] = fdctrl->config;
1376: fdctrl->fifo[9] = fdctrl->precomp_trk;
1377: fdctrl_set_fifo(fdctrl, 10, 0);
1378: }
1379:
1.1.1.10 root 1380: static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1381: {
1382: /* Controller's version */
1383: fdctrl->fifo[0] = fdctrl->version;
1384: fdctrl_set_fifo(fdctrl, 1, 1);
1385: }
1386:
1.1.1.10 root 1387: static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1388: {
1389: fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1390: fdctrl_set_fifo(fdctrl, 1, 0);
1391: }
1392:
1.1.1.10 root 1393: static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1394: {
1.1.1.10 root 1395: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1396:
1397: /* Drives position */
1398: drv0(fdctrl)->track = fdctrl->fifo[3];
1399: drv1(fdctrl)->track = fdctrl->fifo[4];
1400: #if MAX_FD == 4
1401: drv2(fdctrl)->track = fdctrl->fifo[5];
1402: drv3(fdctrl)->track = fdctrl->fifo[6];
1403: #endif
1404: /* timers */
1405: fdctrl->timer0 = fdctrl->fifo[7];
1406: fdctrl->timer1 = fdctrl->fifo[8];
1407: cur_drv->last_sect = fdctrl->fifo[9];
1408: fdctrl->lock = fdctrl->fifo[10] >> 7;
1409: cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1410: fdctrl->config = fdctrl->fifo[11];
1411: fdctrl->precomp_trk = fdctrl->fifo[12];
1412: fdctrl->pwrd = fdctrl->fifo[13];
1413: fdctrl_reset_fifo(fdctrl);
1414: }
1415:
1.1.1.10 root 1416: static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1417: {
1.1.1.10 root 1418: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1419:
1420: fdctrl->fifo[0] = 0;
1421: fdctrl->fifo[1] = 0;
1422: /* Drives position */
1423: fdctrl->fifo[2] = drv0(fdctrl)->track;
1424: fdctrl->fifo[3] = drv1(fdctrl)->track;
1425: #if MAX_FD == 4
1426: fdctrl->fifo[4] = drv2(fdctrl)->track;
1427: fdctrl->fifo[5] = drv3(fdctrl)->track;
1428: #else
1429: fdctrl->fifo[4] = 0;
1430: fdctrl->fifo[5] = 0;
1431: #endif
1432: /* timers */
1433: fdctrl->fifo[6] = fdctrl->timer0;
1434: fdctrl->fifo[7] = fdctrl->timer1;
1435: fdctrl->fifo[8] = cur_drv->last_sect;
1436: fdctrl->fifo[9] = (fdctrl->lock << 7) |
1437: (cur_drv->perpendicular << 2);
1438: fdctrl->fifo[10] = fdctrl->config;
1439: fdctrl->fifo[11] = fdctrl->precomp_trk;
1440: fdctrl->fifo[12] = fdctrl->pwrd;
1441: fdctrl->fifo[13] = 0;
1442: fdctrl->fifo[14] = 0;
1443: fdctrl_set_fifo(fdctrl, 15, 1);
1444: }
1445:
1.1.1.10 root 1446: static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1447: {
1.1.1.10 root 1448: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1449:
1450: /* XXX: should set main status register to busy */
1451: cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1452: qemu_mod_timer(fdctrl->result_timer,
1.1.1.12 root 1453: qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
1.1.1.4 root 1454: }
1455:
1.1.1.10 root 1456: static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1457: {
1.1.1.10 root 1458: FDrive *cur_drv;
1.1.1.4 root 1459:
1460: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1461: cur_drv = get_cur_drv(fdctrl);
1462: fdctrl->data_state |= FD_STATE_FORMAT;
1463: if (fdctrl->fifo[0] & 0x80)
1464: fdctrl->data_state |= FD_STATE_MULTI;
1465: else
1466: fdctrl->data_state &= ~FD_STATE_MULTI;
1467: fdctrl->data_state &= ~FD_STATE_SEEK;
1468: cur_drv->bps =
1469: fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1470: #if 0
1471: cur_drv->last_sect =
1472: cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1473: fdctrl->fifo[3] / 2;
1474: #else
1475: cur_drv->last_sect = fdctrl->fifo[3];
1476: #endif
1477: /* TODO: implement format using DMA expected by the Bochs BIOS
1478: * and Linux fdformat (read 3 bytes per sector via DMA and fill
1479: * the sector with the specified fill byte
1480: */
1481: fdctrl->data_state &= ~FD_STATE_FORMAT;
1482: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1483: }
1484:
1.1.1.10 root 1485: static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1486: {
1487: fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1488: fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1489: if (fdctrl->fifo[2] & 1)
1490: fdctrl->dor &= ~FD_DOR_DMAEN;
1491: else
1492: fdctrl->dor |= FD_DOR_DMAEN;
1493: /* No result back */
1494: fdctrl_reset_fifo(fdctrl);
1495: }
1496:
1.1.1.10 root 1497: static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1498: {
1.1.1.10 root 1499: FDrive *cur_drv;
1.1.1.4 root 1500:
1501: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1502: cur_drv = get_cur_drv(fdctrl);
1503: cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1504: /* 1 Byte status back */
1505: fdctrl->fifo[0] = (cur_drv->ro << 6) |
1506: (cur_drv->track == 0 ? 0x10 : 0x00) |
1507: (cur_drv->head << 2) |
1508: GET_CUR_DRV(fdctrl) |
1509: 0x28;
1510: fdctrl_set_fifo(fdctrl, 1, 0);
1511: }
1512:
1.1.1.10 root 1513: static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1514: {
1.1.1.10 root 1515: FDrive *cur_drv;
1.1.1.4 root 1516:
1517: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1518: cur_drv = get_cur_drv(fdctrl);
1519: fd_recalibrate(cur_drv);
1520: fdctrl_reset_fifo(fdctrl);
1521: /* Raise Interrupt */
1522: fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1523: }
1524:
1.1.1.10 root 1525: static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1526: {
1.1.1.10 root 1527: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1528:
1529: if(fdctrl->reset_sensei > 0) {
1530: fdctrl->fifo[0] =
1531: FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
1532: fdctrl->reset_sensei--;
1533: } else {
1534: /* XXX: status0 handling is broken for read/write
1535: commands, so we do this hack. It should be suppressed
1536: ASAP */
1537: fdctrl->fifo[0] =
1538: FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1539: }
1540:
1541: fdctrl->fifo[1] = cur_drv->track;
1542: fdctrl_set_fifo(fdctrl, 2, 0);
1543: fdctrl_reset_irq(fdctrl);
1544: fdctrl->status0 = FD_SR0_RDYCHG;
1545: }
1546:
1.1.1.10 root 1547: static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1548: {
1.1.1.10 root 1549: FDrive *cur_drv;
1.1.1.4 root 1550:
1551: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1552: cur_drv = get_cur_drv(fdctrl);
1553: fdctrl_reset_fifo(fdctrl);
1554: if (fdctrl->fifo[2] > cur_drv->max_track) {
1555: fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
1556: } else {
1557: cur_drv->track = fdctrl->fifo[2];
1558: /* Raise Interrupt */
1559: fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1560: }
1561: }
1562:
1.1.1.10 root 1563: static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1564: {
1.1.1.10 root 1565: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1566:
1567: if (fdctrl->fifo[1] & 0x80)
1568: cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1569: /* No result back */
1570: fdctrl_reset_fifo(fdctrl);
1571: }
1572:
1.1.1.10 root 1573: static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1574: {
1575: fdctrl->config = fdctrl->fifo[2];
1576: fdctrl->precomp_trk = fdctrl->fifo[3];
1577: /* No result back */
1578: fdctrl_reset_fifo(fdctrl);
1579: }
1580:
1.1.1.10 root 1581: static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1582: {
1583: fdctrl->pwrd = fdctrl->fifo[1];
1584: fdctrl->fifo[0] = fdctrl->fifo[1];
1585: fdctrl_set_fifo(fdctrl, 1, 1);
1586: }
1587:
1.1.1.10 root 1588: static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1589: {
1590: /* No result back */
1591: fdctrl_reset_fifo(fdctrl);
1592: }
1593:
1.1.1.10 root 1594: static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1595: {
1.1.1.10 root 1596: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.4 root 1597:
1598: if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1599: /* Command parameters done */
1600: if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1601: fdctrl->fifo[0] = fdctrl->fifo[1];
1602: fdctrl->fifo[2] = 0;
1603: fdctrl->fifo[3] = 0;
1604: fdctrl_set_fifo(fdctrl, 4, 1);
1605: } else {
1606: fdctrl_reset_fifo(fdctrl);
1.1 root 1607: }
1.1.1.4 root 1608: } else if (fdctrl->data_len > 7) {
1609: /* ERROR */
1610: fdctrl->fifo[0] = 0x80 |
1611: (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1612: fdctrl_set_fifo(fdctrl, 1, 1);
1613: }
1614: }
1615:
1.1.1.10 root 1616: static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1617: {
1.1.1.10 root 1618: FDrive *cur_drv;
1.1.1.4 root 1619:
1620: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1621: cur_drv = get_cur_drv(fdctrl);
1622: if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1623: cur_drv->track = cur_drv->max_track - 1;
1624: } else {
1625: cur_drv->track += fdctrl->fifo[2];
1.1 root 1626: }
1.1.1.4 root 1627: fdctrl_reset_fifo(fdctrl);
1628: /* Raise Interrupt */
1629: fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1630: }
1631:
1.1.1.10 root 1632: static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
1.1.1.4 root 1633: {
1.1.1.10 root 1634: FDrive *cur_drv;
1.1.1.4 root 1635:
1636: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1637: cur_drv = get_cur_drv(fdctrl);
1638: if (fdctrl->fifo[2] > cur_drv->track) {
1639: cur_drv->track = 0;
1640: } else {
1641: cur_drv->track -= fdctrl->fifo[2];
1642: }
1643: fdctrl_reset_fifo(fdctrl);
1644: /* Raise Interrupt */
1645: fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1646: }
1647:
1648: static const struct {
1649: uint8_t value;
1650: uint8_t mask;
1651: const char* name;
1652: int parameters;
1.1.1.10 root 1653: void (*handler)(FDCtrl *fdctrl, int direction);
1.1.1.4 root 1654: int direction;
1655: } handlers[] = {
1656: { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
1657: { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
1658: { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
1659: { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
1660: { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
1661: { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
1662: { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
1663: { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
1664: { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
1665: { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
1666: { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
1667: { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
1668: { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
1669: { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
1670: { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
1671: { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
1672: { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
1673: { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
1674: { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
1675: { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
1676: { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
1677: { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
1678: { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
1679: { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
1680: { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
1681: { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
1682: { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
1683: { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
1684: { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
1685: { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
1686: { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
1687: { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
1688: };
1689: /* Associate command to an index in the 'handlers' array */
1690: static uint8_t command_to_handler[256];
1691:
1.1.1.10 root 1692: static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
1.1.1.4 root 1693: {
1.1.1.10 root 1694: FDrive *cur_drv;
1.1.1.4 root 1695: int pos;
1696:
1697: /* Reset mode */
1698: if (!(fdctrl->dor & FD_DOR_nRESET)) {
1699: FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1700: return;
1701: }
1702: if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
1703: FLOPPY_ERROR("controller not ready for writing\n");
1704: return;
1705: }
1706: fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1707: /* Is it write command time ? */
1708: if (fdctrl->msr & FD_MSR_NONDMA) {
1709: /* FIFO data write */
1710: pos = fdctrl->data_pos++;
1711: pos %= FD_SECTOR_LEN;
1712: fdctrl->fifo[pos] = value;
1713: if (pos == FD_SECTOR_LEN - 1 ||
1714: fdctrl->data_pos == fdctrl->data_len) {
1715: cur_drv = get_cur_drv(fdctrl);
1716: if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1717: FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
1718: return;
1719: }
1720: if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
1721: FLOPPY_DPRINTF("error seeking to next sector %d\n",
1722: fd_sector(cur_drv));
1723: return;
1724: }
1725: }
1726: /* Switch from transfer mode to status mode
1727: * then from status mode to command mode
1728: */
1729: if (fdctrl->data_pos == fdctrl->data_len)
1730: fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1731: return;
1732: }
1733: if (fdctrl->data_pos == 0) {
1734: /* Command */
1735: pos = command_to_handler[value & 0xff];
1736: FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
1737: fdctrl->data_len = handlers[pos].parameters + 1;
1738: }
1739:
1.1 root 1740: FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1.1.1.4 root 1741: fdctrl->fifo[fdctrl->data_pos++] = value;
1742: if (fdctrl->data_pos == fdctrl->data_len) {
1.1 root 1743: /* We now have all parameters
1744: * and will be able to treat the command
1745: */
1.1.1.3 root 1746: if (fdctrl->data_state & FD_STATE_FORMAT) {
1747: fdctrl_format_sector(fdctrl);
1.1 root 1748: return;
1749: }
1.1.1.4 root 1750:
1751: pos = command_to_handler[fdctrl->fifo[0] & 0xff];
1752: FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
1753: (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
1.1 root 1754: }
1755: }
1756:
1757: static void fdctrl_result_timer(void *opaque)
1758: {
1.1.1.10 root 1759: FDCtrl *fdctrl = opaque;
1760: FDrive *cur_drv = get_cur_drv(fdctrl);
1.1.1.3 root 1761:
1762: /* Pretend we are spinning.
1763: * This is needed for Coherent, which uses READ ID to check for
1764: * sector interleaving.
1765: */
1766: if (cur_drv->last_sect != 0) {
1767: cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
1768: }
1.1 root 1769: fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1770: }
1.1.1.4 root 1771:
1.1.1.13! root 1772: static void fdctrl_change_cb(void *opaque, bool load)
! 1773: {
! 1774: FDrive *drive = opaque;
! 1775:
! 1776: drive->media_changed = 1;
! 1777: }
! 1778:
! 1779: static const BlockDevOps fdctrl_block_ops = {
! 1780: .change_media_cb = fdctrl_change_cb,
! 1781: };
! 1782:
1.1.1.4 root 1783: /* Init functions */
1.1.1.10 root 1784: static int fdctrl_connect_drives(FDCtrl *fdctrl)
1.1.1.6 root 1785: {
1786: unsigned int i;
1.1.1.10 root 1787: FDrive *drive;
1.1.1.6 root 1788:
1789: for (i = 0; i < MAX_FD; i++) {
1.1.1.10 root 1790: drive = &fdctrl->drives[i];
1791:
1792: if (drive->bs) {
1793: if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
1794: error_report("fdc doesn't support drive option werror");
1795: return -1;
1796: }
1797: if (bdrv_get_on_error(drive->bs, 1) != BLOCK_ERR_REPORT) {
1798: error_report("fdc doesn't support drive option rerror");
1799: return -1;
1800: }
1801: }
1802:
1803: fd_init(drive);
1804: fd_revalidate(drive);
1805: if (drive->bs) {
1.1.1.13! root 1806: drive->media_changed = 1;
! 1807: bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
1.1.1.10 root 1808: }
1.1.1.6 root 1809: }
1.1.1.10 root 1810: return 0;
1.1.1.6 root 1811: }
1812:
1.1.1.12 root 1813: void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
1814: target_phys_addr_t mmio_base, DriveInfo **fds)
1.1.1.6 root 1815: {
1.1.1.10 root 1816: FDCtrl *fdctrl;
1.1.1.6 root 1817: DeviceState *dev;
1.1.1.10 root 1818: FDCtrlSysBus *sys;
1.1.1.6 root 1819:
1820: dev = qdev_create(NULL, "sysbus-fdc");
1.1.1.10 root 1821: sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
1.1.1.6 root 1822: fdctrl = &sys->state;
1823: fdctrl->dma_chann = dma_chann; /* FIXME */
1.1.1.8 root 1824: if (fds[0]) {
1.1.1.10 root 1825: qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
1.1.1.8 root 1826: }
1827: if (fds[1]) {
1.1.1.10 root 1828: qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
1.1.1.8 root 1829: }
1.1.1.6 root 1830: qdev_init_nofail(dev);
1831: sysbus_connect_irq(&sys->busdev, 0, irq);
1832: sysbus_mmio_map(&sys->busdev, 0, mmio_base);
1833: }
1834:
1.1.1.12 root 1835: void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
1836: DriveInfo **fds, qemu_irq *fdc_tc)
1.1.1.6 root 1837: {
1838: DeviceState *dev;
1.1.1.10 root 1839: FDCtrlSysBus *sys;
1.1.1.6 root 1840:
1841: dev = qdev_create(NULL, "SUNW,fdtwo");
1.1.1.8 root 1842: if (fds[0]) {
1.1.1.10 root 1843: qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
1.1.1.8 root 1844: }
1.1.1.6 root 1845: qdev_init_nofail(dev);
1.1.1.10 root 1846: sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
1.1.1.6 root 1847: sysbus_connect_irq(&sys->busdev, 0, irq);
1848: sysbus_mmio_map(&sys->busdev, 0, io_base);
1849: *fdc_tc = qdev_get_gpio_in(dev, 0);
1850: }
1851:
1.1.1.10 root 1852: static int fdctrl_init_common(FDCtrl *fdctrl)
1.1.1.4 root 1853: {
1854: int i, j;
1.1.1.6 root 1855: static int command_tables_inited = 0;
1.1.1.4 root 1856:
1857: /* Fill 'command_to_handler' lookup table */
1.1.1.6 root 1858: if (!command_tables_inited) {
1859: command_tables_inited = 1;
1860: for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
1861: for (j = 0; j < sizeof(command_to_handler); j++) {
1862: if ((j & handlers[i].mask) == handlers[i].value) {
1863: command_to_handler[j] = i;
1864: }
1865: }
1.1.1.4 root 1866: }
1867: }
1868:
1869: FLOPPY_DPRINTF("init controller\n");
1870: fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
1.1.1.6 root 1871: fdctrl->fifo_size = 512;
1.1.1.12 root 1872: fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
1.1.1.4 root 1873: fdctrl_result_timer, fdctrl);
1874:
1875: fdctrl->version = 0x90; /* Intel 82078 controller */
1876: fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
1.1.1.6 root 1877: fdctrl->num_floppies = MAX_FD;
1878:
1879: if (fdctrl->dma_chann != -1)
1880: DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
1.1.1.10 root 1881: return fdctrl_connect_drives(fdctrl);
1.1.1.4 root 1882: }
1883:
1.1.1.13! root 1884: static const MemoryRegionPortio fdc_portio_list[] = {
! 1885: { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
! 1886: { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
! 1887: PORTIO_END_OF_LIST(),
! 1888: };
! 1889:
1.1.1.6 root 1890: static int isabus_fdc_init1(ISADevice *dev)
1.1.1.4 root 1891: {
1.1.1.10 root 1892: FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
1893: FDCtrl *fdctrl = &isa->state;
1.1.1.6 root 1894: int iobase = 0x3f0;
1895: int isairq = 6;
1896: int dma_chann = 2;
1897: int ret;
1.1.1.4 root 1898:
1.1.1.13! root 1899: isa_register_portio_list(dev, iobase, fdc_portio_list, fdctrl, "fdc");
1.1.1.11 root 1900:
1.1.1.6 root 1901: isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
1902: fdctrl->dma_chann = dma_chann;
1.1.1.4 root 1903:
1.1.1.10 root 1904: qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
1905: ret = fdctrl_init_common(fdctrl);
1.1.1.5 root 1906:
1.1.1.11 root 1907: add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0");
1908: add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy@1");
1909:
1.1.1.6 root 1910: return ret;
1.1.1.4 root 1911: }
1912:
1.1.1.6 root 1913: static int sysbus_fdc_init1(SysBusDevice *dev)
1.1.1.4 root 1914: {
1.1.1.10 root 1915: FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
1916: FDCtrl *fdctrl = &sys->state;
1.1.1.6 root 1917: int io;
1918: int ret;
1.1.1.4 root 1919:
1.1.1.11 root 1920: io = cpu_register_io_memory(fdctrl_mem_read, fdctrl_mem_write, fdctrl,
1921: DEVICE_NATIVE_ENDIAN);
1.1.1.6 root 1922: sysbus_init_mmio(dev, 0x08, io);
1923: sysbus_init_irq(dev, &fdctrl->irq);
1924: qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
1925: fdctrl->dma_chann = -1;
1.1.1.5 root 1926:
1.1.1.10 root 1927: qdev_set_legacy_instance_id(&dev->qdev, io, 2);
1928: ret = fdctrl_init_common(fdctrl);
1.1.1.4 root 1929:
1.1.1.6 root 1930: return ret;
1.1.1.4 root 1931: }
1.1.1.5 root 1932:
1.1.1.6 root 1933: static int sun4m_fdc_init1(SysBusDevice *dev)
1.1.1.5 root 1934: {
1.1.1.10 root 1935: FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
1.1.1.5 root 1936: int io;
1937:
1.1.1.6 root 1938: io = cpu_register_io_memory(fdctrl_mem_read_strict,
1.1.1.11 root 1939: fdctrl_mem_write_strict, fdctrl,
1940: DEVICE_NATIVE_ENDIAN);
1.1.1.5 root 1941: sysbus_init_mmio(dev, 0x08, io);
1.1.1.6 root 1942: sysbus_init_irq(dev, &fdctrl->irq);
1943: qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
1944:
1945: fdctrl->sun4m = 1;
1.1.1.10 root 1946: qdev_set_legacy_instance_id(&dev->qdev, io, 2);
1947: return fdctrl_init_common(fdctrl);
1.1.1.5 root 1948: }
1949:
1.1.1.13! root 1950: void fdc_get_bs(BlockDriverState *bs[], ISADevice *dev)
! 1951: {
! 1952: FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
! 1953: FDCtrl *fdctrl = &isa->state;
! 1954: int i;
! 1955:
! 1956: for (i = 0; i < MAX_FD; i++) {
! 1957: bs[i] = fdctrl->drives[i].bs;
! 1958: }
! 1959: }
! 1960:
! 1961:
1.1.1.10 root 1962: static const VMStateDescription vmstate_isa_fdc ={
1963: .name = "fdc",
1964: .version_id = 2,
1965: .minimum_version_id = 2,
1966: .fields = (VMStateField []) {
1967: VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
1968: VMSTATE_END_OF_LIST()
1969: }
1970: };
1971:
1.1.1.6 root 1972: static ISADeviceInfo isa_fdc_info = {
1973: .init = isabus_fdc_init1,
1974: .qdev.name = "isa-fdc",
1.1.1.11 root 1975: .qdev.fw_name = "fdc",
1.1.1.10 root 1976: .qdev.size = sizeof(FDCtrlISABus),
1.1.1.6 root 1977: .qdev.no_user = 1,
1.1.1.10 root 1978: .qdev.vmsd = &vmstate_isa_fdc,
1.1.1.6 root 1979: .qdev.reset = fdctrl_external_reset_isa,
1980: .qdev.props = (Property[]) {
1.1.1.10 root 1981: DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
1982: DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
1.1.1.11 root 1983: DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
1984: DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
1.1.1.6 root 1985: DEFINE_PROP_END_OF_LIST(),
1986: },
1987: };
1.1.1.5 root 1988:
1.1.1.10 root 1989: static const VMStateDescription vmstate_sysbus_fdc ={
1990: .name = "fdc",
1991: .version_id = 2,
1992: .minimum_version_id = 2,
1993: .fields = (VMStateField []) {
1994: VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
1995: VMSTATE_END_OF_LIST()
1996: }
1997: };
1998:
1.1.1.6 root 1999: static SysBusDeviceInfo sysbus_fdc_info = {
2000: .init = sysbus_fdc_init1,
2001: .qdev.name = "sysbus-fdc",
1.1.1.10 root 2002: .qdev.size = sizeof(FDCtrlSysBus),
2003: .qdev.vmsd = &vmstate_sysbus_fdc,
1.1.1.6 root 2004: .qdev.reset = fdctrl_external_reset_sysbus,
1.1.1.5 root 2005: .qdev.props = (Property[]) {
1.1.1.10 root 2006: DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
2007: DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
1.1.1.6 root 2008: DEFINE_PROP_END_OF_LIST(),
2009: },
2010: };
2011:
2012: static SysBusDeviceInfo sun4m_fdc_info = {
2013: .init = sun4m_fdc_init1,
2014: .qdev.name = "SUNW,fdtwo",
1.1.1.10 root 2015: .qdev.size = sizeof(FDCtrlSysBus),
2016: .qdev.vmsd = &vmstate_sysbus_fdc,
1.1.1.6 root 2017: .qdev.reset = fdctrl_external_reset_sysbus,
2018: .qdev.props = (Property[]) {
1.1.1.10 root 2019: DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
1.1.1.6 root 2020: DEFINE_PROP_END_OF_LIST(),
2021: },
1.1.1.5 root 2022: };
2023:
2024: static void fdc_register_devices(void)
2025: {
1.1.1.6 root 2026: isa_qdev_register(&isa_fdc_info);
2027: sysbus_register_withprop(&sysbus_fdc_info);
2028: sysbus_register_withprop(&sun4m_fdc_info);
1.1.1.5 root 2029: }
2030:
2031: device_init(fdc_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.