Commit 890fa6bebbb540b9761aafc3fe37b87e26578346
1 parent
a4c4785b
floppy fixes (initial patch by Mike Nordell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1101 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
32 additions
and
23 deletions
hw/fdc.c
| 1 | 1 | /* |
| 2 | - * QEMU Floppy disk emulator | |
| 2 | + * QEMU Floppy disk emulator (Intel 82078) | |
| 3 | 3 | * |
| 4 | 4 | * Copyright (c) 2003 Jocelyn Mayer |
| 5 | 5 | * |
| ... | ... | @@ -382,6 +382,7 @@ struct fdctrl_t { |
| 382 | 382 | uint8_t data_state; |
| 383 | 383 | uint8_t data_dir; |
| 384 | 384 | uint8_t int_status; |
| 385 | + uint8_t eot; /* last wanted sector */ | |
| 385 | 386 | /* States kept only to be returned back */ |
| 386 | 387 | /* Timers state */ |
| 387 | 388 | uint8_t timer0; |
| ... | ... | @@ -762,7 +763,7 @@ static void fdctrl_unimplemented (fdctrl_t *fdctrl) |
| 762 | 763 | fdrive_t *cur_drv; |
| 763 | 764 | |
| 764 | 765 | cur_drv = get_cur_drv(fdctrl); |
| 765 | - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl->cur_drv; | |
| 766 | + fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; | |
| 766 | 767 | fdctrl->fifo[1] = 0x00; |
| 767 | 768 | fdctrl->fifo[2] = 0x00; |
| 768 | 769 | fdctrl_set_fifo(fdctrl, 3, 1); |
| ... | ... | @@ -782,8 +783,8 @@ static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, |
| 782 | 783 | cur_drv = get_cur_drv(fdctrl); |
| 783 | 784 | FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", |
| 784 | 785 | status0, status1, status2, |
| 785 | - status0 | (cur_drv->head << 1) | fdctrl->cur_drv); | |
| 786 | - fdctrl->fifo[0] = status0 | (cur_drv->head << 1) | fdctrl->cur_drv; | |
| 786 | + status0 | (cur_drv->head << 2) | fdctrl->cur_drv); | |
| 787 | + fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; | |
| 787 | 788 | fdctrl->fifo[1] = status1; |
| 788 | 789 | fdctrl->fifo[2] = status2; |
| 789 | 790 | fdctrl->fifo[3] = cur_drv->track; |
| ... | ... | @@ -810,7 +811,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) |
| 810 | 811 | kt = fdctrl->fifo[2]; |
| 811 | 812 | kh = fdctrl->fifo[3]; |
| 812 | 813 | ks = fdctrl->fifo[4]; |
| 813 | - FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n", | |
| 814 | + FLOPPY_DPRINTF("Start tranfer at %d %d %02x %02x (%d)\n", | |
| 814 | 815 | fdctrl->cur_drv, kh, kt, ks, |
| 815 | 816 | _fd_sector(kh, kt, ks, cur_drv->last_sect)); |
| 816 | 817 | did_seek = 0; |
| ... | ... | @@ -864,6 +865,7 @@ static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) |
| 864 | 865 | tmp += cur_drv->last_sect; |
| 865 | 866 | fdctrl->data_len *= tmp; |
| 866 | 867 | } |
| 868 | + fdctrl->eot = fdctrl->fifo[6]; | |
| 867 | 869 | if (fdctrl->dma_en) { |
| 868 | 870 | int dma_mode; |
| 869 | 871 | /* DMA transfer are enabled. Check if DMA channel is well programmed */ |
| ... | ... | @@ -924,14 +926,14 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) |
| 924 | 926 | status2 = 0x04; |
| 925 | 927 | if (size > fdctrl->data_len) |
| 926 | 928 | size = fdctrl->data_len; |
| 927 | - if (cur_drv->bs == NULL) { | |
| 929 | + if (cur_drv->bs == NULL) { | |
| 928 | 930 | if (fdctrl->data_dir == FD_DIR_WRITE) |
| 929 | 931 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
| 930 | 932 | else |
| 931 | 933 | fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); |
| 932 | 934 | len = 0; |
| 933 | - goto transfer_error; | |
| 934 | - } | |
| 935 | + goto transfer_error; | |
| 936 | + } | |
| 935 | 937 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; |
| 936 | 938 | for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) { |
| 937 | 939 | len = size - fdctrl->data_pos; |
| ... | ... | @@ -952,7 +954,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) |
| 952 | 954 | /* Sure, image size is too small... */ |
| 953 | 955 | memset(fdctrl->fifo, 0, FD_SECTOR_LEN); |
| 954 | 956 | } |
| 955 | - } | |
| 957 | + } | |
| 956 | 958 | switch (fdctrl->data_dir) { |
| 957 | 959 | case FD_DIR_READ: |
| 958 | 960 | /* READ commands */ |
| ... | ... | @@ -968,7 +970,7 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) |
| 968 | 970 | FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); |
| 969 | 971 | fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); |
| 970 | 972 | goto transfer_error; |
| 971 | - } | |
| 973 | + } | |
| 972 | 974 | break; |
| 973 | 975 | default: |
| 974 | 976 | /* SCAN commands */ |
| ... | ... | @@ -994,30 +996,34 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size) |
| 994 | 996 | rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; |
| 995 | 997 | if (rel_pos == 0) { |
| 996 | 998 | /* Seek to next sector */ |
| 997 | - cur_drv->sect++; | |
| 998 | 999 | FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", |
| 999 | 1000 | cur_drv->head, cur_drv->track, cur_drv->sect, |
| 1000 | 1001 | fd_sector(cur_drv), |
| 1001 | 1002 | fdctrl->data_pos - size); |
| 1002 | - if (cur_drv->sect > cur_drv->last_sect) { | |
| 1003 | + /* XXX: cur_drv->sect >= cur_drv->last_sect should be an | |
| 1004 | + error in fact */ | |
| 1005 | + if (cur_drv->sect >= cur_drv->last_sect || | |
| 1006 | + cur_drv->sect == fdctrl->eot) { | |
| 1003 | 1007 | cur_drv->sect = 1; |
| 1004 | 1008 | if (FD_MULTI_TRACK(fdctrl->data_state)) { |
| 1005 | 1009 | if (cur_drv->head == 0 && |
| 1006 | 1010 | (cur_drv->flags & FDISK_DBL_SIDES) != 0) { |
| 1007 | - cur_drv->head = 1; | |
| 1008 | - } else { | |
| 1009 | - cur_drv->head = 0; | |
| 1011 | + cur_drv->head = 1; | |
| 1012 | + } else { | |
| 1013 | + cur_drv->head = 0; | |
| 1010 | 1014 | cur_drv->track++; |
| 1011 | 1015 | if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) |
| 1012 | 1016 | break; |
| 1017 | + } | |
| 1018 | + } else { | |
| 1019 | + cur_drv->track++; | |
| 1020 | + break; | |
| 1013 | 1021 | } |
| 1014 | - } else { | |
| 1015 | - cur_drv->track++; | |
| 1016 | - break; | |
| 1017 | - } | |
| 1018 | 1022 | FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", |
| 1019 | 1023 | cur_drv->head, cur_drv->track, |
| 1020 | 1024 | cur_drv->sect, fd_sector(cur_drv)); |
| 1025 | + } else { | |
| 1026 | + cur_drv->sect++; | |
| 1021 | 1027 | } |
| 1022 | 1028 | } |
| 1023 | 1029 | } |
| ... | ... | @@ -1033,7 +1039,7 @@ end_transfer: |
| 1033 | 1039 | status0 |= 0x20; |
| 1034 | 1040 | fdctrl->data_len -= len; |
| 1035 | 1041 | // if (fdctrl->data_len == 0) |
| 1036 | - fdctrl_stop_transfer(fdctrl, status0, status1, status2); | |
| 1042 | + fdctrl_stop_transfer(fdctrl, status0, status1, status2); | |
| 1037 | 1043 | transfer_error: |
| 1038 | 1044 | |
| 1039 | 1045 | return len; |
| ... | ... | @@ -1066,7 +1072,7 @@ static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) |
| 1066 | 1072 | retval = fdctrl->fifo[pos]; |
| 1067 | 1073 | if (++fdctrl->data_pos == fdctrl->data_len) { |
| 1068 | 1074 | fdctrl->data_pos = 0; |
| 1069 | - /* Switch from transfert mode to status mode | |
| 1075 | + /* Switch from transfer mode to status mode | |
| 1070 | 1076 | * then from status mode to command mode |
| 1071 | 1077 | */ |
| 1072 | 1078 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { |
| ... | ... | @@ -1170,7 +1176,7 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) |
| 1170 | 1176 | bdrv_write(cur_drv->bs, fd_sector(cur_drv), |
| 1171 | 1177 | fdctrl->fifo, FD_SECTOR_LEN); |
| 1172 | 1178 | } |
| 1173 | - /* Switch from transfert mode to status mode | |
| 1179 | + /* Switch from transfer mode to status mode | |
| 1174 | 1180 | * then from status mode to command mode |
| 1175 | 1181 | */ |
| 1176 | 1182 | if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) |
| ... | ... | @@ -1510,7 +1516,9 @@ enqueue: |
| 1510 | 1516 | /* 1 Byte status back */ |
| 1511 | 1517 | fdctrl->fifo[0] = (cur_drv->ro << 6) | |
| 1512 | 1518 | (cur_drv->track == 0 ? 0x10 : 0x00) | |
| 1513 | - fdctrl->cur_drv; | |
| 1519 | + (cur_drv->head << 2) | | |
| 1520 | + fdctrl->cur_drv | | |
| 1521 | + 0x28; | |
| 1514 | 1522 | fdctrl_set_fifo(fdctrl, 1, 0); |
| 1515 | 1523 | break; |
| 1516 | 1524 | case 0x07: |
| ... | ... | @@ -1581,6 +1589,7 @@ enqueue: |
| 1581 | 1589 | /* READ_ID */ |
| 1582 | 1590 | FLOPPY_DPRINTF("treat READ_ID command\n"); |
| 1583 | 1591 | /* XXX: should set main status register to busy */ |
| 1592 | + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; | |
| 1584 | 1593 | qemu_mod_timer(fdctrl->result_timer, |
| 1585 | 1594 | qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); |
| 1586 | 1595 | break; | ... | ... |