1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00

Extend the emu10kx driver. With the words of the author:

---snip---
New features:
1.	Optional multichannel recording (32 channels on Live!, 64 channels
 	on Audigy).

 	All channels are 16bit/48000Hz/mono, format is fixed.
 	Half of them are copied from sound output, another half can be
 	used to record any data from DSP. What should be recorded is
 	hardcoded in DSP code. In this version it records dummy data, but
 	can be used to record all DSP inputs, for example..

 	Because there are no support of more-than-stereo sound streams
 	multichannell stream is presented as one 32(64)*48000 Hz 16bit mono
 	stream.

 	Channel map:

 	SB Live! (4.0/5.1)
 	offset (words)	substream
 	0x00		Front L
 	0x01		Front R
 	0x02		Digital Front L
 	0x03		Digital Front R
 	0x04		Digital Center
 	0x05		Digital Sub
 	0x06		Headphones L
 	0x07		Headphones R
 	0x08		Rear L
 	0x09		Rear R
 	0x0A		ADC (multi-rate recording) L
 	0x0B		ADC (multi-rate recording) R
 	0x0C		unused
 	0x0D		unused
 	0x0E		unused
 	0x0F		unused
 	0x10		Analog Center (Live! 5.1) / dummy (Live! 4.0)
 	0x11		Analog Sub (Live! 5.1) / dummy (Live! 4.0)
 	0x12..-0x1F	dummy

 	Audigy / Audigy 2 / Audigy 2 Value / Audigy 4
 	offset (words)	substream
 	0x00		Digital Front L
 	0x01		Digital Front R
 	0x02		Digital Center
 	0x03		Digital Sub
 	0x04		Digital Side L (7.1 cards) / Headphones L (5.1 cards)
 	0x05		Digital Side R (7.1 cards) / Headphones R (5.1 cards)
 	0x06		Digital Rear L
 	0x07		Digital Rear R
 	0x08		Front L
 	0x09		Front R
 	0x0A		Center
 	0x0B		Sub
 	0x0C		Side L
 	0x0D		Side R
 	0x0E		Rear L
 	0x0F		Rear R
 	0x10		output to AC97 input L (muted)
 	0x11		output to AC97 input R (muted)
 	0x12		unused
 	0x13		unused
 	0x14		unused
 	0x15		unused
 	0x16		ADC (multi-rate recording) L
 	0x17		ADC (multi-rate recording) R
 	0x18		unused
 	0x19		unused
 	0x1A		unused
 	0x1B		unused
 	0x1C		unused
 	0x1D		unused
 	0x1E		unused
 	0x1F		unused
 	0x20..0x3F	dummy

Fixes:
1.	Do not assign negative values to variables used to index emu_cards
 	array. This array was never accessed when index is negative, but
 	Alexander (netchild@) told me that Coverity does not like it.
 	After this change emu_cards[0] should never be used to identify
 	valid sound card.
2.	Fix off-by-one errors in interrupt manager. Add more checks there.
3.	Fixes to sound buffering code now allows driver to use large playback
 	buffers.
4.	Fix memory allocation bug when multichannel recording is not
 	enabled.
5.	Fix interrupt timeout when recording with low bitrate (8kHz).

Hardware:
1.	Add one more known Audigy ZS card to list. Add two cards with
 	PCI IDs betwen old known cards and new one.

Other changes:
1.	Do not use ALL CAPS in messages.

Incomplete code:
1.	Automute S/PDIF when S/PDIF signal is lost.

Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only).
---snip---

This commits enables a little bit of debugging output when the driver is
loaded as a module. I did a cross-build test for amd64.

The code has some style issues, this will be addressed later.

The multichannel recording part is some work in progress to allow playing
around with it until the generic sound code is better able to handle
multichannel streams.

This is supposed to fix
CID:		171187
Found by:	Coverity Prevent

Submitted by:	Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
This commit is contained in:
Alexander Leidinger 2007-01-06 18:59:35 +00:00
parent 4f383e20a9
commit f856af0466
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=165833
4 changed files with 403 additions and 64 deletions

View File

@ -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);

View File

@ -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;
/* DSP map */
/* sc->fx_base = 0x0 */
sc->input_base = 0x40;
/* sc->p16vinput_base = 0x50; */
sc->output_base = 0x60;
sc->efxc_base = 0x80;
/* 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->gpr_base = A_FXGPREGBASE;
sc->num_gprs = 0x200;
sc->input_base = 0x40;
/* sc->p16vinput_base = 0x50; */
sc->output_base = 0x60;
sc->efxc_base = 0x80;
/* sc->output32h_base = 0xa0; */
/* sc->output32l_base = 0xb0; */
sc->dsp_zero = 0xc0;
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)

View File

@ -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 */

View File

@ -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>