Commit 65cef780e2a637b0ae08ad759665241b9c1a8b0f

Authored by blueswir1
1 parent 2e4d9fb1

Simplify FDC code (Hervé Poussineau)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4174 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 361 additions and 517 deletions
hw/fdc.c
... ... @@ -2,6 +2,7 @@
2 2 * QEMU Floppy disk emulator (Intel 82078)
3 3 *
4 4 * Copyright (c) 2003, 2007 Jocelyn Mayer
  5 + * Copyright (c) 2008 Hervé Poussineau
5 6 *
6 7 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 8 * of this software and associated documentation files (the "Software"), to deal
... ... @@ -372,35 +373,34 @@ enum {
372 373 };
373 374  
374 375 enum {
  376 + FD_CMD_READ_TRACK = 0x02,
375 377 FD_CMD_SPECIFY = 0x03,
376 378 FD_CMD_SENSE_DRIVE_STATUS = 0x04,
  379 + FD_CMD_WRITE = 0x05,
  380 + FD_CMD_READ = 0x06,
377 381 FD_CMD_RECALIBRATE = 0x07,
378 382 FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
  383 + FD_CMD_WRITE_DELETED = 0x09,
  384 + FD_CMD_READ_ID = 0x0a,
  385 + FD_CMD_READ_DELETED = 0x0c,
  386 + FD_CMD_FORMAT_TRACK = 0x0d,
379 387 FD_CMD_DUMPREG = 0x0e,
380 388 FD_CMD_SEEK = 0x0f,
381 389 FD_CMD_VERSION = 0x10,
  390 + FD_CMD_SCAN_EQUAL = 0x11,
382 391 FD_CMD_PERPENDICULAR_MODE = 0x12,
383 392 FD_CMD_CONFIGURE = 0x13,
384   - FD_CMD_UNLOCK = 0x14,
  393 + FD_CMD_LOCK = 0x14,
  394 + FD_CMD_VERIFY = 0x16,
385 395 FD_CMD_POWERDOWN_MODE = 0x17,
386 396 FD_CMD_PART_ID = 0x18,
  397 + FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
  398 + FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
387 399 FD_CMD_SAVE = 0x2c,
388 400 FD_CMD_OPTION = 0x33,
389   - FD_CMD_READ_TRACK = 0x42,
390   - FD_CMD_WRITE = 0x45,
391   - FD_CMD_READ = 0x46,
392   - FD_CMD_WRITE_DELETED = 0x49,
393   - FD_CMD_READ_ID = 0x4a,
394   - FD_CMD_READ_DELETED = 0x4c,
395 401 FD_CMD_RESTORE = 0x4c,
396   - FD_CMD_FORMAT_TRACK = 0x4d,
397   - FD_CMD_SCAN_EQUAL = 0x50,
398   - FD_CMD_VERIFY = 0x56,
399   - FD_CMD_SCAN_LOW_OR_EQUAL = 0x59,
400   - FD_CMD_SCAN_HIGH_OR_EQUAL = 0x5d,
401 402 FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
402 403 FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
403   - FD_CMD_LOCK = 0x94,
404 404 FD_CMD_FORMAT_AND_WRITE = 0xcd,
405 405 FD_CMD_RELATIVE_SEEK_IN = 0xcf,
406 406 };
... ... @@ -1047,7 +1047,7 @@ static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
1047 1047 }
1048 1048  
1049 1049 /* Set an error: unimplemented/unknown command */
1050   -static void fdctrl_unimplemented (fdctrl_t *fdctrl)
  1050 +static void fdctrl_unimplemented (fdctrl_t *fdctrl, int direction)
1051 1051 {
1052 1052 #if 0
1053 1053 fdrive_t *cur_drv;
... ... @@ -1441,9 +1441,339 @@ static void fdctrl_format_sector (fdctrl_t *fdctrl)
1441 1441 }
1442 1442 }
1443 1443  
  1444 +static void fdctrl_handle_lock (fdctrl_t *fdctrl, int direction)
  1445 +{
  1446 + fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
  1447 + fdctrl->fifo[0] = fdctrl->lock << 4;
  1448 + fdctrl_set_fifo(fdctrl, 1, fdctrl->lock);
  1449 +}
  1450 +
  1451 +static void fdctrl_handle_dumpreg (fdctrl_t *fdctrl, int direction)
  1452 +{
  1453 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1454 +
  1455 + /* Drives position */
  1456 + fdctrl->fifo[0] = drv0(fdctrl)->track;
  1457 + fdctrl->fifo[1] = drv1(fdctrl)->track;
  1458 + fdctrl->fifo[2] = 0;
  1459 + fdctrl->fifo[3] = 0;
  1460 + /* timers */
  1461 + fdctrl->fifo[4] = fdctrl->timer0;
  1462 + fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
  1463 + fdctrl->fifo[6] = cur_drv->last_sect;
  1464 + fdctrl->fifo[7] = (fdctrl->lock << 7) |
  1465 + (cur_drv->perpendicular << 2);
  1466 + fdctrl->fifo[8] = fdctrl->config;
  1467 + fdctrl->fifo[9] = fdctrl->precomp_trk;
  1468 + fdctrl_set_fifo(fdctrl, 10, 0);
  1469 +}
  1470 +
  1471 +static void fdctrl_handle_version (fdctrl_t *fdctrl, int direction)
  1472 +{
  1473 + /* Controller's version */
  1474 + fdctrl->fifo[0] = fdctrl->version;
  1475 + fdctrl_set_fifo(fdctrl, 1, 1);
  1476 +}
  1477 +
  1478 +static void fdctrl_handle_partid (fdctrl_t *fdctrl, int direction)
  1479 +{
  1480 + fdctrl->fifo[0] = 0x41; /* Stepping 1 */
  1481 + fdctrl_set_fifo(fdctrl, 1, 0);
  1482 +}
  1483 +
  1484 +static void fdctrl_handle_restore (fdctrl_t *fdctrl, int direction)
  1485 +{
  1486 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1487 +
  1488 + /* Drives position */
  1489 + drv0(fdctrl)->track = fdctrl->fifo[3];
  1490 + drv1(fdctrl)->track = fdctrl->fifo[4];
  1491 + /* timers */
  1492 + fdctrl->timer0 = fdctrl->fifo[7];
  1493 + fdctrl->timer1 = fdctrl->fifo[8];
  1494 + cur_drv->last_sect = fdctrl->fifo[9];
  1495 + fdctrl->lock = fdctrl->fifo[10] >> 7;
  1496 + cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
  1497 + fdctrl->config = fdctrl->fifo[11];
  1498 + fdctrl->precomp_trk = fdctrl->fifo[12];
  1499 + fdctrl->pwrd = fdctrl->fifo[13];
  1500 + fdctrl_reset_fifo(fdctrl);
  1501 +}
  1502 +
  1503 +static void fdctrl_handle_save (fdctrl_t *fdctrl, int direction)
  1504 +{
  1505 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1506 +
  1507 + fdctrl->fifo[0] = 0;
  1508 + fdctrl->fifo[1] = 0;
  1509 + /* Drives position */
  1510 + fdctrl->fifo[2] = drv0(fdctrl)->track;
  1511 + fdctrl->fifo[3] = drv1(fdctrl)->track;
  1512 + fdctrl->fifo[4] = 0;
  1513 + fdctrl->fifo[5] = 0;
  1514 + /* timers */
  1515 + fdctrl->fifo[6] = fdctrl->timer0;
  1516 + fdctrl->fifo[7] = fdctrl->timer1;
  1517 + fdctrl->fifo[8] = cur_drv->last_sect;
  1518 + fdctrl->fifo[9] = (fdctrl->lock << 7) |
  1519 + (cur_drv->perpendicular << 2);
  1520 + fdctrl->fifo[10] = fdctrl->config;
  1521 + fdctrl->fifo[11] = fdctrl->precomp_trk;
  1522 + fdctrl->fifo[12] = fdctrl->pwrd;
  1523 + fdctrl->fifo[13] = 0;
  1524 + fdctrl->fifo[14] = 0;
  1525 + fdctrl_set_fifo(fdctrl, 15, 1);
  1526 +}
  1527 +
  1528 +static void fdctrl_handle_readid (fdctrl_t *fdctrl, int direction)
  1529 +{
  1530 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1531 +
  1532 + /* XXX: should set main status register to busy */
  1533 + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
  1534 + qemu_mod_timer(fdctrl->result_timer,
  1535 + qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
  1536 +}
  1537 +
  1538 +static void fdctrl_handle_format_track (fdctrl_t *fdctrl, int direction)
  1539 +{
  1540 + fdrive_t *cur_drv;
  1541 +
  1542 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1543 + cur_drv = get_cur_drv(fdctrl);
  1544 + fdctrl->data_state |= FD_STATE_FORMAT;
  1545 + if (fdctrl->fifo[0] & 0x80)
  1546 + fdctrl->data_state |= FD_STATE_MULTI;
  1547 + else
  1548 + fdctrl->data_state &= ~FD_STATE_MULTI;
  1549 + fdctrl->data_state &= ~FD_STATE_SEEK;
  1550 + cur_drv->bps =
  1551 + fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
  1552 +#if 0
  1553 + cur_drv->last_sect =
  1554 + cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
  1555 + fdctrl->fifo[3] / 2;
  1556 +#else
  1557 + cur_drv->last_sect = fdctrl->fifo[3];
  1558 +#endif
  1559 + /* TODO: implement format using DMA expected by the Bochs BIOS
  1560 + * and Linux fdformat (read 3 bytes per sector via DMA and fill
  1561 + * the sector with the specified fill byte
  1562 + */
  1563 + fdctrl->data_state &= ~FD_STATE_FORMAT;
  1564 + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
  1565 +}
  1566 +
  1567 +static void fdctrl_handle_specify (fdctrl_t *fdctrl, int direction)
  1568 +{
  1569 + fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
  1570 + fdctrl->timer1 = fdctrl->fifo[2] >> 1;
  1571 + fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
  1572 + /* No result back */
  1573 + fdctrl_reset_fifo(fdctrl);
  1574 +}
  1575 +
  1576 +static void fdctrl_handle_sense_drive_status (fdctrl_t *fdctrl, int direction)
  1577 +{
  1578 + fdrive_t *cur_drv;
  1579 +
  1580 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1581 + cur_drv = get_cur_drv(fdctrl);
  1582 + cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
  1583 + /* 1 Byte status back */
  1584 + fdctrl->fifo[0] = (cur_drv->ro << 6) |
  1585 + (cur_drv->track == 0 ? 0x10 : 0x00) |
  1586 + (cur_drv->head << 2) |
  1587 + fdctrl->cur_drv |
  1588 + 0x28;
  1589 + fdctrl_set_fifo(fdctrl, 1, 0);
  1590 +}
  1591 +
  1592 +static void fdctrl_handle_recalibrate (fdctrl_t *fdctrl, int direction)
  1593 +{
  1594 + fdrive_t *cur_drv;
  1595 +
  1596 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1597 + cur_drv = get_cur_drv(fdctrl);
  1598 + fd_recalibrate(cur_drv);
  1599 + fdctrl_reset_fifo(fdctrl);
  1600 + /* Raise Interrupt */
  1601 + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
  1602 +}
  1603 +
  1604 +static void fdctrl_handle_sense_interrupt_status (fdctrl_t *fdctrl, int direction)
  1605 +{
  1606 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1607 +
  1608 +#if 0
  1609 + fdctrl->fifo[0] =
  1610 + fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
  1611 +#else
  1612 + /* XXX: int_status handling is broken for read/write
  1613 + commands, so we do this hack. It should be suppressed
  1614 + ASAP */
  1615 + fdctrl->fifo[0] =
  1616 + 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
  1617 +#endif
  1618 + fdctrl->fifo[1] = cur_drv->track;
  1619 + fdctrl_set_fifo(fdctrl, 2, 0);
  1620 + fdctrl_reset_irq(fdctrl);
  1621 + fdctrl->int_status = FD_SR0_RDYCHG;
  1622 +}
  1623 +
  1624 +static void fdctrl_handle_seek (fdctrl_t *fdctrl, int direction)
  1625 +{
  1626 + fdrive_t *cur_drv;
  1627 +
  1628 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1629 + cur_drv = get_cur_drv(fdctrl);
  1630 + fd_start(cur_drv);
  1631 + if (fdctrl->fifo[2] <= cur_drv->track)
  1632 + cur_drv->dir = 1;
  1633 + else
  1634 + cur_drv->dir = 0;
  1635 + fdctrl_reset_fifo(fdctrl);
  1636 + if (fdctrl->fifo[2] > cur_drv->max_track) {
  1637 + fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
  1638 + } else {
  1639 + cur_drv->track = fdctrl->fifo[2];
  1640 + /* Raise Interrupt */
  1641 + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
  1642 + }
  1643 +}
  1644 +
  1645 +static void fdctrl_handle_perpendicular_mode (fdctrl_t *fdctrl, int direction)
  1646 +{
  1647 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1648 +
  1649 + if (fdctrl->fifo[1] & 0x80)
  1650 + cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
  1651 + /* No result back */
  1652 + fdctrl_reset_fifo(fdctrl);
  1653 +}
  1654 +
  1655 +static void fdctrl_handle_configure (fdctrl_t *fdctrl, int direction)
  1656 +{
  1657 + fdctrl->config = fdctrl->fifo[2];
  1658 + fdctrl->precomp_trk = fdctrl->fifo[3];
  1659 + /* No result back */
  1660 + fdctrl_reset_fifo(fdctrl);
  1661 +}
  1662 +
  1663 +static void fdctrl_handle_powerdown_mode (fdctrl_t *fdctrl, int direction)
  1664 +{
  1665 + fdctrl->pwrd = fdctrl->fifo[1];
  1666 + fdctrl->fifo[0] = fdctrl->fifo[1];
  1667 + fdctrl_set_fifo(fdctrl, 1, 1);
  1668 +}
  1669 +
  1670 +static void fdctrl_handle_option (fdctrl_t *fdctrl, int direction)
  1671 +{
  1672 + /* No result back */
  1673 + fdctrl_reset_fifo(fdctrl);
  1674 +}
  1675 +
  1676 +static void fdctrl_handle_drive_specification_command (fdctrl_t *fdctrl, int direction)
  1677 +{
  1678 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1679 +
  1680 + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
  1681 + /* Command parameters done */
  1682 + if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
  1683 + fdctrl->fifo[0] = fdctrl->fifo[1];
  1684 + fdctrl->fifo[2] = 0;
  1685 + fdctrl->fifo[3] = 0;
  1686 + fdctrl_set_fifo(fdctrl, 4, 1);
  1687 + } else {
  1688 + fdctrl_reset_fifo(fdctrl);
  1689 + }
  1690 + } else if (fdctrl->data_len > 7) {
  1691 + /* ERROR */
  1692 + fdctrl->fifo[0] = 0x80 |
  1693 + (cur_drv->head << 2) | fdctrl->cur_drv;
  1694 + fdctrl_set_fifo(fdctrl, 1, 1);
  1695 + }
  1696 +}
  1697 +
  1698 +static void fdctrl_handle_relative_seek_out (fdctrl_t *fdctrl, int direction)
  1699 +{
  1700 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1701 +
  1702 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1703 + cur_drv = get_cur_drv(fdctrl);
  1704 + fd_start(cur_drv);
  1705 + cur_drv->dir = 0;
  1706 + if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
  1707 + cur_drv->track = cur_drv->max_track - 1;
  1708 + } else {
  1709 + cur_drv->track += fdctrl->fifo[2];
  1710 + }
  1711 + fdctrl_reset_fifo(fdctrl);
  1712 + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
  1713 +}
  1714 +
  1715 +static void fdctrl_handle_relative_seek_in (fdctrl_t *fdctrl, int direction)
  1716 +{
  1717 + fdrive_t *cur_drv = get_cur_drv(fdctrl);
  1718 +
  1719 + fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
  1720 + cur_drv = get_cur_drv(fdctrl);
  1721 + fd_start(cur_drv);
  1722 + cur_drv->dir = 1;
  1723 + if (fdctrl->fifo[2] > cur_drv->track) {
  1724 + cur_drv->track = 0;
  1725 + } else {
  1726 + cur_drv->track -= fdctrl->fifo[2];
  1727 + }
  1728 + fdctrl_reset_fifo(fdctrl);
  1729 + /* Raise Interrupt */
  1730 + fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
  1731 +}
  1732 +
1444 1733 static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1445 1734 {
1446 1735 fdrive_t *cur_drv;
  1736 + 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 + };
1447 1777  
1448 1778 cur_drv = get_cur_drv(fdctrl);
1449 1779 /* Reset mode */
... ... @@ -1473,258 +1803,18 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1473 1803 }
1474 1804 if (fdctrl->data_pos == 0) {
1475 1805 /* Command */
1476   - switch (value & 0x5F) {
1477   - case FD_CMD_READ:
1478   - /* READ variants */
1479   - FLOPPY_DPRINTF("READ command\n");
1480   - /* 8 parameters cmd */
1481   - fdctrl->data_len = 9;
1482   - goto enqueue;
1483   - case FD_CMD_READ_DELETED:
1484   - /* READ_DELETED variants */
1485   - FLOPPY_DPRINTF("READ_DELETED command\n");
1486   - /* 8 parameters cmd */
1487   - fdctrl->data_len = 9;
1488   - goto enqueue;
1489   - case FD_CMD_SCAN_EQUAL:
1490   - /* SCAN_EQUAL variants */
1491   - FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1492   - /* 8 parameters cmd */
1493   - fdctrl->data_len = 9;
1494   - goto enqueue;
1495   - case FD_CMD_VERIFY:
1496   - /* VERIFY variants */
1497   - FLOPPY_DPRINTF("VERIFY command\n");
1498   - /* 8 parameters cmd */
1499   - fdctrl->data_len = 9;
1500   - goto enqueue;
1501   - case FD_CMD_SCAN_LOW_OR_EQUAL:
1502   - /* SCAN_LOW_OR_EQUAL variants */
1503   - FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1504   - /* 8 parameters cmd */
1505   - fdctrl->data_len = 9;
1506   - goto enqueue;
1507   - case FD_CMD_SCAN_HIGH_OR_EQUAL:
1508   - /* SCAN_HIGH_OR_EQUAL variants */
1509   - FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1510   - /* 8 parameters cmd */
1511   - fdctrl->data_len = 9;
1512   - goto enqueue;
1513   - default:
1514   - break;
1515   - }
1516   - switch (value & 0x7F) {
1517   - case FD_CMD_WRITE:
1518   - /* WRITE variants */
1519   - FLOPPY_DPRINTF("WRITE command\n");
1520   - /* 8 parameters cmd */
1521   - fdctrl->data_len = 9;
1522   - goto enqueue;
1523   - case FD_CMD_WRITE_DELETED:
1524   - /* WRITE_DELETED variants */
1525   - FLOPPY_DPRINTF("WRITE_DELETED command\n");
1526   - /* 8 parameters cmd */
1527   - fdctrl->data_len = 9;
1528   - goto enqueue;
1529   - default:
1530   - break;
1531   - }
1532   - switch (value) {
1533   - case FD_CMD_SPECIFY:
1534   - /* SPECIFY */
1535   - FLOPPY_DPRINTF("SPECIFY command\n");
1536   - /* 1 parameter cmd */
1537   - fdctrl->data_len = 3;
1538   - goto enqueue;
1539   - case FD_CMD_SENSE_DRIVE_STATUS:
1540   - /* SENSE_DRIVE_STATUS */
1541   - FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1542   - /* 1 parameter cmd */
1543   - fdctrl->data_len = 2;
1544   - goto enqueue;
1545   - case FD_CMD_RECALIBRATE:
1546   - /* RECALIBRATE */
1547   - FLOPPY_DPRINTF("RECALIBRATE command\n");
1548   - /* 1 parameter cmd */
1549   - fdctrl->data_len = 2;
1550   - goto enqueue;
1551   - case FD_CMD_SENSE_INTERRUPT_STATUS:
1552   - /* SENSE_INTERRUPT_STATUS */
1553   - FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1554   - fdctrl->int_status);
1555   - /* No parameters cmd: returns status if no interrupt */
1556   -#if 0
1557   - fdctrl->fifo[0] =
1558   - fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1559   -#else
1560   - /* XXX: int_status handling is broken for read/write
1561   - commands, so we do this hack. It should be suppressed
1562   - ASAP */
1563   - fdctrl->fifo[0] =
1564   - 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1565   -#endif
1566   - fdctrl->fifo[1] = cur_drv->track;
1567   - fdctrl_set_fifo(fdctrl, 2, 0);
1568   - fdctrl_reset_irq(fdctrl);
1569   - fdctrl->int_status = FD_SR0_RDYCHG;
1570   - return;
1571   - case FD_CMD_DUMPREG:
1572   - /* DUMPREG */
1573   - FLOPPY_DPRINTF("DUMPREG command\n");
1574   - /* Drives position */
1575   - fdctrl->fifo[0] = drv0(fdctrl)->track;
1576   - fdctrl->fifo[1] = drv1(fdctrl)->track;
1577   - fdctrl->fifo[2] = 0;
1578   - fdctrl->fifo[3] = 0;
1579   - /* timers */
1580   - fdctrl->fifo[4] = fdctrl->timer0;
1581   - fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1582   - fdctrl->fifo[6] = cur_drv->last_sect;
1583   - fdctrl->fifo[7] = (fdctrl->lock << 7) |
1584   - (cur_drv->perpendicular << 2);
1585   - fdctrl->fifo[8] = fdctrl->config;
1586   - fdctrl->fifo[9] = fdctrl->precomp_trk;
1587   - fdctrl_set_fifo(fdctrl, 10, 0);
1588   - return;
1589   - case FD_CMD_SEEK:
1590   - /* SEEK */
1591   - FLOPPY_DPRINTF("SEEK command\n");
1592   - /* 2 parameters cmd */
1593   - fdctrl->data_len = 3;
1594   - goto enqueue;
1595   - case FD_CMD_VERSION:
1596   - /* VERSION */
1597   - FLOPPY_DPRINTF("VERSION command\n");
1598   - /* No parameters cmd */
1599   - /* Controller's version */
1600   - fdctrl->fifo[0] = fdctrl->version;
1601   - fdctrl_set_fifo(fdctrl, 1, 1);
1602   - return;
1603   - case FD_CMD_PERPENDICULAR_MODE:
1604   - /* PERPENDICULAR_MODE */
1605   - FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1606   - /* 1 parameter cmd */
1607   - fdctrl->data_len = 2;
1608   - goto enqueue;
1609   - case FD_CMD_CONFIGURE:
1610   - /* CONFIGURE */
1611   - FLOPPY_DPRINTF("CONFIGURE command\n");
1612   - /* 3 parameters cmd */
1613   - fdctrl->data_len = 4;
1614   - goto enqueue;
1615   - case FD_CMD_UNLOCK:
1616   - /* UNLOCK */
1617   - FLOPPY_DPRINTF("UNLOCK command\n");
1618   - /* No parameters cmd */
1619   - fdctrl->lock = 0;
1620   - fdctrl->fifo[0] = 0;
1621   - fdctrl_set_fifo(fdctrl, 1, 0);
1622   - return;
1623   - case FD_CMD_POWERDOWN_MODE:
1624   - /* POWERDOWN_MODE */
1625   - FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1626   - /* 2 parameters cmd */
1627   - fdctrl->data_len = 3;
1628   - goto enqueue;
1629   - case FD_CMD_PART_ID:
1630   - /* PART_ID */
1631   - FLOPPY_DPRINTF("PART_ID command\n");
1632   - /* No parameters cmd */
1633   - fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1634   - fdctrl_set_fifo(fdctrl, 1, 0);
1635   - return;
1636   - case FD_CMD_SAVE:
1637   - /* SAVE */
1638   - FLOPPY_DPRINTF("SAVE command\n");
1639   - /* No parameters cmd */
1640   - fdctrl->fifo[0] = 0;
1641   - fdctrl->fifo[1] = 0;
1642   - /* Drives position */
1643   - fdctrl->fifo[2] = drv0(fdctrl)->track;
1644   - fdctrl->fifo[3] = drv1(fdctrl)->track;
1645   - fdctrl->fifo[4] = 0;
1646   - fdctrl->fifo[5] = 0;
1647   - /* timers */
1648   - fdctrl->fifo[6] = fdctrl->timer0;
1649   - fdctrl->fifo[7] = fdctrl->timer1;
1650   - fdctrl->fifo[8] = cur_drv->last_sect;
1651   - fdctrl->fifo[9] = (fdctrl->lock << 7) |
1652   - (cur_drv->perpendicular << 2);
1653   - fdctrl->fifo[10] = fdctrl->config;
1654   - fdctrl->fifo[11] = fdctrl->precomp_trk;
1655   - fdctrl->fifo[12] = fdctrl->pwrd;
1656   - fdctrl->fifo[13] = 0;
1657   - fdctrl->fifo[14] = 0;
1658   - fdctrl_set_fifo(fdctrl, 15, 1);
1659   - return;
1660   - case FD_CMD_OPTION:
1661   - /* OPTION */
1662   - FLOPPY_DPRINTF("OPTION command\n");
1663   - /* 1 parameter cmd */
1664   - fdctrl->data_len = 2;
1665   - goto enqueue;
1666   - case FD_CMD_READ_TRACK:
1667   - /* READ_TRACK */
1668   - FLOPPY_DPRINTF("READ_TRACK command\n");
1669   - /* 8 parameters cmd */
1670   - fdctrl->data_len = 9;
1671   - goto enqueue;
1672   - case FD_CMD_READ_ID:
1673   - /* READ_ID */
1674   - FLOPPY_DPRINTF("READ_ID command\n");
1675   - /* 1 parameter cmd */
1676   - fdctrl->data_len = 2;
1677   - goto enqueue;
1678   - case FD_CMD_RESTORE:
1679   - /* RESTORE */
1680   - FLOPPY_DPRINTF("RESTORE command\n");
1681   - /* 17 parameters cmd */
1682   - fdctrl->data_len = 18;
1683   - goto enqueue;
1684   - case FD_CMD_FORMAT_TRACK:
1685   - /* FORMAT_TRACK */
1686   - FLOPPY_DPRINTF("FORMAT_TRACK command\n");
1687   - /* 5 parameters cmd */
1688   - fdctrl->data_len = 6;
1689   - goto enqueue;
1690   - case FD_CMD_DRIVE_SPECIFICATION_COMMAND:
1691   - /* DRIVE_SPECIFICATION_COMMAND */
1692   - FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
1693   - /* 5 parameters cmd */
1694   - fdctrl->data_len = 6;
1695   - goto enqueue;
1696   - case FD_CMD_RELATIVE_SEEK_OUT:
1697   - /* RELATIVE_SEEK_OUT */
1698   - FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
1699   - /* 2 parameters cmd */
1700   - fdctrl->data_len = 3;
1701   - goto enqueue;
1702   - case FD_CMD_LOCK:
1703   - /* LOCK */
1704   - FLOPPY_DPRINTF("LOCK command\n");
1705   - /* No parameters cmd */
1706   - fdctrl->lock = 1;
1707   - fdctrl->fifo[0] = 0x10;
1708   - fdctrl_set_fifo(fdctrl, 1, 1);
1709   - return;
1710   - case FD_CMD_FORMAT_AND_WRITE:
1711   - /* FORMAT_AND_WRITE */
1712   - FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
1713   - /* 10 parameters cmd */
1714   - fdctrl->data_len = 11;
1715   - goto enqueue;
1716   - case FD_CMD_RELATIVE_SEEK_IN:
1717   - /* RELATIVE_SEEK_IN */
1718   - FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
1719   - /* 2 parameters cmd */
1720   - fdctrl->data_len = 3;
1721   - goto enqueue;
1722   - default:
1723   - /* Unknown command */
1724   - FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1725   - fdctrl_unimplemented(fdctrl);
1726   - return;
  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 + }
1727 1812 }
  1813 +
  1814 + /* Unknown command */
  1815 + FLOPPY_ERROR("unknown command: 0x%02x\n", value);
  1816 + fdctrl_unimplemented(fdctrl, 0);
  1817 + return;
1728 1818 }
1729 1819 enqueue:
1730 1820 FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
... ... @@ -1737,259 +1827,13 @@ static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1737 1827 fdctrl_format_sector(fdctrl);
1738 1828 return;
1739 1829 }
1740   - switch (fdctrl->fifo[0] & 0x1F) {
1741   - case FD_CMD_READ & 0x1F:
1742   - {
1743   - /* READ variants */
1744   - FLOPPY_DPRINTF("treat READ command\n");
1745   - fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1746   - return;
1747   - }
1748   - case FD_CMD_READ_DELETED & 0x1F:
1749   - /* READ_DELETED variants */
1750   -// FLOPPY_DPRINTF("treat READ_DELETED command\n");
1751   - FLOPPY_ERROR("treat READ_DELETED command\n");
1752   - fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
1753   - return;
1754   - case FD_CMD_VERIFY & 0x1F:
1755   - /* VERIFY variants */
1756   -// FLOPPY_DPRINTF("treat VERIFY command\n");
1757   - FLOPPY_ERROR("treat VERIFY command\n");
1758   - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1759   - return;
1760   - case FD_CMD_SCAN_EQUAL & 0x1F:
1761   - /* SCAN_EQUAL variants */
1762   -// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
1763   - FLOPPY_ERROR("treat SCAN_EQUAL command\n");
1764   - fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
1765   - return;
1766   - case FD_CMD_SCAN_LOW_OR_EQUAL & 0x1F:
1767   - /* SCAN_LOW_OR_EQUAL variants */
1768   -// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
1769   - FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
1770   - fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
1771   - return;
1772   - case FD_CMD_SCAN_HIGH_OR_EQUAL & 0x1F:
1773   - /* SCAN_HIGH_OR_EQUAL variants */
1774   -// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
1775   - FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
1776   - fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
1777   - return;
1778   - default:
1779   - break;
1780   - }
1781   - switch (fdctrl->fifo[0] & 0x3F) {
1782   - case FD_CMD_WRITE & 0x3F:
1783   - /* WRITE variants */
1784   - FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
1785   - fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
1786   - return;
1787   - case FD_CMD_WRITE_DELETED & 0x3F:
1788   - /* WRITE_DELETED variants */
1789   -// FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
1790   - FLOPPY_ERROR("treat WRITE_DELETED command\n");
1791   - fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
1792   - return;
1793   - default:
1794   - break;
1795   - }
1796   - switch (fdctrl->fifo[0]) {
1797   - case FD_CMD_SPECIFY:
1798   - /* SPECIFY */
1799   - FLOPPY_DPRINTF("treat SPECIFY command\n");
1800   - fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1801   - fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1802   - fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
1803   - /* No result back */
1804   - fdctrl_reset_fifo(fdctrl);
1805   - break;
1806   - case FD_CMD_SENSE_DRIVE_STATUS:
1807   - /* SENSE_DRIVE_STATUS */
1808   - FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
1809   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1810   - cur_drv = get_cur_drv(fdctrl);
1811   - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1812   - /* 1 Byte status back */
1813   - fdctrl->fifo[0] = (cur_drv->ro << 6) |
1814   - (cur_drv->track == 0 ? 0x10 : 0x00) |
1815   - (cur_drv->head << 2) |
1816   - fdctrl->cur_drv |
1817   - 0x28;
1818   - fdctrl_set_fifo(fdctrl, 1, 0);
1819   - break;
1820   - case FD_CMD_RECALIBRATE:
1821   - /* RECALIBRATE */
1822   - FLOPPY_DPRINTF("treat RECALIBRATE command\n");
1823   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1824   - cur_drv = get_cur_drv(fdctrl);
1825   - fd_recalibrate(cur_drv);
1826   - fdctrl_reset_fifo(fdctrl);
1827   - /* Raise Interrupt */
1828   - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1829   - break;
1830   - case FD_CMD_SEEK:
1831   - /* SEEK */
1832   - FLOPPY_DPRINTF("treat SEEK command\n");
1833   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1834   - cur_drv = get_cur_drv(fdctrl);
1835   - fd_start(cur_drv);
1836   - if (fdctrl->fifo[2] <= cur_drv->track)
1837   - cur_drv->dir = 1;
1838   - else
1839   - cur_drv->dir = 0;
1840   - fdctrl_reset_fifo(fdctrl);
1841   - if (fdctrl->fifo[2] > cur_drv->max_track) {
1842   - fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
1843   - } else {
1844   - cur_drv->track = fdctrl->fifo[2];
1845   - /* Raise Interrupt */
1846   - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1847   - }
1848   - break;
1849   - case FD_CMD_PERPENDICULAR_MODE:
1850   - /* PERPENDICULAR_MODE */
1851   - FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
1852   - if (fdctrl->fifo[1] & 0x80)
1853   - cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1854   - /* No result back */
1855   - fdctrl_reset_fifo(fdctrl);
1856   - break;
1857   - case FD_CMD_CONFIGURE:
1858   - /* CONFIGURE */
1859   - FLOPPY_DPRINTF("treat CONFIGURE command\n");
1860   - fdctrl->config = fdctrl->fifo[2];
1861   - fdctrl->precomp_trk = fdctrl->fifo[3];
1862   - /* No result back */
1863   - fdctrl_reset_fifo(fdctrl);
1864   - break;
1865   - case FD_CMD_POWERDOWN_MODE:
1866   - /* POWERDOWN_MODE */
1867   - FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
1868   - fdctrl->pwrd = fdctrl->fifo[1];
1869   - fdctrl->fifo[0] = fdctrl->fifo[1];
1870   - fdctrl_set_fifo(fdctrl, 1, 1);
1871   - break;
1872   - case FD_CMD_OPTION:
1873   - /* OPTION */
1874   - FLOPPY_DPRINTF("treat OPTION command\n");
1875   - /* No result back */
1876   - fdctrl_reset_fifo(fdctrl);
1877   - break;
1878   - case FD_CMD_READ_TRACK:
1879   - /* READ_TRACK */
1880   - FLOPPY_DPRINTF("treat READ_TRACK command\n");
1881   - FLOPPY_ERROR("treat READ_TRACK command\n");
1882   - fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1883   - break;
1884   - case FD_CMD_READ_ID:
1885   - /* READ_ID */
1886   - FLOPPY_DPRINTF("treat READ_ID command\n");
1887   - /* XXX: should set main status register to busy */
1888   - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1889   - qemu_mod_timer(fdctrl->result_timer,
1890   - qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1891   - break;
1892   - case FD_CMD_RESTORE:
1893   - /* RESTORE */
1894   - FLOPPY_DPRINTF("treat RESTORE command\n");
1895   - /* Drives position */
1896   - drv0(fdctrl)->track = fdctrl->fifo[3];
1897   - drv1(fdctrl)->track = fdctrl->fifo[4];
1898   - /* timers */
1899   - fdctrl->timer0 = fdctrl->fifo[7];
1900   - fdctrl->timer1 = fdctrl->fifo[8];
1901   - cur_drv->last_sect = fdctrl->fifo[9];
1902   - fdctrl->lock = fdctrl->fifo[10] >> 7;
1903   - cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1904   - fdctrl->config = fdctrl->fifo[11];
1905   - fdctrl->precomp_trk = fdctrl->fifo[12];
1906   - fdctrl->pwrd = fdctrl->fifo[13];
1907   - fdctrl_reset_fifo(fdctrl);
1908   - break;
1909   - case FD_CMD_FORMAT_TRACK:
1910   - /* FORMAT_TRACK */
1911   - FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
1912   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1913   - cur_drv = get_cur_drv(fdctrl);
1914   - fdctrl->data_state |= FD_STATE_FORMAT;
1915   - if (fdctrl->fifo[0] & 0x80)
1916   - fdctrl->data_state |= FD_STATE_MULTI;
1917   - else
1918   - fdctrl->data_state &= ~FD_STATE_MULTI;
1919   - fdctrl->data_state &= ~FD_STATE_SEEK;
1920   - cur_drv->bps =
1921   - fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1922   -#if 0
1923   - cur_drv->last_sect =
1924   - cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1925   - fdctrl->fifo[3] / 2;
1926   -#else
1927   - cur_drv->last_sect = fdctrl->fifo[3];
1928   -#endif
1929   - /* TODO: implement format using DMA expected by the Bochs BIOS
1930   - * and Linux fdformat (read 3 bytes per sector via DMA and fill
1931   - * the sector with the specified fill byte
1932   - */
1933   - fdctrl->data_state &= ~FD_STATE_FORMAT;
1934   - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1935   - break;
1936   - case FD_CMD_DRIVE_SPECIFICATION_COMMAND:
1937   - /* DRIVE_SPECIFICATION_COMMAND */
1938   - FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
1939   - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1940   - /* Command parameters done */
1941   - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1942   - fdctrl->fifo[0] = fdctrl->fifo[1];
1943   - fdctrl->fifo[2] = 0;
1944   - fdctrl->fifo[3] = 0;
1945   - fdctrl_set_fifo(fdctrl, 4, 1);
1946   - } else {
1947   - fdctrl_reset_fifo(fdctrl);
1948   - }
1949   - } else if (fdctrl->data_len > 7) {
1950   - /* ERROR */
1951   - fdctrl->fifo[0] = 0x80 |
1952   - (cur_drv->head << 2) | fdctrl->cur_drv;
1953   - fdctrl_set_fifo(fdctrl, 1, 1);
1954   - }
1955   - break;
1956   - case FD_CMD_RELATIVE_SEEK_OUT:
1957   - /* RELATIVE_SEEK_OUT */
1958   - FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
1959   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1960   - cur_drv = get_cur_drv(fdctrl);
1961   - fd_start(cur_drv);
1962   - cur_drv->dir = 0;
1963   - if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1964   - cur_drv->track = cur_drv->max_track - 1;
1965   - } else {
1966   - cur_drv->track += fdctrl->fifo[2];
1967   - }
1968   - fdctrl_reset_fifo(fdctrl);
1969   - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1970   - break;
1971   - case FD_CMD_FORMAT_AND_WRITE:
1972   - /* FORMAT_AND_WRITE */
1973   - FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
1974   - FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
1975   - fdctrl_unimplemented(fdctrl);
1976   - break;
1977   - case FD_CMD_RELATIVE_SEEK_IN:
1978   - /* RELATIVE_SEEK_IN */
1979   - FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
1980   - fdctrl->cur_drv = fdctrl->fifo[1] & FD_DOR_SELMASK;
1981   - cur_drv = get_cur_drv(fdctrl);
1982   - fd_start(cur_drv);
1983   - cur_drv->dir = 1;
1984   - if (fdctrl->fifo[2] > cur_drv->track) {
1985   - cur_drv->track = 0;
1986   - } else {
1987   - cur_drv->track -= fdctrl->fifo[2];
  1830 +
  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;
1988 1836 }
1989   - fdctrl_reset_fifo(fdctrl);
1990   - /* Raise Interrupt */
1991   - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1992   - break;
1993 1837 }
1994 1838 }
1995 1839 }
... ...