diff options
| author | Ariff Abdullah <ariff@FreeBSD.org> | 2007-09-12 07:43:43 +0000 |
|---|---|---|
| committer | Ariff Abdullah <ariff@FreeBSD.org> | 2007-09-12 07:43:43 +0000 |
| commit | b28624fde638caadd4a89f50c9b7e7da0f98c4d2 (patch) | |
| tree | dd78d0fa1d7afdfdfb8eab47903493e8bec3c684 /sys | |
| parent | e61a9df52b49892676471f8ff40fe23e23f2c7e4 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/conf/NOTES | 1 | ||||
| -rw-r--r-- | sys/conf/options | 3 | ||||
| -rw-r--r-- | sys/dev/sound/pci/emu10kx-midi.c | 10 | ||||
| -rw-r--r-- | sys/dev/sound/pci/emu10kx-pcm.c | 467 | ||||
| -rw-r--r-- | sys/dev/sound/pci/emu10kx.c | 1277 | ||||
| -rw-r--r-- | sys/dev/sound/pci/emu10kx.h | 5 | ||||
| -rw-r--r-- | sys/modules/sound/driver/emu10kx/Makefile | 13 |
7 files changed, 1248 insertions, 528 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 76d74e3aea8e..f0c32cd7e25d 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2043,7 +2043,6 @@ device snd_csa device snd_ds1 device snd_emu10k1 device snd_emu10kx -options SND_EMU10KX_MULTICHANNEL device snd_envy24 device snd_envy24ht device snd_es137x diff --git a/sys/conf/options b/sys/conf/options index 9d6959b11c89..43cb60618fbb 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -749,8 +749,5 @@ XBOX opt_xbox.h # XFS XFS -# snd_emu10kx sound driver options -SND_EMU10KX_MULTICHANNEL opt_emu10kx.h - # Interrupt filtering INTR_FILTER opt_global.h diff --git a/sys/dev/sound/pci/emu10kx-midi.c b/sys/dev/sound/pci/emu10kx-midi.c index e6339dbc084a..736e7c25c377 100644 --- a/sys/dev/sound/pci/emu10kx-midi.c +++ b/sys/dev/sound/pci/emu10kx-midi.c @@ -46,7 +46,6 @@ #include <dev/sound/midi/mpu401.h> #include "mpufoi_if.h" -#include "opt_emu10kx.h" #include <dev/sound/pci/emu10kx.h> #include "emu10k1-alsa%diked.h" @@ -117,9 +116,8 @@ emu_midi_card_intr(void *p, uint32_t intr_status) if (sc->mpu_intr == NULL) { /* We should read MIDI event to unlock card after * interrupt. XXX - check, why this happens. */ -#ifdef SND_EMU10KX_DEBUG - device_printf(sc->dev, "midi interrupt %08x without interrupt handler, force mread!\n", intr_status); -#endif + if (bootverbose) + device_printf(sc->dev, "midi interrupt %08x without interrupt handler, force mread!\n", intr_status); (void)emu_mread((void *)(NULL), sc, 0); } return (intr_status); /* Acknowledge everything */ @@ -166,7 +164,7 @@ emu_midi_attach(device_t dev) scp->port = midiinfo->port; scp->card = midiinfo->card; - mtx_init(&scp->mtx, "emu10kx_midi", NULL, MTX_DEF); + mtx_init(&scp->mtx, device_get_nameunit(dev), "midi softc", MTX_DEF); if (scp->is_emu10k1) { /* SB Live! - only one MIDI device here */ @@ -192,8 +190,6 @@ emu_midi_attach(device_t dev) ipr_val |= IPR_A_MIDIRECVBUFEMPTY2; } } - if (inte_val == 0) - return (ENXIO); scp->ihandle = emu_intr_register(scp->card, inte_val, ipr_val, &emu_midi_card_intr, scp); /* Init the interface. */ diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c index daf3d5a42252..99fefd742bbf 100644 --- a/sys/dev/sound/pci/emu10kx-pcm.c +++ b/sys/dev/sound/pci/emu10kx-pcm.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> - * Copyright (c) 2003-2006 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> + * Copyright (c) 2003-2007 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,14 +45,13 @@ #include "mixer_if.h" -#include "opt_emu10kx.h" #include <dev/sound/pci/emu10kx.h> #include "emu10k1-alsa%diked.h" struct emu_pcm_pchinfo { int spd; int fmt; - int blksz; + unsigned int blksz; int run; struct emu_voice *master; struct emu_voice *slave; @@ -65,7 +64,7 @@ struct emu_pcm_pchinfo { struct emu_pcm_rchinfo { int spd; int fmt; - int blksz; + unsigned int blksz; int run; uint32_t idxreg; uint32_t basereg; @@ -77,6 +76,7 @@ struct emu_pcm_rchinfo { struct snd_dbuf *buffer; struct pcm_channel *channel; struct emu_pcm_info *pcm; + int timer; }; /* XXX Hardware playback channels */ @@ -89,7 +89,6 @@ struct emu_pcm_rchinfo { struct emu_pcm_info { struct mtx *lock; device_t dev; /* device information */ - struct snddev_info *devinfo; /* pcm device information */ struct emu_sc_info *card; struct emu_pcm_pchinfo pch[MAX_CHANNELS]; /* hardware channels */ int pnum; /* next free channel number */ @@ -103,6 +102,12 @@ struct emu_pcm_info { int is_emu10k1; struct ac97_info *codec; uint32_t ac97_state[0x7F]; + kobj_class_t ac97_mixerclass; + uint32_t ac97_recdevs; + uint32_t ac97_playdevs; + struct snd_mixer *sm; + int mch_disabled; + unsigned int emu10k1_volcache[2][2]; }; @@ -128,6 +133,14 @@ static struct pcmchan_caps emu_reccaps_efx_audigy = { 48000*64, 48000*64, emu_rfmt_efx, 0 }; +static int emu_rates_live[] = { + 48000*32 +}; + +static int emu_rates_audigy[] = { + 48000*64 +}; + static uint32_t emu_pfmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, @@ -150,27 +163,105 @@ static int emu10k2_adcspeed[9] = {48000, 44100, 32000, 24000, 22050, 16000, 1200 static uint32_t emu_pcm_intr(void *pcm, uint32_t stat); -static const struct emu_dspmix_props { - u_int8_t present; -} dspmix [SOUND_MIXER_NRDEVICES] = { - [SOUND_MIXER_VOLUME] = {1}, - [SOUND_MIXER_PCM] = {1}, +static const struct emu_dspmix_props_k1 { + uint8_t present; + uint8_t recdev; + int8_t input; +} dspmix_k1 [SOUND_MIXER_NRDEVICES] = { + /* no mixer device for ac97 */ /* in0 AC97 */ + [SOUND_MIXER_DIGITAL1] = {1, 1, 1}, /* in1 CD SPDIF */ + /* not connected */ /* in2 (zoom) */ + [SOUND_MIXER_DIGITAL2] = {1, 1, 3}, /* in3 toslink */ + [SOUND_MIXER_LINE2] = {1, 1, 4}, /* in4 Line-In2 */ + [SOUND_MIXER_DIGITAL3] = {1, 1, 5}, /* in5 on-card SPDIF */ + [SOUND_MIXER_LINE3] = {1, 1, 6}, /* in6 AUX2 */ + /* not connected */ /* in7 */ +}; +static const struct emu_dspmix_props_k2 { + uint8_t present; + uint8_t recdev; + int8_t input; +} dspmix_k2 [SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_VOLUME] = {1, 0, (-1)}, + [SOUND_MIXER_PCM] = {1, 0, (-1)}, + + /* no mixer device */ /* in0 AC97 */ + [SOUND_MIXER_DIGITAL1] = {1, 1, 1}, /* in1 CD SPDIF */ + [SOUND_MIXER_DIGITAL2] = {1, 1, 2}, /* in2 COAX SPDIF */ + /* not connected */ /* in3 */ + [SOUND_MIXER_LINE2] = {1, 1, 4}, /* in4 Line-In2 */ + [SOUND_MIXER_DIGITAL3] = {1, 1, 5}, /* in5 on-card SPDIF */ + [SOUND_MIXER_LINE3] = {1, 1, 6}, /* in6 AUX2 */ + /* not connected */ /* in7 */ }; static int emu_dspmixer_init(struct snd_mixer *m) { + struct emu_pcm_info *sc; int i; - int v; + int p, r; + + p = 0; + r = 0; + + sc = mix_getdevinfo(m); + + if (sc->route == RT_FRONT) { + /* create submixer for AC97 codec */ + if ((sc->ac97_mixerclass != NULL) && (sc->codec != NULL)) { + sc->sm = mixer_create(sc->dev, sc->ac97_mixerclass, sc->codec, "ac97"); + if (sc->sm != NULL) { + p = mix_getdevs(sc->sm); + r = mix_getrecdevs(sc->sm); + } + } + + sc->ac97_playdevs = p; + sc->ac97_recdevs = r; + } + + /* This two are always here */ + p |= (1 << SOUND_MIXER_PCM); + p |= (1 << SOUND_MIXER_VOLUME); - v = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (dspmix[i].present) - v |= 1 << i; + if (sc->route == RT_FRONT) { + if (sc->is_emu10k1) { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (dspmix_k1[i].present) + p |= (1 << i); + if (dspmix_k1[i].recdev) + r |= (1 << i); + } + } else { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (dspmix_k2[i].present) + p |= (1 << i); + if (dspmix_k2[i].recdev) + r |= (1 << i); + } + } } - mix_setdevs(m, v); - mix_setrecdevs(m, 0); + mix_setdevs(m, p); + mix_setrecdevs(m, r); + + return (0); +} + +static int +emu_dspmixer_uninit(struct snd_mixer *m) +{ + struct emu_pcm_info *sc; + int err = 0; + + /* drop submixer for AC97 codec */ + sc = mix_getdevinfo(m); + if (sc->sm != NULL) + err = mixer_delete(sc->sm); + if (err) + return (err); + sc->sm = NULL; return (0); } @@ -184,6 +275,30 @@ emu_dspmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned righ switch (dev) { case SOUND_MIXER_VOLUME: switch (sc->route) { + case RT_FRONT: + if (sc->sm != NULL) + mix_set(sc->sm, dev, left, right); + if (sc->mch_disabled) { + /* In emu10k1 case PCM volume does not affect + sound routed to rear & center/sub (it is connected + to AC97 codec). Calculate it manually. */ + /* This really should belong to emu10kx.c */ + if (sc->is_emu10k1) { + sc->emu10k1_volcache[0][0] = left; + left = left * sc->emu10k1_volcache[1][0] / 100; + sc->emu10k1_volcache[0][1] = right; + right = right * sc->emu10k1_volcache[1][1] / 100; + } + + emumix_set_volume(sc->card, M_MASTER_REAR_L, left); + emumix_set_volume(sc->card, M_MASTER_REAR_R, right); + if (!sc->is_emu10k1) { + emumix_set_volume(sc->card, M_MASTER_CENTER, (left+right)/2); + emumix_set_volume(sc->card, M_MASTER_SUBWOOFER, (left+right)/2); + /* XXX side */ + } + } /* mch disabled */ + break; case RT_REAR: emumix_set_volume(sc->card, M_MASTER_REAR_L, left); emumix_set_volume(sc->card, M_MASTER_REAR_R, right); @@ -198,6 +313,27 @@ emu_dspmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned righ break; case SOUND_MIXER_PCM: switch (sc->route) { + case RT_FRONT: + if (sc->sm != NULL) + mix_set(sc->sm, dev, left, right); + if (sc->mch_disabled) { + /* See SOUND_MIXER_VOLUME case */ + if (sc->is_emu10k1) { + sc->emu10k1_volcache[1][0] = left; + left = left * sc->emu10k1_volcache[0][0] / 100; + sc->emu10k1_volcache[1][1] = right; + right = right * sc->emu10k1_volcache[0][1] / 100; + } + emumix_set_volume(sc->card, M_MASTER_REAR_L, left); + emumix_set_volume(sc->card, M_MASTER_REAR_R, right); + + if (!sc->is_emu10k1) { + emumix_set_volume(sc->card, M_MASTER_CENTER, (left+right)/2); + emumix_set_volume(sc->card, M_MASTER_SUBWOOFER, (left+right)/2); + /* XXX side */ + } + } /* mch_disabled */ + break; case RT_REAR: emumix_set_volume(sc->card, M_FX2_REAR_L, left); emumix_set_volume(sc->card, M_FX3_REAR_R, right); @@ -210,26 +346,160 @@ emu_dspmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned righ break; } break; + case SOUND_MIXER_DIGITAL1: /* CD SPDIF, in1 */ + emumix_set_volume(sc->card, M_IN1_FRONT_L, left); + emumix_set_volume(sc->card, M_IN1_FRONT_R, right); + break; + case SOUND_MIXER_DIGITAL2: + if (sc->is_emu10k1) { + /* TOSLink, in3 */ + emumix_set_volume(sc->card, M_IN3_FRONT_L, left); + emumix_set_volume(sc->card, M_IN3_FRONT_R, right); + } else { + /* COAX SPDIF, in2 */ + emumix_set_volume(sc->card, M_IN2_FRONT_L, left); + emumix_set_volume(sc->card, M_IN2_FRONT_R, right); + } + break; + case SOUND_MIXER_LINE2: /* Line-In2, in4 */ + emumix_set_volume(sc->card, M_IN4_FRONT_L, left); + emumix_set_volume(sc->card, M_IN4_FRONT_R, right); + break; + case SOUND_MIXER_DIGITAL3: /* on-card SPDIF, in5 */ + emumix_set_volume(sc->card, M_IN5_FRONT_L, left); + emumix_set_volume(sc->card, M_IN5_FRONT_R, right); + break; + case SOUND_MIXER_LINE3: /* AUX2, in6 */ + emumix_set_volume(sc->card, M_IN6_FRONT_L, left); + emumix_set_volume(sc->card, M_IN6_FRONT_R, right); + break; default: - device_printf(sc->dev, "mixer error: unknown device %d\n", dev); + if (sc->sm != NULL) { + /* XXX emumix_set_volume is not required here */ + emumix_set_volume(sc->card, M_IN0_FRONT_L, 100); + emumix_set_volume(sc->card, M_IN0_FRONT_R, 100); + mix_set(sc->sm, dev, left, right); + } else + device_printf(sc->dev, "mixer error: unknown device %d\n", dev); } return (0); } static int -emu_dspmixer_setrecsrc(struct snd_mixer *m __unused, u_int32_t src __unused) +emu_dspmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) { - return (0); + struct emu_pcm_info *sc; + int i; + u_int32_t recmask; + int input[8]; + + sc = mix_getdevinfo(m); + recmask = 0; + for (i=0; i < 8; i++) + input[i]=0; + + if (sc->sm != NULL) + if ((src & sc->ac97_recdevs) !=0) + if (mix_setrecsrc(sc->sm, src & sc->ac97_recdevs) == 0) { + recmask |= (src & sc->ac97_recdevs); + /* Recording from AC97 codec. + Enable AC97 route to rec on DSP */ + input[0] = 1; + } + if (sc->is_emu10k1) { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (dspmix_k1[i].recdev) + if ((src & (1 << i)) == ((uint32_t)1 << i)) { + recmask |= (1 << i); + /* enable device i */ + input[dspmix_k1[i].input] = 1; + } + } + } else { + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (dspmix_k2[i].recdev) + if ((src & (1 << i)) == ((uint32_t)1 << i)) { + recmask |= (1 << i); + /* enable device i */ + input[dspmix_k2[i].input] = 1; + } + } + } + emumix_set_volume(sc->card, M_IN0_REC_L, input[0] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN0_REC_R, input[0] == 1 ? 100 : 0); + + emumix_set_volume(sc->card, M_IN1_REC_L, input[1] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN1_REC_R, input[1] == 1 ? 100 : 0); + + if (!sc->is_emu10k1) { + emumix_set_volume(sc->card, M_IN2_REC_L, input[2] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN2_REC_R, input[2] == 1 ? 100 : 0); + } + + if (sc->is_emu10k1) { + emumix_set_volume(sc->card, M_IN3_REC_L, input[3] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN3_REC_R, input[3] == 1 ? 100 : 0); + } + + emumix_set_volume(sc->card, M_IN4_REC_L, input[4] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN4_REC_R, input[4] == 1 ? 100 : 0); + + emumix_set_volume(sc->card, M_IN5_REC_L, input[5] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN5_REC_R, input[5] == 1 ? 100 : 0); + + emumix_set_volume(sc->card, M_IN6_REC_L, input[6] == 1 ? 100 : 0); + emumix_set_volume(sc->card, M_IN6_REC_R, input[6] == 1 ? 100 : 0); + + /* XXX check for K1/k2 differences? */ + if ((src & (1 << SOUND_MIXER_PCM)) == (1 << SOUND_MIXER_PCM)) { + emumix_set_volume(sc->card, M_FX0_REC_L, emumix_get_volume(sc->card, M_FX0_FRONT_L)); + emumix_set_volume(sc->card, M_FX1_REC_R, emumix_get_volume(sc->card, M_FX1_FRONT_R)); + } else { + emumix_set_volume(sc->card, M_FX0_REC_L, 0); + emumix_set_volume(sc->card, M_FX1_REC_R, 0); + } + + return (recmask); } static kobj_method_t emudspmixer_methods[] = { KOBJMETHOD(mixer_init, emu_dspmixer_init), + KOBJMETHOD(mixer_uninit, emu_dspmixer_uninit), KOBJMETHOD(mixer_set, emu_dspmixer_set), KOBJMETHOD(mixer_setrecsrc, emu_dspmixer_setrecsrc), { 0, 0 } }; MIXER_DECLARE(emudspmixer); +static int +emu_efxmixer_init(struct snd_mixer *m) +{ + mix_setdevs(m, SOUND_MASK_VOLUME); + mix_setrecdevs(m, SOUND_MASK_MONITOR); + return (0); +} + +static int +emu_efxmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) +{ + if (left + right == 200) return (0); + return (0); +} + +static int +emu_efxmixer_setrecsrc(struct snd_mixer *m __unused, u_int32_t src __unused) +{ + return (SOUND_MASK_MONITOR); +} + +static kobj_method_t emuefxmixer_methods[] = { + KOBJMETHOD(mixer_init, emu_efxmixer_init), + KOBJMETHOD(mixer_set, emu_efxmixer_set), + KOBJMETHOD(mixer_setrecsrc, emu_efxmixer_setrecsrc), + { 0, 0 } +}; +MIXER_DECLARE(emuefxmixer); + /* * AC97 emulation code for Audigy and later cards. * Some parts of AC97 codec are not used by hardware, but can be used @@ -250,7 +520,7 @@ MIXER_DECLARE(emudspmixer); #define BIT6_TO255(x) (255-(x)*255/(0x3f)) #define V100_TOBIT6(x) (0x3f*(100-x)/100) #define V100_TOBIT4(x) (0x0f*(100-x)/100) -#define AC97ENCODE(x_muted,x_left,x_right) (((x_muted&1)<<15) | ((x_left&0x3f)<<8) | (x_right&0x3f)) +#define AC97ENCODE(x_muted, x_left, x_right) (((x_muted & 1)<<15) | ((x_left & 0x3f)<<8) | (x_right & 0x3f)) static int emu_ac97_read_emulation(struct emu_pcm_info *sc, int regno) @@ -325,7 +595,9 @@ emu_ac97_write_emulation(struct emu_pcm_info *sc, int regno, uint32_t data) case AC97_REG_RECSEL: /* * PCM recording source is set to "stereo mix" (labeled "vol" - * in mixer) XXX !I can't remember why! + * in mixer). There is no 'playback' from AC97 codec - + * if you want to hear anything from AC97 you have to _record_ + * it. Keep things simple and record "stereo mix". */ data = 0x0505; break; @@ -414,7 +686,6 @@ emu_k1_recval(int speed) val = 0; while ((val < 7) && (speed < emu10k1_adcspeed[val])) val++; - if (val == 6) val=5; /* XXX 8kHz does not work */ return (val); } @@ -426,7 +697,6 @@ emu_k2_recval(int speed) val = 0; while ((val < 8) && (speed < emu10k2_adcspeed[val])) val++; - if (val == 7) val=6; /* XXX 8kHz does not work */ return (val); } @@ -504,7 +774,7 @@ emupchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize) ch->blksz = blocksize; emu_timer_set(sc->card, ch->timer, ch->blksz / sndbuf_getbps(ch->buffer)); snd_mtxunlock(sc->lock); - return (blocksize); + return (ch->blksz); } static int @@ -606,6 +876,7 @@ emurchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm if (sndbuf_alloc(ch->buffer, emu_gettag(sc->card), 0, sc->bufsz) != 0) return (NULL); else { + ch->timer = emu_timer_create(sc->card); emu_wrptr(sc->card, 0, ch->basereg, sndbuf_getbufaddr(ch->buffer)); emu_wrptr(sc->card, 0, ch->sizereg, 0); /* off */ return (ch); @@ -613,6 +884,16 @@ emurchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct pcm } static int +emurchan_free(kobj_t obj __unused, void *c_devinfo) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; + + emu_timer_clear(sc->card, ch->timer); + return (0); +} + +static int emurchan_setformat(kobj_t obj __unused, void *c_devinfo, uint32_t format) { struct emu_pcm_rchinfo *ch = c_devinfo; @@ -639,12 +920,20 @@ static int emurchan_setblocksize(kobj_t obj __unused, void *c_devinfo, uint32_t blocksize) { struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; 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; + /* + * If blocksize is less than half of buffer size we will not get + * BUFHALFFULL interrupt in time and channel will need to generate + * (and use) timer interrupts. Otherwise channel will be marked dead. + */ + if (ch->blksz < (ch->pcm->bufsz / 2)) { + emu_timer_set(sc->card, ch->timer, ch->blksz / sndbuf_getbps(ch->buffer)); + emu_timer_enable(sc->card, ch->timer, 1); + } else { + emu_timer_enable(sc->card, ch->timer, 0); + } return (ch->blksz); } @@ -732,6 +1021,7 @@ emurchan_getcaps(kobj_t obj __unused, void *c_devinfo __unused) static kobj_method_t emurchan_methods[] = { KOBJMETHOD(channel_init, emurchan_init), + KOBJMETHOD(channel_free, emurchan_free), KOBJMETHOD(channel_setformat, emurchan_setformat), KOBJMETHOD(channel_setspeed, emurchan_setspeed), KOBJMETHOD(channel_setblocksize, emurchan_setblocksize), @@ -763,7 +1053,7 @@ emufxrchan_init(kobj_t obj __unused, void *devinfo, struct snd_dbuf *b, struct p ch->buffer = b; ch->pcm = sc; ch->channel = c; - ch->blksz = sc->bufsz; + ch->blksz = sc->bufsz / 2; if (sndbuf_alloc(ch->buffer, emu_gettag(sc->card), 0, sc->bufsz) != 0) return (NULL); @@ -778,7 +1068,7 @@ static int emufxrchan_setformat(kobj_t obj __unused, void *c_devinfo __unused, uint32_t format) { if (format == AFMT_S16_LE) return (0); - return (-1); + return (EINVAL); } static int @@ -796,9 +1086,13 @@ 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)) + /* + * XXX If blocksize is less than half of buffer size we will not get + * interrupt in time and channel will die due to interrupt timeout. + * This should not happen with FX rchan, because it will fill buffer + * very fast (64K buffer is 0.021seconds on Audigy). + */ + if (ch->blksz < (ch->pcm->bufsz / 2)) ch->blksz = ch->pcm->bufsz / 2; return (ch->blksz); } @@ -839,13 +1133,13 @@ emufxrchan_trigger(kobj_t obj __unused, void *c_devinfo, int go) 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. + /* + * SB Live! is limited to 32 mono channels. Audigy + * has 64 mono channels. Channels are enabled + * by setting a bit in A_FXWC[1|2] registers. */ /* XXX there is no way to demultiplex this streams for now */ - if(sc->is_emu10k1) { + if (sc->is_emu10k1) { emu_wrptr(sc->card, 0, FXWC, 0xffffffff); } else { emu_wrptr(sc->card, 0, A_FXWC1, 0xffffffff); @@ -856,7 +1150,7 @@ emufxrchan_trigger(kobj_t obj __unused, void *c_devinfo, int go) /* FALLTHROUGH */ case PCMTRIG_ABORT: ch->run = 0; - if(sc->is_emu10k1) { + if (sc->is_emu10k1) { emu_wrptr(sc->card, 0, FXWC, 0x0); } else { emu_wrptr(sc->card, 0, A_FXWC1, 0x0); @@ -895,12 +1189,26 @@ 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) + if (sc->is_emu10k1) return (&emu_reccaps_efx_live); return (&emu_reccaps_efx_audigy); } +static int +emufxrchan_getrates(kobj_t obj __unused, void *c_devinfo, int **rates) +{ + struct emu_pcm_rchinfo *ch = c_devinfo; + struct emu_pcm_info *sc = ch->pcm; + + if (sc->is_emu10k1) + *rates = emu_rates_live; + else + *rates = emu_rates_audigy; + + return 1; +} + static kobj_method_t emufxrchan_methods[] = { KOBJMETHOD(channel_init, emufxrchan_init), KOBJMETHOD(channel_setformat, emufxrchan_setformat), @@ -909,6 +1217,7 @@ static kobj_method_t emufxrchan_methods[] = { KOBJMETHOD(channel_trigger, emufxrchan_trigger), KOBJMETHOD(channel_getptr, emufxrchan_getptr), KOBJMETHOD(channel_getcaps, emufxrchan_getcaps), + KOBJMETHOD(channel_getrates, emufxrchan_getrates), {0, 0} }; CHANNEL_DECLARE(emufxrchan); @@ -923,29 +1232,51 @@ emu_pcm_intr(void *pcm, uint32_t stat) ack = 0; + snd_mtxlock(sc->lock); + if (stat & IPR_INTERVALTIMER) { ack |= IPR_INTERVALTIMER; for (i = 0; i < MAX_CHANNELS; i++) if (sc->pch[i].channel) { - if (sc->pch[i].run == 1) + if (sc->pch[i].run == 1) { + snd_mtxunlock(sc->lock); chn_intr(sc->pch[i].channel); - else + snd_mtxlock(sc->lock); + } else emu_timer_enable(sc->card, sc->pch[i].timer, 0); } + /* ADC may install timer to get low-latency interrupts */ + if ((sc->rch_adc.channel) && (sc->rch_adc.run)) { + snd_mtxunlock(sc->lock); + chn_intr(sc->rch_adc.channel); + snd_mtxlock(sc->lock); + } + /* + * EFX does not use timer, because it will fill + * buffer at least 32x times faster than ADC. + */ } if (stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL)) { ack |= stat & (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL); - if (sc->rch_adc.channel) + if (sc->rch_adc.channel) { + snd_mtxunlock(sc->lock); chn_intr(sc->rch_adc.channel); + snd_mtxlock(sc->lock); + } } if (stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)) { ack |= stat & (IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL); - if (sc->rch_efx.channel) + if (sc->rch_efx.channel) { + snd_mtxunlock(sc->lock); chn_intr(sc->rch_efx.channel); + snd_mtxlock(sc->lock); + } } + snd_mtxunlock(sc->lock); + return (ack); } @@ -1009,7 +1340,7 @@ emu_pcm_attach(device_t dev) unsigned int i; char status[SND_STATUSLEN]; uint32_t inte, ipr; - uintptr_t route, r, is_emu10k1; + uintptr_t route, r, ivar; sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); sc->card = (struct emu_sc_info *)(device_get_softc(device_get_parent(dev))); @@ -1019,11 +1350,14 @@ emu_pcm_attach(device_t dev) return (ENXIO); } - sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_emu10kx softc"); + sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_emu10kx pcm softc"); sc->dev = dev; - r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ISEMU10K1, &is_emu10k1); - sc->is_emu10k1 = is_emu10k1 ? 1 : 0; + r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ISEMU10K1, &ivar); + sc->is_emu10k1 = ivar ? 1 : 0; + + r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_MCH_DISABLED, &ivar); + sc->mch_disabled = ivar ? 1 : 0; sc->codec = NULL; @@ -1041,6 +1375,10 @@ emu_pcm_attach(device_t dev) sc->rt_mono.amounts_right[i] = 0x00; } + sc->emu10k1_volcache[0][0] = 75; + sc->emu10k1_volcache[1][0] = 75; + sc->emu10k1_volcache[0][1] = 75; + sc->emu10k1_volcache[1][1] = 75; r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ROUTE, &route); sc->route = route; switch (route) { @@ -1053,16 +1391,13 @@ emu_pcm_attach(device_t dev) sc->codec = AC97_CREATE(dev, sc, emu_ac97); else sc->codec = AC97_CREATE(dev, sc, emu_eac97); - if (sc->codec == NULL) { - if (mixer_init(dev, &emudspmixer_class, sc)) { - device_printf(dev, "failed to initialize DSP mixer\n"); - goto bad; - } - } else - if (mixer_init(dev, ac97_getmixerclass(), sc->codec) == -1) { - device_printf(dev, "can't initialize AC97 mixer!\n"); - goto bad; - } + sc->ac97_mixerclass = NULL; + if (sc->codec != NULL) + sc->ac97_mixerclass = ac97_getmixerclass(); + if (mixer_init(dev, &emudspmixer_class, sc)) { + device_printf(dev, "failed to initialize DSP mixer\n"); + goto bad; + } break; case RT_REAR: sc->rt.amounts_left[2] = 0xff; @@ -1101,7 +1436,10 @@ emu_pcm_attach(device_t dev) } break; case RT_MCHRECORD: - /* XXX add mixer here */ + if (mixer_init(dev, &emuefxmixer_class, sc)) { + device_printf(dev, "failed to initialize EFX mixer\n"); + goto bad; + } break; default: device_printf(dev, "invalid default route\n"); @@ -1109,7 +1447,7 @@ emu_pcm_attach(device_t dev) } inte = INTE_INTERVALTIMERENB; - ipr = IPR_INTERVALTIMER; /* Used by playback */ + ipr = IPR_INTERVALTIMER; /* Used by playback & ADC */ sc->ihandle = emu_intr_register(sc->card, inte, ipr, &emu_pcm_intr, sc); if (emu_pcm_init(sc) == -1) { @@ -1117,6 +1455,12 @@ emu_pcm_attach(device_t dev) goto bad; } + /* + * We don't register interrupt handler with snd_setup_intr + * in pcm device. Mark pcm device as MPSAFE manually. + */ + pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE); + /* XXX we should better get number of available channels from parent */ if (pcm_register(dev, sc, (route == RT_FRONT) ? MAX_CHANNELS : 1, (route == RT_FRONT) ? 1 : 0)) { device_printf(dev, "can't register PCM channels!\n"); @@ -1172,7 +1516,6 @@ static device_method_t emu_pcm_methods[] = { DEVMETHOD(device_probe, emu_pcm_probe), DEVMETHOD(device_attach, emu_pcm_attach), DEVMETHOD(device_detach, emu_pcm_detach), - {0, 0} }; diff --git a/sys/dev/sound/pci/emu10kx.c b/sys/dev/sound/pci/emu10kx.c index 42e9bbd2d172..35af8aabe26c 100644 --- a/sys/dev/sound/pci/emu10kx.c +++ b/sys/dev/sound/pci/emu10kx.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> - * Copyright (c) 2003-2006 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> + * Copyright (c) 2003-2007 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ #include <sys/lock.h> #include <sys/mutex.h> #include <sys/sysctl.h> +#include <sys/kdb.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -48,7 +49,6 @@ #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/ac97.h> -#include "opt_emu10kx.h" #include <dev/sound/pci/emu10kx.h> /* hw flags */ @@ -104,6 +104,9 @@ #define COND_SATURATION DSP_CONST(0x6) #define COND_NEQ_ZERO DSP_CONST(0x8) +#define DSP_ACCUM DSP_CONST(0x16) +#define DSP_CCR DSP_CONST(0x17) + /* Live! Inputs */ #define IN_AC97_L 0x00 #define IN_AC97_R 0x01 @@ -226,7 +229,9 @@ #define C_SIDE_R 9 #define NUM_CACHES 10 -#define NUM_DUMMIES 64 +#define CDSPDIFMUTE 0 +#define ANALOGMUTE 1 +#define NUM_MUTE 2 #define EMU_MAX_GPR 512 #define EMU_MAX_IRQ_CONSUMERS 32 @@ -243,6 +248,8 @@ struct emu_voice { struct emu_voice *slave; uint32_t sa; uint32_t ea; + uint32_t routing[8]; + uint32_t amounts[8]; }; struct emu_memblk { @@ -260,6 +267,7 @@ struct emu_mem { bus_addr_t silent_page_addr; bus_addr_t ptb_pages_addr; bus_dma_tag_t dmat; + struct emu_sc_info *card; SLIST_HEAD(, emu_memblk) blocks; }; @@ -310,6 +318,7 @@ struct emu_sc_info { struct emu_intr_handler ihandler[EMU_MAX_IRQ_CONSUMERS]; /* Card HW configuration */ + unsigned int mode; /* analog / digital */ unsigned int mchannel_fx; unsigned int dsp_zero; unsigned int code_base; @@ -324,10 +333,11 @@ struct emu_sc_info { unsigned int address_mask; uint32_t is_emu10k1:1, is_emu10k2, is_ca0102, is_ca0108:1, has_ac97:1, has_51:1, has_71:1, - enable_ir:1, enable_debug:1, + enable_ir:1, broken_digital:1, is_cardbus:1; - unsigned int num_inputs; + signed int mch_disabled, mch_rec, dbg_level; + signed int num_inputs; unsigned int num_outputs; unsigned int num_fxbuses; unsigned int routing_code_start; @@ -345,7 +355,8 @@ struct emu_sc_info { int mixer_gpr[NUM_MIXERS]; int mixer_volcache[NUM_MIXERS]; int cache_gpr[NUM_CACHES]; - int dummy_gpr[NUM_DUMMIES]; + int dummy_gpr; + int mute_gpr[NUM_MUTE]; struct sysctl_ctx_list *ctx; struct sysctl_oid *root; }; @@ -397,6 +408,35 @@ static int emu_pci_attach(device_t dev); static int emu_pci_detach(device_t dev); static int emu_modevent(module_t mod __unused, int cmd, void *data __unused); +#ifdef SND_EMU10KX_DEBUG + +#define EMU_MTX_DEBUG() do { \ + if (mtx_owned(&sc->rw)) { \ + printf("RW owned in %s line %d for %s\n", __func__, \ + __LINE__ , device_get_nameunit(sc->dev)); \ + printf("rw lock owned: %d\n", mtx_owned(&sc->rw)); \ + printf("rw lock: value %x thread %x\n", \ + ((&sc->rw)->mtx_lock & ~MTX_FLAGMASK), \ + (uintptr_t)curthread); \ + printf("rw lock: recursed %d\n", mtx_recursed(&sc->rw));\ + db_show_mtx(&sc->rw); \ + } \ + } while (0) +#else +#define EMU_MTX_DEBUG() do { \ + } while (0) +#endif + +#define EMU_RWLOCK() do { \ + EMU_MTX_DEBUG(); \ + mtx_lock(&(sc->rw)); \ + } while (0) + +#define EMU_RWUNLOCK() do { \ + mtx_unlock(&(sc->rw)); \ + EMU_MTX_DEBUG(); \ + } while (0) + /* Supported cards */ struct emu_hwinfo { uint16_t vendor; @@ -432,6 +472,7 @@ static struct emu_hwinfo emu_cards[] = { /* 0x8061..0x???? 5.1 EMU10K1 cards */ {0x1102, 0x0002, 0x1102, 0x8061, "SB????", "SBLive! Player 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1}, + {0x1102, 0x0002, 0x1102, 0x8062, "CT4830", "SBLive! 1024", HAS_AC97 | HAS_51 | IS_EMU10K1}, {0x1102, 0x0002, 0x1102, 0x8064, "SB????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1}, {0x1102, 0x0002, 0x1102, 0x8065, "SB0220", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1}, {0x1102, 0x0002, 0x1102, 0x8066, "CT4780", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1}, @@ -522,8 +563,10 @@ emu_getcard(device_t dev) } if (0x0000 == emu_cards[i].subdevice) { thiscard = i; - /* don't break, we can get more specific card - * later in the list */ + /* + * don't break, we can get more specific card + * later in the list. + */ } } } @@ -593,10 +636,12 @@ emu_rdptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg) uint32_t ptr, val, mask, size, offset; ptr = ((reg << 16) & sc->address_mask) | (chn & PTR_CHANNELNUM_MASK); - mtx_lock(&sc->rw); + + EMU_RWLOCK(); emu_wr_nolock(sc, PTR, ptr, 4); val = emu_rd_nolock(sc, DATA, 4); - mtx_unlock(&sc->rw); + EMU_RWUNLOCK(); + /* * XXX Some register numbers has data size and offset encoded in * it to get only part of 32bit register. This use is not described @@ -616,8 +661,10 @@ void emu_wrptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg, uint32_t data) { uint32_t ptr, mask, size, offset; + ptr = ((reg << 16) & sc->address_mask) | (chn & PTR_CHANNELNUM_MASK); - mtx_lock(&sc->rw); + + EMU_RWLOCK(); emu_wr_nolock(sc, PTR, ptr, 4); /* * XXX Another kind of magic encoding in register number. This can @@ -633,7 +680,7 @@ emu_wrptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg, uint32_t d data |= emu_rd_nolock(sc, DATA, 4) & ~mask; } emu_wr_nolock(sc, DATA, data, 4); - mtx_unlock(&sc->rw); + EMU_RWUNLOCK(); } /* * PTR2 / DATA2 interface. Access to P16v is made @@ -645,10 +692,13 @@ emu_rd_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg) { uint32_t val; - mtx_lock(&sc->rw); + /* XXX separate lock? */ + EMU_RWLOCK(); emu_wr_nolock(sc, PTR2, (reg << 16) | chn, 4); val = emu_rd_nolock(sc, DATA2, 4); - mtx_unlock(&sc->rw); + + EMU_RWUNLOCK(); + return (val); } @@ -656,10 +706,10 @@ void emu_wr_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg, uint32_t data) { - mtx_lock(&sc->rw); + EMU_RWLOCK(); emu_wr_nolock(sc, PTR2, (reg << 16) | chn, 4); emu_wr_nolock(sc, DATA2, data, 4); - mtx_unlock(&sc->rw); + EMU_RWUNLOCK(); } /* * XXX CardBus interface. Not tested on any real hardware. @@ -669,26 +719,29 @@ emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data) { uint32_t val; - /* 0x38 is IPE3 (CD S/PDIF interrupt pending register) on CA0102 Seems + /* + * 0x38 is IPE3 (CD S/PDIF interrupt pending register) on CA0102. Seems * to be some reg/value accessible kind of config register on CardBus - * CA0108, with value(?) in top 16 bit, address(?) in low 16 */ - mtx_lock(&sc->rw); + * CA0108, with value(?) in top 16 bit, address(?) in low 16 + */ + val = emu_rd_nolock(sc, 0x38, 4); emu_wr_nolock(sc, 0x38, data, 4); val = emu_rd_nolock(sc, 0x38, 4); - mtx_unlock(&sc->rw); + } /* * Direct hardware register access + * Assume that it is never used to access PTR-based registers and can run unlocked. */ void emu_wr(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size) { + KASSERT(regno != PTR, ("emu_wr: attempt to write to PTR")); + KASSERT(regno != PTR2, ("emu_wr: attempt to write to PTR2")); - mtx_lock(&sc->rw); emu_wr_nolock(sc, regno, data, size); - mtx_unlock(&sc->rw); } uint32_t @@ -696,9 +749,10 @@ emu_rd(struct emu_sc_info *sc, unsigned int regno, unsigned int size) { uint32_t rd; - mtx_lock(&sc->rw); + KASSERT(regno != DATA, ("emu_rd: attempt to read DATA")); + KASSERT(regno != DATA2, ("emu_rd: attempt to read DATA2")); + rd = emu_rd_nolock(sc, regno, size); - mtx_unlock(&sc->rw); return (rd); } @@ -711,7 +765,6 @@ emu_enable_ir(struct emu_sc_info *sc) { uint32_t iocfg; - mtx_lock(&sc->rw); if (sc->is_emu10k2 || sc->is_ca0102) { iocfg = emu_rd_nolock(sc, A_IOCFG, 2); emu_wr_nolock(sc, A_IOCFG, iocfg | A_IOCFG_GPOUT2, 2); @@ -734,7 +787,6 @@ emu_enable_ir(struct emu_sc_info *sc) device_printf(sc->dev, "SB Live! IR MIDI events enabled.\n"); sc->enable_ir = 1; } - mtx_unlock(&sc->rw); } @@ -747,12 +799,16 @@ emu_timer_create(struct emu_sc_info *sc) int i, timer; timer = -1; + + mtx_lock(&sc->lock); for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) if (sc->timer[i] == 0) { sc->timer[i] = -1; /* disable it */ timer = i; + mtx_unlock(&sc->lock); return (timer); } + mtx_unlock(&sc->lock); return (-1); } @@ -762,18 +818,22 @@ emu_timer_set(struct emu_sc_info *sc, int timer, int delay) { int i; - if(timer < 0) + if (timer < 0) return (-1); RANGE(delay, 16, 1024); RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); + mtx_lock(&sc->lock); sc->timer[timer] = delay; for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) if (sc->timerinterval > sc->timer[i]) sc->timerinterval = sc->timer[i]; + /* XXX */ emu_wr(sc, TIMER, sc->timerinterval & 0x03ff, 2); + mtx_unlock(&sc->lock); + return (timer); } @@ -784,7 +844,7 @@ emu_timer_enable(struct emu_sc_info *sc, int timer, int go) int ena_int; int i; - if(timer < 0) + if (timer < 0) return (-1); RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); @@ -822,7 +882,7 @@ 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) + if (timer < 0) return (-1); RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1); @@ -857,15 +917,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 + if (sc->dbg_level > 1) + device_printf(sc->dev, "ihandle %d registered\n", i); + return (i); } mtx_unlock(&sc->lock); -#ifdef SND_EMU10KX_DEBUG - device_printf(sc->dev, "ihandle not registered\n"); -#endif + if (sc->dbg_level > 1) + device_printf(sc->dev, "ihandle not registered\n"); + return (-1); } @@ -921,10 +981,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->dbg_level > 1) + if (stat & (~ack)) + device_printf(sc->dev, "Unhandled interrupt: %08x\n", stat & (~ack)); + } if ((sc->is_ca0102) || (sc->is_ca0108)) @@ -934,7 +994,9 @@ emu_intr(void *p) if (stat == 0) break; emu_wr(sc, IPR2, stat, 4); - device_printf(sc->dev, "IPR2: %08x\n", stat); + if (sc->dbg_level > 1) + device_printf(sc->dev, "IPR2: %08x\n", stat); + break; /* to avoid infinite loop. shoud be removed * after completion of P16V interface. */ } @@ -946,7 +1008,9 @@ emu_intr(void *p) if (stat == 0) break; emu_wr(sc, IPR3, stat, 4); - device_printf(sc->dev, "IPR3: %08x\n", stat); + if (sc->dbg_level > 1) + device_printf(sc->dev, "IPR3: %08x\n", stat); + break; /* to avoid infinite loop. should be removed * after completion of S/PDIF interface */ } @@ -982,12 +1046,19 @@ emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr) { void *dmabuf; bus_dmamap_t map; + int error; *addr = 0; - if (bus_dmamem_alloc(mem->dmat, &dmabuf, BUS_DMA_NOWAIT, &map)) + if ((error = bus_dmamem_alloc(mem->dmat, &dmabuf, BUS_DMA_NOWAIT, &map))) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_malloc: failed to alloc DMA map: %d\n", error); return (NULL); - if (bus_dmamap_load(mem->dmat, map, dmabuf, sz, emu_setmap, addr, 0) || !*addr) + } + if ((error = bus_dmamap_load(mem->dmat, map, dmabuf, sz, emu_setmap, addr, 0)) || !*addr) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_malloc: failed to load DMA memory: %d\n", error); return (NULL); + } return (dmabuf); } @@ -1007,8 +1078,11 @@ emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *ow blksz = sz / EMUPAGESIZE; if (sz > (blksz * EMUPAGESIZE)) blksz++; - if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE) + if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_memalloc: memory request tool large\n"); return (NULL); + } /* find a free block in the bitmap */ found = 0; start = 1; @@ -1020,15 +1094,23 @@ emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *ow if (!found) start++; } - if (!found) + if (!found) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_memalloc: no free space in bitmap\n"); return (NULL); + } blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT); - if (blk == NULL) + if (blk == NULL) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_memalloc: buffer allocation failed\n"); return (NULL); + } bzero(blk, sizeof(*blk)); membuf = emu_malloc(mem, sz, &blk->buf_addr); *addr = blk->buf_addr; if (membuf == NULL) { + if (mem->card->dbg_level > 2) + device_printf(mem->card->dev, "emu_memalloc: can't setup HW memory\n"); free(blk, M_DEVBUF); return (NULL); } @@ -1037,9 +1119,6 @@ emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *ow blk->pte_size = blksz; strncpy(blk->owner, owner, 15); blk->owner[15] = '\0'; -#ifdef SND_EMU10KX_DEBUG - printf("emu10kx emu_memalloc: allocating %d for %s\n", blk->pte_size, blk->owner); -#endif ofs = 0; for (idx = start; idx < start + blksz; idx++) { mem->bmap[idx >> 3] |= 1 << (idx & 7); @@ -1064,9 +1143,6 @@ emu_memfree(struct emu_mem *mem, void *membuf) } if (blk == NULL) return (EINVAL); -#ifdef SND_EMU10KX_DEBUG - printf("emu10kx emu_memfree: freeing %d for %s\n", blk->pte_size, blk->owner); -#endif SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link); emu_free(mem, membuf); tmp = (uint32_t) (mem->silent_page_addr) << 1; @@ -1184,9 +1260,11 @@ emu_vfree(struct emu_sc_info *sc, struct emu_voice *v) for (i = 0; i < NUM_G; i++) { if (v == &sc->voice[i] && sc->voice[i].busy) { v->busy = 0; - /* XXX What we should do with mono channels? - See -pcm.c emupchan_init for other side of - this problem */ + /* + * XXX What we should do with mono channels? + * See -pcm.c emupchan_init for other side of + * this problem + */ if (v->slave != NULL) r = emu_memfree(&sc->mem, v->vbuf); } @@ -1202,12 +1280,17 @@ emu_vinit(struct emu_sc_info *sc, struct emu_voice *m, struct emu_voice *s, bus_addr_t tmp_addr; vbuf = emu_memalloc(&sc->mem, sz, &tmp_addr, "vinit"); - if (vbuf == NULL) + if (vbuf == NULL) { + if(sc->dbg_level > 2) + device_printf(sc->dev, "emu_memalloc returns NULL in enu_vinit\n"); return (ENOMEM); + } if (b != NULL) sndbuf_setup(b, vbuf, sz); m->start = emu_memstart(&sc->mem, vbuf) * EMUPAGESIZE; - if (m->start == -1) { + if (m->start < 0) { + if(sc->dbg_level > 2) + device_printf(sc->dev, "emu_memstart returns (-1) in enu_vinit\n"); emu_memfree(&sc->mem, vbuf); return (ENOMEM); } @@ -1258,41 +1341,18 @@ emu_vsetup(struct emu_voice *v, int fmt, int spd) void emu_vroute(struct emu_sc_info *sc, struct emu_route *rt, struct emu_voice *v) { - unsigned int routing[8], amounts[8]; int i; for (i = 0; i < 8; i++) { - routing[i] = rt->routing_left[i]; - amounts[i] = rt->amounts_left[i]; + v->routing[i] = rt->routing_left[i]; + v->amounts[i] = rt->amounts_left[i]; } if ((v->stereo) && (v->ismaster == 0)) for (i = 0; i < 8; i++) { - routing[i] = rt->routing_right[i]; - amounts[i] = rt->amounts_right[i]; + v->routing[i] = rt->routing_right[i]; + v->amounts[i] = rt->amounts_right[i]; } - if (sc->is_emu10k1) { - emu_wrptr(sc, v->vnum, FXRT, ((routing[3] << 12) | - (routing[2] << 8) | - (routing[1] << 4) | - (routing[0] << 0)) << 16); - } else { - emu_wrptr(sc, v->vnum, A_FXRT1, (routing[3] << 24) | - (routing[2] << 16) | - (routing[1] << 8) | - (routing[0] << 0)); - emu_wrptr(sc, v->vnum, A_FXRT2, (routing[7] << 24) | - (routing[6] << 16) | - (routing[5] << 8) | - (routing[4] << 0)); - emu_wrptr(sc, v->vnum, A_SENDAMOUNTS, (amounts[7] << 24) | - (amounts[6] << 26) | - (amounts[5] << 8) | - (amounts[4] << 0)); - } - emu_wrptr(sc, v->vnum, PTRX, (amounts[0] << 8) | (amounts[1] << 0)); - emu_wrptr(sc, v->vnum, DSL, v->ea | (amounts[3] << 24)); - emu_wrptr(sc, v->vnum, PSST, v->sa | (amounts[2] << 24)); if ((v->stereo) && (v->slave != NULL)) emu_vroute(sc, rt, v->slave); } @@ -1301,7 +1361,7 @@ void emu_vwrite(struct emu_sc_info *sc, struct emu_voice *v) { int s; - uint32_t am_2, am_3, start, val, silent_page; + uint32_t start, val, silent_page; s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0); @@ -1318,10 +1378,28 @@ emu_vwrite(struct emu_sc_info *sc, struct emu_voice *v) val *= v->b16 ? 1 : 2; start = v->sa + val; - am_3 = emu_rdptr(sc, v->vnum, DSL) & 0xff000000; - emu_wrptr(sc, v->vnum, DSL, v->ea | am_3); - am_2 = emu_rdptr(sc, v->vnum, PSST) & 0xff000000; - emu_wrptr(sc, v->vnum, PSST, v->sa | am_2); + if (sc->is_emu10k1) { + emu_wrptr(sc, v->vnum, FXRT, ((v->routing[3] << 12) | + (v->routing[2] << 8) | + (v->routing[1] << 4) | + (v->routing[0] << 0)) << 16); + } else { + emu_wrptr(sc, v->vnum, A_FXRT1, (v->routing[3] << 24) | + (v->routing[2] << 16) | + (v->routing[1] << 8) | + (v->routing[0] << 0)); + emu_wrptr(sc, v->vnum, A_FXRT2, (v->routing[7] << 24) | + (v->routing[6] << 16) | + (v->routing[5] << 8) | + (v->routing[4] << 0)); + emu_wrptr(sc, v->vnum, A_SENDAMOUNTS, (v->amounts[7] << 24) | + (v->amounts[6] << 26) | + (v->amounts[5] << 8) | + (v->amounts[4] << 0)); + } + emu_wrptr(sc, v->vnum, PTRX, (v->amounts[0] << 8) | (v->amounts[1] << 0)); + emu_wrptr(sc, v->vnum, DSL, v->ea | (v->amounts[3] << 24)); + emu_wrptr(sc, v->vnum, PSST, v->sa | (v->amounts[2] << 24)); emu_wrptr(sc, v->vnum, CCCA, start | (v->b16 ? 0 : CCCA_8BITSELECT)); emu_wrptr(sc, v->vnum, Z1, 0); @@ -1468,24 +1546,70 @@ emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, volgpr = emu_rm_gpr_alloc(sc->rm, 1); emumix_set_fxvol(sc, volgpr, defvolume); - /* Mixer controls with NULL mix_name are handled by AC97 emulation - code or PCM mixer. */ + /* + * Mixer controls with NULL mix_name are handled + * by AC97 emulation code or PCM mixer. + */ if (mix_name != NULL) { - /* Temporary sysctls should start with underscore, + /* + * Temporary sysctls should start with underscore, * see freebsd-current mailing list, emu10kx driver - * discussion around 2006-05-24. */ + * discussion around 2006-05-24. + */ snprintf(sysctl_name, 32, "_%s", mix_name); SYSCTL_ADD_PROC(sc->ctx, SYSCTL_CHILDREN(sc->root), OID_AUTO, sysctl_name, CTLTYPE_INT | CTLFLAG_RW, sc, mix_id, - sysctl_emu_mixer_control, "I",""); + sysctl_emu_mixer_control, "I", ""); } return (volgpr); } -/* allocate cache GPRs that will hold mixed output channels +static int +sysctl_emu_digitalswitch_control(SYSCTL_HANDLER_ARGS) +{ + struct emu_sc_info *sc; + int new_val; + int err; + + sc = arg1; + + new_val = (sc->mode == MODE_DIGITAL) ? 1 : 0; + err = sysctl_handle_int(oidp, &new_val, 0, req); + + if (err || req->newptr == NULL) + return (err); + if (new_val < 0 || new_val > 1) + return (EINVAL); + + switch (new_val) { + case 0: + emumix_set_mode(sc, MODE_ANALOG); + break; + case 1: + emumix_set_mode(sc, MODE_DIGITAL); + break; + } + return (0); +} + +static void +emu_digitalswitch(struct emu_sc_info *sc) +{ + /* XXX temporary? */ + SYSCTL_ADD_PROC(sc->ctx, + SYSCTL_CHILDREN(sc->root), + OID_AUTO, "_digital", + CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_emu_digitalswitch_control, "I", "Enable digital output"); + + return; +} + +/* + * Allocate cache GPRs that will hold mixed output channels * and clear it on every DSP run. */ #define EFX_CACHE(CACHE_IDX) do { \ @@ -1511,7 +1635,7 @@ emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, } while (0) /* allocate GPR, OUT = IN * VOL */ -#define EFX_OUTPUT(TITLE,OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR, DEF) do { \ +#define EFX_OUTPUT(TITLE, OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR, DEF) do { \ sc->mixer_gpr[OUT_GPR_IDX] = emu_addefxmixer(sc, TITLE, OUT_GPR_IDX, DEF); \ sc->mixer_volcache[OUT_GPR_IDX] = DEF; \ emu_addefxop(sc, MACS, \ @@ -1523,29 +1647,37 @@ emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, } while (0) /* like EFX_OUTPUT, but don't allocate mixer gpr */ -#define EFX_OUTPUTD(OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR) do{ \ +#define EFX_OUTPUTD(OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR) do { \ emu_addefxop(sc, MACS, \ OUTP(OUTP_NR), \ DSP_CONST(0), \ GPR(sc->cache_gpr[OUT_CACHE_IDX]), \ GPR(sc->mixer_gpr[OUT_GPR_IDX]), \ &pc); \ -} while(0) +} while (0) -/* mute, if FLAG != 0 */ -/* XXX */ -#define EFX_MUTEIF(GPR_IDX, FLAG) do { \ -} while(0) +/* skip next OPCOUNT instructions if FLAG != 0 */ +#define EFX_SKIP(OPCOUNT, FLAG_GPR) do { \ + emu_addefxop(sc, MACS, \ + DSP_CONST(0), \ + GPR(sc->mute_gpr[FLAG_GPR]), \ + DSP_CONST(0), \ + DSP_CONST(0), \ + &pc); \ + emu_addefxop(sc, SKIP, \ + DSP_CCR, \ + DSP_CCR, \ + COND_NEQ_ZERO, \ + OPCOUNT, \ + &pc); \ +} 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]), \ +#define EFX_COPY(TO, FROM) do { \ + emu_addefxop(sc, ACC3, \ + TO, \ DSP_CONST(0), \ DSP_CONST(0), \ + FROM, \ &pc); \ } while (0) @@ -1573,9 +1705,16 @@ emu_initefx(struct emu_sc_info *sc) } } + /* allocate GPRs for mute switches (EFX_SKIP). Mute by default */ + for (i = 0; i < NUM_MUTE; i++) { + sc->mute_gpr[i] = emu_rm_gpr_alloc(sc->rm, 1); + emumix_set_gpr(sc, sc->mute_gpr[i], 1); + } + emu_digitalswitch(sc); + pc = 0; - /* + /* * DSP code below is not good, because: * 1. It can be written smaller, if it can use DSP accumulator register * instead of cache_gpr[]. @@ -1598,8 +1737,8 @@ emu_initefx(struct emu_sc_info *sc) /* fx0 to front/record, 100%/muted by default */ EFX_ROUTE("pcm_front_l", FX(0), M_FX0_FRONT_L, C_FRONT_L, 100); EFX_ROUTE("pcm_front_r", FX(1), M_FX1_FRONT_R, C_FRONT_R, 100); - EFX_ROUTE("pcm_rec_l", FX(0), M_FX0_REC_L, C_REC_L, 0); - EFX_ROUTE("pcm_rec_r", FX(1), M_FX1_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0); /* in0, from AC97 codec output */ EFX_ROUTE("ac97_front_l", INP(IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 0); @@ -1608,114 +1747,193 @@ emu_initefx(struct emu_sc_info *sc) EFX_ROUTE("ac97_rec_r", INP(IN_AC97_R), M_IN0_REC_R, C_REC_R, 0); /* 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); - 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 -#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); - EFX_ROUTE("toslink_rec_l", INP(IN_TOSLINK_L), M_IN3_REC_L, C_REC_L, 0); - EFX_ROUTE("toslink_rec_r", INP(IN_TOSLINK_R), M_IN3_REC_R, C_REC_R, 0); -#endif + /* XXX EFX_SKIP 4 assumes that each EFX_ROUTE is one DSP op */ + EFX_SKIP(4, CDSPDIFMUTE); + EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); + + if (sc->dbg_level > 0) { + /* 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); + } + + /* in3, TOSLink */ + EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_REC_R, C_REC_R, 0); /* in4, LineIn */ - EFX_ROUTE("linein_front_l", INP(IN_LINE1_L), M_IN4_FRONT_L, C_FRONT_L, 0); - EFX_ROUTE("linein_front_r", INP(IN_LINE1_R), M_IN4_FRONT_R, C_FRONT_R, 0); - EFX_ROUTE("linein_rec_l", INP(IN_LINE1_L), M_IN4_REC_L, C_REC_L, 0); - EFX_ROUTE("linein_rec_r", INP(IN_LINE1_R), M_IN4_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_REC_R, C_REC_R, 0); /* in5, on-card S/PDIF */ - EFX_ROUTE("spdif_front_l", INP(IN_COAX_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); - EFX_ROUTE("spdif_front_r", INP(IN_COAX_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); - EFX_ROUTE("spdif_rec_l", INP(IN_COAX_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); - EFX_ROUTE("spdif_rec_r", INP(IN_COAX_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); /* in6, Line2 on Live!Drive */ - EFX_ROUTE("line2_front_l", INP(IN_LINE2_L), M_IN6_FRONT_L, C_FRONT_L, 0); - 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); -#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 hedaphones and both analog and digital */ + EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_REC_R, C_REC_R, 0); + + if (sc->dbg_level > 0) { + /* 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); + } + + /* 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); + /* S/PDIF */ + EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_TOSLINK_L); + EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_TOSLINK_R); + /* Headphones */ 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); EFX_OUTPUT("master_rec_r", C_REC_R, M_MASTER_REC_R, OUT_ADC_REC_R, 100); -#ifdef SND_EMU10KX_MULTICHANNEL - /* - * Additional channel volume is controlled by mixer in - * emu_dspmixer_set() in -pcm.c - */ - /* fx2/3 (pcm1) to rear */ - EFX_CACHE(C_REAR_L); - EFX_CACHE(C_REAR_R); - EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); - EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); + if (!(sc->mch_disabled)) { + /* + * Additional channel volume is controlled by mixer in + * emu_dspmixer_set() in -pcm.c + */ + + /* fx2/3 (pcm1) to rear */ + EFX_CACHE(C_REAR_L); + EFX_CACHE(C_REAR_R); + EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); + EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); + + 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); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER); + + /* 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); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB); + + } + } else { + /* SND_EMU10KX_MULTICHANNEL_DISABLED */ + EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_REAR_L, OUT_REAR_L, 57); /* 75%*75% */ + EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_REAR_R, OUT_REAR_R, 57); /* 75%*75% */ - 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); + /* XXX 5.1 does not work */ - } -#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); + if (sc->has_51) { + /* (fx0+fx1)/2 to center */ + EFX_CACHE(C_CENTER); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_L]), + &pc); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_R]), + &pc); + EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER); + + /* (fx0+fx1)/2 to sub */ + EFX_CACHE(C_SUB); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_L]), + &pc); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_R]), + &pc); + /* XXX add lowpass filter here */ + + EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB); + } #endif + } /* !mch_disabled */ + if (sc->mch_rec) { + /* + * MCH RECORDING , hight 16 slots. On 5.1 cards first 4 slots + * are used as outputs and already filled with data + */ + /* + * XXX On Live! cards stream does not begin at zero offset. + * It can be HW, driver or sound buffering problem. + * Use sync substream (offset 0x3E) to let userland find + * correct data. + */ + + /* + * Substream map (in byte offsets, each substream is 2 bytes): + * 0x00..0x1E - outputs + * 0x20..0x3E - FX, inputs ans sync stream + */ + + /* First 2 channels (offset 0x20,0x22) are empty */ + for(i = (sc->has_51 ? 2 : 0); i < 2; i++) + EFX_COPY(FX2(i), DSP_CONST(0)); + + /* PCM Playback monitoring, offset 0x24..0x2A */ + for(i = 0; i < 4; i++) + EFX_COPY(FX2(i+2), FX(i)); + + /* Copy of some inputs, offset 0x2C..0x3C */ + for(i = 0; i < 9; i++) + EFX_COPY(FX2(i+8), INP(i)); + + /* sync data (0xc0de, offset 0x3E) */ + sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1); + emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000); + + EFX_COPY(FX2(15), GPR(sc->dummy_gpr)); + } /* mch_rec */ } else /* emu10k2 and later */ { EFX_CACHE(C_FRONT_L); EFX_CACHE(C_FRONT_R); @@ -1729,58 +1947,62 @@ emu_initefx(struct emu_sc_info *sc) */ EFX_ROUTE(NULL, FX(0), M_FX0_FRONT_L, C_FRONT_L, 100); EFX_ROUTE(NULL, FX(1), M_FX1_FRONT_R, C_FRONT_R, 100); - EFX_ROUTE("pcm_rec_l", FX(0), M_FX0_REC_L, C_REC_L, 0); - EFX_ROUTE("pcm_rec_r", FX(1), M_FX1_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0); /* in0, from AC97 codec output */ - EFX_ROUTE("ac97_front_l", INP(A_IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 100); - EFX_ROUTE("ac97_front_r", INP(A_IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 100); - EFX_ROUTE("ac97_rec_l", INP(A_IN_AC97_L), M_IN0_REC_L, C_REC_L, 0); - EFX_ROUTE("ac97_rec_r", INP(A_IN_AC97_R), M_IN0_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 100); + EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 100); + EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_REC_R, C_REC_R, 0); /* in1, from CD S/PDIF */ - EFX_ROUTE("cdspdif_front_l", INP(A_IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); - EFX_ROUTE("cdspdif_front_r", INP(A_IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); - EFX_ROUTE("cdspdif_rec_l", INP(A_IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); - EFX_ROUTE("cdspdif_rec_r", INP(A_IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, 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); -#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); - EFX_ROUTE("in3_rec_l", INP(0x6), M_IN3_REC_L, C_REC_L, 0); - EFX_ROUTE("in3_rec_r", INP(0x7), M_IN3_REC_R, C_REC_R, 0); -#endif + EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_REC_R, C_REC_R, 0); + + if (sc->dbg_level > 0) { + /* 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); + EFX_ROUTE("in3_rec_l", INP(0x6), M_IN3_REC_L, C_REC_L, 0); + EFX_ROUTE("in3_rec_r", INP(0x7), M_IN3_REC_R, C_REC_R, 0); + } + /* in4, LineIn 2 on AudigyDrive */ - EFX_ROUTE("linein2_front_l", INP(A_IN_LINE2_L), M_IN4_FRONT_L, C_FRONT_L, 0); - EFX_ROUTE("linein2_front_r", INP(A_IN_LINE2_R), M_IN4_FRONT_R, C_FRONT_R, 0); - EFX_ROUTE("linein2_rec_l", INP(A_IN_LINE2_L), M_IN4_REC_L, C_REC_L, 0); - EFX_ROUTE("linein2_rec_r", INP(A_IN_LINE2_R), M_IN4_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_REC_R, C_REC_R, 0); /* in5, on-card S/PDIF */ - EFX_ROUTE("spdif_front_l", INP(A_IN_R_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); - EFX_ROUTE("spdif_front_r", INP(A_IN_R_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); - EFX_ROUTE("spdif_rec_l", INP(A_IN_R_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); - EFX_ROUTE("spdif_rec_r", INP(A_IN_R_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); + EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_REC_R, C_REC_R, 0); /* in6, AUX2 on AudigyDrive */ - EFX_ROUTE("aux2_front_l", INP(A_IN_AUX2_L), M_IN6_FRONT_L, C_FRONT_L, 0); - 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); -#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 + EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_FRONT_L, C_FRONT_L, 0); + EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_FRONT_R, C_FRONT_R, 0); + EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_REC_L, C_REC_L, 0); + EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_REC_R, C_REC_R, 0); + + if (sc->dbg_level > 0) { + /* 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); + } + /* front output to headphones and alog and digital *front */ /* volume controlled by AC97 emulation */ EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_FRONT_L, 100); @@ -1794,73 +2016,142 @@ emu_initefx(struct emu_sc_info *sc) /* volume controlled by AC97 emulation */ EFX_OUTPUT(NULL, C_REC_L, M_MASTER_REC_L, A_OUT_ADC_REC_L, 100); EFX_OUTPUT(NULL, C_REC_R, M_MASTER_REC_R, A_OUT_ADC_REC_R, 100); -#ifdef SND_EMU10KX_MULTICHANNEL - /* - * Additional channel volume is controlled by mixer in - * emu_dspmixer_set() in -pcm.c - */ - /* fx2/3 (pcm1) to rear */ - EFX_CACHE(C_REAR_L); - EFX_CACHE(C_REAR_R); - EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); - EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); + if (!(sc->mch_disabled)) { + /* + * Additional channel volume is controlled by mixer in + * emu_dspmixer_set() in -pcm.c + */ + + /* fx2/3 (pcm1) to rear */ + EFX_CACHE(C_REAR_L); + EFX_CACHE(C_REAR_R); + EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100); + EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100); - EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, A_OUT_A_REAR_L, 100); - EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, A_OUT_A_REAR_R, 100); - EFX_OUTPUTD(C_REAR_L, M_MASTER_REAR_L, A_OUT_D_REAR_L); - EFX_OUTPUTD(C_REAR_R, M_MASTER_REAR_R, A_OUT_D_REAR_R); + EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, A_OUT_A_REAR_L, 100); + EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, A_OUT_A_REAR_R, 100); + EFX_OUTPUTD(C_REAR_L, M_MASTER_REAR_L, A_OUT_D_REAR_L); + EFX_OUTPUTD(C_REAR_R, M_MASTER_REAR_R, A_OUT_D_REAR_R); - /* 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, A_OUT_D_CENTER, 100); + /* 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, A_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, A_OUT_A_CENTER); + /* + * XXX in digital mode (default) this should be muted + * because this output is shared with digital out + */ + EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_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, A_OUT_D_SUB, 100); + /* 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, A_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, A_OUT_A_SUB); + /* + * XXX in digital mode (default) this should be muted + * because this output is shared with digital out + */ + EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB); #endif - if (sc->has_71) { - /* XXX this will broke headphones on AudigyDrive */ - /* fx6/7 (pcm4) to side */ - EFX_CACHE(C_SIDE_L); - EFX_CACHE(C_SIDE_R); - EFX_ROUTE(NULL, FX(6), M_FX6_SIDE_L, C_SIDE_L, 100); - EFX_ROUTE(NULL, FX(7), M_FX7_SIDE_R, C_SIDE_R, 100); - EFX_OUTPUT(NULL, C_SIDE_L, M_MASTER_SIDE_L, A_OUT_A_SIDE_L, 100); - EFX_OUTPUT(NULL, C_SIDE_R, M_MASTER_SIDE_R, A_OUT_A_SIDE_R, 100); - 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); + if (sc->has_71) { + /* XXX this will broke headphones on AudigyDrive */ + /* fx6/7 (pcm4) to side */ + EFX_CACHE(C_SIDE_L); + EFX_CACHE(C_SIDE_R); + EFX_ROUTE(NULL, FX(6), M_FX6_SIDE_L, C_SIDE_L, 100); + EFX_ROUTE(NULL, FX(7), M_FX7_SIDE_R, C_SIDE_R, 100); + EFX_OUTPUT(NULL, C_SIDE_L, M_MASTER_SIDE_L, A_OUT_A_SIDE_L, 100); + EFX_OUTPUT(NULL, C_SIDE_R, M_MASTER_SIDE_R, A_OUT_A_SIDE_R, 100); + 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); + } + } else { /* mch_disabled */ + 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); + + EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_REAR_L); + EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_REAR_R); - EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_REAR_L); - EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_REAR_R); + if (sc->has_51) { + /* (fx0+fx1)/2 to center */ + EFX_CACHE(C_CENTER); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_L]), + &pc); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_CENTER]), + GPR(sc->cache_gpr[C_CENTER]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_R]), + &pc); + EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER); + + /* (fx0+fx1)/2 to sub */ + EFX_CACHE(C_SUB); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_SUB]), + GPR(sc->cache_gpr[C_SUB]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_L]), + &pc); + emu_addefxop(sc, MACS, + GPR(sc->cache_gpr[C_SUB]), + GPR(sc->cache_gpr[C_SUB]), + DSP_CONST(0xd), /* = 1/2 */ + GPR(sc->cache_gpr[C_FRONT_R]), + &pc); + /* XXX add lowpass filter here */ + + EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100); + + /* XXX in digital mode (default) this should be muted because + this output is shared with digital out */ + EFX_SKIP(1, ANALOGMUTE); + EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB); + } + } /* mch_disabled */ + if (sc->mch_rec) { + /* MCH RECORDING, high 32 slots */ + + /* + * Stream map (in byte offsets): + * 0x00..0x3E - outputs + * 0x40..0x7E - FX, inputs + * each substream is 2 bytes. + */ + /* + * XXX Audigy 2 Value cards (and, possibly, + * Audigy 4) write some unknown data in place of + * some outputs (offsets 0x20..0x3F) and one + * input (offset 0x7E). + */ + + /* PCM Playback monitoring, offsets 0x40..0x5E */ + for(i = 0; i < 16; i++) + EFX_COPY(FX2(i), FX(i)); + + /* Copy of all inputs, offsets 0x60..0x7E */ + for(i = 0; i < 16; i++) + EFX_COPY(FX2(i+16), INP(i)); +#if 0 + /* XXX Audigy seems to work correct and does not need this */ + /* sync data (0xc0de), offset 0x7E */ + sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1); + emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000); + EFX_COPY(FX2(31), GPR(sc->dummy_gpr)); #endif + } /* mch_rec */ } sc->routing_code_end = pc; @@ -2007,6 +2298,8 @@ emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s) if (device_is_attached(sc->midi[0])) { sbuf_printf(s, "\tIR reciever MIDI events %s\n", sc->enable_ir ? "enabled" : "disabled"); } + sbuf_printf(s, "Card is in %s mode\n", (sc->mode == MODE_ANALOG) ? "analog" : "digital"); + sbuf_finish(s); return (sbuf_len(s)); } @@ -2017,7 +2310,7 @@ emu10kx_dev_init(struct emu_sc_info *sc) { int unit; - mtx_init(&sc->emu10kx_lock, "kxdevlock", NULL, 0); + mtx_init(&sc->emu10kx_lock, device_get_nameunit(sc->dev), "kxdevlock", 0); unit = device_get_unit(sc->dev); sc->cdev = make_dev(&emu10kx_cdevsw, unit2minor(unit), UID_ROOT, GID_WHEEL, 0640, "emu10kx%d", unit); @@ -2031,20 +2324,15 @@ emu10kx_dev_init(struct emu_sc_info *sc) static int emu10kx_dev_uninit(struct emu_sc_info *sc) { - intrmask_t s; - - s = spltty(); mtx_lock(&sc->emu10kx_lock); if (sc->emu10kx_isopen) { mtx_unlock(&sc->emu10kx_lock); - splx(s); return (EBUSY); } if (sc->cdev) destroy_dev(sc->cdev); sc->cdev = 0; - splx(s); mtx_destroy(&sc->emu10kx_lock); return (0); } @@ -2065,11 +2353,13 @@ emu_rm_init(struct emu_sc_info *sc) rm->card = sc; maxcount = sc->num_gprs; rm->num_used = 0; - mtx_init(&(rm->gpr_lock), "emu10k", "gpr alloc", MTX_DEF); + mtx_init(&(rm->gpr_lock), device_get_nameunit(sc->dev), "gpr alloc", MTX_DEF); rm->num_gprs = (maxcount < EMU_MAX_GPR ? maxcount : EMU_MAX_GPR); for (i = 0; i < rm->num_gprs; i++) rm->allocmap[i] = 0; - rm->last_free_gpr = 0; + /* pre-allocate gpr[0] */ + rm->allocmap[0] = 1; + rm->last_free_gpr = 1; return (0); } @@ -2077,15 +2367,16 @@ emu_rm_init(struct emu_sc_info *sc) int emu_rm_uninit(struct emu_sc_info *sc) { -#ifdef SND_EMU10KX_DEBUG int i; - mtx_lock(&(sc->rm->gpr_lock)); - for (i = 0; i < sc->rm->last_free_gpr; i++) - if (sc->rm->allocmap[i] > 0) - device_printf(sc->dev, "rm: gpr %d not free before uninit\n", i); - mtx_unlock(&(sc->rm->gpr_lock)); -#endif + if (sc->dbg_level > 1) { + mtx_lock(&(sc->rm->gpr_lock)); + for (i = 1; i < sc->rm->last_free_gpr; i++) + if (sc->rm->allocmap[i] > 0) + device_printf(sc->dev, "rm: gpr %d not free before uninit\n", i); + mtx_unlock(&(sc->rm->gpr_lock)); + } + mtx_destroy(&(sc->rm->gpr_lock)); free(sc->rm, M_DEVBUF); return (0); @@ -2169,7 +2460,7 @@ emumix_set_mode(struct emu_sc_info *sc, int mode) if (mode == MODE_DIGITAL) { if (sc->broken_digital) { - device_printf(sc->dev, "Digital mode is reported as broken on this card,\n"); + device_printf(sc->dev, "Digital mode is reported as broken on this card.\n"); } a_iocfg |= A_IOCFG_ENABLE_DIGITAL; hcfg |= HCFG_GPOUT0; @@ -2182,12 +2473,21 @@ emumix_set_mode(struct emu_sc_info *sc, int mode) a_iocfg |= 0x80; /* XXX */ if ((sc->is_ca0102) || (sc->is_ca0108)) - a_iocfg |= A_IOCFG_DISABLE_ANALOG; /* means "don't disable" - on this two cards. Means "disable" on emu10k2. */ + /* + * Setting A_IOCFG_DISABLE_ANALOG will do opposite things + * on diffrerent cards. + * "don't disable analog outs" on Audigy 2 (ca0102/ca0108) + * "disable analog outs" on Audigy (emu10k2) + */ + a_iocfg |= A_IOCFG_DISABLE_ANALOG; if (sc->is_ca0108) a_iocfg |= 0x20; /* XXX */ + /* Mute analog center & subwoofer before mode change */ + if (mode == MODE_DIGITAL) + emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 1); + emu_wr(sc, HCFG, hcfg, 4); if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) { @@ -2196,11 +2496,12 @@ emumix_set_mode(struct emu_sc_info *sc, int mode) emu_wr(sc, A_IOCFG, tmp, 2); } - /* - * XXX Mute center/sub if we go digital on Audigy or later card. - * Route to analog center / sub in emu_initef should be disabled - * until this problem is fixed. - */ + /* Unmute if we have changed mode to analog. */ + + if (mode == MODE_ANALOG) + emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 0); + + sc->mode = mode; } void @@ -2293,6 +2594,14 @@ emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol) void emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val) { + if (sc->dbg_level > 1) + if (gpr == 0) { + device_printf(sc->dev, "Zero gpr write access\n"); +#ifdef KDB + kdb_backtrace(); +#endif + return; + } emu_wrptr(sc, 0, GPR(gpr), val); } @@ -2398,6 +2707,7 @@ emu_init(struct emu_sc_info *sc) return (ENOMEM); } + sc->mem.card = sc; SLIST_INIT(&sc->mem.blocks); sc->mem.ptb_pages = emu_malloc(&sc->mem, EMU_MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr); if (sc->mem.ptb_pages == NULL) @@ -2633,16 +2943,29 @@ emu_read_ivar(device_t bus, device_t dev, int ivar_index, uintptr_t * result) struct sndcard_func *func = device_get_ivars(dev); struct emu_sc_info *sc = device_get_softc(bus); + if (func==NULL) + return (ENOMEM); + if (sc == NULL) + return (ENOMEM); + switch (ivar_index) { case EMU_VAR_FUNC: *result = func->func; break; case EMU_VAR_ROUTE: + if (func->varinfo == NULL) + return (ENOMEM); *result = ((struct emu_pcminfo *)func->varinfo)->route; break; case EMU_VAR_ISEMU10K1: *result = sc->is_emu10k1; break; + case EMU_VAR_MCH_DISABLED: + *result = sc->mch_disabled; + break; + case EMU_VAR_MCH_REC: + *result = sc->mch_rec; + break; default: return (ENOENT); } @@ -2686,6 +3009,9 @@ emu_pci_probe(device_t dev) sbuf_finish(s); device_set_desc_copy(dev, sbuf_data(s)); + + sbuf_delete(s); + return (BUS_PROBE_DEFAULT); } @@ -2696,23 +3022,58 @@ emu_pci_attach(device_t dev) struct sndcard_func *func; struct emu_sc_info *sc; struct emu_pcminfo *pcminfo; - struct emu_midiinfo *midiinfo[3]; +#if 0 + struct emu_midiinfo *midiinfo; +#endif uint32_t data; int i; int device_flags; char status[255]; int error = ENXIO; + int unit; sc = device_get_softc(dev); + unit = device_get_unit(dev); + + if (resource_disabled("emu10kx", unit)) { + device_printf(dev, "disabled by kernel hints\n"); + return (ENXIO); /* XXX to avoid unit reuse */ + } + + /* Get configuration */ + + sc->ctx = device_get_sysctl_ctx(dev); + if (sc->ctx == NULL) + goto bad; + sc->root = device_get_sysctl_tree(dev); + if (sc->root == NULL) + goto bad; + + if (resource_int_value("emu10kx", unit, "multichannel_disabled", &(sc->mch_disabled))) + RANGE(sc->mch_disabled, 0, 1); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "multichannel_disabled", CTLFLAG_RD, &(sc->mch_disabled), 0, "Multichannel playback setting"); + + if (resource_int_value("emu10kx", unit, "multichannel_recording", &(sc->mch_rec))) + RANGE(sc->mch_rec, 0, 1); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "multichannel_recording", CTLFLAG_RD, &(sc->mch_rec), 0, "Multichannel recording setting"); + + if (resource_int_value("emu10kx", unit, "debug", &(sc->dbg_level))) + RANGE(sc->mch_rec, 0, 2); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "debug", CTLFLAG_RW, &(sc->dbg_level), 0, "Debug level"); /* Fill in the softc. */ - mtx_init(&sc->lock, "emu10kx", "bridge conf", MTX_DEF); - mtx_init(&sc->rw, "emu10kx", "atomic op", MTX_DEF); + mtx_init(&sc->lock, device_get_nameunit(dev), "bridge conf", MTX_DEF); + mtx_init(&sc->rw, device_get_nameunit(dev), "exclusive io", MTX_DEF); sc->dev = dev; sc->type = pci_get_devid(dev); sc->rev = pci_get_revid(dev); sc->enable_ir = 0; - sc->enable_debug = 0; sc->has_ac97 = 0; sc->has_51 = 0; sc->has_71 = 0; @@ -2759,8 +3120,8 @@ 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; - - /* DSP map */ + + /* DSP map */ /* sc->fx_base = 0x0 */ sc->input_base = 0x40; /* sc->p16vinput_base = 0x50; */ @@ -2785,7 +3146,7 @@ emu_pci_attach(device_t dev) sc->address_mask = A_PTR_ADDRESS_MASK; } if (sc->is_emu10k1) { - sc->has_51 = 0; /* We don't support 5.1 sound Live! 5.1 */ + sc->has_51 = 0; /* We don't support 5.1 sound on SB Live! 5.1 */ sc->opcode_shift = 20; sc->high_operand_shift = 10; sc->code_base = MICROCODEBASE; @@ -2795,8 +3156,8 @@ 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! + /* + * 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! */ @@ -2832,7 +3193,7 @@ emu_pci_attach(device_t dev) i = 0; sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE | RF_SHAREABLE); - if ((sc->irq == NULL) || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) { + if ((sc->irq == NULL) || bus_setup_intr(dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV, NULL, emu_intr, sc, &sc->ih)) { device_printf(dev, "unable to map interrupt\n"); goto bad; } @@ -2845,17 +3206,11 @@ emu_pci_attach(device_t dev) device_printf(dev, "unable to initialize CardBus interface\n"); goto bad; } - sc->ctx = device_get_sysctl_ctx(dev); - if (sc->ctx == NULL) - goto bad; - sc->root = device_get_sysctl_tree(dev); - if (sc->root == NULL) - goto bad; - if (emu_init(sc) == -1) { + if (emu_init(sc) != 0) { device_printf(dev, "unable to initialize the card\n"); goto bad; } - if (emu10kx_dev_init(sc) == ENXIO) { + if (emu10kx_dev_init(sc) != 0) { device_printf(dev, "unable to create control device\n"); goto bad; } @@ -2876,6 +3231,9 @@ emu_pci_attach(device_t dev) } /* PCM Audio */ + for (i = 0; i < RT_COUNT; i++) + sc->pcm[i] = NULL; + /* FRONT */ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); if (func == NULL) { @@ -2895,27 +3253,8 @@ emu_pci_attach(device_t dev) 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) { - 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_REAR; - - func->func = SCF_PCM; - func->varinfo = pcminfo; - sc->pcm[RT_REAR] = device_add_child(dev, "pcm", -1); - device_set_ivars(sc->pcm[RT_REAR], func); - if (sc->has_51) { - /* CENTER */ + if (!(sc->mch_disabled)) { + /* REAR */ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); if (func == NULL) { error = ENOMEM; @@ -2927,33 +3266,73 @@ emu_pci_attach(device_t dev) goto bad; } pcminfo->card = sc; - pcminfo->route = RT_CENTER; + pcminfo->route = RT_REAR; func->func = SCF_PCM; func->varinfo = pcminfo; - sc->pcm[RT_CENTER] = device_add_child(dev, "pcm", -1); - device_set_ivars(sc->pcm[RT_CENTER], func); - /* SUB */ - func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); - if (func == NULL) { - error = ENOMEM; - goto bad; + sc->pcm[RT_REAR] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_REAR], func); + if (sc->has_51) { + /* CENTER */ + 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_CENTER; + + func->func = SCF_PCM; + func->varinfo = pcminfo; + sc->pcm[RT_CENTER] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_CENTER], func); + /* SUB */ + 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_SUB; + + func->func = SCF_PCM; + func->varinfo = pcminfo; + sc->pcm[RT_SUB] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_SUB], func); } - pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO); - if (pcminfo == NULL) { - error = ENOMEM; - goto bad; + if (sc->has_71) { + /* SIDE */ + 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_SIDE; + + func->func = SCF_PCM; + func->varinfo = pcminfo; + sc->pcm[RT_SIDE] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_SIDE], func); } - pcminfo->card = sc; - pcminfo->route = RT_SUB; + } /* mch_disabled */ - func->func = SCF_PCM; - func->varinfo = pcminfo; - sc->pcm[RT_SUB] = device_add_child(dev, "pcm", -1); - device_set_ivars(sc->pcm[RT_SUB], func); - } - if (sc->has_71) { - /* SIDE */ + if (sc->mch_rec) { func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); if (func == NULL) { error = ENOMEM; @@ -2965,36 +3344,19 @@ emu_pci_attach(device_t dev) goto bad; } pcminfo->card = sc; - pcminfo->route = RT_SIDE; + pcminfo->route = RT_MCHRECORD; func->func = SCF_PCM; func->varinfo = pcminfo; - 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; + sc->pcm[RT_MCHRECORD] = device_add_child(dev, "pcm", -1); + device_set_ivars(sc->pcm[RT_MCHRECORD], func); + } /*mch_rec */ - 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 */ + for (i = 0; i < 2; i++) + sc->midi[i] = NULL; + /* MIDI has some memory mangament and (possible) locking problems */ +#if 0 /* Midi Interface 1: Live!, Audigy, Audigy 2 */ if ((sc->is_emu10k1) || (sc->is_emu10k2) || (sc->is_ca0102)) { func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); @@ -3002,22 +3364,22 @@ emu_pci_attach(device_t dev) error = ENOMEM; goto bad; } - midiinfo[0] = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); - if (midiinfo[0] == NULL) { + midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (midiinfo == NULL) { error = ENOMEM; goto bad; } - midiinfo[0]->card = sc; + midiinfo->card = sc; if (sc->is_emu10k2 || (sc->is_ca0102)) { - midiinfo[0]->port = A_MUDATA1; - midiinfo[0]->portnr = 1; + midiinfo->port = A_MUDATA1; + midiinfo->portnr = 1; } if (sc->is_emu10k1) { - midiinfo[0]->port = MUDATA; - midiinfo[0]->portnr = 1; + midiinfo->port = MUDATA; + midiinfo->portnr = 1; } func->func = SCF_MIDI; - func->varinfo = midiinfo[0]; + func->varinfo = midiinfo; sc->midi[0] = device_add_child(dev, "midi", -1); device_set_ivars(sc->midi[0], func); } @@ -3028,22 +3390,22 @@ emu_pci_attach(device_t dev) error = ENOMEM; goto bad; } - midiinfo[1] = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); - if (midiinfo[1] == NULL) { + midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (midiinfo == NULL) { error = ENOMEM; goto bad; } - midiinfo[1]->card = sc; + midiinfo->card = sc; - midiinfo[1]->port = A_MUDATA2; - midiinfo[1]->portnr = 2; + midiinfo->port = A_MUDATA2; + midiinfo->portnr = 2; func->func = SCF_MIDI; - func->varinfo = midiinfo[1]; + func->varinfo = midiinfo; sc->midi[1] = device_add_child(dev, "midi", -1); device_set_ivars(sc->midi[1], func); } - +#endif return (bus_generic_attach(dev)); bad: @@ -3058,8 +3420,8 @@ bad: bus_teardown_intr(dev, sc->irq, sc->ih); if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); - mtx_destroy(&sc->lock); mtx_destroy(&sc->rw); + mtx_destroy(&sc->lock); return (error); } @@ -3067,38 +3429,68 @@ static int emu_pci_detach(device_t dev) { struct emu_sc_info *sc; + struct sndcard_func *func; int devcount, i; device_t *childlist; int r = 0; sc = device_get_softc(dev); - + for (i = 0; i < RT_COUNT; i++) { - if (sc->pcm[i] != NULL) + if (sc->pcm[i] != NULL) { + func = device_get_ivars(sc->pcm[i]); + if (func != NULL && func->func == SCF_PCM) { + device_set_ivars(sc->pcm[i], NULL); + free(func->varinfo, M_DEVBUF); + free(func, M_DEVBUF); + } r = device_delete_child(dev, sc->pcm[i]); - if (r) - return (r); + if (r) return (r); + } } - if (sc->midi[0] != NULL) + + if (sc->midi[0] != NULL) { + func = device_get_ivars(sc->midi[0]); + if (func != NULL && func->func == SCF_MIDI) { + device_set_ivars(sc->midi[0], NULL); + free(func->varinfo, M_DEVBUF); + free(func, M_DEVBUF); + } r = device_delete_child(dev, sc->midi[0]); - if (r) - return (r); - if (sc->midi[1] != NULL) + if (r) return (r); + } + + if (sc->midi[1] != NULL) { + func = device_get_ivars(sc->midi[1]); + if (func != NULL && func->func == SCF_MIDI) { + device_set_ivars(sc->midi[1], NULL); + free(func->varinfo, M_DEVBUF); + free(func, M_DEVBUF); + } r = device_delete_child(dev, sc->midi[1]); - if (r) - return (r); - (void)device_get_children(dev, &childlist, &devcount); - for (i = 0; i < devcount - 1; i++) { - device_printf(dev, "removing stale child %d (unit %d)\n", i, device_get_unit(childlist[i])); - device_delete_child(dev, childlist[i]); + if (r) return (r); } - free(childlist, M_TEMP); - /* shutdown chip */ - emu_uninit(sc); + if (device_get_children(dev, &childlist, &devcount) == 0) + for (i = 0; i < devcount - 1; i++) { + device_printf(dev, "removing stale child %d (unit %d)\n", i, device_get_unit(childlist[i])); + func = device_get_ivars(childlist[i]); + if (func != NULL && (func->func == SCF_MIDI || func->func == SCF_PCM)) { + device_set_ivars(childlist[i], NULL); + free(func->varinfo, M_DEVBUF); + free(func, M_DEVBUF); + } + device_delete_child(dev, childlist[i]); + } + if (childlist != NULL) + free(childlist, M_TEMP); + r = emu10kx_dev_uninit(sc); if (r) return (r); + + /* shutdown chip */ + emu_uninit(sc); emu_rm_uninit(sc); if (sc->mem.dmat) @@ -3108,8 +3500,9 @@ emu_pci_detach(device_t dev) bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg); bus_teardown_intr(dev, sc->irq, sc->ih); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); - mtx_destroy(&sc->lock); mtx_destroy(&sc->rw); + mtx_destroy(&sc->lock); + return (bus_generic_detach(dev)); } /* add suspend, resume */ diff --git a/sys/dev/sound/pci/emu10kx.h b/sys/dev/sound/pci/emu10kx.h index 302f175dc53f..d27c9db4fc3f 100644 --- a/sys/dev/sound/pci/emu10kx.h +++ b/sys/dev/sound/pci/emu10kx.h @@ -38,7 +38,8 @@ #define EMUPAGESIZE 4096 #define NUM_G 64 -#define EMU_PLAY_BUFSZ EMUPAGESIZE*16 +/* XXX some (empty) samples are played when play buffer is > EMUPAGESIZE */ +#define EMU_PLAY_BUFSZ EMUPAGESIZE /* Recording is limited by EMUPAGESIZE*16=64K buffer */ #define EMU_REC_BUFSZ EMUPAGESIZE*16 #define EMU_MAX_BUFSZ EMUPAGESIZE*16 @@ -48,6 +49,8 @@ #define EMU_VAR_FUNC 0 #define EMU_VAR_ROUTE 1 #define EMU_VAR_ISEMU10K1 2 +#define EMU_VAR_MCH_DISABLED 3 +#define EMU_VAR_MCH_REC 4 #define RT_FRONT 0 #define RT_REAR 1 diff --git a/sys/modules/sound/driver/emu10kx/Makefile b/sys/modules/sound/driver/emu10kx/Makefile index ea26ddd3e93a..3037af765e66 100644 --- a/sys/modules/sound/driver/emu10kx/Makefile +++ b/sys/modules/sound/driver/emu10kx/Makefile @@ -2,10 +2,7 @@ .PATH: ${.CURDIR}/../../../../dev/sound/pci \ ${.CURDIR}/../../../../gnu/dev/sound/pci -WARNS?= 2 ## because sound is WARNS=2 only -## WARNS=3 fails on _class.refs in -pcm.c -## WARNS=4 fails on min/max in sound headers -## otherwise it should be WARNS=6 clean +WARNS?= 2 KMOD= snd_emu10kx SRCS= device_if.h bus_if.h pci_if.h @@ -40,12 +37,4 @@ CLEANFILES+= emu10k1-alsa%diked.h CLEANFILES+= p16v-alsa%diked.h CLEANFILES+= p17v-alsa%diked.h -.if !defined(KERNBUILDDIR) -opt_emu10kx.h: - echo "#define SND_EMU10KX_MULTICHANNEL" > opt_emu10kx.h - echo "#undef 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 <bsd.kmod.mk> |
