mirror of https://gitee.com/openkylin/qemu.git
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