Revision ab17b46d
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