Update of /cvsroot/alsa/alsa-kernel/usb
In directory usw-pr-cvs1:/tmp/cvs-serv19914

Modified Files:
        usbmixer.c 
Added Files:
        usbmixer_maps.c 
Log Message:
- added the manual mixer mapping.
  used for the complex mixer topology such as SB extigy.
- more strict buffer-overflow checks.



--- NEW FILE: usbmixer_maps.c ---
/*
 *   Additional mixer mapping
 *
 *   Copyright (c) 2002 by Takashi Iwai <[EMAIL PROTECTED]>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */


struct usbmix_name_map {
        int id;
        const char *name;
};

struct usbmix_ctl_map {
        int vendor;
        int product;
        const struct usbmix_name_map *map;
};
        
/*
 * USB control mappers for SB Exitigy
 */

/*
 * Topology of SB Extigy (see on the wide screen :)

USB_IN[1] --->FU[2] -----------------------------+->MU[16] - PE[17]-+- FU[18] -+- 
EU[27] -+- EU[21] - FU[22] -+- FU[23] > Dig_OUT[24]
                                                 |                  |          |       
   |                   |
USB_IN[3] -+->SU[5] - FU[6] -+- MU[14] - PE[15] -+                  |          |       
   |                   +- FU[25] > Dig_OUT[26]
           ^                 |                   |                  |          |       
   |
Dig_IN[4] -+                 |                   |                  |          |       
   +- FU[28] --------------------> Spk_OUT[19]
                             |                   |                  |          |
Lin-IN[7] -+-- FU[8] --------+                   |                  |          
+----------------------------------------> Hph_OUT[20]
           |                                     |                  |
Mic-IN[9] --+- FU[10] ---------------------------+                  |
           ||                                                       |
           ||  +----------------------------------------------------+
           VV  V
           ++--+->SU[11] ->FU[12] 
-------------------------------------------------------------------------------------->
 USB_OUT[13]
*/

static struct usbmix_name_map extigy_map[] = {
        { 2, "PCM Playback" }, /* FU */
        { 5, "Digital Playback Source" }, /* SU */
        { 6, "Digital" }, /* FU */
        { 8, "Line Playback" }, /* FU */
        { 10, "Mic Playback" }, /* FU */
        { 11, "Capture Source" }, /* SU */
        { 12, "Capture" }, /* FU */
        { 18, "Master Playback" }, /* FU */
        /* FIXME: more to come here... */
        { 0 } /* terminator */
};


/*
 * Control map entries
 */

static struct usbmix_ctl_map usbmix_ctl_maps[] = {
        { 0x41e, 0x3000, extigy_map },
        { 0 } /* terminator */
};


Index: usbmixer.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbmixer.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- usbmixer.c  3 Oct 2002 10:33:09 -0000       1.4
+++ usbmixer.c  10 Oct 2002 13:45:32 -0000      1.5
@@ -103,6 +103,37 @@
 
 
 /*
+ * manual mapping of mixer names
+ * if the mixer topology is too complicated and the parsed names are
+ * ambiguous, add the entries in usbmixer_maps.c.
+ */
+#include "usbmixer_maps.c"
+
+/* get the mapped name if the unit matches */
+static int check_mapped_name(mixer_build_t *state, int unitid, char *buf, int buflen)
+{
+       const struct usbmix_ctl_map *map;
+       const struct usbmix_name_map *p;
+       struct usb_device_descriptor *dev = &state->chip->dev->descriptor;
+
+       for (map = usbmix_ctl_maps; map->vendor; map++) {
+               if (map->vendor != dev->idVendor ||
+                   map->product != dev->idProduct)
+                       continue;
+               for (p = map->map; p->id; p++) {
+                       if (p->id == unitid) {
+                               buflen--;
+                               strncpy(buf, p->name, buflen - 1);
+                               buf[buflen] = 0;
+                               return strlen(buf);
+                       }
+               }
+       }
+       return 0;
+}
+
+
+/*
  * find an audio control unit with the given unit id
  */
 static void *find_audio_control_unit(mixer_build_t *state, unsigned char unit)
@@ -610,7 +641,7 @@
                              unsigned int ctl_mask, int control,
                              usb_audio_term_t *iterm, int unitid)
 {
-       int len = 0;
+       int len = 0, mapped_name = 0;
        int nameid = desc[desc[0] - 1];
        snd_kcontrol_t *kctl;
        usb_mixer_elem_info_t *cval;
@@ -666,7 +697,9 @@
        }
        kctl->private_free = usb_mixer_elem_free;
 
-       if (nameid)
+       len = check_mapped_name(state, unitid, kctl->id.name, sizeof(kctl->id.name));
+       mapped_name = len != 0;
+       if (! len && nameid)
                len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, 
sizeof(kctl->id.name));
 
        switch (control) {
@@ -679,7 +712,7 @@
                 * - if the connected output can be determined, use it.
                 * - otherwise, anonymous name.
                 */
-               if (! nameid) {
+               if (! len) {
                        len = get_term_name(state, iterm, kctl->id.name, 
sizeof(kctl->id.name), 1);
                        if (! len)
                                len = get_term_name(state, &state->oterm, 
kctl->id.name, sizeof(kctl->id.name), 1);
@@ -690,20 +723,25 @@
                 * if the connected output is USB stream, then it's likely a
                 * capture stream.  otherwise it should be playback (hopefully :)
                 */
-               if (! (state->oterm.type >> 16)) {
+               if (! mapped_name && ! (state->oterm.type >> 16)) {
                        if ((state->oterm.type & 0xff00) == 0x0100) {
-                               strcpy(kctl->id.name + len, " Capture");
-                               len += 8;
+                               if (len + 8 < sizeof(kctl->id.name)) {
+                                       strcpy(kctl->id.name + len, " Capture");
+                                       len += 8;
+                               }
                        } else {
-                               strcpy(kctl->id.name + len, " Playback");
-                               len += 9;
+                               if (len + 9 < sizeof(kctl->id.name)) {
+                                       strcpy(kctl->id.name + len, " Playback");
+                                       len += 9;
+                               }
                        }
                }
-               strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : 
" Volume");
+               if (len + 7 < sizeof(kctl->id.name))
+                       strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " 
+Switch" : " Volume");
                break;
 
        default:
-               if (! nameid)
+               if (! len)
                        strcpy(kctl->id.name, audio_feature_info[control].name);
                break;
        }
@@ -823,10 +861,13 @@
        }
        kctl->private_free = usb_mixer_elem_free;
 
-       len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
+       len = check_mapped_name(state, unitid, kctl->id.name, sizeof(kctl->id.name));
+       if (! len)
+               len = get_term_name(state, &iterm, kctl->id.name, 
+sizeof(kctl->id.name), 0);
        if (! len)
                len = sprintf(kctl->id.name, "Mixer Source %d", in_ch);
-       strcpy(kctl->id.name + len, " Volume");
+       if (len + 7 < sizeof(kctl->id.name))
+               strcpy(kctl->id.name + len, " Volume");
 
        snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
                    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
@@ -973,7 +1014,7 @@
        int num_ins = dsc[6];
        usb_mixer_elem_info_t *cval;
        snd_kcontrol_t *kctl;
-       int i, err, nameid, type;
+       int i, err, nameid, type, len;
        struct procunit_info *info;
        struct procunit_value_info *valinfo;
        static struct procunit_value_info default_value_info[] = {
@@ -1035,17 +1076,25 @@
                }
                kctl->private_free = usb_mixer_elem_free;
 
-               if (info->name)
-                       sprintf(kctl->id.name, "%s %s", info->name, valinfo->suffix);
+               if (check_mapped_name(state, unitid, kctl->id.name, 
+sizeof(kctl->id.name)))
+                       ;
+               else if (info->name)
+                       strcpy(kctl->id.name, info->name);
                else {
                        nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
-                       if (nameid) {
-                               int len = snd_usb_copy_string_desc(state, nameid, 
kctl->id.name, sizeof(kctl->id.name));
-                               strcpy(kctl->id.name + len, valinfo->suffix);
-                       } else
-                               sprintf(kctl->id.name, "%s %s", name, valinfo->suffix);
+                       len = 0;
+                       if (nameid)
+                               len = snd_usb_copy_string_desc(state, nameid, 
+kctl->id.name, sizeof(kctl->id.name));
+                       if (! len) {
+                               strncpy(kctl->id.name, name, sizeof(kctl->id.name) - 
+1);
+                               kctl->id.name[sizeof(kctl->id.name)-1] = 0;
+                       }
+               }
+               len = strlen(kctl->id.name);
+               if (len + sizeof(valinfo->suffix) + 1 < sizeof(kctl->id.name)) {
+                       kctl->id.name[len] = ' ';
+                       strcpy(kctl->id.name + len + 1, valinfo->suffix);
                }
-
                snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
                            cval->id, kctl->id.name, cval->channels, cval->min, 
cval->max);
                if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
@@ -1158,7 +1207,7 @@
 static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned char 
*desc)
 {
        int num_ins = desc[4];
-       int i, err, nameid;
+       int i, err, nameid, len;
        usb_mixer_elem_info_t *cval;
        snd_kcontrol_t *kctl;
        char **namelist;
@@ -1196,7 +1245,7 @@
 #define MAX_ITEM_NAME_LEN      64
        for (i = 0; i < num_ins; i++) {
                usb_audio_term_t iterm;
-               int len = 0;
+               len = 0;
                namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
                if (! namelist[i]) {
                        snd_printk(KERN_ERR "cannot malloc\n");
@@ -1222,17 +1271,23 @@
        kctl->private_free = usb_mixer_selector_elem_free;
 
        nameid = desc[desc[0] - 1];
-       if (nameid)
+       len = check_mapped_name(state, unitid, kctl->id.name, sizeof(kctl->id.name));
+       if (len)
+               ;
+       else if (nameid)
                snd_usb_copy_string_desc(state, nameid, kctl->id.name, 
sizeof(kctl->id.name));
        else {
-               int len = get_term_name(state, &state->oterm,
-                                       kctl->id.name, sizeof(kctl->id.name), 0);
+               len = get_term_name(state, &state->oterm,
+                                   kctl->id.name, sizeof(kctl->id.name), 0);
                if (! len)
                        len = sprintf(kctl->id.name, "USB");
-               if ((state->oterm.type & 0xff00) == 0x0100)
-                       strcpy(kctl->id.name + len, " Capture Source");
-               else
-                       strcpy(kctl->id.name + len, " Playback Source");
+               if ((state->oterm.type & 0xff00) == 0x0100) {
+                       if (len + 15 < sizeof(kctl->id.name))
+                               strcpy(kctl->id.name + len, " Capture Source");
+               } else {
+                       if (len + 16 < sizeof(kctl->id.name))
+                               strcpy(kctl->id.name + len, " Playback Source");
+               }
        }
 
        snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to