Add Audigy support.
I started with a year-old patch by Orlando Bassotto <orlando.bassotto@ieo-research.it>, and ported it to 5.2-CURRENT along with fixing the problems working with pre-Audigy cards.
This commit is contained in:
parent
804517817f
commit
21f1e37cbd
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2004 David O'Brien <obrien@FreeBSD.org>
|
||||
* Copyright (c) 2003 Orlando Bassotto <orlando.bassotto@ieo-research.it>
|
||||
* Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -28,6 +29,7 @@
|
||||
#include <dev/sound/pcm/sound.h>
|
||||
#include <dev/sound/pcm/ac97.h>
|
||||
#include <gnu/dev/sound/pci/emu10k1.h>
|
||||
#include <gnu/dev/sound/pci/emu10k1-alsa%diked.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
@ -40,14 +42,30 @@ SND_DECLARE_FILE("$FreeBSD$");
|
||||
#define NUM_G 64 /* use all channels */
|
||||
#define WAVEOUT_MAXBUFSIZE 32768
|
||||
#define EMUPAGESIZE 4096 /* don't change */
|
||||
#define MAXPAGES (WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE)
|
||||
#define EMU10K1_PCI_ID 0x00021102
|
||||
#define EMU10K2_PCI_ID 0x00041102
|
||||
#define EMUMAXPAGES (WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE)
|
||||
#define EMU10K1_PCI_ID 0x00021102 /* 1102 => Creative Labs Vendor ID */
|
||||
#define EMU10K2_PCI_ID 0x00041102
|
||||
#define EMU_DEFAULT_BUFSZ 4096
|
||||
#define EMU_MAX_CHANS 8
|
||||
#define EMU_CHANS 4
|
||||
|
||||
#define MAXREQVOICES 8
|
||||
#define RESERVED 0
|
||||
#define NUM_MIDI 16
|
||||
#define NUM_FXSENDS 4
|
||||
|
||||
#define TMEMSIZE 256*1024
|
||||
#define TMEMSIZEREG 4
|
||||
|
||||
#define ENABLE 0xffffffff
|
||||
#define DISABLE 0x00000000
|
||||
#define ENV_ON DCYSUSV_CHANNELENABLE_MASK
|
||||
#define ENV_OFF 0x00 /* XXX: should this be 1? */
|
||||
|
||||
#define A_IOCFG_GPOUT_A 0x40 /* Analog Output */
|
||||
#define A_IOCFG_GPOUT_D 0x04 /* Digital Output */
|
||||
#define A_IOCFG_GPOUT_AD (A_IOCFG_GPOUT_A|A_IOCFG_GPOUT_D) /* A_IOCFG_GPOUT0 */
|
||||
|
||||
struct emu_memblk {
|
||||
SLIST_ENTRY(emu_memblk) link;
|
||||
void *buf;
|
||||
@ -56,7 +74,7 @@ struct emu_memblk {
|
||||
};
|
||||
|
||||
struct emu_mem {
|
||||
u_int8_t bmap[MAXPAGES / 8];
|
||||
u_int8_t bmap[EMUMAXPAGES / 8];
|
||||
u_int32_t *ptb_pages;
|
||||
void *silent_page;
|
||||
bus_addr_t silent_page_addr;
|
||||
@ -69,6 +87,8 @@ struct emu_voice {
|
||||
int b16:1, stereo:1, busy:1, running:1, ismaster:1;
|
||||
int speed;
|
||||
int start, end, vol;
|
||||
int fxrt1; /* FX routing */
|
||||
int fxrt2; /* FX routing (only for audigy) */
|
||||
u_int32_t buf;
|
||||
struct emu_voice *slave;
|
||||
struct pcm_channel *channel;
|
||||
@ -97,7 +117,8 @@ struct sc_rchinfo {
|
||||
struct sc_info {
|
||||
device_t dev;
|
||||
u_int32_t type, rev;
|
||||
u_int32_t tos_link:1, APS:1;
|
||||
u_int32_t tos_link:1, APS:1, audigy:1, audigy2:1;
|
||||
u_int32_t addrmask; /* wider if audigy */
|
||||
|
||||
bus_space_tag_t st;
|
||||
bus_space_handle_t sh;
|
||||
@ -110,9 +131,10 @@ struct sc_info {
|
||||
unsigned int bufsz;
|
||||
int timer, timerinterval;
|
||||
int pnum, rnum;
|
||||
int nchans;
|
||||
struct emu_mem mem;
|
||||
struct emu_voice voice[64];
|
||||
struct sc_pchinfo pch[EMU_CHANS];
|
||||
struct sc_pchinfo pch[EMU_MAX_CHANS];
|
||||
struct sc_rchinfo rch[3];
|
||||
};
|
||||
|
||||
@ -172,6 +194,10 @@ static u_int32_t emu_pfmt[] = {
|
||||
static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
|
||||
|
||||
static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000};
|
||||
/* audigy supports 12kHz. */
|
||||
static int audigy_adcspeed[9] = {
|
||||
48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Hardware */
|
||||
@ -211,7 +237,7 @@ emu_rdptr(struct sc_info *sc, int chn, int reg)
|
||||
{
|
||||
u_int32_t ptr, val, mask, size, offset;
|
||||
|
||||
ptr = ((reg << 16) & PTR_ADDRESS_MASK) | (chn & PTR_CHANNELNUM_MASK);
|
||||
ptr = ((reg << 16) & sc->addrmask) | (chn & PTR_CHANNELNUM_MASK);
|
||||
emu_wr(sc, PTR, ptr, 4);
|
||||
val = emu_rd(sc, DATA, 4);
|
||||
if (reg & 0xff000000) {
|
||||
@ -229,7 +255,7 @@ emu_wrptr(struct sc_info *sc, int chn, int reg, u_int32_t data)
|
||||
{
|
||||
u_int32_t ptr, mask, size, offset;
|
||||
|
||||
ptr = ((reg << 16) & PTR_ADDRESS_MASK) | (chn & PTR_CHANNELNUM_MASK);
|
||||
ptr = ((reg << 16) & sc->addrmask) | (chn & PTR_CHANNELNUM_MASK);
|
||||
emu_wr(sc, PTR, ptr, 4);
|
||||
if (reg & 0xff000000) {
|
||||
size = (reg >> 24) & 0x3f;
|
||||
@ -245,7 +271,8 @@ emu_wrptr(struct sc_info *sc, int chn, int reg, u_int32_t data)
|
||||
static void
|
||||
emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data)
|
||||
{
|
||||
emu_wrptr(sc, 0, MICROCODEBASE + pc, data);
|
||||
pc += sc->audigy ? AUDIGY_CODEBASE : MICROCODEBASE;
|
||||
emu_wrptr(sc, 0, pc, data);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@ -288,10 +315,11 @@ emu_settimer(struct sc_info *sc)
|
||||
int i, tmp, rate;
|
||||
|
||||
rate = 0;
|
||||
for (i = 0; i < EMU_CHANS; i++) {
|
||||
for (i = 0; i < sc->nchans; i++) {
|
||||
pch = &sc->pch[i];
|
||||
if (pch->buffer) {
|
||||
tmp = (pch->spd * sndbuf_getbps(pch->buffer)) / pch->blksz;
|
||||
tmp = (pch->spd * sndbuf_getbps(pch->buffer))
|
||||
/ pch->blksz;
|
||||
if (tmp > rate)
|
||||
rate = tmp;
|
||||
}
|
||||
@ -300,7 +328,8 @@ emu_settimer(struct sc_info *sc)
|
||||
for (i = 0; i < 3; i++) {
|
||||
rch = &sc->rch[i];
|
||||
if (rch->buffer) {
|
||||
tmp = (rch->spd * sndbuf_getbps(rch->buffer)) / rch->blksz;
|
||||
tmp = (rch->spd * sndbuf_getbps(rch->buffer))
|
||||
/ rch->blksz;
|
||||
if (tmp > rate)
|
||||
rate = tmp;
|
||||
}
|
||||
@ -351,6 +380,16 @@ emu_recval(int speed) {
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
audigy_recval(int speed) {
|
||||
int val;
|
||||
|
||||
val = 0;
|
||||
while (val < 8 && speed < audigy_adcspeed[val])
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
emu_rate_to_pitch(u_int32_t rate)
|
||||
{
|
||||
@ -453,6 +492,16 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
|
||||
m->vol = 0xff;
|
||||
m->buf = tmp_addr;
|
||||
m->slave = s;
|
||||
if (sc->audigy) {
|
||||
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_LEFT << 8 |
|
||||
FXBUS_PCM_RIGHT << 16 | FXBUS_MIDI_REVERB << 24;
|
||||
m->fxrt2 = 0x3f3f3f3f; /* No effects on second route */
|
||||
} else {
|
||||
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_LEFT << 4 |
|
||||
FXBUS_PCM_RIGHT << 8 | FXBUS_MIDI_REVERB << 12;
|
||||
m->fxrt2 = 0;
|
||||
}
|
||||
|
||||
if (s != NULL) {
|
||||
s->start = m->start;
|
||||
s->end = m->end;
|
||||
@ -464,6 +513,8 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
|
||||
s->ismaster = 0;
|
||||
s->vol = m->vol;
|
||||
s->buf = m->buf;
|
||||
s->fxrt1 = m->fxrt1;
|
||||
s->fxrt2 = m->fxrt2;
|
||||
s->slave = NULL;
|
||||
}
|
||||
return 0;
|
||||
@ -512,7 +563,13 @@ emu_vwrite(struct sc_info *sc, struct emu_voice *v)
|
||||
val *= v->b16 ? 1 : 2;
|
||||
start = sa + val;
|
||||
|
||||
emu_wrptr(sc, v->vnum, FXRT, 0xd01c0000);
|
||||
if (sc->audigy) {
|
||||
emu_wrptr(sc, v->vnum, A_FXRT1, v->fxrt1);
|
||||
emu_wrptr(sc, v->vnum, A_FXRT2, v->fxrt2);
|
||||
emu_wrptr(sc, v->vnum, A_SENDAMOUNTS, 0);
|
||||
}
|
||||
else
|
||||
emu_wrptr(sc, v->vnum, FXRT, v->fxrt1 << 16);
|
||||
|
||||
emu_wrptr(sc, v->vnum, PTRX, (x << 8) | r);
|
||||
emu_wrptr(sc, v->vnum, DSL, ea | (y << 24));
|
||||
@ -522,7 +579,8 @@ emu_vwrite(struct sc_info *sc, struct emu_voice *v)
|
||||
emu_wrptr(sc, v->vnum, Z1, 0);
|
||||
emu_wrptr(sc, v->vnum, Z2, 0);
|
||||
|
||||
silent_page = ((u_int32_t)(sc->mem.silent_page_addr) << 1) | MAP_PTI_MASK;
|
||||
silent_page = ((u_int32_t)(sc->mem.silent_page_addr) << 1)
|
||||
| MAP_PTI_MASK;
|
||||
emu_wrptr(sc, v->vnum, MAPA, silent_page);
|
||||
emu_wrptr(sc, v->vnum, MAPB, silent_page);
|
||||
|
||||
@ -537,7 +595,8 @@ emu_vwrite(struct sc_info *sc, struct emu_voice *v)
|
||||
emu_wrptr(sc, v->vnum, FM2FRQ2, 0);
|
||||
emu_wrptr(sc, v->vnum, ENVVAL, 0x8000);
|
||||
|
||||
emu_wrptr(sc, v->vnum, ATKHLDV, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
|
||||
emu_wrptr(sc, v->vnum, ATKHLDV,
|
||||
ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
|
||||
emu_wrptr(sc, v->vnum, ENVVOL, 0x8000);
|
||||
|
||||
emu_wrptr(sc, v->vnum, PEFE_FILTERAMOUNT, 0x7f);
|
||||
@ -613,6 +672,12 @@ emu_vdump(struct sc_info *sc, struct emu_voice *v)
|
||||
"ip", "ifatn", "pefe", "fmmod", "tremfrq", "fmfrq2",
|
||||
"tempenv"
|
||||
};
|
||||
char *regname2[] = {
|
||||
"mudata1", "mustat1", "mudata2", "mustat2",
|
||||
"fxwc1", "fxwc2", "spdrate", NULL, NULL,
|
||||
NULL, NULL, NULL, "fxrt2", "sndamnt", "fxrt1",
|
||||
NULL, NULL
|
||||
};
|
||||
int i, x;
|
||||
|
||||
printf("voice number %d\n", v->vnum);
|
||||
@ -625,13 +690,28 @@ emu_vdump(struct sc_info *sc, struct emu_voice *v)
|
||||
if (x > 2)
|
||||
x = 0;
|
||||
}
|
||||
|
||||
/* Print out audigy extra registers */
|
||||
if (sc->audigy) {
|
||||
for (i = 0; i <= 0xe; i++) {
|
||||
if (regname2[i] == NULL)
|
||||
continue;
|
||||
printf("%s\t[%08x]", regname2[i],
|
||||
emu_rdptr(sc, v->vnum, i + 0x70));
|
||||
printf("%s", (x == 2)? "\n" : "\t");
|
||||
x++;
|
||||
if (x > 2)
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* channel interface */
|
||||
static void *
|
||||
emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
|
||||
emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
||||
struct pcm_channel *c, int dir)
|
||||
{
|
||||
struct sc_info *sc = devinfo;
|
||||
struct sc_pchinfo *ch;
|
||||
@ -649,7 +729,8 @@ emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
ch->master = emu_valloc(sc);
|
||||
ch->slave = emu_valloc(sc);
|
||||
snd_mtxunlock(sc->lock);
|
||||
r = (emu_vinit(sc, ch->master, ch->slave, sc->bufsz, ch->buffer)) ? NULL : ch;
|
||||
r = (emu_vinit(sc, ch->master, ch->slave, sc->bufsz, ch->buffer))
|
||||
? NULL : ch;
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -767,7 +848,8 @@ CHANNEL_DECLARE(emupchan);
|
||||
|
||||
/* channel interface */
|
||||
static void *
|
||||
emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
|
||||
emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
||||
struct pcm_channel *c, int dir)
|
||||
{
|
||||
struct sc_info *sc = devinfo;
|
||||
struct sc_rchinfo *ch;
|
||||
@ -783,7 +865,7 @@ emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel
|
||||
ch->num = sc->rnum;
|
||||
switch(sc->rnum) {
|
||||
case 0:
|
||||
ch->idxreg = ADCIDX;
|
||||
ch->idxreg = sc->audigy ? A_ADCIDX : ADCIDX;
|
||||
ch->basereg = ADCBA;
|
||||
ch->sizereg = ADCBS;
|
||||
ch->setupreg = ADCCR;
|
||||
@ -832,8 +914,12 @@ emurchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
||||
{
|
||||
struct sc_rchinfo *ch = data;
|
||||
|
||||
if (ch->num == 0)
|
||||
speed = adcspeed[emu_recval(speed)];
|
||||
if (ch->num == 0) {
|
||||
if (ch->parent->audigy)
|
||||
speed = audigy_adcspeed[audigy_recval(speed)];
|
||||
else
|
||||
speed = adcspeed[emu_recval(speed)];
|
||||
}
|
||||
if (ch->num == 1)
|
||||
speed = 48000;
|
||||
if (ch->num == 2)
|
||||
@ -897,10 +983,18 @@ emurchan_trigger(kobj_t obj, void *data, int go)
|
||||
ch->run = 1;
|
||||
emu_wrptr(sc, 0, ch->sizereg, sz);
|
||||
if (ch->num == 0) {
|
||||
val = ADCCR_LCHANENABLE;
|
||||
if (ch->fmt & AFMT_STEREO)
|
||||
val |= ADCCR_RCHANENABLE;
|
||||
val |= emu_recval(ch->spd);
|
||||
if (sc->audigy) {
|
||||
val = A_ADCCR_LCHANENABLE;
|
||||
if (ch->fmt & AFMT_STEREO)
|
||||
val |= A_ADCCR_RCHANENABLE;
|
||||
val |= audigy_recval(ch->spd);
|
||||
} else {
|
||||
val = ADCCR_LCHANENABLE;
|
||||
if (ch->fmt & AFMT_STEREO)
|
||||
val |= ADCCR_RCHANENABLE;
|
||||
val |= emu_recval(ch->spd);
|
||||
}
|
||||
|
||||
emu_wrptr(sc, 0, ch->setupreg, 0);
|
||||
emu_wrptr(sc, 0, ch->setupreg, val);
|
||||
}
|
||||
@ -982,7 +1076,7 @@ emu_intr(void *p)
|
||||
if (stat & IPR_INTERVALTIMER) {
|
||||
ack |= IPR_INTERVALTIMER;
|
||||
x = 0;
|
||||
for (i = 0; i < EMU_CHANS; i++) {
|
||||
for (i = 0; i < sc->nchans; i++) {
|
||||
if (sc->pch[i].run) {
|
||||
x = 1;
|
||||
chn_intr(sc->pch[i].channel);
|
||||
@ -1015,7 +1109,10 @@ emu_intr(void *p)
|
||||
}
|
||||
if (stat & IPR_SAMPLERATETRACKER) {
|
||||
ack |= IPR_SAMPLERATETRACKER;
|
||||
/* device_printf(sc->dev, "sample rate tracker lock status change\n"); */
|
||||
#ifdef EMUDEBUG
|
||||
device_printf(sc->dev,
|
||||
"sample rate tracker lock status change\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (stat & ~ack)
|
||||
@ -1076,7 +1173,7 @@ emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr)
|
||||
/* find a free block in the bitmap */
|
||||
found = 0;
|
||||
start = 1;
|
||||
while (!found && start + blksz < MAXPAGES) {
|
||||
while (!found && start + blksz < EMUMAXPAGES) {
|
||||
found = 1;
|
||||
for (idx = start; idx < start + blksz; idx++)
|
||||
if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
|
||||
@ -1098,12 +1195,18 @@ emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr)
|
||||
blk->buf = buf;
|
||||
blk->pte_start = start;
|
||||
blk->pte_size = blksz;
|
||||
/* printf("buf %p, pte_start %d, pte_size %d\n", blk->buf, blk->pte_start, blk->pte_size); */
|
||||
#ifdef EMUDEBUG
|
||||
printf("buf %p, pte_start %d, pte_size %d\n", blk->buf,
|
||||
blk->pte_start, blk->pte_size);
|
||||
#endif
|
||||
ofs = 0;
|
||||
for (idx = start; idx < start + blksz; idx++) {
|
||||
mem->bmap[idx >> 3] |= 1 << (idx & 7);
|
||||
tmp = (u_int32_t)(u_long)((u_int8_t *)blk->buf_addr + ofs);
|
||||
/* printf("pte[%d] -> %x phys, %x virt\n", idx, tmp, ((u_int32_t)buf) + ofs); */
|
||||
#ifdef EMUDEBUG
|
||||
printf("pte[%d] -> %x phys, %x virt\n", idx, tmp,
|
||||
((u_int32_t)buf) + ofs);
|
||||
#endif
|
||||
mem->ptb_pages[idx] = (tmp << 1) | idx;
|
||||
ofs += EMUPAGESIZE;
|
||||
}
|
||||
@ -1153,19 +1256,184 @@ emu_memstart(struct sc_info *sc, void *buf)
|
||||
}
|
||||
|
||||
static void
|
||||
emu_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y, u_int32_t *pc)
|
||||
emu_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
|
||||
u_int32_t *pc)
|
||||
{
|
||||
emu_wrefx(sc, (*pc) * 2, (x << 10) | y);
|
||||
emu_wrefx(sc, (*pc) * 2 + 1, (op << 20) | (z << 10) | w);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void
|
||||
audigy_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
|
||||
u_int32_t *pc)
|
||||
{
|
||||
emu_wrefx(sc, (*pc) * 2, (x << 12) | y);
|
||||
emu_wrefx(sc, (*pc) * 2 + 1, (op << 24) | (z << 12) | w);
|
||||
(*pc)++;
|
||||
}
|
||||
|
||||
static void
|
||||
audigy_initefx(struct sc_info *sc)
|
||||
{
|
||||
int i;
|
||||
u_int32_t pc = 0;
|
||||
|
||||
/* skip 0, 0, -1, 0 - NOPs */
|
||||
for (i = 0; i < 512; i++)
|
||||
audigy_addefxop(sc, 0x0f, 0x0c0, 0x0c0, 0x0cf, 0x0c0, &pc);
|
||||
|
||||
for (i = 0; i < 512; i++)
|
||||
emu_wrptr(sc, 0, A_FXGPREGBASE + i, 0x0);
|
||||
|
||||
pc = 16;
|
||||
|
||||
/* stop fx processor */
|
||||
emu_wrptr(sc, 0, A_DBG, A_DBG_SINGLE_STEP);
|
||||
|
||||
/* Audigy 2 (EMU10K2) DSP Registers:
|
||||
FX Bus
|
||||
0x000-0x00f : 16 registers (???)
|
||||
Input
|
||||
0x040/0x041 : AC97 Codec (l/r)
|
||||
0x042/0x043 : ADC, S/PDIF (l/r)
|
||||
0x044/0x045 : Optical S/PDIF in (l/r)
|
||||
0x046/0x047 : ???
|
||||
0x048/0x049 : Line/Mic 2 (l/r)
|
||||
0x04a/0x04b : RCA S/PDIF (l/r)
|
||||
0x04c/0x04d : Aux 2 (l/r)
|
||||
Output
|
||||
0x060/0x061 : Digital Front (l/r)
|
||||
0x062/0x063 : Digital Center/LFE
|
||||
0x064/0x065 : AudigyDrive Heaphone (l/r)
|
||||
0x066/0x067 : Digital Rear (l/r)
|
||||
0x068/0x069 : Analog Front (l/r)
|
||||
0x06a/0x06b : Analog Center/LFE
|
||||
0x06c/0x06d : ???
|
||||
0x06e/0x06f : Analog Rear (l/r)
|
||||
0x070/0x071 : AC97 Output (l/r)
|
||||
0x072/0x073 : ???
|
||||
0x074/0x075 : ???
|
||||
0x076/0x077 : ADC Recording Buffer (l/r)
|
||||
Constants
|
||||
0x0c0 - 0x0c4 = 0 - 4
|
||||
0x0c5 = 0x8, 0x0c6 = 0x10, 0x0c7 = 0x20
|
||||
0x0c8 = 0x100, 0x0c9 = 0x10000, 0x0ca = 0x80000
|
||||
0x0cb = 0x10000000, 0x0cc = 0x20000000, 0x0cd = 0x40000000
|
||||
0x0ce = 0x80000000, 0x0cf = 0x7fffffff, 0x0d0 = 0xffffffff
|
||||
0x0d1 = 0xfffffffe, 0x0d2 = 0xc0000000, 0x0d3 = 0x41fbbcdc
|
||||
0x0d4 = 0x5a7ef9db, 0x0d5 = 0x00100000, 0x0dc = 0x00000001 (???)
|
||||
Temporary Values
|
||||
0x0d6 : Accumulator (???)
|
||||
0x0d7 : Condition Register
|
||||
0x0d8 : Noise source
|
||||
0x0d9 : Noise source
|
||||
Tank Memory Data Registers
|
||||
0x200 - 0x2ff
|
||||
Tank Memory Address Registers
|
||||
0x300 - 0x3ff
|
||||
General Purpose Registers
|
||||
0x400 - 0x5ff
|
||||
*/
|
||||
|
||||
/* AC97Output[l/r] = FXBus PCM[l/r] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_L), A_C_00000000,
|
||||
A_C_00000000, A_FXBUS(FXBUS_PCM_LEFT), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_R), A_C_00000000,
|
||||
A_C_00000000, A_FXBUS(FXBUS_PCM_RIGHT), &pc);
|
||||
|
||||
/* GPR[0/1] = RCA S/PDIF[l/r] -- Master volume */
|
||||
audigy_addefxop(sc, iACC3, A_GPR(0), A_C_00000000,
|
||||
A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_L), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_GPR(1), A_C_00000000,
|
||||
A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_R), &pc);
|
||||
|
||||
/* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
|
||||
audigy_addefxop(sc, iINTERP, A_GPR(2), A_GPR(1),
|
||||
A_C_40000000, A_GPR(0), &pc);
|
||||
|
||||
/* Headphones[l/r] = GPR[0/1] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_L),
|
||||
A_C_00000000, A_C_00000000, A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_R),
|
||||
A_C_00000000, A_C_00000000, A_GPR(1), &pc);
|
||||
|
||||
/* Analog Front[l/r] = GPR[0/1] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_L), A_C_00000000,
|
||||
A_C_00000000, A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_R), A_C_00000000,
|
||||
A_C_00000000, A_GPR(1), &pc);
|
||||
|
||||
/* Digital Front[l/r] = GPR[0/1] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L), A_C_00000000,
|
||||
A_C_00000000, A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_R), A_C_00000000,
|
||||
A_C_00000000, A_GPR(1), &pc);
|
||||
|
||||
/* Center and Subwoofer configuration */
|
||||
/* Analog Center = GPR[0] + GPR[2] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ACENTER), A_C_00000000,
|
||||
A_GPR(0), A_GPR(2), &pc);
|
||||
/* Analog Sub = GPR[1] + GPR[2] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ALFE), A_C_00000000,
|
||||
A_GPR(1), A_GPR(2), &pc);
|
||||
|
||||
/* Digital Center = GPR[0] + GPR[2] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_CENTER), A_C_00000000,
|
||||
A_GPR(0), A_GPR(2), &pc);
|
||||
/* Digital Sub = GPR[1] + GPR[2] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_LFE), A_C_00000000,
|
||||
A_GPR(1), A_GPR(2), &pc);
|
||||
|
||||
#if 0
|
||||
/* Analog Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
|
||||
/* RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
|
||||
audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
|
||||
A_GPR(16), A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
|
||||
A_GPR(17), A_GPR(1), &pc);
|
||||
|
||||
/* Digital Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
|
||||
/* RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
|
||||
audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
|
||||
A_GPR(16), A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
|
||||
A_GPR(17), A_GPR(1), &pc);
|
||||
#else
|
||||
/* XXX This is just a copy to the channel, since we do not have
|
||||
* a patch manager, it is useful for have another output enabled.
|
||||
*/
|
||||
|
||||
/* Analog Rear[l/r] = GPR[0/1] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
|
||||
A_C_00000000, A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
|
||||
A_C_00000000, A_GPR(1), &pc);
|
||||
|
||||
/* Digital Rear[l/r] = GPR[0/1] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
|
||||
A_C_00000000, A_GPR(0), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
|
||||
A_C_00000000, A_GPR(1), &pc);
|
||||
#endif
|
||||
|
||||
/* ADC Recording buffer[l/r] = AC97Input[l/r] */
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_L), A_C_00000000,
|
||||
A_C_00000000, A_EXTIN(A_EXTIN_AC97_L), &pc);
|
||||
audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_R), A_C_00000000,
|
||||
A_C_00000000, A_EXTIN(A_EXTIN_AC97_R), &pc);
|
||||
|
||||
/* resume normal operations */
|
||||
emu_wrptr(sc, 0, A_DBG, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
emu_initefx(struct sc_info *sc)
|
||||
{
|
||||
int i;
|
||||
u_int32_t pc = 16;
|
||||
|
||||
/* acc3 0,0,0,0 - NOPs */
|
||||
for (i = 0; i < 512; i++) {
|
||||
emu_wrefx(sc, i * 2, 0x10040);
|
||||
emu_wrefx(sc, i * 2 + 1, 0x610040);
|
||||
@ -1181,24 +1449,34 @@ emu_initefx(struct sc_info *sc)
|
||||
0x010/0x011 : AC97 Codec (l/r)
|
||||
0x012/0x013 : ADC, S/PDIF (l/r)
|
||||
0x014/0x015 : Mic(left), Zoom (l/r)
|
||||
0x016/0x017 : APS S/PDIF?? (l/r)
|
||||
0x016/0x017 : TOS link in (l/r)
|
||||
0x018/0x019 : Line/Mic 1 (l/r)
|
||||
0x01a/0x01b : COAX S/PDIF (l/r)
|
||||
0x01c/0x01d : Line/Mic 2 (l/r)
|
||||
Output
|
||||
0x020/0x021 : AC97 Output (l/r)
|
||||
0x022/0x023 : TOS link out (l/r)
|
||||
0x024/0x025 : ??? (l/r)
|
||||
0x024/0x025 : Center/LFE
|
||||
0x026/0x027 : LiveDrive Headphone (l/r)
|
||||
0x028/0x029 : Rear Channel (l/r)
|
||||
0x02a/0x02b : ADC Recording Buffer (l/r)
|
||||
0x02c : Mic Recording Buffer
|
||||
0x031/0x032 : Analog Center/LFE
|
||||
Constants
|
||||
0x040 - 0x044 = 0 - 4
|
||||
0x045 = 0x8, 0x046 = 0x10, 0x047 = 0x20
|
||||
0x048 = 0x100, 0x049 = 0x10000, 0x04a = 0x80000
|
||||
0x04b = 0x10000000, 0x04c = 0x20000000, 0x04d = 0x40000000
|
||||
0x04e = 0x80000000, 0x04f = 0x7fffffff
|
||||
0x04e = 0x80000000, 0x04f = 0x7fffffff, 0x050 = 0xffffffff
|
||||
0x051 = 0xfffffffe, 0x052 = 0xc0000000, 0x053 = 0x41fbbcdc
|
||||
0x054 = 0x5a7ef9db, 0x055 = 0x00100000
|
||||
Temporary Values
|
||||
0x056 : Accumulator
|
||||
0x058 : Noise source?
|
||||
0x059 : Noise source?
|
||||
0x057 : Condition Register
|
||||
0x058 : Noise source
|
||||
0x059 : Noise source
|
||||
0x05a : IRQ Register
|
||||
0x05b : TRAM Delay Base Address Count
|
||||
General Purpose Registers
|
||||
0x100 - 0x1ff
|
||||
Tank Memory Data Registers
|
||||
@ -1207,40 +1485,81 @@ emu_initefx(struct sc_info *sc)
|
||||
0x300 - 0x3ff
|
||||
*/
|
||||
|
||||
/* Operators:
|
||||
0 : z := w + (x * y >> 31)
|
||||
4 : z := w + x * y
|
||||
6 : z := w + x + y
|
||||
*/
|
||||
|
||||
/* Routing - this will be configurable in later version */
|
||||
|
||||
/* GPR[0/1] = FX * 4 + SPDIF-in */
|
||||
emu_addefxop(sc, 4, 0x100, 0x12, 0, 0x44, &pc);
|
||||
emu_addefxop(sc, 4, 0x101, 0x13, 1, 0x44, &pc);
|
||||
/* GPR[0/1] += APS-input */
|
||||
emu_addefxop(sc, 6, 0x100, 0x100, 0x40, sc->APS ? 0x16 : 0x40, &pc);
|
||||
emu_addefxop(sc, 6, 0x101, 0x101, 0x40, sc->APS ? 0x17 : 0x40, &pc);
|
||||
/* FrontOut (AC97) = GPR[0/1] */
|
||||
emu_addefxop(sc, 6, 0x20, 0x40, 0x40, 0x100, &pc);
|
||||
emu_addefxop(sc, 6, 0x21, 0x40, 0x41, 0x101, &pc);
|
||||
/* RearOut = (GPR[0/1] * RearVolume) >> 31 */
|
||||
/* RearVolume = GRP[0x10/0x11] */
|
||||
emu_addefxop(sc, 0, 0x28, 0x40, 0x110, 0x100, &pc);
|
||||
emu_addefxop(sc, 0, 0x29, 0x40, 0x111, 0x101, &pc);
|
||||
/* TOS out = GPR[0/1] */
|
||||
emu_addefxop(sc, 6, 0x22, 0x40, 0x40, 0x100, &pc);
|
||||
emu_addefxop(sc, 6, 0x23, 0x40, 0x40, 0x101, &pc);
|
||||
/* Mute Out2 */
|
||||
emu_addefxop(sc, 6, 0x24, 0x40, 0x40, 0x40, &pc);
|
||||
emu_addefxop(sc, 6, 0x25, 0x40, 0x40, 0x40, &pc);
|
||||
/* Mute Out3 */
|
||||
emu_addefxop(sc, 6, 0x26, 0x40, 0x40, 0x40, &pc);
|
||||
emu_addefxop(sc, 6, 0x27, 0x40, 0x40, 0x40, &pc);
|
||||
/* Input0 (AC97) -> Record */
|
||||
emu_addefxop(sc, 6, 0x2a, 0x40, 0x40, 0x10, &pc);
|
||||
emu_addefxop(sc, 6, 0x2b, 0x40, 0x40, 0x11, &pc);
|
||||
emu_addefxop(sc, iMACINT0, GPR(0), EXTIN(EXTIN_SPDIF_CD_L),
|
||||
FXBUS(FXBUS_PCM_LEFT), C_00000004, &pc);
|
||||
emu_addefxop(sc, iMACINT0, GPR(1), EXTIN(EXTIN_SPDIF_CD_R),
|
||||
FXBUS(FXBUS_PCM_RIGHT), C_00000004, &pc);
|
||||
|
||||
/* GPR[0/1] += APS-input */
|
||||
emu_addefxop(sc, iACC3, GPR(0), GPR(0), C_00000000,
|
||||
sc->APS ? EXTIN(EXTIN_TOSLINK_L) : C_00000000, &pc);
|
||||
emu_addefxop(sc, iACC3, GPR(1), GPR(1), C_00000000,
|
||||
sc->APS ? EXTIN(EXTIN_TOSLINK_R) : C_00000000, &pc);
|
||||
|
||||
/* FrontOut (AC97) = GPR[0/1] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_L), C_00000000,
|
||||
C_00000000, GPR(0), &pc);
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_R), C_00000000,
|
||||
C_00000001, GPR(1), &pc);
|
||||
|
||||
/* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
|
||||
emu_addefxop(sc, iINTERP, GPR(2), GPR(1), C_40000000, GPR(0), &pc);
|
||||
|
||||
#if 0
|
||||
/* RearOut = (GPR[0/1] * RearVolume) >> 31 */
|
||||
/* RearVolume = GPR[0x10/0x11] */
|
||||
emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_L), C_00000000,
|
||||
GPR(16), GPR(0), &pc);
|
||||
emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_R), C_00000000,
|
||||
GPR(17), GPR(1), &pc);
|
||||
#else
|
||||
/* XXX This is just a copy to the channel, since we do not have
|
||||
* a patch manager, it is useful for have another output enabled.
|
||||
*/
|
||||
|
||||
/* Rear[l/r] = GPR[0/1] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_L), C_00000000,
|
||||
C_00000000, GPR(0), &pc);
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_R), C_00000000,
|
||||
C_00000000, GPR(1), &pc);
|
||||
#endif
|
||||
|
||||
/* TOS out[l/r] = GPR[0/1] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_L), C_00000000,
|
||||
C_00000000, GPR(0), &pc);
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_R), C_00000000,
|
||||
C_00000000, GPR(1), &pc);
|
||||
|
||||
/* Center and Subwoofer configuration */
|
||||
/* Analog Center = GPR[0] + GPR[2] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ACENTER), C_00000000,
|
||||
GPR(0), GPR(2), &pc);
|
||||
/* Analog Sub = GPR[1] + GPR[2] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ALFE), C_00000000,
|
||||
GPR(1), GPR(2), &pc);
|
||||
/* Digital Center = GPR[0] + GPR[2] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_CENTER), C_00000000,
|
||||
GPR(0), GPR(2), &pc);
|
||||
/* Digital Sub = GPR[1] + GPR[2] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_LFE), C_00000000,
|
||||
GPR(1), GPR(2), &pc);
|
||||
|
||||
/* Headphones[l/r] = GPR[0/1] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_L), C_00000000,
|
||||
C_00000000, GPR(0), &pc);
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_R), C_00000000,
|
||||
C_00000000, GPR(1), &pc);
|
||||
|
||||
/* ADC Recording buffer[l/r] = AC97Input[l/r] */
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_L), C_00000000,
|
||||
C_00000000, EXTIN(EXTIN_AC97_L), &pc);
|
||||
emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_R), C_00000000,
|
||||
C_00000000, EXTIN(EXTIN_AC97_R), &pc);
|
||||
|
||||
/* resume normal operations */
|
||||
emu_wrptr(sc, 0, DBG, 0);
|
||||
}
|
||||
|
||||
@ -1250,8 +1569,15 @@ emu_init(struct sc_info *sc)
|
||||
{
|
||||
u_int32_t spcs, ch, tmp, i;
|
||||
|
||||
if (sc->audigy) {
|
||||
/* enable additional AC97 slots */
|
||||
emu_wrptr(sc, 0, AC97SLOT, AC97SLOT_CNTR | AC97SLOT_LFE);
|
||||
}
|
||||
|
||||
/* disable audio and lock cache */
|
||||
emu_wr(sc, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, 4);
|
||||
emu_wr(sc, HCFG,
|
||||
HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
|
||||
4);
|
||||
|
||||
/* reset recording buffers */
|
||||
emu_wrptr(sc, 0, MICBS, ADCBS_BUFSIZE_NONE);
|
||||
@ -1262,12 +1588,20 @@ emu_init(struct sc_info *sc)
|
||||
emu_wrptr(sc, 0, ADCBA, 0);
|
||||
|
||||
/* disable channel interrupt */
|
||||
emu_wr(sc, INTE, INTE_INTERVALTIMERENB | INTE_SAMPLERATETRACKER | INTE_PCIERRORENABLE, 4);
|
||||
emu_wr(sc, INTE,
|
||||
INTE_INTERVALTIMERENB | INTE_SAMPLERATETRACKER | INTE_PCIERRORENABLE,
|
||||
4);
|
||||
emu_wrptr(sc, 0, CLIEL, 0);
|
||||
emu_wrptr(sc, 0, CLIEH, 0);
|
||||
emu_wrptr(sc, 0, SOLEL, 0);
|
||||
emu_wrptr(sc, 0, SOLEH, 0);
|
||||
|
||||
/* wonder what these do... */
|
||||
if (sc->audigy) {
|
||||
emu_wrptr(sc, 0, SPBYPASS, 0xf00);
|
||||
emu_wrptr(sc, 0, AC97SLOT, 0x3);
|
||||
}
|
||||
|
||||
/* init envelope engine */
|
||||
for (ch = 0; ch < NUM_G; ch++) {
|
||||
emu_wrptr(sc, ch, DCYSUSV, ENV_OFF);
|
||||
@ -1301,6 +1635,18 @@ emu_init(struct sc_info *sc)
|
||||
emu_wrptr(sc, ch, ENVVOL, 0);
|
||||
emu_wrptr(sc, ch, ENVVAL, 0);
|
||||
|
||||
if (sc->audigy) {
|
||||
/* audigy cards need this to initialize correctly */
|
||||
emu_wrptr(sc, ch, 0x4c, 0);
|
||||
emu_wrptr(sc, ch, 0x4d, 0);
|
||||
emu_wrptr(sc, ch, 0x4e, 0);
|
||||
emu_wrptr(sc, ch, 0x4f, 0);
|
||||
/* set default routing */
|
||||
emu_wrptr(sc, ch, A_FXRT1, 0x03020100);
|
||||
emu_wrptr(sc, ch, A_FXRT2, 0x3f3f3f3f);
|
||||
emu_wrptr(sc, ch, A_SENDAMOUNTS, 0);
|
||||
}
|
||||
|
||||
sc->voice[ch].vnum = ch;
|
||||
sc->voice[ch].slave = NULL;
|
||||
sc->voice[ch].busy = 0;
|
||||
@ -1337,14 +1683,35 @@ emu_init(struct sc_info *sc)
|
||||
emu_wrptr(sc, 0, SPCS1, spcs);
|
||||
emu_wrptr(sc, 0, SPCS2, spcs);
|
||||
|
||||
emu_initefx(sc);
|
||||
if (!sc->audigy)
|
||||
emu_initefx(sc);
|
||||
else if (sc->audigy2) { /* Audigy 2 */
|
||||
/* from ALSA initialization code: */
|
||||
|
||||
/* Hack for Alice3 to work independent of haP16V driver */
|
||||
u_int32_t tmp;
|
||||
|
||||
/* Setup SRCMulti_I2S SamplingRate */
|
||||
tmp = emu_rdptr(sc, 0, A_SPDIF_SAMPLERATE) & 0xfffff1ff;
|
||||
emu_wrptr(sc, 0, A_SPDIF_SAMPLERATE, tmp | 0x400);
|
||||
|
||||
/* Setup SRCSel (Enable SPDIF, I2S SRCMulti) */
|
||||
emu_wr(sc, 0x20, 0x00600000, 4);
|
||||
emu_wr(sc, 0x24, 0x00000014, 4);
|
||||
|
||||
/* Setup SRCMulti Input Audio Enable */
|
||||
emu_wr(sc, 0x20, 0x006e0000, 4);
|
||||
emu_wr(sc, 0x24, 0xff00ff00, 4);
|
||||
}
|
||||
|
||||
SLIST_INIT(&sc->mem.blocks);
|
||||
sc->mem.ptb_pages = emu_malloc(sc, MAXPAGES * sizeof(u_int32_t), &sc->mem.ptb_pages_addr);
|
||||
sc->mem.ptb_pages = emu_malloc(sc, EMUMAXPAGES * sizeof(u_int32_t),
|
||||
&sc->mem.ptb_pages_addr);
|
||||
if (sc->mem.ptb_pages == NULL)
|
||||
return -1;
|
||||
|
||||
sc->mem.silent_page = emu_malloc(sc, EMUPAGESIZE, &sc->mem.silent_page_addr);
|
||||
sc->mem.silent_page = emu_malloc(sc, EMUPAGESIZE,
|
||||
&sc->mem.silent_page_addr);
|
||||
if (sc->mem.silent_page == NULL) {
|
||||
emu_free(sc, sc->mem.ptb_pages);
|
||||
return -1;
|
||||
@ -1352,7 +1719,7 @@ emu_init(struct sc_info *sc)
|
||||
/* Clear page with silence & setup all pointers to this page */
|
||||
bzero(sc->mem.silent_page, EMUPAGESIZE);
|
||||
tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1;
|
||||
for (i = 0; i < MAXPAGES; i++)
|
||||
for (i = 0; i < EMUMAXPAGES; i++)
|
||||
sc->mem.ptb_pages[i] = tmp | i;
|
||||
|
||||
emu_wrptr(sc, 0, PTB, (sc->mem.ptb_pages_addr));
|
||||
@ -1367,26 +1734,70 @@ emu_init(struct sc_info *sc)
|
||||
/* emu_memalloc(sc, EMUPAGESIZE); */
|
||||
/*
|
||||
* Hokay, now enable the AUD bit
|
||||
*
|
||||
* Audigy
|
||||
* Enable Audio = 0 (enabled after fx processor initialization)
|
||||
* Mute Disable Audio = 0
|
||||
* Joystick = 1
|
||||
*
|
||||
* Audigy 2
|
||||
* Enable Audio = 1
|
||||
* Mute Disable Audio = 0
|
||||
* Joystick = 1
|
||||
* GP S/PDIF AC3 Enable = 1
|
||||
* CD S/PDIF AC3 Enable = 1
|
||||
*
|
||||
* EMU10K1
|
||||
* Enable Audio = 1
|
||||
* Mute Disable Audio = 0
|
||||
* Lock Tank Memory = 1
|
||||
* Lock Sound Memory = 0
|
||||
* Auto Mute = 1
|
||||
*/
|
||||
tmp = HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE;
|
||||
if (sc->rev >= 6)
|
||||
tmp |= HCFG_JOYENABLE;
|
||||
emu_wr(sc, HCFG, tmp, 4);
|
||||
|
||||
/* TOSLink detection */
|
||||
sc->tos_link = 0;
|
||||
tmp = emu_rd(sc, HCFG, 4);
|
||||
if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
|
||||
emu_wr(sc, HCFG, tmp | 0x800, 4);
|
||||
DELAY(50);
|
||||
if (tmp != (emu_rd(sc, HCFG, 4) & ~0x800)) {
|
||||
sc->tos_link = 1;
|
||||
emu_wr(sc, HCFG, tmp, 4);
|
||||
if (sc->audigy) {
|
||||
tmp = HCFG_AUTOMUTE | HCFG_JOYENABLE;
|
||||
if (sc->audigy2) /* Audigy 2 */
|
||||
tmp = HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF |
|
||||
HCFG_AC3ENABLE_GPSPDIF;
|
||||
emu_wr(sc, HCFG, tmp, 4);
|
||||
|
||||
audigy_initefx(sc);
|
||||
|
||||
/* from ALSA initialization code: */
|
||||
|
||||
/* enable audio and disable both audio/digital outputs */
|
||||
emu_wr(sc, HCFG, emu_rd(sc, HCFG, 4) | HCFG_AUDIOENABLE, 4);
|
||||
emu_wr(sc, A_IOCFG, emu_rd(sc, A_IOCFG, 4) & ~A_IOCFG_GPOUT_AD,
|
||||
4);
|
||||
if (sc->audigy2) { /* Audigy 2 */
|
||||
/* Unmute Analog.
|
||||
* Set GPO6 to 1 for Apollo. This has to be done after
|
||||
* init Alice3 I2SOut beyond 48kHz.
|
||||
* So, sequence is important.
|
||||
*/
|
||||
emu_wr(sc, A_IOCFG,
|
||||
emu_rd(sc, A_IOCFG, 4) | A_IOCFG_GPOUT_A, 4);
|
||||
}
|
||||
} else {
|
||||
/* EMU10K1 initialization code */
|
||||
tmp = HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK
|
||||
| HCFG_AUTOMUTE;
|
||||
if (sc->rev >= 6)
|
||||
tmp |= HCFG_JOYENABLE;
|
||||
|
||||
emu_wr(sc, HCFG, tmp, 4);
|
||||
|
||||
/* TOSLink detection */
|
||||
sc->tos_link = 0;
|
||||
tmp = emu_rd(sc, HCFG, 4);
|
||||
if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
|
||||
emu_wr(sc, HCFG, tmp | HCFG_GPOUT1, 4);
|
||||
DELAY(50);
|
||||
if (tmp != (emu_rd(sc, HCFG, 4) & ~HCFG_GPOUT1)) {
|
||||
sc->tos_link = 1;
|
||||
emu_wr(sc, HCFG, tmp, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1408,8 +1819,14 @@ emu_uninit(struct sc_info *sc)
|
||||
emu_wrptr(sc, ch, CPF, 0);
|
||||
}
|
||||
|
||||
if (sc->audigy) { /* stop fx processor */
|
||||
emu_wrptr(sc, 0, A_DBG, A_DBG_SINGLE_STEP);
|
||||
}
|
||||
|
||||
/* disable audio and lock cache */
|
||||
emu_wr(sc, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, 4);
|
||||
emu_wr(sc, HCFG,
|
||||
HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE,
|
||||
4);
|
||||
|
||||
emu_wrptr(sc, 0, PTB, 0);
|
||||
/* reset recording buffers */
|
||||
@ -1447,11 +1864,14 @@ emu_pci_probe(device_t dev)
|
||||
case EMU10K1_PCI_ID:
|
||||
s = "Creative EMU10K1";
|
||||
break;
|
||||
/*
|
||||
|
||||
case EMU10K2_PCI_ID:
|
||||
s = "Creative EMU10K2";
|
||||
if (pci_get_revid(dev) == 0x04)
|
||||
s = "Creative Audigy 2 (EMU10K2)";
|
||||
else
|
||||
s = "Creative Audigy (EMU10K2)";
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
return ENXIO;
|
||||
}
|
||||
@ -1478,6 +1898,10 @@ emu_pci_attach(device_t dev)
|
||||
sc->dev = dev;
|
||||
sc->type = pci_get_devid(dev);
|
||||
sc->rev = pci_get_revid(dev);
|
||||
sc->audigy = (sc->type == EMU10K2_PCI_ID);
|
||||
sc->audigy2 = (sc->audigy && sc->rev == 0x04);
|
||||
sc->nchans = sc->audigy ? 8 : 4;
|
||||
sc->addrmask = sc->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
|
||||
|
||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
|
||||
@ -1485,7 +1909,8 @@ emu_pci_attach(device_t dev)
|
||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
|
||||
i = PCIR_BAR(0);
|
||||
sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &i, 0, ~0, 1, RF_ACTIVE);
|
||||
sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &i, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
if (sc->reg == NULL) {
|
||||
device_printf(dev, "unable to map register space\n");
|
||||
goto bad;
|
||||
@ -1517,16 +1942,19 @@ emu_pci_attach(device_t dev)
|
||||
if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
|
||||
|
||||
i = 0;
|
||||
sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &i, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
|
||||
if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) {
|
||||
sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &i, 0, ~0, 1,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
if (!sc->irq ||
|
||||
snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) {
|
||||
device_printf(dev, "unable to map interrupt\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", rman_get_start(sc->reg), rman_get_start(sc->irq));
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld",
|
||||
rman_get_start(sc->reg), rman_get_start(sc->irq));
|
||||
|
||||
if (pcm_register(dev, sc, EMU_CHANS, gotmic ? 3 : 2)) goto bad;
|
||||
for (i = 0; i < EMU_CHANS; i++)
|
||||
if (pcm_register(dev, sc, sc->nchans, gotmic ? 3 : 2)) goto bad;
|
||||
for (i = 0; i < sc->nchans; i++)
|
||||
pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc);
|
||||
for (i = 0; i < (gotmic ? 3 : 2); i++)
|
||||
pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc);
|
||||
|
@ -1,9 +1,18 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../../dev/sound/pci
|
||||
.PATH: ${.CURDIR}/../../../../dev/sound/pci \
|
||||
${.CURDIR}/../../../../gnu/dev/sound/pci
|
||||
|
||||
KMOD= snd_emu10k1
|
||||
SRCS= device_if.h bus_if.h pci_if.h
|
||||
SRCS= device_if.h bus_if.h pci_if.h emu10k1-alsa%diked.h
|
||||
SRCS+= emu10k1.c
|
||||
|
||||
CLEANFILES+= emu10k1-alsa%diked.h
|
||||
|
||||
emu10k1-alsa%diked.h: emu10k1-alsa.h
|
||||
grep -v '#include' ${.OODATE} | $(CC) -E -D__KERNEL__ -dM - \
|
||||
| awk -F"[ (]" '/define/ \
|
||||
{ print "#ifndef " $$2 ; print ; print "#endif" }' \
|
||||
>${.TARGET}
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
Loading…
x
Reference in New Issue
Block a user