summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/sound/pci/emu10kx-pcm.c245
-rw-r--r--sys/dev/sound/pci/emu10kx.c204
-rw-r--r--sys/dev/sound/pci/emu10kx.h13
-rw-r--r--sys/modules/sound/driver/emu10kx/Makefile3
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 b35dc32..7ba00c1 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 d603a0b..2519285 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 7075ef9..302f175 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 f65be35..dd44711 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 <bsd.kmod.mk>
OpenPOWER on IntegriCloud