Commit ab17b46d00f21a3c2fcbe4d0f8894372e79528fa

Authored by balrog
1 parent c580d92b

Correct audio api usage in OMAP EAC (spotted by malc).

This is to improve the usage of audio API thanks to explanation from malc.
Functionally may not be better.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4969 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 79 additions and 31 deletions
hw/omap2.c
... ... @@ -1447,6 +1447,7 @@ struct omap_eac_s {
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,7 +1479,7 @@ static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
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,26 +1491,61 @@ static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
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,8 +1553,9 @@ 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,10 +1563,10 @@ 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,7 +1628,9 @@ static void omap_eac_format_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,10 +1638,14 @@ static void omap_eac_format_update(struct omap_eac_s *s)
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,6 +1706,7 @@ static void omap_eac_reset(struct omap_eac_s *s)
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,6 +1720,7 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
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,16 +1784,19 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
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,8 +1929,8 @@ static void omap_eac_write(void *opaque, target_phys_addr_t addr,
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  
... ...