summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2000-08-20 22:18:56 +0000
committercg <cg@FreeBSD.org>2000-08-20 22:18:56 +0000
commitcc65486f22393469327f3952efc2526af719e4a2 (patch)
treef4dad15d15847c43242bb2f8e08bd8143dae99e5
parentb648921accec69a7e5c83e915ded3037cbca7f3d (diff)
downloadFreeBSD-src-cc65486f22393469327f3952efc2526af719e4a2.zip
FreeBSD-src-cc65486f22393469327f3952efc2526af719e4a2.tar.gz
rework feeder sytem to allow feeders in klds
modify driver capability reporting format to list every audio format seperately- required for above and because we could not previously indicate that mono was unsupported. there should be no functional impact.
-rw-r--r--sys/dev/sound/isa/ad1816.c16
-rw-r--r--sys/dev/sound/isa/ess.c32
-rw-r--r--sys/dev/sound/isa/mss.c43
-rw-r--r--sys/dev/sound/isa/sb.c51
-rw-r--r--sys/dev/sound/isa/sb16.c51
-rw-r--r--sys/dev/sound/isa/sb8.c51
-rw-r--r--sys/dev/sound/pci/aureal.c24
-rw-r--r--sys/dev/sound/pci/csapcm.c22
-rw-r--r--sys/dev/sound/pci/ds1.c28
-rw-r--r--sys/dev/sound/pci/emu10k1.c34
-rw-r--r--sys/dev/sound/pci/es137x.c24
-rw-r--r--sys/dev/sound/pci/neomagic.c11
-rw-r--r--sys/dev/sound/pci/solo.c30
-rw-r--r--sys/dev/sound/pci/t4dwave.c32
-rw-r--r--sys/dev/sound/pci/via82c686.c24
-rw-r--r--sys/dev/sound/pcm/channel.c53
-rw-r--r--sys/dev/sound/pcm/channel.h6
-rw-r--r--sys/dev/sound/pcm/datatypes.h19
-rw-r--r--sys/dev/sound/pcm/dsp.c6
-rw-r--r--sys/dev/sound/pcm/fake.c18
-rw-r--r--sys/dev/sound/pcm/feeder.c397
-rw-r--r--sys/dev/sound/pcm/feeder.h36
-rw-r--r--sys/dev/sound/pcm/sound.h1
23 files changed, 705 insertions, 304 deletions
diff --git a/sys/dev/sound/isa/ad1816.c b/sys/dev/sound/isa/ad1816.c
index a041ba9..ec7a61e 100644
--- a/sys/dev/sound/isa/ad1816.c
+++ b/sys/dev/sound/isa/ad1816.c
@@ -85,12 +85,20 @@ static int ad1816chan_trigger(void *data, int go);
static int ad1816chan_getptr(void *data);
static pcmchan_caps *ad1816chan_getcaps(void *data);
-static pcmchan_caps ad1816_caps = {
- 4000, 55200,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t ad1816_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_MU_LAW,
+ AFMT_STEREO | AFMT_MU_LAW,
+ AFMT_A_LAW,
+ AFMT_STEREO | AFMT_A_LAW,
+ 0
};
+static pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0};
+
static pcm_channel ad1816_chantemplate = {
ad1816chan_init,
ad1816chan_setdir,
diff --git a/sys/dev/sound/isa/ess.c b/sys/dev/sound/isa/ess.c
index 709549b..2252cd9 100644
--- a/sys/dev/sound/isa/ess.c
+++ b/sys/dev/sound/isa/ess.c
@@ -55,18 +55,34 @@ static int esschan_trigger(void *data, int go);
static int esschan_getptr(void *data);
static pcmchan_caps *esschan_getcaps(void *data);
-static pcmchan_caps ess_playcaps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t ess_pfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
-static pcmchan_caps ess_reccaps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps ess_playcaps = {5000, 49000, ess_pfmt, 0};
+
+static u_int32_t ess_rfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
+static pcmchan_caps ess_reccaps = {5000, 49000, ess_rfmt, 0};
+
static pcm_channel ess_chantemplate = {
esschan_init,
esschan_setdir,
diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c
index 5240938..71f9dd5 100644
--- a/sys/dev/sound/isa/mss.c
+++ b/sys/dev/sound/isa/mss.c
@@ -136,23 +136,38 @@ static int msschan_trigger(void *data, int go);
static int msschan_getptr(void *data);
static pcmchan_caps *msschan_getcaps(void *data);
-static pcmchan_caps mss_caps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t mss_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_MU_LAW,
+ AFMT_STEREO | AFMT_MU_LAW,
+ AFMT_A_LAW,
+ AFMT_STEREO | AFMT_A_LAW,
+ 0
};
-
-static pcmchan_caps guspnp_caps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE | AFMT_A_LAW,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps mss_caps = {4000, 48000, mss_fmt, 0};
+
+static u_int32_t guspnp_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_A_LAW,
+ AFMT_STEREO | AFMT_A_LAW,
+ 0
};
-
-static pcmchan_caps opti931_caps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps guspnp_caps = {4000, 48000, guspnp_fmt, 0};
+
+static u_int32_t opti931_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps opti931_caps = {4000, 48000, opti931_fmt, 0};
static pcm_channel mss_chantemplate = {
msschan_init,
diff --git a/sys/dev/sound/isa/sb.c b/sys/dev/sound/isa/sb.c
index f984d5c..d975311 100644
--- a/sys/dev/sound/isa/sb.c
+++ b/sys/dev/sound/isa/sb.c
@@ -49,47 +49,54 @@ static int sbchan_trigger(void *data, int go);
static int sbchan_getptr(void *data);
static pcmchan_caps *sbchan_getcaps(void *data);
-static pcmchan_caps sb_playcaps = {
- 4000, 22050,
+static u_int32_t sb_playfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_playcaps = {4000, 22050, sb_playfmt, 0};
-static pcmchan_caps sb_reccaps = {
- 4000, 13000,
+static u_int32_t sb_recfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_reccaps = {4000, 13000, sb_recfmt, 0};
-static pcmchan_caps sbpro_playcaps = {
- 4000, 45000,
+static u_int32_t sbpro_playfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_playcaps = {4000, 45000, sbpro_playfmt, 0};
-static pcmchan_caps sbpro_reccaps = {
- 4000, 15000,
+static u_int32_t sbpro_recfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_reccaps = {4000, 15000, sbpro_recfmt, 0};
-static pcmchan_caps sb16_hcaps = {
- 5000, 45000,
+static u_int32_t sb16_hfmt[] = {
+ AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+ 0
};
+static pcmchan_caps sb16_hcaps = {5000, 45000, sb16_hfmt, 0};
-static pcmchan_caps sb16_lcaps = {
- 5000, 45000,
+static u_int32_t sb16_lfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sb16_lcaps = {5000, 45000, sb16_lfmt, 0};
-static pcmchan_caps sb16x_caps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t sb16x_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
static pcm_channel sb_chantemplate = {
sbchan_init,
diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c
index f984d5c..d975311 100644
--- a/sys/dev/sound/isa/sb16.c
+++ b/sys/dev/sound/isa/sb16.c
@@ -49,47 +49,54 @@ static int sbchan_trigger(void *data, int go);
static int sbchan_getptr(void *data);
static pcmchan_caps *sbchan_getcaps(void *data);
-static pcmchan_caps sb_playcaps = {
- 4000, 22050,
+static u_int32_t sb_playfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_playcaps = {4000, 22050, sb_playfmt, 0};
-static pcmchan_caps sb_reccaps = {
- 4000, 13000,
+static u_int32_t sb_recfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_reccaps = {4000, 13000, sb_recfmt, 0};
-static pcmchan_caps sbpro_playcaps = {
- 4000, 45000,
+static u_int32_t sbpro_playfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_playcaps = {4000, 45000, sbpro_playfmt, 0};
-static pcmchan_caps sbpro_reccaps = {
- 4000, 15000,
+static u_int32_t sbpro_recfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_reccaps = {4000, 15000, sbpro_recfmt, 0};
-static pcmchan_caps sb16_hcaps = {
- 5000, 45000,
+static u_int32_t sb16_hfmt[] = {
+ AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+ 0
};
+static pcmchan_caps sb16_hcaps = {5000, 45000, sb16_hfmt, 0};
-static pcmchan_caps sb16_lcaps = {
- 5000, 45000,
+static u_int32_t sb16_lfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sb16_lcaps = {5000, 45000, sb16_lfmt, 0};
-static pcmchan_caps sb16x_caps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t sb16x_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
static pcm_channel sb_chantemplate = {
sbchan_init,
diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c
index f984d5c..d975311 100644
--- a/sys/dev/sound/isa/sb8.c
+++ b/sys/dev/sound/isa/sb8.c
@@ -49,47 +49,54 @@ static int sbchan_trigger(void *data, int go);
static int sbchan_getptr(void *data);
static pcmchan_caps *sbchan_getcaps(void *data);
-static pcmchan_caps sb_playcaps = {
- 4000, 22050,
+static u_int32_t sb_playfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_playcaps = {4000, 22050, sb_playfmt, 0};
-static pcmchan_caps sb_reccaps = {
- 4000, 13000,
+static u_int32_t sb_recfmt[] = {
AFMT_U8,
- AFMT_U8
+ 0
};
+static pcmchan_caps sb_reccaps = {4000, 13000, sb_recfmt, 0};
-static pcmchan_caps sbpro_playcaps = {
- 4000, 45000,
+static u_int32_t sbpro_playfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_playcaps = {4000, 45000, sbpro_playfmt, 0};
-static pcmchan_caps sbpro_reccaps = {
- 4000, 15000,
+static u_int32_t sbpro_recfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sbpro_reccaps = {4000, 15000, sbpro_recfmt, 0};
-static pcmchan_caps sb16_hcaps = {
- 5000, 45000,
+static u_int32_t sb16_hfmt[] = {
+ AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+ 0
};
+static pcmchan_caps sb16_hcaps = {5000, 45000, sb16_hfmt, 0};
-static pcmchan_caps sb16_lcaps = {
- 5000, 45000,
+static u_int32_t sb16_lfmt[] = {
+ AFMT_U8,
AFMT_STEREO | AFMT_U8,
- AFMT_STEREO | AFMT_U8
+ 0
};
+static pcmchan_caps sb16_lcaps = {5000, 45000, sb16_lfmt, 0};
-static pcmchan_caps sb16x_caps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t sb16x_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
static pcm_channel sb_chantemplate = {
sbchan_init,
diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c
index e97b689..5b5e47c 100644
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -46,17 +46,23 @@ static int auchan_trigger(void *data, int go);
static int auchan_getptr(void *data);
static pcmchan_caps *auchan_getcaps(void *data);
-static pcmchan_caps au_playcaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t au_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
-
-static pcmchan_caps au_reccaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0};
+
+static u_int32_t au_recfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0};
static pcm_channel au_chantemplate = {
auchan_init,
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index 6eb67c4..f0ea0a3 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -96,17 +96,25 @@ static int csachan_trigger(void *data, int go);
static int csachan_getptr(void *data);
static pcmchan_caps *csachan_getcaps(void *data);
-static pcmchan_caps csa_playcaps = {
- 8000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t csa_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_S16_BE,
+ AFMT_STEREO | AFMT_S16_BE,
+ 0
};
+static pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0};
-static pcmchan_caps csa_reccaps = {
- 11025, 48000,
+static u_int32_t csa_recfmt[] = {
+ AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+ 0
};
+static pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
static pcm_channel csa_chantemplate = {
csachan_init,
diff --git a/sys/dev/sound/pci/ds1.c b/sys/dev/sound/pci/ds1.c
index 07b0918..6932ee0 100644
--- a/sys/dev/sound/pci/ds1.c
+++ b/sys/dev/sound/pci/ds1.c
@@ -184,17 +184,27 @@ static void ds_wr(struct sc_info *, int, u_int32_t, int);
/* -------------------------------------------------------------------- */
-static pcmchan_caps ds_reccaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t ds_recfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
-
-static pcmchan_caps ds_playcaps = {
- 4000, 96000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
+
+static u_int32_t ds_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
static pcm_channel ds_pchantemplate = {
ds1pchan_init,
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c
index d31b21c..584c2a7 100644
--- a/sys/dev/sound/pci/emu10k1.c
+++ b/sys/dev/sound/pci/emu10k1.c
@@ -154,18 +154,38 @@ static void emu_wr(struct sc_info *, int, u_int32_t, int);
/* -------------------------------------------------------------------- */
+static u_int32_t emu_rfmt_ac97[] = {
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
+};
+
+static u_int32_t emu_rfmt_mic[] = {
+ AFMT_U8,
+ 0
+};
+
+static u_int32_t emu_rfmt_efx[] = {
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
+};
+
static pcmchan_caps emu_reccaps[3] = {
- {8000, 48000, AFMT_STEREO | AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE},
- {8000, 8000, AFMT_U8, AFMT_U8},
- {48000, 48000, AFMT_STEREO | AFMT_S16_LE, AFMT_STEREO | AFMT_S16_LE},
+ {8000, 48000, emu_rfmt_ac97, 0},
+ {8000, 8000, emu_rfmt_mic, 0},
+ {48000, 48000, emu_rfmt_efx, 0},
};
-static pcmchan_caps emu_playcaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t emu_pfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
+
static pcm_channel emu_chantemplate = {
emupchan_init,
emupchan_setdir,
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index 0664dbc..b4ce4da 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -122,17 +122,23 @@ static int eschan_trigger(void *data, int go);
static int eschan_getptr(void *data);
static pcmchan_caps *eschan_getcaps(void *data);
-static pcmchan_caps es_playcaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t es_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
-
-static pcmchan_caps es_reccaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps es_playcaps = {4000, 48000, es_playfmt, 0};
+
+static u_int32_t es_recfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps es_reccaps = {4000, 48000, es_recfmt, 0};
static pcm_channel es1370_chantemplate = {
eschan_init,
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 90006b7..f7a864f 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -125,11 +125,14 @@ static int samplerates[9] = {
/* -------------------------------------------------------------------- */
-static pcmchan_caps nm_caps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t nm_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
+static pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0};
static pcm_channel nm_chantemplate = {
nmchan_init,
diff --git a/sys/dev/sound/pci/solo.c b/sys/dev/sound/pci/solo.c
index 8c1f7bb..cd69868 100644
--- a/sys/dev/sound/pci/solo.c
+++ b/sys/dev/sound/pci/solo.c
@@ -52,20 +52,34 @@ static int esschan_trigger(void *data, int go);
static int esschan_getptr(void *data);
static pcmchan_caps *esschan_getcaps(void *data);
-static pcmchan_caps ess_playcaps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t ess_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
+static pcmchan_caps ess_playcaps = {5000, 49000, ess_playfmt, 0};
/*
* Recording output is byte-swapped
*/
-static pcmchan_caps ess_reccaps = {
- 5000, 49000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_U16_BE | AFMT_S16_BE,
- AFMT_STEREO | AFMT_S16_BE
+static u_int32_t ess_recfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_BE,
+ AFMT_STEREO | AFMT_S16_BE,
+ AFMT_U16_BE,
+ AFMT_STEREO | AFMT_U16_BE,
+ 0
};
+static pcmchan_caps ess_reccaps = {5000, 49000, ess_recfmt, 0};
static pcm_channel ess_chantemplate = {
esschan_init,
diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c
index 01c6220..83b38aa 100644
--- a/sys/dev/sound/pci/t4dwave.c
+++ b/sys/dev/sound/pci/t4dwave.c
@@ -115,17 +115,31 @@ static void tr_stopch(struct tr_info *, char);
/* -------------------------------------------------------------------- */
-static pcmchan_caps tr_reccaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t tr_recfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
-
-static pcmchan_caps tr_playcaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
+
+static u_int32_t tr_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ 0
};
+static pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
static pcm_channel tr_chantemplate = {
trchan_init,
diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c
index 98ca7bf..5c9c6c5 100644
--- a/sys/dev/sound/pci/via82c686.c
+++ b/sys/dev/sound/pci/via82c686.c
@@ -85,17 +85,23 @@ static int viachan_trigger(void *data, int go);
static int viachan_getptr(void *data);
static pcmchan_caps *viachan_getcaps(void *data);
-static pcmchan_caps via_playcaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+static u_int32_t via_playfmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ 0
};
-
-static pcmchan_caps via_reccaps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
- AFMT_STEREO | AFMT_S16_LE
+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 pcm_channel via_chantemplate = {
viachan_init,
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index cd40903..d461ba3 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1127,8 +1127,18 @@ chn_init(pcm_channel *c, void *devinfo, int dir)
snd_dbuf *bs = &c->buffer2nd;
/* Initialize the hardware and DMA buffer first. */
+ c->feeder = malloc(sizeof(*(c->feeder)), M_DEVBUF, M_NOWAIT);
+ *(c->feeder) = *feeder_getroot();
+ c->feederdesc = malloc(sizeof(*(c->feeder)), M_DEVBUF, M_NOWAIT);
+ c->feederdesc->type = FEEDER_ROOT;
+ c->feederdesc->in = 0;
+ c->feederdesc->out = 0;
+ c->feederdesc->flags = 0;
+ c->feederdesc->idx = 0;
+ c->feeder->desc = c->feederdesc;
+ c->feeder->source = NULL;
+
c->flags = 0;
- c->feeder = &feeder_root;
c->buffer.chan = -1;
c->devinfo = c->init(devinfo, &c->buffer, c, dir);
if (c->devinfo == NULL || c->buffer.bufsize == 0)
@@ -1182,6 +1192,18 @@ chn_setspeed(pcm_channel *c, int speed)
}
int
+fmtvalid(u_int32_t fmt, u_int32_t *fmtlist)
+{
+ int i;
+
+ for (i = 0; fmtlist[i]; i++)
+ if (fmt == fmtlist[i])
+ return 1;
+
+ return 0;
+}
+
+int
chn_setformat(pcm_channel *c, u_int32_t fmt)
{
snd_dbuf *b = &c->buffer;
@@ -1189,10 +1211,17 @@ chn_setformat(pcm_channel *c, u_int32_t fmt)
u_int32_t hwfmt;
if (CANCHANGE(c)) {
+ while (chn_removefeeder(c) == 0);
c->format = fmt;
- hwfmt = chn_feedchain(c);
- if ((c->flags & CHN_F_MAPPED) && c->format != hwfmt)
- return EINVAL;
+ c->feederdesc->out = c->format;
+ hwfmt = c->format;
+ if (!fmtvalid(hwfmt, chn_getcaps(c)->fmtlist)) {
+ if (c->flags & CHN_F_MAPPED)
+ return EINVAL;
+ hwfmt = chn_feedchain(c, chn_getcaps(c)->fmtlist);
+ if (hwfmt == 0)
+ return EINVAL;
+ }
b->fmt = hwfmt;
bs->fmt = hwfmt;
chn_resetbuf(c);
@@ -1287,3 +1316,19 @@ chn_getcaps(pcm_channel *c)
{
return c->getcaps(c->devinfo);
}
+
+u_int32_t
+chn_getformats(pcm_channel *c)
+{
+ u_int32_t *fmtlist, fmts;
+ int i;
+
+ fmtlist = chn_getcaps(c)->fmtlist;
+ fmts = 0;
+ for (i = 0; fmtlist[i]; i++)
+ fmts |= fmtlist[i];
+
+ return fmts;
+}
+
+
diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
index 23e31df..3f6a359 100644
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -43,6 +43,7 @@ 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_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat);
void chn_resetbuf(pcm_channel *c);
@@ -52,11 +53,10 @@ int chn_wrfeed(pcm_channel *c);
int chn_rdfeed(pcm_channel *c);
int chn_abort(pcm_channel *c);
+int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
+
void buf_isadma(snd_dbuf *b, int go);
int buf_isadmaptr(snd_dbuf *b);
-int chn_feedchain(pcm_channel *c);
-
-extern pcm_feeder feeder_root;
#define PCMDIR_PLAY 1
#define PCMDIR_REC -1
diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h
index 716c21b..6f831e5 100644
--- a/sys/dev/sound/pcm/datatypes.h
+++ b/sys/dev/sound/pcm/datatypes.h
@@ -78,9 +78,24 @@ typedef int (pcmfeed_free_t)(pcm_feeder *feeder);
typedef int (pcmfeed_feed_t)(pcm_feeder *feeder, pcm_channel *c, u_int8_t *buffer,
u_int32_t count, struct uio *stream);
+#define FEEDER_ROOT 1
+#define FEEDER_FMT 2
+#define FEEDER_RATE 3
+#define FEEDER_FILTER 4
+
+struct pcm_feederdesc {
+ u_int32_t type;
+ u_int32_t in, out;
+ u_int32_t flags;
+ int idx;
+};
+
+#define MAXFEEDERS 256
+
struct _pcm_feeder {
char name[16];
int align;
+ struct pcm_feederdesc *desc;
pcmfeed_init_t *init;
pcmfeed_free_t *free;
pcmfeed_feed_t *feed;
@@ -90,7 +105,8 @@ struct _pcm_feeder {
struct _pcmchan_caps {
u_int32_t minspeed, maxspeed;
- u_int32_t formats, bestfmt;
+ u_int32_t *fmtlist;
+ u_int32_t caps;
};
typedef void *(pcmchan_init_t)(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
@@ -112,6 +128,7 @@ struct _pcm_channel {
pcmchan_getptr_t *getptr;
pcmchan_getcaps_t *getcaps;
pcm_feeder *feeder;
+ struct pcm_feederdesc *feederdesc;
u_int32_t align;
int volume;
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 19bfd96..9bd8bc5 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -283,8 +283,8 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
p->bufsize = min(rdch? rdch->buffer2nd.bufsize : 1000000,
wrch? wrch->buffer2nd.bufsize : 1000000);
/* XXX bad on sb16 */
- p->formats = (rcaps? rcaps->formats : 0xffffffff) &
- (pcaps? pcaps->formats : 0xffffffff);
+ p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
+ (wrch? chn_getformats(wrch) : 0xffffffff);
if (rdch && wrch)
p->formats |= (d->flags & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX;
p->mixers = 1; /* default: one mixer */
@@ -406,7 +406,7 @@ dsp_ioctl(snddev_info *d, int chan, u_long cmd, caddr_t arg)
break;
case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */
- *arg_i = wrch? chn_getcaps(wrch)->formats : chn_getcaps(rdch)->formats;
+ *arg_i = wrch? chn_getformats(wrch) : chn_getformats(rdch);
break ;
case SNDCTL_DSP_SETFMT: /* sets _one_ format */
diff --git a/sys/dev/sound/pcm/fake.c b/sys/dev/sound/pcm/fake.c
index d3368c0..9cdb1f6 100644
--- a/sys/dev/sound/pcm/fake.c
+++ b/sys/dev/sound/pcm/fake.c
@@ -38,10 +38,22 @@ static int fkchan_trigger(void *data, int go);
static int fkchan_getptr(void *data);
static pcmchan_caps *fkchan_getcaps(void *data);
-static pcmchan_caps fk_caps = {
- 4000, 48000,
- AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE
+static u_int32_t fk_fmt[] = {
+ AFMT_U8,
+ AFMT_STEREO | AFMT_U8,
+ AFMT_S8,
+ AFMT_STEREO | AFMT_S8,
+ AFMT_S16_LE,
+ AFMT_STEREO | AFMT_S16_LE,
+ AFMT_U16_LE,
+ AFMT_STEREO | AFMT_U16_LE,
+ AFMT_S16_BE,
+ AFMT_STEREO | AFMT_S16_BE,
+ AFMT_U16_BE,
+ AFMT_STEREO | AFMT_U16_BE,
+ 0
};
+static pcmchan_caps fk_caps = {4000, 48000, fk_fmt, 0};
static pcm_channel fk_chantemplate = {
fkchan_init,
diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c
index 5eaf89a..91049e6 100644
--- a/sys/dev/sound/pcm/feeder.c
+++ b/sys/dev/sound/pcm/feeder.c
@@ -28,9 +28,6 @@
#include <dev/sound/pcm/sound.h>
-static int chn_addfeeder(pcm_channel *c, pcm_feeder *f);
-static int chn_removefeeder(pcm_channel *c);
-
#define FEEDBUFSZ 8192
static unsigned char ulaw_to_u8[] = {
@@ -103,15 +100,65 @@ static unsigned char u8_to_ulaw[] = {
129, 129, 129, 129, 128, 128, 128, 128,
};
+struct feedertab_entry {
+ SLIST_ENTRY(feedertab_entry) link;
+ pcm_feeder *feeder;
+ struct pcm_feederdesc *desc;
+
+ int idx;
+};
+static SLIST_HEAD(, feedertab_entry) feedertab;
+
+/*****************************************************************************/
+
+void
+feeder_register(void *p)
+{
+ pcm_feeder *f = p;
+ struct feedertab_entry *fte;
+ static int feedercnt = 0;
+ int i;
+
+ if (feedercnt == 0) {
+ if (f->desc)
+ panic("FIRST FEEDER NOT ROOT: %s\n", f->name);
+ SLIST_INIT(&feedertab);
+ fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT);
+ fte->feeder = f;
+ fte->desc = NULL;
+ fte->idx = feedercnt;
+ SLIST_INSERT_HEAD(&feedertab, fte, link);
+ feedercnt++;
+ return;
+ }
+ /* printf("installing feeder: %s\n", f->name); */
+
+ i = 0;
+ while ((feedercnt < MAXFEEDERS) && (f->desc[i].type > 0)) {
+ fte = malloc(sizeof(*fte), M_DEVBUF, M_NOWAIT);
+ fte->feeder = f;
+ fte->desc = &f->desc[i];
+ fte->idx = feedercnt;
+ fte->desc->idx = feedercnt;
+ SLIST_INSERT_HEAD(&feedertab, fte, link);
+ i++;
+ }
+ feedercnt++;
+ if (feedercnt >= MAXFEEDERS)
+ printf("MAXFEEDERS exceeded\n");
+}
+
/*****************************************************************************/
static int
feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count, struct uio *stream)
{
- int ret, c = 0, s;
+ int ret, s;
+
KASSERT(count, ("feed_root: count == 0"));
count &= ~((1 << ch->align) - 1);
KASSERT(count, ("feed_root: aligned count == 0"));
+
s = spltty();
count = min(count, stream->uio_resid);
if (count) {
@@ -119,16 +166,19 @@ feed_root(pcm_feeder *feeder, pcm_channel *ch, u_int8_t *buffer, u_int32_t count
KASSERT(ret == 0, ("feed_root: uiomove failed"));
}
splx(s);
- return c + count;
+
+ return count;
}
-pcm_feeder feeder_root = { "root", 0, NULL, NULL, feed_root };
+static pcm_feeder feeder_root = { "root", 0, NULL, NULL, NULL, feed_root };
+SYSINIT(feeder_root, SI_SUB_DRIVERS, SI_ORDER_FIRST, feeder_register, &feeder_root);
/*****************************************************************************/
static int
-feed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
+feed_8to16le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
{
int i, j, k;
+
k = f->source->feed(f->source, c, b, count / 2, stream);
j = k - 1;
i = j * 2 + 1;
@@ -138,7 +188,17 @@ feed_8to16(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct u
}
return k * 2;
}
-static pcm_feeder feeder_8to16 = { "8to16", 0, NULL, NULL, feed_8to16 };
+
+static struct pcm_feederdesc desc_8to16le[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_U16_LE, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S16_LE, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
+ {0},
+};
+static pcm_feeder feeder_8to16le =
+ { "8to16le", 0, desc_8to16le, NULL, NULL, feed_8to16le };
+SYSINIT(feeder_8to16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_8to16le);
/*****************************************************************************/
@@ -158,10 +218,11 @@ feed_16to8_free(pcm_feeder *f)
}
static int
-feed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
+feed_16leto8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
{
u_int32_t i = 0, toget = count * 2;
int j = 1, k;
+
k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
while (j < k) {
b[i++] = ((u_int8_t *)f->data)[j];
@@ -169,8 +230,17 @@ feed_16to8le(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct
}
return i;
}
-static pcm_feeder feeder_16to8le =
- { "16to8le", 1, feed_16to8_init, feed_16to8_free, feed_16to8le };
+
+static struct pcm_feederdesc desc_16leto8[] = {
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {0},
+};
+static pcm_feeder feeder_16leto8 =
+ { "16leto8", 1, desc_16leto8, feed_16to8_init, feed_16to8_free, feed_16leto8 };
+SYSINIT(feeder_16leto8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_16leto8);
/*****************************************************************************/
@@ -178,6 +248,7 @@ static int
feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
{
int i, j, k = f->source->feed(f->source, c, b, count / 2, stream);
+
j = k - 1;
i = j * 2 + 1;
while (i > 0 && j >= 0) {
@@ -187,8 +258,15 @@ feed_monotostereo8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count,
}
return k * 2;
}
+
+static struct pcm_feederdesc desc_monotostereo8[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_U8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_S8 | AFMT_STEREO, 0},
+ {0},
+};
static pcm_feeder feeder_monotostereo8 =
- { "monotostereo8", 0, NULL, NULL, feed_monotostereo8 };
+ { "monotostereo8", 0, desc_monotostereo8, NULL, NULL, feed_monotostereo8 };
+SYSINIT(feeder_monotostereo8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_monotostereo8);
/*****************************************************************************/
@@ -212,6 +290,7 @@ feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count,
{
u_int32_t i = 0, toget = count * 2;
int j = 0, k;
+
k = f->source->feed(f->source, c, f->data, min(toget, FEEDBUFSZ), stream);
while (j < k) {
b[i++] = ((u_int8_t *)f->data)[j];
@@ -219,9 +298,15 @@ feed_stereotomono8(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count,
}
return i;
}
+
+static struct pcm_feederdesc desc_stereotomono8[] = {
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_S8, 0},
+ {0},
+};
static pcm_feeder feeder_stereotomono8 =
- { "stereotomono8", 1, feed_stereotomono8_init, feed_stereotomono8_free,
- feed_stereotomono8 };
+ { "stereotomono8", 1, desc_stereotomono8, feed_stereotomono8_init, feed_stereotomono8_free, feed_stereotomono8 };
+SYSINIT(feeder_stereotomono8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_stereotomono8);
/*****************************************************************************/
@@ -230,6 +315,7 @@ feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct
{
u_int8_t t;
int i = 0, j = f->source->feed(f->source, c, b, count, stream);
+
while (i < j) {
t = b[i];
b[i] = b[i + 1];
@@ -238,7 +324,20 @@ feed_endian(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct
}
return i;
}
-static pcm_feeder feeder_endian = { "endian", -1, NULL, NULL, feed_endian };
+
+static struct pcm_feederdesc desc_endian[] = {
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_U16_BE, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_S16_BE, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_U16_BE, AFMT_U16_LE, 0},
+ {FEEDER_FMT, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_BE, AFMT_S16_LE, 0},
+ {FEEDER_FMT, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
+ {0},
+};
+static pcm_feeder feeder_endian = { "endian", -1, desc_endian, NULL, NULL, feed_endian };
+SYSINIT(feeder_endian, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_endian);
/*****************************************************************************/
@@ -247,16 +346,35 @@ feed_sign(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct ui
{
int i = 0, j = f->source->feed(f->source, c, b, count, stream);
int ssz = (int)f->data, ofs = ssz - 1;
+
while (i < j) {
b[i + ofs] ^= 0x80;
i += ssz;
}
return i;
}
+
+static struct pcm_feederdesc desc_sign8[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_S8, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S8, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_S8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {0},
+};
static pcm_feeder feeder_sign8 =
- { "sign8", 0, NULL, NULL, feed_sign, (void *)1 };
-static pcm_feeder feeder_sign16 =
- { "sign16", -1, NULL, NULL, feed_sign, (void *)2 };
+ { "sign8", 0, desc_sign8, NULL, NULL, feed_sign, (void *)1 };
+SYSINIT(feeder_sign8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign8);
+
+static struct pcm_feederdesc desc_sign16le[] = {
+ {FEEDER_FMT, AFMT_U16_LE, AFMT_S16_LE, 0},
+ {FEEDER_FMT, AFMT_U16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
+ {FEEDER_FMT, AFMT_S16_LE, AFMT_U16_LE, 0},
+ {FEEDER_FMT, AFMT_S16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
+ {0},
+};
+static pcm_feeder feeder_sign16le =
+ { "sign16le", -1, desc_sign16le, NULL, NULL, feed_sign, (void *)2 };
+SYSINIT(feeder_sign16le, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_sign16le);
/*****************************************************************************/
@@ -264,147 +382,172 @@ static int
feed_table(pcm_feeder *f, pcm_channel *c, u_int8_t *b, u_int32_t count, struct uio *stream)
{
int i = 0, j = f->source->feed(f->source, c, b, count, stream);
+
while (i < j) {
b[i] = ((u_int8_t *)f->data)[b[i]];
i++;
}
return i;
}
-static pcm_feeder feeder_ulawtou8 =
- { "ulawtou8", 0, NULL, NULL, feed_table, ulaw_to_u8 };
-static pcm_feeder feeder_u8toulaw =
- { "u8toulaw", 0, NULL, NULL, feed_table, u8_to_ulaw };
-/*****************************************************************************/
-
-struct fmtspec {
- int stereo;
- int sign;
- int bit16;
- int bigendian;
- int ulaw;
- int bad;
+static struct pcm_feederdesc desc_ulawtou8[] = {
+ {FEEDER_FMT, AFMT_MU_LAW, AFMT_U8, 0},
+ {FEEDER_FMT, AFMT_MU_LAW | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
+ {0},
};
+static pcm_feeder feeder_ulawtou8 =
+ { "ulawtou8", 0, desc_ulawtou8, NULL, NULL, feed_table, ulaw_to_u8 };
+SYSINIT(feeder_ulawtou8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_ulawtou8);
-struct fmtcvt {
- pcm_feeder *f;
- struct fmtspec ispec, ospec;
+static struct pcm_feederdesc desc_u8toulaw[] = {
+ {FEEDER_FMT, AFMT_U8, AFMT_MU_LAW, 0},
+ {FEEDER_FMT, AFMT_U8 | AFMT_STEREO, AFMT_MU_LAW | AFMT_STEREO, 0},
+ {0},
};
+static pcm_feeder feeder_u8toulaw =
+ { "u8toulaw", 0, desc_u8toulaw, NULL, NULL, feed_table, u8_to_ulaw };
+SYSINIT(feeder_u8toulaw, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_u8toulaw);
-struct fmtcvt cvttab[] = {
- {&feeder_ulawtou8, {-1, 0, 0, 0, 1}, {-1, 0, 0, 0, 0}},
- {&feeder_u8toulaw, {-1, 0, 0, 0, 0}, {-1, 0, 0, 0, 1}},
- {&feeder_sign8, {-1, 0, 0, 0, 0}, {-1, 1, 0, 0, 0}},
- {&feeder_sign8, {-1, 1, 0, 0, 0}, {-1, 0, 0, 0, 0}},
- {&feeder_monotostereo8, { 0, -1, 0, 0, -1}, { 1, -1, 0, 0, -1}},
- {&feeder_stereotomono8, { 1, -1, 0, 0, -1}, { 0, -1, 0, 0, -1}},
- {&feeder_sign16, {-1, 0, 1, 0, 0}, {-1, 1, 1, 0, 0}},
- {&feeder_sign16, {-1, 1, 1, 0, 0}, {-1, 0, 1, 0, 0}},
- {&feeder_8to16, {-1, -1, 0, 0, 0}, {-1, -1, 1, 0, 0}},
- {&feeder_16to8le, {-1, -1, 1, 0, 0}, {-1, -1, 0, 0, 0}},
- {&feeder_endian, {-1, -1, 1, 0, 0}, {-1, -1, 1, 1, 0}},
- {&feeder_endian, {-1, -1, 1, 1, 0}, {-1, -1, 1, 0, 0}},
-};
-#define FEEDERTABSZ (sizeof(cvttab) / sizeof(struct fmtcvt))
+/*****************************************************************************/
static int
-getspec(u_int32_t fmt, struct fmtspec *spec)
+cmpdesc(struct pcm_feederdesc *n, struct pcm_feederdesc *m)
{
- spec->stereo = (fmt & AFMT_STEREO)? 1 : 0;
- spec->sign = (fmt & AFMT_SIGNED)? 1 : 0;
- spec->bit16 = (fmt & AFMT_16BIT)? 1 : 0;
- spec->bigendian = (fmt & AFMT_BIGENDIAN)? 1 : 0;
- spec->ulaw = (fmt & AFMT_MU_LAW)? 1 : 0;
- spec->bad = (fmt & (AFMT_A_LAW | AFMT_MPEG))? 1 : 0;
- return 0;
+ return ((n->type == m->type) && (n->in == m->in) && (n->out == m->out) && (n->flags == m->flags));
}
-static int
-cmp(int x, int y)
+pcm_feeder *
+feeder_get(struct pcm_feederdesc *desc)
{
- return (x == -1 || x == y || y == -1)? 1 : 0;
-}
+ struct feedertab_entry *fte;
-static int
-cmpspec(struct fmtspec *x, struct fmtspec *y)
-{
- int i = 0;
- if (cmp(x->stereo, y->stereo)) i |= 0x01;
- if (cmp(x->sign, y->sign)) i |= 0x02;
- if (cmp(x->bit16, y->bit16)) i |= 0x04;
- if (cmp(x->bigendian, y->bigendian)) i |= 0x08;
- if (cmp(x->ulaw, y->ulaw)) i |= 0x10;
- return i;
+ SLIST_FOREACH(fte, &feedertab, link) {
+ if ((fte->desc != NULL) && cmpdesc(desc, fte->desc))
+ return fte->feeder;
+ }
+ return NULL;
}
-static int
-cvtapply(pcm_channel *c, struct fmtcvt *cvt, struct fmtspec *s)
+pcm_feeder *
+feeder_getroot()
{
- int i = cmpspec(s, &cvt->ospec);
- chn_addfeeder(c, cvt->f);
- if (cvt->ospec.stereo != -1) s->stereo = cvt->ospec.stereo;
- if (cvt->ospec.sign != -1) s->sign = cvt->ospec.sign;
- if (cvt->ospec.bit16 != -1) s->bit16 = cvt->ospec.bit16;
- if (cvt->ospec.bigendian != -1) s->bigendian = cvt->ospec.bigendian;
- if (cvt->ospec.ulaw != -1) s->ulaw = cvt->ospec.ulaw;
- return i;
+ struct feedertab_entry *fte;
+
+ SLIST_FOREACH(fte, &feedertab, link) {
+ if (fte->desc == NULL)
+ return fte->feeder;
+ }
+ return NULL;
}
int
-chn_feedchain(pcm_channel *c)
+chn_removefeeder(pcm_channel *c)
{
- int i, chosen, iter;
- u_int32_t mask;
- struct fmtspec s, t;
- struct fmtcvt *e;
+ pcm_feeder *f;
- while (chn_removefeeder(c) != -1);
- c->align = 0;
- if ((c->format & chn_getcaps(c)->formats) == c->format)
- return c->format;
- getspec(c->format, &s);
- if (s.bad) return -1;
- getspec(chn_getcaps(c)->bestfmt, &t);
- mask = (~cmpspec(&s, &t)) & 0x1f;
- iter = 0;
- do {
- if (mask == 0 || iter >= 8) break;
- chosen = -1;
- for (i = 0; i < FEEDERTABSZ && chosen == -1; i++) {
- e = &cvttab[i];
- if ((cmpspec(&s, &e->ispec) == 0x1f) &&
- ((~cmpspec(&e->ispec, &e->ospec)) & mask))
- chosen = i;
- }
- if (chosen != -1) mask &= cvtapply(c, &cvttab[chosen], &s);
- iter++;
- } while (chosen != -1);
- return (iter < 8)? chn_getcaps(c)->bestfmt : -1;
+ if (c->feeder->source == NULL)
+ return -1;
+ f = c->feeder->source;
+ if (c->feeder->free)
+ c->feeder->free(c->feeder);
+ free(c->feeder, M_DEVBUF);
+ c->feeder = f;
+ return 0;
}
static int
-chn_addfeeder(pcm_channel *c, pcm_feeder *f)
+chainok(pcm_feeder *test, pcm_feeder *stop)
{
- pcm_feeder *n;
- n = malloc(sizeof(pcm_feeder), M_DEVBUF, M_NOWAIT);
- *n = *f;
- n->source = c->feeder;
- c->feeder = n;
- if (n->init) n->init(n);
- if (n->align > 0) c->align += n->align;
- else if (n->align < 0 && c->align < -n->align) c->align -= n->align;
- return 0;
+ u_int32_t visited[MAXFEEDERS / 32];
+ u_int32_t idx, mask;
+
+ bzero(visited, sizeof(visited));
+ while (test && (test != stop)) {
+ idx = test->desc->idx;
+ if (idx < 0)
+ panic("bad idx %d", idx);
+ if (idx >= MAXFEEDERS)
+ panic("bad idx %d", idx);
+ mask = 1 << (idx & 31);
+ idx >>= 5;
+ if (visited[idx] & mask)
+ return 0;
+ visited[idx] |= mask;
+ test = test->source;
+ }
+ return 1;
}
-static int
-chn_removefeeder(pcm_channel *c)
+static pcm_feeder *
+feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth)
{
- pcm_feeder *f;
- if (c->feeder == &feeder_root) return -1;
- f = c->feeder->source;
- if (c->feeder->free) c->feeder->free(c->feeder);
- free(c->feeder, M_DEVBUF);
- c->feeder = f;
- return 0;
+ struct feedertab_entry *fte;
+ pcm_feeder *try, *ret;
+ struct pcm_feederdesc *trydesc;
+
+ /* printf("trying %s...\n", source->name); */
+ if (fmtvalid(source->desc->out, to)) {
+ /* printf("got it\n"); */
+ return source;
+ }
+
+ if (maxdepth < 0)
+ return NULL;
+
+ try = malloc(sizeof(*try), M_DEVBUF, M_NOWAIT);
+ trydesc = malloc(sizeof(*trydesc), M_DEVBUF, M_NOWAIT);
+ trydesc->type = FEEDER_FMT;
+ trydesc->in = source->desc->out;
+ trydesc->out = 0;
+ trydesc->flags = 0;
+ trydesc->idx = -1;
+
+ SLIST_FOREACH(fte, &feedertab, link) {
+ if ((fte->desc) && (fte->desc->in == source->desc->out)) {
+ *try = *(fte->feeder);
+ try->source = source;
+ try->desc = trydesc;
+ trydesc->out = fte->desc->out;
+ trydesc->idx = fte->idx;
+ ret = chainok(try, stop)? feeder_fmtchain(to, try, stop, maxdepth - 1) : NULL;
+ if (ret != NULL)
+ return ret;
+ }
+ }
+ free(try, M_DEVBUF);
+ free(trydesc, M_DEVBUF);
+ /* printf("giving up %s...\n", source->name); */
+ return NULL;
}
+u_int32_t
+chn_feedchain(pcm_channel *c, u_int32_t *to)
+{
+ pcm_feeder *try, *stop;
+ int max;
+
+ stop = c->feeder;
+ try = NULL;
+ max = 0;
+ while (try == NULL && max++ < 8)
+ try = feeder_fmtchain(to, c->feeder, stop, max);
+ if (try == NULL)
+ return 0;
+ c->feeder = try;
+ c->align = 0;
+ /* printf("chain: "); */
+ while (try && (try != stop)) {
+ /* printf("%s [%d]", try->name, try->desc->idx); */
+ /* if (try->source) */
+ /* printf(" -> "); */
+ if (try->init)
+ try->init(try);
+ if (try->align > 0)
+ c->align += try->align;
+ else if (try->align < 0 && c->align < -try->align)
+ c->align = -try->align;
+ try = try->source;
+ }
+ /* printf("%s [%d]", try->name, try->desc->idx); */
+ return c->feeder->desc->out;
+}
diff --git a/sys/dev/sound/pcm/feeder.h b/sys/dev/sound/pcm/feeder.h
new file mode 100644
index 0000000..b6890e6
--- /dev/null
+++ b/sys/dev/sound/pcm/feeder.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+void feeder_register(void *p);
+pcm_feeder *feeder_get(struct pcm_feederdesc *desc);
+pcm_feeder *feeder_getroot(void);
+
+u_int32_t chn_feedchain(pcm_channel *c, u_int32_t *to);
+int chn_removefeeder(pcm_channel *c);
+
+
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 90394ba..0e50926 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -81,6 +81,7 @@ struct isa_device { int dummy; };
#include <dev/sound/pcm/datatypes.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>
OpenPOWER on IntegriCloud