Revision 844f65d6 hw/fdc.c
b/hw/fdc.c | ||
---|---|---|
62 | 62 |
#define FD_SECTOR_SC 2 /* Sector size code */ |
63 | 63 |
#define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */ |
64 | 64 |
|
65 |
typedef struct FDCtrl FDCtrl; |
|
66 |
|
|
65 | 67 |
/* Floppy disk drive emulation */ |
66 | 68 |
typedef enum FDiskFlags { |
67 | 69 |
FDISK_DBL_SIDES = 0x01, |
68 | 70 |
} FDiskFlags; |
69 | 71 |
|
70 | 72 |
typedef struct FDrive { |
73 |
FDCtrl *fdctrl; |
|
71 | 74 |
BlockDriverState *bs; |
72 | 75 |
/* Drive status */ |
73 | 76 |
FDriveType drive; |
... | ... | |
83 | 86 |
uint16_t bps; /* Bytes per sector */ |
84 | 87 |
uint8_t ro; /* Is read-only */ |
85 | 88 |
uint8_t media_changed; /* Is media changed */ |
89 |
uint8_t media_rate; /* Data rate of medium */ |
|
86 | 90 |
} FDrive; |
87 | 91 |
|
88 | 92 |
static void fd_init(FDrive *drv) |
... | ... | |
195 | 199 |
drv->last_sect = last_sect; |
196 | 200 |
drv->ro = ro; |
197 | 201 |
drv->drive = drive; |
202 |
drv->media_rate = rate; |
|
198 | 203 |
} else { |
199 | 204 |
FLOPPY_DPRINTF("No disk in drive\n"); |
200 | 205 |
drv->last_sect = 0; |
... | ... | |
206 | 211 |
/********************************************************/ |
207 | 212 |
/* Intel 82078 floppy disk controller emulation */ |
208 | 213 |
|
209 |
typedef struct FDCtrl FDCtrl; |
|
210 |
|
|
211 | 214 |
static void fdctrl_reset(FDCtrl *fdctrl, int do_irq); |
212 | 215 |
static void fdctrl_reset_fifo(FDCtrl *fdctrl); |
213 | 216 |
static int fdctrl_transfer_handler (void *opaque, int nchan, |
... | ... | |
303 | 306 |
}; |
304 | 307 |
|
305 | 308 |
enum { |
309 |
FD_SR1_MA = 0x01, /* Missing address mark */ |
|
306 | 310 |
FD_SR1_NW = 0x02, /* Not writable */ |
307 | 311 |
FD_SR1_EC = 0x80, /* End of cylinder */ |
308 | 312 |
}; |
... | ... | |
549 | 553 |
} |
550 | 554 |
}; |
551 | 555 |
|
556 |
static bool fdrive_media_rate_needed(void *opaque) |
|
557 |
{ |
|
558 |
FDrive *drive = opaque; |
|
559 |
|
|
560 |
return drive->fdctrl->check_media_rate; |
|
561 |
} |
|
562 |
|
|
563 |
static const VMStateDescription vmstate_fdrive_media_rate = { |
|
564 |
.name = "fdrive/media_rate", |
|
565 |
.version_id = 1, |
|
566 |
.minimum_version_id = 1, |
|
567 |
.minimum_version_id_old = 1, |
|
568 |
.fields = (VMStateField[]) { |
|
569 |
VMSTATE_UINT8(media_rate, FDrive), |
|
570 |
VMSTATE_END_OF_LIST() |
|
571 |
} |
|
572 |
}; |
|
573 |
|
|
552 | 574 |
static const VMStateDescription vmstate_fdrive = { |
553 | 575 |
.name = "fdrive", |
554 | 576 |
.version_id = 1, |
... | ... | |
565 | 587 |
.vmsd = &vmstate_fdrive_media_changed, |
566 | 588 |
.needed = &fdrive_media_changed_needed, |
567 | 589 |
} , { |
590 |
.vmsd = &vmstate_fdrive_media_rate, |
|
591 |
.needed = &fdrive_media_rate_needed, |
|
592 |
} , { |
|
568 | 593 |
/* empty */ |
569 | 594 |
} |
570 | 595 |
} |
... | ... | |
1078 | 1103 |
break; |
1079 | 1104 |
} |
1080 | 1105 |
|
1106 |
/* Check the data rate. If the programmed data rate does not match |
|
1107 |
* the currently inserted medium, the operation has to fail. */ |
|
1108 |
if (fdctrl->check_media_rate && |
|
1109 |
(fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) { |
|
1110 |
FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n", |
|
1111 |
fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate); |
|
1112 |
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); |
|
1113 |
fdctrl->fifo[3] = kt; |
|
1114 |
fdctrl->fifo[4] = kh; |
|
1115 |
fdctrl->fifo[5] = ks; |
|
1116 |
return; |
|
1117 |
} |
|
1118 |
|
|
1081 | 1119 |
/* Set the FIFO state */ |
1082 | 1120 |
fdctrl->data_dir = direction; |
1083 | 1121 |
fdctrl->data_pos = 0; |
... | ... | |
1800 | 1838 |
if (cur_drv->last_sect != 0) { |
1801 | 1839 |
cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1; |
1802 | 1840 |
} |
1803 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); |
|
1841 |
/* READ_ID can't automatically succeed! */ |
|
1842 |
if (fdctrl->check_media_rate && |
|
1843 |
(fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) { |
|
1844 |
FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n", |
|
1845 |
fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate); |
|
1846 |
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); |
|
1847 |
} else { |
|
1848 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); |
|
1849 |
} |
|
1804 | 1850 |
} |
1805 | 1851 |
|
1806 | 1852 |
static void fdctrl_change_cb(void *opaque, bool load) |
... | ... | |
1822 | 1868 |
|
1823 | 1869 |
for (i = 0; i < MAX_FD; i++) { |
1824 | 1870 |
drive = &fdctrl->drives[i]; |
1871 |
drive->fdctrl = fdctrl; |
|
1825 | 1872 |
|
1826 | 1873 |
if (drive->bs) { |
1827 | 1874 |
if (bdrv_get_on_error(drive->bs, 0) != BLOCK_ERR_STOP_ENOSPC) { |
Also available in: Unified diff