mega-commit.

this introduces a new buffering mechanism which results in dramatic
simplification of the channel manager.

as several structures have changed, we take the opportunity to move their
definitions into the source files where they are used, make them private and
de-typedef them.

the sound drivers are updated to use snd_setup_intr instead of
bus_setup_intr, and to comply with the de-typedefed structures.

the ac97, mixer and channel layers have been updated with finegrained
locking, as have some drivers- not all though.  the rest will follow soon.
This commit is contained in:
cg 2001-03-24 23:10:29 +00:00
parent 22bbfa146c
commit 56760f72c6
44 changed files with 2200 additions and 1891 deletions

View File

@ -37,8 +37,8 @@ struct ad1816_info;
struct ad1816_chinfo {
struct ad1816_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir, blksz;
};
@ -53,6 +53,7 @@ struct ad1816_info {
int drq2_rid;
void *ih;
bus_dma_tag_t parent_dmat;
void *lock;
struct ad1816_chinfo pch, rch;
};
@ -80,10 +81,22 @@ static u_int32_t ad1816_fmt[] = {
0
};
static pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0};
static struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0};
#define AD1816_MUTE 31 /* value for mute */
static void
ad1816_lock(struct ad1816_info *ad1816)
{
snd_mtxlock(ad1816);
}
static void
ad1816_unlock(struct ad1816_info *ad1816)
{
snd_mtxunlock(ad1816);
}
static int
port_rd(struct resource *port, int off)
{
@ -122,6 +135,7 @@ ad1816_intr(void *arg)
struct ad1816_info *ad1816 = (struct ad1816_info *)arg;
unsigned char c, served = 0;
ad1816_lock(ad1816);
/* get interupt status */
c = io_rd(ad1816, AD1816_INT);
@ -149,6 +163,7 @@ ad1816_intr(void *arg)
io_wr(ad1816, AD1816_INT, c);
c = io_rd(ad1816, AD1816_INT);
if (c != 0) printf("pcm: int clear failed (%x)\n", c);
ad1816_unlock(ad1816);
}
static int
@ -166,37 +181,29 @@ ad1816_wait_init(struct ad1816_info *ad1816, int x)
static unsigned short
ad1816_read(struct ad1816_info *ad1816, unsigned int reg)
{
int flags;
u_short x = 0;
/* we don't want to be blocked here */
flags = spltty();
if (ad1816_wait_init(ad1816, 100) == -1) return 0;
io_wr(ad1816, AD1816_ALE, 0);
io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
if (ad1816_wait_init(ad1816, 100) == -1) return 0;
x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW);
splx(flags);
return x;
}
static void
ad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data)
{
int flags;
flags = spltty();
if (ad1816_wait_init(ad1816, 100) == -1) return;
io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
io_wr(ad1816, AD1816_LOW, (data & 0x000000ff));
io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8);
splx(flags);
}
/* -------------------------------------------------------------------- */
static int
ad1816mix_init(snd_mixer *m)
ad1816mix_init(struct snd_mixer *m)
{
mix_setdevs(m, AD1816_MIXER_DEVICES);
mix_setrecdevs(m, AD1816_REC_DEVICES);
@ -204,7 +211,7 @@ ad1816mix_init(snd_mixer *m)
}
static int
ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
ad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct ad1816_info *ad1816 = mix_getdevinfo(m);
u_short reg = 0;
@ -219,6 +226,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
if (left == AD1816_MUTE) reg |= 0x8000;
if (right == AD1816_MUTE) reg |= 0x0080;
ad1816_lock(ad1816);
switch (dev) {
case SOUND_MIXER_VOLUME: /* Register 14 master volume */
ad1816_write(ad1816, 14, reg);
@ -257,6 +265,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
printf("ad1816_mixer_set(): unknown device.\n");
break;
}
ad1816_unlock(ad1816);
left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE;
right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE;
@ -265,7 +274,7 @@ ad1816mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
ad1816mix_setrecsrc(snd_mixer *m, u_int32_t src)
ad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct ad1816_info *ad1816 = mix_getdevinfo(m);
int dev;
@ -288,7 +297,9 @@ ad1816mix_setrecsrc(snd_mixer *m, u_int32_t src)
}
dev |= dev << 8;
ad1816_lock(ad1816);
ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev);
ad1816_unlock(ad1816);
return src;
}
@ -303,7 +314,7 @@ MIXER_DECLARE(ad1816mixer);
/* -------------------------------------------------------------------- */
/* channel interface */
static void *
ad1816chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct ad1816_info *ad1816 = devinfo;
struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch;
@ -331,8 +342,9 @@ ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct ad1816_chinfo *ch = data;
struct ad1816_info *ad1816 = ch->parent;
int fmt = AD1816_U8, reg;
ad1816_lock(ad1816);
if (ch->dir == PCMDIR_PLAY) {
reg = AD1816_PLAY;
ad1816_write(ad1816, 8, 0x0000); /* reset base and current counter */
@ -365,6 +377,7 @@ ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format)
}
if (format & AFMT_STEREO) fmt |= AD1816_STEREO;
io_wr(ad1816, reg, fmt);
ad1816_unlock(ad1816);
return format;
}
@ -375,7 +388,9 @@ ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
struct ad1816_info *ad1816 = ch->parent;
RANGE(speed, 4000, 55200);
ad1816_lock(ad1816);
ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed);
ad1816_unlock(ad1816);
return speed;
}
@ -401,6 +416,7 @@ ad1816chan_trigger(kobj_t obj, void *data, int go)
sndbuf_isadma(ch->buffer, go);
wr = (ch->dir == PCMDIR_PLAY);
reg = wr? AD1816_PLAY : AD1816_CAPT;
ad1816_lock(ad1816);
switch (go) {
case PCMTRIG_START:
/* start only if not already running */
@ -435,6 +451,7 @@ ad1816chan_trigger(kobj_t obj, void *data, int go)
}
break;
}
ad1816_unlock(ad1816);
return 0;
}
@ -445,7 +462,7 @@ ad1816chan_getptr(kobj_t obj, void *data)
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
ad1816chan_getcaps(kobj_t obj, void *data)
{
return &ad1816_caps;
@ -495,6 +512,7 @@ ad1816_release_resources(struct ad1816_info *ad1816, device_t dev)
bus_dma_tag_destroy(ad1816->parent_dmat);
ad1816->parent_dmat = 0;
}
if (ad1816->lock) snd_mtxfree(ad1816->lock);
free(ad1816, M_DEVBUF);
}
@ -577,6 +595,7 @@ ad1816_attach(device_t dev)
if (!ad1816) return ENXIO;
bzero(ad1816, sizeof *ad1816);
ad1816->lock = snd_mtxcreate(device_get_nameunit(dev));
ad1816->io_rid = 2;
ad1816->irq_rid = 0;
ad1816->drq1_rid = 0;
@ -586,7 +605,7 @@ ad1816_attach(device_t dev)
ad1816_init(ad1816, dev);
if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no;
bus_setup_intr(dev, ad1816->irq, INTR_TYPE_TTY, ad1816_intr, ad1816, &ad1816->ih);
snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816, &ad1816->ih);
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
@ -613,6 +632,7 @@ ad1816_attach(device_t dev)
return 0;
no:
ad1816_release_resources(ad1816, dev);
return ENXIO;
}
@ -644,7 +664,7 @@ static device_method_t ad1816_methods[] = {
static driver_t ad1816_driver = {
"pcm",
ad1816_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0);

View File

@ -59,7 +59,7 @@ static u_int32_t ess_pfmt[] = {
0
};
static pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0};
static struct pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0};
static u_int32_t ess_rfmt[] = {
AFMT_U8,
@ -73,19 +73,20 @@ static u_int32_t ess_rfmt[] = {
0
};
static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
static struct pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
struct ess_info;
struct ess_chinfo {
struct ess_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir, hwch, stopping, run;
u_int32_t fmt, spd, blksz;
};
struct ess_info {
device_t parent_dev;
struct resource *io_base; /* I/O address for the board */
struct resource *irq;
struct resource *drq1;
@ -130,6 +131,18 @@ static devclass_t pcm_devclass;
* ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte
*/
static void
ess_lock(struct ess_info *sc) {
sbc_lock(device_get_softc(sc->parent_dev));
}
static void
ess_unlock(struct ess_info *sc) {
sbc_unlock(device_get_softc(sc->parent_dev));
}
static int
port_rd(struct resource *port, int off)
{
@ -203,29 +216,21 @@ ess_cmd1(struct ess_info *sc, u_char cmd, int val)
static void
ess_setmixer(struct ess_info *sc, u_int port, u_int value)
{
u_long flags;
DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);)
flags = spltty();
ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff));
DELAY(10);
splx(flags);
}
static int
ess_getmixer(struct ess_info *sc, u_int port)
{
int val;
u_long flags;
flags = spltty();
ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
val = ess_rd(sc, SB_MIX_DATA);
DELAY(10);
splx(flags);
return val;
}
@ -344,6 +349,7 @@ ess_intr(void *arg)
struct ess_info *sc = (struct ess_info *)arg;
int src, pirq, rirq;
ess_lock(sc);
src = 0;
if (ess_getmixer(sc, 0x7a) & 0x80)
src |= 2;
@ -383,6 +389,7 @@ ess_intr(void *arg)
ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80);
if (src & 1)
ess_rd(sc, DSP_DATA_AVAIL);
ess_unlock(sc);
}
/* utility functions for ESS */
@ -497,8 +504,8 @@ ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int le
/* filter cutoff */
ess_setmixer(sc, 0x72, ess_calcfilter(spd));
}
}
return 0;
}
static int
@ -507,6 +514,7 @@ ess_start(struct ess_chinfo *ch)
struct ess_info *sc = ch->parent;
int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
ess_lock(sc);
ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz);
ch->stopping = 0;
if (ch->hwch == 1)
@ -515,6 +523,7 @@ ess_start(struct ess_chinfo *ch)
ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03);
if (play)
ess_cmd(sc, DSP_CMD_SPKON);
ess_unlock(sc);
return 0;
}
@ -524,6 +533,7 @@ ess_stop(struct ess_chinfo *ch)
struct ess_info *sc = ch->parent;
int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
ess_lock(sc);
ch->stopping = 1;
if (ch->hwch == 1)
ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04);
@ -531,13 +541,14 @@ ess_stop(struct ess_chinfo *ch)
ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10);
if (play)
ess_cmd(sc, DSP_CMD_SPKOFF);
ess_unlock(sc);
return 0;
}
/* -------------------------------------------------------------------- */
/* channel interface for ESS18xx */
static void *
esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
esschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct ess_info *sc = devinfo;
struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
@ -619,7 +630,7 @@ esschan_getptr(kobj_t obj, void *data)
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
esschan_getcaps(kobj_t obj, void *data)
{
struct ess_chinfo *ch = data;
@ -642,7 +653,7 @@ CHANNEL_DECLARE(esschan);
/************************************************************/
static int
essmix_init(snd_mixer *m)
essmix_init(struct snd_mixer *m)
{
struct ess_info *sc = mix_getdevinfo(m);
@ -659,7 +670,7 @@ essmix_init(snd_mixer *m)
}
static int
essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
essmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct ess_info *sc = mix_getdevinfo(m);
int preg = 0, rreg = 0, l, r;
@ -723,7 +734,7 @@ essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
essmix_setrecsrc(snd_mixer *m, u_int32_t src)
essmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct ess_info *sc = mix_getdevinfo(m);
u_char recdev;
@ -795,6 +806,7 @@ ess_attach(device_t dev)
return ENXIO;
bzero(sc, sizeof *sc);
sc->parent_dev = device_get_parent(dev);
if (ess_alloc_resources(sc, dev))
goto no;
if (ess_reset_dsp(sc))
@ -828,7 +840,7 @@ ess_attach(device_t dev)
if (sc->newspeed)
ess_setmixer(sc, 0x71, 0x22);
bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih);
snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ess_intr, sc, &sc->ih);
if (!sc->duplex)
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
@ -890,11 +902,12 @@ static device_method_t ess_methods[] = {
static driver_t ess_driver = {
"pcm",
ess_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_ess, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
MODULE_DEPEND(snd_ess, snd_sbc, 1, 1, 1);
MODULE_VERSION(snd_ess, 1);
/************************************************************/
@ -961,7 +974,7 @@ static device_method_t esscontrol_methods[] = {
static driver_t esscontrol_driver = {
"esscontrol",
esscontrol_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(esscontrol, isa, esscontrol_driver, esscontrol_devclass, 0, 0);

View File

@ -46,8 +46,8 @@ struct mss_info;
struct mss_chinfo {
struct mss_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
u_int32_t fmt, blksz;
};
@ -65,6 +65,7 @@ struct mss_info {
int drq2_rid;
void *ih;
bus_dma_tag_t parent_dmat;
void *lock;
char mss_indexed_regs[MSS_INDEXED_REGS];
char opl_indexed_regs[OPL_INDEXED_REGS];
@ -132,7 +133,7 @@ static u_int32_t mss_fmt[] = {
AFMT_STEREO | AFMT_A_LAW,
0
};
static pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0};
static struct pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0};
static u_int32_t guspnp_fmt[] = {
AFMT_U8,
@ -143,7 +144,7 @@ static u_int32_t guspnp_fmt[] = {
AFMT_STEREO | AFMT_A_LAW,
0
};
static pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0};
static struct pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0};
static u_int32_t opti931_fmt[] = {
AFMT_U8,
@ -152,7 +153,7 @@ static u_int32_t opti931_fmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0};
static struct pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0};
#define MD_AD1848 0x91
#define MD_AD1845 0x92
@ -170,6 +171,18 @@ static pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0};
#define FULL_DUPLEX(x) ((x)->bd_flags & BD_F_DUPLEX)
static void
mss_lock(struct mss_info *mss)
{
snd_mtxlock(mss);
}
static void
mss_unlock(struct mss_info *mss)
{
snd_mtxunlock(mss);
}
static int
port_rd(struct resource *port, int off)
{
@ -280,6 +293,8 @@ mss_release_resources(struct mss_info *mss, device_t dev)
bus_dma_tag_destroy(mss->parent_dmat);
mss->parent_dmat = 0;
}
if (mss->lock) snd_mtxfree(mss->lock);
free(mss, M_DEVBUF);
}
@ -322,6 +337,37 @@ mss_alloc_resources(struct mss_info *mss, device_t dev)
return ok;
}
/*
* The various mixers use a variety of bitmasks etc. The Voxware
* driver had a very nice technique to describe a mixer and interface
* to it. A table defines, for each channel, which register, bits,
* offset, polarity to use. This procedure creates the new value
* using the table and the old value.
*/
static void
change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval)
{
u_char mask;
int shift;
DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x "
"r %d p %d bit %d off %d\n",
dev, chn, newval, *regval,
(*t)[dev][chn].regno, (*t)[dev][chn].polarity,
(*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) );
if ( (*t)[dev][chn].polarity == 1) /* reverse */
newval = 100 - newval ;
mask = (1 << (*t)[dev][chn].nbits) - 1;
newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/;
*regval &= ~(mask << shift); /* Filter out the previous value */
*regval |= (newval & mask) << shift; /* Set the new value */
}
/* -------------------------------------------------------------------- */
/* only one source can be set... */
static int
@ -409,7 +455,7 @@ mss_mixer_set(struct mss_info *mss, int dev, int left, int right)
/* -------------------------------------------------------------------- */
static int
mssmix_init(snd_mixer *m)
mssmix_init(struct snd_mixer *m)
{
struct mss_info *mss = mix_getdevinfo(m);
@ -422,8 +468,10 @@ mssmix_init(snd_mixer *m)
case MD_OPTI931:
mix_setdevs(m, OPTI931_MIXER_DEVICES);
mss_lock(mss);
ad_write(mss, 20, 0x88);
ad_write(mss, 21, 0x88);
mss_unlock(mss);
break;
case MD_AD1848:
@ -433,29 +481,35 @@ mssmix_init(snd_mixer *m)
case MD_GUSPNP:
case MD_GUSMAX:
/* this is only necessary in mode 3 ... */
mss_lock(mss);
ad_write(mss, 22, 0x88);
ad_write(mss, 23, 0x88);
mss_unlock(mss);
break;
}
return 0;
}
static int
mssmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
mssmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct mss_info *mss = mix_getdevinfo(m);
mss_lock(mss);
mss_mixer_set(mss, dev, left, right);
mss_unlock(mss);
return left | (right << 8);
}
static int
mssmix_setrecsrc(snd_mixer *m, u_int32_t src)
mssmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct mss_info *mss = mix_getdevinfo(m);
mss_lock(mss);
src = mss_set_recsrc(mss, src);
mss_unlock(mss);
return src;
}
@ -470,7 +524,7 @@ MIXER_DECLARE(mssmix_mixer);
/* -------------------------------------------------------------------- */
static int
ymmix_init(snd_mixer *m)
ymmix_init(struct snd_mixer *m)
{
struct mss_info *mss = mix_getdevinfo(m);
@ -478,18 +532,21 @@ ymmix_init(snd_mixer *m)
mix_setdevs(m, mix_getdevs(m) | SOUND_MASK_VOLUME | SOUND_MASK_MIC
| SOUND_MASK_BASS | SOUND_MASK_TREBLE);
/* Set master volume */
mss_lock(mss);
conf_wr(mss, OPL3SAx_VOLUMEL, 7);
conf_wr(mss, OPL3SAx_VOLUMER, 7);
mss_unlock(mss);
return 0;
}
static int
ymmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
ymmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct mss_info *mss = mix_getdevinfo(m);
int t, l, r;
mss_lock(mss);
switch (dev) {
case SOUND_MIXER_VOLUME:
if (left) t = 15 - (left * 15) / 100;
@ -524,15 +581,18 @@ ymmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
default:
mss_mixer_set(mss, dev, left, right);
}
mss_unlock(mss);
return left | (right << 8);
}
static int
ymmix_setrecsrc(snd_mixer *m, u_int32_t src)
ymmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct mss_info *mss = mix_getdevinfo(m);
mss_lock(mss);
src = mss_set_recsrc(mss, src);
mss_unlock(mss);
return src;
}
@ -711,6 +771,7 @@ mss_intr(void *arg)
int i;
DEB(printf("mss_intr\n"));
mss_lock(mss);
ad_read(mss, 11); /* fake read of status bits */
/* loop until there are interrupts, but no more than 10 times. */
@ -740,6 +801,7 @@ mss_intr(void *arg)
*/
io_wr(mss, MSS_STATUS, 0); /* Clear interrupt status */
}
mss_unlock(mss);
}
/*
@ -751,7 +813,7 @@ ad_wait_init(struct mss_info *mss, int x)
{
int arg = x, n = 0; /* to shut up the compiler... */
for (; x > 0; x--)
if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10);
if ((n = io_rd(mss, MSS_INDEX)) & MSS_IDXBUSY) DELAY(10000);
else return n;
printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n);
return n;
@ -760,15 +822,12 @@ ad_wait_init(struct mss_info *mss, int x)
static int
ad_read(struct mss_info *mss, int reg)
{
u_long flags;
int x;
flags = spltty();
ad_wait_init(mss, 201000);
x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK;
io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x);
x = io_rd(mss, MSS_IDATA);
splx(flags);
/* printf("ad_read %d, %x\n", reg, x); */
return x;
}
@ -776,16 +835,13 @@ ad_read(struct mss_info *mss, int reg)
static void
ad_write(struct mss_info *mss, int reg, u_char data)
{
u_long flags;
int x;
/* printf("ad_write %d, %x\n", reg, data); */
flags = spltty();
ad_wait_init(mss, 1002000);
x = io_rd(mss, MSS_INDEX) & ~MSS_IDXMASK;
io_wr(mss, MSS_INDEX, (u_char)(reg & MSS_IDXMASK) | x);
io_wr(mss, MSS_IDATA, data);
splx(flags);
}
static void
@ -849,7 +905,6 @@ ad_enter_MCE(struct mss_info *mss)
static void
ad_leave_MCE(struct mss_info *mss)
{
u_long flags;
u_char prev;
if ((mss->bd_flags & BD_F_MCE_BIT) == 0) {
@ -859,14 +914,12 @@ ad_leave_MCE(struct mss_info *mss)
ad_wait_init(mss, 1000000);
flags = spltty();
mss->bd_flags &= ~BD_F_MCE_BIT;
prev = io_rd(mss, MSS_INDEX);
prev &= ~MSS_TRD;
io_wr(mss, MSS_INDEX, prev & ~MSS_MCE); /* Clear the MCE bit */
wait_for_calibration(mss);
splx(flags);
}
static int
@ -1011,6 +1064,7 @@ opti931_intr(void *arg)
return;
}
#endif
mss_lock(mss);
i11 = ad_read(mss, 11); /* XXX what's for ? */
again:
@ -1039,6 +1093,7 @@ opti931_intr(void *arg)
else DDB(printf("intr, but mc11 not set\n");)
}
if (loops == 0) BVDDB(printf("intr, nothing in mcir11 0x%02x\n", mc11));
mss_unlock(mss);
return;
}
@ -1046,13 +1101,14 @@ opti931_intr(void *arg)
if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) chn_intr(mss->pch.channel);
opti_wr(mss, 11, ~mc11); /* ack */
if (--loops) goto again;
mss_unlock(mss);
DEB(printf("xxx too many loops\n");)
}
/* -------------------------------------------------------------------- */
/* channel interface */
static void *
msschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
msschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct mss_info *mss = devinfo;
struct mss_chinfo *ch = (dir == PCMDIR_PLAY)? &mss->pch : &mss->rch;
@ -1070,8 +1126,11 @@ static int
msschan_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct mss_chinfo *ch = data;
struct mss_info *mss = ch->parent;
mss_lock(mss);
mss_format(ch, format);
mss_unlock(mss);
return 0;
}
@ -1079,8 +1138,14 @@ static int
msschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct mss_chinfo *ch = data;
struct mss_info *mss = ch->parent;
int r;
return mss_speed(ch, speed);
mss_lock(mss);
r = mss_speed(ch, speed);
mss_unlock(mss);
return r;
}
static int
@ -1096,12 +1161,15 @@ static int
msschan_trigger(kobj_t obj, void *data, int go)
{
struct mss_chinfo *ch = data;
struct mss_info *mss = ch->parent;
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
sndbuf_isadma(ch->buffer, go);
mss_lock(mss);
mss_trigger(ch, go);
mss_unlock(mss);
return 0;
}
@ -1112,7 +1180,7 @@ msschan_getptr(kobj_t obj, void *data)
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
msschan_getcaps(kobj_t obj, void *data)
{
struct mss_chinfo *ch = data;
@ -1581,6 +1649,7 @@ mss_doattach(device_t dev, struct mss_info *mss)
int pdma, rdma, flags = device_get_flags(dev);
char status[SND_STATUSLEN];
mss->lock = snd_mtxcreate(device_get_nameunit(dev));
if (!mss_alloc_resources(mss, dev)) goto no;
mss_init(mss, dev);
pdma = rman_get_start(mss->drq1);
@ -1620,10 +1689,10 @@ mss_doattach(device_t dev, struct mss_info *mss)
mixer_init(dev, (mss->bd_id == MD_YM0020)? &ymmix_mixer_class : &mssmix_mixer_class, mss);
switch (mss->bd_id) {
case MD_OPTI931:
bus_setup_intr(dev, mss->irq, INTR_TYPE_TTY, opti931_intr, mss, &mss->ih);
snd_setup_intr(dev, mss->irq, INTR_MPSAFE, opti931_intr, mss, &mss->ih);
break;
default:
bus_setup_intr(dev, mss->irq, INTR_TYPE_TTY, mss_intr, mss, &mss->ih);
snd_setup_intr(dev, mss->irq, INTR_MPSAFE, mss_intr, mss, &mss->ih);
}
if (pdma == rdma)
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
@ -1775,7 +1844,7 @@ static device_method_t mss_methods[] = {
static driver_t mss_driver = {
"pcm",
mss_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_mss, isa, mss_driver, pcm_devclass, 0, 0);
@ -2049,7 +2118,7 @@ static device_method_t pnpmss_methods[] = {
static driver_t pnpmss_driver = {
"pcm",
pnpmss_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_pnpmss, isa, pnpmss_driver, pcm_devclass, 0, 0);
@ -2134,7 +2203,7 @@ static device_method_t guspcm_methods[] = {
static driver_t guspcm_driver = {
"pcm",
guspcm_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_guspcm, gusc, guspcm_driver, pcm_devclass, 0, 0);

View File

@ -23,6 +23,23 @@ ahead.
*
*/
struct mixer_def {
u_int regno:7;
u_int polarity:1; /* 1 means reversed */
u_int bitoffs:4;
u_int nbits:4;
};
typedef struct mixer_def mixer_ent;
typedef struct mixer_def mixer_tab[32][2];
#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \
{{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}}
#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \
{{reg_l, 0, pos_l, len_l}, {reg_r, 0, pos_r, len_r}}
#define MIX_NONE(name) MIX_ENT(name, 0,0,0,0, 0,0,0,0)
/*
* The four visible registers of the MSS :
*

View File

@ -3,6 +3,13 @@
* $FreeBSD$
*/
#ifndef SB_H
#define SB_H
struct sbc_softc;
void sbc_lock(struct sbc_softc *);
void sbc_unlock(struct sbc_softc *);
/*
* sound blaster registers
*/
@ -182,6 +189,4 @@
#define SB16_IMASK_L 0x3d
#define SB16_IMASK_R 0x3e
#define SB16_OMASK 0x3c
#endif

View File

@ -36,6 +36,8 @@
#include <dev/sound/isa/sb.h>
#include <dev/sound/chip.h>
#include <sys/mutex.h>
#include "mixer_if.h"
#define SB16_BUFFSIZE 4096
@ -46,14 +48,14 @@ static u_int32_t sb16_fmt8[] = {
AFMT_STEREO | AFMT_U8,
0
};
static pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0};
static struct pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0};
static u_int32_t sb16_fmt16[] = {
AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0};
static struct pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0};
static u_int32_t sb16x_fmt[] = {
AFMT_U8,
@ -62,14 +64,14 @@ static u_int32_t sb16x_fmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
static struct pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
struct sb_info;
struct sb_chinfo {
struct sb_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir, run, dch;
u_int32_t fmt, spd, blksz;
};
@ -86,8 +88,11 @@ struct sb_info {
u_long bd_flags; /* board-specific flags */
int prio, prio16;
struct sb_chinfo pch, rch;
device_t parent_dev;
};
static void sb_lock(struct sb_info *sb);
static void sb_unlock(struct sb_info *sb);
static int sb_rd(struct sb_info *sb, int reg);
static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
static int sb_cmd(struct sb_info *sb, u_char val);
@ -148,6 +153,7 @@ sb_dspwr(struct sb_info *sb, u_char val)
return 1;
}
}
if (curproc->p_intr_nesting_level == 0)
printf("sb_dspwr(0x%02x) timed out.\n", val);
return 0;
}
@ -193,28 +199,25 @@ sb_cmd2(struct sb_info *sb, u_char cmd, int val)
static void
sb_setmixer(struct sb_info *sb, u_int port, u_int value)
{
u_long flags;
flags = spltty();
sb_lock(sb);
sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
DELAY(10);
splx(flags);
sb_unlock(sb);
}
static int
sb_getmixer(struct sb_info *sb, u_int port)
{
int val;
u_long flags;
flags = spltty();
sb_lock(sb);
sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
val = sb_rd(sb, SB_MIX_DATA);
DELAY(10);
splx(flags);
sb_unlock(sb);
return val;
}
@ -236,10 +239,15 @@ sb_get_byte(struct sb_info *sb)
static int
sb_reset_dsp(struct sb_info *sb)
{
u_char b;
sb_lock(sb);
sb_wr(sb, SBDSP_RST, 3);
DELAY(100);
sb_wr(sb, SBDSP_RST, 0);
if (sb_get_byte(sb) != 0xAA) {
b = sb_get_byte(sb);
sb_unlock(sb);
if (b != 0xAA) {
DEB(printf("sb_reset_dsp 0x%lx failed\n",
rman_get_start(d->io_base)));
return ENXIO; /* Sorry */
@ -271,7 +279,7 @@ static const struct sb16_mixent sb16_mixtab[32] = {
};
static int
sb16mix_init(snd_mixer *m)
sb16mix_init(struct snd_mixer *m)
{
struct sb_info *sb = mix_getdevinfo(m);
@ -292,7 +300,7 @@ sb16mix_init(snd_mixer *m)
}
static int
sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
sb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct sb_info *sb = mix_getdevinfo(m);
const struct sb16_mixent *e;
@ -317,7 +325,7 @@ sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
sb16mix_setrecsrc(snd_mixer *m, u_int32_t src)
sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct sb_info *sb = mix_getdevinfo(m);
u_char recdev;
@ -429,6 +437,7 @@ sb16_alloc_resources(struct sb_info *sb, device_t dev)
} else return ENXIO;
}
/* sbc does locking for us */
static void
sb_intr(void *arg)
{
@ -441,7 +450,14 @@ sb_intr(void *arg)
*/
reason = 0;
sb_lock(sb);
c = sb_getmixer(sb, IRQ_STAT);
if (c & 1)
sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
if (c & 2)
sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
sb_unlock(sb);
/*
* this tells us if the source is 8-bit or 16-bit dma. We
@ -483,12 +499,6 @@ sb_intr(void *arg)
if ((reason & 2) && (sb->rch.run))
chn_intr(sb->rch.channel);
if (c & 1)
sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
if (c & 2)
sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
}
static int
@ -498,6 +508,7 @@ sb_setup(struct sb_info *sb)
u_int8_t v;
int l, pprio;
sb_lock(sb);
if (sb->bd_flags & BD_F_DMARUN)
sndbuf_isadma(sb->pch.buffer, PCMTRIG_STOP);
if (sb->bd_flags & BD_F_DMARUN2)
@ -591,13 +602,14 @@ sb_setup(struct sb_info *sb)
sndbuf_isadma(ch->buffer, PCMTRIG_START);
sb->bd_flags |= BD_F_DMARUN2;
}
sb_unlock(sb);
return 0;
}
/* channel interface */
static void *
sb16chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
sb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sb_info *sb = devinfo;
struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
@ -671,7 +683,7 @@ sb16chan_getptr(kobj_t obj, void *data)
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
sb16chan_getcaps(kobj_t obj, void *data)
{
struct sb_chinfo *ch = data;
@ -745,7 +757,8 @@ sb16_attach(device_t dev)
return ENXIO;
bzero(sb, sizeof *sb);
BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
sb->parent_dev = device_get_parent(dev);
BUS_READ_IVAR(sb->parent_dev, dev, 1, &ver);
sb->bd_id = ver & 0x0000ffff;
sb->bd_flags = (ver & 0xffff0000) >> 16;
@ -755,7 +768,7 @@ sb16_attach(device_t dev)
goto no;
if (mixer_init(dev, &sb16mix_mixer_class, sb))
goto no;
if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih))
if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih))
goto no;
if (sb->bd_flags & BD_F_SB16X)
@ -810,6 +823,18 @@ sb16_detach(device_t dev)
return 0;
}
static void
sb_lock(struct sb_info *sb) {
sbc_lock(device_get_softc(sb->parent_dev));
}
static void
sb_unlock(struct sb_info *sb) {
sbc_unlock(device_get_softc(sb->parent_dev));
}
static device_method_t sb16_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, sb16_probe),
@ -822,13 +847,10 @@ static device_method_t sb16_methods[] = {
static driver_t sb16_driver = {
"pcm",
sb16_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_sb16, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
MODULE_DEPEND(snd_sb16, snd_sbc, 1, 1, 1);
MODULE_VERSION(snd_sb16, 1);

View File

@ -44,30 +44,31 @@ static u_int32_t sb_fmt[] = {
AFMT_U8,
0
};
static pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0};
static pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0};
static pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0};
static pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0};
static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0};
static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0};
static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0};
static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0};
static u_int32_t sbpro_fmt[] = {
AFMT_U8,
AFMT_STEREO | AFMT_U8,
0
};
static pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0};
static pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0};
static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0};
static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0};
struct sb_info;
struct sb_chinfo {
struct sb_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
u_int32_t fmt, spd, blksz;
};
struct sb_info {
device_t parent_dev;
struct resource *io_base; /* I/O address for the board */
struct resource *irq;
struct resource *drq;
@ -106,6 +107,18 @@ static devclass_t pcm_devclass;
* sb_get_byte returns a single byte from the DSP data port
*/
static void
sb_lock(struct sb_info *sb) {
sbc_lock(device_get_softc(sb->parent_dev));
}
static void
sb_unlock(struct sb_info *sb) {
sbc_unlock(device_get_softc(sb->parent_dev));
}
static int
port_rd(struct resource *port, int off)
{
@ -187,32 +200,27 @@ sb_cmd2(struct sb_info *sb, u_char cmd, int val)
/*
* in the SB, there is a set of indirect "mixer" registers with
* address at offset 4, data at offset 5
*
* we don't need to interlock these, the mixer lock will suffice.
*/
static void
sb_setmixer(struct sb_info *sb, u_int port, u_int value)
{
u_long flags;
flags = spltty();
sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
DELAY(10);
splx(flags);
}
static int
sb_getmixer(struct sb_info *sb, u_int port)
{
int val;
u_long flags;
flags = spltty();
sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
DELAY(10);
val = sb_rd(sb, SB_MIX_DATA);
DELAY(10);
splx(flags);
return val;
}
@ -297,7 +305,7 @@ sb_alloc_resources(struct sb_info *sb, device_t dev)
/************************************************************/
static int
sbpromix_init(snd_mixer *m)
sbpromix_init(struct snd_mixer *m)
{
struct sb_info *sb = mix_getdevinfo(m);
@ -312,7 +320,7 @@ sbpromix_init(snd_mixer *m)
}
static int
sbpromix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct sb_info *sb = mix_getdevinfo(m);
int reg, max;
@ -362,7 +370,7 @@ sbpromix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
sbpromix_setrecsrc(snd_mixer *m, u_int32_t src)
sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct sb_info *sb = mix_getdevinfo(m);
u_char recdev;
@ -391,7 +399,7 @@ MIXER_DECLARE(sbpromix_mixer);
/************************************************************/
static int
sbmix_init(snd_mixer *m)
sbmix_init(struct snd_mixer *m)
{
struct sb_info *sb = mix_getdevinfo(m);
@ -405,7 +413,7 @@ sbmix_init(snd_mixer *m)
}
static int
sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct sb_info *sb = mix_getdevinfo(m);
int reg, max;
@ -443,7 +451,7 @@ sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
return 0;
}
@ -463,6 +471,7 @@ sb_intr(void *arg)
{
struct sb_info *sb = (struct sb_info *)arg;
sb_lock(sb);
if (sndbuf_runsz(sb->pch.buffer) > 0)
chn_intr(sb->pch.channel);
@ -470,6 +479,7 @@ sb_intr(void *arg)
chn_intr(sb->rch.channel);
sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
sb_unlock(sb);
}
static int
@ -496,6 +506,7 @@ sb_speed(struct sb_chinfo *ch)
if (speed > max)
speed = max;
sb_lock(sb);
sb->bd_flags &= ~BD_F_HISPEED;
if (speed > thresh)
sb->bd_flags |= BD_F_HISPEED;
@ -508,6 +519,7 @@ sb_speed(struct sb_chinfo *ch)
speed = (256000000 / (65536 - tmp)) >> stereo;
ch->spd = speed;
sb_unlock(sb);
return speed;
}
@ -522,6 +534,7 @@ sb_start(struct sb_chinfo *ch)
l--;
sb_lock(sb);
if (play)
sb_cmd(sb, DSP_CMD_SPKON);
@ -535,6 +548,7 @@ sb_start(struct sb_chinfo *ch)
sb_cmd(sb, i);
sb->bd_flags |= BD_F_DMARUN;
sb_unlock(sb);
return 0;
}
@ -544,6 +558,7 @@ sb_stop(struct sb_chinfo *ch)
struct sb_info *sb = ch->parent;
int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
sb_lock(sb);
if (sb->bd_flags & BD_F_HISPEED)
sb_reset_dsp(sb);
else
@ -551,13 +566,14 @@ sb_stop(struct sb_chinfo *ch)
if (play)
sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
sb_unlock(sb);
sb->bd_flags &= ~BD_F_DMARUN;
return 0;
}
/* channel interface */
static void *
sbchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sb_info *sb = devinfo;
struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
@ -623,7 +639,7 @@ sbchan_getptr(kobj_t obj, void *data)
return sndbuf_isadmaptr(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
sbchan_getcaps(kobj_t obj, void *data)
{
struct sb_chinfo *ch = data;
@ -687,6 +703,7 @@ sb_attach(device_t dev)
return ENXIO;
bzero(sb, sizeof *sb);
sb->parent_dev = device_get_parent(dev);
BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
sb->bd_id = ver & 0x0000ffff;
sb->bd_flags = (ver & 0xffff0000) >> 16;
@ -697,7 +714,7 @@ sb_attach(device_t dev)
goto no;
if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb))
goto no;
if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih))
if (snd_setup_intr(dev, sb->irq, INTR_MPSAFE, sb_intr, sb, &sb->ih))
goto no;
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
@ -757,11 +774,12 @@ static device_method_t sb_methods[] = {
static driver_t sb_driver = {
"pcm",
sb_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_sb8, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1);
MODULE_VERSION(snd_sb8, 1);

View File

@ -35,9 +35,12 @@
#define DRQ_MAX 2
#define INTR_MAX 2
struct sbc_softc;
struct sbc_ihl {
driver_intr_t *intr[INTR_MAX];
void *intr_arg[INTR_MAX];
struct sbc_softc *parent;
};
/* Here is the parameter structure per a device. */
@ -61,6 +64,8 @@ struct sbc_softc {
void *ih[IRQ_MAX];
void *lock;
u_int32_t bd_ver;
};
@ -106,6 +111,30 @@ static int sb_cmd(struct resource *io, u_char val);
static u_int sb_get_byte(struct resource *io);
static void sb_setmixer(struct resource *io, u_int port, u_int value);
static void
sbc_lockinit(struct sbc_softc *scp)
{
scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev));
}
static void
sbc_lockdestroy(struct sbc_softc *scp)
{
snd_mtxfree(scp->lock);
}
void
sbc_lock(struct sbc_softc *scp)
{
snd_mtxlock(scp->lock);
}
void
sbc_unlock(struct sbc_softc *scp)
{
snd_mtxunlock(scp->lock);
}
static int
sb_rd(struct resource *io, int reg)
{
@ -311,6 +340,7 @@ sbc_attach(device_t dev)
scp = device_get_softc(dev);
bzero(scp, sizeof(*scp));
scp->dev = dev;
sbc_lockinit(scp);
err = "alloc_resource";
if (alloc_resource(scp)) goto bad;
@ -396,7 +426,8 @@ sbc_attach(device_t dev)
err = "setup_intr";
for (i = 0; i < IRQ_MAX; i++) {
if (bus_setup_intr(dev, scp->irq[i], INTR_TYPE_TTY, sbc_intr, &scp->ihl[i], &scp->ih[i]))
scp->ihl[i].parent = scp;
if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i]))
goto bad;
}
@ -439,10 +470,12 @@ sbc_detach(device_t dev)
{
struct sbc_softc *scp = device_get_softc(dev);
sbc_lock(scp);
device_delete_child(dev, scp->child_midi2);
device_delete_child(dev, scp->child_midi1);
device_delete_child(dev, scp->child_pcm);
release_resource(scp);
sbc_lockdestroy(scp);
return bus_generic_detach(dev);
}
@ -452,11 +485,13 @@ sbc_intr(void *p)
struct sbc_ihl *ihl = p;
int i;
/* sbc_lock(ihl->parent); */
i = 0;
while (i < INTR_MAX) {
if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]);
i++;
}
/* sbc_unlock(ihl->parent); */
}
static int
@ -466,24 +501,27 @@ sbc_setup_intr(device_t dev, device_t child, struct resource *irq,
{
struct sbc_softc *scp = device_get_softc(dev);
struct sbc_ihl *ihl = NULL;
int i;
int i, ret;
sbc_lock(scp);
i = 0;
while (i < IRQ_MAX) {
if (irq == scp->irq[i]) ihl = &scp->ihl[i];
i++;
}
if (ihl == NULL) return (EINVAL);
ret = 0;
if (ihl == NULL) ret = EINVAL;
i = 0;
while (i < INTR_MAX) {
while ((ret == 0) && (i < INTR_MAX)) {
if (ihl->intr[i] == NULL) {
ihl->intr[i] = intr;
ihl->intr_arg[i] = arg;
*cookiep = &ihl->intr[i];
return 0;
ret = -1;
} else i++;
}
return (EINVAL);
sbc_unlock(scp);
return (ret > 0)? EINVAL : 0;
}
static int
@ -492,23 +530,26 @@ sbc_teardown_intr(device_t dev, device_t child, struct resource *irq,
{
struct sbc_softc *scp = device_get_softc(dev);
struct sbc_ihl *ihl = NULL;
int i;
int i, ret;
sbc_lock(scp);
i = 0;
while (i < IRQ_MAX) {
if (irq == scp->irq[i]) ihl = &scp->ihl[i];
i++;
}
if (ihl == NULL) return (EINVAL);
ret = 0;
if (ihl == NULL) ret = EINVAL;
i = 0;
while (i < INTR_MAX) {
while ((ret == 0) && (i < INTR_MAX)) {
if (cookie == &ihl->intr[i]) {
ihl->intr[i] = NULL;
ihl->intr_arg[i] = NULL;
return 0;
} else i++;
}
return (EINVAL);
sbc_unlock(scp);
return (ret > 0)? EINVAL : 0;
}
static struct resource *

View File

@ -44,7 +44,7 @@ static u_int32_t au_playfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0};
static struct pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0};
static u_int32_t au_recfmt[] = {
AFMT_U8,
@ -53,7 +53,7 @@ static u_int32_t au_recfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0};
static struct pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0};
/* -------------------------------------------------------------------- */
@ -61,8 +61,8 @@ struct au_info;
struct au_chinfo {
struct au_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
};
@ -73,6 +73,7 @@ struct au_info {
bus_space_handle_t sh[3];
bus_dma_tag_t parent_dmat;
void *lock;
u_int32_t x[32], y[128];
char z[128];
@ -293,7 +294,7 @@ au_prepareoutput(struct au_chinfo *ch, u_int32_t format)
/* -------------------------------------------------------------------- */
/* channel interface */
static void *
auchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
auchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct au_info *au = devinfo;
struct au_chinfo *ch = (dir == PCMDIR_PLAY)? &au->pch : NULL;
@ -365,7 +366,7 @@ auchan_getptr(kobj_t obj, void *data)
}
}
static pcmchan_caps *
static struct pcmchan_caps *
auchan_getcaps(kobj_t obj, void *data)
{
struct au_chinfo *ch = data;
@ -620,8 +621,7 @@ au_pci_attach(device_t dev)
irqid = 0;
irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!irq
|| bus_setup_intr(dev, irq, INTR_TYPE_TTY, au_intr, au, &ih)) {
if (!irq || snd_setup_intr(dev, irq, 0, au_intr, au, &ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -678,7 +678,7 @@ static device_method_t au_methods[] = {
static driver_t au_driver = {
"pcm",
au_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -83,8 +83,8 @@ struct cmi_info;
struct cmi_chinfo {
struct cmi_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
int bps; /* bytes per sample */
u_int32_t fmt, spd, phys_buf;
@ -115,7 +115,7 @@ static u_int32_t cmi_fmt[] = {
0
};
static pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0};
static struct pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0};
/* ------------------------------------------------------------------------- */
/* Register Utilities */
@ -328,7 +328,7 @@ cmi_spdif_speed(struct cmi_info *cmi, int speed) {
/* Channel Interface implementation */
static void *
cmichan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
cmichan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct cmi_info *cmi = devinfo;
struct cmi_chinfo *ch = (dir == PCMDIR_PLAY) ? &cmi->pch : &cmi->rch;
@ -541,7 +541,7 @@ cmi_intr(void *data)
return;
}
static pcmchan_caps *
static struct pcmchan_caps *
cmichan_getcaps(kobj_t obj, void *data)
{
return &cmi_caps;
@ -610,7 +610,7 @@ struct sb16props {
#define MIXER_GAIN_REG_RTOL(r) (r - 1)
static int
cmimix_init(snd_mixer *m)
cmimix_init(struct snd_mixer *m)
{
struct cmi_info *cmi = mix_getdevinfo(m);
u_int32_t i,v;
@ -635,7 +635,7 @@ cmimix_init(snd_mixer *m)
}
static int
cmimix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
cmimix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct cmi_info *cmi = mix_getdevinfo(m);
u_int32_t r, l, max;
@ -683,7 +683,7 @@ cmimix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
cmimix_setrecsrc(snd_mixer *m, u_int32_t src)
cmimix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct cmi_info *cmi = mix_getdevinfo(m);
u_int32_t i, ml, sl;
@ -760,7 +760,7 @@ cmi_probe(device_t dev)
static int
cmi_attach(device_t dev)
{
snddev_info *d;
struct snddev_info *d;
struct cmi_info *cmi;
u_int32_t data;
char status[SND_STATUSLEN];
@ -793,7 +793,7 @@ cmi_attach(device_t dev)
cmi->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &cmi->irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!cmi->irq ||
bus_setup_intr(dev, cmi->irq, INTR_TYPE_TTY, cmi_intr, cmi, &cmi->ih)){
snd_setup_intr(dev, cmi->irq, 0, cmi_intr, cmi, &cmi->ih)) {
device_printf(dev, "cmi_attach: Unable to map interrupt\n");
goto bad;
}
@ -877,7 +877,7 @@ static device_method_t cmi_methods[] = {
static driver_t cmi_driver = {
"pcm",
cmi_methods,
sizeof(snddev_info)
sizeof(struct snddev_info)
};
static devclass_t pcm_devclass;

View File

@ -68,8 +68,8 @@ struct sc_info;
struct sc_chinfo {
struct sc_info *parent;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
u_int32_t spd, fmt, bps, blksz;
@ -134,7 +134,7 @@ static u_int32_t cs4281_fmts[] = {
0
};
static pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0};
static struct pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0};
/* -------------------------------------------------------------------- */
/* Hardware */
@ -310,7 +310,7 @@ AC97_DECLARE(cs4281_ac97);
/* shared rec/play channel interface */
static void *
cs4281chan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
cs4281chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch;
@ -437,7 +437,7 @@ cs4281chan_trigger(kobj_t obj, void *data, int go)
return 0;
}
static pcmchan_caps *
static struct pcmchan_caps *
cs4281chan_getcaps(kobj_t obj, void *data)
{
return &cs4281_caps;
@ -810,7 +810,7 @@ cs4281_pci_attach(device_t dev)
goto bad;
}
if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, cs4281_intr, sc, &sc->ih)) {
if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) {
device_printf(dev, "unable to setup interrupt\n");
goto bad;
}
@ -962,7 +962,7 @@ static device_method_t cs4281_methods[] = {
static driver_t cs4281_driver = {
"pcm",
cs4281_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -155,7 +155,7 @@ csa_attach(device_t dev)
}
/* Enable interrupt. */
if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, scp, &scp->ih)) {
if (snd_setup_intr(dev, resp->irq, 0, csa_intr, scp, &scp->ih)) {
bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);

View File

@ -45,8 +45,8 @@ struct csa_info;
struct csa_chinfo {
struct csa_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
u_int32_t fmt;
int dma;
@ -93,14 +93,14 @@ static u_int32_t csa_playfmt[] = {
AFMT_STEREO | AFMT_S16_BE,
0
};
static pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0};
static struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0};
static u_int32_t csa_recfmt[] = {
AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
/* -------------------------------------------------------------------- */
/* ac97 codec */
@ -515,7 +515,7 @@ csa_startdsp(csa_res *resp)
/* channel interface */
static void *
csachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct csa_info *csa = devinfo;
struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch;
@ -654,7 +654,7 @@ csachan_getptr(kobj_t obj, void *data)
return (ptr);
}
static pcmchan_caps *
static struct pcmchan_caps *
csachan_getcaps(kobj_t obj, void *data)
{
struct csa_chinfo *ch = data;
@ -854,7 +854,7 @@ pcmcsa_attach(device_t dev)
snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq));
/* Enable interrupt. */
if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, csa, &csa->ih)) {
if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) {
ac97_destroy(codec);
csa_releaseres(csa, dev);
return (ENXIO);
@ -902,7 +902,7 @@ static device_method_t pcmcsa_methods[] = {
static driver_t pcmcsa_driver = {
"pcm",
pcmcsa_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -87,8 +87,8 @@ struct sc_info;
/* channel registers */
struct sc_pchinfo {
int run, spd, dir, fmt;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
volatile struct pbank *lslot, *rslot;
int lsnum, rsnum;
struct sc_info *parent;
@ -96,8 +96,8 @@ struct sc_pchinfo {
struct sc_rchinfo {
int run, spd, dir, fmt, num;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
volatile struct rbank *slot;
struct sc_info *parent;
};
@ -116,6 +116,7 @@ struct sc_info {
struct resource *reg, *irq;
int regid, irqid;
void *ih;
void *lock;
void *regbase;
u_int32_t *pbase, pbankbase, pbanksize;
@ -175,7 +176,7 @@ static u_int32_t ds_recfmt[] = {
AFMT_STEREO | AFMT_U16_LE,
0
};
static pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
static struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
static u_int32_t ds_playfmt[] = {
AFMT_U8,
@ -184,7 +185,7 @@ static u_int32_t ds_playfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
static struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
/* -------------------------------------------------------------------- */
/* Hardware */
@ -473,7 +474,7 @@ ds_setuprch(struct sc_rchinfo *ch)
/* -------------------------------------------------------------------- */
/* play channel interface */
static void *
ds1pchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ds1pchan_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;
@ -550,7 +551,9 @@ ds1pchan_trigger(kobj_t obj, void *data, int go)
ds_setuppch(ch);
ds_enapslot(sc, ch->lsnum, 1);
ds_enapslot(sc, ch->rsnum, stereo);
snd_mtxlock(sc->lock);
ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
snd_mtxunlock(sc->lock);
} else {
ch->run = 0;
/* ds_setuppch(ch); */
@ -580,7 +583,7 @@ ds1pchan_getptr(kobj_t obj, void *data)
return ptr;
}
static pcmchan_caps *
static struct pcmchan_caps *
ds1pchan_getcaps(kobj_t obj, void *data)
{
return &ds_playcaps;
@ -601,7 +604,7 @@ CHANNEL_DECLARE(ds1pchan);
/* -------------------------------------------------------------------- */
/* record channel interface */
static void *
ds1rchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ds1rchan_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;
@ -672,15 +675,19 @@ ds1rchan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_START) {
ch->run = 1;
ds_setuprch(ch);
snd_mtxlock(sc->lock);
x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01;
ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
snd_mtxunlock(sc->lock);
} else {
ch->run = 0;
snd_mtxlock(sc->lock);
x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01);
ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
snd_mtxunlock(sc->lock);
}
return 0;
@ -695,7 +702,7 @@ ds1rchan_getptr(kobj_t obj, void *data)
return ch->slot[sc->currbank].PgStart;
}
static pcmchan_caps *
static struct pcmchan_caps *
ds1rchan_getcaps(kobj_t obj, void *data)
{
return &ds_reccaps;
@ -721,6 +728,7 @@ ds_intr(void *p)
struct sc_info *sc = (struct sc_info *)p;
u_int32_t i, x;
snd_mtxlock(sc->lock);
i = ds_rd(sc, YDSXGR_STATUS, 4);
if (i & 0x00008000)
device_printf(sc->dev, "timeout irq\n");
@ -746,6 +754,7 @@ ds_intr(void *p)
ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
}
snd_mtxunlock(sc->lock);
}
/* -------------------------------------------------------------------- */
@ -922,12 +931,12 @@ ds_pci_attach(device_t dev)
struct ac97_info *codec = NULL;
char status[SND_STATUSLEN];
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
device_printf(dev, "cannot allocate softc\n");
return ENXIO;
}
bzero(sc, sizeof(*sc));
sc->lock = snd_mtxcreate(device_get_nameunit(dev));
sc->dev = dev;
subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
sc->type = ds_finddev(pci_get_devid(dev), subdev);
@ -973,8 +982,7 @@ ds_pci_attach(device_t dev)
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)) {
if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -1003,6 +1011,8 @@ ds_pci_attach(device_t dev)
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
if (sc->parent_dmat)
bus_dma_tag_destroy(sc->parent_dmat);
if (sc->lock)
snd_mtxfree(sc->lock);
free(sc, M_DEVBUF);
return ENXIO;
}
@ -1041,6 +1051,7 @@ ds_pci_detach(device_t dev)
bus_teardown_intr(dev, sc->irq, sc->ih);
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
bus_dma_tag_destroy(sc->parent_dmat);
snd_mtxfree(sc->lock);
free(sc, M_DEVBUF);
return 0;
}
@ -1057,7 +1068,7 @@ static device_method_t ds1_methods[] = {
static driver_t ds1_driver = {
"pcm",
ds1_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -61,7 +61,7 @@ struct emu_voice {
int start, end, vol;
u_int32_t buf;
struct emu_voice *slave;
pcm_channel *channel;
struct pcm_channel *channel;
};
struct sc_info;
@ -70,16 +70,16 @@ struct sc_info;
struct sc_pchinfo {
int spd, fmt, blksz, run;
struct emu_voice *master, *slave;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
};
struct sc_rchinfo {
int spd, fmt, run, blksz, num;
u_int32_t idxreg, basereg, sizereg, setupreg, irqmask;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
};
@ -96,6 +96,7 @@ struct sc_info {
struct resource *reg, *irq;
int regtype, regid, irqid;
void *ih;
void *lock;
int timer, timerinterval;
int pnum, rnum;
@ -144,7 +145,7 @@ static u_int32_t emu_rfmt_efx[] = {
0
};
static pcmchan_caps emu_reccaps[3] = {
static struct pcmchan_caps emu_reccaps[3] = {
{8000, 48000, emu_rfmt_ac97, 0},
{8000, 8000, emu_rfmt_mic, 0},
{48000, 48000, emu_rfmt_efx, 0},
@ -158,7 +159,7 @@ static u_int32_t emu_pfmt[] = {
0
};
static pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000};
@ -239,6 +240,7 @@ emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data)
/* -------------------------------------------------------------------- */
/* ac97 codec */
/* no locking needed */
static int
emu_rdcd(kobj_t obj, void *devinfo, int regno)
@ -267,40 +269,6 @@ static kobj_method_t emu_ac97_methods[] = {
AC97_DECLARE(emu_ac97);
/* -------------------------------------------------------------------- */
#if 0
/* playback channel interrupts */
static u_int32_t
emu_testint(struct sc_info *sc, char channel)
{
int reg = (channel & 0x20)? CLIPH : CLIPL;
channel &= 0x1f;
reg |= 1 << 24;
reg |= channel << 16;
return emu_rdptr(sc, 0, reg);
}
static void
emu_clrint(struct sc_info *sc, char channel)
{
int reg = (channel & 0x20)? CLIPH : CLIPL;
channel &= 0x1f;
reg |= 1 << 24;
reg |= channel << 16;
emu_wrptr(sc, 0, reg, 1);
}
static void
emu_enaint(struct sc_info *sc, char channel, int enable)
{
int reg = (channel & 0x20)? CLIEH : CLIEL;
channel &= 0x1f;
reg |= 1 << 24;
reg |= channel << 16;
emu_wrptr(sc, 0, reg, enable);
}
#endif
/* stuff */
static int
emu_settimer(struct sc_info *sc)
@ -450,15 +418,15 @@ emu_valloc(struct sc_info *sc)
static int
emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
u_int32_t sz, pcm_channel *c)
u_int32_t sz, struct snd_dbuf *b)
{
void *buf;
buf = emu_memalloc(sc, sz);
if (buf == NULL)
return -1;
if (c != NULL)
sndbuf_setup(&c->buffer, buf, sz);
if (b != NULL)
sndbuf_setup(b, buf, sz);
m->start = emu_memstart(sc, buf) * EMUPAGESIZE;
m->end = m->start + sz;
m->channel = NULL;
@ -646,10 +614,11 @@ emu_vdump(struct sc_info *sc, struct emu_voice *v)
/* channel interface */
static void *
emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, 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;
void *r;
KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction"));
ch = &sc->pch[sc->pnum++];
@ -659,12 +628,13 @@ emupchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
ch->blksz = EMU_BUFFSIZE / 2;
ch->fmt = AFMT_U8;
ch->spd = 8000;
snd_mtxlock(sc->lock);
ch->master = emu_valloc(sc);
ch->slave = emu_valloc(sc);
if (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->channel))
return NULL;
else
return ch;
r = (emu_vinit(sc, ch->master, ch->slave, EMU_BUFFSIZE, ch->buffer))? NULL : ch;
snd_mtxunlock(sc->lock);
return r;
}
static int
@ -672,8 +642,13 @@ emupchan_free(kobj_t obj, void *data)
{
struct sc_pchinfo *ch = data;
struct sc_info *sc = ch->parent;
int r;
return emu_memfree(sc, sndbuf_getbuf(ch->buffer));
snd_mtxlock(sc->lock);
r = emu_memfree(sc, sndbuf_getbuf(ch->buffer));
snd_mtxunlock(sc->lock);
return r;
}
static int
@ -702,8 +677,10 @@ emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
int irqrate, blksz;
ch->blksz = blocksize;
snd_mtxlock(sc->lock);
emu_settimer(sc);
irqrate = 48000 / sc->timerinterval;
snd_mtxunlock(sc->lock);
blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate;
return blocksize;
}
@ -717,6 +694,7 @@ emupchan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
snd_mtxlock(sc->lock);
if (go == PCMTRIG_START) {
emu_vsetup(ch);
emu_vwrite(sc, ch->master);
@ -733,6 +711,7 @@ emupchan_trigger(kobj_t obj, void *data, int go)
}
ch->run = (go == PCMTRIG_START)? 1 : 0;
emu_vtrigger(sc, ch->master, ch->run);
snd_mtxunlock(sc->lock);
return 0;
}
@ -741,11 +720,16 @@ emupchan_getptr(kobj_t obj, void *data)
{
struct sc_pchinfo *ch = data;
struct sc_info *sc = ch->parent;
int r;
return emu_vpos(sc, ch->master);
snd_mtxlock(sc->lock);
r = emu_vpos(sc, ch->master);
snd_mtxunlock(sc->lock);
return r;
}
static pcmchan_caps *
static struct pcmchan_caps *
emupchan_getcaps(kobj_t obj, void *data)
{
return &emu_playcaps;
@ -766,7 +750,7 @@ CHANNEL_DECLARE(emupchan);
/* channel interface */
static void *
emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, 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;
@ -809,8 +793,10 @@ emurchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, EMU_BUFFSIZE) == -1)
return NULL;
else {
snd_mtxlock(sc->lock);
emu_wrptr(sc, 0, ch->basereg, vtophys(sndbuf_getbuf(ch->buffer)));
emu_wrptr(sc, 0, ch->sizereg, 0); /* off */
snd_mtxunlock(sc->lock);
return ch;
}
}
@ -847,8 +833,10 @@ emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
int irqrate, blksz;
ch->blksz = blocksize;
snd_mtxlock(sc->lock);
emu_settimer(sc);
irqrate = 48000 / sc->timerinterval;
snd_mtxunlock(sc->lock);
blksz = (ch->spd * sndbuf_getbps(ch->buffer)) / irqrate;
return blocksize;
}
@ -861,6 +849,7 @@ emurchan_trigger(kobj_t obj, void *data, int go)
struct sc_info *sc = ch->parent;
u_int32_t val;
snd_mtxlock(sc->lock);
switch(go) {
case PCMTRIG_START:
ch->run = 1;
@ -893,6 +882,7 @@ emurchan_trigger(kobj_t obj, void *data, int go)
default:
break;
}
snd_mtxunlock(sc->lock);
return 0;
}
@ -902,11 +892,16 @@ emurchan_getptr(kobj_t obj, void *data)
{
struct sc_rchinfo *ch = data;
struct sc_info *sc = ch->parent;
int r;
return emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff;
snd_mtxlock(sc->lock);
r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff;
snd_mtxunlock(sc->lock);
return r;
}
static pcmchan_caps *
static struct pcmchan_caps *
emurchan_getcaps(kobj_t obj, void *data)
{
struct sc_rchinfo *ch = data;
@ -1421,12 +1416,12 @@ emu_pci_attach(device_t dev)
int i, mapped;
char status[SND_STATUSLEN];
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
device_printf(dev, "cannot allocate softc\n");
return ENXIO;
}
bzero(sc, sizeof(*sc));
sc->lock = snd_mtxcreate(device_get_nameunit(dev));
sc->dev = dev;
sc->type = pci_get_devid(dev);
sc->rev = pci_get_revid(dev);
@ -1482,8 +1477,7 @@ emu_pci_attach(device_t dev)
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, emu_intr, sc, &sc->ih)) {
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;
}
@ -1508,6 +1502,7 @@ emu_pci_attach(device_t dev)
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);
if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat);
if (sc->lock) snd_mtxfree(sc->lock);
free(sc, M_DEVBUF);
return ENXIO;
}
@ -1530,6 +1525,7 @@ emu_pci_detach(device_t dev)
bus_teardown_intr(dev, sc->irq, sc->ih);
bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
bus_dma_tag_destroy(sc->parent_dmat);
snd_mtxfree(sc->lock);
free(sc, M_DEVBUF);
return 0;
@ -1548,7 +1544,7 @@ static device_method_t emu_methods[] = {
static driver_t emu_driver = {
"pcm",
emu_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -79,8 +79,8 @@ struct es_info;
struct es_chinfo {
struct es_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir, num;
u_int32_t fmt, blksz, bufsz;
};
@ -122,7 +122,7 @@ static u_int32_t es_playfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0};
static struct pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0};
static u_int32_t es_recfmt[] = {
AFMT_U8,
@ -131,7 +131,7 @@ static u_int32_t es_recfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0};
static struct pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0};
static const struct {
unsigned volidx:4;
@ -157,7 +157,7 @@ static const struct {
/* The es1370 mixer interface */
static int
es1370_mixinit(snd_mixer *m)
es1370_mixinit(struct snd_mixer *m)
{
int i;
u_int32_t v;
@ -174,7 +174,7 @@ es1370_mixinit(snd_mixer *m)
}
static int
es1370_mixset(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
es1370_mixset(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
int l, r, rl, rr;
@ -195,7 +195,7 @@ es1370_mixset(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
es1370_mixsetrecsrc(snd_mixer *m, u_int32_t src)
es1370_mixsetrecsrc(struct snd_mixer *m, u_int32_t src)
{
int i, j = 0;
@ -245,7 +245,7 @@ es1370_wrcodec(struct es_info *es, u_char i, u_char data)
/* channel interface */
static void *
eschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
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;
@ -394,7 +394,7 @@ eschan_getptr(kobj_t obj, void *data)
return cnt << 2;
}
static pcmchan_caps *
static struct pcmchan_caps *
eschan_getcaps(kobj_t obj, void *data)
{
struct es_chinfo *ch = data;
@ -818,8 +818,7 @@ es_pci_attach(device_t dev)
es->irqid = 0;
es->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &es->irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!es->irq
|| bus_setup_intr(dev, es->irq, INTR_TYPE_TTY, es_intr, es, &es->ih)) {
if (!es->irq || snd_setup_intr(dev, es->irq, 0, es_intr, es, &es->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -887,7 +886,7 @@ static device_method_t es_methods[] = {
static driver_t es_driver = {
"pcm",
es_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -102,7 +102,7 @@
#define DPRINT if(0) printf
/*
static int fm801ch_setup(pcm_channel *c);
static int fm801ch_setup(struct pcm_channel *c);
*/
static u_int32_t fmts[] = {
@ -113,7 +113,7 @@ static u_int32_t fmts[] = {
0
};
static pcmchan_caps fm801ch_caps = {
static struct pcmchan_caps fm801ch_caps = {
4000, 48000,
fmts, 0
};
@ -122,8 +122,8 @@ struct fm801_info;
struct fm801_chinfo {
struct fm801_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
u_int32_t spd, dir, fmt; /* speed, direction, format */
u_int32_t shift;
};
@ -318,7 +318,7 @@ fm801_intr(void *p)
/* -------------------------------------------------------------------- */
/* channel interface */
static void *
fm801ch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
fm801ch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct fm801_info *fm801 = (struct fm801_info *)devinfo;
struct fm801_chinfo *ch = (dir == PCMDIR_PLAY)? &fm801->pch : &fm801->rch;
@ -504,7 +504,7 @@ fm801ch_getptr(kobj_t obj, void *data)
return result;
}
static pcmchan_caps *
static struct pcmchan_caps *
fm801ch_getcaps(kobj_t obj, void *data)
{
return &fm801ch_caps;
@ -615,9 +615,7 @@ fm801_pci_attach(device_t dev)
fm801->irqid = 0;
fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!fm801->irq ||
bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY,
fm801_intr, fm801, &fm801->ih)) {
if (!fm801->irq || snd_setup_intr(dev, fm801->irq, 0, fm801_intr, fm801, &fm801->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto oops;
}
@ -703,7 +701,7 @@ static device_method_t fm801_methods[] = {
static driver_t fm801_driver = {
"pcm",
fm801_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -81,8 +81,8 @@
*/
struct agg_chinfo {
struct agg_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
bus_addr_t offset;
u_int32_t blocksize;
u_int32_t speed;
@ -109,6 +109,7 @@ struct agg_info {
bus_addr_t baseaddr;
struct ac97_info *codec;
void *lock;
u_int playchns, active;
struct agg_chinfo pch[AGG_MAXPLAYCH];
@ -637,7 +638,7 @@ set_timer(struct agg_info *ess)
*/
static void *
aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct agg_info *ess = devinfo;
struct agg_chinfo *ch;
@ -661,8 +662,7 @@ aggch_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) {
device_printf(ess->dev,
"offset %#x exceeds limit. ", ch->offset);
dma_free(ess, b->buf);
b->buf = NULL;
dma_free(ess, sndbuf_getbuf(b));
return NULL;
}
@ -786,7 +786,7 @@ aggch_getplayptr(kobj_t obj, void *data)
return cp;
}
static pcmchan_caps *
static struct pcmchan_caps *
aggch_getcaps(kobj_t obj, void *data)
{
static u_int32_t playfmt[] = {
@ -798,7 +798,7 @@ aggch_getcaps(kobj_t obj, void *data)
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps playcaps = {2000, 96000, playfmt, 0};
static struct pcmchan_caps playcaps = {2000, 96000, playfmt, 0};
static u_int32_t recfmt[] = {
AFMT_S8,
@ -807,7 +807,7 @@ aggch_getcaps(kobj_t obj, void *data)
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps reccaps = {4000, 48000, recfmt, 0};
static struct pcmchan_caps reccaps = {4000, 48000, recfmt, 0};
return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)?
&playcaps : &reccaps;
@ -1020,8 +1020,7 @@ agg_attach(device_t dev)
irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid,
0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE);
if (irq == NULL
|| bus_setup_intr(dev, irq, INTR_TYPE_TTY, agg_intr, ess, &ih)) {
if (irq == NULL || snd_setup_intr(dev, irq, 0, agg_intr, ess, &ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -1183,7 +1182,7 @@ static device_method_t agg_methods[] = {
static driver_t agg_driver = {
"pcm",
agg_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -95,8 +95,8 @@ struct sc_info;
struct sc_pchinfo {
u_int32_t spd;
u_int32_t fmt;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
u_int32_t bufsize;
u_int32_t dac_data;
@ -107,8 +107,8 @@ struct sc_pchinfo {
struct sc_rchinfo {
u_int32_t spd;
u_int32_t fmt;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
u_int32_t bufsize;
u_int32_t adc_data;
@ -145,24 +145,24 @@ struct sc_info {
/* -------------------------------------------------------------------- */
/* play channel interface */
static void *m3_pchan_init(kobj_t, void *, snd_dbuf *, pcm_channel *, int);
static void *m3_pchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
static int m3_pchan_free(kobj_t, void *);
static int m3_pchan_setformat(kobj_t, void *, u_int32_t);
static int m3_pchan_setspeed(kobj_t, void *, u_int32_t);
static int m3_pchan_setblocksize(kobj_t, void *, u_int32_t);
static int m3_pchan_trigger(kobj_t, void *, int);
static int m3_pchan_getptr(kobj_t, void *);
static pcmchan_caps *m3_pchan_getcaps(kobj_t, void *);
static struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *);
/* record channel interface */
static void *m3_rchan_init(kobj_t, void *, snd_dbuf *, pcm_channel *, int);
static void *m3_rchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
static int m3_rchan_free(kobj_t, void *);
static int m3_rchan_setformat(kobj_t, void *, u_int32_t);
static int m3_rchan_setspeed(kobj_t, void *, u_int32_t);
static int m3_rchan_setblocksize(kobj_t, void *, u_int32_t);
static int m3_rchan_trigger(kobj_t, void *, int);
static int m3_rchan_getptr(kobj_t, void *);
static pcmchan_caps *m3_rchan_getcaps(kobj_t, void *);
static struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *);
/* talk to the codec - called from ac97.c */
static int m3_initcd(kobj_t, void *);
@ -200,7 +200,7 @@ static u_int32_t m3_playfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0};
static struct pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0};
static kobj_method_t m3_pch_methods[] = {
KOBJMETHOD(channel_init, m3_pchan_init),
@ -222,7 +222,7 @@ static u_int32_t m3_recfmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0};
static struct pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0};
static kobj_method_t m3_rch_methods[] = {
KOBJMETHOD(channel_init, m3_rchan_init),
@ -314,7 +314,7 @@ m3_rdcd(kobj_t kobj, void *devinfo, int regno)
return -1;
}
m3_wr_1(sc, CODEC_COMMAND, (regno & 0x7f) | 0x80);
DELAY(21); /* ac97 cycle = 20.8 usec */
DELAY(50); /* ac97 cycle = 20.8 usec */
if (m3_wait(sc)) {
device_printf(sc->dev, "m3_rdcd timed out.\n");
return -1;
@ -333,6 +333,7 @@ m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data)
}
m3_wr_2(sc, CODEC_DATA, data);
m3_wr_1(sc, CODEC_COMMAND, regno & 0x7f);
DELAY(50); /* ac97 cycle = 20.8 usec */
return 0;
}
@ -343,7 +344,7 @@ m3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data)
#define HI(x) (((x) & 0xffff0000) >> 16)
static void *
m3_pchan_init(kobj_t kobj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
m3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_pchinfo *ch;
@ -609,7 +610,7 @@ m3_pchan_getptr(kobj_t kobj, void *chdata)
return (bus_crnt - bus_base); /* current byte offset of channel */
}
static pcmchan_caps *
static struct pcmchan_caps *
m3_pchan_getcaps(kobj_t kobj, void *chdata)
{
struct sc_pchinfo *ch = chdata;
@ -623,7 +624,7 @@ m3_pchan_getcaps(kobj_t kobj, void *chdata)
/* rec channel interface */
static void *
m3_rchan_init(kobj_t kobj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
m3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_rchinfo *ch;
@ -879,7 +880,7 @@ m3_rchan_getptr(kobj_t kobj, void *chdata)
return (bus_crnt - bus_base); /* current byte offset of channel */
}
static pcmchan_caps *
static struct pcmchan_caps *
m3_rchan_getcaps(kobj_t kobj, void *chdata)
{
struct sc_rchinfo *ch = chdata;
@ -1133,8 +1134,7 @@ m3_pci_attach(device_t dev)
goto bad;
}
if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, m3_intr, sc,
&sc->ih)) {
if (snd_setup_intr(dev, sc->irq, 0, m3_intr, sc, &sc->ih)) {
device_printf(dev, "unable to setup interrupt\n");
goto bad;
}
@ -1192,6 +1192,7 @@ m3_pci_attach(device_t dev)
device_printf(dev, "attach: pcm_setstatus error\n");
goto bad;
}
mixer_hwvol_init(dev);
/* Create the buffer for saving the card state during suspend */
len = sizeof(u_int16_t) * (REV_B_CODE_MEMORY_LENGTH +
@ -1491,7 +1492,7 @@ static device_method_t m3_methods[] = {
static driver_t m3_driver = {
"pcm",
m3_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -48,8 +48,8 @@ struct sc_info;
/* channel registers */
struct sc_chinfo {
int spd, dir, fmt;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct sc_info *parent;
};
@ -117,7 +117,7 @@ static u_int32_t nm_fmt[] = {
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0};
static struct pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0};
/* -------------------------------------------------------------------- */
@ -329,7 +329,7 @@ nm_setch(struct sc_chinfo *ch)
/* channel interface */
static void *
nmchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
nmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_chinfo *ch;
@ -341,7 +341,7 @@ nmchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE);
if (bootverbose)
device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)?
"play" : "rec", ch->buffer->buf);
"play" : "rec", sndbuf_getbuf(ch->buffer));
ch->parent = sc;
ch->channel = c;
ch->dir = dir;
@ -432,7 +432,7 @@ nmchan_getptr(kobj_t obj, void *data)
return nm_rd(sc, NM_RBUFFER_CURRP, 4) - sc->rbuf;
}
static pcmchan_caps *
static struct pcmchan_caps *
nmchan_getcaps(kobj_t obj, void *data)
{
return &nm_caps;
@ -623,8 +623,7 @@ nm_pci_attach(device_t dev)
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, nm_intr, sc, &sc->ih)) {
if (!sc->irq || snd_setup_intr(dev, sc->irq, 0, nm_intr, sc, &sc->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -702,7 +701,7 @@ static device_method_t nm_methods[] = {
static driver_t nm_driver = {
"pcm",
nm_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -55,7 +55,7 @@ static u_int32_t ess_playfmt[] = {
AFMT_STEREO | AFMT_U16_LE,
0
};
static pcmchan_caps ess_playcaps = {5000, 49000, ess_playfmt, 0};
static struct pcmchan_caps ess_playcaps = {5000, 49000, ess_playfmt, 0};
/*
* Recording output is byte-swapped
@ -71,14 +71,14 @@ static u_int32_t ess_recfmt[] = {
AFMT_STEREO | AFMT_U16_BE,
0
};
static pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0};
static struct pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0};
struct ess_info;
struct ess_chinfo {
struct ess_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir, hwch, stopping;
u_int32_t fmt, spd, blksz;
};
@ -510,7 +510,7 @@ ess_stop(struct ess_chinfo *ch)
/* -------------------------------------------------------------------- */
/* channel interface for ESS18xx */
static void *
esschan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
esschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct ess_info *sc = devinfo;
struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
@ -595,7 +595,7 @@ esschan_getptr(kobj_t obj, void *data)
return ess_dmapos(sc, ch->hwch);
}
static pcmchan_caps *
static struct pcmchan_caps *
esschan_getcaps(kobj_t obj, void *data)
{
struct ess_chinfo *ch = data;
@ -618,7 +618,7 @@ CHANNEL_DECLARE(esschan);
/************************************************************/
static int
essmix_init(snd_mixer *m)
essmix_init(struct snd_mixer *m)
{
struct ess_info *sc = mix_getdevinfo(m);
@ -635,7 +635,7 @@ essmix_init(snd_mixer *m)
}
static int
essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
essmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct ess_info *sc = mix_getdevinfo(m);
int preg = 0, rreg = 0, l, r;
@ -695,7 +695,7 @@ essmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
essmix_setrecsrc(snd_mixer *m, u_int32_t src)
essmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct ess_info *sc = mix_getdevinfo(m);
u_char recdev;
@ -944,7 +944,7 @@ ess_attach(device_t dev)
if (sc->newspeed)
ess_setmixer(sc, 0x71, 0x2a);
bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ess_intr, sc, &sc->ih);
snd_setup_intr(dev, sc->irq, 0, ess_intr, sc, &sc->ih);
if (!sc->duplex)
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
@ -1005,7 +1005,7 @@ static device_method_t ess_methods[] = {
static driver_t ess_driver = {
"pcm",
ess_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
DRIVER_MODULE(snd_solo, pci, ess_driver, pcm_devclass, 0, 0);

View File

@ -52,15 +52,15 @@ struct tr_chinfo {
u_int32_t rvol, cvol;
u_int32_t gvsel, pan, vol, ctrl;
int index, bufhalf;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct tr_info *parent;
};
struct tr_rchinfo {
u_int32_t delta;
snd_dbuf *buffer;
pcm_channel *channel;
struct snd_dbuf *buffer;
struct pcm_channel *channel;
struct tr_info *parent;
};
@ -76,6 +76,8 @@ struct tr_info {
int regtype, regid, irqid;
void *ih;
void *lock;
u_int32_t playchns;
struct tr_chinfo chinfo[TR_MAXPLAYCH];
struct tr_rchinfo recchinfo;
@ -94,7 +96,7 @@ static u_int32_t tr_recfmt[] = {
AFMT_STEREO | AFMT_U16_LE,
0
};
static pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
static u_int32_t tr_playfmt[] = {
AFMT_U8,
@ -107,7 +109,7 @@ static u_int32_t tr_playfmt[] = {
AFMT_STEREO | AFMT_U16_LE,
0
};
static pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
/* -------------------------------------------------------------------- */
@ -168,9 +170,11 @@ tr_rdcd(kobj_t obj, void *devinfo, int regno)
}
regno &= 0x7f;
snd_mtxlock(tr->lock);
tr_wr(tr, treg, regno | trw, 4);
j=trw;
for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
snd_mtxunlock(tr->lock);
if (i == 0) printf("codec timeout during read of register %x\n", regno);
return (j >> TR_CDC_DATA) & 0xffff;
}
@ -200,11 +204,13 @@ tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno));
#endif
j=trw;
snd_mtxlock(tr->lock);
for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4);
#if 0
printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno));
#endif
snd_mtxunlock(tr->lock);
if (i==0) printf("codec timeout writing %x, data %x\n", regno, data);
return (i > 0)? 0 : -1;
}
@ -250,6 +256,7 @@ tr_enaint(struct tr_chinfo *ch, int enable)
u_int32_t i, reg;
int bank, chan;
snd_mtxlock(tr->lock);
bank = (ch->index & 0x20) ? 1 : 0;
chan = ch->index & 0x1f;
reg = bank? TR_REG_INTENB : TR_REG_INTENA;
@ -260,6 +267,7 @@ tr_enaint(struct tr_chinfo *ch, int enable)
tr_clrint(ch);
tr_wr(tr, reg, i, 4);
snd_mtxunlock(tr->lock);
}
/* playback channels */
@ -336,9 +344,11 @@ tr_wrch(struct tr_chinfo *ch)
cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14);
break;
}
snd_mtxlock(tr->lock);
tr_selch(ch);
for (i=0; i<TR_CHN_REGS; i++)
tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
snd_mtxunlock(tr->lock);
}
static void
@ -347,9 +357,11 @@ tr_rdch(struct tr_chinfo *ch)
struct tr_info *tr = ch->parent;
u_int32_t cr[5], i;
snd_mtxlock(tr->lock);
tr_selch(ch);
for (i=0; i<5; i++)
cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
snd_mtxunlock(tr->lock);
ch->lba= (cr[1] & 0x3fffffff);
@ -396,7 +408,7 @@ tr_fmttobits(u_int32_t fmt)
/* channel interface */
static void *
trpchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct tr_info *tr = devinfo;
struct tr_chinfo *ch;
@ -480,7 +492,7 @@ trpchan_getptr(kobj_t obj, void *data)
return ch->cso * sndbuf_getbps(ch->buffer);
}
static pcmchan_caps *
static struct pcmchan_caps *
trpchan_getcaps(kobj_t obj, void *data)
{
return &tr_playcaps;
@ -502,7 +514,7 @@ CHANNEL_DECLARE(trpchan);
/* rec channel interface */
static void *
trrchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct tr_info *tr = devinfo;
struct tr_rchinfo *ch;
@ -600,7 +612,7 @@ trrchan_getptr(kobj_t obj, void *data)
return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer));
}
static pcmchan_caps *
static struct pcmchan_caps *
trrchan_getcaps(kobj_t obj, void *data)
{
return &tr_reccaps;
@ -646,9 +658,7 @@ tr_intr(void *p)
if (ch->bufhalf != tmp) {
chn_intr(ch->channel);
ch->bufhalf = tmp;
} else
printf("same bufhalf\n");
}
}
}
chnum++;
@ -716,6 +726,7 @@ tr_pci_attach(device_t dev)
bzero(tr, sizeof(*tr));
tr->type = pci_get_devid(dev);
tr->lock = snd_mtxcreate(device_get_nameunit(dev));
data = pci_read_config(dev, PCIR_COMMAND, 2);
data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
@ -745,8 +756,7 @@ tr_pci_attach(device_t dev)
tr->irqid = 0;
tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!tr->irq ||
bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) {
if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
@ -778,6 +788,7 @@ tr_pci_attach(device_t dev)
if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih);
if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat);
if (tr->lock) snd_mtxfree(tr->lock);
free(tr, M_DEVBUF);
return ENXIO;
}
@ -797,6 +808,7 @@ tr_pci_detach(device_t dev)
bus_teardown_intr(dev, tr->irq, tr->ih);
bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
bus_dma_tag_destroy(tr->parent_dmat);
snd_mtxfree(tr->lock);
free(tr, M_DEVBUF);
return 0;
@ -814,7 +826,7 @@ static device_method_t tr_methods[] = {
static driver_t tr_driver = {
"pcm",
tr_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -36,12 +36,12 @@
#include <dev/sound/pci/via82c686.h>
#define VIA_PCI_ID 0x30581106
#define NSEGS 16 /* Number of segments in SGD table */
#define NSEGS 4 /* Number of segments in SGD table */
#define SEGS_PER_CHAN (NSEGS/2)
#define TIMEOUT 50
#define VIA_BUFFSIZE 0x4000
#define VIA_BUFFSIZE 0x1000
#undef DEB
#define DEB(x)
@ -60,9 +60,11 @@ struct via_info;
struct via_chinfo {
struct via_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
int dir;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
struct via_dma_op *sgd_table;
int dir, blksz;
int base, count, mode, ctrl;
};
struct via_info {
@ -70,39 +72,27 @@ struct via_info {
bus_space_handle_t sh;
bus_dma_tag_t parent_dmat;
bus_dma_tag_t sgd_dmat;
bus_dmamap_t sgd_dmamap;
struct resource *reg, *irq;
int regid, irqid;
void *ih;
struct ac97_info *codec;
struct via_chinfo pch, rch;
struct via_dma_op *sgd_table;
u_int16_t codec_caps;
};
static u_int32_t via_rd(struct via_info *via, int regno, int size);
static void via_wr(struct via_info *, int regno, u_int32_t data, int size);
static void via_intr(void *);
bus_dmamap_callback_t dma_cb;
static u_int32_t via_playfmt[] = {
static u_int32_t via_fmt[] = {
AFMT_U8,
AFMT_STEREO | AFMT_U8,
AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps via_playcaps = {4000, 48000, via_playfmt, 0};
static u_int32_t via_recfmt[] = {
AFMT_U8,
AFMT_STEREO | AFMT_U8,
AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
0
};
static pcmchan_caps via_reccaps = {4000, 48000, via_recfmt, 0};
static struct pcmchan_caps via_vracaps = {4000, 48000, via_fmt, 0};
static struct pcmchan_caps via_caps = {48000, 48000, via_fmt, 0};
static u_int32_t
via_rd(struct via_info *via, int regno, int size)
@ -184,8 +174,7 @@ via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val)
if (via_waitready_codec(via)) return -1;
via_wr(via, VIA_CODEC_CTL,
VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4);
via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4);
return 0;
}
@ -197,16 +186,15 @@ via_read_codec(kobj_t obj, void *addr, int reg)
struct via_info *via = addr;
if (via_waitready_codec(via))
return 1;
return -1;
via_wr(via, VIA_CODEC_CTL,
VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4);
via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4);
if (via_waitready_codec(via))
return 1;
return -1;
if (via_waitvalid_codec(via))
return 1;
return -1;
return via_rd(via, VIA_CODEC_CTL, 2);
}
@ -220,58 +208,60 @@ AC97_DECLARE(via_ac97);
/* -------------------------------------------------------------------- */
/* channel interface */
static void *
viachan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
{
struct via_info *via = devinfo;
struct via_chinfo *ch = (dir == PCMDIR_PLAY) ? &via->pch : &via->rch;
ch->parent = via;
ch->channel = c;
ch->buffer = b;
if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1) return NULL;
return ch;
}
static int
viachan_setdir(kobj_t obj, void *data, int dir)
via_buildsgdt(struct via_chinfo *ch)
{
struct via_chinfo *ch = data;
struct via_info *via = ch->parent;
struct via_dma_op *ado;
int i, chunk_size;
int phys_addr, flag;
u_int32_t phys_addr, flag;
int i, segs, seg_size;
ch->dir = dir;
/*
* Build the scatter/gather DMA (SGD) table.
* There are four slots in the table: two for play, two for record.
* This creates two half-buffers, one of which is playing; the other
* is feeding.
*/
ado = via->sgd_table;
chunk_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
if (dir == PCMDIR_REC) {
ado += SEGS_PER_CHAN;
}
DEB(printf("SGD table located at va %p\n", ado));
seg_size = ch->blksz;
segs = sndbuf_getsize(ch->buffer) / seg_size;
phys_addr = vtophys(sndbuf_getbuf(ch->buffer));
for (i = 0; i < SEGS_PER_CHAN; i++) {
ado->ptr = phys_addr;
flag = (i == SEGS_PER_CHAN-1) ?
VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
ado->flags = flag | chunk_size;
DEB(printf("ado->ptr/flags = %x/%x\n", phys_addr, flag));
phys_addr += chunk_size;
ado++;
for (i = 0; i < segs; i++) {
flag = (i == segs - 1)? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
ch->sgd_table[i].ptr = phys_addr + (i * seg_size);
ch->sgd_table[i].flags = flag | seg_size;
}
return 0;
}
/* channel interface */
static void *
viachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct via_info *via = devinfo;
struct via_chinfo *ch = (dir == PCMDIR_PLAY)? &via->pch : &via->rch;
ch->parent = via;
ch->channel = c;
ch->buffer = b;
ch->dir = dir;
ch->sgd_table = &via->sgd_table[(dir == PCMDIR_PLAY)? 0 : SEGS_PER_CHAN];
if (ch->dir == PCMDIR_PLAY) {
ch->base = VIA_PLAY_DMAOPS_BASE;
ch->count = VIA_PLAY_DMAOPS_COUNT;
ch->ctrl = VIA_RECORD_CONTROL;
ch->mode = VIA_PLAY_MODE;
} else {
ch->base = VIA_RECORD_DMAOPS_BASE;
ch->count = VIA_RECORD_DMAOPS_COUNT;
ch->ctrl = VIA_PLAY_CONTROL;
ch->mode = VIA_RECORD_MODE;
}
if (sndbuf_alloc(ch->buffer, via->parent_dmat, VIA_BUFFSIZE) == -1)
return NULL;
return ch;
}
static int
viachan_setformat(kobj_t obj, void *data, u_int32_t format)
{
@ -285,21 +275,11 @@ viachan_setformat(kobj_t obj, void *data, u_int32_t format)
if (format & AFMT_S16_LE)
mode_set |= VIA_RPMODE_16BIT;
/* Set up for output format */
if (ch->dir == PCMDIR_PLAY) {
DEB(printf("set play format: %x\n", format));
mode = via_rd(via, VIA_PLAY_MODE, 1);
DEB(printf("set format: dir = %d, format=%x\n", ch->dir, format));
mode = via_rd(via, ch->mode, 1);
mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
mode |= mode_set;
via_wr(via, VIA_PLAY_MODE, mode, 1);
}
else {
DEB(printf("set record format: %x\n", format));
mode = via_rd(via, VIA_RECORD_MODE, 1);
mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
mode |= mode_set;
via_wr(via, VIA_RECORD_MODE, mode, 1);
}
via_wr(via, ch->mode, mode, 1);
return 0;
}
@ -309,6 +289,7 @@ viachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct via_chinfo *ch = data;
struct via_info *via = ch->parent;
int reg;
/*
* Basic AC'97 defines a 48 kHz sample rate only. For other rates,
@ -319,31 +300,11 @@ viachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
* itself), then negotiate the rate with the codec. Otherwise,
* return 48 kHz cuz that's all you got.
*/
if (ch->dir == PCMDIR_PLAY) {
DEB(printf("requested play speed: %d\n", speed));
if (via->codec_caps & AC97_CODEC_DOES_VRA) {
via_write_codec(NULL, via, AC97_REG_EXT_DAC_RATE, speed);
speed = via_read_codec(NULL, via, AC97_REG_EXT_DAC_RATE);
}
else {
DEB(printf("VRA not supported!\n"));
speed = 48000;
}
DEB(printf("obtained play speed: %d\n", speed));
}
else {
DEB(printf("requested record speed: %d\n", speed));
if (via->codec_caps & AC97_CODEC_DOES_VRA) {
via_write_codec(NULL, via, AC97_REG_EXT_ADC_RATE, speed);
speed = via_read_codec(NULL, via, AC97_REG_EXT_ADC_RATE);
}
else {
DEB(printf("VRA not supported!\n"));
speed = 48000;
}
DEB(printf("obtained record speed: %d\n", speed));
}
return speed;
if (via->codec_caps & AC97_EXTCAP_VRA) {
reg = (ch->dir == PCMDIR_PLAY)? AC97_REGEXT_FDACRATE : AC97_REGEXT_LADCRATE;
return ac97_setrate(via->codec, reg, speed);
} else
return 48000;
}
static int
@ -351,7 +312,10 @@ viachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct via_chinfo *ch = data;
return sndbuf_getsize(ch->buffer) / 2;
ch->blksz = blocksize;
sndbuf_resize(ch->buffer, SEGS_PER_CHAN, ch->blksz);
return ch->blksz;
}
static int
@ -361,37 +325,20 @@ viachan_trigger(kobj_t obj, void *data, int go)
struct via_info *via = ch->parent;
struct via_dma_op *ado;
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0;
if (ch->dir == PCMDIR_PLAY) {
if (go == PCMTRIG_START) {
ado = &via->sgd_table[0];
DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
via_wr(via, VIA_PLAY_DMAOPS_BASE, vtophys(ado),4);
via_wr(via, VIA_PLAY_CONTROL,
VIA_RPCTRL_START, 1);
}
else {
/* Stop DMA */
via_wr(via, VIA_PLAY_CONTROL,
VIA_RPCTRL_TERMINATE, 1);
}
} else {
if (go == PCMTRIG_START) {
ado = &via->sgd_table[SEGS_PER_CHAN];
DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
via_wr(via, VIA_RECORD_DMAOPS_BASE,
vtophys(ado),4);
via_wr(via, VIA_RECORD_CONTROL,
VIA_RPCTRL_START, 1);
}
else {
/* Stop DMA */
via_wr(via, VIA_RECORD_CONTROL,
VIA_RPCTRL_TERMINATE, 1);
}
}
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
DEB(printf("viachan_trigger: go=%d\n", go));
ado = ch->sgd_table;
DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado)));
if (go == PCMTRIG_START) {
via_buildsgdt(ch);
via_wr(via, ch->base, vtophys(ado), 4);
via_wr(via, ch->ctrl, VIA_RPCTRL_START, 1);
} else
via_wr(via, ch->ctrl, VIA_RPCTRL_TERMINATE, 1);
DEB(printf("viachan_trigger: go=%d\n", go));
return 0;
}
@ -401,68 +348,47 @@ viachan_getptr(kobj_t obj, void *data)
struct via_chinfo *ch = data;
struct via_info *via = ch->parent;
struct via_dma_op *ado;
int ptr, base, len, seg;
int base1;
int ptr, base, base1, len, seg;
ado = ch->sgd_table;
base1 = via_rd(via, ch->base, 4);
len = via_rd(via, ch->count, 4);
base = via_rd(via, ch->base, 4);
if (base != base1) /* Avoid race hazard */
len = via_rd(via, ch->count, 4);
if (ch->dir == PCMDIR_PLAY) {
ado = &via->sgd_table[0];
base1 = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
base = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4);
if (base != base1) { /* Avoid race hazzard */
len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4);
}
DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
/* Base points to SGD segment to do, one past current */
/* Base points to SGD segment to do, one past current */
/* Determine how many segments have been done */
seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
if (seg == 0) seg = SEGS_PER_CHAN;
if (seg == 0)
seg = SEGS_PER_CHAN;
/* Now work out offset: seg less count */
ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
DEB(printf("return ptr=%d\n", ptr));
return ptr;
}
else {
base1 = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
ado = &via->sgd_table[SEGS_PER_CHAN];
len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
base = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4);
if (base != base1) { /* Avoid race hazzard */
len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4);
}
DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
/* Base points to next block to do, one past current */
/* Determine how many segments have been done */
seg = (base - vtophys(ado)) / sizeof(struct via_dma_op);
if (seg == 0) seg = SEGS_PER_CHAN;
/* Now work out offset: seg less count */
ptr = seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN - len;
ptr = (seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN) - len;
if (ch->dir == PCMDIR_REC) {
/* DMA appears to operate on memory 'lines' of 32 bytes */
/* so don't return any part line - it isn't in RAM yet */
ptr = ptr & ~0x1f;
}
DEB(printf("return ptr=%d\n", ptr));
return ptr;
}
return 0;
}
static pcmchan_caps *
static struct pcmchan_caps *
viachan_getcaps(kobj_t obj, void *data)
{
struct via_chinfo *ch = data;
return (ch->dir == PCMDIR_PLAY) ? &via_playcaps : &via_reccaps;
struct via_info *via = ch->parent;
return (via->codec_caps & AC97_EXTCAP_VRA)? &via_vracaps : &via_caps;
}
static kobj_method_t viachan_methods[] = {
KOBJMETHOD(channel_init, viachan_init),
KOBJMETHOD(channel_setdir, viachan_setdir),
KOBJMETHOD(channel_setformat, viachan_setformat),
KOBJMETHOD(channel_setspeed, viachan_setspeed),
KOBJMETHOD(channel_setblocksize, viachan_setblocksize),
@ -511,7 +437,8 @@ via_probe(device_t dev)
}
void dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
static void
dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
{
}
@ -520,14 +447,9 @@ static int
via_attach(device_t dev)
{
struct via_info *via = 0;
struct ac97_info *codec = 0;
char status[SND_STATUSLEN];
u_int32_t data;
u_int16_t v;
bus_dmamap_t sgd_dma_map;
if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT)) == NULL) {
device_printf(dev, "cannot allocate softc\n");
return ENXIO;
@ -541,12 +463,10 @@ via_attach(device_t dev)
data = pci_read_config(dev, PCIR_COMMAND, 2);
pci_write_config(dev, VIA_PCICONF_MISC,
VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD |
VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1);
VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD | VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1);
via->regid = PCIR_MAPS;
via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid,
0, ~0, 1, RF_ACTIVE);
via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid, 0, ~0, 1, RF_ACTIVE);
if (!via->reg) {
device_printf(dev, "cannot allocate bus resource.");
goto bad;
@ -555,44 +475,24 @@ via_attach(device_t dev)
via->sh = rman_get_bushandle(via->reg);
via->irqid = 0;
via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!via->irq
|| bus_setup_intr(dev, via->irq, INTR_TYPE_TTY, via_intr, via, &via->ih)){
via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (!via->irq || snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
via_wr(via, VIA_PLAY_MODE,
VIA_RPMODE_AUTOSTART |
VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
via_wr(via, VIA_RECORD_MODE,
VIA_RPMODE_AUTOSTART |
VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
via_wr(via, VIA_PLAY_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
via_wr(via, VIA_RECORD_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
codec = AC97_CREATE(dev, via, via_ac97);
if (!codec) goto bad;
via->codec = AC97_CREATE(dev, via, via_ac97);
if (!via->codec)
goto bad;
mixer_init(dev, ac97_getmixerclass(), codec);
mixer_init(dev, ac97_getmixerclass(), via->codec);
/*
* The mixer init resets the codec. So enabling VRA must be done
* afterwards.
*/
v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_ID);
v &= (AC97_ENAB_VRA | AC97_ENAB_MICVRA);
via_write_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT, v);
via->codec_caps = v;
{
v = via_read_codec(NULL, via, AC97_REG_EXT_AUDIO_STAT);
DEB(printf("init: codec stat: %d\n", v));
}
if (!(v & AC97_CODEC_DOES_VRA)) {
/* no VRA => can do only 48 kbps */
via_playcaps.minspeed = 48000;
via_reccaps.minspeed = 48000;
}
via->codec_caps = ac97_getextcaps(via->codec);
if (via->codec_caps & AC97_EXTCAP_VRA)
ac97_setextmode(via->codec, AC97_EXTCAP_VRA | AC97_EXTCAP_VRM);
/* DMA tag for buffers */
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
@ -621,13 +521,12 @@ via_attach(device_t dev)
goto bad;
}
if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
BUS_DMA_NOWAIT, &sgd_dma_map) == -1) goto bad;
if (bus_dmamap_load(via->sgd_dmat, sgd_dma_map, via->sgd_table,
NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) goto bad;
if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
goto bad;
if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0))
goto bad;
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld",
rman_get_start(via->reg), rman_get_start(via->irq));
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", rman_get_start(via->reg), rman_get_start(via->irq));
/* Register */
if (pcm_register(dev, via, 1, 1)) goto bad;
@ -636,11 +535,12 @@ via_attach(device_t dev)
pcm_setstatus(dev, status);
return 0;
bad:
if (codec) ac97_destroy(codec);
if (via->codec) ac97_destroy(via->codec);
if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
if (via) free(via, M_DEVBUF);
return ENXIO;
@ -661,6 +561,7 @@ via_detach(device_t dev)
bus_teardown_intr(dev, via->irq, via->ih);
bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
bus_dma_tag_destroy(via->parent_dmat);
bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
bus_dma_tag_destroy(via->sgd_dmat);
free(via, M_DEVBUF);
return 0;
@ -677,7 +578,7 @@ static device_method_t via_methods[] = {
static driver_t via_driver = {
"pcm",
via_methods,
sizeof(snddev_info),
sizeof(struct snddev_info),
};
static devclass_t pcm_devclass;

View File

@ -56,8 +56,8 @@ struct sc_info;
struct sc_chinfo {
struct sc_info *parent;
pcm_channel *channel;
snd_dbuf *buffer;
struct pcm_channel *channel;
struct snd_dbuf *buffer;
u_int32_t fmt, spd;
int dir;
int dma_active, dma_was_active;
@ -100,7 +100,7 @@ static u_int32_t sc_fmt[] = {
0
};
static pcmchan_caps sc_caps = {8000, 48000, sc_fmt, 0};
static struct pcmchan_caps sc_caps = {8000, 48000, sc_fmt, 0};
/* ------------------------------------------------------------------------- */
/* Register Manipulations */
@ -178,7 +178,7 @@ sv_dma_get_count(bus_space_tag_t st, bus_space_handle_t sh)
/* Play / Record Common Interface */
static void *
svchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
svchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct sc_info *sc = devinfo;
struct sc_chinfo *ch;
@ -200,7 +200,7 @@ svchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
return ch;
}
static pcmchan_caps *
static struct pcmchan_caps *
svchan_getcaps(kobj_t obj, void *data)
{
return &sc_caps;
@ -505,7 +505,7 @@ sv_mix_mute_all(struct sc_info *sc)
}
static int
sv_mix_init(snd_mixer *m)
sv_mix_init(struct snd_mixer *m)
{
u_int32_t i, v;
@ -523,14 +523,14 @@ sv_mix_init(snd_mixer *m)
}
static int
sv_mix_set(snd_mixer *m, u_int32_t dev, u_int32_t left, u_int32_t right)
sv_mix_set(struct snd_mixer *m, u_int32_t dev, u_int32_t left, u_int32_t right)
{
struct sc_info *sc = mix_getdevinfo(m);
return sv_gain(sc, dev, left, right);
}
static int
sv_mix_setrecsrc(snd_mixer *m, u_int32_t mask)
sv_mix_setrecsrc(struct snd_mixer *m, u_int32_t mask)
{
struct sc_info *sc = mix_getdevinfo(m);
u_int32_t i, v;
@ -706,7 +706,7 @@ sv_probe(device_t dev)
static int
sv_attach(device_t dev) {
snddev_info *d;
struct snddev_info *d;
struct sc_info *sc;
u_int32_t data;
char status[SND_STATUSLEN];
@ -920,7 +920,7 @@ static device_method_t sc_methods[] = {
static driver_t sonicvibes_driver = {
"pcm",
sc_methods,
sizeof(snddev_info)
sizeof(struct snddev_info)
};
static devclass_t pcm_devclass;

View File

@ -33,6 +33,19 @@
MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
#define AC97_NAMELEN 16
struct ac97_info {
kobj_t methods;
device_t dev;
void *devinfo;
char *id;
char rev;
unsigned count, caps, se, extcaps, extid, extstat, noext:1;
struct ac97mixtable_entry mix[32];
char name[AC97_NAMELEN];
void *lock;
};
struct ac97_codecid {
u_int32_t id, noext:1;
char *name;
@ -192,6 +205,7 @@ ac97_setrate(struct ac97_info *codec, int which, int rate)
return -1;
}
snd_mtxlock(codec->lock);
if (rate != 0) {
v = rate;
if (codec->extstat & AC97_EXTCAP_DRA)
@ -201,6 +215,7 @@ ac97_setrate(struct ac97_info *codec, int which, int rate)
v = rdcd(codec, which);
if (codec->extstat & AC97_EXTCAP_DRA)
v <<= 1;
snd_mtxunlock(codec->lock);
return v;
}
@ -210,8 +225,10 @@ ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
mode &= AC97_EXTCAPS;
if ((mode & ~codec->extcaps) != 0)
return -1;
snd_mtxlock(codec->lock);
wrcd(codec, AC97_REGEXT_STAT, mode);
codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
snd_mtxunlock(codec->lock);
return (mode == codec->extstat)? 0 : -1;
}
@ -235,7 +252,9 @@ ac97_setrecsrc(struct ac97_info *codec, int channel)
if (e->recidx > 0) {
int val = e->recidx - 1;
val |= val << 8;
snd_mtxlock(codec->lock);
wrcd(codec, AC97_REG_RECSEL, val);
snd_mtxunlock(codec->lock);
return 0;
} else
return -1;
@ -280,7 +299,9 @@ ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned
}
if (left == 0 && right == 0 && e->mute == 1)
val = AC97_MUTE;
snd_mtxlock(codec->lock);
wrcd(codec, reg, val);
snd_mtxunlock(codec->lock);
return left | (right << 8);
} else {
/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
@ -318,12 +339,14 @@ ac97_initmixer(struct ac97_info *codec)
unsigned i, j, k, old;
u_int32_t id;
snd_mtxlock(codec->lock);
for (i = 0; i < 32; i++)
codec->mix[i] = ac97mixtable_default[i];
codec->count = AC97_INIT(codec->methods, codec->devinfo);
if (codec->count == 0) {
device_printf(codec->dev, "ac97 codec init failed\n");
snd_mtxunlock(codec->lock);
return ENODEV;
}
@ -340,14 +363,15 @@ ac97_initmixer(struct ac97_info *codec)
codec->rev = id & 0x000000ff;
if (id == 0 || id == 0xffffffff) {
device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
snd_mtxunlock(codec->lock);
return ENODEV;
}
codec->noext = 0;
codec->name = NULL;
codec->id = NULL;
for (i = 0; ac97codecid[i].id; i++) {
if (ac97codecid[i].id == id) {
codec->name = ac97codecid[i].name;
codec->id = ac97codecid[i].name;
codec->noext = ac97codecid[i].noext;
}
}
@ -380,8 +404,8 @@ ac97_initmixer(struct ac97_info *codec)
if (bootverbose) {
device_printf(codec->dev, "ac97 codec id 0x%08x", id);
if (codec->name)
printf(" (%s)", codec->name);
if (codec->id)
printf(" (%s)", codec->id);
printf("\n");
device_printf(codec->dev, "ac97 codec features ");
for (i = j = 0; i < 10; i++)
@ -404,6 +428,7 @@ ac97_initmixer(struct ac97_info *codec)
if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
device_printf(codec->dev, "ac97 codec reports dac not ready\n");
snd_mtxunlock(codec->lock);
return 0;
}
@ -412,9 +437,11 @@ ac97_reinitmixer(struct ac97_info *codec)
{
unsigned i;
snd_mtxlock(codec->lock);
codec->count = AC97_INIT(codec->methods, codec->devinfo);
if (codec->count == 0) {
device_printf(codec->dev, "ac97 codec init failed\n");
snd_mtxunlock(codec->lock);
return ENODEV;
}
@ -432,6 +459,7 @@ ac97_reinitmixer(struct ac97_info *codec)
if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
device_printf(codec->dev, "ac97 codec reports dac not ready\n");
snd_mtxunlock(codec->lock);
return 0;
}
@ -444,8 +472,12 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
if (codec == NULL)
return NULL;
snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
codec->lock = snd_mtxcreate(codec->name);
codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
if (codec->methods == NULL) {
snd_mtxlock(codec->lock);
snd_mtxfree(codec->lock);
free(codec, M_AC97);
return NULL;
}
@ -458,15 +490,17 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
void
ac97_destroy(struct ac97_info *codec)
{
snd_mtxlock(codec->lock);
if (codec->methods != NULL)
kobj_delete(codec->methods, M_AC97);
snd_mtxfree(codec->lock);
free(codec, M_AC97);
}
/* -------------------------------------------------------------------- */
static int
ac97mix_init(snd_mixer *m)
ac97mix_init(struct snd_mixer *m)
{
struct ac97_info *codec = mix_getdevinfo(m);
u_int32_t i, mask;
@ -490,7 +524,7 @@ ac97mix_init(snd_mixer *m)
}
static int
ac97mix_uninit(snd_mixer *m)
ac97mix_uninit(struct snd_mixer *m)
{
struct ac97_info *codec = mix_getdevinfo(m);
@ -505,7 +539,7 @@ ac97mix_uninit(snd_mixer *m)
}
static int
ac97mix_reinit(snd_mixer *m)
ac97mix_reinit(struct snd_mixer *m)
{
struct ac97_info *codec = mix_getdevinfo(m);
@ -515,7 +549,7 @@ ac97mix_reinit(snd_mixer *m)
}
static int
ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct ac97_info *codec = mix_getdevinfo(m);
@ -525,7 +559,7 @@ ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
}
static int
ac97mix_setrecsrc(snd_mixer *m, u_int32_t src)
ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
int i;
struct ac97_info *codec = mix_getdevinfo(m);

View File

@ -77,15 +77,7 @@ struct ac97mixtable_entry {
#define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
#define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class)
struct ac97_info {
kobj_t methods;
device_t dev;
void *devinfo;
char *name;
char rev;
unsigned count, caps, se, extcaps, extid, extstat, noext:1;
struct ac97mixtable_entry mix[32];
};
struct ac97_info;
#include "ac97_if.h"

View File

@ -28,10 +28,50 @@
#include <dev/sound/pcm/sound.h>
#include "feeder_if.h"
#define MIN(x, y) (((x) < (y))? (x) : (y))
#define SNDBUF_NAMELEN 48
struct snd_dbuf {
u_int8_t *buf, *tmpbuf;
unsigned int bufsize, maxsize;
volatile int dl; /* transfer size */
volatile int rp; /* pointers to the ready area */
volatile int rl; /* length of ready area */
volatile int hp;
volatile u_int32_t total, prev_total;
int isadmachan, dir; /* dma channel */
u_int32_t fmt, spd, bps;
unsigned int blksz, blkcnt;
int xrun;
u_int32_t flags;
bus_dmamap_t dmamap;
bus_dma_tag_t dmatag;
struct selinfo sel;
char name[SNDBUF_NAMELEN];
};
struct snd_dbuf *
sndbuf_create(char *drv, char *desc)
{
struct snd_dbuf *b;
b = malloc(sizeof(*b), M_DEVBUF, M_WAITOK | M_ZERO);
snprintf(b->name, SNDBUF_NAMELEN, "%s:%s", drv, desc);
return b;
}
void
sndbuf_destroy(struct snd_dbuf *b)
{
free(b, M_DEVBUF);
}
static void
sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
snd_dbuf *b = (snd_dbuf *)arg;
struct snd_dbuf *b = (struct snd_dbuf *)arg;
if (bootverbose) {
printf("pcm: setmap %lx, %lx; ", (unsigned long)segs->ds_addr,
@ -41,11 +81,11 @@ sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
}
/*
* Allocate memory for DMA buffer. If the device do not perform DMA transfer,
* the driver can call malloc(9) by its own.
* Allocate memory for DMA buffer. If the device does not use DMA transfers,
* the driver can call malloc(9) and sndbuf_setup() itself.
*/
int
sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size)
sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size)
{
b->dmatag = dmatag;
b->maxsize = size;
@ -58,7 +98,7 @@ sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size)
}
int
sndbuf_setup(snd_dbuf *b, void *buf, int size)
sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size)
{
bzero(b, sizeof(*b));
b->buf = buf;
@ -68,15 +108,24 @@ sndbuf_setup(snd_dbuf *b, void *buf, int size)
}
void
sndbuf_free(snd_dbuf *b)
sndbuf_free(struct snd_dbuf *b)
{
if (b->tmpbuf)
free(b->tmpbuf, M_DEVBUF);
b->tmpbuf = NULL;
if (b->dmamap)
bus_dmamap_unload(b->dmatag, b->dmamap);
if (b->dmamap && b->buf)
bus_dmamem_free(b->dmatag, b->buf, b->dmamap);
}
int
sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz)
sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
{
if (b->maxsize == 0)
return 0;
if (blkcnt == 0)
blkcnt = b->blkcnt;
if (blksz == 0)
@ -86,12 +135,43 @@ sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz)
b->blkcnt = blkcnt;
b->blksz = blksz;
b->bufsize = blkcnt * blksz;
if (b->tmpbuf)
free(b->tmpbuf, M_DEVBUF);
b->tmpbuf = malloc(b->bufsize, M_DEVBUF, M_WAITOK);
sndbuf_reset(b);
return 0;
}
int
sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz)
{
if (blkcnt < 2 || blksz < 16)
return EINVAL;
b->blkcnt = blkcnt;
b->blksz = blksz;
b->maxsize = blkcnt * blksz;
b->bufsize = b->maxsize;
if (b->buf)
free(b->buf, M_DEVBUF);
b->buf = malloc(b->bufsize, M_DEVBUF, M_WAITOK);
if (b->buf == NULL)
return ENOMEM;
if (b->tmpbuf)
free(b->tmpbuf, M_DEVBUF);
b->tmpbuf = malloc(b->bufsize, M_DEVBUF, M_WAITOK);
if (b->tmpbuf == NULL)
return ENOMEM;
sndbuf_reset(b);
return 0;
}
void
sndbuf_clear(snd_dbuf *b, int length)
sndbuf_clear(struct snd_dbuf *b, unsigned int length)
{
int i;
u_char data, *p;
@ -106,8 +186,13 @@ sndbuf_clear(snd_dbuf *b, int length)
else
data = 0x80;
i = b->fp;
p = b->buf;
if (b->fmt & AFMT_16BIT)
data <<= 8;
else
data |= data << 8;
i = sndbuf_getfreeptr(b);
p = sndbuf_getbuf(b);
while (length > 0) {
p[i] = data;
length--;
@ -118,20 +203,27 @@ sndbuf_clear(snd_dbuf *b, int length)
}
void
sndbuf_reset(snd_dbuf *b)
sndbuf_reset(struct snd_dbuf *b)
{
b->rp = b->fp = 0;
b->dl = b->rl = 0;
b->fl = b->bufsize;
b->prev_total = b->total = 0;
b->prev_int_count = b->int_count = 0;
b->underflow = 0;
b->hp = 0;
b->rp = 0;
b->rl = 0;
b->dl = 0;
b->prev_total = 0;
b->total = 0;
b->xrun = 0;
if (b->buf && b->bufsize > 0)
sndbuf_clear(b, b->bufsize);
}
u_int32_t
sndbuf_getfmt(struct snd_dbuf *b)
{
return b->fmt;
}
int
sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt)
sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
{
b->fmt = fmt;
b->bps = 1;
@ -141,67 +233,368 @@ sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt)
return 0;
}
int
sndbuf_getbps(snd_dbuf *b)
unsigned int
sndbuf_getspd(struct snd_dbuf *b)
{
return b->spd;
}
void
sndbuf_setspd(struct snd_dbuf *b, unsigned int spd)
{
b->spd = spd;
}
unsigned int
sndbuf_getalign(struct snd_dbuf *b)
{
static int align[] = {0, 1, 1, 2, 2, 2, 2, 3};
return align[b->bps - 1];
}
unsigned int
sndbuf_getblkcnt(struct snd_dbuf *b)
{
return b->blkcnt;
}
void
sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt)
{
b->blkcnt = blkcnt;
}
unsigned int
sndbuf_getblksz(struct snd_dbuf *b)
{
return b->blksz;
}
void
sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz)
{
b->blksz = blksz;
}
unsigned int
sndbuf_getbps(struct snd_dbuf *b)
{
return b->bps;
}
void *
sndbuf_getbuf(snd_dbuf *b)
sndbuf_getbuf(struct snd_dbuf *b)
{
return b->buf;
}
int
sndbuf_getsize(snd_dbuf *b)
void *
sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs)
{
KASSERT((ofs >= 0) && (ofs <= b->bufsize), ("%s: ofs invalid %d", __FUNCTION__, ofs));
return b->buf + ofs;
}
unsigned int
sndbuf_getsize(struct snd_dbuf *b)
{
return b->bufsize;
}
int
sndbuf_runsz(snd_dbuf *b)
unsigned int
sndbuf_getmaxsize(struct snd_dbuf *b)
{
return b->maxsize;
}
unsigned int
sndbuf_runsz(struct snd_dbuf *b)
{
return b->dl;
}
void
sndbuf_setrun(struct snd_dbuf *b, int go)
{
b->dl = go? b->blksz : 0;
}
struct selinfo *
sndbuf_getsel(struct snd_dbuf *b)
{
return &b->sel;
}
/************************************************************/
unsigned int
sndbuf_getxrun(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
return b->xrun;
}
void
sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt)
{
SNDBUF_LOCKASSERT(b);
b->xrun = cnt;
}
unsigned int
sndbuf_gethwptr(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
return b->hp;
}
void
sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr)
{
SNDBUF_LOCKASSERT(b);
b->hp = ptr;
}
unsigned int
sndbuf_getready(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl));
return b->rl;
}
unsigned int
sndbuf_getreadyptr(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __FUNCTION__, b->rp));
return b->rp;
}
unsigned int
sndbuf_getfree(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl));
return b->bufsize - b->rl;
}
unsigned int
sndbuf_getfreeptr(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
KASSERT((b->rp >= 0) && (b->rp <= b->bufsize), ("%s: b->rp invalid %d", __FUNCTION__, b->rp));
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl));
return (b->rp + b->rl) % b->bufsize;
}
unsigned int
sndbuf_getblocks(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
return b->total / b->blksz;
}
unsigned int
sndbuf_getprevblocks(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
return b->prev_total / b->blksz;
}
unsigned int
sndbuf_gettotal(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
return b->total;
}
void
sndbuf_updateprevtotal(struct snd_dbuf *b)
{
SNDBUF_LOCKASSERT(b);
b->prev_total = b->total;
}
/************************************************************/
int
sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq)
sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count)
{
int l;
KASSERT(count <= sndbuf_getfree(b), ("%s: count %d > free %d", __FUNCTION__, count, sndbuf_getfree(b)));
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl));
b->total += count;
if (from != NULL) {
while (count > 0) {
l = MIN(count, sndbuf_getsize(b) - sndbuf_getfreeptr(b));
bcopy(from, sndbuf_getbufofs(b, sndbuf_getfreeptr(b)), l);
from += l;
b->rl += l;
count -= l;
}
} else
b->rl += count;
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __FUNCTION__, b->rl, count));
return 0;
}
int
sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
{
int l;
KASSERT(count <= sndbuf_getready(b), ("%s: count %d > ready %d", __FUNCTION__, count, sndbuf_getready(b)));
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d", __FUNCTION__, b->rl));
if (to != NULL) {
while (count > 0) {
l = MIN(count, sndbuf_getsize(b) - sndbuf_getreadyptr(b));
bcopy(sndbuf_getbufofs(b, sndbuf_getreadyptr(b)), to, l);
to += l;
b->rl -= l;
b->rp = (b->rp + l) % b->bufsize;
count -= l;
}
} else {
b->rl -= count;
b->rp = (b->rp + count) % b->bufsize;
}
KASSERT((b->rl >= 0) && (b->rl <= b->bufsize), ("%s: b->rl invalid %d, count %d", __FUNCTION__, b->rl, count));
return 0;
}
int
sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count)
{
int x, c, p, rd, err;
err = 0;
rd = (uio->uio_rw == UIO_READ)? 1 : 0;
if (count > uio->uio_resid)
return EINVAL;
if (count > (rd? sndbuf_getready(b) : sndbuf_getfree(b))) {
return EINVAL;
}
while (err == 0 && count > 0) {
p = rd? sndbuf_getreadyptr(b) : sndbuf_getfreeptr(b);
c = MIN(count, sndbuf_getsize(b) - p);
x = uio->uio_resid;
err = uiomove(sndbuf_getbufofs(b, p), c, uio);
x -= uio->uio_resid;
count -= x;
x = rd? sndbuf_dispose(b, NULL, x) : sndbuf_acquire(b, NULL, x);
}
return 0;
}
/* count is number of bytes we want added to destination buffer */
int
sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)
{
if (sndbuf_getfree(to) < count)
return EINVAL;
count = FEEDER_FEED(feeder, channel, to->tmpbuf, count, from);
sndbuf_acquire(to, to->tmpbuf, count);
/* the root feeder has called sndbuf_dispose(from, , bytes fetched) */
return 0;
}
/************************************************************/
void
sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what)
{
printf("%s: [", s);
if (what & 0x01)
printf(" bufsize: %d, maxsize: %d", b->bufsize, b->maxsize);
if (what & 0x02)
printf(" dl: %d, rp: %d, rl: %d, hp: %d", b->dl, b->rp, b->rl, b->hp);
if (what & 0x04)
printf(" total: %d, prev_total: %d, xrun: %d", b->total, b->prev_total, b->xrun);
if (what & 0x08)
printf(" fmt: 0x%x, spd: %d", b->fmt, b->spd);
if (what & 0x10)
printf(" blksz: %d, blkcnt: %d, flags: 0x%x", b->blksz, b->blkcnt, b->flags);
printf(" ]\n");
}
/************************************************************/
u_int32_t
sndbuf_getflags(struct snd_dbuf *b)
{
return b->flags;
}
void
sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on)
{
b->flags &= ~flags;
if (on)
b->flags |= flags;
}
/************************************************************/
int
sndbuf_isadmasetup(struct snd_dbuf *b, struct resource *drq)
{
/* should do isa_dma_acquire/isa_dma_release here */
if (drq == NULL) {
b->flags &= ~SNDBUF_F_ISADMA;
b->chan = -1;
b->isadmachan = -1;
} else {
b->flags &= ~SNDBUF_F_ISADMA;
b->chan = rman_get_start(drq);
sndbuf_setflags(b, SNDBUF_F_ISADMA, 1);
b->isadmachan = rman_get_start(drq);
}
return 0;
}
int
sndbuf_isadmasetdir(snd_dbuf *b, int dir)
sndbuf_isadmasetdir(struct snd_dbuf *b, int dir)
{
KASSERT(b, ("sndbuf_isadmasetdir called with b == NULL"));
KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmasetdir called on non-ISA buffer"));
b->dir = (dir == PCMDIR_PLAY)? ISADMA_WRITE : ISADMA_READ;
return 0;
}
void
sndbuf_isadma(snd_dbuf *b, int go)
sndbuf_isadma(struct snd_dbuf *b, int go)
{
KASSERT(b, ("sndbuf_isadma called with b == NULL"));
KASSERT(ISA_DMA(b), ("sndbuf_isadma called on non-ISA channel"));
KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadma called on non-ISA buffer"));
switch (go) {
case PCMTRIG_START:
/* isa_dmainit(b->chan, size); */
isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan);
isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan);
break;
case PCMTRIG_STOP:
case PCMTRIG_ABORT:
isa_dmastop(b->chan);
isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->chan);
isa_dmastop(b->isadmachan);
isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->isadmachan);
break;
}
@ -212,23 +605,26 @@ sndbuf_isadma(snd_dbuf *b, int go)
}
int
sndbuf_isadmaptr(snd_dbuf *b)
sndbuf_isadmaptr(struct snd_dbuf *b)
{
if (ISA_DMA(b)) {
int i = b->dl? isa_dmastatus(b->chan) : b->bufsize;
if (i < 0)
i = 0;
int i;
KASSERT(b, ("sndbuf_isadmaptr called with b == NULL"));
KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmaptr called on non-ISA buffer"));
if (!sndbuf_runsz(b))
return 0;
i = isa_dmastatus(b->isadmachan);
KASSERT(i >= 0, ("isa_dmastatus returned %d", i));
return b->bufsize - i;
} else KASSERT(1, ("sndbuf_isadmaptr called on invalid channel"));
return -1;
}
void
sndbuf_isadmabounce(snd_dbuf *b)
sndbuf_isadmabounce(struct snd_dbuf *b)
{
if (ISA_DMA(b)) {
KASSERT(b, ("sndbuf_isadmabounce called with b == NULL"));
KASSERT(sndbuf_getflags(b) & SNDBUF_F_ISADMA, ("sndbuf_isadmabounce called on non-ISA buffer"));
/* tell isa_dma to bounce data in/out */
} else
KASSERT(1, ("chn_isadmabounce called on invalid channel"));
}

View File

@ -26,24 +26,70 @@
* $FreeBSD$
*/
#define ISA_DMA(b) (((b)->chan >= 0 && (b)->chan != 4 && (b)->chan < 8))
#define ISA_DMA(b) (sndbuf_getflags((b)) & SNDBUF_F_ISADMA)
#define SNDBUF_LOCKASSERT(b)
int sndbuf_alloc(snd_dbuf *b, bus_dma_tag_t dmatag, int size);
int sndbuf_setup(snd_dbuf *b, void *buf, int size);
void sndbuf_free(snd_dbuf *b);
int sndbuf_resize(snd_dbuf *b, int blkcnt, int blksz);
void sndbuf_reset(snd_dbuf *b);
void sndbuf_clear(snd_dbuf *b, int length);
int sndbuf_setfmt(snd_dbuf *b, u_int32_t fmt);
int sndbuf_getbps(snd_dbuf *b);
void *sndbuf_getbuf(snd_dbuf *b);
int sndbuf_getsize(snd_dbuf *b);
int sndbuf_runsz(snd_dbuf *b);
#define SNDBUF_F_ISADMA 0x00000001
#define SNDBUF_F_XRUN 0x00000002
#define SNDBUF_F_RUNNING 0x00000004
int sndbuf_isadmasetup(snd_dbuf *b, struct resource *drq);
int sndbuf_isadmasetdir(snd_dbuf *b, int dir);
void sndbuf_isadma(snd_dbuf *b, int go);
int sndbuf_isadmaptr(snd_dbuf *b);
void sndbuf_isadmabounce(snd_dbuf *b);
struct snd_dbuf *sndbuf_create(char *drv, char *desc);
void sndbuf_destroy(struct snd_dbuf *b);
void sndbuf_dump(struct snd_dbuf *b, char *s, u_int32_t what);
int sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, unsigned int size);
int sndbuf_setup(struct snd_dbuf *b, void *buf, unsigned int size);
void sndbuf_free(struct snd_dbuf *b);
int sndbuf_resize(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz);
int sndbuf_remalloc(struct snd_dbuf *b, unsigned int blkcnt, unsigned int blksz);
void sndbuf_reset(struct snd_dbuf *b);
void sndbuf_clear(struct snd_dbuf *b, unsigned int length);
u_int32_t sndbuf_getfmt(struct snd_dbuf *b);
int sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt);
unsigned int sndbuf_getspd(struct snd_dbuf *b);
void sndbuf_setspd(struct snd_dbuf *b, unsigned int spd);
unsigned int sndbuf_getbps(struct snd_dbuf *b);
void *sndbuf_getbuf(struct snd_dbuf *b);
void *sndbuf_getbufofs(struct snd_dbuf *b, unsigned int ofs);
unsigned int sndbuf_getsize(struct snd_dbuf *b);
unsigned int sndbuf_getmaxsize(struct snd_dbuf *b);
unsigned int sndbuf_getalign(struct snd_dbuf *b);
unsigned int sndbuf_getblkcnt(struct snd_dbuf *b);
void sndbuf_setblkcnt(struct snd_dbuf *b, unsigned int blkcnt);
unsigned int sndbuf_getblksz(struct snd_dbuf *b);
void sndbuf_setblksz(struct snd_dbuf *b, unsigned int blksz);
unsigned int sndbuf_runsz(struct snd_dbuf *b);
void sndbuf_setrun(struct snd_dbuf *b, int go);
struct selinfo *sndbuf_getsel(struct snd_dbuf *b);
unsigned int sndbuf_getxrun(struct snd_dbuf *b);
void sndbuf_setxrun(struct snd_dbuf *b, unsigned int cnt);
unsigned int sndbuf_gethwptr(struct snd_dbuf *b);
void sndbuf_sethwptr(struct snd_dbuf *b, unsigned int ptr);
unsigned int sndbuf_getfree(struct snd_dbuf *b);
unsigned int sndbuf_getfreeptr(struct snd_dbuf *b);
unsigned int sndbuf_getready(struct snd_dbuf *b);
unsigned int sndbuf_getreadyptr(struct snd_dbuf *b);
unsigned int sndbuf_getblocks(struct snd_dbuf *b);
unsigned int sndbuf_getprevblocks(struct snd_dbuf *b);
unsigned int sndbuf_gettotal(struct snd_dbuf *b);
void sndbuf_updateprevtotal(struct snd_dbuf *b);
int sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count);
int sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count);
int sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count);
int sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count);
u_int32_t sndbuf_getflags(struct snd_dbuf *b);
void sndbuf_setflags(struct snd_dbuf *b, u_int32_t flags, int on);
int sndbuf_isadmasetup(struct snd_dbuf *b, struct resource *drq);
int sndbuf_isadmasetdir(struct snd_dbuf *b, int dir);
void sndbuf_isadma(struct snd_dbuf *b, int go);
int sndbuf_isadmaptr(struct snd_dbuf *b);
void sndbuf_isadmabounce(struct snd_dbuf *b);

File diff suppressed because it is too large Load Diff

View File

@ -26,35 +26,69 @@
* $FreeBSD$
*/
struct pcmchan_caps {
u_int32_t minspeed, maxspeed;
u_int32_t *fmtlist;
u_int32_t caps;
};
#define CHN_NAMELEN 32
struct pcm_channel {
kobj_t methods;
struct pcm_feeder *feeder;
u_int32_t align;
int volume;
u_int32_t speed;
u_int32_t format;
u_int32_t flags;
u_int32_t feederflags;
u_int32_t blocks;
int direction;
struct snd_dbuf *bufhard, *bufsoft;
struct snddev_info *parent;
void *devinfo;
char name[CHN_NAMELEN];
void *lock;
};
#include "channel_if.h"
int chn_reinit(pcm_channel *c);
int chn_write(pcm_channel *c, struct uio *buf);
int chn_read(pcm_channel *c, struct uio *buf);
u_int32_t chn_start(pcm_channel *c, int force);
int chn_sync(pcm_channel *c, int threshold);
int chn_flush(pcm_channel *c);
int chn_poll(pcm_channel *c, int ev, struct proc *p);
int chn_reinit(struct pcm_channel *c);
int chn_write(struct pcm_channel *c, struct uio *buf);
int chn_read(struct pcm_channel *c, struct uio *buf);
u_int32_t chn_start(struct pcm_channel *c, int force);
int chn_sync(struct pcm_channel *c, int threshold);
int chn_flush(struct pcm_channel *c);
int chn_poll(struct pcm_channel *c, int ev, struct proc *p);
int chn_init(pcm_channel *c, void *devinfo, int dir);
int chn_kill(pcm_channel *c);
int chn_setdir(pcm_channel *c, int dir);
int chn_reset(pcm_channel *c, u_int32_t fmt);
int chn_setvolume(pcm_channel *c, int left, int right);
int chn_setspeed(pcm_channel *c, int speed);
int chn_setformat(pcm_channel *c, u_int32_t fmt);
int chn_setblocksize(pcm_channel *c, int blkcnt, int blksz);
int chn_trigger(pcm_channel *c, int go);
int chn_getptr(pcm_channel *c);
pcmchan_caps *chn_getcaps(pcm_channel *c);
u_int32_t chn_getformats(pcm_channel *c);
int chn_init(struct pcm_channel *c, void *devinfo, int dir);
int chn_kill(struct pcm_channel *c);
int chn_setdir(struct pcm_channel *c, int dir);
int chn_reset(struct pcm_channel *c, u_int32_t fmt);
int chn_setvolume(struct pcm_channel *c, int left, int right);
int chn_setspeed(struct pcm_channel *c, int speed);
int chn_setformat(struct pcm_channel *c, u_int32_t fmt);
int chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz);
int chn_trigger(struct pcm_channel *c, int go);
int chn_getptr(struct pcm_channel *c);
struct pcmchan_caps *chn_getcaps(struct pcm_channel *c);
u_int32_t chn_getformats(struct pcm_channel *c);
void chn_resetbuf(pcm_channel *c);
void chn_intr(pcm_channel *c);
void chn_checkunderflow(pcm_channel *c);
int chn_wrfeed(pcm_channel *c);
int chn_rdfeed(pcm_channel *c);
int chn_abort(pcm_channel *c);
void chn_resetbuf(struct pcm_channel *c);
void chn_intr(struct pcm_channel *c);
int chn_wrfeed(struct pcm_channel *c);
int chn_rdfeed(struct pcm_channel *c);
int chn_abort(struct pcm_channel *c);
void chn_wrupdate(struct pcm_channel *c);
void chn_rdupdate(struct pcm_channel *c);
#define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock))
#define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock))
#define CHN_LOCKASSERT(c)
int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
@ -67,11 +101,8 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
#define PCMTRIG_STOP 0
#define PCMTRIG_ABORT -1
#define CHN_F_READING 0x00000001 /* have a pending read */
#define CHN_F_WRITING 0x00000002 /* have a pending write */
#define CHN_F_CLOSING 0x00000004 /* a pending close */
#define CHN_F_ABORTING 0x00000008 /* a pending abort */
#define CHN_F_PENDING_IO (CHN_F_READING | CHN_F_WRITING)
#define CHN_F_RUNNING 0x00000010 /* dma is running */
#define CHN_F_TRIGGERED 0x00000020
#define CHN_F_NOTRIGGER 0x00000040
@ -79,7 +110,6 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
#define CHN_F_BUSY 0x00001000 /* has been opened */
#define CHN_F_HAS_SIZE 0x00002000 /* user set block size */
#define CHN_F_NBIO 0x00004000 /* do non-blocking i/o */
#define CHN_F_INIT 0x00008000 /* changed parameters. need init */
#define CHN_F_MAPPED 0x00010000 /* has been mmap()ed */
#define CHN_F_DEAD 0x00020000
#define CHN_F_BADSETTING 0x00040000
@ -92,9 +122,9 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
* (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec)
*/
#define CHN_2NDBUFBLKSIZE (2 * 1024)
/* The total number of blocks per secondary buffer. */
/* The total number of blocks per secondary bufhard. */
#define CHN_2NDBUFBLKNUM (32)
/* The size of a whole secondary buffer. */
/* The size of a whole secondary bufhard. */
#define CHN_2NDBUFMAXSIZE (131072)
#define CHN_DEFAULT_HZ 50

View File

@ -62,8 +62,8 @@ CODE {
METHOD void* init {
kobj_t obj;
void *devinfo;
snd_dbuf *b;
pcm_channel *c;
struct snd_dbuf *b;
struct pcm_channel *c;
int dir;
};
@ -117,7 +117,7 @@ METHOD u_int32_t getptr {
void *data;
};
METHOD pcmchan_caps* getcaps {
METHOD struct pcmchan_caps* getcaps {
kobj_t obj;
void *data;
};

View File

@ -118,7 +118,7 @@ struct _pcm_channel {
u_int32_t blocks;
int direction;
snd_dbuf buffer, buffer2nd;
snd_dbuf buffer, bufsoft;
snddev_info *parent;
void *devinfo;
};

View File

@ -33,12 +33,12 @@
#define OLDPCM_IOCTL
static int getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch);
static int getchns(struct snddev_info *d, int chan, struct pcm_channel **rdch, struct pcm_channel **wrch);
static pcm_channel *
allocchn(snddev_info *d, int direction)
static struct pcm_channel *
allocchn(struct snddev_info *d, int direction)
{
pcm_channel *chns = (direction == PCMDIR_PLAY)? d->play : d->rec;
struct pcm_channel *chns = (direction == PCMDIR_PLAY)? d->play : d->rec;
int i, cnt = (direction == PCMDIR_PLAY)? d->playcount : d->reccount;
for (i = 0; i < cnt; i++) {
if (!(chns[i].flags & (CHN_F_BUSY | CHN_F_DEAD))) {
@ -50,15 +50,15 @@ allocchn(snddev_info *d, int direction)
}
static int
getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch)
getchns(struct snddev_info *d, int chan, struct pcm_channel **rdch, struct pcm_channel **wrch)
{
KASSERT((d->flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
("getchns: read and write both prioritised"));
if ((d->flags & SD_F_SIMPLEX) && (d->flags & SD_F_PRIO_SET)) {
*rdch = (d->flags & SD_F_PRIO_RD)? d->arec[chan] : &d->fakechan;
*wrch = (d->flags & SD_F_PRIO_WR)? d->aplay[chan] : &d->fakechan;
d->fakechan.flags |= CHN_F_BUSY;
*rdch = (d->flags & SD_F_PRIO_RD)? d->arec[chan] : d->fakechan;
*wrch = (d->flags & SD_F_PRIO_WR)? d->aplay[chan] : d->fakechan;
d->fakechan->flags |= CHN_F_BUSY;
} else {
*rdch = d->arec[chan];
*wrch = d->aplay[chan];
@ -67,7 +67,7 @@ getchns(snddev_info *d, int chan, pcm_channel **rdch, pcm_channel **wrch)
}
static void
setchns(snddev_info *d, int chan)
setchns(struct snddev_info *d, int chan)
{
KASSERT((d->flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \
("getchns: read and write both prioritised"));
@ -75,14 +75,13 @@ setchns(snddev_info *d, int chan)
}
int
dsp_open(snddev_info *d, int chan, int oflags, int devtype)
dsp_open(struct snddev_info *d, int chan, int oflags, int devtype)
{
pcm_channel *rdch, *wrch;
struct pcm_channel *rdch, *wrch;
u_int32_t fmt;
if (chan >= d->chancount) return ENODEV;
if ((d->flags & SD_F_SIMPLEX) && (d->ref[chan] > 0)) return EBUSY;
if (d->atype[chan] != 0 && d->atype[chan] != devtype) return EBUSY;
rdch = d->arec[chan];
wrch = d->aplay[chan];
@ -102,7 +101,6 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype)
}
} else return EBUSY;
}
d->atype[chan] = devtype;
d->aplay[chan] = wrch;
d->arec[chan] = rdch;
d->ref[chan]++;
@ -126,6 +124,10 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype)
default:
return ENXIO;
}
if (rdch)
CHN_LOCK(rdch);
if (wrch)
CHN_LOCK(wrch);
if (rdch && (oflags & FREAD)) {
chn_reset(rdch, fmt);
@ -135,77 +137,101 @@ dsp_open(snddev_info *d, int chan, int oflags, int devtype)
chn_reset(wrch, fmt);
if (oflags & O_NONBLOCK) wrch->flags |= CHN_F_NBIO;
}
if (wrch)
CHN_UNLOCK(wrch);
if (rdch)
CHN_UNLOCK(rdch);
return 0;
}
int
dsp_close(snddev_info *d, int chan, int devtype)
dsp_close(struct snddev_info *d, int chan, int devtype)
{
pcm_channel *rdch, *wrch;
struct pcm_channel *rdch, *wrch;
d->ref[chan] = 0;
#if 0
/* enable this if/when every close() is propagated here */
d->ref[chan]--;
if (d->ref[chan]) return 0;
#endif
d->flags &= ~SD_F_TRANSIENT;
rdch = d->arec[chan];
wrch = d->aplay[chan];
if (rdch) {
CHN_LOCK(rdch);
chn_abort(rdch);
rdch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
chn_reset(rdch, 0);
CHN_UNLOCK(rdch);
}
if (wrch) {
CHN_LOCK(wrch);
chn_flush(wrch);
wrch->flags &= ~(CHN_F_BUSY | CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
chn_reset(wrch, 0);
CHN_UNLOCK(wrch);
}
d->aplay[chan] = NULL;
d->arec[chan] = NULL;
d->atype[chan] = 0;
return 0;
}
int
dsp_read(snddev_info *d, int chan, struct uio *buf, int flag)
dsp_read(struct snddev_info *d, int chan, struct uio *buf, int flag)
{
pcm_channel *rdch, *wrch;
struct pcm_channel *rdch, *wrch;
int ret;
if (!(d->flags & SD_F_PRIO_SET)) d->flags |= SD_F_PRIO_RD;
if (!(d->flags & SD_F_DIR_SET)) setchns(d, chan);
getchns(d, chan, &rdch, &wrch);
CHN_LOCK(rdch);
KASSERT(rdch, ("dsp_read: nonexistant channel"));
KASSERT(rdch->flags & CHN_F_BUSY, ("dsp_read: nonbusy channel"));
if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL;
if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
CHN_UNLOCK(rdch);
return EINVAL;
}
if (!(rdch->flags & CHN_F_RUNNING))
rdch->flags |= CHN_F_RUNNING;
return chn_read(rdch, buf);
ret = chn_read(rdch, buf);
CHN_UNLOCK(rdch);
return ret;
}
int
dsp_write(snddev_info *d, int chan, struct uio *buf, int flag)
dsp_write(struct snddev_info *d, int chan, struct uio *buf, int flag)
{
pcm_channel *rdch, *wrch;
struct pcm_channel *rdch, *wrch;
int ret;
if (!(d->flags & SD_F_PRIO_SET)) d->flags |= SD_F_PRIO_WR;
if (!(d->flags & SD_F_DIR_SET)) setchns(d, chan);
getchns(d, chan, &rdch, &wrch);
CHN_LOCK(wrch);
KASSERT(wrch, ("dsp_write: nonexistant channel"));
KASSERT(wrch->flags & CHN_F_BUSY, ("dsp_write: nonbusy channel"));
if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) return EINVAL;
if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
CHN_UNLOCK(wrch);
return EINVAL;
}
if (!(wrch->flags & CHN_F_RUNNING))
wrch->flags |= CHN_F_RUNNING;
return chn_write(wrch, buf);
ret = chn_write(wrch, buf);
CHN_UNLOCK(wrch);
return ret;
}
int
dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
dsp_ioctl(struct snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
int ret = 0, *arg_i = (int *)arg;
u_long s;
pcm_channel *wrch = NULL, *rdch = NULL;
struct pcm_channel *wrch = NULL, *rdch = NULL;
rdch = d->arec[chan];
wrch = d->aplay[chan];
@ -216,6 +242,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
wrch = NULL;
if (!(rdch || wrch))
return EINVAL;
if (wrch)
CHN_LOCK(wrch);
if (rdch)
CHN_LOCK(rdch);
/*
* all routines are called with int. blocked. Make sure that
* ints are re-enabled when calling slow or blocking functions!
@ -227,9 +258,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
* we start with the new ioctl interface.
*/
case AIONWRITE: /* how many bytes can write ? */
if (wrch && wrch->buffer.dl)
while (chn_wrfeed(wrch) > 0);
*arg_i = wrch? wrch->buffer2nd.fl : 0;
/*
if (wrch && wrch->bufhard.dl)
while (chn_wrfeed(wrch) == 0);
*/
*arg_i = wrch? sndbuf_getfree(wrch->bufsoft) : 0;
break;
case AIOSSIZE: /* set the current blocksize */
@ -245,9 +278,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
struct snd_size *p = (struct snd_size *)arg;
if (wrch)
p->play_size = wrch->buffer2nd.blksz;
p->play_size = sndbuf_getblksz(wrch->bufsoft);
if (rdch)
p->rec_size = rdch->buffer2nd.blksz;
p->rec_size = sndbuf_getblksz(rdch->bufsoft);
}
break;
@ -278,15 +311,15 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case AIOGCAP: /* get capabilities */
{
snd_capabilities *p = (snd_capabilities *)arg;
pcmchan_caps *pcaps = NULL, *rcaps = NULL;
struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
if (rdch) rcaps = chn_getcaps(rdch);
if (wrch) pcaps = chn_getcaps(wrch);
p->rate_min = max(rcaps? rcaps->minspeed : 0,
pcaps? pcaps->minspeed : 0);
p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
pcaps? pcaps->maxspeed : 1000000);
p->bufsize = min(rdch? rdch->buffer2nd.bufsize : 1000000,
wrch? wrch->buffer2nd.bufsize : 1000000);
p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
/* XXX bad on sb16 */
p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
(wrch? chn_getformats(wrch) : 0xffffffff);
@ -318,9 +351,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
* here follow the standard ioctls (filio.h etc.)
*/
case FIONREAD: /* get # bytes to read */
if (rdch && rdch->buffer.dl)
while (chn_rdfeed(rdch) > 0);
*arg_i = rdch? rdch->buffer2nd.rl : 0;
/* if (rdch && rdch->bufhard.dl)
while (chn_rdfeed(rdch) == 0);
*/ *arg_i = rdch? sndbuf_getready(rdch->bufsoft) : 0;
break;
case FIOASYNC: /*set/clear async i/o */
@ -344,9 +377,9 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
case SNDCTL_DSP_GETBLKSIZE:
if (wrch)
*arg_i = wrch->buffer2nd.blksz;
*arg_i = sndbuf_getblksz(wrch->bufsoft);
else if (rdch)
*arg_i = rdch->buffer2nd.blksz;
*arg_i = sndbuf_getblksz(rdch->bufsoft);
else
*arg_i = 0;
break ;
@ -359,19 +392,18 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_RESET:
DEB(printf("dsp reset\n"));
splx(s);
if (wrch) chn_abort(wrch);
if (rdch) chn_abort(rdch);
if (wrch)
chn_abort(wrch);
if (rdch)
chn_abort(rdch);
break;
case SNDCTL_DSP_SYNC:
DEB(printf("dsp sync\n"));
splx(s);
if (wrch) chn_sync(wrch, wrch->buffer2nd.bufsize - 4);
if (wrch) chn_sync(wrch, sndbuf_getsize(wrch->bufsoft) - 4);
break;
case SNDCTL_DSP_SPEED:
splx(s);
if (wrch)
ret = chn_setspeed(wrch, *arg_i);
if (rdch && ret == 0)
@ -383,7 +415,6 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
break;
case SNDCTL_DSP_STEREO:
splx(s);
if (wrch)
ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
((*arg_i)? AFMT_STEREO : 0));
@ -395,7 +426,6 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SOUND_PCM_WRITE_CHANNELS:
/* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
splx(s);
if (*arg_i == 1 || *arg_i == 2) {
if (wrch)
ret = chn_setformat(wrch, (wrch->format & ~AFMT_STEREO) |
@ -427,15 +457,10 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
*arg_i = (wrch? wrch->format : rdch->format) & ~AFMT_STEREO;
break;
case SNDCTL_DSP_SUBDIVIDE:
/* XXX watch out, this is RW! */
printf("SNDCTL_DSP_SUBDIVIDE unimplemented\n");
break;
case SNDCTL_DSP_SETFRAGMENT:
DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
{
pcm_channel *c = wrch? wrch : rdch;
struct pcm_channel *c = wrch? wrch : rdch;
u_int32_t fragln = (*arg_i) & 0x0000ffff;
u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
u_int32_t fragsz;
@ -458,13 +483,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
if (wrch && ret == 0)
ret = chn_setblocksize(wrch, maxfrags, fragsz);
fragsz = c->buffer2nd.blksz;
fragsz = sndbuf_getblksz(c->bufsoft);
fragln = 0;
while (fragsz > 1) {
fragln++;
fragsz >>= 1;
}
*arg_i = (c->buffer2nd.blkcnt << 16) | fragln;
*arg_i = (sndbuf_getblkcnt(c->bufsoft) << 16) | fragln;
}
break;
@ -473,18 +498,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
audio_buf_info *a = (audio_buf_info *)arg;
if (rdch) {
snd_dbuf *b = &rdch->buffer;
snd_dbuf *bs = &rdch->buffer2nd;
if (b->dl && !(rdch->flags & CHN_F_MAPPED))
/*
* Suck up the secondary and DMA buffer.
* chn_rdfeed*() takes care of the alignment.
*/
while (chn_rdfeed(rdch) > 0);
a->bytes = bs->rl;
a->fragments = a->bytes / rdch->buffer2nd.blksz;
a->fragstotal = rdch->buffer2nd.blkcnt;
a->fragsize = rdch->buffer2nd.blksz;
struct snd_dbuf *bs = rdch->bufsoft;
chn_rdupdate(rdch);
a->bytes = sndbuf_getfree(bs);
a->fragments = a->bytes / sndbuf_getblksz(bs);
a->fragstotal = sndbuf_getblkcnt(bs);
a->fragsize = sndbuf_getblksz(bs);
}
}
break;
@ -494,21 +514,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
audio_buf_info *a = (audio_buf_info *)arg;
if (wrch) {
snd_dbuf *b = &wrch->buffer;
snd_dbuf *bs = &wrch->buffer2nd;
if (b->dl && !(wrch->flags & CHN_F_MAPPED)) {
/*
* Fill up the secondary and DMA buffer.
* chn_wrfeed*() takes care of the alignment.
* Check for underflow before writing into the buffers.
*/
chn_checkunderflow(wrch);
while (chn_wrfeed(wrch) > 0);
}
a->bytes = bs->fl;
a->fragments = a->bytes / wrch->buffer2nd.blksz;
a->fragstotal = wrch->buffer2nd.blkcnt;
a->fragsize = wrch->buffer2nd.blksz;
struct snd_dbuf *bs = wrch->bufsoft;
chn_wrupdate(wrch);
a->bytes = sndbuf_getfree(bs);
a->fragments = a->bytes / sndbuf_getblksz(bs);
a->fragstotal = sndbuf_getblkcnt(bs);
a->fragsize = sndbuf_getblksz(bs);
}
}
break;
@ -517,18 +529,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
count_info *a = (count_info *)arg;
if (rdch) {
snd_dbuf *b = &rdch->buffer;
snd_dbuf *bs = &rdch->buffer2nd;
if (b->dl && !(rdch->flags & CHN_F_MAPPED))
/*
* Suck up the secondary and DMA buffer.
* chn_rdfeed*() takes care of the alignment.
*/
while (chn_rdfeed(rdch) > 0);
a->bytes = bs->total;
a->blocks = rdch->blocks;
a->ptr = bs->rp;
rdch->blocks = 0;
struct snd_dbuf *bs = rdch->bufsoft;
chn_rdupdate(rdch);
a->bytes = sndbuf_gettotal(bs);
a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
a->ptr = sndbuf_getreadyptr(bs);
rdch->blocks = sndbuf_getblocks(bs);
} else ret = EINVAL;
}
break;
@ -537,21 +544,13 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
{
count_info *a = (count_info *)arg;
if (wrch) {
snd_dbuf *b = &wrch->buffer;
snd_dbuf *bs = &wrch->buffer2nd;
if (b->dl && !(wrch->flags & CHN_F_MAPPED)) {
/*
* Fill up the secondary and DMA buffer.
* chn_wrfeed*() takes care of the alignment.
* Check for underflow before writing into the buffers.
*/
chn_checkunderflow(wrch);
while (chn_wrfeed(wrch) > 0);
}
a->bytes = bs->total;
a->blocks = wrch->blocks;
a->ptr = bs->rp;
wrch->blocks = 0;
struct snd_dbuf *bs = wrch->bufsoft;
chn_wrupdate(wrch);
a->bytes = sndbuf_gettotal(bs);
a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
a->ptr = sndbuf_getreadyptr(bs);
wrch->blocks = sndbuf_getblocks(bs);
} else ret = EINVAL;
}
break;
@ -569,19 +568,19 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_SETTRIGGER:
if (rdch) {
rdch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
if (*arg_i & PCM_ENABLE_INPUT)
if (*arg_i & PCM_ENABLE_INPUT) {
rdch->flags |= CHN_F_TRIGGERED;
else
chn_start(rdch, 1);
} else
rdch->flags |= CHN_F_NOTRIGGER;
chn_intr(rdch);
}
if (wrch) {
wrch->flags &= ~(CHN_F_TRIGGERED | CHN_F_NOTRIGGER);
if (*arg_i & PCM_ENABLE_OUTPUT)
if (*arg_i & PCM_ENABLE_OUTPUT) {
wrch->flags |= CHN_F_TRIGGERED;
else
chn_start(wrch, 1);
} else
wrch->flags |= CHN_F_NOTRIGGER;
chn_intr(wrch);
}
break;
@ -595,14 +594,11 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_GETODELAY:
if (wrch) {
snd_dbuf *b = &wrch->buffer;
snd_dbuf *bs = &wrch->buffer2nd;
if (b->dl) {
chn_checkunderflow(wrch);
if (!(wrch->flags & CHN_F_MAPPED))
while (chn_wrfeed(wrch) > 0);
}
*arg_i = b->rl + bs->rl;
struct snd_dbuf *b = wrch->bufhard;
struct snd_dbuf *bs = wrch->bufsoft;
chn_wrupdate(wrch);
*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
} else
ret = EINVAL;
break;
@ -619,6 +615,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
case SNDCTL_DSP_SETSYNCRO:
/* undocumented */
case SNDCTL_DSP_SUBDIVIDE:
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
/* dunno what these do, don't sound important */
@ -627,39 +624,57 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
ret = EINVAL;
break;
}
splx(s);
if (rdch)
CHN_UNLOCK(rdch);
if (wrch)
CHN_UNLOCK(wrch);
return ret;
}
int
dsp_poll(snddev_info *d, int chan, int events, struct proc *p)
dsp_poll(struct snddev_info *d, int chan, int events, struct proc *p)
{
int ret = 0, e;
pcm_channel *wrch = NULL, *rdch = NULL;
struct pcm_channel *wrch = NULL, *rdch = NULL;
getchns(d, chan, &rdch, &wrch);
e = events & (POLLOUT | POLLWRNORM);
if (wrch && e) ret |= chn_poll(wrch, e, p);
e = events & (POLLIN | POLLRDNORM);
if (rdch && e) ret |= chn_poll(rdch, e, p);
return ret;
}
int
dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot)
dsp_mmap(struct snddev_info *d, int chan, vm_offset_t offset, int nprot)
{
pcm_channel *wrch = NULL, *rdch = NULL, *c = NULL;
struct pcm_channel *wrch = NULL, *rdch = NULL, *c = NULL;
int ret;
getchns(d, chan, &rdch, &wrch);
/* XXX this is broken by line 204 of vm/device_pager.c, so force write buffer */
#if 0
/*
* XXX the linux api uses the nprot to select read/write bufhard
* our vm system doesn't allow this, so force write bufhard
*/
if (1 || (wrch && (nprot & PROT_WRITE)))
c = wrch;
else if (rdch && (nprot & PROT_READ))
c = rdch;
if (c && (c->format == c->buffer.fmt)) {
c->flags |= CHN_F_MAPPED;
return atop(vtophys(c->buffer2nd.buf + offset));
} else
#else
c = wrch;
#endif
if (c == NULL)
return -1;
CHN_LOCK(c);
c->flags |= CHN_F_MAPPED;
ret = atop(vtophys(((char *)sndbuf_getbuf(c->bufsoft)) + offset));
CHN_UNLOCK(c);
return ret;
}

View File

@ -26,12 +26,12 @@
* $FreeBSD$
*/
int dsp_open(snddev_info *d, int chan, int oflags, int devtype);
int dsp_close(snddev_info *d, int chan, int devtype);
int dsp_read(snddev_info *d, int chan, struct uio *buf, int flag);
int dsp_write(snddev_info *d, int chan, struct uio *buf, int flag);
int dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg);
int dsp_poll(snddev_info *d, int chan, int events, struct proc *p);
int dsp_mmap(snddev_info *d, int chan, vm_offset_t offset, int nprot);
int dsp_open(struct snddev_info *d, int chan, int oflags, int devtype);
int dsp_close(struct snddev_info *d, int chan, int devtype);
int dsp_read(struct snddev_info *d, int chan, struct uio *buf, int flag);
int dsp_write(struct snddev_info *d, int chan, struct uio *buf, int flag);
int dsp_ioctl(struct snddev_info *d, int chan, u_long cmd, caddr_t arg);
int dsp_poll(struct snddev_info *d, int chan, int events, struct proc *p);
int dsp_mmap(struct snddev_info *d, int chan, vm_offset_t offset, int nprot);

View File

@ -43,14 +43,16 @@ static u_int32_t fk_fmt[] = {
AFMT_STEREO | AFMT_U16_BE,
0
};
static pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0};
static struct pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0};
#define FKBUFSZ 4096
static char fakebuf[FKBUFSZ];
/* channel interface */
static void *
fkchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
fkchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
b->bufsize = 16384;
b->buf = malloc(b->bufsize, M_DEVBUF, M_NOWAIT);
sndbuf_setup(b, fakebuf, FKBUFSZ);
return (void *)0xbabef00d;
}
@ -90,7 +92,7 @@ fkchan_getptr(kobj_t obj, void *data)
return 0;
}
static pcmchan_caps *
static struct pcmchan_caps *
fkchan_getcaps(kobj_t obj, void *data)
{
return &fk_caps;
@ -109,18 +111,26 @@ static kobj_method_t fkchan_methods[] = {
};
CHANNEL_DECLARE(fkchan);
int
fkchan_setup(pcm_channel *c)
struct pcm_channel *
fkchan_setup(device_t dev)
{
struct snddev_info *d = device_get_softc(dev);
struct pcm_channel *c;
c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK);
c->methods = kobj_create(&fkchan_class, M_DEVBUF, M_WAITOK);
return 0;
c->parent = d;
snprintf(c->name, CHN_NAMELEN, "%s:fake", device_get_nameunit(dev));
return c;
}
int
fkchan_kill(pcm_channel *c)
fkchan_kill(struct pcm_channel *c)
{
kobj_delete(c->methods, M_DEVBUF);
c->methods = NULL;
free(c, M_DEVBUF);
return 0;
}

View File

@ -105,20 +105,20 @@ cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
}
static void
feeder_destroy(pcm_feeder *f)
feeder_destroy(struct pcm_feeder *f)
{
FEEDER_FREE(f);
free(f->desc, M_FEEDER);
kobj_delete((kobj_t)f, M_FEEDER);
}
static pcm_feeder *
static struct pcm_feeder *
feeder_create(struct feeder_class *fc, struct pcm_feederdesc *desc)
{
pcm_feeder *f;
struct pcm_feeder *f;
int err;
f = (pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO);
f = (struct pcm_feeder *)kobj_create((kobj_class_t)fc, M_FEEDER, M_WAITOK | M_ZERO);
f->align = fc->align;
f->desc = malloc(sizeof(*(f->desc)), M_FEEDER, M_WAITOK | M_ZERO);
if (desc)
@ -155,9 +155,9 @@ feeder_getclass(struct pcm_feederdesc *desc)
}
int
chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc)
{
pcm_feeder *nf;
struct pcm_feeder *nf;
nf = feeder_create(fc, desc);
if (nf == NULL)
@ -176,9 +176,9 @@ chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *de
}
int
chn_removefeeder(pcm_channel *c)
chn_removefeeder(struct pcm_channel *c)
{
pcm_feeder *f;
struct pcm_feeder *f;
if (c->feeder == NULL)
return -1;
@ -188,10 +188,10 @@ chn_removefeeder(pcm_channel *c)
return 0;
}
pcm_feeder *
chn_findfeeder(pcm_channel *c, u_int32_t type)
struct pcm_feeder *
chn_findfeeder(struct pcm_channel *c, u_int32_t type)
{
pcm_feeder *f;
struct pcm_feeder *f;
f = c->feeder;
while (f != NULL) {
@ -203,7 +203,7 @@ chn_findfeeder(pcm_channel *c, u_int32_t type)
}
static int
chainok(pcm_feeder *test, pcm_feeder *stop)
chainok(struct pcm_feeder *test, struct pcm_feeder *stop)
{
u_int32_t visited[MAXFEEDERS / 32];
u_int32_t idx, mask;
@ -225,11 +225,11 @@ chainok(pcm_feeder *test, pcm_feeder *stop)
return 1;
}
static pcm_feeder *
feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth)
static struct pcm_feeder *
feeder_fmtchain(u_int32_t *to, struct pcm_feeder *source, struct pcm_feeder *stop, int maxdepth)
{
struct feedertab_entry *fte;
pcm_feeder *try, *ret;
struct pcm_feeder *try, *ret;
struct pcm_feederdesc trydesc;
/* printf("trying %s...\n", source->name); */
@ -266,9 +266,9 @@ feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdept
}
u_int32_t
chn_fmtchain(pcm_channel *c, u_int32_t *to)
chn_fmtchain(struct pcm_channel *c, u_int32_t *to)
{
pcm_feeder *try, *stop;
struct pcm_feeder *try, *stop;
int max;
stop = c->feeder;
@ -306,21 +306,27 @@ chn_fmtchain(pcm_channel *c, u_int32_t *to)
/*****************************************************************************/
static int
feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream)
feed_root(struct pcm_feeder *feeder, struct pcm_channel *ch, u_int8_t *buffer, u_int32_t count, void *source)
{
int ret, s;
struct snd_dbuf *src = source;
int l;
u_int8_t x;
KASSERT(count, ("feed_root: count == 0"));
count &= ~((1 << ch->align) - 1);
KASSERT(count, ("feed_root: aligned count == 0 (align = %d)", ch->align));
KASSERT(count > 0, ("feed_root: count == 0"));
/* count &= ~((1 << ch->align) - 1); */
KASSERT(count > 0, ("feed_root: aligned count == 0 (align = %d)", ch->align));
s = spltty();
count = min(count, stream->uio_resid);
if (count) {
ret = uiomove(buffer, count, stream);
KASSERT(ret == 0, ("feed_root: uiomove failed (%d)", ret));
}
splx(s);
l = min(count, sndbuf_getready(src));
sndbuf_dispose(src, buffer, l);
/*
if (l < count)
printf("appending %d bytes\n", count - l);
*/
x = (sndbuf_getfmt(src) & AFMT_SIGNED)? 0 : 0x80;
while (l < count)
buffer[l++] = x;
return count;
}
@ -332,7 +338,7 @@ static kobj_method_t feeder_root_methods[] = {
static struct feeder_class feeder_root_class = {
name: "feeder_root",
methods: feeder_root_methods,
size: sizeof(pcm_feeder),
size: sizeof(struct pcm_feeder),
align: 0,
desc: NULL,
data: NULL,

View File

@ -26,6 +26,21 @@
* $FreeBSD$
*/
struct pcm_feederdesc {
u_int32_t type;
u_int32_t in, out;
u_int32_t flags;
int idx;
};
struct pcm_feeder {
KOBJ_FIELDS;
int align;
struct pcm_feederdesc *desc;
void *data;
struct pcm_feeder *source;
};
struct feeder_class {
KOBJ_CLASS_FIELDS;
int align;
@ -36,16 +51,16 @@ struct feeder_class {
void feeder_register(void *p);
struct feeder_class *feeder_getclass(struct pcm_feederdesc *desc);
u_int32_t chn_fmtchain(pcm_channel *c, u_int32_t *to);
int chn_addfeeder(pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc);
int chn_removefeeder(pcm_channel *c);
pcm_feeder *chn_findfeeder(pcm_channel *c, u_int32_t type);
u_int32_t chn_fmtchain(struct pcm_channel *c, u_int32_t *to);
int chn_addfeeder(struct pcm_channel *c, struct feeder_class *fc, struct pcm_feederdesc *desc);
int chn_removefeeder(struct pcm_channel *c);
struct pcm_feeder *chn_findfeeder(struct pcm_channel *c, u_int32_t type);
#define FEEDER_DECLARE(feeder, palign, pdata) \
static struct feeder_class feeder ## _class = { \
name: #feeder, \
methods: feeder ## _methods, \
size: sizeof(pcm_feeder), \
size: sizeof(struct pcm_feeder), \
align: palign, \
desc: feeder ## _desc, \
data: pdata, \

View File

@ -177,11 +177,11 @@ static unsigned char ulaw_to_alaw[] = {
/*****************************************************************************/
static int
feed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_8to16le(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
int i, j, k;
k = FEEDER_FEED(f->source, c, b, count / 2, stream);
k = FEEDER_FEED(f->source, c, b, count / 2, source);
j = k - 1;
i = j * 2 + 1;
while (i > 0 && j >= 0) {
@ -207,14 +207,14 @@ FEEDER_DECLARE(feeder_8to16le, 0, NULL);
/*****************************************************************************/
static int
feed_16to8_init(pcm_feeder *f)
feed_16to8_init(struct pcm_feeder *f)
{
f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO);
return (f->data == NULL)? 0 : ENOMEM;
}
static int
feed_16to8_free(pcm_feeder *f)
feed_16to8_free(struct pcm_feeder *f)
{
if (f->data)
free(f->data, M_FMTFEEDER);
@ -223,12 +223,12 @@ feed_16to8_free(pcm_feeder *f)
}
static int
feed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_16leto8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
u_int32_t i = 0, toget = count * 2;
int j = 1, k;
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source);
while (j < k) {
b[i++] = ((u_int8_t *)f->data)[j];
j += 2;
@ -254,9 +254,9 @@ FEEDER_DECLARE(feeder_16leto8, 1, NULL);
/*****************************************************************************/
static int
feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_monotostereo8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, stream);
int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, source);
j = k - 1;
i = j * 2 + 1;
@ -282,9 +282,9 @@ FEEDER_DECLARE(feeder_monotostereo8, 0, NULL);
/*****************************************************************************/
static int
feed_monotostereo16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_monotostereo16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, stream);
int i, j, k = FEEDER_FEED(f->source, c, b, count / 2, source);
u_int8_t x, y;
j = k - 1;
@ -316,14 +316,14 @@ FEEDER_DECLARE(feeder_monotostereo16, 0, NULL);
/*****************************************************************************/
static int
feed_stereotomono8_init(pcm_feeder *f)
feed_stereotomono8_init(struct pcm_feeder *f)
{
f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO);
return (f->data == NULL)? 0 : ENOMEM;
}
static int
feed_stereotomono8_free(pcm_feeder *f)
feed_stereotomono8_free(struct pcm_feeder *f)
{
if (f->data)
free(f->data, M_FMTFEEDER);
@ -332,12 +332,12 @@ feed_stereotomono8_free(pcm_feeder *f)
}
static int
feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_stereotomono8(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
u_int32_t i = 0, toget = count * 2;
int j = 0, k;
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source);
while (j < k) {
b[i++] = ((u_int8_t *)f->data)[j];
j += 2;
@ -361,14 +361,14 @@ FEEDER_DECLARE(feeder_stereotomono8, 1, NULL);
/*****************************************************************************/
static int
feed_stereotomono16_init(pcm_feeder *f)
feed_stereotomono16_init(struct pcm_feeder *f)
{
f->data = malloc(FEEDBUFSZ, M_FMTFEEDER, M_WAITOK | M_ZERO);
return (f->data == NULL)? 0 : ENOMEM;
}
static int
feed_stereotomono16_free(pcm_feeder *f)
feed_stereotomono16_free(struct pcm_feeder *f)
{
if (f->data)
free(f->data, M_FMTFEEDER);
@ -377,12 +377,12 @@ feed_stereotomono16_free(pcm_feeder *f)
}
static int
feed_stereotomono16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_stereotomono16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
u_int32_t i = 0, toget = count * 2;
int j = 0, k;
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
k = FEEDER_FEED(f->source, c, f->data, min(toget, FEEDBUFSZ), source);
while (j < k) {
b[i++] = ((u_int8_t *)f->data)[j];
b[i++] = ((u_int8_t *)f->data)[j + 1];
@ -409,10 +409,10 @@ FEEDER_DECLARE(feeder_stereotomono16, 1, NULL);
/*****************************************************************************/
static int
feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_endian(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
u_int8_t t;
int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream);
int i = 0, j = FEEDER_FEED(f->source, c, b, count, source);
while (i < j) {
t = b[i];
@ -443,9 +443,9 @@ FEEDER_DECLARE(feeder_endian, 0, NULL);
/*****************************************************************************/
static int
feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_sign(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream);
int i = 0, j = FEEDER_FEED(f->source, c, b, count, source);
int ssz = (int)f->data, ofs = ssz - 1;
while (i < j) {
@ -484,9 +484,9 @@ FEEDER_DECLARE(feeder_sign16le, -1, (void *)2);
/*****************************************************************************/
static int
feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
feed_table(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32_t count, void *source)
{
int i = 0, j = FEEDER_FEED(f->source, c, b, count, stream);
int i = 0, j = FEEDER_FEED(f->source, c, b, count, source);
while (i < j) {
b[i] = ((u_int8_t *)f->data)[b[i]];

View File

@ -34,13 +34,13 @@ INTERFACE feeder;
CODE {
static int
feeder_noinit(pcm_feeder* feeder)
feeder_noinit(struct pcm_feeder* feeder)
{
return 0;
}
static int
feeder_nofree(pcm_feeder* feeder)
feeder_nofree(struct pcm_feeder* feeder)
{
return 0;
}
@ -48,25 +48,25 @@ CODE {
};
METHOD int init {
pcm_feeder* feeder;
struct pcm_feeder* feeder;
} DEFAULT feeder_noinit;
METHOD int free {
pcm_feeder* feeder;
struct pcm_feeder* feeder;
} DEFAULT feeder_nofree;
METHOD int set {
pcm_feeder* feeder;
struct pcm_feeder* feeder;
int what;
int value;
};
METHOD int feed {
pcm_feeder* feeder;
pcm_channel* c;
struct pcm_feeder* feeder;
struct pcm_channel* c;
u_int8_t* buffer;
u_int32_t count;
struct uio* stream;
void* source;
};

View File

@ -32,6 +32,24 @@
MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
#define MIXER_NAMELEN 16
struct snd_mixer {
KOBJ_FIELDS;
const char *type;
void *devinfo;
int busy;
int hwvol_muted;
int hwvol_mixer;
int hwvol_step;
u_int32_t hwvol_mute_level;
u_int32_t devs;
u_int32_t recdevs;
u_int32_t recsrc;
u_int16_t level[32];
char name[MIXER_NAMELEN];
void *lock;
};
static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
[SOUND_MIXER_VOLUME] = 75,
[SOUND_MIXER_BASS] = 50,
@ -65,7 +83,7 @@ mixer_lookup(char *devname)
#endif
static int
mixer_set(snd_mixer *mixer, unsigned dev, unsigned lev)
mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
{
unsigned l, r;
int v;
@ -85,7 +103,7 @@ mixer_set(snd_mixer *mixer, unsigned dev, unsigned lev)
}
static int
mixer_get(snd_mixer *mixer, int dev)
mixer_get(struct snd_mixer *mixer, int dev)
{
if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev)))
return mixer->level[dev];
@ -93,7 +111,7 @@ mixer_get(snd_mixer *mixer, int dev)
}
static int
mixer_setrecsrc(snd_mixer *mixer, u_int32_t src)
mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
{
src &= mixer->recdevs;
if (src == 0)
@ -103,50 +121,50 @@ mixer_setrecsrc(snd_mixer *mixer, u_int32_t src)
}
static int
mixer_getrecsrc(snd_mixer *mixer)
mixer_getrecsrc(struct snd_mixer *mixer)
{
return mixer->recsrc;
}
void
mix_setdevs(snd_mixer *m, u_int32_t v)
mix_setdevs(struct snd_mixer *m, u_int32_t v)
{
m->devs = v;
}
void
mix_setrecdevs(snd_mixer *m, u_int32_t v)
mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
{
m->recdevs = v;
}
u_int32_t
mix_getdevs(snd_mixer *m)
mix_getdevs(struct snd_mixer *m)
{
return m->devs;
}
u_int32_t
mix_getrecdevs(snd_mixer *m)
mix_getrecdevs(struct snd_mixer *m)
{
return m->recdevs;
}
void *
mix_getdevinfo(snd_mixer *m)
mix_getdevinfo(struct snd_mixer *m)
{
return m->devinfo;
}
int
mixer_busy(snd_mixer *m, int busy)
mixer_busy(struct snd_mixer *m, int busy)
{
m->busy = busy;
return 0;
}
int
mixer_isbusy(snd_mixer *m)
mixer_isbusy(struct snd_mixer *m)
{
return m->busy;
}
@ -154,15 +172,15 @@ mixer_isbusy(snd_mixer *m)
int
mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
{
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
u_int16_t v;
int i;
d = device_get_softc(dev);
m = (snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
m->name = cls->name;
m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
snprintf(m->name, MIXER_NAMELEN, "%s:mixer", device_get_nameunit(dev));
m->lock = snd_mtxcreate(m->name);
m->type = cls->name;
m->devinfo = devinfo;
if (MIXER_INIT(m))
@ -175,11 +193,15 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
mixer_setrecsrc(m, SOUND_MASK_MIC);
d = device_get_softc(dev);
d->mixer = m;
return 0;
bad: kobj_delete((kobj_t)m, M_MIXER);
bad:
snd_mtxlock(m->lock);
snd_mtxfree(m->lock);
kobj_delete((kobj_t)m, M_MIXER);
return -1;
}
@ -187,11 +209,12 @@ int
mixer_uninit(device_t dev)
{
int i;
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
d = device_get_softc(dev);
m = d->mixer;
snd_mtxlock(m->lock);
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
mixer_set(m, i, 0);
@ -200,6 +223,7 @@ mixer_uninit(device_t dev)
MIXER_UNINIT(m);
snd_mtxfree(m->lock);
kobj_delete((kobj_t)m, M_MIXER);
d->mixer = NULL;
@ -210,38 +234,44 @@ int
mixer_reinit(device_t dev)
{
int i;
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
d = device_get_softc(dev);
m = d->mixer;
snd_mtxlock(m->lock);
i = MIXER_REINIT(m);
if (i)
if (i) {
snd_mtxunlock(m->lock);
return i;
}
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
mixer_set(m, i, m->level[i]);
mixer_setrecsrc(m, m->recsrc);
snd_mtxunlock(m->lock);
return 0;
}
int
mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg)
mixer_ioctl(struct snddev_info *d, u_long cmd, caddr_t arg)
{
int ret, *arg_i = (int *)arg;
int v = -1, j = cmd & 0xff;
snd_mixer *m;
struct snd_mixer *m;
m = d->mixer;
snd_mtxlock(m->lock);
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
if (j == SOUND_MIXER_RECSRC)
ret = mixer_setrecsrc(m, *arg_i);
else
ret = mixer_set(m, j, *arg_i);
snd_mtxunlock(m->lock);
return (ret == 0)? 0 : ENXIO;
}
@ -265,8 +295,10 @@ mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg)
v = mixer_get(m, j);
}
*arg_i = v;
snd_mtxunlock(m->lock);
return (v != -1)? 0 : ENXIO;
}
snd_mtxunlock(m->lock);
return ENXIO;
}
@ -276,20 +308,24 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
{
char devname[32];
int error, dev;
snd_mixer *m;
struct snd_mixer *m;
m = oidp->oid_arg1;
snd_mtxlock(m->lock);
strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
if (error == 0 && req->newptr != NULL) {
dev = mixer_lookup(devname);
if (dev == -1)
if (dev == -1) {
snd_mtxunlock(m->lock);
return EINVAL;
}
else if (dev != m->hwvol_mixer) {
m->hwvol_mixer = dev;
m->hwvol_muted = 0;
}
}
snd_mtxunlock(m->lock);
return error;
}
#endif
@ -297,11 +333,12 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
int
mixer_hwvol_init(device_t dev)
{
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
d = device_get_softc(dev);
m = d->mixer;
snd_mtxlock(m->lock);
m->hwvol_mixer = SOUND_MIXER_VOLUME;
m->hwvol_step = 5;
#ifdef SND_DYNSYSCTL
@ -311,17 +348,19 @@ mixer_hwvol_init(device_t dev)
OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
sysctl_hw_snd_hwvol_mixer, "A", "")
#endif
snd_mtxunlock(m->lock);
return 0;
}
void
mixer_hwvol_mute(device_t dev)
{
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
d = device_get_softc(dev);
m = d->mixer;
snd_mtxlock(m->lock);
if (m->hwvol_muted) {
m->hwvol_muted = 0;
mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
@ -330,17 +369,19 @@ mixer_hwvol_mute(device_t dev)
m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
mixer_set(m, m->hwvol_mixer, 0);
}
snd_mtxunlock(m->lock);
}
void
mixer_hwvol_step(device_t dev, int left_step, int right_step)
{
snddev_info *d;
snd_mixer *m;
struct snddev_info *d;
struct snd_mixer *m;
int level, left, right;
d = device_get_softc(dev);
m = d->mixer;
snd_mtxlock(m->lock);
if (m->hwvol_muted) {
m->hwvol_muted = 0;
level = m->hwvol_mute_level;
@ -357,36 +398,7 @@ mixer_hwvol_step(device_t dev, int left_step, int right_step)
right = 0;
mixer_set(m, m->hwvol_mixer, left | right << 8);
}
snd_mtxunlock(m->lock);
}
/*
* The various mixers use a variety of bitmasks etc. The Voxware
* driver had a very nice technique to describe a mixer and interface
* to it. A table defines, for each channel, which register, bits,
* offset, polarity to use. This procedure creates the new value
* using the table and the old value.
*/
void
change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval)
{
u_char mask;
int shift;
DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x "
"r %d p %d bit %d off %d\n",
dev, chn, newval, *regval,
(*t)[dev][chn].regno, (*t)[dev][chn].polarity,
(*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) );
if ( (*t)[dev][chn].polarity == 1) /* reverse */
newval = 100 - newval ;
mask = (1 << (*t)[dev][chn].nbits) - 1;
newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/;
*regval &= ~(mask << shift); /* Filter out the previous value */
*regval |= (newval & mask) << shift; /* Set the new value */
}

View File

@ -26,23 +26,27 @@
* $FreeBSD$
*/
extern int mixer_init(device_t dev, kobj_class_t cls, void *devinfo);
extern int mixer_uninit(device_t dev);
extern int mixer_reinit(device_t dev);
extern int mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg);
extern int mixer_busy(snd_mixer *m, int busy);
extern int mixer_isbusy(snd_mixer *m);
int mixer_init(device_t dev, kobj_class_t cls, void *devinfo);
int mixer_uninit(device_t dev);
int mixer_reinit(device_t dev);
int mixer_ioctl(struct snddev_info *d, u_long cmd, caddr_t arg);
int mixer_busy(struct snd_mixer *m, int busy);
int mixer_isbusy(struct snd_mixer *m);
int mixer_hwvol_init(device_t dev);
void mixer_hwvol_mute(device_t dev);
void mixer_hwvol_step(device_t dev, int left_step, int right_step);
extern void change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval);
void mix_setdevs(struct snd_mixer *m, u_int32_t v);
void mix_setrecdevs(struct snd_mixer *m, u_int32_t v);
u_int32_t mix_getdevs(struct snd_mixer *m);
u_int32_t mix_getrecdevs(struct snd_mixer *m);
void *mix_getdevinfo(struct snd_mixer *m);
void mix_setdevs(snd_mixer *m, u_int32_t v);
void mix_setrecdevs(snd_mixer *m, u_int32_t v);
u_int32_t mix_getdevs(snd_mixer *m);
u_int32_t mix_getrecdevs(snd_mixer *m);
void *mix_getdevinfo(snd_mixer *m);
/*
* this is a kludge to allow hiding of the struct snd_mixer definition
* 512 should be enough for all architectures
*/
#define MIXER_SIZE (512 + sizeof(struct kobj))
#define MIXER_DECLARE(name) DEFINE_CLASS(name, name ## _methods, sizeof(snd_mixer))
#define MIXER_DECLARE(name) DEFINE_CLASS(name, name ## _methods, MIXER_SIZE)

View File

@ -34,7 +34,7 @@ INTERFACE mixer;
CODE {
static int
mixer_noreinit(snd_mixer *m)
mixer_noreinit(struct snd_mixer *m)
{
return 0;
}
@ -42,26 +42,26 @@ CODE {
};
METHOD int init {
snd_mixer *m;
struct snd_mixer *m;
};
METHOD int reinit {
snd_mixer *m;
struct snd_mixer *m;
} DEFAULT mixer_noreinit;
METHOD int uninit {
snd_mixer *m;
struct snd_mixer *m;
};
METHOD int set {
snd_mixer *m;
struct snd_mixer *m;
unsigned dev;
unsigned left;
unsigned right;
};
METHOD u_int32_t setrecsrc {
snd_mixer *m;
struct snd_mixer *m;
u_int32_t src
};

View File

@ -57,7 +57,7 @@ static struct cdevsw snd_cdevsw = {
/* maj */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* flags */ D_TRACKCLOSE,
/* bmaj */ -1
};
@ -229,8 +229,8 @@ int
pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
{
int unit = device_get_unit(dev), idx;
snddev_info *d = device_get_softc(dev);
pcm_channel *chns, *ch;
struct snddev_info *d = device_get_softc(dev);
struct pcm_channel *chns, *ch;
char *dirs;
int err;
@ -245,6 +245,7 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
ch = &chns[idx];
ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK);
ch->parent = d;
snprintf(ch->name, 32, "%s:%s:%d", device_get_nameunit(dev), dirs, idx);
err = chn_init(ch, devinfo, dir);
if (err) {
device_printf(dev, "chn_init() for (%s:%d) failed: err = %d\n", dirs, idx, err);
@ -269,8 +270,8 @@ static int
pcm_killchan(device_t dev, int dir)
{
int unit = device_get_unit(dev), idx;
snddev_info *d = device_get_softc(dev);
pcm_channel *chns, *ch;
struct snddev_info *d = device_get_softc(dev);
struct pcm_channel *chns, *ch;
char *dirs;
dev_t pdev;
@ -302,7 +303,7 @@ pcm_killchan(device_t dev, int dir)
int
pcm_setstatus(device_t dev, char *str)
{
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
strncpy(d->status, str, SND_STATUSLEN);
return 0;
}
@ -310,21 +311,21 @@ pcm_setstatus(device_t dev, char *str)
u_int32_t
pcm_getflags(device_t dev)
{
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
return d->flags;
}
void
pcm_setflags(device_t dev, u_int32_t val)
{
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
d->flags = val;
}
void *
pcm_getdevinfo(device_t dev)
{
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
return d->devinfo;
}
@ -333,7 +334,7 @@ int
pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
{
int sz, unit = device_get_unit(dev);
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
if (!pcm_devclass) {
pcm_devclass = device_get_devclass(dev);
@ -346,14 +347,14 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
d->devinfo = devinfo;
d->chancount = d->playcount = d->reccount = 0;
d->maxchans = numplay + numrec;
sz = (numplay + numrec) * sizeof(pcm_channel *);
sz = (numplay + numrec) * sizeof(struct pcm_channel *);
if (sz > 0) {
d->aplay = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
d->aplay = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
if (!d->aplay) goto no;
bzero(d->aplay, sz);
d->arec = (pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
d->arec = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_NOWAIT);
if (!d->arec) goto no;
bzero(d->arec, sz);
@ -361,25 +362,21 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
d->ref = (int *)malloc(sz, M_DEVBUF, M_NOWAIT);
if (!d->ref) goto no;
bzero(d->ref, sz);
d->atype = (int *)malloc(sz, M_DEVBUF, M_NOWAIT);
if (!d->atype) goto no;
bzero(d->atype, sz);
}
if (numplay > 0) {
d->play = (pcm_channel *)malloc(numplay * sizeof(pcm_channel),
d->play = (struct pcm_channel *)malloc(numplay * sizeof(struct pcm_channel),
M_DEVBUF, M_NOWAIT);
if (!d->play) goto no;
bzero(d->play, numplay * sizeof(pcm_channel));
bzero(d->play, numplay * sizeof(struct pcm_channel));
} else
d->play = NULL;
if (numrec > 0) {
d->rec = (pcm_channel *)malloc(numrec * sizeof(pcm_channel),
d->rec = (struct pcm_channel *)malloc(numrec * sizeof(struct pcm_channel),
M_DEVBUF, M_NOWAIT);
if (!d->rec) goto no;
bzero(d->rec, numrec * sizeof(pcm_channel));
bzero(d->rec, numrec * sizeof(struct pcm_channel));
} else
d->rec = NULL;
@ -397,9 +394,8 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
if (numplay == 0 || numrec == 0)
d->flags |= SD_F_SIMPLEX;
fkchan_setup(&d->fakechan);
chn_init(&d->fakechan, NULL, 0);
d->magic = MAGIC(unit); /* debugging... */
d->fakechan = fkchan_setup(dev);
chn_init(d->fakechan, NULL, 0);
return 0;
no:
@ -408,7 +404,6 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
if (d->arec) free(d->arec, M_DEVBUF);
if (d->rec) free(d->rec, M_DEVBUF);
if (d->ref) free(d->ref, M_DEVBUF);
if (d->atype) free(d->atype, M_DEVBUF);
return ENXIO;
}
@ -416,15 +411,9 @@ int
pcm_unregister(device_t dev)
{
int r, i, unit = device_get_unit(dev);
snddev_info *d = device_get_softc(dev);
struct snddev_info *d = device_get_softc(dev);
dev_t pdev;
#ifdef SND_DYNSYSCTL
sysctl_remove_oid(d->sysctl_tree_top, 1, 1);
d->sysctl_tree_top = NULL;
sysctl_ctx_free(&d->sysctl_tree);
#endif
r = 0;
for (i = 0; i < d->chancount; i++)
if (d->ref[i]) r = EBUSY;
@ -437,6 +426,11 @@ pcm_unregister(device_t dev)
return EBUSY;
}
#ifdef SND_DYNSYSCTL
d->sysctl_tree_top = NULL;
sysctl_ctx_free(&d->sysctl_tree);
#endif
pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0));
destroy_dev(pdev);
mixer_uninit(dev);
@ -445,17 +439,15 @@ pcm_unregister(device_t dev)
pcm_killchan(dev, PCMDIR_PLAY);
while (d->reccount > 0)
pcm_killchan(dev, PCMDIR_REC);
d->magic = 0;
if (d->aplay) free(d->aplay, M_DEVBUF);
if (d->play) free(d->play, M_DEVBUF);
if (d->arec) free(d->arec, M_DEVBUF);
if (d->rec) free(d->rec, M_DEVBUF);
if (d->ref) free(d->ref, M_DEVBUF);
if (d->atype) free(d->atype, M_DEVBUF);
chn_kill(&d->fakechan);
fkchan_kill(&d->fakechan);
chn_kill(d->fakechan);
fkchan_kill(d->fakechan);
#ifdef USING_DEVFS
pcm_makelinks(NULL);
@ -465,13 +457,13 @@ pcm_unregister(device_t dev)
/*
* a small utility function which, given a device number, returns
* a pointer to the associated snddev_info struct, and sets the unit
* a pointer to the associated struct snddev_info struct, and sets the unit
* number.
*/
static snddev_info *
static struct snddev_info *
get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
{
snddev_info *sc;
struct snddev_info *sc;
int u, d, c;
u = PCMUNIT(i_dev);
@ -484,7 +476,7 @@ get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
if (u < 0) return NULL;
sc = devclass_get_softc(pcm_devclass, u);
if (sc == NULL || sc->magic == 0) return NULL;
if (sc == NULL) return NULL;
switch(d) {
case SND_DEV_CTL: /* /dev/mixer handled by pcm */
@ -508,7 +500,7 @@ static int
sndopen(dev_t i_dev, int flags, int mode, struct proc *p)
{
int dev, unit, chan;
snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n",
unit, dev, flags, mode));
@ -537,7 +529,7 @@ static int
sndclose(dev_t i_dev, int flags, int mode, struct proc *p)
{
int dev, unit, chan;
snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
DEB(printf("close snd%d subdev %d\n", unit, dev));
@ -564,7 +556,7 @@ static int
sndread(dev_t i_dev, struct uio *buf, int flag)
{
int dev, unit, chan;
snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag));
switch(dev) {
@ -585,7 +577,7 @@ static int
sndwrite(dev_t i_dev, struct uio *buf, int flag)
{
int dev, unit, chan;
snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
@ -604,7 +596,7 @@ static int
sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
{
int dev, chan;
snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
if (d == NULL) return ENXIO;
@ -629,7 +621,7 @@ static int
sndpoll(dev_t i_dev, int events, struct proc *p)
{
int dev, chan;
snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events));
@ -665,7 +657,7 @@ static int
sndmmap(dev_t i_dev, vm_offset_t offset, int nprot)
{
int unit, dev, chan;
snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n",
d, dev, offset, nprot));
@ -688,7 +680,7 @@ status_init(char *buf, int size)
{
int i;
device_t dev;
snddev_info *d;
struct snddev_info *d;
snprintf(buf, size, "FreeBSD Audio Driver (newpcm) %s %s\n"
"Installed devices:\n", __DATE__, __TIME__);

View File

@ -87,13 +87,33 @@ struct isa_device { int dummy; };
#endif /* _OS_H_ */
#include <dev/sound/pcm/datatypes.h>
#include <dev/sound/pcm/channel.h>
struct pcm_channel;
struct pcm_feeder;
struct snd_dbuf;
struct snd_mixer;
#include <dev/sound/pcm/buffer.h>
#include <dev/sound/pcm/channel.h>
#include <dev/sound/pcm/feeder.h>
#include <dev/sound/pcm/mixer.h>
#include <dev/sound/pcm/dsp.h>
#define SND_STATUSLEN 64
/* descriptor of audio device */
struct snddev_info {
struct pcm_channel *play, *rec, **aplay, **arec, *fakechan;
int *ref;
unsigned playcount, reccount, chancount, maxchans;
struct snd_mixer *mixer;
unsigned flags;
void *devinfo;
device_t dev;
char status[SND_STATUSLEN];
struct sysctl_ctx_list sysctl_tree;
struct sysctl_oid *sysctl_tree_top;
struct mtx mutex;
};
#ifndef ISADMA_WRITE
#define ISADMA_WRITE B_WRITE
#define ISADMA_READ B_READ
@ -127,8 +147,8 @@ struct isa_device { int dummy; };
#define AFMT_SIGNED (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)
#define AFMT_BIGENDIAN (AFMT_S16_BE | AFMT_U16_BE)
int fkchan_setup(pcm_channel *c);
int fkchan_kill(pcm_channel *c);
struct pcm_channel *fkchan_setup(device_t dev);
int fkchan_kill(struct pcm_channel *c);
/*
* Minor numbers for the sound driver.