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,6 +1447,7 @@ struct omap_eac_s {
1447 1447
1448 #define EAC_BUF_LEN 1024 1448 #define EAC_BUF_LEN 1024
1449 uint32_t rxbuf[EAC_BUF_LEN]; 1449 uint32_t rxbuf[EAC_BUF_LEN];
  1450 + int rxoff;
1450 int rxlen; 1451 int rxlen;
1451 int rxavail; 1452 int rxavail;
1452 uint32_t txbuf[EAC_BUF_LEN]; 1453 uint32_t txbuf[EAC_BUF_LEN];
@@ -1478,7 +1479,7 @@ static inline void omap_eac_interrupt_update(struct omap_eac_s *s) @@ -1478,7 +1479,7 @@ static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
1478 1479
1479 static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s) 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 ((s->codec.config[1] >> 12) & 1)); /* DMAREN */ 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,26 +1491,61 @@ static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
1490 1491
1491 static inline void omap_eac_in_refill(struct omap_eac_s *s) 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 static inline void omap_eac_out_empty(struct omap_eac_s *s) 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 static void omap_eac_in_cb(void *opaque, int avail_b) 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,8 +1553,9 @@ static void omap_eac_in_cb(void *opaque, int avail_b)
1517 struct omap_eac_s *s = (struct omap_eac_s *) opaque; 1553 struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1518 1554
1519 s->codec.rxavail = avail_b >> 2; 1555 s->codec.rxavail = avail_b >> 2;
1520 - omap_eac_in_dmarequest_update(s); 1556 + omap_eac_in_refill(s);
1521 /* TODO: possibly discard current buffer if overrun */ 1557 /* TODO: possibly discard current buffer if overrun */
  1558 + omap_eac_in_dmarequest_update(s);
1522 } 1559 }
1523 1560
1524 static void omap_eac_out_cb(void *opaque, int free_b) 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,10 +1563,10 @@ static void omap_eac_out_cb(void *opaque, int free_b)
1526 struct omap_eac_s *s = (struct omap_eac_s *) opaque; 1563 struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1527 1564
1528 s->codec.txavail = free_b >> 2; 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 static void omap_eac_enable_update(struct omap_eac_s *s) 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,7 +1628,9 @@ static void omap_eac_format_update(struct omap_eac_s *s)
1591 { 1628 {
1592 audsettings_t fmt; 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 if (s->codec.in_voice) { 1635 if (s->codec.in_voice) {
1597 AUD_set_active_in(s->codec.in_voice, 0); 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,10 +1638,14 @@ static void omap_eac_format_update(struct omap_eac_s *s)
1599 s->codec.in_voice = 0; 1638 s->codec.in_voice = 0;
1600 } 1639 }
1601 if (s->codec.out_voice) { 1640 if (s->codec.out_voice) {
  1641 + omap_eac_out_empty(s);
1602 AUD_set_active_out(s->codec.out_voice, 0); 1642 AUD_set_active_out(s->codec.out_voice, 0);
1603 AUD_close_out(&s->codec.card, s->codec.out_voice); 1643 AUD_close_out(&s->codec.card, s->codec.out_voice);
1604 s->codec.out_voice = 0; 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 omap_eac_enable_update(s); 1650 omap_eac_enable_update(s);
1608 if (!s->codec.enable) 1651 if (!s->codec.enable)
@@ -1663,6 +1706,7 @@ static void omap_eac_reset(struct omap_eac_s *s) @@ -1663,6 +1706,7 @@ static void omap_eac_reset(struct omap_eac_s *s)
1663 s->codec.config[1] = 0x0000; 1706 s->codec.config[1] = 0x0000;
1664 s->codec.config[2] = 0x0007; 1707 s->codec.config[2] = 0x0007;
1665 s->codec.config[3] = 0x1ffc; 1708 s->codec.config[3] = 0x1ffc;
  1709 + s->codec.rxoff = 0;
1666 s->codec.rxlen = 0; 1710 s->codec.rxlen = 0;
1667 s->codec.txlen = 0; 1711 s->codec.txlen = 0;
1668 s->codec.rxavail = 0; 1712 s->codec.rxavail = 0;
@@ -1676,6 +1720,7 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr) @@ -1676,6 +1720,7 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
1676 { 1720 {
1677 struct omap_eac_s *s = (struct omap_eac_s *) opaque; 1721 struct omap_eac_s *s = (struct omap_eac_s *) opaque;
1678 int offset = addr - s->base; 1722 int offset = addr - s->base;
  1723 + uint32_t ret;
1679 1724
1680 switch (offset) { 1725 switch (offset) {
1681 case 0x000: /* CPCFR1 */ 1726 case 0x000: /* CPCFR1 */
@@ -1739,16 +1784,19 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr) @@ -1739,16 +1784,19 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
1739 /* This should be write-only? Docs list it as read-only. */ 1784 /* This should be write-only? Docs list it as read-only. */
1740 return 0x0000; 1785 return 0x0000;
1741 case 0x0b8: /* ADRDR */ 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 if (s->codec.rxavail) 1796 if (s->codec.rxavail)
1746 omap_eac_in_refill(s); 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 return 0x0000; 1801 return 0x0000;
1754 case 0x0bc: /* AGCFR */ 1802 case 0x0bc: /* AGCFR */
@@ -1881,8 +1929,8 @@ static void omap_eac_write(void *opaque, target_phys_addr_t addr, @@ -1881,8 +1929,8 @@ static void omap_eac_write(void *opaque, target_phys_addr_t addr,
1881 s->codec.txlen == s->codec.txavail)) { 1929 s->codec.txlen == s->codec.txavail)) {
1882 if (s->codec.txavail) 1930 if (s->codec.txavail)
1883 omap_eac_out_empty(s); 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 break; 1935 break;
1888 1936