Revision 4f431960 hw/fdc.c
b/hw/fdc.c | ||
---|---|---|
106 | 106 |
} |
107 | 107 |
|
108 | 108 |
static int _fd_sector (uint8_t head, uint8_t track, |
109 |
uint8_t sect, uint8_t last_sect)
|
|
109 |
uint8_t sect, uint8_t last_sect) |
|
110 | 110 |
{ |
111 | 111 |
return (((track * 2) + head) * last_sect) + sect - 1; |
112 | 112 |
} |
... | ... | |
124 | 124 |
int ret; |
125 | 125 |
|
126 | 126 |
if (track > drv->max_track || |
127 |
(head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
|
|
127 |
(head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
|
|
128 | 128 |
FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", |
129 | 129 |
head, track, sect, 1, |
130 | 130 |
(drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, |
... | ... | |
149 | 149 |
} |
150 | 150 |
#endif |
151 | 151 |
drv->head = head; |
152 |
if (drv->track != track)
|
|
153 |
ret = 1;
|
|
152 |
if (drv->track != track)
|
|
153 |
ret = 1;
|
|
154 | 154 |
drv->track = track; |
155 | 155 |
drv->sect = sect; |
156 | 156 |
} |
... | ... | |
236 | 236 |
|
237 | 237 |
FLOPPY_DPRINTF("revalidate\n"); |
238 | 238 |
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { |
239 |
ro = bdrv_is_read_only(drv->bs);
|
|
240 |
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
|
|
241 |
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
|
242 |
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
|
|
239 |
ro = bdrv_is_read_only(drv->bs);
|
|
240 |
bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
|
|
241 |
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
|
242 |
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
|
|
243 | 243 |
nb_heads - 1, max_track, last_sect); |
244 |
} else {
|
|
245 |
bdrv_get_geometry(drv->bs, &nb_sectors);
|
|
246 |
match = -1;
|
|
247 |
first_match = -1;
|
|
248 |
for (i = 0;; i++) {
|
|
249 |
parse = &fd_formats[i];
|
|
250 |
if (parse->drive == FDRIVE_DRV_NONE)
|
|
251 |
break;
|
|
252 |
if (drv->drive == parse->drive ||
|
|
253 |
drv->drive == FDRIVE_DRV_NONE) {
|
|
254 |
size = (parse->max_head + 1) * parse->max_track *
|
|
255 |
parse->last_sect;
|
|
256 |
if (nb_sectors == size) {
|
|
257 |
match = i;
|
|
258 |
break;
|
|
259 |
}
|
|
260 |
if (first_match == -1)
|
|
261 |
first_match = i;
|
|
262 |
}
|
|
263 |
}
|
|
264 |
if (match == -1) {
|
|
265 |
if (first_match == -1)
|
|
266 |
match = 1;
|
|
267 |
else
|
|
268 |
match = first_match;
|
|
269 |
parse = &fd_formats[match];
|
|
270 |
}
|
|
271 |
nb_heads = parse->max_head + 1;
|
|
272 |
max_track = parse->max_track;
|
|
273 |
last_sect = parse->last_sect;
|
|
274 |
drv->drive = parse->drive;
|
|
275 |
FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
|
|
244 |
} else {
|
|
245 |
bdrv_get_geometry(drv->bs, &nb_sectors);
|
|
246 |
match = -1;
|
|
247 |
first_match = -1;
|
|
248 |
for (i = 0;; i++) {
|
|
249 |
parse = &fd_formats[i];
|
|
250 |
if (parse->drive == FDRIVE_DRV_NONE)
|
|
251 |
break;
|
|
252 |
if (drv->drive == parse->drive ||
|
|
253 |
drv->drive == FDRIVE_DRV_NONE) {
|
|
254 |
size = (parse->max_head + 1) * parse->max_track *
|
|
255 |
parse->last_sect;
|
|
256 |
if (nb_sectors == size) {
|
|
257 |
match = i;
|
|
258 |
break;
|
|
259 |
}
|
|
260 |
if (first_match == -1)
|
|
261 |
first_match = i;
|
|
262 |
}
|
|
263 |
}
|
|
264 |
if (match == -1) {
|
|
265 |
if (first_match == -1)
|
|
266 |
match = 1;
|
|
267 |
else
|
|
268 |
match = first_match;
|
|
269 |
parse = &fd_formats[match];
|
|
270 |
}
|
|
271 |
nb_heads = parse->max_head + 1;
|
|
272 |
max_track = parse->max_track;
|
|
273 |
last_sect = parse->last_sect;
|
|
274 |
drv->drive = parse->drive;
|
|
275 |
FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
|
|
276 | 276 |
nb_heads, max_track, last_sect, ro ? "ro" : "rw"); |
277 |
}
|
|
278 |
if (nb_heads == 1) {
|
|
279 |
drv->flags &= ~FDISK_DBL_SIDES;
|
|
280 |
} else {
|
|
281 |
drv->flags |= FDISK_DBL_SIDES;
|
|
282 |
}
|
|
283 |
drv->max_track = max_track;
|
|
284 |
drv->last_sect = last_sect;
|
|
285 |
drv->ro = ro;
|
|
277 |
}
|
|
278 |
if (nb_heads == 1) {
|
|
279 |
drv->flags &= ~FDISK_DBL_SIDES;
|
|
280 |
} else {
|
|
281 |
drv->flags |= FDISK_DBL_SIDES;
|
|
282 |
}
|
|
283 |
drv->max_track = max_track;
|
|
284 |
drv->last_sect = last_sect;
|
|
285 |
drv->ro = ro;
|
|
286 | 286 |
} else { |
287 |
FLOPPY_DPRINTF("No disk in drive\n");
|
|
287 |
FLOPPY_DPRINTF("No disk in drive\n");
|
|
288 | 288 |
drv->last_sect = 0; |
289 |
drv->max_track = 0;
|
|
290 |
drv->flags &= ~FDISK_DBL_SIDES;
|
|
289 |
drv->max_track = 0;
|
|
290 |
drv->flags &= ~FDISK_DBL_SIDES;
|
|
291 | 291 |
} |
292 | 292 |
} |
293 | 293 |
|
... | ... | |
414 | 414 |
} else { |
415 | 415 |
retval = (uint32_t)(-1); |
416 | 416 |
} |
417 |
break;
|
|
417 |
break;
|
|
418 | 418 |
case 0x01: |
419 |
retval = fdctrl_read_statusB(fdctrl);
|
|
420 |
break;
|
|
419 |
retval = fdctrl_read_statusB(fdctrl);
|
|
420 |
break;
|
|
421 | 421 |
case 0x02: |
422 |
retval = fdctrl_read_dor(fdctrl);
|
|
423 |
break;
|
|
422 |
retval = fdctrl_read_dor(fdctrl);
|
|
423 |
break;
|
|
424 | 424 |
case 0x03: |
425 | 425 |
retval = fdctrl_read_tape(fdctrl); |
426 |
break;
|
|
426 |
break;
|
|
427 | 427 |
case 0x04: |
428 | 428 |
retval = fdctrl_read_main_status(fdctrl); |
429 |
break;
|
|
429 |
break;
|
|
430 | 430 |
case 0x05: |
431 | 431 |
retval = fdctrl_read_data(fdctrl); |
432 |
break;
|
|
432 |
break;
|
|
433 | 433 |
case 0x07: |
434 | 434 |
retval = fdctrl_read_dir(fdctrl); |
435 |
break;
|
|
435 |
break;
|
|
436 | 436 |
default: |
437 |
retval = (uint32_t)(-1);
|
|
438 |
break;
|
|
437 |
retval = (uint32_t)(-1);
|
|
438 |
break;
|
|
439 | 439 |
} |
440 | 440 |
FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval); |
441 | 441 |
|
... | ... | |
450 | 450 |
|
451 | 451 |
switch (reg & 0x07) { |
452 | 452 |
case 0x02: |
453 |
fdctrl_write_dor(fdctrl, value);
|
|
454 |
break;
|
|
453 |
fdctrl_write_dor(fdctrl, value);
|
|
454 |
break;
|
|
455 | 455 |
case 0x03: |
456 | 456 |
fdctrl_write_tape(fdctrl, value); |
457 |
break;
|
|
457 |
break;
|
|
458 | 458 |
case 0x04: |
459 | 459 |
fdctrl_write_rate(fdctrl, value); |
460 |
break;
|
|
460 |
break;
|
|
461 | 461 |
case 0x05: |
462 | 462 |
fdctrl_write_data(fdctrl, value); |
463 |
break;
|
|
463 |
break;
|
|
464 | 464 |
default: |
465 |
break;
|
|
465 |
break;
|
|
466 | 466 |
} |
467 | 467 |
} |
468 | 468 |
|
... | ... | |
615 | 615 |
fdctrl_reset(fdctrl, 0); |
616 | 616 |
fdctrl->state = FD_CTRL_ACTIVE; |
617 | 617 |
if (mem_mapped) { |
618 |
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); |
|
618 |
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, |
|
619 |
fdctrl); |
|
619 | 620 |
cpu_register_physical_memory(io_base, 0x08, io_mem); |
620 | 621 |
} else { |
621 | 622 |
register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read, |
... | ... | |
665 | 666 |
{ |
666 | 667 |
// Sparc mutation |
667 | 668 |
if (fdctrl->sun4m && !fdctrl->dma_en) { |
668 |
fdctrl->state &= ~FD_CTRL_BUSY;
|
|
669 |
fdctrl->int_status = status;
|
|
670 |
return;
|
|
669 |
fdctrl->state &= ~FD_CTRL_BUSY;
|
|
670 |
fdctrl->int_status = status;
|
|
671 |
return;
|
|
671 | 672 |
} |
672 | 673 |
if (~(fdctrl->state & FD_CTRL_INTR)) { |
673 | 674 |
qemu_set_irq(fdctrl->irq, 1); |
... | ... | |
727 | 728 |
|
728 | 729 |
/* Drive motors state indicators */ |
729 | 730 |
if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) |
730 |
retval |= 1 << 5;
|
|
731 |
retval |= 1 << 5;
|
|
731 | 732 |
if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) |
732 |
retval |= 1 << 4;
|
|
733 |
retval |= 1 << 4;
|
|
733 | 734 |
/* DMA enable */ |
734 | 735 |
retval |= fdctrl->dma_en << 3; |
735 | 736 |
/* Reset indicator */ |
... | ... | |
836 | 837 |
{ |
837 | 838 |
/* Reset mode */ |
838 | 839 |
if (fdctrl->state & FD_CTRL_RESET) { |
839 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
|
|
840 |
return;
|
|
841 |
}
|
|
840 |
FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); |
|
841 |
return; |
|
842 |
} |
|
842 | 843 |
FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); |
843 | 844 |
/* Reset: autoclear */ |
844 | 845 |
if (value & 0x80) { |
... | ... | |
856 | 857 |
static int fdctrl_media_changed(fdrive_t *drv) |
857 | 858 |
{ |
858 | 859 |
int ret; |
860 |
|
|
859 | 861 |
if (!drv->bs) |
860 | 862 |
return 0; |
861 | 863 |
ret = bdrv_media_changed(drv->bs); |
... | ... | |
871 | 873 |
uint32_t retval = 0; |
872 | 874 |
|
873 | 875 |
if (fdctrl_media_changed(drv0(fdctrl)) || |
874 |
fdctrl_media_changed(drv1(fdctrl)))
|
|
876 |
fdctrl_media_changed(drv1(fdctrl)))
|
|
875 | 877 |
retval |= 0x80; |
876 | 878 |
if (retval != 0) |
877 | 879 |
FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); |
... | ... | |
918 | 920 |
|
919 | 921 |
/* Callback for transfer end (stop or abort) */ |
920 | 922 |
static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, |
921 |
uint8_t status1, uint8_t status2)
|
|
923 |
uint8_t status1, uint8_t status2)
|
|
922 | 924 |
{ |
923 | 925 |
fdrive_t *cur_drv; |
924 | 926 |
|
... | ... | |
1000 | 1002 |
if (fdctrl->fifo[5] == 00) { |
1001 | 1003 |
fdctrl->data_len = fdctrl->fifo[8]; |
1002 | 1004 |
} else { |
1003 |
int tmp;
|
|
1005 |
int tmp;
|
|
1004 | 1006 |
fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); |
1005 | 1007 |
tmp = (cur_drv->last_sect - ks + 1); |
1006 | 1008 |
if (fdctrl->fifo[0] & 0x80) |
1007 | 1009 |
tmp += cur_drv->last_sect; |
1008 |
fdctrl->data_len *= tmp;
|
|
1010 |
fdctrl->data_len *= tmp;
|
|
1009 | 1011 |
} |
1010 | 1012 |
fdctrl->eot = fdctrl->fifo[6]; |
1011 | 1013 |
if (fdctrl->dma_en) { |
... | ... | |
1014 | 1016 |
dma_mode = DMA_get_channel_mode(fdctrl->dma_chann); |
1015 | 1017 |
dma_mode = (dma_mode >> 2) & 3; |
1016 | 1018 |
FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n", |
1017 |
dma_mode, direction,
|
|
1019 |
dma_mode, direction,
|
|
1018 | 1020 |
(128 << fdctrl->fifo[5]) * |
1019 |
(cur_drv->last_sect - ks + 1), fdctrl->data_len);
|
|
1021 |
(cur_drv->last_sect - ks + 1), fdctrl->data_len);
|
|
1020 | 1022 |
if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || |
1021 | 1023 |
direction == FD_DIR_SCANH) && dma_mode == 0) || |
1022 | 1024 |
(direction == FD_DIR_WRITE && dma_mode == 2) || |
... | ... | |
1030 | 1032 |
DMA_schedule(fdctrl->dma_chann); |
1031 | 1033 |
return; |
1032 | 1034 |
} else { |
1033 |
FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
|
|
1035 |
FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
|
|
1034 | 1036 |
} |
1035 | 1037 |
} |
1036 | 1038 |
FLOPPY_DPRINTF("start non-DMA transfer\n"); |
... | ... | |
1070 | 1072 |
if (dma_len > fdctrl->data_len) |
1071 | 1073 |
dma_len = fdctrl->data_len; |
1072 | 1074 |
if (cur_drv->bs == NULL) { |
1073 |
if (fdctrl->data_dir == FD_DIR_WRITE)
|
|
1074 |
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
|
|
1075 |
else
|
|
1076 |
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
|
|
1077 |
len = 0;
|
|
1075 |
if (fdctrl->data_dir == FD_DIR_WRITE)
|
|
1076 |
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
|
|
1077 |
else
|
|
1078 |
fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
|
|
1079 |
len = 0;
|
|
1078 | 1080 |
goto transfer_error; |
1079 | 1081 |
} |
1080 | 1082 |
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; |
... | ... | |
1088 | 1090 |
cur_drv->track, cur_drv->sect, fd_sector(cur_drv), |
1089 | 1091 |
fd_sector(cur_drv) * 512); |
1090 | 1092 |
if (fdctrl->data_dir != FD_DIR_WRITE || |
1091 |
len < FD_SECTOR_LEN || rel_pos != 0) {
|
|
1093 |
len < FD_SECTOR_LEN || rel_pos != 0) {
|
|
1092 | 1094 |
/* READ & SCAN commands and realign to a sector for WRITE */ |
1093 | 1095 |
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), |
1094 |
fdctrl->fifo, 1) < 0) {
|
|
1096 |
fdctrl->fifo, 1) < 0) {
|
|
1095 | 1097 |
FLOPPY_DPRINTF("Floppy: error getting sector %d\n", |
1096 | 1098 |
fd_sector(cur_drv)); |
1097 | 1099 |
/* Sure, image size is too small... */ |
1098 | 1100 |
memset(fdctrl->fifo, 0, FD_SECTOR_LEN); |
1099 | 1101 |
} |
1100 | 1102 |
} |
1101 |
switch (fdctrl->data_dir) {
|
|
1102 |
case FD_DIR_READ:
|
|
1103 |
/* READ commands */
|
|
1103 |
switch (fdctrl->data_dir) {
|
|
1104 |
case FD_DIR_READ:
|
|
1105 |
/* READ commands */
|
|
1104 | 1106 |
DMA_write_memory (nchan, fdctrl->fifo + rel_pos, |
1105 | 1107 |
fdctrl->data_pos, len); |
1106 |
/* cpu_physical_memory_write(addr + fdctrl->data_pos, */ |
|
1107 |
/* fdctrl->fifo + rel_pos, len); */ |
|
1108 |
break; |
|
1109 |
case FD_DIR_WRITE: |
|
1108 |
break; |
|
1109 |
case FD_DIR_WRITE: |
|
1110 | 1110 |
/* WRITE commands */ |
1111 | 1111 |
DMA_read_memory (nchan, fdctrl->fifo + rel_pos, |
1112 | 1112 |
fdctrl->data_pos, len); |
1113 |
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ |
|
1114 |
/* fdctrl->fifo + rel_pos, len); */ |
|
1115 | 1113 |
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), |
1116 |
fdctrl->fifo, 1) < 0) {
|
|
1114 |
fdctrl->fifo, 1) < 0) {
|
|
1117 | 1115 |
FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); |
1118 | 1116 |
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
1119 | 1117 |
goto transfer_error; |
1120 | 1118 |
} |
1121 |
break;
|
|
1122 |
default:
|
|
1123 |
/* SCAN commands */
|
|
1119 |
break;
|
|
1120 |
default:
|
|
1121 |
/* SCAN commands */
|
|
1124 | 1122 |
{ |
1125 |
uint8_t tmpbuf[FD_SECTOR_LEN];
|
|
1123 |
uint8_t tmpbuf[FD_SECTOR_LEN];
|
|
1126 | 1124 |
int ret; |
1127 | 1125 |
DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); |
1128 |
/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ |
|
1129 |
/* tmpbuf, len); */ |
|
1130 | 1126 |
ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); |
1131 | 1127 |
if (ret == 0) { |
1132 | 1128 |
status2 = 0x08; |
... | ... | |
1138 | 1134 |
goto end_transfer; |
1139 | 1135 |
} |
1140 | 1136 |
} |
1141 |
break;
|
|
1137 |
break;
|
|
1142 | 1138 |
} |
1143 |
fdctrl->data_pos += len;
|
|
1144 |
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
|
|
1139 |
fdctrl->data_pos += len;
|
|
1140 |
rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
|
|
1145 | 1141 |
if (rel_pos == 0) { |
1146 | 1142 |
/* Seek to next sector */ |
1147 |
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
|
|
1148 |
cur_drv->head, cur_drv->track, cur_drv->sect,
|
|
1149 |
fd_sector(cur_drv),
|
|
1150 |
fdctrl->data_pos - len);
|
|
1143 |
FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
|
|
1144 |
cur_drv->head, cur_drv->track, cur_drv->sect,
|
|
1145 |
fd_sector(cur_drv),
|
|
1146 |
fdctrl->data_pos - len);
|
|
1151 | 1147 |
/* XXX: cur_drv->sect >= cur_drv->last_sect should be an |
1152 | 1148 |
error in fact */ |
1153 | 1149 |
if (cur_drv->sect >= cur_drv->last_sect || |
1154 | 1150 |
cur_drv->sect == fdctrl->eot) { |
1155 |
cur_drv->sect = 1;
|
|
1156 |
if (FD_MULTI_TRACK(fdctrl->data_state)) {
|
|
1157 |
if (cur_drv->head == 0 &&
|
|
1158 |
(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
|
|
1151 |
cur_drv->sect = 1;
|
|
1152 |
if (FD_MULTI_TRACK(fdctrl->data_state)) {
|
|
1153 |
if (cur_drv->head == 0 &&
|
|
1154 |
(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
|
|
1159 | 1155 |
cur_drv->head = 1; |
1160 | 1156 |
} else { |
1161 | 1157 |
cur_drv->head = 0; |
1162 |
cur_drv->track++;
|
|
1163 |
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
|
|
1164 |
break;
|
|
1158 |
cur_drv->track++;
|
|
1159 |
if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
|
|
1160 |
break;
|
|
1165 | 1161 |
} |
1166 | 1162 |
} else { |
1167 | 1163 |
cur_drv->track++; |
1168 | 1164 |
break; |
1169 | 1165 |
} |
1170 |
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
|
|
1171 |
cur_drv->head, cur_drv->track,
|
|
1172 |
cur_drv->sect, fd_sector(cur_drv));
|
|
1166 |
FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
|
|
1167 |
cur_drv->head, cur_drv->track,
|
|
1168 |
cur_drv->sect, fd_sector(cur_drv));
|
|
1173 | 1169 |
} else { |
1174 | 1170 |
cur_drv->sect++; |
1175 | 1171 |
} |
1176 | 1172 |
} |
1177 | 1173 |
} |
1178 |
end_transfer: |
|
1174 |
end_transfer:
|
|
1179 | 1175 |
len = fdctrl->data_pos - start_pos; |
1180 | 1176 |
FLOPPY_DPRINTF("end transfer %d %d %d\n", |
1181 |
fdctrl->data_pos, len, fdctrl->data_len);
|
|
1177 |
fdctrl->data_pos, len, fdctrl->data_len);
|
|
1182 | 1178 |
if (fdctrl->data_dir == FD_DIR_SCANE || |
1183 | 1179 |
fdctrl->data_dir == FD_DIR_SCANL || |
1184 | 1180 |
fdctrl->data_dir == FD_DIR_SCANH) |
... | ... | |
1188 | 1184 |
fdctrl->data_len -= len; |
1189 | 1185 |
// if (fdctrl->data_len == 0) |
1190 | 1186 |
fdctrl_stop_transfer(fdctrl, status0, status1, status2); |
1191 |
transfer_error: |
|
1187 |
transfer_error:
|
|
1192 | 1188 |
|
1193 | 1189 |
return len; |
1194 | 1190 |
} |
... | ... | |
1284 | 1280 |
FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv)); |
1285 | 1281 |
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
1286 | 1282 |
} else { |
1287 |
if (cur_drv->sect == cur_drv->last_sect) {
|
|
1288 |
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
|
1289 |
/* Last sector done */
|
|
1290 |
if (FD_DID_SEEK(fdctrl->data_state))
|
|
1291 |
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
|
|
1292 |
else
|
|
1293 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
|
1294 |
} else {
|
|
1295 |
/* More to do */
|
|
1296 |
fdctrl->data_pos = 0;
|
|
1297 |
fdctrl->data_len = 4;
|
|
1298 |
}
|
|
1283 |
if (cur_drv->sect == cur_drv->last_sect) {
|
|
1284 |
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
|
1285 |
/* Last sector done */
|
|
1286 |
if (FD_DID_SEEK(fdctrl->data_state))
|
|
1287 |
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
|
|
1288 |
else
|
|
1289 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
|
1290 |
} else {
|
|
1291 |
/* More to do */
|
|
1292 |
fdctrl->data_pos = 0;
|
|
1293 |
fdctrl->data_len = 4;
|
|
1294 |
}
|
|
1299 | 1295 |
} |
1300 | 1296 |
} |
1301 | 1297 |
|
... | ... | |
1423 | 1419 |
#endif |
1424 | 1420 |
fdctrl->fifo[1] = cur_drv->track; |
1425 | 1421 |
fdctrl_set_fifo(fdctrl, 2, 0); |
1426 |
fdctrl_reset_irq(fdctrl);
|
|
1427 |
fdctrl->int_status = 0xC0;
|
|
1422 |
fdctrl_reset_irq(fdctrl);
|
|
1423 |
fdctrl->int_status = 0xC0;
|
|
1428 | 1424 |
return; |
1429 | 1425 |
case 0x0E: |
1430 | 1426 |
/* DUMPREG */ |
... | ... | |
1439 | 1435 |
fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en; |
1440 | 1436 |
fdctrl->fifo[6] = cur_drv->last_sect; |
1441 | 1437 |
fdctrl->fifo[7] = (fdctrl->lock << 7) | |
1442 |
(cur_drv->perpendicular << 2);
|
|
1438 |
(cur_drv->perpendicular << 2); |
|
1443 | 1439 |
fdctrl->fifo[8] = fdctrl->config; |
1444 | 1440 |
fdctrl->fifo[9] = fdctrl->precomp_trk; |
1445 | 1441 |
fdctrl_set_fifo(fdctrl, 10, 0); |
... | ... | |
1507 | 1503 |
fdctrl->fifo[7] = fdctrl->timer1; |
1508 | 1504 |
fdctrl->fifo[8] = cur_drv->last_sect; |
1509 | 1505 |
fdctrl->fifo[9] = (fdctrl->lock << 7) | |
1510 |
(cur_drv->perpendicular << 2);
|
|
1506 |
(cur_drv->perpendicular << 2); |
|
1511 | 1507 |
fdctrl->fifo[10] = fdctrl->config; |
1512 | 1508 |
fdctrl->fifo[11] = fdctrl->precomp_trk; |
1513 | 1509 |
fdctrl->fifo[12] = fdctrl->pwrd; |
... | ... | |
1584 | 1580 |
return; |
1585 | 1581 |
} |
1586 | 1582 |
} |
1587 |
enqueue: |
|
1583 |
enqueue:
|
|
1588 | 1584 |
FLOPPY_DPRINTF("%s: %02x\n", __func__, value); |
1589 | 1585 |
fdctrl->fifo[fdctrl->data_pos] = value; |
1590 | 1586 |
if (++fdctrl->data_pos == fdctrl->data_len) { |
1591 | 1587 |
/* We now have all parameters |
1592 | 1588 |
* and will be able to treat the command |
1593 | 1589 |
*/ |
1594 |
if (fdctrl->data_state & FD_STATE_FORMAT) { |
|
1595 |
fdctrl_format_sector(fdctrl); |
|
1596 |
return; |
|
1597 |
} |
|
1598 |
switch (fdctrl->fifo[0] & 0x1F) { |
|
1599 |
case 0x06: |
|
1600 |
{ |
|
1601 |
/* READ variants */ |
|
1602 |
FLOPPY_DPRINTF("treat READ command\n"); |
|
1603 |
fdctrl_start_transfer(fdctrl, FD_DIR_READ); |
|
1590 |
if (fdctrl->data_state & FD_STATE_FORMAT) { |
|
1591 |
fdctrl_format_sector(fdctrl); |
|
1604 | 1592 |
return; |
1605 | 1593 |
} |
1594 |
switch (fdctrl->fifo[0] & 0x1F) { |
|
1595 |
case 0x06: |
|
1596 |
{ |
|
1597 |
/* READ variants */ |
|
1598 |
FLOPPY_DPRINTF("treat READ command\n"); |
|
1599 |
fdctrl_start_transfer(fdctrl, FD_DIR_READ); |
|
1600 |
return; |
|
1601 |
} |
|
1606 | 1602 |
case 0x0C: |
1607 | 1603 |
/* READ_DELETED variants */ |
1608 | 1604 |
// FLOPPY_DPRINTF("treat READ_DELETED command\n"); |
... | ... | |
1657 | 1653 |
FLOPPY_DPRINTF("treat SPECIFY command\n"); |
1658 | 1654 |
fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; |
1659 | 1655 |
fdctrl->timer1 = fdctrl->fifo[2] >> 1; |
1660 |
fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
|
|
1656 |
fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
|
|
1661 | 1657 |
/* No result back */ |
1662 | 1658 |
fdctrl_reset_fifo(fdctrl); |
1663 | 1659 |
break; |
... | ... | |
1665 | 1661 |
/* SENSE_DRIVE_STATUS */ |
1666 | 1662 |
FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); |
1667 | 1663 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1; |
1668 |
cur_drv = get_cur_drv(fdctrl);
|
|
1664 |
cur_drv = get_cur_drv(fdctrl);
|
|
1669 | 1665 |
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; |
1670 | 1666 |
/* 1 Byte status back */ |
1671 | 1667 |
fdctrl->fifo[0] = (cur_drv->ro << 6) | |
... | ... | |
1679 | 1675 |
/* RECALIBRATE */ |
1680 | 1676 |
FLOPPY_DPRINTF("treat RECALIBRATE command\n"); |
1681 | 1677 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1; |
1682 |
cur_drv = get_cur_drv(fdctrl);
|
|
1678 |
cur_drv = get_cur_drv(fdctrl);
|
|
1683 | 1679 |
fd_recalibrate(cur_drv); |
1684 |
fdctrl_reset_fifo(fdctrl);
|
|
1680 |
fdctrl_reset_fifo(fdctrl);
|
|
1685 | 1681 |
/* Raise Interrupt */ |
1686 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1682 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1687 | 1683 |
break; |
1688 | 1684 |
case 0x0F: |
1689 | 1685 |
/* SEEK */ |
1690 | 1686 |
FLOPPY_DPRINTF("treat SEEK command\n"); |
1691 | 1687 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1; |
1692 |
cur_drv = get_cur_drv(fdctrl);
|
|
1693 |
fd_start(cur_drv);
|
|
1688 |
cur_drv = get_cur_drv(fdctrl);
|
|
1689 |
fd_start(cur_drv);
|
|
1694 | 1690 |
if (fdctrl->fifo[2] <= cur_drv->track) |
1695 | 1691 |
cur_drv->dir = 1; |
1696 | 1692 |
else |
1697 | 1693 |
cur_drv->dir = 0; |
1698 |
fdctrl_reset_fifo(fdctrl);
|
|
1694 |
fdctrl_reset_fifo(fdctrl);
|
|
1699 | 1695 |
if (fdctrl->fifo[2] > cur_drv->max_track) { |
1700 | 1696 |
fdctrl_raise_irq(fdctrl, 0x60); |
1701 | 1697 |
} else { |
... | ... | |
1740 | 1736 |
fdctrl_start_transfer(fdctrl, FD_DIR_READ); |
1741 | 1737 |
break; |
1742 | 1738 |
case 0x4A: |
1743 |
/* READ_ID */
|
|
1739 |
/* READ_ID */ |
|
1744 | 1740 |
FLOPPY_DPRINTF("treat READ_ID command\n"); |
1745 | 1741 |
/* XXX: should set main status register to busy */ |
1746 | 1742 |
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; |
... | ... | |
1766 | 1762 |
break; |
1767 | 1763 |
case 0x4D: |
1768 | 1764 |
/* FORMAT_TRACK */ |
1769 |
FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
|
|
1770 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
|
|
1771 |
cur_drv = get_cur_drv(fdctrl);
|
|
1772 |
fdctrl->data_state |= FD_STATE_FORMAT;
|
|
1773 |
if (fdctrl->fifo[0] & 0x80)
|
|
1774 |
fdctrl->data_state |= FD_STATE_MULTI;
|
|
1775 |
else
|
|
1776 |
fdctrl->data_state &= ~FD_STATE_MULTI;
|
|
1777 |
fdctrl->data_state &= ~FD_STATE_SEEK;
|
|
1778 |
cur_drv->bps =
|
|
1779 |
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
|
|
1765 |
FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
|
|
1766 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
|
|
1767 |
cur_drv = get_cur_drv(fdctrl);
|
|
1768 |
fdctrl->data_state |= FD_STATE_FORMAT;
|
|
1769 |
if (fdctrl->fifo[0] & 0x80)
|
|
1770 |
fdctrl->data_state |= FD_STATE_MULTI;
|
|
1771 |
else
|
|
1772 |
fdctrl->data_state &= ~FD_STATE_MULTI;
|
|
1773 |
fdctrl->data_state &= ~FD_STATE_SEEK;
|
|
1774 |
cur_drv->bps =
|
|
1775 |
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
|
|
1780 | 1776 |
#if 0 |
1781 |
cur_drv->last_sect =
|
|
1782 |
cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
|
|
1783 |
fdctrl->fifo[3] / 2;
|
|
1777 |
cur_drv->last_sect =
|
|
1778 |
cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
|
|
1779 |
fdctrl->fifo[3] / 2;
|
|
1784 | 1780 |
#else |
1785 |
cur_drv->last_sect = fdctrl->fifo[3];
|
|
1781 |
cur_drv->last_sect = fdctrl->fifo[3];
|
|
1786 | 1782 |
#endif |
1787 |
/* TODO: implement format using DMA expected by the Bochs BIOS
|
|
1788 |
* and Linux fdformat (read 3 bytes per sector via DMA and fill
|
|
1789 |
* the sector with the specified fill byte
|
|
1790 |
*/
|
|
1791 |
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
|
1792 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
|
1783 |
/* TODO: implement format using DMA expected by the Bochs BIOS
|
|
1784 |
* and Linux fdformat (read 3 bytes per sector via DMA and fill
|
|
1785 |
* the sector with the specified fill byte
|
|
1786 |
*/
|
|
1787 |
fdctrl->data_state &= ~FD_STATE_FORMAT;
|
|
1788 |
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
|
1793 | 1789 |
break; |
1794 | 1790 |
case 0x8E: |
1795 | 1791 |
/* DRIVE_SPECIFICATION_COMMAND */ |
... | ... | |
1815 | 1811 |
/* RELATIVE_SEEK_OUT */ |
1816 | 1812 |
FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); |
1817 | 1813 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1; |
1818 |
cur_drv = get_cur_drv(fdctrl);
|
|
1819 |
fd_start(cur_drv);
|
|
1820 |
cur_drv->dir = 0;
|
|
1814 |
cur_drv = get_cur_drv(fdctrl);
|
|
1815 |
fd_start(cur_drv);
|
|
1816 |
cur_drv->dir = 0; |
|
1821 | 1817 |
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { |
1822 |
cur_drv->track = cur_drv->max_track - 1;
|
|
1818 |
cur_drv->track = cur_drv->max_track - 1;
|
|
1823 | 1819 |
} else { |
1824 | 1820 |
cur_drv->track += fdctrl->fifo[2]; |
1825 | 1821 |
} |
1826 |
fdctrl_reset_fifo(fdctrl);
|
|
1827 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1822 |
fdctrl_reset_fifo(fdctrl);
|
|
1823 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1828 | 1824 |
break; |
1829 | 1825 |
case 0xCD: |
1830 | 1826 |
/* FORMAT_AND_WRITE */ |
... | ... | |
1833 | 1829 |
fdctrl_unimplemented(fdctrl); |
1834 | 1830 |
break; |
1835 | 1831 |
case 0xCF: |
1836 |
/* RELATIVE_SEEK_IN */
|
|
1832 |
/* RELATIVE_SEEK_IN */ |
|
1837 | 1833 |
FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); |
1838 | 1834 |
fdctrl->cur_drv = fdctrl->fifo[1] & 1; |
1839 |
cur_drv = get_cur_drv(fdctrl);
|
|
1840 |
fd_start(cur_drv);
|
|
1841 |
cur_drv->dir = 1;
|
|
1835 |
cur_drv = get_cur_drv(fdctrl);
|
|
1836 |
fd_start(cur_drv);
|
|
1837 |
cur_drv->dir = 1; |
|
1842 | 1838 |
if (fdctrl->fifo[2] > cur_drv->track) { |
1843 |
cur_drv->track = 0;
|
|
1839 |
cur_drv->track = 0;
|
|
1844 | 1840 |
} else { |
1845 | 1841 |
cur_drv->track -= fdctrl->fifo[2]; |
1846 | 1842 |
} |
1847 |
fdctrl_reset_fifo(fdctrl);
|
|
1848 |
/* Raise Interrupt */
|
|
1849 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1843 |
fdctrl_reset_fifo(fdctrl);
|
|
1844 |
/* Raise Interrupt */
|
|
1845 |
fdctrl_raise_irq(fdctrl, 0x20);
|
|
1850 | 1846 |
break; |
1851 | 1847 |
} |
1852 | 1848 |
} |
... | ... | |
1856 | 1852 |
{ |
1857 | 1853 |
fdctrl_t *fdctrl = opaque; |
1858 | 1854 |
fdrive_t *cur_drv = get_cur_drv(fdctrl); |
1855 |
|
|
1859 | 1856 |
/* Pretend we are spinning. |
1860 | 1857 |
* This is needed for Coherent, which uses READ ID to check for |
1861 | 1858 |
* sector interleaving. |
Also available in: Unified diff