diff options
-rw-r--r-- | sys/dev/sound/pci/maestro3.c | 176 |
1 files changed, 134 insertions, 42 deletions
diff --git a/sys/dev/sound/pci/maestro3.c b/sys/dev/sound/pci/maestro3.c index 1d9571a..e8454f2 100644 --- a/sys/dev/sound/pci/maestro3.c +++ b/sys/dev/sound/pci/maestro3.c @@ -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 @@ -573,6 +581,22 @@ m3_pchan_trigger(kobj_t kobj, void *chdata, int go) } 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) { struct sc_pchinfo *ch = chdata; @@ -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; |