]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Implements support for capture/playback enums.
authorJames Courtier-Dutton <James@superbug.demon.co.uk>
Fri, 13 Oct 2006 21:06:17 +0000 (22:06 +0100)
committerJames Courtier-Dutton <James@superbug.demon.co.uk>
Fri, 13 Oct 2006 21:06:17 +0000 (22:06 +0100)
src/mixer/simple_none.c

index 3270ea999c50e1b5114a8c86f47f32dcb036ca49..3b190c3997943c8ff0dcbaea1a92021304560dda 100644 (file)
 
 typedef enum _selem_ctl_type {
        CTL_SINGLE,
-       CTL_ENUMLIST,
+       CTL_GLOBAL_ENUM,
        CTL_GLOBAL_SWITCH,
        CTL_GLOBAL_VOLUME,
        CTL_GLOBAL_ROUTE,
+       CTL_PLAYBACK_ENUM,
        CTL_PLAYBACK_SWITCH,
        CTL_PLAYBACK_VOLUME,
        CTL_PLAYBACK_ROUTE,
+       CTL_CAPTURE_ENUM,
        CTL_CAPTURE_SWITCH,
        CTL_CAPTURE_VOLUME,
        CTL_CAPTURE_ROUTE,
@@ -286,7 +288,16 @@ static int elem_read_enum(selem_none_t *s)
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
-       selem_ctl_t *c = &s->ctls[CTL_ENUMLIST];
+       int type;
+       selem_ctl_t *c;
+       type = CTL_GLOBAL_ENUM;
+       if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) )
+               type = CTL_GLOBAL_ENUM;
+       else if (s->selem.caps & SM_CAP_PENUM)
+               type = CTL_PLAYBACK_ENUM;
+       else if (s->selem.caps & SM_CAP_CENUM)
+               type = CTL_CAPTURE_ENUM;
+       c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
        if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
                return err;
@@ -319,13 +330,28 @@ static int selem_read(snd_mixer_elem_t *elem)
        csw = s->str[SM_CAPT].sw;
        s->str[SM_CAPT].sw = ~0U;
 
-       if (s->ctls[CTL_ENUMLIST].elem) {
+       if (s->ctls[CTL_GLOBAL_ENUM].elem) {
+               err = elem_read_enum(s);
+               if (err < 0)
+                       return err;
+               goto __skip_cswitch;
+       }
+
+       if (s->ctls[CTL_CAPTURE_ENUM].elem) {
                err = elem_read_enum(s);
                if (err < 0)
                        return err;
                goto __skip_cswitch;
        }
 
+       if (s->ctls[CTL_PLAYBACK_ENUM].elem) {
+               err = elem_read_enum(s);
+               if (err < 0)
+                       return err;
+               goto __skip_cswitch;
+       }
+
+
        if (s->ctls[CTL_PLAYBACK_VOLUME].elem)
                err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME);
        else if (s->ctls[CTL_GLOBAL_VOLUME].elem)
@@ -504,7 +530,16 @@ static int elem_write_enum(selem_none_t *s)
        snd_ctl_elem_value_t *ctl;
        unsigned int idx;
        int err;
-       selem_ctl_t *c = &s->ctls[CTL_ENUMLIST];
+       int type;
+       selem_ctl_t *c;
+       type = CTL_GLOBAL_ENUM;
+       if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) == (SM_CAP_CENUM | SM_CAP_PENUM) )
+               type = CTL_GLOBAL_ENUM;
+       else if (s->selem.caps & SM_CAP_PENUM)
+               type = CTL_PLAYBACK_ENUM;
+       else if (s->selem.caps & SM_CAP_CENUM)
+               type = CTL_CAPTURE_ENUM;
+       c = &s->ctls[type];
        snd_ctl_elem_value_alloca(&ctl);
        if ((err = snd_hctl_elem_read(c->elem, ctl)) < 0)
                return err;
@@ -524,7 +559,13 @@ static int selem_write_main(snd_mixer_elem_t *elem)
        assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
        s = snd_mixer_elem_get_private(elem);
 
-       if (s->ctls[CTL_ENUMLIST].elem)
+       if (s->ctls[CTL_GLOBAL_ENUM].elem)
+               return elem_write_enum(s);
+
+       if (s->ctls[CTL_PLAYBACK_ENUM].elem)
+               return elem_write_enum(s);
+
+       if (s->ctls[CTL_CAPTURE_ENUM].elem)
                return elem_write_enum(s);
 
        if (s->ctls[CTL_SINGLE].elem) {
@@ -626,6 +667,7 @@ static int simple_update(snd_mixer_elem_t *melem)
        unsigned int caps, pchannels, cchannels;
        long pmin, pmax, cmin, cmax;
        selem_ctl_t *ctl;
+       const char *name;
 
        caps = 0;
        pchannels = 0;
@@ -634,6 +676,7 @@ static int simple_update(snd_mixer_elem_t *melem)
        cmin = cmax = 0;
        assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE);
        simple = snd_mixer_elem_get_private(melem);
+       name = snd_mixer_selem_get_name(melem);
        ctl = &simple->ctls[CTL_SINGLE];
        if (ctl->elem) {
                pchannels = cchannels = ctl->values;
@@ -733,12 +776,23 @@ static int simple_update(snd_mixer_elem_t *melem)
                caps |= SM_CAP_CSWITCH | SM_CAP_CSWITCH_EXCL;
                caps &= ~SM_CAP_GSWITCH;
        }
-       ctl = &simple->ctls[CTL_ENUMLIST];
+       ctl = &simple->ctls[CTL_GLOBAL_ENUM];
+       if (ctl->elem) {
+               if (pchannels < ctl->values)
+                       pchannels = ctl->values;
+               caps |= SM_CAP_PENUM | SM_CAP_CENUM;
+       }
+       ctl = &simple->ctls[CTL_PLAYBACK_ENUM];
        if (ctl->elem) {
                if (pchannels < ctl->values)
                        pchannels = ctl->values;
-               /* FIXME: differentiate some controls */
-               caps |= SM_CAP_PENUM|SM_CAP_CENUM;
+               caps |= SM_CAP_PENUM;
+       }
+       ctl = &simple->ctls[CTL_CAPTURE_ENUM];
+       if (ctl->elem) {
+               if (pchannels < ctl->values)
+                       pchannels = ctl->values;
+               caps |= SM_CAP_CENUM;
        }
        if (pchannels > 32)
                pchannels = 32;
@@ -829,12 +883,15 @@ static struct suf {
        const char *suffix;
        selem_ctl_type_t type;
 } suffixes[] = {
+       {" Playback Enum", CTL_PLAYBACK_ENUM},
        {" Playback Switch", CTL_PLAYBACK_SWITCH},
        {" Playback Route", CTL_PLAYBACK_ROUTE},
        {" Playback Volume", CTL_PLAYBACK_VOLUME},
+       {" Capture Enum", CTL_CAPTURE_ENUM},
        {" Capture Switch", CTL_CAPTURE_SWITCH},
        {" Capture Route", CTL_CAPTURE_ROUTE},
        {" Capture Volume", CTL_CAPTURE_VOLUME},
+       {" Enum", CTL_GLOBAL_ENUM},
        {" Switch", CTL_GLOBAL_SWITCH},
        {" Route", CTL_GLOBAL_ROUTE},
        {" Volume", CTL_GLOBAL_VOLUME},
@@ -930,16 +987,33 @@ static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
 
        case SM_OPS_IS_ENUMERATED:
                if (val == 1) {
-                       if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM))
+                       if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) )
+                               return 1;
+                       if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) )
                                return 1;
-                       return !!(s->selem.caps & SM_CAP_CENUM);
+                       return 0;
                }
-               return s->ctls[CTL_ENUMLIST].elem != 0;
+               if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) )
+                       return 1;
+               return 0;
        
        case SM_OPS_IS_ENUMCNT:
-               if (! s->ctls[CTL_ENUMLIST].elem)
-                       return -EINVAL;
-               return s->ctls[CTL_ENUMLIST].max;
+               /* Both */
+               if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) {
+                       if (! s->ctls[CTL_GLOBAL_ENUM].elem)
+                               return -EINVAL;
+                       return s->ctls[CTL_GLOBAL_ENUM].max;
+               /* Only Playback */
+               } else if (s->selem.caps & SM_CAP_PENUM ) {
+                       if (! s->ctls[CTL_PLAYBACK_ENUM].elem)
+                               return -EINVAL;
+                       return s->ctls[CTL_PLAYBACK_ENUM].max;
+               /* Only Capture */
+               } else if (s->selem.caps & SM_CAP_CENUM ) {
+                       if (! s->ctls[CTL_CAPTURE_ENUM].elem)
+                               return -EINVAL;
+                       return s->ctls[CTL_CAPTURE_ENUM].max;
+               }
 
        }
        
@@ -1424,10 +1498,20 @@ static int enum_item_name_ops(snd_mixer_elem_t *elem,
        selem_none_t *s = snd_mixer_elem_get_private(elem);
        snd_ctl_elem_info_t *info;
        snd_hctl_elem_t *helem;
+       int type;
 
-       helem = s->ctls[CTL_ENUMLIST].elem;
+       type = CTL_GLOBAL_ENUM;
+       helem = s->ctls[type].elem;
+       if (!helem) {
+               type = CTL_PLAYBACK_ENUM;
+               helem = s->ctls[type].elem;
+       }
+       if (!helem) {
+               type = CTL_CAPTURE_ENUM;
+               helem = s->ctls[type].elem;
+       }
        assert(helem);
-       if (item >= (unsigned int)s->ctls[CTL_ENUMLIST].max)
+       if (item >= (unsigned int)s->ctls[type].max)
                return -EINVAL;
        snd_ctl_elem_info_alloca(&info);
        snd_hctl_elem_info(helem, info);
@@ -1448,7 +1532,9 @@ static int get_enum_item_ops(snd_mixer_elem_t *elem,
 
        if ((unsigned int) channel >= s->str[0].channels)
                return -EINVAL;
-       helem = s->ctls[CTL_ENUMLIST].elem;
+       helem = s->ctls[CTL_GLOBAL_ENUM].elem;
+       if (!helem) helem = s->ctls[CTL_PLAYBACK_ENUM].elem;
+       if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem;
        assert(helem);
        snd_ctl_elem_value_alloca(&ctl);
        err = snd_hctl_elem_read(helem, ctl);
@@ -1465,17 +1551,30 @@ static int set_enum_item_ops(snd_mixer_elem_t *elem,
        snd_ctl_elem_value_t *ctl;
        snd_hctl_elem_t *helem;
        int err;
+       int type;
 
-       if ((unsigned int) channel >= s->str[0].channels)
+       if ((unsigned int) channel >= s->str[0].channels) {
                return -EINVAL;
-       helem = s->ctls[CTL_ENUMLIST].elem;
+       }
+       type = CTL_GLOBAL_ENUM;
+       helem = s->ctls[type].elem;
+       if (!helem) {
+               type = CTL_PLAYBACK_ENUM;
+               helem = s->ctls[type].elem;
+       }
+       if (!helem) {
+               type = CTL_CAPTURE_ENUM;
+               helem = s->ctls[type].elem;
+       }
        assert(helem);
-       if (item >= (unsigned int)s->ctls[CTL_ENUMLIST].max)
+       if (item >= (unsigned int)s->ctls[type].max) {
                return -EINVAL;
+       }
        snd_ctl_elem_value_alloca(&ctl);
        err = snd_hctl_elem_read(helem, ctl);
-       if (err < 0)
+       if (err < 0) {
                return err;
+       }
        snd_ctl_elem_value_set_enumerated(ctl, channel, item);
        return snd_hctl_elem_write(helem, ctl);
 }
@@ -1519,7 +1618,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        switch (type) {
        case CTL_SINGLE:
                if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED)
-                       type = CTL_ENUMLIST;
+                       type = CTL_GLOBAL_ENUM;
                else if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN &&
                         ctype != SND_CTL_ELEM_TYPE_INTEGER)
                        return 0;
@@ -1530,7 +1629,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        {
                unsigned int n;
                if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
-                       type = CTL_ENUMLIST;
+                       type = CTL_GLOBAL_ENUM;
                        break;
                }
                if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN)
@@ -1545,7 +1644,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        case CTL_PLAYBACK_SWITCH:
        case CTL_CAPTURE_SWITCH:
                if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
-                       type = CTL_ENUMLIST;
+                       type = CTL_GLOBAL_ENUM;
                        break;
                }
                if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN)
@@ -1555,7 +1654,7 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        case CTL_PLAYBACK_VOLUME:
        case CTL_CAPTURE_VOLUME:
                if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
-                       type = CTL_ENUMLIST;
+                       type = CTL_GLOBAL_ENUM;
                        break;
                }
                if (ctype != SND_CTL_ELEM_TYPE_INTEGER)
@@ -1565,6 +1664,12 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
                if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED)
                        return 0;
                break;
+       case CTL_GLOBAL_ENUM:
+       case CTL_PLAYBACK_ENUM:
+       case CTL_CAPTURE_ENUM:
+               if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED)
+                       return 0;
+               break;
        default:
                assert(0);
                break;
@@ -1610,7 +1715,9 @@ static int simple_add1(snd_mixer_class_t *class, const char *name,
        simple->ctls[type].type = snd_ctl_elem_info_get_type(info);
        simple->ctls[type].inactive = snd_ctl_elem_info_is_inactive(info);
        simple->ctls[type].values = values;
-       if (type == CTL_ENUMLIST) {
+       if ( (type == CTL_GLOBAL_ENUM) ||
+            (type == CTL_PLAYBACK_ENUM) ||
+            (type == CTL_CAPTURE_ENUM) ) {
                simple->ctls[type].min = 0;
                simple->ctls[type].max = snd_ctl_elem_info_get_items(info);
        } else {