1393
1269
if (cur_drv->bs == NULL ||
1394
1270
bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1395
1271
FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
1396
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
1398
if (cur_drv->sect == cur_drv->last_sect) {
1399
fdctrl->data_state &= ~FD_STATE_FORMAT;
1400
/* Last sector done */
1401
if (FD_DID_SEEK(fdctrl->data_state))
1402
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1404
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1407
fdctrl->data_pos = 0;
1408
fdctrl->data_len = 4;
1413
static void fdctrl_handle_lock (fdctrl_t *fdctrl, int direction)
1415
fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
1416
fdctrl->fifo[0] = fdctrl->lock << 4;
1417
fdctrl_set_fifo(fdctrl, 1, fdctrl->lock);
1420
static void fdctrl_handle_dumpreg (fdctrl_t *fdctrl, int direction)
1422
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1424
/* Drives position */
1425
fdctrl->fifo[0] = drv0(fdctrl)->track;
1426
fdctrl->fifo[1] = drv1(fdctrl)->track;
1428
fdctrl->fifo[2] = drv2(fdctrl)->track;
1429
fdctrl->fifo[3] = drv3(fdctrl)->track;
1431
fdctrl->fifo[2] = 0;
1432
fdctrl->fifo[3] = 0;
1435
fdctrl->fifo[4] = fdctrl->timer0;
1436
fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
1437
fdctrl->fifo[6] = cur_drv->last_sect;
1438
fdctrl->fifo[7] = (fdctrl->lock << 7) |
1439
(cur_drv->perpendicular << 2);
1440
fdctrl->fifo[8] = fdctrl->config;
1441
fdctrl->fifo[9] = fdctrl->precomp_trk;
1442
fdctrl_set_fifo(fdctrl, 10, 0);
1445
static void fdctrl_handle_version (fdctrl_t *fdctrl, int direction)
1447
/* Controller's version */
1448
fdctrl->fifo[0] = fdctrl->version;
1449
fdctrl_set_fifo(fdctrl, 1, 1);
1452
static void fdctrl_handle_partid (fdctrl_t *fdctrl, int direction)
1454
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1455
fdctrl_set_fifo(fdctrl, 1, 0);
1458
static void fdctrl_handle_restore (fdctrl_t *fdctrl, int direction)
1460
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1462
/* Drives position */
1463
drv0(fdctrl)->track = fdctrl->fifo[3];
1464
drv1(fdctrl)->track = fdctrl->fifo[4];
1466
drv2(fdctrl)->track = fdctrl->fifo[5];
1467
drv3(fdctrl)->track = fdctrl->fifo[6];
1470
fdctrl->timer0 = fdctrl->fifo[7];
1471
fdctrl->timer1 = fdctrl->fifo[8];
1472
cur_drv->last_sect = fdctrl->fifo[9];
1473
fdctrl->lock = fdctrl->fifo[10] >> 7;
1474
cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1475
fdctrl->config = fdctrl->fifo[11];
1476
fdctrl->precomp_trk = fdctrl->fifo[12];
1477
fdctrl->pwrd = fdctrl->fifo[13];
1478
fdctrl_reset_fifo(fdctrl);
1481
static void fdctrl_handle_save (fdctrl_t *fdctrl, int direction)
1483
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1485
fdctrl->fifo[0] = 0;
1486
fdctrl->fifo[1] = 0;
1487
/* Drives position */
1488
fdctrl->fifo[2] = drv0(fdctrl)->track;
1489
fdctrl->fifo[3] = drv1(fdctrl)->track;
1491
fdctrl->fifo[4] = drv2(fdctrl)->track;
1492
fdctrl->fifo[5] = drv3(fdctrl)->track;
1494
fdctrl->fifo[4] = 0;
1495
fdctrl->fifo[5] = 0;
1498
fdctrl->fifo[6] = fdctrl->timer0;
1499
fdctrl->fifo[7] = fdctrl->timer1;
1500
fdctrl->fifo[8] = cur_drv->last_sect;
1501
fdctrl->fifo[9] = (fdctrl->lock << 7) |
1502
(cur_drv->perpendicular << 2);
1503
fdctrl->fifo[10] = fdctrl->config;
1504
fdctrl->fifo[11] = fdctrl->precomp_trk;
1505
fdctrl->fifo[12] = fdctrl->pwrd;
1506
fdctrl->fifo[13] = 0;
1507
fdctrl->fifo[14] = 0;
1508
fdctrl_set_fifo(fdctrl, 15, 1);
1511
static void fdctrl_handle_readid (fdctrl_t *fdctrl, int direction)
1513
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1515
/* XXX: should set main status register to busy */
1516
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1517
qemu_mod_timer(fdctrl->result_timer,
1518
qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1521
static void fdctrl_handle_format_track (fdctrl_t *fdctrl, int direction)
1525
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1526
cur_drv = get_cur_drv(fdctrl);
1527
fdctrl->data_state |= FD_STATE_FORMAT;
1528
if (fdctrl->fifo[0] & 0x80)
1529
fdctrl->data_state |= FD_STATE_MULTI;
1531
fdctrl->data_state &= ~FD_STATE_MULTI;
1532
fdctrl->data_state &= ~FD_STATE_SEEK;
1534
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1536
cur_drv->last_sect =
1537
cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1538
fdctrl->fifo[3] / 2;
1540
cur_drv->last_sect = fdctrl->fifo[3];
1542
/* TODO: implement format using DMA expected by the Bochs BIOS
1543
* and Linux fdformat (read 3 bytes per sector via DMA and fill
1544
* the sector with the specified fill byte
1546
fdctrl->data_state &= ~FD_STATE_FORMAT;
1547
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1550
static void fdctrl_handle_specify (fdctrl_t *fdctrl, int direction)
1552
fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1553
fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1554
if (fdctrl->fifo[2] & 1)
1555
fdctrl->dor &= ~FD_DOR_DMAEN;
1557
fdctrl->dor |= FD_DOR_DMAEN;
1558
/* No result back */
1559
fdctrl_reset_fifo(fdctrl);
1562
static void fdctrl_handle_sense_drive_status (fdctrl_t *fdctrl, int direction)
1566
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1567
cur_drv = get_cur_drv(fdctrl);
1568
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1569
/* 1 Byte status back */
1570
fdctrl->fifo[0] = (cur_drv->ro << 6) |
1571
(cur_drv->track == 0 ? 0x10 : 0x00) |
1572
(cur_drv->head << 2) |
1573
GET_CUR_DRV(fdctrl) |
1575
fdctrl_set_fifo(fdctrl, 1, 0);
1578
static void fdctrl_handle_recalibrate (fdctrl_t *fdctrl, int direction)
1582
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1583
cur_drv = get_cur_drv(fdctrl);
1584
fd_recalibrate(cur_drv);
1585
fdctrl_reset_fifo(fdctrl);
1586
/* Raise Interrupt */
1587
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1590
static void fdctrl_handle_sense_interrupt_status (fdctrl_t *fdctrl, int direction)
1592
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1596
fdctrl->status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1598
/* XXX: status0 handling is broken for read/write
1599
commands, so we do this hack. It should be suppressed
1602
FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1604
fdctrl->fifo[1] = cur_drv->track;
1605
fdctrl_set_fifo(fdctrl, 2, 0);
1606
fdctrl_reset_irq(fdctrl);
1607
fdctrl->status0 = FD_SR0_RDYCHG;
1610
static void fdctrl_handle_seek (fdctrl_t *fdctrl, int direction)
1614
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1615
cur_drv = get_cur_drv(fdctrl);
1616
fdctrl_reset_fifo(fdctrl);
1617
if (fdctrl->fifo[2] > cur_drv->max_track) {
1618
fdctrl_raise_irq(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK);
1620
cur_drv->track = fdctrl->fifo[2];
1621
/* Raise Interrupt */
1622
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1626
static void fdctrl_handle_perpendicular_mode (fdctrl_t *fdctrl, int direction)
1628
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1630
if (fdctrl->fifo[1] & 0x80)
1631
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1632
/* No result back */
1633
fdctrl_reset_fifo(fdctrl);
1636
static void fdctrl_handle_configure (fdctrl_t *fdctrl, int direction)
1638
fdctrl->config = fdctrl->fifo[2];
1639
fdctrl->precomp_trk = fdctrl->fifo[3];
1640
/* No result back */
1641
fdctrl_reset_fifo(fdctrl);
1644
static void fdctrl_handle_powerdown_mode (fdctrl_t *fdctrl, int direction)
1646
fdctrl->pwrd = fdctrl->fifo[1];
1647
fdctrl->fifo[0] = fdctrl->fifo[1];
1648
fdctrl_set_fifo(fdctrl, 1, 1);
1651
static void fdctrl_handle_option (fdctrl_t *fdctrl, int direction)
1653
/* No result back */
1654
fdctrl_reset_fifo(fdctrl);
1657
static void fdctrl_handle_drive_specification_command (fdctrl_t *fdctrl, int direction)
1659
fdrive_t *cur_drv = get_cur_drv(fdctrl);
1661
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1662
/* Command parameters done */
1663
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1664
fdctrl->fifo[0] = fdctrl->fifo[1];
1665
fdctrl->fifo[2] = 0;
1666
fdctrl->fifo[3] = 0;
1667
fdctrl_set_fifo(fdctrl, 4, 1);
1669
fdctrl_reset_fifo(fdctrl);
1671
} else if (fdctrl->data_len > 7) {
1673
fdctrl->fifo[0] = 0x80 |
1674
(cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
1675
fdctrl_set_fifo(fdctrl, 1, 1);
1679
static void fdctrl_handle_relative_seek_out (fdctrl_t *fdctrl, int direction)
1683
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1684
cur_drv = get_cur_drv(fdctrl);
1685
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1686
cur_drv->track = cur_drv->max_track - 1;
1688
cur_drv->track += fdctrl->fifo[2];
1690
fdctrl_reset_fifo(fdctrl);
1691
/* Raise Interrupt */
1692
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1695
static void fdctrl_handle_relative_seek_in (fdctrl_t *fdctrl, int direction)
1699
SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
1700
cur_drv = get_cur_drv(fdctrl);
1701
if (fdctrl->fifo[2] > cur_drv->track) {
1704
cur_drv->track -= fdctrl->fifo[2];
1706
fdctrl_reset_fifo(fdctrl);
1707
/* Raise Interrupt */
1708
fdctrl_raise_irq(fdctrl, FD_SR0_SEEK);
1711
static const struct {
1716
void (*handler)(fdctrl_t *fdctrl, int direction);
1719
{ FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
1720
{ FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
1721
{ FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
1722
{ FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
1723
{ FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
1724
{ FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
1725
{ FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
1726
{ FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
1727
{ FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
1728
{ FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
1729
{ FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
1730
{ FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented },
1731
{ FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
1732
{ FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
1733
{ FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
1734
{ FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
1735
{ FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
1736
{ FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
1737
{ FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
1738
{ FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
1739
{ FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
1740
{ FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
1741
{ FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
1742
{ FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
1743
{ FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
1744
{ FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
1745
{ FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
1746
{ FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
1747
{ FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
1748
{ FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
1749
{ FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
1750
{ 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
1752
/* Associate command to an index in the 'handlers' array */
1753
static uint8_t command_to_handler[256];
1272
fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
1274
if (cur_drv->sect == cur_drv->last_sect) {
1275
fdctrl->data_state &= ~FD_STATE_FORMAT;
1276
/* Last sector done */
1277
if (FD_DID_SEEK(fdctrl->data_state))
1278
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1280
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1283
fdctrl->data_pos = 0;
1284
fdctrl->data_len = 4;
1755
1289
static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
1757
1291
fdrive_t *cur_drv;
1293
cur_drv = get_cur_drv(fdctrl);
1760
1294
/* Reset mode */
1761
if (!(fdctrl->dor & FD_DOR_nRESET)) {
1295
if (fdctrl->state & FD_CTRL_RESET) {
1762
1296
FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
1765
if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
1766
FLOPPY_ERROR("controller not ready for writing\n");
1299
fdctrl->state &= ~FD_CTRL_SLEEP;
1300
if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
1301
FLOPPY_ERROR("can't write data in status mode\n");
1769
fdctrl->dsr &= ~FD_DSR_PWRDOWN;
1770
1304
/* Is it write command time ? */
1771
if (fdctrl->msr & FD_MSR_NONDMA) {
1305
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
1772
1306
/* FIFO data write */
1773
pos = fdctrl->data_pos++;
1774
pos %= FD_SECTOR_LEN;
1775
fdctrl->fifo[pos] = value;
1776
if (pos == FD_SECTOR_LEN - 1 ||
1307
fdctrl->fifo[fdctrl->data_pos++] = value;
1308
if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
1777
1309
fdctrl->data_pos == fdctrl->data_len) {
1778
cur_drv = get_cur_drv(fdctrl);
1779
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
1780
FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
1783
if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
1784
FLOPPY_DPRINTF("error seeking to next sector %d\n",
1785
fd_sector(cur_drv));
1310
bdrv_write(cur_drv->bs, fd_sector(cur_drv),
1311
fdctrl->fifo, FD_SECTOR_LEN);
1789
1313
/* Switch from transfer mode to status mode
1790
1314
* then from status mode to command mode
1792
if (fdctrl->data_pos == fdctrl->data_len)
1793
fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00);
1316
if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
1317
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1796
1320
if (fdctrl->data_pos == 0) {
1798
pos = command_to_handler[value & 0xff];
1799
FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
1800
fdctrl->data_len = handlers[pos].parameters + 1;
1322
switch (value & 0x5F) {
1325
FLOPPY_DPRINTF("READ command\n");
1326
/* 8 parameters cmd */
1327
fdctrl->data_len = 9;
1330
/* READ_DELETED variants */
1331
FLOPPY_DPRINTF("READ_DELETED command\n");
1332
/* 8 parameters cmd */
1333
fdctrl->data_len = 9;
1336
/* SCAN_EQUAL variants */
1337
FLOPPY_DPRINTF("SCAN_EQUAL command\n");
1338
/* 8 parameters cmd */
1339
fdctrl->data_len = 9;
1342
/* VERIFY variants */
1343
FLOPPY_DPRINTF("VERIFY command\n");
1344
/* 8 parameters cmd */
1345
fdctrl->data_len = 9;
1348
/* SCAN_LOW_OR_EQUAL variants */
1349
FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
1350
/* 8 parameters cmd */
1351
fdctrl->data_len = 9;
1354
/* SCAN_HIGH_OR_EQUAL variants */
1355
FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
1356
/* 8 parameters cmd */
1357
fdctrl->data_len = 9;
1362
switch (value & 0x7F) {
1364
/* WRITE variants */
1365
FLOPPY_DPRINTF("WRITE command\n");
1366
/* 8 parameters cmd */
1367
fdctrl->data_len = 9;
1370
/* WRITE_DELETED variants */
1371
FLOPPY_DPRINTF("WRITE_DELETED command\n");
1372
/* 8 parameters cmd */
1373
fdctrl->data_len = 9;
1381
FLOPPY_DPRINTF("SPECIFY command\n");
1382
/* 1 parameter cmd */
1383
fdctrl->data_len = 3;
1386
/* SENSE_DRIVE_STATUS */
1387
FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
1388
/* 1 parameter cmd */
1389
fdctrl->data_len = 2;
1393
FLOPPY_DPRINTF("RECALIBRATE command\n");
1394
/* 1 parameter cmd */
1395
fdctrl->data_len = 2;
1398
/* SENSE_INTERRUPT_STATUS */
1399
FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
1400
fdctrl->int_status);
1401
/* No parameters cmd: returns status if no interrupt */
1404
fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
1406
/* XXX: int_status handling is broken for read/write
1407
commands, so we do this hack. It should be suppressed
1410
0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
1412
fdctrl->fifo[1] = cur_drv->track;
1413
fdctrl_set_fifo(fdctrl, 2, 0);
1414
fdctrl_reset_irq(fdctrl);
1415
fdctrl->int_status = 0xC0;
1419
FLOPPY_DPRINTF("DUMPREG command\n");
1420
/* Drives position */
1421
fdctrl->fifo[0] = drv0(fdctrl)->track;
1422
fdctrl->fifo[1] = drv1(fdctrl)->track;
1423
fdctrl->fifo[2] = 0;
1424
fdctrl->fifo[3] = 0;
1426
fdctrl->fifo[4] = fdctrl->timer0;
1427
fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
1428
fdctrl->fifo[6] = cur_drv->last_sect;
1429
fdctrl->fifo[7] = (fdctrl->lock << 7) |
1430
(cur_drv->perpendicular << 2);
1431
fdctrl->fifo[8] = fdctrl->config;
1432
fdctrl->fifo[9] = fdctrl->precomp_trk;
1433
fdctrl_set_fifo(fdctrl, 10, 0);
1437
FLOPPY_DPRINTF("SEEK command\n");
1438
/* 2 parameters cmd */
1439
fdctrl->data_len = 3;
1443
FLOPPY_DPRINTF("VERSION command\n");
1444
/* No parameters cmd */
1445
/* Controller's version */
1446
fdctrl->fifo[0] = fdctrl->version;
1447
fdctrl_set_fifo(fdctrl, 1, 1);
1450
/* PERPENDICULAR_MODE */
1451
FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
1452
/* 1 parameter cmd */
1453
fdctrl->data_len = 2;
1457
FLOPPY_DPRINTF("CONFIGURE command\n");
1458
/* 3 parameters cmd */
1459
fdctrl->data_len = 4;
1463
FLOPPY_DPRINTF("UNLOCK command\n");
1464
/* No parameters cmd */
1466
fdctrl->fifo[0] = 0;
1467
fdctrl_set_fifo(fdctrl, 1, 0);
1470
/* POWERDOWN_MODE */
1471
FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
1472
/* 2 parameters cmd */
1473
fdctrl->data_len = 3;
1477
FLOPPY_DPRINTF("PART_ID command\n");
1478
/* No parameters cmd */
1479
fdctrl->fifo[0] = 0x41; /* Stepping 1 */
1480
fdctrl_set_fifo(fdctrl, 1, 0);
1484
FLOPPY_DPRINTF("SAVE command\n");
1485
/* No parameters cmd */
1486
fdctrl->fifo[0] = 0;
1487
fdctrl->fifo[1] = 0;
1488
/* Drives position */
1489
fdctrl->fifo[2] = drv0(fdctrl)->track;
1490
fdctrl->fifo[3] = drv1(fdctrl)->track;
1491
fdctrl->fifo[4] = 0;
1492
fdctrl->fifo[5] = 0;
1494
fdctrl->fifo[6] = fdctrl->timer0;
1495
fdctrl->fifo[7] = fdctrl->timer1;
1496
fdctrl->fifo[8] = cur_drv->last_sect;
1497
fdctrl->fifo[9] = (fdctrl->lock << 7) |
1498
(cur_drv->perpendicular << 2);
1499
fdctrl->fifo[10] = fdctrl->config;
1500
fdctrl->fifo[11] = fdctrl->precomp_trk;
1501
fdctrl->fifo[12] = fdctrl->pwrd;
1502
fdctrl->fifo[13] = 0;
1503
fdctrl->fifo[14] = 0;
1504
fdctrl_set_fifo(fdctrl, 15, 1);
1508
FLOPPY_DPRINTF("OPTION command\n");
1509
/* 1 parameter cmd */
1510
fdctrl->data_len = 2;
1514
FLOPPY_DPRINTF("READ_TRACK command\n");
1515
/* 8 parameters cmd */
1516
fdctrl->data_len = 9;
1520
FLOPPY_DPRINTF("READ_ID command\n");
1521
/* 1 parameter cmd */
1522
fdctrl->data_len = 2;
1526
FLOPPY_DPRINTF("RESTORE command\n");
1527
/* 17 parameters cmd */
1528
fdctrl->data_len = 18;
1532
FLOPPY_DPRINTF("FORMAT_TRACK command\n");
1533
/* 5 parameters cmd */
1534
fdctrl->data_len = 6;
1537
/* DRIVE_SPECIFICATION_COMMAND */
1538
FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
1539
/* 5 parameters cmd */
1540
fdctrl->data_len = 6;
1543
/* RELATIVE_SEEK_OUT */
1544
FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
1545
/* 2 parameters cmd */
1546
fdctrl->data_len = 3;
1550
FLOPPY_DPRINTF("LOCK command\n");
1551
/* No parameters cmd */
1553
fdctrl->fifo[0] = 0x10;
1554
fdctrl_set_fifo(fdctrl, 1, 1);
1557
/* FORMAT_AND_WRITE */
1558
FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
1559
/* 10 parameters cmd */
1560
fdctrl->data_len = 11;
1563
/* RELATIVE_SEEK_IN */
1564
FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
1565
/* 2 parameters cmd */
1566
fdctrl->data_len = 3;
1569
/* Unknown command */
1570
FLOPPY_ERROR("unknown command: 0x%02x\n", value);
1571
fdctrl_unimplemented(fdctrl);
1803
1576
FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
1804
fdctrl->fifo[fdctrl->data_pos++] = value;
1805
if (fdctrl->data_pos == fdctrl->data_len) {
1577
fdctrl->fifo[fdctrl->data_pos] = value;
1578
if (++fdctrl->data_pos == fdctrl->data_len) {
1806
1579
/* We now have all parameters
1807
1580
* and will be able to treat the command
1809
if (fdctrl->data_state & FD_STATE_FORMAT) {
1810
fdctrl_format_sector(fdctrl);
1814
pos = command_to_handler[fdctrl->fifo[0] & 0xff];
1815
FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
1816
(*handlers[pos].handler)(fdctrl, handlers[pos].direction);
1582
if (fdctrl->data_state & FD_STATE_FORMAT) {
1583
fdctrl_format_sector(fdctrl);
1586
switch (fdctrl->fifo[0] & 0x1F) {
1590
FLOPPY_DPRINTF("treat READ command\n");
1591
fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1595
/* READ_DELETED variants */
1596
// FLOPPY_DPRINTF("treat READ_DELETED command\n");
1597
FLOPPY_ERROR("treat READ_DELETED command\n");
1598
fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
1601
/* VERIFY variants */
1602
// FLOPPY_DPRINTF("treat VERIFY command\n");
1603
FLOPPY_ERROR("treat VERIFY command\n");
1604
fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
1607
/* SCAN_EQUAL variants */
1608
// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
1609
FLOPPY_ERROR("treat SCAN_EQUAL command\n");
1610
fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
1613
/* SCAN_LOW_OR_EQUAL variants */
1614
// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
1615
FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
1616
fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
1619
/* SCAN_HIGH_OR_EQUAL variants */
1620
// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
1621
FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
1622
fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
1627
switch (fdctrl->fifo[0] & 0x3F) {
1629
/* WRITE variants */
1630
FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
1631
fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
1634
/* WRITE_DELETED variants */
1635
// FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
1636
FLOPPY_ERROR("treat WRITE_DELETED command\n");
1637
fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
1642
switch (fdctrl->fifo[0]) {
1645
FLOPPY_DPRINTF("treat SPECIFY command\n");
1646
fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
1647
fdctrl->timer1 = fdctrl->fifo[2] >> 1;
1648
fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
1649
/* No result back */
1650
fdctrl_reset_fifo(fdctrl);
1653
/* SENSE_DRIVE_STATUS */
1654
FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
1655
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1656
cur_drv = get_cur_drv(fdctrl);
1657
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1658
/* 1 Byte status back */
1659
fdctrl->fifo[0] = (cur_drv->ro << 6) |
1660
(cur_drv->track == 0 ? 0x10 : 0x00) |
1661
(cur_drv->head << 2) |
1664
fdctrl_set_fifo(fdctrl, 1, 0);
1668
FLOPPY_DPRINTF("treat RECALIBRATE command\n");
1669
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1670
cur_drv = get_cur_drv(fdctrl);
1671
fd_recalibrate(cur_drv);
1672
fdctrl_reset_fifo(fdctrl);
1673
/* Raise Interrupt */
1674
fdctrl_raise_irq(fdctrl, 0x20);
1678
FLOPPY_DPRINTF("treat SEEK command\n");
1679
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1680
cur_drv = get_cur_drv(fdctrl);
1682
if (fdctrl->fifo[2] <= cur_drv->track)
1686
fdctrl_reset_fifo(fdctrl);
1687
if (fdctrl->fifo[2] > cur_drv->max_track) {
1688
fdctrl_raise_irq(fdctrl, 0x60);
1690
cur_drv->track = fdctrl->fifo[2];
1691
/* Raise Interrupt */
1692
fdctrl_raise_irq(fdctrl, 0x20);
1696
/* PERPENDICULAR_MODE */
1697
FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
1698
if (fdctrl->fifo[1] & 0x80)
1699
cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
1700
/* No result back */
1701
fdctrl_reset_fifo(fdctrl);
1705
FLOPPY_DPRINTF("treat CONFIGURE command\n");
1706
fdctrl->config = fdctrl->fifo[2];
1707
fdctrl->precomp_trk = fdctrl->fifo[3];
1708
/* No result back */
1709
fdctrl_reset_fifo(fdctrl);
1712
/* POWERDOWN_MODE */
1713
FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
1714
fdctrl->pwrd = fdctrl->fifo[1];
1715
fdctrl->fifo[0] = fdctrl->fifo[1];
1716
fdctrl_set_fifo(fdctrl, 1, 1);
1720
FLOPPY_DPRINTF("treat OPTION command\n");
1721
/* No result back */
1722
fdctrl_reset_fifo(fdctrl);
1726
// FLOPPY_DPRINTF("treat READ_TRACK command\n");
1727
FLOPPY_ERROR("treat READ_TRACK command\n");
1728
fdctrl_start_transfer(fdctrl, FD_DIR_READ);
1732
FLOPPY_DPRINTF("treat READ_ID command\n");
1733
/* XXX: should set main status register to busy */
1734
cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
1735
qemu_mod_timer(fdctrl->result_timer,
1736
qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
1740
FLOPPY_DPRINTF("treat RESTORE command\n");
1741
/* Drives position */
1742
drv0(fdctrl)->track = fdctrl->fifo[3];
1743
drv1(fdctrl)->track = fdctrl->fifo[4];
1745
fdctrl->timer0 = fdctrl->fifo[7];
1746
fdctrl->timer1 = fdctrl->fifo[8];
1747
cur_drv->last_sect = fdctrl->fifo[9];
1748
fdctrl->lock = fdctrl->fifo[10] >> 7;
1749
cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
1750
fdctrl->config = fdctrl->fifo[11];
1751
fdctrl->precomp_trk = fdctrl->fifo[12];
1752
fdctrl->pwrd = fdctrl->fifo[13];
1753
fdctrl_reset_fifo(fdctrl);
1757
FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
1758
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1759
cur_drv = get_cur_drv(fdctrl);
1760
fdctrl->data_state |= FD_STATE_FORMAT;
1761
if (fdctrl->fifo[0] & 0x80)
1762
fdctrl->data_state |= FD_STATE_MULTI;
1764
fdctrl->data_state &= ~FD_STATE_MULTI;
1765
fdctrl->data_state &= ~FD_STATE_SEEK;
1767
fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
1769
cur_drv->last_sect =
1770
cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
1771
fdctrl->fifo[3] / 2;
1773
cur_drv->last_sect = fdctrl->fifo[3];
1775
/* TODO: implement format using DMA expected by the Bochs BIOS
1776
* and Linux fdformat (read 3 bytes per sector via DMA and fill
1777
* the sector with the specified fill byte
1779
fdctrl->data_state &= ~FD_STATE_FORMAT;
1780
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
1783
/* DRIVE_SPECIFICATION_COMMAND */
1784
FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
1785
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
1786
/* Command parameters done */
1787
if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
1788
fdctrl->fifo[0] = fdctrl->fifo[1];
1789
fdctrl->fifo[2] = 0;
1790
fdctrl->fifo[3] = 0;
1791
fdctrl_set_fifo(fdctrl, 4, 1);
1793
fdctrl_reset_fifo(fdctrl);
1795
} else if (fdctrl->data_len > 7) {
1797
fdctrl->fifo[0] = 0x80 |
1798
(cur_drv->head << 2) | fdctrl->cur_drv;
1799
fdctrl_set_fifo(fdctrl, 1, 1);
1803
/* RELATIVE_SEEK_OUT */
1804
FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
1805
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1806
cur_drv = get_cur_drv(fdctrl);
1809
if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
1810
cur_drv->track = cur_drv->max_track - 1;
1812
cur_drv->track += fdctrl->fifo[2];
1814
fdctrl_reset_fifo(fdctrl);
1815
fdctrl_raise_irq(fdctrl, 0x20);
1818
/* FORMAT_AND_WRITE */
1819
// FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
1820
FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
1821
fdctrl_unimplemented(fdctrl);
1824
/* RELATIVE_SEEK_IN */
1825
FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
1826
fdctrl->cur_drv = fdctrl->fifo[1] & 1;
1827
cur_drv = get_cur_drv(fdctrl);
1830
if (fdctrl->fifo[2] > cur_drv->track) {
1833
cur_drv->track -= fdctrl->fifo[2];
1835
fdctrl_reset_fifo(fdctrl);
1836
/* Raise Interrupt */
1837
fdctrl_raise_irq(fdctrl, 0x20);