@@ -230,6 +230,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
+static void fdctrl_read_pio_cb(void *opaque, int ret);
+static void fdctrl_write_pio_cb(void *opaque, int ret);
enum {
FD_DIR_WRITE = 0,
@@ -429,6 +431,8 @@ struct FDCtrl {
/* Timers state */
uint8_t timer0;
uint8_t timer1;
+ QEMUIOVector qiov;
+ struct iovec iov;
};
typedef struct FDCtrlSysBus {
@@ -443,6 +447,9 @@ typedef struct FDCtrlISABus {
int32_t bootindexB;
} FDCtrlISABus;
+/* Associate command to an index in the 'handlers' array */
+static uint8_t command_to_handler[256];
+
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
{
FDCtrl *fdctrl = opaque;
@@ -1164,6 +1171,16 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
fdctrl->msr |= FD_MSR_NONDMA;
if (direction != FD_DIR_WRITE)
fdctrl->msr |= FD_MSR_DIO;
+
+ if (0 == command_to_handler[fdctrl->fifo[0] & 0xff]) {
+ fdctrl->msr &= ~FD_MSR_RQM;
+ fdctrl->iov.iov_base = fdctrl->fifo;
+ fdctrl->iov.iov_len = FD_SECTOR_LEN;
+ qemu_iovec_init_external(&fdctrl->qiov, &fdctrl->iov, 1);
+ bdrv_aio_readv(cur_drv->bs, fd_sector(cur_drv),
+ &fdctrl->qiov, 1, fdctrl_read_pio_cb, fdctrl);
+ }
+
/* IO based transfer: calculate len */
fdctrl_raise_irq(fdctrl, 0x00);
@@ -1301,6 +1318,23 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
return len;
}
+static void fdctrl_read_pio_cb(void *opaque, int ret)
+{
+ FDCtrl *fdctrl = opaque;
+ FDrive *cur_drv;
+
+ if (ret < 0) {
+ cur_drv = get_cur_drv(fdctrl);
+ FLOPPY_DPRINTF("error getting sector %d\n",
+ fd_sector(cur_drv));
+ /* Sure, image size is too small... */
+ memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+ return;
+ }
+
+ fdctrl->msr |= FD_MSR_RQM;
+ return;
+}
/* Data register : 0x05 */
static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
{
@@ -1315,23 +1349,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
return 0;
}
pos = fdctrl->data_pos;
- if (fdctrl->msr & FD_MSR_NONDMA) {
- pos %= FD_SECTOR_LEN;
- if (pos == 0) {
- if (fdctrl->data_pos != 0)
- if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
- FLOPPY_DPRINTF("error seeking to next sector %d\n",
- fd_sector(cur_drv));
- return 0;
- }
- if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
- FLOPPY_DPRINTF("error getting sector %d\n",
- fd_sector(cur_drv));
- /* Sure, image size is too small... */
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- }
- }
- }
+ pos %= FD_SECTOR_LEN;
retval = fdctrl->fifo[pos];
if (++fdctrl->data_pos == fdctrl->data_len) {
fdctrl->data_pos = 0;
@@ -1344,9 +1362,27 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
fdctrl_reset_fifo(fdctrl);
fdctrl_reset_irq(fdctrl);
}
+ goto end;
}
- FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
+ if (fdctrl->msr & FD_MSR_NONDMA) {
+ if (pos + 1 == FD_SECTOR_LEN) {
+ if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+ FLOPPY_DPRINTF("error seeking to next sector %d\n",
+ fd_sector(cur_drv));
+ return 0;
+ }
+ fdctrl->msr &= ~FD_MSR_RQM;
+ fdctrl->iov.iov_base = fdctrl->fifo;
+ fdctrl->iov.iov_len = FD_SECTOR_LEN;
+ qemu_iovec_init_external(&fdctrl->qiov, &fdctrl->iov, 1);
+ bdrv_aio_readv(cur_drv->bs, fd_sector(cur_drv),
+ &fdctrl->qiov, 1, fdctrl_read_pio_cb, fdctrl);
+ }
+ }
+
+end:
+ FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
return retval;
}
@@ -1756,8 +1792,34 @@ static const struct {
{ FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
{ 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
};
-/* Associate command to an index in the 'handlers' array */
-static uint8_t command_to_handler[256];
+
+static void fdctrl_write_pio_cb(void *opaque, int ret)
+{
+ FDCtrl *fdctrl = opaque;
+ FDrive *cur_drv;
+
+ cur_drv = get_cur_drv(fdctrl);
+ if (ret < 0) {
+ FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+ return;
+ }
+ if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+ FLOPPY_DPRINTF("error seeking to next sector %d\n",
+ fd_sector(cur_drv));
+ return;
+ }
+
+ fdctrl->msr |= FD_MSR_RQM;
+
+ /* Switch from transfer mode to status mode
+ * then from status mode to command mode
+ */
+ if (fdctrl->data_pos == fdctrl->data_len) {
+ fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
+ }
+
+ return;
+}
static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
{
@@ -1783,21 +1845,14 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
if (pos == FD_SECTOR_LEN - 1 ||
fdctrl->data_pos == fdctrl->data_len) {
cur_drv = get_cur_drv(fdctrl);
- if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
- FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
- return;
- }
- if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
- FLOPPY_DPRINTF("error seeking to next sector %d\n",
- fd_sector(cur_drv));
- return;
- }
+
+ fdctrl->msr &= ~FD_MSR_RQM;
+ fdctrl->iov.iov_base = fdctrl->fifo;
+ fdctrl->iov.iov_len = FD_SECTOR_LEN;
+ qemu_iovec_init_external(&fdctrl->qiov, &fdctrl->iov, 1);
+ bdrv_aio_writev(cur_drv->bs, fd_sector(cur_drv),
+ &fdctrl->qiov, 1, fdctrl_write_pio_cb, fdctrl);
}
- /* Switch from transfer mode to status mode
- * then from status mode to command mode
- */
- if (fdctrl->data_pos == fdctrl->data_len)
- fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
return;
}
if (fdctrl->data_pos == 0) {
Replace bdrv_* to bdrv_aio_* functions in pio mode in fdc.c. Signed-off-by: Li Zhi Hui <zhihuili@linux.vnet.ibm.com> --- hw/fdc.c | 123 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 89 insertions(+), 34 deletions(-)