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 #define EAC_BUF_LEN 1024
uint32_t rxbuf[EAC_BUF_LEN]; uint32_t rxbuf[EAC_BUF_LEN];
int rxoff;
int rxlen; int rxlen;
int rxavail; int rxavail;
uint32_t txbuf[EAC_BUF_LEN]; 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) 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 */ ((s->codec.config[1] >> 12) & 1)); /* DMAREN */
} }
@ -1490,25 +1491,60 @@ 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) 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); left -= leftwrap;
s->codec.rxavail -= s->codec.rxlen; 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) if (recv > 0 && left > 0) {
left -= AUD_read(s->codec.in_voice, start = 0;
(uint8_t *) s->codec.rxbuf + start, left); 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) 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) while (left && (sent = AUD_write(s->codec.out_voice,
left -= AUD_write(s->codec.out_voice, (uint8_t *) s->codec.txbuf + start,
(uint8_t *) s->codec.txbuf + start, left); left)) > 0) { /* Be defensive */
start += sent;
left -= sent;
}
s->codec.txavail -= s->codec.txlen; if (!sent) {
s->codec.txavail = 0;
omap_eac_out_dmarequest_update(s);
}
if (start)
s->codec.txlen = 0; s->codec.txlen = 0;
} }
@ -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; struct omap_eac_s *s = (struct omap_eac_s *) opaque;
s->codec.rxavail = avail_b >> 2; s->codec.rxavail = avail_b >> 2;
omap_eac_in_dmarequest_update(s); omap_eac_in_refill(s);
/* TODO: possibly discard current buffer if overrun */ /* TODO: possibly discard current buffer if overrun */
omap_eac_in_dmarequest_update(s);
} }
static void omap_eac_out_cb(void *opaque, int free_b) static void omap_eac_out_cb(void *opaque, int free_b)
@ -1526,9 +1563,9 @@ static void omap_eac_out_cb(void *opaque, int free_b)
struct omap_eac_s *s = (struct omap_eac_s *) opaque; struct omap_eac_s *s = (struct omap_eac_s *) opaque;
s->codec.txavail = free_b >> 2; s->codec.txavail = free_b >> 2;
if (s->codec.txlen > s->codec.txavail) if (s->codec.txlen)
s->codec.txlen = s->codec.txavail;
omap_eac_out_empty(s); omap_eac_out_empty(s);
else
omap_eac_out_dmarequest_update(s); omap_eac_out_dmarequest_update(s);
} }
@ -1591,7 +1628,9 @@ static void omap_eac_format_update(struct omap_eac_s *s)
{ {
audsettings_t fmt; 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) { if (s->codec.in_voice) {
AUD_set_active_in(s->codec.in_voice, 0); 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; s->codec.in_voice = 0;
} }
if (s->codec.out_voice) { if (s->codec.out_voice) {
omap_eac_out_empty(s);
AUD_set_active_out(s->codec.out_voice, 0); AUD_set_active_out(s->codec.out_voice, 0);
AUD_close_out(&s->codec.card, s->codec.out_voice); AUD_close_out(&s->codec.card, s->codec.out_voice);
s->codec.out_voice = 0; s->codec.out_voice = 0;
s->codec.txavail = 0;
} }
/* Discard what couldn't be written */
s->codec.txlen = 0;
omap_eac_enable_update(s); omap_eac_enable_update(s);
if (!s->codec.enable) 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[1] = 0x0000;
s->codec.config[2] = 0x0007; s->codec.config[2] = 0x0007;
s->codec.config[3] = 0x1ffc; s->codec.config[3] = 0x1ffc;
s->codec.rxoff = 0;
s->codec.rxlen = 0; s->codec.rxlen = 0;
s->codec.txlen = 0; s->codec.txlen = 0;
s->codec.rxavail = 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; struct omap_eac_s *s = (struct omap_eac_s *) opaque;
int offset = addr - s->base; int offset = addr - s->base;
uint32_t ret;
switch (offset) { switch (offset) {
case 0x000: /* CPCFR1 */ 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. */ /* This should be write-only? Docs list it as read-only. */
return 0x0000; return 0x0000;
case 0x0b8: /* ADRDR */ case 0x0b8: /* ADRDR */
if (likely(s->codec.rxlen > 1)) if (likely(s->codec.rxlen > 1)) {
return s->codec.rxbuf[EAC_BUF_LEN - s->codec.rxlen --]; ret = s->codec.rxbuf[s->codec.rxoff ++];
else if (s->codec.rxlen) { 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) if (s->codec.rxavail)
omap_eac_in_refill(s); omap_eac_in_refill(s);
else {
s->codec.rxlen = 0;
omap_eac_in_dmarequest_update(s); omap_eac_in_dmarequest_update(s);
} return ret;
return s->codec.rxbuf[EAC_BUF_LEN - 1];
} }
return 0x0000; return 0x0000;
case 0x0bc: /* AGCFR */ case 0x0bc: /* AGCFR */
@ -1881,7 +1929,7 @@ static void omap_eac_write(void *opaque, target_phys_addr_t addr,
s->codec.txlen == s->codec.txavail)) { s->codec.txlen == s->codec.txavail)) {
if (s->codec.txavail) if (s->codec.txavail)
omap_eac_out_empty(s); omap_eac_out_empty(s);
else /* Discard what couldn't be written */
s->codec.txlen = 0; s->codec.txlen = 0;
} }
break; break;