From b5a092936855a30b45608a0bc6d040a408842fe9 Mon Sep 17 00:00:00 2001 From: netchild Date: Sat, 6 Jan 2007 18:59:35 +0000 Subject: [PATCH] Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov --- sys/dev/sound/pci/emu10kx-pcm.c | 245 ++++++++++++++++++++-- sys/dev/sound/pci/emu10kx.c | 204 +++++++++++++++--- sys/dev/sound/pci/emu10kx.h | 13 +- sys/modules/sound/driver/emu10kx/Makefile | 3 + 4 files changed, 402 insertions(+), 63 deletions(-) diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c index b35dc321a4b..7ba00c166e5 100644 --- a/sys/dev/sound/pci/emu10kx-pcm.c +++ b/sys/dev/sound/pci/emu10kx-pcm.c @@ -79,12 +79,13 @@ struct emu_pcm_rchinfo { struct emu_pcm_info *pcm; }; -/* Hardware channels for front output */ +/* XXX Hardware playback channels */ #define MAX_CHANNELS 4 #if MAX_CHANNELS > 13 #error Too many hardware channels defined. 13 is the maximum #endif + struct emu_pcm_info { struct mtx *lock; device_t dev; /* device information */ @@ -92,7 +93,8 @@ struct emu_pcm_info { struct emu_sc_info *card; struct emu_pcm_pchinfo pch[MAX_CHANNELS]; /* hardware channels */ int pnum; /* next free channel number */ - struct emu_pcm_rchinfo rch; + struct emu_pcm_rchinfo rch_adc; + struct emu_pcm_rchinfo rch_efx; struct emu_route rt; struct emu_route rt_mono; int route; @@ -104,14 +106,26 @@ struct emu_pcm_info { }; -static uint32_t emu_rfmt[] = { +static uint32_t emu_rfmt_adc[] = { AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE, 0 }; -static struct pcmchan_caps emu_reccaps = { - /* XXX should be "8000, 48000, emu_rfmt, 0", but 8000/8bit/mono is broken */ - 11025, 48000, emu_rfmt, 0 +static struct pcmchan_caps emu_reccaps_adc = { + 8000, 48000, emu_rfmt_adc, 0 +}; + +static uint32_t emu_rfmt_efx[] = { + AFMT_S16_LE, + 0 +}; + +static struct pcmchan_caps emu_reccaps_efx_live = { + 48000*32, 48000*32, emu_rfmt_efx, 0 +}; + +static struct pcmchan_caps emu_reccaps_efx_audigy = { + 48000*64, 48000*64, emu_rfmt_efx, 0 }; static uint32_t emu_pfmt[] = { @@ -433,8 +447,7 @@ emupchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm ch->buffer = b; ch->pcm = sc; ch->channel = c; - /* XXX blksz should not be modified, see emu10kx.h for reasons */ - ch->blksz = EMU_PLAY_BUFSZ; + ch->blksz = sc->bufsz; ch->fmt = AFMT_U8; ch->spd = 8000; ch->master = emu_valloc(sc->card); @@ -575,13 +588,13 @@ emurchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm struct emu_pcm_rchinfo *ch; KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction")); - ch = &sc->rch; + ch = &sc->rch_adc; ch->buffer = b; ch->pcm = sc; ch->channel = c; - ch->blksz = sc->bufsz; + ch->blksz = sc->bufsz / 2; /* We rise interrupt for half-full buffer */ ch->fmt = AFMT_U8; - ch->spd = 11025; /* XXX 8000 Hz does not work */ + ch->spd = 8000; ch->idxreg = sc->is_emu10k1 ? ADCIDX : A_ADCIDX; ch->basereg = ADCBA; ch->sizereg = ADCBS; @@ -627,7 +640,11 @@ emurchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize) struct emu_pcm_rchinfo *ch = c_devinfo; ch->blksz = blocksize; - return (blocksize); + /* If blocksize is less than half of buffer size we will not get + interrupt in time and channel will die due to interrupt timeout */ + if(ch->blksz < (ch->pcm->bufsz / 2)) + ch->blksz = ch->pcm->bufsz / 2; + return (ch->blksz); } static int @@ -706,7 +723,7 @@ emurchan_getptr(kobj_t obj __unused, void *c_devinfo) static struct pcmchan_caps * emurchan_getcaps(kobj_t obj __unused, void *c_devinfo __unused) { - return (&emu_reccaps); + return (&emu_reccaps_adc); } static kobj_method_t emurchan_methods[] = { @@ -721,6 +738,174 @@ static kobj_method_t emurchan_methods[] = { }; CHANNEL_DECLARE(emurchan); +static void * +emufxrchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir __unused) +{ + struct emu_pcm_info *sc = devinfo; + struct emu_pcm_rchinfo *ch; + + KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction")); + + if (sc == NULL) return (NULL); + + ch = &(sc->rch_efx); + ch->fmt = AFMT_S16_LE; + ch->spd = sc->is_emu10k1 ? 48000*32 : 48000 * 64; + ch->idxreg = FXIDX; + ch->basereg = FXBA; + ch->sizereg = FXBS; + ch->irqmask = INTE_EFXBUFENABLE; + ch->iprmask = IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL; + ch->buffer = b; + ch->pcm = sc; + ch->channel = c; + ch->blksz = sc->bufsz; + + if (sndbuf_alloc(ch->buffer, emu_gettag(sc->card), sc->bufsz) != 0) + return (NULL); + else { + emu_wrptr(sc->card, 0, ch->basereg, sndbuf_getbufaddr(ch->buffer)); + emu_wrptr(sc->card, 0, ch->sizereg, 0); /* off */ + return (ch); + } +} + +static int +emufxrchan_setformat(kobj_t obj __unused, void *c_devinfo __unused, uint32_t format) +{ + if (format == AFMT_S16_LE) return (0); + return (-1); +} + +static int +emufxrchan_setspeed(kobj_t obj __unused, void *c_devinfo, uint32_t speed) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + + /* FIXED RATE CHANNEL */ + return (ch->spd); +} + +static int +emufxrchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + + ch->blksz = blocksize; + /* If blocksize is less than half of buffer size we will not get + interrupt in time and channel will die due to interrupt timeout */ + if(ch->blksz < (ch->pcm->bufsz / 2)) + ch->blksz = ch->pcm->bufsz / 2; + return (ch->blksz); +} + +static int +emufxrchan_trigger(kobj_t obj __unused, void *c_devinfo, int go) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; + uint32_t sz; + + switch (sc->bufsz) { + case 4096: + sz = ADCBS_BUFSIZE_4096; + break; + case 8192: + sz = ADCBS_BUFSIZE_8192; + break; + case 16384: + sz = ADCBS_BUFSIZE_16384; + break; + case 32768: + sz = ADCBS_BUFSIZE_32768; + break; + case 65536: + sz = ADCBS_BUFSIZE_65536; + break; + default: + sz = ADCBS_BUFSIZE_4096; + } + + snd_mtxlock(sc->lock); + switch (go) { + case PCMTRIG_START: + ch->run = 1; + emu_wrptr(sc->card, 0, ch->sizereg, sz); + ch->ihandle = emu_intr_register(sc->card, ch->irqmask, ch->iprmask, &emu_pcm_intr, sc); + /* + SB Live! is limited to 32 mono channels. Audigy + has 64 mono channels, each of them is selected from + one of two A_FXWC[1|2] registers. + */ + /* XXX there is no way to demultiplex this streams for now */ + if(sc->is_emu10k1) { + emu_wrptr(sc->card, 0, FXWC, 0xffffffff); + } else { + emu_wrptr(sc->card, 0, A_FXWC1, 0xffffffff); + emu_wrptr(sc->card, 0, A_FXWC2, 0xffffffff); + } + break; + case PCMTRIG_STOP: + /* FALLTHROUGH */ + case PCMTRIG_ABORT: + ch->run = 0; + if(sc->is_emu10k1) { + emu_wrptr(sc->card, 0, FXWC, 0x0); + } else { + emu_wrptr(sc->card, 0, A_FXWC1, 0x0); + emu_wrptr(sc->card, 0, A_FXWC2, 0x0); + } + emu_wrptr(sc->card, 0, ch->sizereg, 0); + (void)emu_intr_unregister(sc->card, ch->ihandle); + break; + case PCMTRIG_EMLDMAWR: + /* FALLTHROUGH */ + case PCMTRIG_EMLDMARD: + /* FALLTHROUGH */ + default: + break; + } + snd_mtxunlock(sc->lock); + + return (0); +} + +static int +emufxrchan_getptr(kobj_t obj __unused, void *c_devinfo) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; + int r; + + r = emu_rdptr(sc->card, 0, ch->idxreg) & 0x0000ffff; + + return (r); +} + +static struct pcmchan_caps * +emufxrchan_getcaps(kobj_t obj __unused, void *c_devinfo) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; + + if(sc->is_emu10k1) + return (&emu_reccaps_efx_live); + return (&emu_reccaps_efx_audigy); + +} + +static kobj_method_t emufxrchan_methods[] = { + KOBJMETHOD(channel_init, emufxrchan_init), + KOBJMETHOD(channel_setformat, emufxrchan_setformat), + KOBJMETHOD(channel_setspeed, emufxrchan_setspeed), + KOBJMETHOD(channel_setblocksize, emufxrchan_setblocksize), + KOBJMETHOD(channel_trigger, emufxrchan_trigger), + KOBJMETHOD(channel_getptr, emufxrchan_getptr), + KOBJMETHOD(channel_getcaps, emufxrchan_getcaps), + {0, 0} +}; +CHANNEL_DECLARE(emufxrchan); + static uint32_t emu_pcm_intr(void *pcm, uint32_t stat) @@ -745,8 +930,14 @@ emu_pcm_intr(void *pcm, uint32_t stat) if (stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL)) { ack |= stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL); - if (sc->rch.channel) - chn_intr(sc->rch.channel); + if (sc->rch_adc.channel) + chn_intr(sc->rch_adc.channel); + } + + if (stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)) { + ack |= stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL); + if (sc->rch_efx.channel) + chn_intr(sc->rch_efx.channel); } return (ack); } @@ -780,23 +971,26 @@ emu_pcm_probe(device_t dev) r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ROUTE, &route); switch (route) { case RT_FRONT: - rt = "FRONT"; + rt = "front"; break; case RT_REAR: - rt = "REAR"; + rt = "rear"; break; case RT_CENTER: - rt = "CENTER"; + rt = "center"; break; case RT_SUB: - rt = "SUBWOOFER"; + rt = "subwoofer"; break; case RT_SIDE: - rt = "SIDE"; + rt = "side"; + break; + case RT_MCHRECORD: + rt = "multichannel recording"; break; } - snprintf(buffer, 255, "EMU10Kx DSP %s PCM Interface", rt); + snprintf(buffer, 255, "EMU10Kx DSP %s PCM interface", rt); device_set_desc_copy(dev, buffer); return (0); } @@ -903,6 +1097,9 @@ emu_pcm_attach(device_t dev) goto bad; } break; + case RT_MCHRECORD: + /* XXX add mixer here */ + break; default: device_printf(dev, "invalid default route\n"); goto bad; @@ -923,12 +1120,16 @@ emu_pcm_attach(device_t dev) goto bad; } sc->pnum = 0; - pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc); + if (route != RT_MCHRECORD) + pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc); if (route == RT_FRONT) { for (i = 1; i < MAX_CHANNELS; i++) pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc); pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc); } + if (route == RT_MCHRECORD) + pcm_addchan(dev, PCMDIR_REC, &emufxrchan_class, sc); + snprintf(status, SND_STATUSLEN, "on %s", device_get_nameunit(device_get_parent(dev))); pcm_setstatus(dev, status); diff --git a/sys/dev/sound/pci/emu10kx.c b/sys/dev/sound/pci/emu10kx.c index d603a0b5323..25192851a63 100644 --- a/sys/dev/sound/pci/emu10kx.c +++ b/sys/dev/sound/pci/emu10kx.c @@ -149,6 +149,8 @@ #define OUT_ADC_REC_R 0x0b #define OUT_ADC_REC OUT_ADC_REC_L #define OUT_MIC_CAP 0x0c + +/* Live! 5.1 Digital, non-standart 5.1 (center & sub) outputs */ #define OUT_A_CENTER 0x11 #define OUT_A_SUB 0x12 @@ -224,6 +226,8 @@ #define C_SIDE_R 9 #define NUM_CACHES 10 +#define NUM_DUMMIES 64 + #define EMU_MAX_GPR 512 #define EMU_MAX_IRQ_CONSUMERS 32 @@ -282,7 +286,7 @@ struct emu_sc_info { /* Hardware and subdevices */ device_t dev; - device_t pcm[5]; + device_t pcm[RT_COUNT]; device_t midi[2]; uint32_t type; uint32_t rev; @@ -341,6 +345,7 @@ struct emu_sc_info { int mixer_gpr[NUM_MIXERS]; int mixer_volcache[NUM_MIXERS]; int cache_gpr[NUM_CACHES]; + int dummy_gpr[NUM_DUMMIES]; struct sysctl_ctx_list *ctx; struct sysctl_oid *root; }; @@ -367,7 +372,7 @@ static int emu_rm_init(struct emu_sc_info *sc); static int emu_rm_uninit(struct emu_sc_info *sc); static int emu_rm_gpr_alloc(struct emu_rm *rm, int count); -static int emu_getcard(device_t dev); +static unsigned int emu_getcard(device_t dev); static uint32_t emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size); static void emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size); static void emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data); @@ -404,6 +409,7 @@ struct emu_hwinfo { }; static struct emu_hwinfo emu_cards[] = { + {0xffff, 0xffff, 0xffff, 0xffff, "BADCRD", "Not a compatible card", 0}, /* 0x0020..0x002f 4.0 EMU10K1 cards */ {0x1102, 0x0002, 0x1102, 0x0020, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1}, {0x1102, 0x0002, 0x1102, 0x0021, "CT4620", "SBLive!", HAS_AC97 | IS_EMU10K1}, @@ -452,6 +458,10 @@ static struct emu_hwinfo emu_cards[] = { /* 0x2001..0x2003 7.1 CA0102-ICT cards */ {0x1102, 0x0004, 0x1102, 0x2001, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, {0x1102, 0x0004, 0x1102, 0x2002, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, + /* XXX No reports about 0x2003 & 0x2004 cards */ + {0x1102, 0x0004, 0x1102, 0x2003, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, + {0x1102, 0x0004, 0x1102, 0x2004, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, + {0x1102, 0x0004, 0x1102, 0x2005, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102}, /* (range unknown) 7.1 CA0102-xxx Audigy 4 cards */ {0x1102, 0x0004, 0x1102, 0x2007, "SB0380", "Audigy 4 Pro", HAS_AC97 | HAS_71 | IS_CA0102}, @@ -490,21 +500,21 @@ static struct emu_hwinfo emu_bad_cards[] = { /* * Get best known information about device. */ -static int +static unsigned int emu_getcard(device_t dev) { uint16_t device; uint16_t subdevice; int n_cards; - int thiscard; + unsigned int thiscard; int i; device = pci_read_config(dev, PCIR_DEVICE, /* bytes */ 2); subdevice = pci_read_config(dev, PCIR_SUBDEV_0, /* bytes */ 2); n_cards = sizeof(emu_cards) / sizeof(struct emu_hwinfo); - thiscard = (-1); - for (i = 0; i < n_cards; i++) { + thiscard = 0; + for (i = 1; i < n_cards; i++) { if (device == emu_cards[i].device) { if (subdevice == emu_cards[i].subdevice) { thiscard = i; @@ -522,11 +532,11 @@ emu_getcard(device_t dev) for (i = 0; i < n_cards; i++) { if (device == emu_bad_cards[i].device) { if (subdevice == emu_bad_cards[i].subdevice) { - thiscard = (-1); + thiscard = 0; break; } if (0x0000 == emu_bad_cards[i].subdevice) { - thiscard = (-1); + thiscard = 0; break; /* we avoid all this cards */ } } @@ -752,8 +762,11 @@ emu_timer_set(struct emu_sc_info *sc, int timer, int delay) { int i; + if(timer < 0) + return (-1); + RANGE(delay, 16, 1024); - RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS); + RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); sc->timer[timer] = delay; for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) @@ -771,6 +784,11 @@ emu_timer_enable(struct emu_sc_info *sc, int timer, int go) int ena_int; int i; + if(timer < 0) + return (-1); + + RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); + mtx_lock(&sc->lock); if ((go == 1) && (sc->timer[timer] < 0)) @@ -804,6 +822,11 @@ emu_timer_enable(struct emu_sc_info *sc, int timer, int go) int emu_timer_clear(struct emu_sc_info *sc, int timer) { + if(timer < 0) + return (-1); + + RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); + emu_timer_enable(sc, timer, 0); mtx_lock(&sc->lock); @@ -834,9 +857,15 @@ emu_intr_register(struct emu_sc_info *sc, uint32_t inte_mask, uint32_t intr_mask x |= inte_mask; emu_wr(sc, INTE, x, 4); mtx_unlock(&sc->lock); +#ifdef SND_EMU10KX_DEBUG + device_printf(sc->dev, "ihandle %d registered\n", i); +#endif return (i); } mtx_unlock(&sc->lock); +#ifdef SND_EMU10KX_DEBUG + device_printf(sc->dev, "ihandle not registered\n"); +#endif return (-1); } @@ -892,6 +921,10 @@ emu_intr(void *p) (sc->ihandler[i].intr_mask) & stat); } } +#ifdef SND_EMU10KX_DEBUG + if(stat & (~ack)) + device_printf(sc->dev, "Unhandled interrupt: %08x\n", stat & (~ack)); +#endif } if ((sc->is_ca0102) || (sc->is_ca0108)) @@ -1499,10 +1532,28 @@ emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, &pc); \ } while(0) +/* mute, if FLAG != 0 */ +/* XXX */ +#define EFX_MUTEIF(GPR_IDX, FLAG) do { \ +} while(0) + +/* allocate dummy GPR. It's content will be used somewhere */ +#define EFX_DUMMY(DUMMY_IDX, DUMMY_VALUE) do { \ + sc->dummy_gpr[DUMMY_IDX] = emu_rm_gpr_alloc(sc->rm, 1); \ + emumix_set_gpr(sc, sc->dummy_gpr[DUMMY_IDX], DUMMY_VALUE); \ + emu_addefxop(sc, ACC3, \ + FX2(DUMMY_IDX), \ + GPR(sc->dummy_gpr[DUMMY_IDX]), \ + DSP_CONST(0), \ + DSP_CONST(0), \ + &pc); \ +} while (0) + + static void emu_initefx(struct emu_sc_info *sc) { - unsigned int c; + unsigned int i; uint32_t pc; /* stop DSP */ @@ -1514,7 +1565,7 @@ emu_initefx(struct emu_sc_info *sc) /* code size is in instructions */ pc = 0; - for (c = 0; c < sc->code_size; c++) { + for (i = 0; i < sc->code_size; i++) { if (sc->is_emu10k1) { emu_addefxop(sc, ACC3, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), &pc); } else { @@ -1533,8 +1584,8 @@ emu_initefx(struct emu_sc_info *sc) */ /* clean outputs */ - for (c = 0; c < 16 ; c++) { - emu_addefxop(sc, ACC3, OUTP(c), DSP_CONST(0), DSP_CONST(0), DSP_CONST(0), &pc); + for (i = 0; i < 16 ; i++) { + emu_addefxop(sc, ACC3, OUTP(i), DSP_CONST(0), DSP_CONST(0), DSP_CONST(0), &pc); } @@ -1558,17 +1609,21 @@ emu_initefx(struct emu_sc_info *sc) /* in1, from CD S/PDIF */ EFX_ROUTE("cdspdif_front_l", INP(IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); + EFX_MUTEIF(M_IN1_FRONT_L, CDSPDIFMUTE); EFX_ROUTE("cdspdif_front_r", INP(IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); + EFX_MUTEIF(M_IN1_FRONT_R, CDSPDIFMUTE); EFX_ROUTE("cdspdif_rec_l", INP(IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); + EFX_MUTEIF(M_IN1_REC_L, CDSPDIFMUTE); EFX_ROUTE("cdspdif_rec_r", INP(IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); -#if 0 + EFX_MUTEIF(M_IN1_REC_L, CDSPDIFMUTE); +#ifdef SND_EMU10KX_DEBUG_OUTPUTS /* in2, ZoomVide (???) */ EFX_ROUTE("zoom_front_l", INP(IN_ZOOM_L), M_IN2_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("zoom_front_r", INP(IN_ZOOM_R), M_IN2_FRONT_R, C_FRONT_R, 0); EFX_ROUTE("zoom_rec_l", INP(IN_ZOOM_L), M_IN2_REC_L, C_REC_L, 0); EFX_ROUTE("zoom_rec_r", INP(IN_ZOOM_R), M_IN2_REC_R, C_REC_R, 0); #endif -#if 0 +#ifdef SND_EMU10KX_DEBUG_OUTPUTS /* in3, TOSLink (???) */ EFX_ROUTE("toslink_front_l", INP(IN_TOSLINK_L), M_IN3_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("toslink_front_r", INP(IN_TOSLINK_R), M_IN3_FRONT_R, C_FRONT_R, 0); @@ -1592,16 +1647,18 @@ emu_initefx(struct emu_sc_info *sc) EFX_ROUTE("line2_front_r", INP(IN_LINE2_R), M_IN6_FRONT_R, C_FRONT_R, 0); EFX_ROUTE("line2_rec_l", INP(IN_LINE2_L), M_IN6_REC_L, C_REC_L, 0); EFX_ROUTE("line2_rec_r", INP(IN_LINE2_R), M_IN6_REC_R, C_REC_R, 0); -#if 0 +#ifdef SND_EMU10KX_DEBUG_OUTPUTS /* in7, unknown */ EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0); EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0); EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0); #endif - /* front output to both analog and digital */ + /* front output to hedaphones and both analog and digital */ EFX_OUTPUT("master_front_l", C_FRONT_L, M_MASTER_FRONT_L, OUT_AC97_L, 100); EFX_OUTPUT("master_front_r", C_FRONT_R, M_MASTER_FRONT_R, OUT_AC97_R, 100); + EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_HEADPHONE_L); + EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_HEADPHONE_R); /* rec output to "ADC" */ EFX_OUTPUT("master_rec_l", C_REC_L, M_MASTER_REC_L, OUT_ADC_REC_L, 100); @@ -1620,6 +1677,41 @@ emu_initefx(struct emu_sc_info *sc) EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, OUT_REAR_L, 100); EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, OUT_REAR_R, 100); + if (sc->has_51) { + /* fx4 (pcm2) to center */ + EFX_CACHE(C_CENTER); + EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100); + EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100); +#if 0 + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER); +#endif + /* fx5 (pcm3) to sub */ + EFX_CACHE(C_SUB); + EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100); + EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100); +#if 0 + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB); +#endif + } +#ifdef SND_EMU10KX_MCH_RECORDING + /* MCH RECORDING , hight 16 slots. On 5.1 cards first 4 slots are used + as outputs and already filled with data */ + for(i = (sc->has_51 ? 4 : 0); i < 16; i++) { + /* XXX fill with dummy data */ + EFX_DUMMY(i,i*0x10000); + emu_addefxop(sc, ACC3, + FX2(i), + DSP_CONST(0), + DSP_CONST(0), + GPR(sc->dummy_gpr[i]), + &pc); + + } +#endif #else /* !SND_EMU10KX_MULTICHANNEL */ EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_REAR_L); EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_REAR_R); @@ -1653,11 +1745,12 @@ emu_initefx(struct emu_sc_info *sc) EFX_ROUTE("cdspdif_rec_r", INP(A_IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); /* in2, optical & coax S/PDIF on AudigyDrive*/ + /* XXX Should be muted when GPRSCS valid stream == 0 */ EFX_ROUTE("ospdif_front_l", INP(A_IN_O_SPDIF_L), M_IN2_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("ospdif_front_r", INP(A_IN_O_SPDIF_R), M_IN2_FRONT_R, C_FRONT_R, 0); EFX_ROUTE("ospdif_rec_l", INP(A_IN_O_SPDIF_L), M_IN2_REC_L, C_REC_L, 0); EFX_ROUTE("ospdif_rec_r", INP(A_IN_O_SPDIF_R), M_IN2_REC_R, C_REC_R, 0); -#if 0 +#ifdef SND_EMU10KX_DEBUG_OUTPUTS /* in3, unknown */ EFX_ROUTE("in3_front_l", INP(0x6), M_IN3_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("in3_front_r", INP(0x7), M_IN3_FRONT_R, C_FRONT_R, 0); @@ -1681,7 +1774,7 @@ emu_initefx(struct emu_sc_info *sc) EFX_ROUTE("aux2_front_r", INP(A_IN_AUX2_R), M_IN6_FRONT_R, C_FRONT_R, 0); EFX_ROUTE("aux2_rec_l", INP(A_IN_AUX2_L), M_IN6_REC_L, C_REC_L, 0); EFX_ROUTE("aux2_rec_r", INP(A_IN_AUX2_R), M_IN6_REC_R, C_REC_R, 0); -#if 0 +#ifdef SND_EMU10KX_DEBUG_OUTPUTS /* in7, unknown */ EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0); EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0); @@ -1748,6 +1841,19 @@ emu_initefx(struct emu_sc_info *sc) EFX_OUTPUTD(C_SIDE_L, M_MASTER_SIDE_L, A_OUT_D_SIDE_L); EFX_OUTPUTD(C_SIDE_R, M_MASTER_SIDE_R, A_OUT_D_SIDE_R); } +#ifdef SND_EMU10KX_MCH_RECORDING + /* MCH RECORDING, high 32 slots */ + for(i = 0; i < 32; i++) { + /* XXX fill with dummy data */ + EFX_DUMMY(i,i*0x10000); + emu_addefxop(sc, ACC3, + FX2(i), + DSP_CONST(0), + DSP_CONST(0), + GPR(sc->dummy_gpr[i]), + &pc); + } +#endif #else /* !SND_EMU10KX_MULTICHANNEL */ EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_REAR_L); EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_REAR_R); @@ -1883,7 +1989,7 @@ emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s) if (sc->broken_digital) sbuf_printf(s, "Digital mode unsupported\n"); sbuf_printf(s, "\nInstalled devices:\n"); - for (i = 0; i < 5; i++) + for (i = 0; i < RT_COUNT; i++) if (sc->pcm[i] != NULL) if (device_is_attached(sc->pcm[i])) { sbuf_printf(s, "%s on %s\n", device_get_desc(sc->pcm[i]), device_get_nameunit(sc->pcm[i])); @@ -2564,7 +2670,7 @@ static int emu_pci_probe(device_t dev) { struct sbuf *s; - int thiscard = 0; + unsigned int thiscard = 0; uint16_t vendor; vendor = pci_read_config(dev, PCIR_DEVVENDOR, /* bytes */ 2); @@ -2572,7 +2678,7 @@ emu_pci_probe(device_t dev) return (ENXIO); /* Not Creative */ thiscard = emu_getcard(dev); - if (thiscard < 0) + if (thiscard == 0) return (ENXIO); s = sbuf_new(NULL, NULL, 4096, 0); @@ -2655,18 +2761,25 @@ emu_pci_attach(device_t dev) if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { sc->opcode_shift = 24; sc->high_operand_shift = 12; - sc->code_base = A_MICROCODEBASE; - sc->code_size = 0x800 / 2; /* 0x600-0xdff, 2048 words, - * 1024 instructions */ - sc->gpr_base = A_FXGPREGBASE; - sc->num_gprs = 0x200; + + /* DSP map */ + /* sc->fx_base = 0x0 */ sc->input_base = 0x40; -/* sc->p16vinput_base = 0x50; */ + /* sc->p16vinput_base = 0x50; */ sc->output_base = 0x60; sc->efxc_base = 0x80; -/* sc->output32h_base = 0xa0; */ -/* sc->output32l_base = 0xb0; */ + /* sc->output32h_base = 0xa0; */ + /* sc->output32l_base = 0xb0; */ sc->dsp_zero = 0xc0; + /* 0xe0...0x100 are unknown */ + /* sc->tram_base = 0x200 */ + /* sc->tram_addr_base = 0x300 */ + sc->gpr_base = A_FXGPREGBASE; + sc->num_gprs = 0x200; + sc->code_base = A_MICROCODEBASE; + sc->code_size = 0x800 / 2; /* 0x600-0xdff, 2048 words, + * 1024 instructions */ + sc->mchannel_fx = 8; sc->num_fxbuses = 16; sc->num_inputs = 8; @@ -2684,6 +2797,11 @@ emu_pci_attach(device_t dev) sc->num_gprs = 0x100; sc->input_base = 0x10; sc->output_base = 0x20; + /* + * XXX 5.1 Analog outputs are inside efxc address space! + * They use ouput+0x11/+0x12 (=efxc+1/+2). + * Don't use this efx registers for recording on SB Live! 5.1! + */ sc->efxc_base = 0x30; sc->dsp_zero = 0x40; sc->mchannel_fx = 0; @@ -2778,6 +2896,8 @@ emu_pci_attach(device_t dev) func->varinfo = pcminfo; sc->pcm[RT_FRONT] = device_add_child(dev, "pcm", -1); device_set_ivars(sc->pcm[RT_FRONT], func); + +#ifdef SND_EMU10KX_MULTICHANNEL /* REAR */ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); if (func == NULL) { @@ -2789,7 +2909,6 @@ emu_pci_attach(device_t dev) error = ENOMEM; goto bad; } -#ifdef SND_EMU10KX_MULTICHANNEL pcminfo->card = sc; pcminfo->route = RT_REAR; @@ -2855,6 +2974,27 @@ emu_pci_attach(device_t dev) sc->pcm[RT_SIDE] = device_add_child(dev, "pcm", -1); device_set_ivars(sc->pcm[RT_SIDE], func); }; +#ifdef SND_EMU10KX_MCH_RECORDING + /* MULTICHANNEL RECORDING */ + func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); + if (func == NULL) { + error = ENOMEM; + goto bad; + } + pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (pcminfo == NULL) { + error = ENOMEM; + goto bad; + } + pcminfo->card = sc; + pcminfo->route = RT_MCHRECORD; + + func->func = SCF_PCM; + func->varinfo = pcminfo; + sc->pcm[RT_MCHRECORD] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_MCHRECORD], func); + +#endif /* SMD_EMU10KX_MCH_RECORDING */ #endif /* SND_EMU10KX_MULTICHANNEL */ /* Midi Interface 1: Live!, Audigy, Audigy 2 */ @@ -2935,7 +3075,7 @@ emu_pci_detach(device_t dev) sc = device_get_softc(dev); - for (i = 0; i < 5; i++) { + for (i = 0; i < RT_COUNT; i++) { if (sc->pcm[i] != NULL) r = device_delete_child(dev, sc->pcm[i]); if (r) diff --git a/sys/dev/sound/pci/emu10kx.h b/sys/dev/sound/pci/emu10kx.h index 7075ef937b3..302f175dc53 100644 --- a/sys/dev/sound/pci/emu10kx.h +++ b/sys/dev/sound/pci/emu10kx.h @@ -38,15 +38,8 @@ #define EMUPAGESIZE 4096 #define NUM_G 64 -/* XXX */ - /* - * There are some problems when EMU_PLAY_BUFSZ is larger then EMU_PAGESIZE - * 1) there is a sound lag, because first round of playback is silence - * 2) the end of large file (equal to the lag duration) is lost - * 3) as a result of 1) and 2) no sound at all, when file size is less than - * EMU_PLAY_BUFSZ (it plays silence and then stops) - */ -#define EMU_PLAY_BUFSZ EMUPAGESIZE +#define EMU_PLAY_BUFSZ EMUPAGESIZE*16 +/* Recording is limited by EMUPAGESIZE*16=64K buffer */ #define EMU_REC_BUFSZ EMUPAGESIZE*16 #define EMU_MAX_BUFSZ EMUPAGESIZE*16 #define EMU_MAXPAGES 8192 @@ -61,6 +54,8 @@ #define RT_CENTER 2 #define RT_SUB 3 #define RT_SIDE 4 +#define RT_MCHRECORD 5 +#define RT_COUNT 6 /* mixer controls */ /* fx play */ diff --git a/sys/modules/sound/driver/emu10kx/Makefile b/sys/modules/sound/driver/emu10kx/Makefile index f65be350613..dd44711af49 100644 --- a/sys/modules/sound/driver/emu10kx/Makefile +++ b/sys/modules/sound/driver/emu10kx/Makefile @@ -43,6 +43,9 @@ CLEANFILES+= p17v-alsa%diked.h .if !defined(KERNBUILDDIR) opt_emu10kx.h: echo "#define SND_EMU10KX_MULTICHANNEL" > opt_emu10kx.h + echo "#define SND_EMU10KX_MCH_RECORDING" >> opt_emu10kx.h + echo "#undef SND_EMU10KX_DEBUG_OUTPUTS" >> opt_emu10kx.h + echo "#undef SND_EMU10KX_DEBUG" >> opt_emu10kx.h .endif .include -- 2.45.0