Fix long standing multi playback/recording issues, caused by
excessive interrupt clock timer reset, screwing interrupt generation for already active channels. Track moving DMA pointer and call buffer interrupt on each blocksize boundary. PR: kern/109791 MFC after: 3 days
This commit is contained in:
parent
6c078b8ddb
commit
28cfa6c331
@ -86,7 +86,7 @@ static struct m3_card_type {
|
||||
{ 0, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
#define M3_BUFSIZE_MIN 1024
|
||||
#define M3_BUFSIZE_MIN 4096
|
||||
#define M3_BUFSIZE_MAX 65536
|
||||
#define M3_BUFSIZE_DEFAULT 4096
|
||||
#define M3_PCHANS 4 /* create /dev/dsp0.[0-N] to use more than one */
|
||||
@ -105,6 +105,8 @@ struct sc_pchinfo {
|
||||
u_int32_t dac_data;
|
||||
u_int32_t dac_idx;
|
||||
u_int32_t active;
|
||||
u_int32_t ptr;
|
||||
u_int32_t prevptr;
|
||||
};
|
||||
|
||||
struct sc_rchinfo {
|
||||
@ -117,6 +119,8 @@ struct sc_rchinfo {
|
||||
u_int32_t adc_data;
|
||||
u_int32_t adc_idx;
|
||||
u_int32_t active;
|
||||
u_int32_t ptr;
|
||||
u_int32_t prevptr;
|
||||
};
|
||||
|
||||
struct sc_info {
|
||||
@ -162,7 +166,8 @@ static int m3_pchan_setspeed(kobj_t, void *, u_int32_t);
|
||||
static int m3_pchan_setblocksize(kobj_t, void *, u_int32_t);
|
||||
static int m3_pchan_trigger(kobj_t, void *, int);
|
||||
static int m3_pchan_trigger_locked(kobj_t, void *, int);
|
||||
static int m3_pchan_getptr(kobj_t, void *);
|
||||
static u_int32_t m3_pchan_getptr_internal(struct sc_pchinfo *);
|
||||
static u_int32_t m3_pchan_getptr(kobj_t, void *);
|
||||
static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *);
|
||||
|
||||
/* record channel interface */
|
||||
@ -173,9 +178,12 @@ static int m3_rchan_setspeed(kobj_t, void *, u_int32_t);
|
||||
static int m3_rchan_setblocksize(kobj_t, void *, u_int32_t);
|
||||
static int m3_rchan_trigger(kobj_t, void *, int);
|
||||
static int m3_rchan_trigger_locked(kobj_t, void *, int);
|
||||
static int m3_rchan_getptr(kobj_t, void *);
|
||||
static u_int32_t m3_rchan_getptr_internal(struct sc_rchinfo *);
|
||||
static u_int32_t m3_rchan_getptr(kobj_t, void *);
|
||||
static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *);
|
||||
|
||||
static int m3_chan_active(struct sc_info *);
|
||||
|
||||
/* talk to the codec - called from ac97.c */
|
||||
static int m3_initcd(kobj_t, void *);
|
||||
static int m3_rdcd(kobj_t, void *, int);
|
||||
@ -555,7 +563,7 @@ m3_pchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
|
||||
M3_DEBUG(CHANGE, ("m3_pchan_setblocksize(dac=%d, blocksize=%d)\n",
|
||||
ch->dac_idx, blocksize));
|
||||
|
||||
return blocksize;
|
||||
return (sndbuf_getblksz(ch->buffer));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -572,6 +580,22 @@ m3_pchan_trigger(kobj_t kobj, void *chdata, int go)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
m3_chan_active(struct sc_info *sc)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < sc->pch_cnt; i++)
|
||||
ret += sc->pch[i].active;
|
||||
|
||||
for (i = 0; i < sc->rch_cnt; i++)
|
||||
ret += sc->rch[i].active;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
{
|
||||
@ -595,13 +619,17 @@ m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
return 0;
|
||||
}
|
||||
ch->active = 1;
|
||||
ch->ptr = 0;
|
||||
ch->prevptr = 0;
|
||||
sc->pch_active_cnt++;
|
||||
|
||||
/*[[inc_timer_users]]*/
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
|
||||
if (m3_chan_active(sc) == 1) {
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 1);
|
||||
m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER,
|
||||
@ -618,10 +646,12 @@ m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
|
||||
/* XXX should the channel be drained? */
|
||||
/*[[dec_timer_users]]*/
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
|
||||
if (m3_chan_active(sc) == 0) {
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 0);
|
||||
m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER,
|
||||
@ -638,14 +668,12 @@ m3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
m3_pchan_getptr(kobj_t kobj, void *chdata)
|
||||
static u_int32_t
|
||||
m3_pchan_getptr_internal(struct sc_pchinfo *ch)
|
||||
{
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t hi, lo, bus_base, bus_crnt;
|
||||
|
||||
M3_LOCK(sc);
|
||||
bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
hi = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH);
|
||||
lo = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL);
|
||||
@ -653,11 +681,24 @@ m3_pchan_getptr(kobj_t kobj, void *chdata)
|
||||
|
||||
M3_DEBUG(CALL, ("m3_pchan_getptr(dac=%d) result=%d\n",
|
||||
ch->dac_idx, bus_crnt - bus_base));
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (bus_crnt - bus_base); /* current byte offset of channel */
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
m3_pchan_getptr(kobj_t kobj, void *chdata)
|
||||
{
|
||||
struct sc_pchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t ptr;
|
||||
|
||||
M3_LOCK(sc);
|
||||
ptr = ch->ptr;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
static struct pcmchan_caps *
|
||||
m3_pchan_getcaps(kobj_t kobj, void *chdata)
|
||||
{
|
||||
@ -865,7 +906,7 @@ m3_rchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
|
||||
M3_DEBUG(CHANGE, ("m3_rchan_setblocksize(adc=%d, blocksize=%d)\n",
|
||||
ch->adc_idx, blocksize));
|
||||
|
||||
return blocksize;
|
||||
return (sndbuf_getblksz(ch->buffer));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -905,12 +946,16 @@ m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
return 0;
|
||||
}
|
||||
ch->active = 1;
|
||||
ch->ptr = 0;
|
||||
ch->prevptr = 0;
|
||||
|
||||
/*[[inc_timer_users]]*/
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
|
||||
if (m3_chan_active(sc) == 1) {
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 1);
|
||||
m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 1);
|
||||
@ -924,10 +969,12 @@ m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
ch->active = 0;
|
||||
|
||||
/*[[dec_timer_users]]*/
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
|
||||
if (m3_chan_active(sc) == 0) {
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
|
||||
m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
|
||||
data = m3_rd_2(sc, HOST_INT_CTRL);
|
||||
m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
|
||||
}
|
||||
|
||||
m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 0);
|
||||
m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 0);
|
||||
@ -943,14 +990,12 @@ m3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
m3_rchan_getptr(kobj_t kobj, void *chdata)
|
||||
static u_int32_t
|
||||
m3_rchan_getptr_internal(struct sc_rchinfo *ch)
|
||||
{
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t hi, lo, bus_base, bus_crnt;
|
||||
|
||||
M3_LOCK(sc);
|
||||
bus_base = sndbuf_getbufaddr(ch->buffer);
|
||||
hi = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH);
|
||||
lo = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL);
|
||||
@ -958,11 +1003,24 @@ m3_rchan_getptr(kobj_t kobj, void *chdata)
|
||||
|
||||
M3_DEBUG(CALL, ("m3_rchan_getptr(adc=%d) result=%d\n",
|
||||
ch->adc_idx, bus_crnt - bus_base));
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (bus_crnt - bus_base); /* current byte offset of channel */
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
m3_rchan_getptr(kobj_t kobj, void *chdata)
|
||||
{
|
||||
struct sc_rchinfo *ch = chdata;
|
||||
struct sc_info *sc = ch->parent;
|
||||
u_int32_t ptr;
|
||||
|
||||
M3_LOCK(sc);
|
||||
ptr = ch->ptr;
|
||||
M3_UNLOCK(sc);
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
static struct pcmchan_caps *
|
||||
m3_rchan_getcaps(kobj_t kobj, void *chdata)
|
||||
{
|
||||
@ -980,7 +1038,9 @@ static void
|
||||
m3_intr(void *p)
|
||||
{
|
||||
struct sc_info *sc = (struct sc_info *)p;
|
||||
u_int32_t status, ctl, i;
|
||||
struct sc_pchinfo *pch;
|
||||
struct sc_rchinfo *rch;
|
||||
u_int32_t status, ctl, i, delta;
|
||||
|
||||
M3_DEBUG(INTR, ("m3_intr\n"));
|
||||
|
||||
@ -1024,25 +1084,44 @@ m3_intr(void *p)
|
||||
m3_wr_1(sc, ASSP_HOST_INT_STATUS,
|
||||
DSP2HOST_REQ_TIMER);
|
||||
/*[[ess_update_ptr]]*/
|
||||
goto m3_handle_channel_intr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto m3_handle_channel_intr_out;
|
||||
|
||||
m3_handle_channel_intr:
|
||||
for (i=0 ; i<sc->pch_cnt ; i++) {
|
||||
if (sc->pch[i].active) {
|
||||
pch = &sc->pch[i];
|
||||
if (pch->active) {
|
||||
pch->ptr = m3_pchan_getptr_internal(pch);
|
||||
delta = pch->bufsize + pch->ptr - pch->prevptr;
|
||||
delta %= pch->bufsize;
|
||||
if (delta < sndbuf_getblksz(pch->buffer))
|
||||
continue;
|
||||
pch->prevptr = pch->ptr;
|
||||
M3_UNLOCK(sc);
|
||||
chn_intr(sc->pch[i].channel);
|
||||
chn_intr(pch->channel);
|
||||
M3_LOCK(sc);
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<sc->rch_cnt ; i++) {
|
||||
if (sc->rch[i].active) {
|
||||
rch = &sc->rch[i];
|
||||
if (rch->active) {
|
||||
rch->ptr = m3_rchan_getptr_internal(rch);
|
||||
delta = rch->bufsize + rch->ptr - rch->prevptr;
|
||||
delta %= rch->bufsize;
|
||||
if (delta < sndbuf_getblksz(rch->buffer))
|
||||
continue;
|
||||
rch->prevptr = rch->ptr;
|
||||
M3_UNLOCK(sc);
|
||||
chn_intr(sc->rch[i].channel);
|
||||
chn_intr(rch->channel);
|
||||
M3_LOCK(sc);
|
||||
}
|
||||
}
|
||||
|
||||
m3_handle_channel_intr_out:
|
||||
M3_UNLOCK(sc);
|
||||
}
|
||||
|
||||
@ -1173,10 +1252,10 @@ m3_pci_attach(device_t dev)
|
||||
{
|
||||
struct sc_info *sc;
|
||||
struct ac97_info *codec = NULL;
|
||||
u_int32_t data, i;
|
||||
u_int32_t data;
|
||||
char status[SND_STATUSLEN];
|
||||
struct m3_card_type *card;
|
||||
int len;
|
||||
int i, len, dacn, adcn;
|
||||
|
||||
M3_DEBUG(CALL, ("m3_pci_attach\n"));
|
||||
|
||||
@ -1203,6 +1282,19 @@ m3_pci_attach(device_t dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
||||
"dac", &i) == 0) {
|
||||
if (i < 1)
|
||||
dacn = 1;
|
||||
else if (i > M3_PCHANS)
|
||||
dacn = M3_PCHANS;
|
||||
else
|
||||
dacn = i;
|
||||
} else
|
||||
dacn = M3_PCHANS;
|
||||
|
||||
adcn = M3_RCHANS;
|
||||
|
||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
|
||||
pci_write_config(dev, PCIR_COMMAND, data, 2);
|
||||
@ -1236,7 +1328,7 @@ m3_pci_attach(device_t dev)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MAX, M3_BUFSIZE_DEFAULT,
|
||||
sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MIN, M3_BUFSIZE_DEFAULT,
|
||||
M3_BUFSIZE_MAX);
|
||||
|
||||
if (bus_dma_tag_create(
|
||||
@ -1279,17 +1371,17 @@ m3_pci_attach(device_t dev)
|
||||
|
||||
m3_enable_ints(sc);
|
||||
|
||||
if (pcm_register(dev, sc, M3_PCHANS, M3_RCHANS)) {
|
||||
if (pcm_register(dev, sc, dacn, adcn)) {
|
||||
device_printf(dev, "pcm_register error\n");
|
||||
goto bad;
|
||||
}
|
||||
for (i=0 ; i<M3_PCHANS ; i++) {
|
||||
for (i=0 ; i<dacn ; i++) {
|
||||
if (pcm_addchan(dev, PCMDIR_PLAY, &m3_pch_class, sc)) {
|
||||
device_printf(dev, "pcm_addchan (play) error\n");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
for (i=0 ; i<M3_RCHANS ; i++) {
|
||||
for (i=0 ; i<adcn ; i++) {
|
||||
if (pcm_addchan(dev, PCMDIR_REC, &m3_rch_class, sc)) {
|
||||
device_printf(dev, "pcm_addchan (rec) error\n");
|
||||
goto bad;
|
||||
|
Loading…
Reference in New Issue
Block a user