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:
parent
c580d92b0e
commit
ab17b46d00
106
hw/omap2.c
106
hw/omap2.c
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user