yamaha ds1/ds1e pci sound driver - work in progress, mixer and playback only.
tested on ymf724f only. conf/files entry is commented out, enable it manually to test this code and let me know results.
This commit is contained in:
parent
5744d83648
commit
bd68ce8be9
@ -249,6 +249,7 @@ dev/sound/isa/sbc.c optional sbc isa
|
||||
dev/sound/pci/csa.c optional csa pci
|
||||
dev/sound/pci/csa.c optional pcm pci
|
||||
dev/sound/pci/csapcm.c optional pcm pci
|
||||
#dev/sound/pci/ds1.c optional pcm pci
|
||||
dev/sound/pci/emu10k1.c optional pcm pci
|
||||
dev/sound/pci/es137x.c optional pcm pci
|
||||
dev/sound/pci/neomagic.c optional pcm pci
|
||||
|
1578
sys/dev/sound/pci/ds1-fw.h
Normal file
1578
sys/dev/sound/pci/ds1-fw.h
Normal file
File diff suppressed because it is too large
Load Diff
788
sys/dev/sound/pci/ds1.c
Normal file
788
sys/dev/sound/pci/ds1.c
Normal file
@ -0,0 +1,788 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#include "pcm.h"
|
||||
|
||||
#include <dev/sound/pcm/sound.h>
|
||||
#include <dev/sound/pcm/ac97.h>
|
||||
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
|
||||
#include <dev/sound/pci/ds1.h>
|
||||
#include <dev/sound/pci/ds1-fw.h>
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#define DS1_CHANS 4
|
||||
|
||||
struct pbank {
|
||||
volatile u_int32_t Format;
|
||||
volatile u_int32_t LoopDefault;
|
||||
volatile u_int32_t PgBase;
|
||||
volatile u_int32_t PgLoop;
|
||||
volatile u_int32_t PgLoopEnd;
|
||||
volatile u_int32_t PgLoopFrac;
|
||||
volatile u_int32_t PgDeltaEnd;
|
||||
volatile u_int32_t LpfKEnd;
|
||||
volatile u_int32_t EgGainEnd;
|
||||
volatile u_int32_t LchGainEnd;
|
||||
volatile u_int32_t RchGainEnd;
|
||||
volatile u_int32_t Effect1GainEnd;
|
||||
volatile u_int32_t Effect2GainEnd;
|
||||
volatile u_int32_t Effect3GainEnd;
|
||||
volatile u_int32_t LpfQ;
|
||||
volatile u_int32_t Status;
|
||||
volatile u_int32_t NumOfFrames;
|
||||
volatile u_int32_t LoopCount;
|
||||
volatile u_int32_t PgStart;
|
||||
volatile u_int32_t PgStartFrac;
|
||||
volatile u_int32_t PgDelta;
|
||||
volatile u_int32_t LpfK;
|
||||
volatile u_int32_t EgGain;
|
||||
volatile u_int32_t LchGain;
|
||||
volatile u_int32_t RchGain;
|
||||
volatile u_int32_t Effect1Gain;
|
||||
volatile u_int32_t Effect2Gain;
|
||||
volatile u_int32_t Effect3Gain;
|
||||
volatile u_int32_t LpfD1;
|
||||
volatile u_int32_t LpfD2;
|
||||
};
|
||||
|
||||
struct sc_info;
|
||||
|
||||
/* channel registers */
|
||||
struct sc_chinfo {
|
||||
int run, spd, dir, fmt;
|
||||
snd_dbuf *buffer;
|
||||
pcm_channel *channel;
|
||||
volatile struct pbank *lslot, *rslot;
|
||||
int lsnum, rsnum;
|
||||
struct sc_info *parent;
|
||||
};
|
||||
|
||||
/* device private data */
|
||||
struct sc_info {
|
||||
device_t dev;
|
||||
u_int32_t type, rev;
|
||||
u_int32_t cd2id, ctrlbase;
|
||||
|
||||
bus_space_tag_t st;
|
||||
bus_space_handle_t sh;
|
||||
bus_dma_tag_t parent_dmat;
|
||||
|
||||
struct resource *reg, *irq;
|
||||
int regid, irqid;
|
||||
void *ih;
|
||||
|
||||
u_int32_t *pbase, pbankbase, pbanksize;
|
||||
volatile struct pbank *pbank[2 * 64];
|
||||
int pslotfree, currbank, pchn, rchn;
|
||||
|
||||
struct sc_chinfo pch[DS1_CHANS], rch[2];
|
||||
};
|
||||
|
||||
struct {
|
||||
u_int32_t dev, subdev;
|
||||
char *name;
|
||||
u_int32_t *mcode;
|
||||
} ds_devs[] = {
|
||||
{0x00041073, 0, "Yamaha DS-1 (YMF724)", CntrlInst},
|
||||
{0x000d1073, 0, "Yamaha DS-1E (YMF724F)", CntrlInst1E},
|
||||
{0x00051073, 0, "Yamaha DS-1? (YMF734)", CntrlInst},
|
||||
{0x00081073, 0, "Yamaha DS-1? (YMF737)", CntrlInst},
|
||||
{0x00201073, 0, "Yamaha DS-1? (YMF738)", CntrlInst},
|
||||
{0x00061073, 0, "Yamaha DS-1? (YMF738_TEG)", CntrlInst},
|
||||
{0x000a1073, 0x00041073, "Yamaha DS-1 (YMF740)", CntrlInst},
|
||||
{0x000a1073, 0x000a1073, "Yamaha DS-1 (YMF740B)", CntrlInst},
|
||||
{0x000c1073, 0, "Yamaha DS-1E (YMF740C)", CntrlInst1E},
|
||||
{0x00101073, 0, "Yamaha DS-1E (YMF744)", CntrlInst1E},
|
||||
{0x00121073, 0, "Yamaha DS-1E (YMF754)", CntrlInst1E},
|
||||
{0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
|
||||
/* channel interface */
|
||||
static void *ds1chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
|
||||
static int ds1chan_setdir(void *data, int dir);
|
||||
static int ds1chan_setformat(void *data, u_int32_t format);
|
||||
static int ds1chan_setspeed(void *data, u_int32_t speed);
|
||||
static int ds1chan_setblocksize(void *data, u_int32_t blocksize);
|
||||
static int ds1chan_trigger(void *data, int go);
|
||||
static int ds1chan_getptr(void *data);
|
||||
static pcmchan_caps *ds1chan_getcaps(void *data);
|
||||
|
||||
/* talk to the codec - called from ac97.c */
|
||||
static u_int32_t ds_rdcd(void *, int);
|
||||
static void ds_wrcd(void *, int, u_int32_t);
|
||||
|
||||
/* stuff */
|
||||
static int ds_init(struct sc_info *);
|
||||
static void ds_intr(void *);
|
||||
|
||||
/* talk to the card */
|
||||
static u_int32_t ds_rd(struct sc_info *, int, int);
|
||||
static void ds_wr(struct sc_info *, int, u_int32_t, int);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static pcmchan_caps ds_reccaps = {
|
||||
4000, 48000,
|
||||
AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
|
||||
AFMT_STEREO | AFMT_S16_LE
|
||||
};
|
||||
|
||||
static pcmchan_caps ds_playcaps = {
|
||||
4000, 96000,
|
||||
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
|
||||
AFMT_STEREO | AFMT_S16_LE
|
||||
};
|
||||
|
||||
static pcm_channel ds_chantemplate = {
|
||||
ds1chan_init,
|
||||
ds1chan_setdir,
|
||||
ds1chan_setformat,
|
||||
ds1chan_setspeed,
|
||||
ds1chan_setblocksize,
|
||||
ds1chan_trigger,
|
||||
ds1chan_getptr,
|
||||
ds1chan_getcaps,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Hardware */
|
||||
static u_int32_t
|
||||
ds_rd(struct sc_info *sc, int regno, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
return bus_space_read_1(sc->st, sc->sh, regno);
|
||||
case 2:
|
||||
return bus_space_read_2(sc->st, sc->sh, regno);
|
||||
case 4:
|
||||
return bus_space_read_4(sc->st, sc->sh, regno);
|
||||
default:
|
||||
return 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ds_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
bus_space_write_1(sc->st, sc->sh, regno, data);
|
||||
break;
|
||||
case 2:
|
||||
bus_space_write_2(sc->st, sc->sh, regno, data);
|
||||
break;
|
||||
case 4:
|
||||
bus_space_write_4(sc->st, sc->sh, regno, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val)
|
||||
{
|
||||
*(volatile u_int32_t *)ptr = val;
|
||||
bus_space_barrier(sc->sh, sc->st, 0, 0, BUS_SPACE_BARRIER_WRITE);
|
||||
}
|
||||
|
||||
/* ac97 codec */
|
||||
static int
|
||||
ds_cdbusy(struct sc_info *sc, int sec)
|
||||
{
|
||||
int i, reg;
|
||||
|
||||
reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
|
||||
i = YDSXG_AC97TIMEOUT;
|
||||
while (i > 0) {
|
||||
if (!(ds_rd(sc, reg, 2) & 0x8000))
|
||||
return 0;
|
||||
i--;
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
ds_initcd(void *devinfo)
|
||||
{
|
||||
struct sc_info *sc = (struct sc_info *)devinfo;
|
||||
u_int32_t x;
|
||||
|
||||
x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1);
|
||||
if (x & 0x03) {
|
||||
pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
|
||||
pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1);
|
||||
pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
|
||||
}
|
||||
|
||||
return ds_cdbusy(sc, 0);
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
ds_rdcd(void *devinfo, int regno)
|
||||
{
|
||||
struct sc_info *sc = (struct sc_info *)devinfo;
|
||||
int sec, cid, i;
|
||||
u_int32_t cmd, reg;
|
||||
|
||||
sec = regno & 0x100;
|
||||
regno &= 0xff;
|
||||
cid = sec? (sc->cd2id << 8) : 0;
|
||||
reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA;
|
||||
if (sec && cid == 0)
|
||||
return 0xffffffff;
|
||||
|
||||
cmd = YDSXG_AC97READCMD | cid | regno;
|
||||
ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2);
|
||||
|
||||
if (ds_cdbusy(sc, sec))
|
||||
return 0xffffffff;
|
||||
|
||||
if (sc->type == 9 && sc->rev < 2)
|
||||
for (i = 0; i < 600; i++)
|
||||
ds_rd(sc, reg, 2);
|
||||
|
||||
return ds_rd(sc, reg, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
ds_wrcd(void *devinfo, int regno, u_int32_t data)
|
||||
{
|
||||
struct sc_info *sc = (struct sc_info *)devinfo;
|
||||
int sec, cid;
|
||||
u_int32_t cmd;
|
||||
|
||||
sec = regno & 0x100;
|
||||
regno &= 0xff;
|
||||
cid = sec? (sc->cd2id << 8) : 0;
|
||||
if (sec && cid == 0)
|
||||
return;
|
||||
|
||||
cmd = YDSXG_AC97WRITECMD | cid | regno;
|
||||
cmd <<= 16;
|
||||
cmd |= data;
|
||||
ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4);
|
||||
|
||||
ds_cdbusy(sc, sec);
|
||||
}
|
||||
|
||||
static void
|
||||
ds_enadsp(struct sc_info *sc, int on)
|
||||
{
|
||||
u_int32_t v, i;
|
||||
|
||||
v = on? 1 : 0;
|
||||
if (on) {
|
||||
ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4);
|
||||
} else {
|
||||
if (ds_rd(sc, YDSXGR_CONFIG, 4))
|
||||
ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4);
|
||||
i = YDSXG_WORKBITTIMEOUT;
|
||||
while (i > 0) {
|
||||
if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002))
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static volatile struct pbank *
|
||||
ds_allocpslot(struct sc_info *sc)
|
||||
{
|
||||
int slot;
|
||||
|
||||
if (sc->pslotfree > 63)
|
||||
return NULL;
|
||||
slot = sc->pslotfree++;
|
||||
return sc->pbank[slot * 2];
|
||||
}
|
||||
|
||||
static int
|
||||
ds_initpbank(volatile struct pbank *pb, int ch, int b16, int stereo, u_int32_t rate, void *base, u_int32_t len)
|
||||
{
|
||||
u_int32_t lv[] = {1, 1, 0, 0, 0};
|
||||
u_int32_t rv[] = {1, 0, 1, 0, 0};
|
||||
u_int32_t e1[] = {0, 0, 0, 0, 0};
|
||||
u_int32_t e2[] = {1, 0, 0, 1, 0};
|
||||
u_int32_t e3[] = {1, 0, 0, 0, 1};
|
||||
int ss, i;
|
||||
u_int32_t delta;
|
||||
|
||||
struct {
|
||||
int rate, fK, fQ;
|
||||
} speedinfo[] = {
|
||||
{ 100, 0x00570000, 0x35280000},
|
||||
{ 2000, 0x06aa0000, 0x34a70000},
|
||||
{ 8000, 0x18b20000, 0x32020000},
|
||||
{11025, 0x20930000, 0x31770000},
|
||||
{16000, 0x2b9a0000, 0x31390000},
|
||||
{22050, 0x35a10000, 0x31c90000},
|
||||
{32000, 0x3eaa0000, 0x33d00000},
|
||||
/* {44100, 0x04646000, 0x370a0000},
|
||||
*/ {48000, 0x40000000, 0x40000000},
|
||||
};
|
||||
|
||||
ss = b16? 1 : 0;
|
||||
ss += stereo? 1 : 0;
|
||||
delta = (65536 * rate) / 48000;
|
||||
i = 0;
|
||||
while (i < 7 && speedinfo[i].rate < rate)
|
||||
i++;
|
||||
|
||||
pb->Format = stereo? 0x00010000 : 0;
|
||||
pb->Format |= b16? 0 : 0x80000000;
|
||||
pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0;
|
||||
pb->LoopDefault = 0;
|
||||
pb->PgBase = base? vtophys(base) : 0;
|
||||
pb->PgLoop = 0;
|
||||
pb->PgLoopEnd = len >> ss;
|
||||
pb->PgLoopFrac = 0;
|
||||
pb->Status = 0;
|
||||
pb->NumOfFrames = 0;
|
||||
pb->LoopCount = 0;
|
||||
pb->PgStart = 0;
|
||||
pb->PgStartFrac = 0;
|
||||
pb->PgDelta = pb->PgDeltaEnd = delta << 12;
|
||||
pb->LpfQ = speedinfo[i].fQ;
|
||||
pb->LpfK = pb->LpfKEnd = speedinfo[i].fK;
|
||||
pb->LpfD1 = pb->LpfD2 = 0;
|
||||
pb->EgGain = pb->EgGainEnd = 0x40000000;
|
||||
pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000;
|
||||
pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000;
|
||||
pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000;
|
||||
pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000;
|
||||
pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ds_enapslot(struct sc_info *sc, int slot, int go)
|
||||
{
|
||||
wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0);
|
||||
/* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */
|
||||
}
|
||||
|
||||
static void
|
||||
ds_setupch(struct sc_chinfo *ch)
|
||||
{
|
||||
int stereo, b16, c;
|
||||
void *buf;
|
||||
|
||||
stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
|
||||
c = stereo? 1 : 0;
|
||||
buf = ch->buffer->buf;
|
||||
|
||||
ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, buf, ch->buffer->bufsize);
|
||||
ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, buf, ch->buffer->bufsize);
|
||||
ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, buf, ch->buffer->bufsize);
|
||||
ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, buf, ch->buffer->bufsize);
|
||||
}
|
||||
|
||||
/* channel interface */
|
||||
void *
|
||||
ds1chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
|
||||
{
|
||||
struct sc_info *sc = devinfo;
|
||||
struct sc_chinfo *ch;
|
||||
|
||||
ch = (dir == PCMDIR_PLAY)? &sc->pch[sc->pchn++] : &sc->rch[sc->rchn++];
|
||||
ch->buffer = b;
|
||||
ch->buffer->bufsize = 4096;
|
||||
ch->parent = sc;
|
||||
ch->channel = c;
|
||||
ch->fmt = AFMT_U8;
|
||||
ch->spd = 8000;
|
||||
ch->run = 0;
|
||||
if (chn_allocbuf(ch->buffer, sc->parent_dmat) == -1)
|
||||
return NULL;
|
||||
else {
|
||||
ch->lsnum = sc->pslotfree;
|
||||
ch->lslot = ds_allocpslot(sc);
|
||||
ch->rsnum = sc->pslotfree;
|
||||
ch->rslot = ds_allocpslot(sc);
|
||||
ds_setupch(ch);
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ds1chan_setdir(void *data, int dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ds1chan_setformat(void *data, u_int32_t format)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
|
||||
ch->fmt = format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ds1chan_setspeed(void *data, u_int32_t speed)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
|
||||
ch->spd = speed;
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
static int
|
||||
ds1chan_setblocksize(void *data, u_int32_t blocksize)
|
||||
{
|
||||
return blocksize;
|
||||
}
|
||||
|
||||
/* semantic note: must start at beginning of buffer */
|
||||
static int
|
||||
ds1chan_trigger(void *data, int go)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
struct sc_info *sc = ch->parent;
|
||||
int stereo;
|
||||
|
||||
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
|
||||
return 0;
|
||||
stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
if (go == PCMTRIG_START) {
|
||||
ch->run = 1;
|
||||
ds_setupch(ch);
|
||||
ds_enapslot(sc, ch->lsnum, 1);
|
||||
ds_enapslot(sc, ch->rsnum, stereo);
|
||||
ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
|
||||
} else {
|
||||
ch->run = 0;
|
||||
ds_setupch(ch);
|
||||
ds_enapslot(sc, ch->lsnum, 0);
|
||||
ds_enapslot(sc, ch->rsnum, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ds1chan_getptr(void *data)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
struct sc_info *sc = ch->parent;
|
||||
volatile struct pbank *bank;
|
||||
int ss;
|
||||
u_int32_t ptr;
|
||||
|
||||
ss = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
ss += (ch->fmt & AFMT_16BIT)? 1 : 0;
|
||||
|
||||
bank = ch->lslot + sc->currbank;
|
||||
/* printf("getptr: %d\n", bank->PgStart << ss); */
|
||||
ptr = bank->PgStart;
|
||||
ptr <<= ss;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static pcmchan_caps *
|
||||
ds1chan_getcaps(void *data)
|
||||
{
|
||||
struct sc_chinfo *ch = data;
|
||||
|
||||
return (ch->dir == PCMDIR_PLAY)? &ds_playcaps : &ds_reccaps;
|
||||
}
|
||||
|
||||
/* The interrupt handler */
|
||||
static void
|
||||
ds_intr(void *p)
|
||||
{
|
||||
struct sc_info *sc = (struct sc_info *)p;
|
||||
u_int32_t i, x;
|
||||
|
||||
i = ds_rd(sc, YDSXGR_STATUS, 4);
|
||||
if (i & 0x80008000) {
|
||||
ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
|
||||
sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;
|
||||
|
||||
x = 0;
|
||||
for (i = 0; i < DS1_CHANS; i++)
|
||||
if (sc->pch[i].run) {
|
||||
x = 1;
|
||||
chn_intr(sc->pch[i].channel);
|
||||
}
|
||||
|
||||
i = ds_rd(sc, YDSXGR_MODE, 4);
|
||||
if (x)
|
||||
ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Probe and attach the card
|
||||
*/
|
||||
|
||||
static void
|
||||
ds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
{
|
||||
struct sc_info *sc = arg;
|
||||
|
||||
sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr;
|
||||
|
||||
if (bootverbose) {
|
||||
printf("ds1: setmap %lx, %lx; ", (unsigned long)segs->ds_addr,
|
||||
(unsigned long)segs->ds_len);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ds_init(struct sc_info *sc)
|
||||
{
|
||||
int i;
|
||||
u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb;
|
||||
u_int8_t *t;
|
||||
void *buf;
|
||||
bus_dmamap_t map;
|
||||
|
||||
ci = ds_devs[sc->type].mcode;
|
||||
|
||||
ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
|
||||
ds_enadsp(sc, 0);
|
||||
ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
|
||||
ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
|
||||
ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
|
||||
ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
|
||||
ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
|
||||
ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
|
||||
ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
|
||||
r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
|
||||
ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
|
||||
|
||||
for (i = 0; i < YDSXG_DSPLENGTH; i += 4)
|
||||
ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4);
|
||||
|
||||
for (i = 0; i < YDSXG_CTRLLENGTH; i += 4)
|
||||
ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4);
|
||||
|
||||
ds_enadsp(sc, 1);
|
||||
|
||||
pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2;
|
||||
rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2;
|
||||
ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2;
|
||||
ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2;
|
||||
|
||||
memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws;
|
||||
memsz += (64 + 1) * 4;
|
||||
|
||||
if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map))
|
||||
return -1;
|
||||
if (bus_dmamap_load(sc->parent_dmat, map, buf, memsz, ds_setmap, sc, 0))
|
||||
return -1;
|
||||
if (!sc->ctrlbase)
|
||||
return -1;
|
||||
|
||||
cb = 0;
|
||||
t = buf;
|
||||
ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
|
||||
cb += ws;
|
||||
sc->pbase = (u_int32_t *)(t + cb);
|
||||
/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
|
||||
ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
|
||||
cb += (64 + 1) * 4;
|
||||
ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
|
||||
cb += 2 * 2 * rcs;
|
||||
ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
|
||||
cb += 5 * 2 * ecs;
|
||||
|
||||
sc->pbankbase = sc->ctrlbase + cb;
|
||||
sc->pbanksize = pcs;
|
||||
for (i = 0; i < 64; i++) {
|
||||
wrl(sc, &sc->pbase[i + 1], 0);
|
||||
sc->pbank[i * 2] = (struct pbank *)(t + cb);
|
||||
/* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
|
||||
cb += pcs;
|
||||
sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb);
|
||||
/* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
|
||||
cb += pcs;
|
||||
}
|
||||
wrl(sc, &sc->pbase[0], DS1_CHANS * 2);
|
||||
|
||||
sc->pchn = sc->rchn = 0;
|
||||
ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ds_finddev(u_int32_t dev, u_int32_t subdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ds_devs[i].dev; i++) {
|
||||
if (ds_devs[i].dev == dev &&
|
||||
(ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ds_pci_probe(device_t dev)
|
||||
{
|
||||
int i;
|
||||
u_int32_t subdev;
|
||||
|
||||
subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
|
||||
i = ds_finddev(pci_get_devid(dev), subdev);
|
||||
if (i >= 0) {
|
||||
device_set_desc(dev, ds_devs[i].name);
|
||||
return 0;
|
||||
} else
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
ds_pci_attach(device_t dev)
|
||||
{
|
||||
snddev_info *d;
|
||||
u_int32_t data;
|
||||
u_int32_t subdev, i;
|
||||
struct sc_info *sc;
|
||||
struct ac97_info *codec;
|
||||
char status[SND_STATUSLEN];
|
||||
|
||||
d = device_get_softc(dev);
|
||||
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
|
||||
device_printf(dev, "cannot allocate softc\n");
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
bzero(sc, sizeof(*sc));
|
||||
sc->dev = dev;
|
||||
subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
|
||||
sc->type = ds_finddev(pci_get_devid(dev), subdev);
|
||||
sc->rev = pci_get_revid(dev);
|
||||
|
||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
|
||||
pci_write_config(dev, PCIR_COMMAND, data, 2);
|
||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
|
||||
sc->regid = PCIR_MAPS;
|
||||
sc->reg = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->regid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (!sc->reg) {
|
||||
device_printf(dev, "unable to map register space\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
sc->st = rman_get_bustag(sc->reg);
|
||||
sc->sh = rman_get_bushandle(sc->reg);
|
||||
|
||||
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
|
||||
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
/*filter*/NULL, /*filterarg*/NULL,
|
||||
/*maxsize*/65536, /*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||
/*flags*/0, &sc->parent_dmat) != 0) {
|
||||
device_printf(dev, "unable to create dma tag\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (ds_init(sc) == -1) {
|
||||
device_printf(dev, "unable to initialize the card\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
codec = ac97_create(dev, sc, ds_initcd, ds_rdcd, ds_wrcd);
|
||||
if (codec == NULL)
|
||||
goto bad;
|
||||
mixer_init(d, &ac97_mixer, codec);
|
||||
|
||||
sc->irqid = 0;
|
||||
sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
|
||||
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
|
||||
if (!sc->irq ||
|
||||
bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ds_intr, sc, &sc->ih)) {
|
||||
device_printf(dev, "unable to map interrupt\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld",
|
||||
rman_get_start(sc->reg), rman_get_start(sc->irq));
|
||||
|
||||
if (pcm_register(dev, sc, DS1_CHANS, 0))
|
||||
goto bad;
|
||||
for (i = 0; i < DS1_CHANS; i++)
|
||||
pcm_addchan(dev, PCMDIR_PLAY, &ds_chantemplate, sc);
|
||||
/*
|
||||
pcm_addchan(dev, PCMDIR_REC, &ds_chantemplate, sc);
|
||||
*/
|
||||
pcm_setstatus(dev, status);
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
if (sc->reg)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
|
||||
if (sc->ih)
|
||||
bus_teardown_intr(dev, sc->irq, sc->ih);
|
||||
if (sc->irq)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
|
||||
free(sc, M_DEVBUF);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static device_method_t ds1_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, ds_pci_probe),
|
||||
DEVMETHOD(device_attach, ds_pci_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t ds1_driver = {
|
||||
"pcm",
|
||||
ds1_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
static devclass_t pcm_devclass;
|
||||
|
||||
DRIVER_MODULE(ds1, pci, ds1_driver, pcm_devclass, 0, 0);
|
156
sys/dev/sound/pci/ds1.h
Normal file
156
sys/dev/sound/pci/ds1.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* =======================================================================
|
||||
* title : define
|
||||
* company : YAMAHA
|
||||
* author : Taichi Sugiyama
|
||||
* create Data : 28/Sep/99
|
||||
* =======================================================================
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
|
||||
/* ----- YAMAHA DS-XG Devices -------------------------------------------- */
|
||||
#define YAMAHA 0x1073
|
||||
#define YMF724 0x0004
|
||||
#define YMF724F 0x000d
|
||||
#define YMF734 0x0005
|
||||
#define YMF737 0x0008
|
||||
#define YMF738 0x0020
|
||||
#define YMF740 0x000a
|
||||
#define YMF740C 0x000c
|
||||
#define YMF744 0x0010
|
||||
#define YMF754 0x0012
|
||||
#define YMF738_TEG 0x0006
|
||||
#define DEVICE4CH(x) ((x == YMF738) || (x == YMF744) || (x == YMF754))
|
||||
|
||||
|
||||
#define PCIR_DSXGCTRL 0x48
|
||||
/* ----- interrupt flag -------------------------------------------------- */
|
||||
#define YDSXG_DEFINT 0x01
|
||||
#define YDSXG_TIMERINT 0x02
|
||||
|
||||
|
||||
/* ----- AC97 ------------------------------------------------------------ */
|
||||
#define YDSXG_AC97TIMEOUT 1000
|
||||
#define YDSXG_AC97READCMD 0x8000
|
||||
#define YDSXG_AC97WRITECMD 0x0000
|
||||
#define YDSXG_AC97READFALSE 0xFFFF
|
||||
|
||||
|
||||
/* ----- AC97 register map _---------------------------------------------- */
|
||||
#define AC97R_GPIOSTATUS 0x54
|
||||
|
||||
|
||||
/* ----- work buffer ----------------------------------------------------- */
|
||||
#define DEF_WORKBUFFLENGTH 0x0400
|
||||
|
||||
|
||||
/* ----- register size --------------------------------------------------- */
|
||||
#define YDSXG_MAPLENGTH 0x8000
|
||||
#define YDSXG_DSPLENGTH 0x0080
|
||||
#define YDSXG_CTRLLENGTH 0x3000
|
||||
|
||||
|
||||
/* ----- register map ---------------------------------------------------- */
|
||||
#define YDSXGR_INTFLAG 0x0004
|
||||
#define YDSXGR_ACTIVITY 0x0006
|
||||
#define YDSXGR_GLOBALCTRL 0x0008
|
||||
#define YDSXGR_ZVCTRL 0x000A
|
||||
#define YDSXGR_TIMERCTRL 0x0010
|
||||
#define YDSXGR_TIMERCOUNT 0x0012
|
||||
#define YDSXGR_SPDIFOUTCTRL 0x0018
|
||||
#define YDSXGR_SPDIFOUTSTATUS 0x001C
|
||||
#define YDSXGR_EEPROMCTRL 0x0020
|
||||
#define YDSXGR_SPDIFINCTRL 0x0034
|
||||
#define YDSXGR_SPDIFINSTATUS 0x0038
|
||||
#define YDSXGR_DSPPROGRAMDL 0x0048
|
||||
#define YDSXGR_DLCNTRL 0x004C
|
||||
#define YDSXGR_GPIOININTFLAG 0x0050
|
||||
#define YDSXGR_GPIOININTENABLE 0x0052
|
||||
#define YDSXGR_GPIOINSTATUS 0x0054
|
||||
#define YDSXGR_GPIOOUTCTRL 0x0056
|
||||
#define YDSXGR_GPIOFUNCENABLE 0x0058
|
||||
#define YDSXGR_GPIOTYPECONFIG 0x005A
|
||||
#define YDSXGR_AC97CMDDATA 0x0060
|
||||
#define YDSXGR_AC97CMDADR 0x0062
|
||||
#define YDSXGR_PRISTATUSDATA 0x0064
|
||||
#define YDSXGR_PRISTATUSADR 0x0066
|
||||
#define YDSXGR_SECSTATUSDATA 0x0068
|
||||
#define YDSXGR_SECSTATUSADR 0x006A
|
||||
#define YDSXGR_SECCONFIG 0x0070
|
||||
#define YDSXGR_LEGACYOUTVOL 0x0080
|
||||
#define YDSXGR_LEGACYOUTVOLL 0x0080
|
||||
#define YDSXGR_LEGACYOUTVOLR 0x0082
|
||||
#define YDSXGR_NATIVEDACOUTVOL 0x0084
|
||||
#define YDSXGR_NATIVEDACOUTVOLL 0x0084
|
||||
#define YDSXGR_NATIVEDACOUTVOLR 0x0086
|
||||
#define YDSXGR_SPDIFOUTVOL 0x0088
|
||||
#define YDSXGR_SPDIFOUTVOLL 0x0088
|
||||
#define YDSXGR_SPDIFOUTVOLR 0x008A
|
||||
#define YDSXGR_AC3OUTVOL 0x008C
|
||||
#define YDSXGR_AC3OUTVOLL 0x008C
|
||||
#define YDSXGR_AC3OUTVOLR 0x008E
|
||||
#define YDSXGR_PRIADCOUTVOL 0x0090
|
||||
#define YDSXGR_PRIADCOUTVOLL 0x0090
|
||||
#define YDSXGR_PRIADCOUTVOLR 0x0092
|
||||
#define YDSXGR_LEGACYLOOPVOL 0x0094
|
||||
#define YDSXGR_LEGACYLOOPVOLL 0x0094
|
||||
#define YDSXGR_LEGACYLOOPVOLR 0x0096
|
||||
#define YDSXGR_NATIVEDACLOOPVOL 0x0098
|
||||
#define YDSXGR_NATIVEDACLOOPVOLL 0x0098
|
||||
#define YDSXGR_NATIVEDACLOOPVOLR 0x009A
|
||||
#define YDSXGR_SPDIFLOOPVOL 0x009C
|
||||
#define YDSXGR_SPDIFLOOPVOLL 0x009E
|
||||
#define YDSXGR_SPDIFLOOPVOLR 0x009E
|
||||
#define YDSXGR_AC3LOOPVOL 0x00A0
|
||||
#define YDSXGR_AC3LOOPVOLL 0x00A0
|
||||
#define YDSXGR_AC3LOOPVOLR 0x00A2
|
||||
#define YDSXGR_PRIADCLOOPVOL 0x00A4
|
||||
#define YDSXGR_PRIADCLOOPVOLL 0x00A4
|
||||
#define YDSXGR_PRIADCLOOPVOLR 0x00A6
|
||||
#define YDSXGR_NATIVEADCINVOL 0x00A8
|
||||
#define YDSXGR_NATIVEADCINVOLL 0x00A8
|
||||
#define YDSXGR_NATIVEADCINVOLR 0x00AA
|
||||
#define YDSXGR_NATIVEDACINVOL 0x00AC
|
||||
#define YDSXGR_NATIVEDACINVOLL 0x00AC
|
||||
#define YDSXGR_NATIVEDACINVOLR 0x00AE
|
||||
#define YDSXGR_BUF441OUTVOL 0x00B0
|
||||
#define YDSXGR_BUF441OUTVOLL 0x00B0
|
||||
#define YDSXGR_BUF441OUTVOLR 0x00B2
|
||||
#define YDSXGR_BUF441LOOPVOL 0x00B4
|
||||
#define YDSXGR_BUF441LOOPVOLL 0x00B4
|
||||
#define YDSXGR_BUF441LOOPVOLR 0x00B6
|
||||
#define YDSXGR_SPDIFOUTVOL2 0x00B8
|
||||
#define YDSXGR_SPDIFOUTVOL2L 0x00B8
|
||||
#define YDSXGR_SPDIFOUTVOL2R 0x00BA
|
||||
#define YDSXGR_SPDIFLOOPVOL2 0x00BC
|
||||
#define YDSXGR_SPDIFLOOPVOL2L 0x00BC
|
||||
#define YDSXGR_SPDIFLOOPVOL2R 0x00BE
|
||||
#define YDSXGR_ADCSLOTSR 0x00C0
|
||||
#define YDSXGR_RECSLOTSR 0x00C4
|
||||
#define YDSXGR_ADCFORMAT 0x00C8
|
||||
#define YDSXGR_RECFORMAT 0x00CC
|
||||
#define YDSXGR_P44SLOTSR 0x00D0
|
||||
#define YDSXGR_STATUS 0x0100
|
||||
#define YDSXGR_CTRLSELECT 0x0104
|
||||
#define YDSXGR_MODE 0x0108
|
||||
#define YDSXGR_SAMPLECOUNT 0x010C
|
||||
#define YDSXGR_NUMOFSAMPLES 0x0110
|
||||
#define YDSXGR_CONFIG 0x0114
|
||||
#define YDSXGR_PLAYCTRLSIZE 0x0140
|
||||
#define YDSXGR_RECCTRLSIZE 0x0144
|
||||
#define YDSXGR_EFFCTRLSIZE 0x0148
|
||||
#define YDSXGR_WORKSIZE 0x014C
|
||||
#define YDSXGR_MAPOFREC 0x0150
|
||||
#define YDSXGR_MAPOFEFFECT 0x0154
|
||||
#define YDSXGR_PLAYCTRLBASE 0x0158
|
||||
#define YDSXGR_RECCTRLBASE 0x015C
|
||||
#define YDSXGR_EFFCTRLBASE 0x0160
|
||||
#define YDSXGR_WORKBASE 0x0164
|
||||
#define YDSXGR_DSPINSTRAM 0x1000
|
||||
#define YDSXGR_CTRLINSTRAM 0x4000
|
||||
|
||||
|
||||
/* ----- time out -------------------------------------------------------- */
|
||||
#define YDSXG_WORKBITTIMEOUT 250000
|
||||
|
Loading…
Reference in New Issue
Block a user