Revision 678803ab hw/fdc.c

b/hw/fdc.c
322 322
static int fdctrl_transfer_handler (void *opaque, int nchan,
323 323
                                    int dma_pos, int dma_len);
324 324
static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
325
static void fdctrl_result_timer(void *opaque);
326 325

  
327 326
static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
328 327
static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
......
694 693
    fdctrl_reset(s, 0);
695 694
}
696 695

  
697
static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann,
698
                                     target_phys_addr_t io_base,
699
                                     BlockDriverState **fds)
700
{
701
    fdctrl_t *fdctrl;
702
    int i;
703

  
704
    FLOPPY_DPRINTF("init controller\n");
705
    fdctrl = qemu_mallocz(sizeof(fdctrl_t));
706
    if (!fdctrl)
707
        return NULL;
708
    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
709
    if (fdctrl->fifo == NULL) {
710
        qemu_free(fdctrl);
711
        return NULL;
712
    }
713
    fdctrl->result_timer = qemu_new_timer(vm_clock,
714
                                          fdctrl_result_timer, fdctrl);
715

  
716
    fdctrl->version = 0x90; /* Intel 82078 controller */
717
    fdctrl->irq = irq;
718
    fdctrl->dma_chann = dma_chann;
719
    fdctrl->io_base = io_base;
720
    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
721
    if (fdctrl->dma_chann != -1) {
722
        fdctrl->dma_en = 1;
723
        DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
724
    } else {
725
        fdctrl->dma_en = 0;
726
    }
727
    for (i = 0; i < MAX_FD; i++) {
728
        fd_init(&fdctrl->drives[i], fds[i]);
729
    }
730
    fdctrl_reset(fdctrl, 0);
731
    fdctrl->state = FD_CTRL_ACTIVE;
732
    register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
733
    qemu_register_reset(fdctrl_external_reset, fdctrl);
734
    for (i = 0; i < MAX_FD; i++) {
735
        fd_revalidate(&fdctrl->drives[i]);
736
    }
737

  
738
    return fdctrl;
739
}
740

  
741
fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
742
                       target_phys_addr_t io_base,
743
                       BlockDriverState **fds)
744
{
745
    fdctrl_t *fdctrl;
746
    int io_mem;
747

  
748
    fdctrl = fdctrl_init_common(irq, dma_chann, io_base, fds);
749

  
750
    fdctrl->sun4m = 0;
751
    if (mem_mapped) {
752
        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write,
753
                                        fdctrl);
754
        cpu_register_physical_memory(io_base, 0x08, io_mem);
755
    } else {
756
        register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
757
                             fdctrl);
758
        register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
759
                             fdctrl);
760
        register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
761
                              fdctrl);
762
        register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
763
                              fdctrl);
764
    }
765

  
766
    return fdctrl;
767
}
768

  
769 696
static void fdctrl_handle_tc(void *opaque, int irq, int level)
770 697
{
771 698
    //fdctrl_t *s = opaque;
......
776 703
    }
777 704
}
778 705

  
779
fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
780
                             BlockDriverState **fds, qemu_irq *fdc_tc)
781
{
782
    fdctrl_t *fdctrl;
783
    int io_mem;
784

  
785
    fdctrl = fdctrl_init_common(irq, 0, io_base, fds);
786
    fdctrl->sun4m = 1;
787
    io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict,
788
                                    fdctrl_mem_write_strict,
789
                                    fdctrl);
790
    cpu_register_physical_memory(io_base, 0x08, io_mem);
791
    *fdc_tc = *qemu_allocate_irqs(fdctrl_handle_tc, fdctrl, 1);
792

  
793
    return fdctrl;
794
}
795

  
796 706
/* XXX: may change if moved to bdrv */
797 707
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
798 708
{
......
1730 1640
    fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1731 1641
}
1732 1642

  
1643
static const struct {
1644
    uint8_t value;
1645
    uint8_t mask;
1646
    const char* name;
1647
    int parameters;
1648
    void (*handler)(fdctrl_t *fdctrl, int direction);
1649
    int direction;
1650
} handlers[] = {
1651
    { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
1652
    { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
1653
    { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
1654
    { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
1655
    { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
1656
    { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
1657
    { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
1658
    { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
1659
    { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
1660
    { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
1661
    { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
1662
    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
1663
    { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
1664
    { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
1665
    { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
1666
    { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
1667
    { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
1668
    { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
1669
    { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
1670
    { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
1671
    { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
1672
    { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
1673
    { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
1674
    { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
1675
    { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
1676
    { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
1677
    { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
1678
    { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
1679
    { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
1680
    { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
1681
    { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
1682
    { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
1683
};
1684
/* Associate command to an index in the 'handlers' array */
1685
static uint8_t command_to_handler[256];
1686

  
1733 1687
static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1734 1688
{
1735 1689
    fdrive_t *cur_drv;
1736 1690
    int pos;
1737
    static const struct {
1738
        uint8_t value;
1739
        uint8_t mask;
1740
        const char* name;
1741
        int parameters;
1742
        void (*handler)(fdctrl_t *fdctrl, int direction);
1743
        int parameter;
1744
    } commands[] = {
1745
        { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
1746
        { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
1747
        { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
1748
        { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
1749
        { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
1750
        { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
1751
        { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
1752
        { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
1753
        { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
1754
        { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
1755
        { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
1756
        { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
1757
        { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
1758
        { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
1759
        { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
1760
        { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
1761
        { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
1762
        { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
1763
        { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
1764
        { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
1765
        { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
1766
        { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
1767
        { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
1768
        { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
1769
        { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
1770
        { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
1771
        { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
1772
        { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
1773
        { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
1774
        { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
1775
        { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
1776
    };
1777 1691

  
1778 1692
    cur_drv = get_cur_drv(fdctrl);
1779 1693
    /* Reset mode */
......
1803 1717
    }
1804 1718
    if (fdctrl->data_pos == 0) {
1805 1719
        /* Command */
1806
        for (pos = 0; pos < sizeof(commands)/sizeof(commands[0]); pos++) {
1807
            if ((value & commands[pos].mask) == commands[pos].value) {
1808
                FLOPPY_DPRINTF("%s command\n", commands[pos].name);
1809
                fdctrl->data_len = commands[pos].parameters + 1;
1810
                goto enqueue;
1811
            }
1812
        }
1813

  
1814
        /* Unknown command */
1815
        FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1816
        fdctrl_unimplemented(fdctrl, 0);
1817
        return;
1720
        pos = command_to_handler[value & 0xff];
1721
        FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
1722
        fdctrl->data_len = handlers[pos].parameters + 1;
1818 1723
    }
1819
 enqueue:
1724

  
1820 1725
    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1821 1726
    fdctrl->fifo[fdctrl->data_pos] = value;
1822 1727
    if (++fdctrl->data_pos == fdctrl->data_len) {
......
1828 1733
            return;
1829 1734
        }
1830 1735

  
1831
        for (pos = 0; pos < sizeof(commands)/sizeof(commands[0]); pos++) {
1832
            if ((fdctrl->fifo[0] & commands[pos].mask) == commands[pos].value) {
1833
                FLOPPY_DPRINTF("treat %s command\n", commands[pos].name);
1834
                (*commands[pos].handler)(fdctrl, commands[pos].parameter);
1835
                break;
1836
            }
1837
        }
1736
        pos = command_to_handler[fdctrl->fifo[0] & 0xff];
1737
        FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
1738
        (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
1838 1739
    }
1839 1740
}
1840 1741

  
......
1852 1753
    }
1853 1754
    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1854 1755
}
1756

  
1757
/* Init functions */
1758
static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann,
1759
                                     target_phys_addr_t io_base,
1760
                                     BlockDriverState **fds)
1761
{
1762
    fdctrl_t *fdctrl;
1763
    int i, j;
1764

  
1765
    /* Fill 'command_to_handler' lookup table */
1766
    for (i = sizeof(handlers)/sizeof(handlers[0]) - 1; i >= 0; i--) {
1767
        for (j = 0; j < sizeof(command_to_handler); j++) {
1768
            if ((j & handlers[i].mask) == handlers[i].value)
1769
                command_to_handler[j] = i;
1770
        }
1771
    }
1772

  
1773
    FLOPPY_DPRINTF("init controller\n");
1774
    fdctrl = qemu_mallocz(sizeof(fdctrl_t));
1775
    if (!fdctrl)
1776
        return NULL;
1777
    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
1778
    if (fdctrl->fifo == NULL) {
1779
        qemu_free(fdctrl);
1780
        return NULL;
1781
    }
1782
    fdctrl->result_timer = qemu_new_timer(vm_clock,
1783
                                          fdctrl_result_timer, fdctrl);
1784

  
1785
    fdctrl->version = 0x90; /* Intel 82078 controller */
1786
    fdctrl->irq = irq;
1787
    fdctrl->dma_chann = dma_chann;
1788
    fdctrl->io_base = io_base;
1789
    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
1790
    if (fdctrl->dma_chann != -1) {
1791
        fdctrl->dma_en = 1;
1792
        DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
1793
    } else {
1794
        fdctrl->dma_en = 0;
1795
    }
1796
    for (i = 0; i < MAX_FD; i++) {
1797
        fd_init(&fdctrl->drives[i], fds[i]);
1798
    }
1799
    fdctrl_reset(fdctrl, 0);
1800
    fdctrl->state = FD_CTRL_ACTIVE;
1801
    register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
1802
    qemu_register_reset(fdctrl_external_reset, fdctrl);
1803
    for (i = 0; i < MAX_FD; i++) {
1804
        fd_revalidate(&fdctrl->drives[i]);
1805
    }
1806

  
1807
    return fdctrl;
1808
}
1809

  
1810
fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
1811
                       target_phys_addr_t io_base,
1812
                       BlockDriverState **fds)
1813
{
1814
    fdctrl_t *fdctrl;
1815
    int io_mem;
1816

  
1817
    fdctrl = fdctrl_init_common(irq, dma_chann, io_base, fds);
1818

  
1819
    fdctrl->sun4m = 0;
1820
    if (mem_mapped) {
1821
        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write,
1822
                                        fdctrl);
1823
        cpu_register_physical_memory(io_base, 0x08, io_mem);
1824
    } else {
1825
        register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
1826
                             fdctrl);
1827
        register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
1828
                             fdctrl);
1829
        register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
1830
                              fdctrl);
1831
        register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
1832
                              fdctrl);
1833
    }
1834

  
1835
    return fdctrl;
1836
}
1837

  
1838
fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
1839
                             BlockDriverState **fds, qemu_irq *fdc_tc)
1840
{
1841
    fdctrl_t *fdctrl;
1842
    int io_mem;
1843

  
1844
    fdctrl = fdctrl_init_common(irq, 0, io_base, fds);
1845
    fdctrl->sun4m = 1;
1846
    io_mem = cpu_register_io_memory(0, fdctrl_mem_read_strict,
1847
                                    fdctrl_mem_write_strict,
1848
                                    fdctrl);
1849
    cpu_register_physical_memory(io_base, 0x08, io_mem);
1850
    *fdc_tc = *qemu_allocate_irqs(fdctrl_handle_tc, fdctrl, 1);
1851

  
1852
    return fdctrl;
1853
}

Also available in: Unified diff