mixer of uaudio driver

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

mixer of uaudio driver

Alexandre Ratchov
hello,

the usb audio spec allows devices to use signed numbers for mixer values,
but the current uaudio(4) driver doesn't handle properly negative values.
The attached patch fixes this.

It also improves the way the driver converts bsd mixer values (in the range
0..255) to uaudio values (in the range mc->minval..mc->maxval). It ensures
that we have the following properties:

        -  when writing to the mixer:

           0 (on the bsd side) is mapped to mc->minval (on the uaudio side)
           and 255 is mapped to mc->maxval

        -  when reading the mixer:

           mc->maxval is mapped to 255 and
           mc->minval is mapped to 0

        -  mc->delta (used on the bsd side) is such that if an application

            1. reads the mixer,
                2. adds mc->delta to the returned value
          3. writes the obtained value to the mixer and
                4. reads again the mixer

           then the returned value will be different from the initial one.

Imo, it is important for an user application to be able to reach the maximum
and minimum values of a mixer control because on some devices these seems to
be "special values". Example: on the m-audio mobilepre the "direct monitor"
feature is turned off by setting the corresponding mixer control to
mc->minval.

Comments ? Other suggestions ?

regards,

--
Alexandre
Index: uaudio.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uaudio.c,v
retrieving revision 1.34
diff -u -r1.34 uaudio.c
--- uaudio.c 6 Jan 2006 11:34:08 -0000 1.34
+++ uaudio.c 28 Jan 2006 09:35:55 -0000
@@ -101,7 +101,6 @@
 #define MIX_UNSIGNED(n) ((n) == MIX_UNSIGNED_16)
  int minval, maxval;
  u_int delta;
- u_int mul;
  u_int8_t class;
  char ctlname[MAX_AUDIO_DEV_LEN];
  char *ctlunit;
@@ -265,6 +264,7 @@
  (struct uaudio_softc *, const usb_config_descriptor_t *);
 
 Static int uaudio_signext(int, int);
+Static int uaudio_unsignext(int, int);
 Static int uaudio_value2bsd(struct mixerctl *, int);
 Static int uaudio_bsd2value(struct mixerctl *, int);
 Static int uaudio_get(struct uaudio_softc *, int, int, int, int, int);
@@ -600,7 +600,7 @@
 Static void
 uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct mixerctl *mc)
 {
- int res;
+ int res, range;
  size_t len;
  struct mixerctl *nmc;
 
@@ -635,18 +635,16 @@
  uaudio_get(sc, GET_MIN, UT_READ_CLASS_INTERFACE,
    mc->wValue[0], mc->wIndex,
    MIX_SIZE(mc->type)));
- mc->maxval = 1 + uaudio_signext(mc->type,
+ mc->maxval = uaudio_signext(mc->type,
  uaudio_get(sc, GET_MAX, UT_READ_CLASS_INTERFACE,
    mc->wValue[0], mc->wIndex,
    MIX_SIZE(mc->type)));
- mc->mul = mc->maxval - mc->minval;
- if (mc->mul == 0)
- mc->mul = 1;
+ range = mc->maxval - mc->minval;
  res = uaudio_get(sc, GET_RES, UT_READ_CLASS_INTERFACE,
  mc->wValue[0], mc->wIndex,
  MIX_SIZE(mc->type));
- if (res > 0)
- mc->delta = (res * 255 + mc->mul/2) / mc->mul;
+ if (res > 0 && range > 0)
+ mc->delta = (res * 255 + res - 1) / range;
  }
 
  sc->sc_ctls[sc->sc_nctls++] = *mc;
@@ -832,7 +830,6 @@
  mix.ctlunit = "";
  mix.minval = 1;
  mix.maxval = d->bNrInPins;
- mix.mul = mix.maxval - mix.minval;
  wp = snprintf(mix.ctlname, MAX_AUDIO_DEV_LEN, "sel%d-", d->bUnitId);
  for (i = 1; i <= d->bNrInPins; i++) {
  wp += snprintf(mix.ctlname + wp, MAX_AUDIO_DEV_LEN - wp,
@@ -2289,8 +2286,21 @@
 }
 
 Static int
+uaudio_unsignext(int type, int val)
+{
+ if (!MIX_UNSIGNED(type)) {
+ if (MIX_SIZE(type) == 2)
+ val = (u_int16_t)val;
+ else
+ val = (u_int8_t)val;
+ }
+ return (val);
+}
+
+Static int
 uaudio_value2bsd(struct mixerctl *mc, int val)
 {
+ int range;
  DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ",
      mc->type, val, mc->minval, mc->maxval));
  if (mc->type == MIX_ON_OFF) {
@@ -2298,9 +2308,14 @@
  } else if (mc->type == MIX_SELECTOR) {
  if (val < mc->minval || val > mc->maxval)
  val = mc->minval;
- } else
- val = ((uaudio_signext(mc->type, val) - mc->minval) * 255
- + mc->mul/2) / mc->mul;
+ } else {
+ range = mc->maxval - mc->minval;
+ if (range == 0)
+ val = 0;
+ else
+ val = 255 * (uaudio_signext(mc->type, val) -
+    mc->minval) / range;
+ }
  DPRINTFN(5, ("val'=%d\n", val));
  return (val);
 }
@@ -2316,7 +2331,8 @@
  if (val < mc->minval || val > mc->maxval)
  val = mc->minval;
  } else
- val = (val + mc->delta/2) * mc->mul / 255 + mc->minval;
+ val = uaudio_unsignext(mc->type,
+    val * (mc->maxval - mc->minval) / 255 + mc->minval);
  DPRINTFN(5, ("val'=%d\n", val));
  return (val);
 }