Revision ab17b46d hw/omap2.c

b/hw/omap2.c
1447 1447

  
1448 1448
#define EAC_BUF_LEN 1024
1449 1449
        uint32_t rxbuf[EAC_BUF_LEN];
1450
        int rxoff;
1450 1451
        int rxlen;
1451 1452
        int rxavail;
1452 1453
        uint32_t txbuf[EAC_BUF_LEN];
......
1478 1479

  
1479 1480
static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
1480 1481
{
1481
    qemu_set_irq(s->codec.rxdrq, s->codec.rxavail + s->codec.rxlen &&
1482
    qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
1482 1483
                    ((s->codec.config[1] >> 12) & 1));		/* DMAREN */
1483 1484
}
1484 1485

  
......
1490 1491

  
1491 1492
static inline void omap_eac_in_refill(struct omap_eac_s *s)
1492 1493
{
1493
    int left, start = 0;
1494

  
1495
    s->codec.rxlen = MIN(s->codec.rxavail, EAC_BUF_LEN);
1496
    s->codec.rxavail -= s->codec.rxlen;
1497

  
1498
    for (left = s->codec.rxlen << 2; left; start = (EAC_BUF_LEN << 2) - left)
1499
        left -= AUD_read(s->codec.in_voice,
1500
                        (uint8_t *) s->codec.rxbuf + start, left);
1494
    int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
1495
    int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
1496
    int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
1497
    int recv = 1;
1498
    uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
1499

  
1500
    left -= leftwrap;
1501
    start = 0;
1502
    while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
1503
                                    leftwrap)) > 0) {	/* Be defensive */
1504
        start += recv;
1505
        leftwrap -= recv;
1506
    }
1507
    if (recv <= 0)
1508
        s->codec.rxavail = 0;
1509
    else
1510
        s->codec.rxavail -= start >> 2;
1511
    s->codec.rxlen += start >> 2;
1512

  
1513
    if (recv > 0 && left > 0) {
1514
        start = 0;
1515
        while (left && (recv = AUD_read(s->codec.in_voice,
1516
                                        (uint8_t *) s->codec.rxbuf + start,
1517
                                        left)) > 0) {	/* Be defensive */
1518
            start += recv;
1519
            left -= recv;
1520
        }
1521
        if (recv <= 0)
1522
            s->codec.rxavail = 0;
1523
        else
1524
            s->codec.rxavail -= start >> 2;
1525
        s->codec.rxlen += start >> 2;
1526
    }
1501 1527
}
1502 1528

  
1503 1529
static inline void omap_eac_out_empty(struct omap_eac_s *s)
1504 1530
{
1505
    int left, start = 0;
1531
    int left = s->codec.txlen << 2;
1532
    int start = 0;
1533
    int sent = 1;
1534

  
1535
    while (left && (sent = AUD_write(s->codec.out_voice,
1536
                                    (uint8_t *) s->codec.txbuf + start,
1537
                                    left)) > 0) {	/* Be defensive */
1538
        start += sent;
1539
        left -= sent;
1540
    }
1506 1541

  
1507
    for (left = s->codec.txlen << 2; left; start = (s->codec.txlen << 2) - left)
1508
        left -= AUD_write(s->codec.out_voice,
1509
                        (uint8_t *) s->codec.txbuf + start, left);
1542
    if (!sent) {
1543
        s->codec.txavail = 0;
1544
        omap_eac_out_dmarequest_update(s);
1545
    }
1510 1546

  
1511
    s->codec.txavail -= s->codec.txlen;
1512
    s->codec.txlen = 0;
1547
    if (start)
1548
        s->codec.txlen = 0;
1513 1549
}
1514 1550

  
1515 1551
static void omap_eac_in_cb(void *opaque, int avail_b)
......
1517 1553
    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1518 1554

  
1519 1555
    s->codec.rxavail = avail_b >> 2;
1520
    omap_eac_in_dmarequest_update(s);
1556
    omap_eac_in_refill(s);
1521 1557
    /* TODO: possibly discard current buffer if overrun */
1558
    omap_eac_in_dmarequest_update(s);
1522 1559
}
1523 1560

  
1524 1561
static void omap_eac_out_cb(void *opaque, int free_b)
......
1526 1563
    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1527 1564

  
1528 1565
    s->codec.txavail = free_b >> 2;
1529
    if (s->codec.txlen > s->codec.txavail)
1530
        s->codec.txlen = s->codec.txavail;
1531
    omap_eac_out_empty(s);
1532
    omap_eac_out_dmarequest_update(s);
1566
    if (s->codec.txlen)
1567
        omap_eac_out_empty(s);
1568
    else
1569
        omap_eac_out_dmarequest_update(s);
1533 1570
}
1534 1571

  
1535 1572
static void omap_eac_enable_update(struct omap_eac_s *s)
......
1591 1628
{
1592 1629
    audsettings_t fmt;
1593 1630

  
1594
    omap_eac_out_empty(s);
1631
    /* The hardware buffers at most one sample */
1632
    if (s->codec.rxlen)
1633
        s->codec.rxlen = 1;
1595 1634

  
1596 1635
    if (s->codec.in_voice) {
1597 1636
        AUD_set_active_in(s->codec.in_voice, 0);
......
1599 1638
        s->codec.in_voice = 0;
1600 1639
    }
1601 1640
    if (s->codec.out_voice) {
1641
        omap_eac_out_empty(s);
1602 1642
        AUD_set_active_out(s->codec.out_voice, 0);
1603 1643
        AUD_close_out(&s->codec.card, s->codec.out_voice);
1604 1644
        s->codec.out_voice = 0;
1645
        s->codec.txavail = 0;
1605 1646
    }
1647
    /* Discard what couldn't be written */
1648
    s->codec.txlen = 0;
1606 1649

  
1607 1650
    omap_eac_enable_update(s);
1608 1651
    if (!s->codec.enable)
......
1663 1706
    s->codec.config[1] = 0x0000;
1664 1707
    s->codec.config[2] = 0x0007;
1665 1708
    s->codec.config[3] = 0x1ffc;
1709
    s->codec.rxoff = 0;
1666 1710
    s->codec.rxlen = 0;
1667 1711
    s->codec.txlen = 0;
1668 1712
    s->codec.rxavail = 0;
......
1676 1720
{
1677 1721
    struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1678 1722
    int offset = addr - s->base;
1723
    uint32_t ret;
1679 1724

  
1680 1725
    switch (offset) {
1681 1726
    case 0x000:	/* CPCFR1 */
......
1739 1784
        /* This should be write-only?  Docs list it as read-only.  */
1740 1785
        return 0x0000;
1741 1786
    case 0x0b8:	/* ADRDR */
1742
        if (likely(s->codec.rxlen > 1))
1743
            return s->codec.rxbuf[EAC_BUF_LEN - s->codec.rxlen --];
1744
        else if (s->codec.rxlen) {
1787
        if (likely(s->codec.rxlen > 1)) {
1788
            ret = s->codec.rxbuf[s->codec.rxoff ++];
1789
            s->codec.rxlen --;
1790
            s->codec.rxoff &= EAC_BUF_LEN - 1;
1791
            return ret;
1792
        } else if (s->codec.rxlen) {
1793
            ret = s->codec.rxbuf[s->codec.rxoff ++];
1794
            s->codec.rxlen --;
1795
            s->codec.rxoff &= EAC_BUF_LEN - 1;
1745 1796
            if (s->codec.rxavail)
1746 1797
                omap_eac_in_refill(s);
1747
            else {
1748
                s->codec.rxlen = 0;
1749
                omap_eac_in_dmarequest_update(s);
1750
            }
1751
            return s->codec.rxbuf[EAC_BUF_LEN - 1];
1798
            omap_eac_in_dmarequest_update(s);
1799
            return ret;
1752 1800
        }
1753 1801
        return 0x0000;
1754 1802
    case 0x0bc:	/* AGCFR */
......
1881 1929
                                s->codec.txlen == s->codec.txavail)) {
1882 1930
            if (s->codec.txavail)
1883 1931
                omap_eac_out_empty(s);
1884
            else
1885
                s->codec.txlen = 0;
1932
            /* Discard what couldn't be written */
1933
            s->codec.txlen = 0;
1886 1934
        }
1887 1935
        break;
1888 1936

  

Also available in: Unified diff