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
This commit is contained in:
balrog 2008-07-29 17:29:41 +00:00
parent c580d92b0e
commit ab17b46d00
1 changed files with 77 additions and 29 deletions

View File

@ -1447,6 +1447,7 @@ struct omap_eac_s {
#define EAC_BUF_LEN 1024
uint32_t rxbuf[EAC_BUF_LEN];
int rxoff;
int rxlen;
int rxavail;
uint32_t txbuf[EAC_BUF_LEN];
@ -1478,7 +1479,7 @@ static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
{
qemu_set_irq(s->codec.rxdrq, s->codec.rxavail + s->codec.rxlen &&
qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
((s->codec.config[1] >> 12) & 1)); /* DMAREN */
}
@ -1490,26 +1491,61 @@ static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
static inline void omap_eac_in_refill(struct omap_eac_s *s)
{
int left, start = 0;
int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
int recv = 1;
uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
s->codec.rxlen = MIN(s->codec.rxavail, EAC_BUF_LEN);
s->codec.rxavail -= s->codec.rxlen;
left -= leftwrap;
start = 0;
while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
leftwrap)) > 0) { /* Be defensive */
start += recv;
leftwrap -= recv;
}
if (recv <= 0)
s->codec.rxavail = 0;
else
s->codec.rxavail -= start >> 2;
s->codec.rxlen += start >> 2;
for (left = s->codec.rxlen << 2; left; start = (EAC_BUF_LEN << 2) - left)
left -= AUD_read(s->codec.in_voice,
(uint8_t *) s->codec.rxbuf + start, left);
if (recv > 0 && left > 0) {
start = 0;
while (left && (recv = AUD_read(s->codec.in_voice,
(uint8_t *) s->codec.rxbuf + start,
left)) > 0) { /* Be defensive */
start += recv;
left -= recv;
}
if (recv <= 0)
s->codec.rxavail = 0;
else
s->codec.rxavail -= start >> 2;
s->codec.rxlen += start >> 2;
}
}
static inline void omap_eac_out_empty(struct omap_eac_s *s)
{
int left, start = 0;
int left = s->codec.txlen << 2;
int start = 0;
int sent = 1;
for (left = s->codec.txlen << 2; left; start = (s->codec.txlen << 2) - left)
left -= AUD_write(s->codec.out_voice,
(uint8_t *) s->codec.txbuf + start, left);
while (left && (sent = AUD_write(s->codec.out_voice,
(uint8_t *) s->codec.txbuf + start,
left)) > 0) { /* Be defensive */
start += sent;
left -= sent;
}
s->codec.txavail -= s->codec.txlen;
s->codec.txlen = 0;
if (!sent) {
s->codec.txavail = 0;
omap_eac_out_dmarequest_update(s);
}
if (start)
s->codec.txlen = 0;
}
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)
struct omap_eac_s *s = (struct omap_eac_s *) opaque;
s->codec.rxavail = avail_b >> 2;
omap_eac_in_dmarequest_update(s);
omap_eac_in_refill(s);
/* TODO: possibly discard current buffer if overrun */
omap_eac_in_dmarequest_update(s);
}
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)
struct omap_eac_s *s = (struct omap_eac_s *) opaque;
s->codec.txavail = free_b >> 2;
if (s->codec.txlen > s->codec.txavail)
s->codec.txlen = s->codec.txavail;
omap_eac_out_empty(s);
omap_eac_out_dmarequest_update(s);
if (s->codec.txlen)
omap_eac_out_empty(s);
else
omap_eac_out_dmarequest_update(s);
}
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)
{
audsettings_t fmt;
omap_eac_out_empty(s);
/* The hardware buffers at most one sample */
if (s->codec.rxlen)
s->codec.rxlen = 1;
if (s->codec.in_voice) {
AUD_set_active_in(s->codec.in_voice, 0);
@ -1599,10 +1638,14 @@ static void omap_eac_format_update(struct omap_eac_s *s)
s->codec.in_voice = 0;
}
if (s->codec.out_voice) {
omap_eac_out_empty(s);
AUD_set_active_out(s->codec.out_voice, 0);
AUD_close_out(&s->codec.card, s->codec.out_voice);
s->codec.out_voice = 0;
s->codec.txavail = 0;
}
/* Discard what couldn't be written */
s->codec.txlen = 0;
omap_eac_enable_update(s);
if (!s->codec.enable)
@ -1663,6 +1706,7 @@ static void omap_eac_reset(struct omap_eac_s *s)
s->codec.config[1] = 0x0000;
s->codec.config[2] = 0x0007;
s->codec.config[3] = 0x1ffc;
s->codec.rxoff = 0;
s->codec.rxlen = 0;
s->codec.txlen = 0;
s->codec.rxavail = 0;
@ -1676,6 +1720,7 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
{
struct omap_eac_s *s = (struct omap_eac_s *) opaque;
int offset = addr - s->base;
uint32_t ret;
switch (offset) {
case 0x000: /* CPCFR1 */
@ -1739,16 +1784,19 @@ static uint32_t omap_eac_read(void *opaque, target_phys_addr_t addr)
/* This should be write-only? Docs list it as read-only. */
return 0x0000;
case 0x0b8: /* ADRDR */
if (likely(s->codec.rxlen > 1))
return s->codec.rxbuf[EAC_BUF_LEN - s->codec.rxlen --];
else if (s->codec.rxlen) {
if (likely(s->codec.rxlen > 1)) {
ret = s->codec.rxbuf[s->codec.rxoff ++];
s->codec.rxlen --;
s->codec.rxoff &= EAC_BUF_LEN - 1;
return ret;
} else if (s->codec.rxlen) {
ret = s->codec.rxbuf[s->codec.rxoff ++];
s->codec.rxlen --;
s->codec.rxoff &= EAC_BUF_LEN - 1;
if (s->codec.rxavail)
omap_eac_in_refill(s);
else {
s->codec.rxlen = 0;
omap_eac_in_dmarequest_update(s);
}
return s->codec.rxbuf[EAC_BUF_LEN - 1];
omap_eac_in_dmarequest_update(s);
return ret;
}
return 0x0000;
case 0x0bc: /* AGCFR */
@ -1881,8 +1929,8 @@ static void omap_eac_write(void *opaque, target_phys_addr_t addr,
s->codec.txlen == s->codec.txavail)) {
if (s->codec.txavail)
omap_eac_out_empty(s);
else
s->codec.txlen = 0;
/* Discard what couldn't be written */
s->codec.txlen = 0;
}
break;