static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)

{

    fdrive_t *cur_drv;

    uint8_t kh, kt, ks;

    int did_seek;



    fdctrl->cur_drv = fdctrl->fifo[1] & 1;

    cur_drv = get_cur_drv(fdctrl);

    kt = fdctrl->fifo[2];

    kh = fdctrl->fifo[3];

    ks = fdctrl->fifo[4];

    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",

                   fdctrl->cur_drv, kh, kt, ks,

                   _fd_sector(kh, kt, ks, cur_drv->last_sect));

    did_seek = 0;

    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {

    case 2:

        /* sect too big */

        fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);

        fdctrl->fifo[3] = kt;

        fdctrl->fifo[4] = kh;

        fdctrl->fifo[5] = ks;

        return;

    case 3:

        /* track too big */

        fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);

        fdctrl->fifo[3] = kt;

        fdctrl->fifo[4] = kh;

        fdctrl->fifo[5] = ks;

        return;

    case 4:

        /* No seek enabled */

        fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);

        fdctrl->fifo[3] = kt;

        fdctrl->fifo[4] = kh;

        fdctrl->fifo[5] = ks;

        return;

    case 1:

        did_seek = 1;

        break;

    default:

        break;

    }

    /* Set the FIFO state */

    fdctrl->data_dir = direction;

    fdctrl->data_pos = 0;

    FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */

    if (fdctrl->fifo[0] & 0x80)

        fdctrl->data_state |= FD_STATE_MULTI;

    else

        fdctrl->data_state &= ~FD_STATE_MULTI;

    if (did_seek)

        fdctrl->data_state |= FD_STATE_SEEK;

    else

        fdctrl->data_state &= ~FD_STATE_SEEK;

    if (fdctrl->fifo[5] == 00) {

        fdctrl->data_len = fdctrl->fifo[8];

    } else {

	int tmp;

        fdctrl->data_len = 128 << fdctrl->fifo[5];

        tmp = (cur_drv->last_sect - ks + 1);

        if (fdctrl->fifo[0] & 0x80)

            tmp += cur_drv->last_sect;

	fdctrl->data_len *= tmp;

    }

    fdctrl->eot = fdctrl->fifo[6];

    if (fdctrl->dma_en) {

        int dma_mode;

        /* DMA transfer are enabled. Check if DMA channel is well programmed */

        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);

        dma_mode = (dma_mode >> 2) & 3;

        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",

		       dma_mode, direction,

                       (128 << fdctrl->fifo[5]) *

		       (cur_drv->last_sect - ks + 1), fdctrl->data_len);

        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||

              direction == FD_DIR_SCANH) && dma_mode == 0) ||

            (direction == FD_DIR_WRITE && dma_mode == 2) ||

            (direction == FD_DIR_READ && dma_mode == 1)) {

            /* No access is allowed until DMA transfer has completed */

            fdctrl->state |= FD_CTRL_BUSY;

            /* Now, we just have to wait for the DMA controller to

             * recall us...

             */

            DMA_hold_DREQ(fdctrl->dma_chann);

            DMA_schedule(fdctrl->dma_chann);

            return;

        } else {

	    FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);

        }

    }

    FLOPPY_DPRINTF("start non-DMA transfer\n");

    /* IO based transfer: calculate len */

    fdctrl_raise_irq(fdctrl, 0x00);



    return;

}
