Commit 65cef780e2a637b0ae08ad759665241b9c1a8b0f
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 | } | ... | ... |