summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2009-11-03 07:57:25 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2009-11-03 07:57:25 +0000
commita8a5a97040b03c6f4a6574e157b537b21af2120b (patch)
tree6e4ea624f43d7b1abd00b1038d19271df4543f04 /sys
parent1901b7d0c3d82a18b22329057a7413dd9a4fa0a8 (diff)
rewrite supported audio parameter matching code
- easier to read/follow - if can't match desired parameters exactly, find closest match instead of returning an error. this is how most other audio drivers work. ok ratchov
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/uaudio.c231
1 files changed, 97 insertions, 134 deletions
diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c
index 8aa9409c391..9ea41f9a0af 100644
--- a/sys/dev/usb/uaudio.c
+++ b/sys/dev/usb/uaudio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uaudio.c,v 1.64 2009/10/17 07:10:37 jakemsr Exp $ */
+/* $OpenBSD: uaudio.c,v 1.65 2009/11/03 07:57:24 jakemsr Exp $ */
/* $NetBSD: uaudio.c,v 1.90 2004/10/29 17:12:53 kent Exp $ */
/*
@@ -78,6 +78,7 @@ int uaudiodebug = 0;
#define UAUDIO_NCHANBUFS 6 /* number of outstanding request */
#define UAUDIO_NFRAMES 10 /* ms of sound in each request */
+#define UAUDIO_MAX_ALTS 32 /* max alt settings allowed by driver */
#define MIX_MAX_CHAN 8
struct mixerctl {
@@ -293,13 +294,8 @@ int uaudio_query_encoding(void *, struct audio_encoding *);
void uaudio_get_minmax_rates
(int, const struct as_info *, const struct audio_params *,
int, int, int, u_long *, u_long *);
-int uaudio_match_alt_sub
- (int, const struct as_info *, const struct audio_params *,
- int, int, int, u_long);
-int uaudio_match_alt_chan
- (int, const struct as_info *, struct audio_params *, int, int, int);
-int uaudio_match_alt
- (int, const struct as_info *, struct audio_params *, int, int, int);
+int uaudio_match_alt_rate(void *, int, int);
+int uaudio_match_alt(void *, struct audio_params *, int, int, int);
int uaudio_set_params
(void *, int, int, struct audio_params *, struct audio_params *);
int uaudio_round_blocksize(void *, int);
@@ -1688,7 +1684,8 @@ uaudio_process_as(struct uaudio_softc *sc, const char *buf, int *offsp,
ai.edesc1 = epdesc1;
ai.asf1desc = asf1d;
ai.sc_busy = 0;
- uaudio_add_alt(sc, &ai);
+ if (sc->sc_nalts < UAUDIO_MAX_ALTS)
+ uaudio_add_alt(sc, &ai);
#ifdef UAUDIO_DEBUG
if (ai.attributes & UA_SED_FREQ_CONTROL)
DPRINTFN(1, ("uaudio_process_as: FREQ_CONTROL\n"));
@@ -2859,155 +2856,121 @@ uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize)
ch->curchanbuf = 0;
}
-void
-uaudio_get_minmax_rates(int nalts, const struct as_info *alts,
- const struct audio_params *p, int mode,
- int enc, int pre,
- u_long *min, u_long *max)
+int
+uaudio_match_alt_rate(void *addr, int alt, int rate)
{
+ struct uaudio_softc *sc = addr;
const struct usb_audio_streaming_type1_descriptor *a1d;
- int i, j;
+ int i, j, r;
- *min = ULONG_MAX;
- *max = 0;
- for (i = 0; i < nalts; i++) {
- a1d = alts[i].asf1desc;
- if (alts[i].sc_busy)
- continue;
- if (p->channels != a1d->bNrChannels)
- continue;
- if (pre != a1d->bBitResolution)
- continue;
- if (enc != alts[i].encoding)
- continue;
- if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
- continue;
- if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
- DPRINTFN(2,("uaudio_get_minmax_rates: cont %d-%d\n",
- UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
- if (UA_SAMP_LO(a1d) < *min)
- *min = UA_SAMP_LO(a1d);
- if (UA_SAMP_HI(a1d) > *max)
- *max = UA_SAMP_HI(a1d);
+ a1d = sc->sc_alts[alt].asf1desc;
+ if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
+ if ((UA_SAMP_LO(a1d) <= rate) &&
+ (UA_SAMP_HI(a1d) >= rate)) {
+ return rate;
} else {
+ if (UA_SAMP_LO(a1d) > rate)
+ return UA_SAMP_LO(a1d);
+ else
+ return UA_SAMP_HI(a1d);
+ }
+ } else {
+ for (i = 0; i < 100; i++) {
for (j = 0; j < a1d->bSamFreqType; j++) {
- DPRINTFN(2,("uaudio_get_minmax_rates: disc #%d: %d\n",
- j, UA_GETSAMP(a1d, j)));
- if (UA_GETSAMP(a1d, j) < *min)
- *min = UA_GETSAMP(a1d, j);
- if (UA_GETSAMP(a1d, j) > *max)
- *max = UA_GETSAMP(a1d, j);
+ r = UA_GETSAMP(a1d, j);
+ if ((r - (500 * i) <= rate) &&
+ (r + (500 * i) >= rate))
+ return r;
}
}
+ /* assumes rates are listed in order from lowest to highest */
+ if (rate < UA_GETSAMP(a1d, 0))
+ j = 0;
+ else
+ j = a1d->bSamFreqType - 1;
+ return UA_GETSAMP(a1d, j);
}
+ DPRINTF(("%s: could not match rate\n", __func__));
+ return rate;
}
int
-uaudio_match_alt_sub(int nalts, const struct as_info *alts,
- const struct audio_params *p, int mode,
- int enc, int pre, u_long rate)
+uaudio_match_alt(void *addr, struct audio_params *p, int mode, int enc, int pre)
{
+ struct uaudio_softc *sc = addr;
const struct usb_audio_streaming_type1_descriptor *a1d;
- int i, j;
-
- DPRINTF(("uaudio_match_alt_sub: search for %luHz %dch\n",
- rate, p->channels));
- for (i = 0; i < nalts; i++) {
- a1d = alts[i].asf1desc;
- if (alts[i].sc_busy)
- continue;
- if (p->channels != a1d->bNrChannels)
+ int i, j, dir, rate;
+ int alts_eh, alts_ch, ualt;
+
+ alts_eh = 0;
+ for (i = 0; i < sc->sc_nalts; i++) {
+ dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
+ if ((mode == AUMODE_RECORD && dir != UE_DIR_IN) ||
+ (mode == AUMODE_PLAY && dir == UE_DIR_IN))
continue;
- if (pre != a1d->bBitResolution)
+ if (sc->sc_alts[i].encoding != enc)
continue;
- if (enc != alts[i].encoding)
+ a1d = sc->sc_alts[i].asf1desc;
+ if (a1d->bBitResolution != pre)
continue;
- if (mode != UE_GET_DIR(alts[i].edesc->bEndpointAddress))
- continue;
- if (a1d->bSamFreqType == UA_SAMP_CONTNUOUS) {
- DPRINTFN(3,("uaudio_match_alt_sub: cont %d-%d\n",
- UA_SAMP_LO(a1d), UA_SAMP_HI(a1d)));
- if (UA_SAMP_LO(a1d) <= rate && rate <= UA_SAMP_HI(a1d))
- return i;
- } else {
- for (j = 0; j < a1d->bSamFreqType; j++) {
- DPRINTFN(3,("uaudio_match_alt_sub: disc #%d: %d\n",
- j, UA_GETSAMP(a1d, j)));
- /* XXX allow for some slack */
- if (UA_GETSAMP(a1d, j) == rate)
- return i;
- }
- }
+ alts_eh |= 1 << i;
}
- return -1;
-}
-
-int
-uaudio_match_alt_chan(int nalts, const struct as_info *alts,
- struct audio_params *p, int mode, int enc, int pre)
-{
- int i, n;
- u_long min, max;
- u_long rate;
-
- /* Exact match */
- DPRINTF(("uaudio_match_alt_chan: examine %ldHz %dch %dbit.\n",
- p->sample_rate, p->channels, pre));
- i = uaudio_match_alt_sub(nalts, alts, p, mode, enc, pre, p->sample_rate);
- if (i >= 0)
- return i;
-
- uaudio_get_minmax_rates(nalts, alts, p, mode, enc, pre, &min, &max);
- DPRINTF(("uaudio_match_alt_chan: min=%lu max=%lu\n", min, max));
- if (max <= 0)
+ if (alts_eh == 0) {
+ DPRINTF(("%s: could not match dir/enc/prec\n", __func__));
return -1;
- /* Search for biggers */
- n = 2;
- while ((rate = p->sample_rate * n++) <= max) {
- i = uaudio_match_alt_sub(nalts, alts, p, mode, enc, pre, rate);
- if (i >= 0) {
- p->sample_rate = rate;
- return i;
+ }
+
+ alts_ch = 0;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < sc->sc_nalts; j++) {
+ if (!(alts_eh & (1 << j)))
+ continue;
+ a1d = sc->sc_alts[j].asf1desc;
+ if (a1d->bNrChannels == p->channels)
+ alts_ch |= 1 << j;
}
+ if (alts_ch)
+ break;
+ if (p->channels == 2)
+ p->channels = 1;
+ else
+ p->channels = 2;
}
- if (p->sample_rate >= min) {
- i = uaudio_match_alt_sub(nalts, alts, p, mode, enc, pre, max);
- if (i >= 0) {
- p->sample_rate = max;
- return i;
+ if (!alts_ch) {
+ /* just use the first alt that matched the encoding */
+ for (i = 0; i < sc->sc_nalts; i++)
+ if (alts_eh & (1 << i))
+ break;
+ alts_ch = 1 << i;
+ a1d = sc->sc_alts[i].asf1desc;
+ p->channels = a1d->bNrChannels;
+ }
+
+ ualt = -1;
+ for (i = 0; i < sc->sc_nalts; i++) {
+ if (alts_ch & (1 << i)) {
+ rate = uaudio_match_alt_rate(sc, i, p->sample_rate);
+ if (rate - 50 <= p->sample_rate &&
+ rate + 50 >= p->sample_rate) {
+ p->sample_rate = rate;
+ break;
+ }
}
+ }
+ if (i < sc->sc_nalts) {
+ ualt = i;
} else {
- i = uaudio_match_alt_sub(nalts, alts, p, mode, enc, pre, min);
- if (i >= 0) {
- p->sample_rate = min;
- return i;
+ for (i = 0; i < sc->sc_nalts; i++) {
+ if (alts_ch & (1 << i)) {
+ ualt = i;
+ p->sample_rate = uaudio_match_alt_rate(sc,
+ i, p->sample_rate);
+ break;
+ }
}
}
- return -1;
-}
-
-int
-uaudio_match_alt(int nalts, const struct as_info *alts,
- struct audio_params *p, int mode, int enc, int pre)
-{
- int i, n;
-
- mode = mode == AUMODE_PLAY ? UE_DIR_OUT : UE_DIR_IN;
- i = uaudio_match_alt_chan(nalts, alts, p, mode, enc, pre);
- if (i >= 0)
- return i;
-
- for (n = p->channels + 1; n <= AUDIO_MAX_CHANNELS; n++) {
- p->channels = n;
- i = uaudio_match_alt_chan(nalts, alts, p, mode, enc, pre);
- if (i >= 0)
- return i;
- }
- if (p->channels != 2)
- return -1;
- p->channels = 1;
- return uaudio_match_alt_chan(nalts, alts, p, mode, enc, pre);
+ return ualt;
}
int
@@ -3162,7 +3125,7 @@ uaudio_set_params(void *addr, int setmode, int usemode,
DPRINTF(("uaudio_set_params: chan=%d prec=%d enc=%d rate=%ld\n",
p->channels, pre, enc, p->sample_rate));
- i = uaudio_match_alt(sc->sc_nalts, sc->sc_alts, p, mode, enc, pre);
+ i = uaudio_match_alt(sc, p, mode, enc, pre);
if (i < 0)
return (EINVAL);