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