summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound
diff options
context:
space:
mode:
authorariff <ariff@FreeBSD.org>2005-11-14 18:17:31 +0000
committerariff <ariff@FreeBSD.org>2005-11-14 18:17:31 +0000
commit00b7f829bdfebf59c3bf6f11e5642fd2d19a2a52 (patch)
tree8a3324795baa4b3b04f6aa7cbeb5fc66567f6e95 /sys/dev/sound
parentc73a06dc5c92c6eb5d9f67b74be9256a207055d6 (diff)
downloadFreeBSD-src-00b7f829bdfebf59c3bf6f11e5642fd2d19a2a52.zip
FreeBSD-src-00b7f829bdfebf59c3bf6f11e5642fd2d19a2a52.tar.gz
Use both (enabled by default) DAC1 and DAC2 to provide 2
distinct hardware playback channels. DAC configuration can be accessed through kernel hint - hint.pcm.<unit>.dac="val" with following possible values: 0 = Enable both DACs (default) 1 = Enable single DAC (DAC1) 2 = Enable single DAC (DAC2) 3 = Enable both DACs, swap position (DAC2 comes first instead of DAC1) Special case for ES1370: Unlike ES1371,2,3/CT5880, volume for each DAC 1 and 2 can be controlled indepedently (synth for DAC1, pcm for DAC2). It is possible that user will confuse by this behaviour, since both DACs are enabled by default. Thus, provide a knob through sysctl hw.snd.pcm<unit>.single_pcm_mixer: 0 = each DACs will be controlled separately (synth/pcm). 1 = combine both DACs volume mixer controller into a single "pcm" (default) As a side note, fixed rate operation (provided by previous commit) is not a mandatory if the configuration space does not involve DAC2 (perhaps disabled by user through the above kernel hint). Unlike DAC2, DAC1 has its own register / control space, not affected by the speed settings of ADC. Tested by: multimedia@ Approved by: netchild (mentor)
Diffstat (limited to 'sys/dev/sound')
-rw-r--r--sys/dev/sound/pci/es137x.c578
1 files changed, 473 insertions, 105 deletions
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index 9ab68e3..f8dfed3 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -87,6 +87,15 @@ SND_DECLARE_FILE("$FreeBSD$");
#define ES_DEFAULT_BUFSZ 4096
+/* 2 DAC for playback, 1 ADC for record */
+#define ES_DAC1 0
+#define ES_DAC2 1
+#define ES_ADC 2
+#define ES_NCHANS 3
+
+#define ES1370_DAC1_MINSPEED 5512
+#define ES1370_DAC1_MAXSPEED 44100
+
/* device private data */
struct es_info;
@@ -94,10 +103,73 @@ struct es_chinfo {
struct es_info *parent;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
- int dir, num;
+ struct pcmchan_caps caps;
+ int dir, num, index;
u_int32_t fmt, blksz, bufsz;
};
+/*
+ * 32bit Ensoniq Configuration (es->escfg).
+ * ----------------------------------------
+ *
+ * +-------+--------+------+------+---------+--------+---------+---------+
+ * len | 16 | 1 | 1 | 1 | 2 | 2 | 1 | 8 |
+ * +-------+--------+------+------+---------+--------+---------+---------+
+ * | fixed | single | | | | | is | general |
+ * | rate | pcm | DACx | DACy | numplay | numrec | es1370? | purpose |
+ * | | mixer | | | | | | |
+ * +-------+--------+------+------+---------+--------+---------+---------+
+ */
+#define ES_FIXED_RATE(cfgv) \
+ (((cfgv) & 0xffff0000) >> 16)
+#define ES_SET_FIXED_RATE(cfgv, nv) \
+ (((cfgv) & ~0xffff0000) | (((nv) & 0xffff) << 16))
+#define ES_SINGLE_PCM_MIX(cfgv) \
+ (((cfgv) & 0x8000) >> 15)
+#define ES_SET_SINGLE_PCM_MIX(cfgv, nv) \
+ (((cfgv) & ~0x8000) | (((nv) ? 1 : 0) << 15))
+#define ES_DAC_FIRST(cfgv) \
+ (((cfgv) & 0x4000) >> 14)
+#define ES_SET_DAC_FIRST(cfgv, nv) \
+ (((cfgv) & ~0x4000) | (((nv) & 0x1) << 14))
+#define ES_DAC_SECOND(cfgv) \
+ (((cfgv) & 0x2000) >> 13)
+#define ES_SET_DAC_SECOND(cfgv, nv) \
+ (((cfgv) & ~0x2000) | (((nv) & 0x1) << 13))
+#define ES_NUMPLAY(cfgv) \
+ (((cfgv) & 0x1800) >> 11)
+#define ES_SET_NUMPLAY(cfgv, nv) \
+ (((cfgv) & ~0x1800) | (((nv) & 0x3) << 11))
+#define ES_NUMREC(cfgv) \
+ (((cfgv) & 0x600) >> 9)
+#define ES_SET_NUMREC(cfgv, nv) \
+ (((cfgv) & ~0x600) | (((nv) & 0x3) << 9))
+#define ES_IS_ES1370(cfgv) \
+ (((cfgv) & 0x100) >> 8)
+#define ES_SET_IS_ES1370(cfgv, nv) \
+ (((cfgv) & ~0x100) | (((nv) ? 1 : 0) << 8))
+#define ES_GP(cfgv) \
+ ((cfgv) & 0xff)
+#define ES_SET_GP(cfgv, nv) \
+ (((cfgv) & ~0xff) | ((nv) & 0xff))
+
+#define ES_DAC1_ENABLED(cfgv) \
+ (ES_NUMPLAY(cfgv) > 1 || \
+ (ES_NUMPLAY(cfgv) == 1 && ES_DAC_FIRST(cfgv) == ES_DAC1))
+#define ES_DAC2_ENABLED(cfgv) \
+ (ES_NUMPLAY(cfgv) > 1 || \
+ (ES_NUMPLAY(cfgv) == 1 && ES_DAC_FIRST(cfgv) == ES_DAC2))
+
+/*
+ * DAC 1/2 configuration through kernel hint - hint.pcm.<unit>.dac="val"
+ *
+ * 0 = Enable both DACs - Default
+ * 1 = Enable single DAC (DAC1)
+ * 2 = Enable single DAC (DAC2)
+ * 3 = Enable both DACs, swap position (DAC2 comes first instead of DAC1)
+ */
+#define ES_DEFAULT_DAC_CFG 0
+
struct es_info {
bus_space_tag_t st;
bus_space_handle_t sh;
@@ -110,12 +182,12 @@ struct es_info {
device_t dev;
int num;
unsigned int bufsz;
- struct pcmchan_caps caps;
/* Contents of board's registers */
uint32_t ctrl;
uint32_t sctrl;
- struct es_chinfo pch, rch;
+ uint32_t escfg;
+ struct es_chinfo ch[ES_NCHANS];
struct mtx *lock;
};
@@ -150,7 +222,7 @@ static const struct {
unsigned recmask:13;
unsigned avail:1;
} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 },
+ [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x1f7f, 1 },
[SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 },
[SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 },
[SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 },
@@ -200,16 +272,29 @@ es_wr(struct es_info *es, int regno, u_int32_t data, int size)
static int
es1370_mixinit(struct snd_mixer *m)
{
+ struct es_info *es;
int i;
u_int32_t v;
+ es = mix_getdevinfo(m);
v = 0;
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
if (mixtable[i].avail) v |= (1 << i);
+ /*
+ * Each DAC1/2 for ES1370 can be controlled independently
+ * DAC1 = controlled by synth
+ * DAC2 = controlled by pcm
+ * This is indeed can confuse user if DAC1 become primary playback
+ * channel. Try to be smart and combine both if necessary.
+ */
+ if (ES_SINGLE_PCM_MIX(es->escfg))
+ v &= ~(1 << SOUND_MIXER_SYNTH);
mix_setdevs(m, v);
v = 0;
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
if (mixtable[i].recmask) v |= (1 << i);
+ if (ES_SINGLE_PCM_MIX(es->escfg)) /* ditto */
+ v &= ~(1 << SOUND_MIXER_SYNTH);
mix_setrecdevs(m, v);
return 0;
}
@@ -218,7 +303,7 @@ static int
es1370_mixset(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct es_info *es;
- int l, r, rl, rr;
+ int l, r, rl, rr, set_dac1;
if (!mixtable[dev].avail) return -1;
l = left;
@@ -230,11 +315,21 @@ es1370_mixset(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
es = mix_getdevinfo(m);
ES_LOCK(es);
+ if (dev == SOUND_MIXER_PCM && (ES_SINGLE_PCM_MIX(es->escfg)) &&
+ ES_DAC1_ENABLED(es->escfg)) {
+ set_dac1 = 1;
+ } else {
+ set_dac1 = 0;
+ }
if (mixtable[dev].stereo) {
rr = (r < 10)? 0x80 : 15 - (r - 10) / 6;
es1370_wrcodec(es, mixtable[dev].right, rr);
+ if (set_dac1 && mixtable[SOUND_MIXER_SYNTH].stereo)
+ es1370_wrcodec(es, mixtable[SOUND_MIXER_SYNTH].right, rr);
}
es1370_wrcodec(es, mixtable[dev].left, rl);
+ if (set_dac1)
+ es1370_wrcodec(es, mixtable[SOUND_MIXER_SYNTH].left, rl);
ES_UNLOCK(es);
return l | (r << 8);
@@ -253,6 +348,10 @@ es1370_mixsetrecsrc(struct snd_mixer *m, u_int32_t src)
if ((src & (1 << i)) != 0) j |= mixtable[i].recmask;
ES_LOCK(es);
+ if ((src & (1 << SOUND_MIXER_PCM)) && ES_SINGLE_PCM_MIX(es->escfg) &&
+ ES_DAC1_ENABLED(es->escfg)) {
+ j |= mixtable[SOUND_MIXER_SYNTH].recmask;
+ }
es1370_wrcodec(es, CODEC_LIMIX1, j & 0x55);
es1370_wrcodec(es, CODEC_RIMIX1, j & 0xaa);
es1370_wrcodec(es, CODEC_LIMIX2, (j >> 8) & 0x17);
@@ -301,22 +400,75 @@ static void *
eschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct es_info *es = devinfo;
- struct es_chinfo *ch = (dir == PCMDIR_PLAY)? &es->pch : &es->rch;
+ struct es_chinfo *ch;
+ uint32_t index;
+ ES_LOCK(es);
+
+ if (dir == PCMDIR_PLAY) {
+ index = ES_GP(es->escfg);
+ es->escfg = ES_SET_GP(es->escfg, index + 1);
+ if (index == 0) {
+ index = ES_DAC_FIRST(es->escfg);
+ } else if (index == 1) {
+ index = ES_DAC_SECOND(es->escfg);
+ } else {
+ device_printf(es->dev, "Invalid ES_GP index: %d\n", index);
+ ES_UNLOCK(es);
+ return NULL;
+ }
+ if (!(index == ES_DAC1 || index == ES_DAC2)) {
+ device_printf(es->dev, "Unknown DAC: %d\n",
+ index + 1);
+ ES_UNLOCK(es);
+ return NULL;
+ }
+ if (es->ch[index].channel != NULL) {
+ device_printf(es->dev, "DAC%d already initialized!\n",
+ index + 1);
+ ES_UNLOCK(es);
+ return NULL;
+ }
+ } else
+ index = ES_ADC;
+
+ ch = &es->ch[index];
+ ch->index = index;
+ ch->num = es->num++;
+ ch->caps = es_caps;
+ if (ES_IS_ES1370(es->escfg)) {
+ if (ch->index == ES_DAC1) {
+ ch->caps.maxspeed = ES1370_DAC1_MAXSPEED;
+ ch->caps.minspeed = ES1370_DAC1_MINSPEED;
+ } else {
+ uint32_t fixed_rate = ES_FIXED_RATE(es->escfg);
+ if (!(fixed_rate < es_caps.minspeed ||
+ fixed_rate > es_caps.maxspeed)) {
+ ch->caps.maxspeed = fixed_rate;
+ ch->caps.minspeed = fixed_rate;
+ }
+ }
+ }
ch->parent = es;
ch->channel = c;
ch->buffer = b;
ch->bufsz = es->bufsz;
ch->blksz = ch->bufsz / 2;
- ch->num = ch->parent->num++;
ch->dir = dir;
+ ES_UNLOCK(es);
if (sndbuf_alloc(ch->buffer, es->parent_dmat, ch->bufsz) != 0)
return NULL;
ES_LOCK(es);
if (dir == PCMDIR_PLAY) {
- es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC2_FRAMEADR >> 8, 1);
- es_wr(es, ES1370_REG_DAC2_FRAMEADR & 0xff, sndbuf_getbufaddr(ch->buffer), 4);
- es_wr(es, ES1370_REG_DAC2_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
+ if (ch->index == ES_DAC1) {
+ es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC1_FRAMEADR >> 8, 1);
+ es_wr(es, ES1370_REG_DAC1_FRAMEADR & 0xff, sndbuf_getbufaddr(ch->buffer), 4);
+ es_wr(es, ES1370_REG_DAC1_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
+ } else {
+ es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC2_FRAMEADR >> 8, 1);
+ es_wr(es, ES1370_REG_DAC2_FRAMEADR & 0xff, sndbuf_getbufaddr(ch->buffer), 4);
+ es_wr(es, ES1370_REG_DAC2_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
+ }
} else {
es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_ADC_FRAMEADR >> 8, 1);
es_wr(es, ES1370_REG_ADC_FRAMEADR & 0xff, sndbuf_getbufaddr(ch->buffer), 4);
@@ -334,9 +486,15 @@ eschan_setformat(kobj_t obj, void *data, u_int32_t format)
ES_LOCK(es);
if (ch->dir == PCMDIR_PLAY) {
- es->sctrl &= ~SCTRL_P2FMT;
- if (format & AFMT_S16_LE) es->sctrl |= SCTRL_P2SEB;
- if (format & AFMT_STEREO) es->sctrl |= SCTRL_P2SMB;
+ if (ch->index == ES_DAC1) {
+ es->sctrl &= ~SCTRL_P1FMT;
+ if (format & AFMT_S16_LE) es->sctrl |= SCTRL_P1SEB;
+ if (format & AFMT_STEREO) es->sctrl |= SCTRL_P1SMB;
+ } else {
+ es->sctrl &= ~SCTRL_P2FMT;
+ if (format & AFMT_S16_LE) es->sctrl |= SCTRL_P2SEB;
+ if (format & AFMT_STEREO) es->sctrl |= SCTRL_P2SMB;
+ }
} else {
es->sctrl &= ~SCTRL_R1FMT;
if (format & AFMT_S16_LE) es->sctrl |= SCTRL_R1SEB;
@@ -354,23 +512,41 @@ eschan1370_setspeed(kobj_t obj, void *data, u_int32_t speed)
struct es_chinfo *ch = data;
struct es_info *es = ch->parent;
- /* XXX Fixed rate , do nothing. */
+ /* Fixed rate , do nothing. */
+ if (ch->caps.minspeed == ch->caps.maxspeed)
+ return ch->caps.maxspeed;
+ if (speed < ch->caps.minspeed)
+ speed = ch->caps.minspeed;
+ if (speed > ch->caps.maxspeed)
+ speed = ch->caps.maxspeed;
ES_LOCK(es);
- if (es->caps.minspeed == es->caps.maxspeed) {
- speed = es->caps.maxspeed;
- ES_UNLOCK(es);
- return speed;
+ if (ch->index == ES_DAC1) {
+ /*
+ * DAC1 does not support continuous rate settings.
+ * Pick the nearest and use it since FEEDER_RATE will
+ * do the the proper conversion for us.
+ */
+ es->ctrl &= ~CTRL_WTSRSEL;
+ if (speed < 8268) {
+ speed = 5512;
+ es->ctrl |= 0 << CTRL_SH_WTSRSEL;
+ } else if (speed < 16537) {
+ speed = 11025;
+ es->ctrl |= 1 << CTRL_SH_WTSRSEL;
+ } else if (speed < 33075) {
+ speed = 22050;
+ es->ctrl |= 2 << CTRL_SH_WTSRSEL;
+ } else {
+ speed = 44100;
+ es->ctrl |= 3 << CTRL_SH_WTSRSEL;
+ }
+ } else {
+ es->ctrl &= ~CTRL_PCLKDIV;
+ es->ctrl |= DAC2_SRTODIV(speed) << CTRL_SH_PCLKDIV;
}
- if (speed < es->caps.minspeed)
- speed = es->caps.minspeed;
- if (speed > es->caps.maxspeed)
- speed = es->caps.maxspeed;
- es->ctrl &= ~CTRL_PCLKDIV;
- es->ctrl |= DAC2_SRTODIV(speed) << CTRL_SH_PCLKDIV;
es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4);
ES_UNLOCK(es);
- /* rec/play speeds locked together - should indicate in flags */
- return speed; /* XXX calc real speed */
+ return speed;
}
static int
@@ -378,13 +554,14 @@ eschan1371_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct es_chinfo *ch = data;
struct es_info *es = ch->parent;
- int i, delta;
+ uint32_t i;
+ int delta;
ES_LOCK(es);
if (ch->dir == PCMDIR_PLAY)
- i = es1371_dac_rate(es, speed, 3 - ch->num); /* play */
+ i = es1371_dac_rate(es, speed, ch->index); /* play */
else
- i = es1371_adc_rate(es, speed, 1); /* record */
+ i = es1371_adc_rate(es, speed, ch->index); /* record */
ES_UNLOCK(es);
delta = (speed > i) ? speed - i : i - speed;
if (delta < 2)
@@ -420,30 +597,43 @@ eschan_trigger(kobj_t obj, void *data, int go)
{
struct es_chinfo *ch = data;
struct es_info *es = ch->parent;
- unsigned cnt;
+ uint32_t cnt, b = 0;
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
cnt = (ch->blksz / sndbuf_getbps(ch->buffer)) - 1;
-
+ if (ch->fmt & AFMT_16BIT)
+ b |= 0x02;
+ if (ch->fmt & AFMT_STEREO)
+ b |= 0x01;
ES_LOCK(es);
if (ch->dir == PCMDIR_PLAY) {
if (go == PCMTRIG_START) {
- int b = (ch->fmt & AFMT_S16_LE)? 2 : 1;
- es->ctrl |= CTRL_DAC2_EN;
- es->sctrl &= ~(SCTRL_P2ENDINC | SCTRL_P2STINC | SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN);
- es->sctrl |= SCTRL_P2INTEN | (b << SCTRL_SH_P2ENDINC);
- es_wr(es, ES1370_REG_DAC2_SCOUNT, cnt, 4);
- /* start at beginning of buffer */
- es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC2_FRAMECNT >> 8, 4);
- es_wr(es, ES1370_REG_DAC2_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
- } else es->ctrl &= ~CTRL_DAC2_EN;
+ if (ch->index == ES_DAC1) {
+ es->ctrl |= CTRL_DAC1_EN;
+ es->sctrl &= ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD);
+ es->sctrl |= SCTRL_P1INTEN | b;
+ es_wr(es, ES1370_REG_DAC1_SCOUNT, cnt, 4);
+ /* start at beginning of buffer */
+ es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC1_FRAMECNT >> 8, 4);
+ es_wr(es, ES1370_REG_DAC1_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
+ } else {
+ es->ctrl |= CTRL_DAC2_EN;
+ es->sctrl &= ~(SCTRL_P2ENDINC | SCTRL_P2STINC | SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN);
+ es->sctrl |= SCTRL_P2INTEN | (b << 2) |
+ (((b & 2) ? : 1) << SCTRL_SH_P2ENDINC);
+ es_wr(es, ES1370_REG_DAC2_SCOUNT, cnt, 4);
+ /* start at beginning of buffer */
+ es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_DAC2_FRAMECNT >> 8, 4);
+ es_wr(es, ES1370_REG_DAC2_FRAMECNT & 0xff, (ch->bufsz >> 2) - 1, 4);
+ }
+ } else es->ctrl &= ~(ch->index == ES_DAC1 ? CTRL_DAC1_EN : CTRL_DAC2_EN);
} else {
if (go == PCMTRIG_START) {
es->ctrl |= CTRL_ADC_EN;
es->sctrl &= ~SCTRL_R1LOOPSEL;
- es->sctrl |= SCTRL_R1INTEN;
+ es->sctrl |= SCTRL_R1INTEN | (b << 4);
es_wr(es, ES1370_REG_ADC_SCOUNT, cnt, 4);
/* start at beginning of buffer */
es_wr(es, ES1370_REG_MEMPAGE, ES1370_REG_ADC_FRAMECNT >> 8, 4);
@@ -463,9 +653,12 @@ eschan_getptr(kobj_t obj, void *data)
struct es_info *es = ch->parent;
u_int32_t reg, cnt;
- if (ch->dir == PCMDIR_PLAY)
- reg = ES1370_REG_DAC2_FRAMECNT;
- else
+ if (ch->dir == PCMDIR_PLAY) {
+ if (ch->index == ES_DAC1)
+ reg = ES1370_REG_DAC1_FRAMECNT;
+ else
+ reg = ES1370_REG_DAC2_FRAMECNT;
+ } else
reg = ES1370_REG_ADC_FRAMECNT;
ES_LOCK(es);
es_wr(es, ES1370_REG_MEMPAGE, reg >> 8, 4);
@@ -479,9 +672,8 @@ static struct pcmchan_caps *
eschan_getcaps(kobj_t obj, void *data)
{
struct es_chinfo *ch = data;
- struct es_info *es = ch->parent;
- return &es->caps;
+ return &ch->caps;
}
static kobj_method_t eschan1370_methods[] = {
@@ -532,37 +724,56 @@ es_intr(void *p)
es_wr(es, ES1370_REG_SERIAL_CONTROL, es->sctrl, 4);
ES_UNLOCK(es);
- if (intsrc & STAT_ADC) chn_intr(es->rch.channel);
- if (intsrc & STAT_DAC1)
- ; /* nothing */
- if (intsrc & STAT_DAC2) chn_intr(es->pch.channel);
+ if (intsrc & STAT_ADC) chn_intr(es->ch[ES_ADC].channel);
+ if (intsrc & STAT_DAC1) chn_intr(es->ch[ES_DAC1].channel);
+ if (intsrc & STAT_DAC2) chn_intr(es->ch[ES_DAC2].channel);
}
/* ES1370 specific */
static int
es1370_init(struct es_info *es)
{
- int r;
+ uint32_t fixed_rate;
+ int r, single_pcm;
- /* XXX ES1370 default to fixed rate operation */
+ /* ES1370 default to fixed rate operation */
if (resource_int_value(device_get_name(es->dev),
device_get_unit(es->dev), "fixed_rate", &r) == 0) {
- if (r != 0) {
- if (r < es_caps.minspeed)
- r = es_caps.minspeed;
- if (r > es_caps.maxspeed)
- r = es_caps.maxspeed;
+ fixed_rate = r;
+ if (fixed_rate) {
+ if (fixed_rate < es_caps.minspeed)
+ fixed_rate = es_caps.minspeed;
+ if (fixed_rate > es_caps.maxspeed)
+ fixed_rate = es_caps.maxspeed;
}
} else
- r = es_caps.maxspeed;
+ fixed_rate = es_caps.maxspeed;
+
+ if (resource_int_value(device_get_name(es->dev),
+ device_get_unit(es->dev), "single_pcm_mixer", &r) == 0)
+ single_pcm = (r) ? 1 : 0;
+ else
+ single_pcm = 1;
+
ES_LOCK(es);
- es->caps = es_caps;
- if (r != 0) {
- es->caps.minspeed = r;
- es->caps.maxspeed = r;
+ if (ES_NUMPLAY(es->escfg) == 1)
+ single_pcm = 1;
+ /* This is ES1370 */
+ es->escfg = ES_SET_IS_ES1370(es->escfg, 1);
+ if (fixed_rate) {
+ es->escfg = ES_SET_FIXED_RATE(es->escfg, fixed_rate);
+ } else {
+ es->escfg = ES_SET_FIXED_RATE(es->escfg, 0);
+ fixed_rate = DSP_DEFAULT_SPEED;
}
- es->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS |
- (DAC2_SRTODIV(es->caps.maxspeed) << CTRL_SH_PCLKDIV);
+ if (single_pcm) {
+ es->escfg = ES_SET_SINGLE_PCM_MIX(es->escfg, 1);
+ } else {
+ es->escfg = ES_SET_SINGLE_PCM_MIX(es->escfg, 0);
+ }
+ es->ctrl = CTRL_CDC_EN | CTRL_JYSTK_EN | CTRL_SERR_DIS |
+ (DAC2_SRTODIV(fixed_rate) << CTRL_SH_PCLKDIV);
+ es->ctrl |= 3 << CTRL_SH_WTSRSEL;
es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4);
es->sctrl = 0;
@@ -587,10 +798,11 @@ es1371_init(struct es_info *es)
int idx;
ES_LOCK(es);
+ /* This is NOT ES1370 */
+ es->escfg = ES_SET_IS_ES1370(es->escfg, 0);
es->num = 0;
- es->ctrl = 0;
+ es->ctrl = CTRL_JYSTK_EN;
es->sctrl = 0;
- es->caps = es_caps;
cssr = 0;
devid = pci_get_devid(es->dev);
revid = pci_get_revid(es->dev);
@@ -612,9 +824,10 @@ es1371_init(struct es_info *es)
DELAY(20000);
}
/* AC'97 warm reset to start the bitclk */
- es_wr(es, ES1370_REG_CONTROL, es->ctrl | ES1371_SYNC_RES, 4);
- DELAY(2000);
es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4);
+ es_wr(es, ES1371_REG_LEGACY, ES1371_SYNC_RES, 4);
+ DELAY(2000);
+ es_wr(es, ES1370_REG_CONTROL, es->sctrl, 4);
es1371_wait_src_ready(es);
/* Init the sample rate converter */
es_wr(es, ES1371_REG_SMPRATE, ES1371_DIS_SRC, 4);
@@ -630,9 +843,9 @@ es1371_init(struct es_info *es)
es1371_src_write(es, ES_SMPREG_VOL_DAC1 + 1, 1 << 12);
es1371_src_write(es, ES_SMPREG_VOL_DAC2, 1 << 12);
es1371_src_write(es, ES_SMPREG_VOL_DAC2 + 1, 1 << 12);
- es1371_adc_rate (es, 22050, 1);
- es1371_dac_rate (es, 22050, 1);
- es1371_dac_rate (es, 22050, 2);
+ es1371_adc_rate(es, 22050, ES_ADC);
+ es1371_dac_rate(es, 22050, ES_DAC1);
+ es1371_dac_rate(es, 22050, ES_DAC2);
/* WARNING:
* enabling the sample rate converter without properly programming
* its parameters causes the chip to lock up (the SRC busy bit will
@@ -804,20 +1017,18 @@ es1371_dac_rate(struct es_info *es, u_int rate, int set)
if (rate > 48000) rate = 48000;
if (rate < 4000) rate = 4000;
- freq = (rate << 15) / 3000;
+ freq = ((rate << 15) + 1500) / 3000;
result = (freq * 3000) >> 15;
- if (set) {
- dac = (set == 1)? ES_SMPREG_DAC1 : ES_SMPREG_DAC2;
- dis = (set == 1)? ES1371_DIS_P2 : ES1371_DIS_P1;
-
- r = (es1371_wait_src_ready(es) & (ES1371_DIS_SRC | ES1371_DIS_P1 | ES1371_DIS_P2 | ES1371_DIS_R1));
- es_wr(es, ES1371_REG_SMPRATE, r, 4);
- es1371_src_write(es, dac + ES_SMPREG_INT_REGS,
- (es1371_src_read(es, dac + ES_SMPREG_INT_REGS) & 0x00ff) | ((freq >> 5) & 0xfc00));
- es1371_src_write(es, dac + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff);
- r = (es1371_wait_src_ready(es) & (ES1371_DIS_SRC | dis | ES1371_DIS_R1));
- es_wr(es, ES1371_REG_SMPRATE, r, 4);
- }
+
+ dac = (set == ES_DAC1) ? ES_SMPREG_DAC1 : ES_SMPREG_DAC2;
+ dis = (set == ES_DAC1) ? ES1371_DIS_P2 : ES1371_DIS_P1;
+ r = (es1371_wait_src_ready(es) & (ES1371_DIS_SRC | ES1371_DIS_P1 | ES1371_DIS_P2 | ES1371_DIS_R1));
+ es_wr(es, ES1371_REG_SMPRATE, r, 4);
+ es1371_src_write(es, dac + ES_SMPREG_INT_REGS,
+ (es1371_src_read(es, dac + ES_SMPREG_INT_REGS) & 0x00ff) | ((freq >> 5) & 0xfc00));
+ es1371_src_write(es, dac + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff);
+ r = (es1371_wait_src_ready(es) & (ES1371_DIS_SRC | dis | ES1371_DIS_R1));
+ es_wr(es, ES1371_REG_SMPRATE, r, 4);
return result;
}
@@ -890,7 +1101,7 @@ es_pci_probe(device_t dev)
case CT4730_PCI_ID:
switch(pci_get_revid(dev)) {
case CT4730REV_CT4730_A:
- device_set_desc(dev, "Creative SB AudioPCI CT4730");
+ device_set_desc(dev, "Creative SB AudioPCI CT4730/EV1938");
return BUS_PROBE_DEFAULT;
default:
device_set_desc(dev, "Creative SB AudioPCI CT4730-?");
@@ -1000,9 +1211,8 @@ sysctl_es137x_fixed_rate(SYSCTL_HANDLER_ARGS)
dev = oidp->oid_arg1;
es = pcm_getdevinfo(dev);
ES_LOCK(es);
- if (es->caps.minspeed == es->caps.maxspeed)
- val = es->caps.maxspeed;
- else
+ val = ES_FIXED_RATE(es->escfg);
+ if (val < es_caps.minspeed)
val = 0;
ES_UNLOCK(es);
err = sysctl_handle_int(oidp, &val, sizeof(val), req);
@@ -1013,20 +1223,113 @@ sysctl_es137x_fixed_rate(SYSCTL_HANDLER_ARGS)
return (EINVAL);
ES_LOCK(es);
+ if (es->ctrl & (CTRL_DAC2_EN|CTRL_ADC_EN)) {
+ ES_UNLOCK(es);
+ return (EBUSY);
+ }
if (val) {
- es->caps.minspeed = val;
- es->caps.maxspeed = val;
- es->ctrl &= ~CTRL_PCLKDIV;
- es->ctrl |= DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV;
- es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4);
+ if (val != ES_FIXED_RATE(es->escfg)) {
+ es->escfg = ES_SET_FIXED_RATE(es->escfg, val);
+ es->ch[ES_DAC2].caps.maxspeed = val;
+ es->ch[ES_DAC2].caps.minspeed = val;
+ es->ch[ES_ADC].caps.maxspeed = val;
+ es->ch[ES_ADC].caps.minspeed = val;
+ es->ctrl &= ~CTRL_PCLKDIV;
+ es->ctrl |= DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV;
+ es_wr(es, ES1370_REG_CONTROL, es->ctrl, 4);
+ }
} else {
- es->caps.minspeed = es_caps.minspeed;
- es->caps.maxspeed = es_caps.maxspeed;
+ es->escfg = ES_SET_FIXED_RATE(es->escfg, 0);
+ es->ch[ES_DAC2].caps = es_caps;
+ es->ch[ES_ADC].caps = es_caps;
}
ES_UNLOCK(es);
return (0);
}
+
+static int
+sysctl_es137x_single_pcm_mixer(SYSCTL_HANDLER_ARGS)
+{
+ struct es_info *es;
+ struct snddev_info *d;
+ struct snd_mixer *m;
+ struct cdev *i_dev;
+ device_t dev;
+ uint32_t val, set;
+ int recsrc, level, err;
+
+ dev = oidp->oid_arg1;
+ d = device_get_softc(dev);
+ if (d == NULL || d->mixer_dev == NULL || d->mixer_dev->si_drv1 == NULL)
+ return (EINVAL);
+ es = d->devinfo;
+ if (es == NULL)
+ return (EINVAL);
+ ES_LOCK(es);
+ set = ES_SINGLE_PCM_MIX(es->escfg);
+ val = set;
+ ES_UNLOCK(es);
+ err = sysctl_handle_int(oidp, &val, sizeof(val), req);
+
+ if (err || req->newptr == NULL)
+ return (err);
+ if (!(val == 0 || val == 1))
+ return (EINVAL);
+ if (val == set)
+ return (0);
+ i_dev = d->mixer_dev;
+ if (mixer_ioctl(i_dev, 0, (caddr_t)&recsrc, 0, NULL) != EBADF)
+ return (EBUSY);
+ err = mixer_ioctl(i_dev, MIXER_READ(SOUND_MIXER_PCM),
+ (caddr_t)&level, -1, NULL);
+ if (!err)
+ err = mixer_ioctl(i_dev, MIXER_READ(SOUND_MIXER_RECSRC),
+ (caddr_t)&recsrc, -1, NULL);
+ if (err)
+ return (err);
+ if (level < 0)
+ return (EINVAL);
+
+ ES_LOCK(es);
+ if (es->ctrl & (CTRL_ADC_EN | CTRL_DAC1_EN | CTRL_DAC2_EN)) {
+ ES_UNLOCK(es);
+ return (EBUSY);
+ }
+ if (val) {
+ es->escfg = ES_SET_SINGLE_PCM_MIX(es->escfg, 1);
+ } else {
+ es->escfg = ES_SET_SINGLE_PCM_MIX(es->escfg, 0);
+ }
+ ES_UNLOCK(es);
+ m = i_dev->si_drv1;
+ if (!val) {
+ mix_setdevs(m, mix_getdevs(d->mixer_dev->si_drv1) |
+ (1 << SOUND_MIXER_SYNTH));
+ mix_setrecdevs(m, mix_getrecdevs(d->mixer_dev->si_drv1) |
+ (1 << SOUND_MIXER_SYNTH));
+ err = mixer_ioctl(i_dev, MIXER_WRITE(SOUND_MIXER_SYNTH),
+ (caddr_t)&level, -1, NULL);
+ } else {
+ err = mixer_ioctl(i_dev, MIXER_WRITE(SOUND_MIXER_SYNTH),
+ (caddr_t)&level, -1, NULL);
+ mix_setdevs(m, mix_getdevs(d->mixer_dev->si_drv1) &
+ ~(1 << SOUND_MIXER_SYNTH));
+ mix_setrecdevs(m, mix_getrecdevs(d->mixer_dev->si_drv1) &
+ ~(1 << SOUND_MIXER_SYNTH));
+ }
+ if (!err) {
+ level = recsrc;
+ if (recsrc & (1 << SOUND_MIXER_PCM))
+ recsrc |= 1 << SOUND_MIXER_SYNTH;
+ else if (recsrc & (1 << SOUND_MIXER_SYNTH))
+ recsrc |= 1 << SOUND_MIXER_PCM;
+ if (level != recsrc)
+ err = mixer_ioctl(i_dev, MIXER_WRITE(SOUND_MIXER_RECSRC),
+ (caddr_t)&recsrc, -1, NULL);
+ }
+ return (err);
+}
#endif /* SND_DYNSYSCTL */
static void
@@ -1051,12 +1354,28 @@ es_init_sysctls(device_t dev)
sysctl_es137x_spdif_enable, "I",
"Enable S/PDIF output on primary playback channel");
} else if (devid == ES1370_PCI_ID) {
- SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
- SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
- OID_AUTO, "fixed_rate",
- CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
- sysctl_es137x_fixed_rate, "I",
- "Enable fixed rate playback/recording");
+ /*
+ * Enable fixed rate sysctl if both DAC2 / ADC enabled.
+ */
+ if (es->ch[ES_DAC2].channel != NULL && es->ch[ES_ADC].channel != NULL) {
+ SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
+ SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
+ OID_AUTO, "fixed_rate",
+ CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
+ sysctl_es137x_fixed_rate, "I",
+ "Enable fixed rate playback/recording");
+ }
+ /*
+ * Enable single pcm mixer sysctl if both DAC1/2 enabled.
+ */
+ if (es->ch[ES_DAC1].channel != NULL && es->ch[ES_DAC2].channel != NULL) {
+ SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
+ SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
+ OID_AUTO, "single_pcm_mixer",
+ CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
+ sysctl_es137x_single_pcm_mixer, "I",
+ "Single PCM mixer controller for both DAC1/DAC2");
+ }
}
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), "latency_timer", &r) == 0 &&
@@ -1076,7 +1395,7 @@ es_pci_attach(device_t dev)
{
u_int32_t data;
struct es_info *es = NULL;
- int mapped;
+ int mapped, i, numplay, dac_cfg;
char status[SND_STATUSLEN];
struct ac97_info *codec = NULL;
kobj_class_t ct = NULL;
@@ -1088,6 +1407,7 @@ es_pci_attach(device_t dev)
}
es->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
es->dev = dev;
+ es->escfg = 0;
mapped = 0;
pci_enable_busmaster(dev);
@@ -1120,6 +1440,37 @@ es_pci_attach(device_t dev)
es->sh = rman_get_bushandle(es->reg);
es->bufsz = pcm_getbuffersize(dev, 4096, ES_DEFAULT_BUFSZ, 65536);
+ if (resource_int_value(device_get_name(dev),
+ device_get_unit(dev), "dac", &dac_cfg) == 0) {
+ if (dac_cfg < 0 || dac_cfg > 3)
+ dac_cfg = ES_DEFAULT_DAC_CFG;
+ } else
+ dac_cfg = ES_DEFAULT_DAC_CFG;
+
+ switch (dac_cfg) {
+ case 0: /* Enable all DAC: DAC1, DAC2 */
+ numplay = 2;
+ es->escfg = ES_SET_DAC_FIRST(es->escfg, ES_DAC1);
+ es->escfg = ES_SET_DAC_SECOND(es->escfg, ES_DAC2);
+ break;
+ case 1: /* Only DAC1 */
+ numplay = 1;
+ es->escfg = ES_SET_DAC_FIRST(es->escfg, ES_DAC1);
+ break;
+ case 3: /* Enable all DAC / swap position: DAC2, DAC1 */
+ numplay = 2;
+ es->escfg = ES_SET_DAC_FIRST(es->escfg, ES_DAC2);
+ es->escfg = ES_SET_DAC_SECOND(es->escfg, ES_DAC1);
+ break;
+ case 2: /* Only DAC2 */
+ default:
+ numplay = 1;
+ es->escfg = ES_SET_DAC_FIRST(es->escfg, ES_DAC2);
+ break;
+ }
+ es->escfg = ES_SET_NUMPLAY(es->escfg, numplay);
+ es->escfg = ES_SET_NUMREC(es->escfg, 1);
+
devid = pci_get_devid(dev);
switch (devid) {
case ES1371_PCI_ID:
@@ -1139,6 +1490,14 @@ es_pci_attach(device_t dev)
break;
case ES1370_PCI_ID:
es1370_init(es);
+ /*
+ * Disable fixed rate operation if DAC2 disabled.
+ * This is a special case for es1370 only, where the
+ * speed of both ADC and DAC2 locked together.
+ */
+ if (!ES_DAC2_ENABLED(es->escfg)) {
+ es->escfg = ES_SET_FIXED_RATE(es->escfg, 0);
+ }
if (mixer_init(dev, &es1370_mixer_class, es))
goto bad;
ct = &eschan1370_class;
@@ -1171,13 +1530,22 @@ es_pci_attach(device_t dev)
(es->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(es->reg), rman_get_start(es->irq),PCM_KLDSTRING(snd_es137x));
- if (pcm_register(dev, es, 1, 1))
+ if (pcm_register(dev, es, numplay, 1))
goto bad;
+ for (i = 0; i < numplay; i++)
+ pcm_addchan(dev, PCMDIR_PLAY, ct, es);
pcm_addchan(dev, PCMDIR_REC, ct, es);
- pcm_addchan(dev, PCMDIR_PLAY, ct, es);
es_init_sysctls(dev);
pcm_setstatus(dev, status);
-
+ es->escfg = ES_SET_GP(es->escfg, 0);
+ if (numplay == 1) {
+ device_printf(dev, "<Playback: DAC%d / Record: ADC>\n",
+ ES_DAC_FIRST(es->escfg) + 1);
+ } else if (numplay == 2) {
+ device_printf(dev, "<Playback: DAC%d,DAC%d / Record: ADC>\n",
+ ES_DAC_FIRST(es->escfg) + 1,
+ ES_DAC_SECOND(es->escfg) + 1);
+ }
return 0;
bad:
OpenPOWER on IntegriCloud