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.
This commit is contained in:
Cameron Grant 2000-08-20 22:18:56 +00:00
parent 3f54a085a6
commit 513693be6c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=64881
23 changed files with 704 additions and 303 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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 mss_caps = {4000, 48000, mss_fmt, 0};
static pcmchan_caps guspnp_caps = {
4000, 48000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE | AFMT_A_LAW,
AFMT_STEREO | AFMT_S16_LE
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 guspnp_caps = {4000, 48000, guspnp_fmt, 0};
static pcmchan_caps opti931_caps = {
4000, 48000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE
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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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_playcaps = {4000, 48000, au_playfmt, 0};
static pcmchan_caps au_reccaps = {
4000, 48000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE
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,

View file

@ -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 pcmchan_caps csa_reccaps = {
11025, 48000,
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_STEREO | AFMT_S16_LE
AFMT_S16_BE,
AFMT_STEREO | AFMT_S16_BE,
0
};
static 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 pcm_channel csa_chantemplate = {
csachan_init,

View file

@ -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_reccaps = {4000, 48000, ds_recfmt, 0};
static pcmchan_caps ds_playcaps = {
4000, 96000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE
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,

View file

@ -154,18 +154,38 @@ static void emu_wr(struct sc_info *, int, u_int32_t, int);
/* -------------------------------------------------------------------- */
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},
static u_int32_t emu_rfmt_ac97[] = {
AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE,
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_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, emu_rfmt_ac97, 0},
{8000, 8000, emu_rfmt_mic, 0},
{48000, 48000, emu_rfmt_efx, 0},
};
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,

View file

@ -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_playcaps = {4000, 48000, es_playfmt, 0};
static pcmchan_caps es_reccaps = {
4000, 48000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE
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,

View file

@ -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,

View file

@ -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,

View file

@ -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_reccaps = {4000, 48000, tr_recfmt, 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 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,

View file

@ -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_playcaps = {4000, 48000, via_playfmt, 0};
static pcmchan_caps via_reccaps = {
4000, 48000,
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
AFMT_STEREO | AFMT_S16_LE
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,

View file

@ -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)
@ -1181,6 +1191,18 @@ chn_setspeed(pcm_channel *c, int speed)
return 0;
}
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)
{
@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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 */

View file

@ -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,

View file

@ -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 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, NULL, NULL, feed_table, ulaw_to_u8 };
{ "ulawtou8", 0, desc_ulawtou8, NULL, NULL, feed_table, ulaw_to_u8 };
SYSINIT(feeder_ulawtou8, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, feeder_register, &feeder_ulawtou8);
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, NULL, NULL, feed_table, u8_to_ulaw };
{ "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 fmtspec {
int stereo;
int sign;
int bit16;
int bigendian;
int ulaw;
int bad;
};
struct fmtcvt {
pcm_feeder *f;
struct fmtspec ispec, ospec;
};
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;
SLIST_FOREACH(fte, &feedertab, link) {
if ((fte->desc != NULL) && cmpdesc(desc, fte->desc))
return fte->feeder;
}
return NULL;
}
static int
cmpspec(struct fmtspec *x, struct fmtspec *y)
pcm_feeder *
feeder_getroot()
{
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;
}
struct feedertab_entry *fte;
static int
cvtapply(pcm_channel *c, struct fmtcvt *cvt, struct fmtspec *s)
{
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;
SLIST_FOREACH(fte, &feedertab, link) {
if (fte->desc == NULL)
return fte->feeder;
}
return NULL;
}
int
chn_feedchain(pcm_channel *c)
{
int i, chosen, iter;
u_int32_t mask;
struct fmtspec s, t;
struct fmtcvt *e;
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;
}
static int
chn_addfeeder(pcm_channel *c, pcm_feeder *f)
{
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;
}
static int
chn_removefeeder(pcm_channel *c)
{
pcm_feeder *f;
if (c->feeder == &feeder_root) return -1;
if (c->feeder->source == NULL)
return -1;
f = c->feeder->source;
if (c->feeder->free) c->feeder->free(c->feeder);
if (c->feeder->free)
c->feeder->free(c->feeder);
free(c->feeder, M_DEVBUF);
c->feeder = f;
return 0;
}
static int
chainok(pcm_feeder *test, pcm_feeder *stop)
{
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 pcm_feeder *
feeder_fmtchain(u_int32_t *to, pcm_feeder *source, pcm_feeder *stop, int maxdepth)
{
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;
}

View file

@ -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);

View file

@ -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>