⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fdc.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 4 页
字号:
    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] > 7 ? 7 : 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;}/* Prepare a transfer of deleted data */static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction){    /* We don't handle deleted data,     * so we don't return *ANYTHING*     */    fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);}/* handlers for DMA transfers */static int fdctrl_transfer_handler (void *opaque, int nchan,                                    int dma_pos, int dma_len){    fdctrl_t *fdctrl;    fdrive_t *cur_drv;    int len, start_pos, rel_pos;    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;    fdctrl = opaque;    if (!(fdctrl->state & FD_CTRL_BUSY)) {        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");        return 0;    }    cur_drv = get_cur_drv(fdctrl);    if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||        fdctrl->data_dir == FD_DIR_SCANH)        status2 = 0x04;    if (dma_len > fdctrl->data_len)        dma_len = fdctrl->data_len;    if (cur_drv->bs == NULL) {	if (fdctrl->data_dir == FD_DIR_WRITE)	    fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);	else	    fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);	len = 0;        goto transfer_error;    }    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {        len = dma_len - fdctrl->data_pos;        if (len + rel_pos > FD_SECTOR_LEN)            len = FD_SECTOR_LEN - rel_pos;        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,                       fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),                       fd_sector(cur_drv) * 512);        if (fdctrl->data_dir != FD_DIR_WRITE ||	    len < FD_SECTOR_LEN || rel_pos != 0) {            /* READ & SCAN commands and realign to a sector for WRITE */            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),			  fdctrl->fifo, 1) < 0) {                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",                               fd_sector(cur_drv));                /* Sure, image size is too small... */                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);            }        }	switch (fdctrl->data_dir) {	case FD_DIR_READ:	    /* READ commands */            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,                              fdctrl->data_pos, len);/* 	    cpu_physical_memory_write(addr + fdctrl->data_pos, *//* 				      fdctrl->fifo + rel_pos, len); */	    break;	case FD_DIR_WRITE:            /* WRITE commands */            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,                             fdctrl->data_pos, len);/*             cpu_physical_memory_read(addr + fdctrl->data_pos, *//* 				     fdctrl->fifo + rel_pos, len); */            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),			   fdctrl->fifo, 1) < 0) {                FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));                fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);                goto transfer_error;            }	    break;	default:	    /* SCAN commands */            {		uint8_t tmpbuf[FD_SECTOR_LEN];                int ret;                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);/*                 cpu_physical_memory_read(addr + fdctrl->data_pos, *//*                                          tmpbuf, len); */                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);                if (ret == 0) {                    status2 = 0x08;                    goto end_transfer;                }                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {                    status2 = 0x00;                    goto end_transfer;                }            }	    break;        }	fdctrl->data_pos += len;	rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;        if (rel_pos == 0) {            /* Seek to next sector */	    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",			   cur_drv->head, cur_drv->track, cur_drv->sect,			   fd_sector(cur_drv),			   fdctrl->data_pos - len);            /* XXX: cur_drv->sect >= cur_drv->last_sect should be an               error in fact */            if (cur_drv->sect >= cur_drv->last_sect ||                cur_drv->sect == fdctrl->eot) {		cur_drv->sect = 1;		if (FD_MULTI_TRACK(fdctrl->data_state)) {		    if (cur_drv->head == 0 &&			(cur_drv->flags & FDISK_DBL_SIDES) != 0) {	                        cur_drv->head = 1;                    } else {                        cur_drv->head = 0;			cur_drv->track++;			if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)			    break;                    }                } else {                    cur_drv->track++;                    break;                }		FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",			       cur_drv->head, cur_drv->track,			       cur_drv->sect, fd_sector(cur_drv));            } else {                cur_drv->sect++;            }        }    }end_transfer:    len = fdctrl->data_pos - start_pos;    FLOPPY_DPRINTF("end transfer %d %d %d\n",		   fdctrl->data_pos, len, fdctrl->data_len);    if (fdctrl->data_dir == FD_DIR_SCANE ||        fdctrl->data_dir == FD_DIR_SCANL ||        fdctrl->data_dir == FD_DIR_SCANH)        status2 = 0x08;    if (FD_DID_SEEK(fdctrl->data_state))        status0 |= 0x20;    fdctrl->data_len -= len;    //    if (fdctrl->data_len == 0)    fdctrl_stop_transfer(fdctrl, status0, status1, status2);transfer_error:    return len;}/* Data register : 0x05 */static uint32_t fdctrl_read_data (fdctrl_t *fdctrl){    fdrive_t *cur_drv;    uint32_t retval = 0;    int pos, len;    cur_drv = get_cur_drv(fdctrl);    fdctrl->state &= ~FD_CTRL_SLEEP;    if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {        FLOPPY_ERROR("can't read data in CMD state\n");        return 0;    }    pos = fdctrl->data_pos;    if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {        pos %= FD_SECTOR_LEN;        if (pos == 0) {            len = fdctrl->data_len - fdctrl->data_pos;            if (len > FD_SECTOR_LEN)                len = FD_SECTOR_LEN;            if (cur_drv->bs) {                bdrv_read(cur_drv->bs, fd_sector(cur_drv),                          fdctrl->fifo, len);            } else {                FLOPPY_ERROR("can't read data from drive\n");                return 0;            }        }    }    retval = fdctrl->fifo[pos];    if (++fdctrl->data_pos == fdctrl->data_len) {        fdctrl->data_pos = 0;        /* Switch from transfer mode to status mode         * then from status mode to command mode         */        if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {            fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);        } else {            fdctrl_reset_fifo(fdctrl);            fdctrl_reset_irq(fdctrl);        }    }    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);    return retval;}static void fdctrl_format_sector (fdctrl_t *fdctrl){    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[6];    kh = fdctrl->fifo[7];    ks = fdctrl->fifo[8];    FLOPPY_DPRINTF("format sector 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;        fdctrl->data_state |= FD_STATE_SEEK;        break;    default:        break;    }    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);    if (cur_drv->bs == NULL ||        bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {        FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));        fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);    } else {	if (cur_drv->sect == cur_drv->last_sect) {	    fdctrl->data_state &= ~FD_STATE_FORMAT;	    /* Last sector done */	    if (FD_DID_SEEK(fdctrl->data_state))		fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);	    else		fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);	} else {	    /* More to do */	    fdctrl->data_pos = 0;	    fdctrl->data_len = 4;	}    }}static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value){    fdrive_t *cur_drv;    cur_drv = get_cur_drv(fdctrl);    /* Reset mode */    if (fdctrl->state & FD_CTRL_RESET) {        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");        return;    }    fdctrl->state &= ~FD_CTRL_SLEEP;    if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {        FLOPPY_ERROR("can't write data in status mode\n");        return;    }    /* Is it write command time ? */    if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {        /* FIFO data write */        fdctrl->fifo[fdctrl->data_pos++] = value;        if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||            fdctrl->data_pos == fdctrl->data_len) {            bdrv_write(cur_drv->bs, fd_sector(cur_drv),                       fdctrl->fifo, FD_SECTOR_LEN);        }        /* Switch from transfer mode to status mode         * then from status mode to command mode         */        if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)            fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);        return;    }    if (fdctrl->data_pos == 0) {        /* Command */        switch (value & 0x5F) {        case 0x46:            /* READ variants */            FLOPPY_DPRINTF("READ command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x4C:            /* READ_DELETED variants */            FLOPPY_DPRINTF("READ_DELETED command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x50:            /* SCAN_EQUAL variants */            FLOPPY_DPRINTF("SCAN_EQUAL command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x56:            /* VERIFY variants */            FLOPPY_DPRINTF("VERIFY command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x59:            /* SCAN_LOW_OR_EQUAL variants */            FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x5D:            /* SCAN_HIGH_OR_EQUAL variants */            FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        default:            break;        }        switch (value & 0x7F) {        case 0x45:            /* WRITE variants */            FLOPPY_DPRINTF("WRITE command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        case 0x49:            /* WRITE_DELETED variants */            FLOPPY_DPRINTF("WRITE_DELETED command\n");            /* 8 parameters cmd */            fdctrl->data_len = 9;            goto enqueue;        default:            break;        }        switch (value) {        case 0x03:            /* SPECIFY */            FLOPPY_DPRINTF("SPECIFY command\n");            /* 1 parameter cmd */            fdctrl->data_len = 3;            goto enqueue;        case 0x04:            /* SENSE_DRIVE_STATUS */            FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");            /* 1 parameter cmd */            fdctrl->data_len = 2;            goto enqueue;        case 0x07:            /* RECALIBRATE */            FLOPPY_DPRINTF("RECALIBRATE command\n");            /* 1 parameter cmd */            fdctrl->data_len = 2;            goto enqueue;        case 0x08:            /* SENSE_INTERRUPT_STATUS */            FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",                           fdctrl->int_status);            /* No parameters cmd: returns status if no interrupt */#if 0            fdctrl->fifo[0] =                fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;#else            /* XXX: int_status handling is broken for read/write               commands, so we do this hack. It should be suppressed               ASAP */            fdctrl->fifo[0] =

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -