diff options
| author | Jaroslav Kysela <perex@suse.cz> | 2002-10-14 00:21:21 +0200 |
|---|---|---|
| committer | Jaroslav Kysela <perex@suse.cz> | 2002-10-14 00:21:21 +0200 |
| commit | f96f11d2fabe4e837ed147830a69c2725a4d64bc (patch) | |
| tree | 28b4bed12f5b2b00e8a8da23e09ceb5ab12e8b0d | |
| parent | 13e242be9115e6a4909532d9c5b651a1d8c11493 (diff) | |
ALSA update
- USB driver update
- better extdigi support (mixer)
- cleanups in the audio code
| -rw-r--r-- | include/sound/version.h | 2 | ||||
| -rw-r--r-- | sound/usb/usbaudio.c | 28 | ||||
| -rw-r--r-- | sound/usb/usbmixer.c | 271 | ||||
| -rw-r--r-- | sound/usb/usbmixer_maps.c | 100 |
4 files changed, 307 insertions, 94 deletions
diff --git a/include/sound/version.h b/include/sound/version.h index ba48af7a3099..11fb715148ce 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated automatically by configure. */ #define CONFIG_SND_VERSION "0.9.0rc3" -#define CONFIG_SND_DATE " (Fri Oct 04 13:09:13 2002 UTC)" +#define CONFIG_SND_DATE " (Sun Oct 13 15:15:37 2002 UTC)" diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index a71a1586543e..8588a0d52b28 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -957,6 +957,19 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) if (subs->interface >= 0 && subs->interface != fmt->iface) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; + subs->format = 0; + } + + /* set interface */ + if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) { + if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } + snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx); + subs->interface = fmt->iface; + subs->format = fmt->altset_idx; } /* create a data pipe */ @@ -965,7 +978,6 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) subs->datapipe = usb_sndisocpipe(dev, ep); else subs->datapipe = usb_rcvisocpipe(dev, ep); - subs->format = fmt->altset_idx; subs->syncpipe = subs->syncinterval = 0; subs->maxpacksize = alts->endpoint[0].wMaxPacketSize; subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); @@ -998,15 +1010,6 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) subs->syncinterval = alts->endpoint[1].bRefresh; } - /* set interface */ - if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", - dev->devnum, fmt->iface, fmt->altsetting); - return -EIO; - } - snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx); - subs->interface = fmt->iface; - ep = alts->endpoint[0].bEndpointAddress; /* if endpoint has pitch control, enable it */ if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) { @@ -1171,6 +1174,7 @@ static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction, snd_usb_substream_t *subs = &as->substream[direction]; subs->interface = -1; + subs->format = 0; runtime->hw = *hw; runtime->private_data = subs; subs->pcm_substream = substream; @@ -1601,6 +1605,10 @@ static int parse_audio_format_type(struct usb_device *dev, int iface_no, int alt /* FIXME: correct endianess and sign? */ pcm_format = -1; switch (format) { + case 0: /* some devices don't define this correctly... */ + snd_printd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", + dev->devnum, iface_no, altno); + /* fall-through */ case USB_AUDIO_FORMAT_PCM: /* check the format byte size */ switch (fmt[6]) { diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 04da43eb1bef..7be5bbc3e8e0 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -55,6 +55,8 @@ struct usb_audio_term { int name; }; +struct usbmix_name_map; + struct usb_mixer_build { snd_usb_audio_t *chip; unsigned char *buffer; @@ -62,6 +64,7 @@ struct usb_mixer_build { unsigned int ctrlif; DECLARE_BITMAP(unitbitmap, 32*32); usb_audio_term_t oterm; + const struct usbmix_name_map *map; }; struct usb_mixer_elem_info { @@ -78,7 +81,8 @@ struct usb_mixer_elem_info { enum { - USB_FEATURE_MUTE = 0, + USB_FEATURE_NONE = 0, + USB_FEATURE_MUTE = 1, USB_FEATURE_VOLUME, USB_FEATURE_BASS, USB_FEATURE_MID, @@ -99,10 +103,72 @@ enum { USB_MIXER_U16, }; +enum { + USB_PROC_UPDOWN = 1, + USB_PROC_UPDOWN_SWITCH = 1, + USB_PROC_UPDOWN_MODE_SEL = 2, + + USB_PROC_PROLOGIC = 2, + USB_PROC_PROLOGIC_SWITCH = 1, + USB_PROC_PROLOGIC_MODE_SEL = 2, + + USB_PROC_3DENH = 3, + USB_PROC_3DENH_SWITCH = 1, + USB_PROC_3DENH_SPACE = 2, + + USB_PROC_REVERB = 4, + USB_PROC_REVERB_SWITCH = 1, + USB_PROC_REVERB_LEVEL = 2, + USB_PROC_REVERB_TIME = 3, + USB_PROC_REVERB_DELAY = 4, + + USB_PROC_CHORUS = 5, + USB_PROC_CHORUS_SWITCH = 1, + USB_PROC_CHORUS_LEVEL = 2, + USB_PROC_CHORUS_RATE = 3, + USB_PROC_CHORUS_DEPTH = 4, + + USB_PROC_DCR = 6, + USB_PROC_DCR_SWITCH = 1, + USB_PROC_DCR_RATIO = 2, + USB_PROC_DCR_MAX_AMP = 3, + USB_PROC_DCR_THRESHOLD = 4, + USB_PROC_DCR_ATTACK = 5, + USB_PROC_DCR_RELEASE = 6, +}; + #define MAX_CHANNELS 10 /* max logical channels */ /* + * 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, int control, char *buf, int buflen) +{ + const struct usbmix_name_map *p; + + if (! state->map) + return 0; + + for (p = state->map; p->id; p++) { + if (p->id == unitid && + (! control || ! p->control || control == p->control)) { + buflen--; + strncpy(buf, p->name, buflen); + 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) @@ -227,7 +293,7 @@ static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value /* channel = 0: master, 1 = first channel */ inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value) { - return get_ctl_value(cval, GET_CUR, ((cval->control + 1) << 8) | channel, value); + return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); } /* @@ -256,7 +322,7 @@ static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value) inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value) { - return set_ctl_value(cval, SET_CUR, ((cval->control + 1) << 8) | channel, value); + return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); } @@ -291,7 +357,7 @@ static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl) while (snd_ctl_find_id(card, &kctl->id)) kctl->id.index++; if ((err = snd_ctl_add(card, kctl)) < 0) { - snd_printk(KERN_ERR "cannot add control\n"); + snd_printd(KERN_ERR "cannot add control (err = %d)\n", err); snd_ctl_free_one(kctl); } return err; @@ -509,9 +575,9 @@ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t break; } } - if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 || - get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0) { - snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, cval->control); + if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || + get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { + snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id); return -EINVAL; } cval->initialized = 1; @@ -534,7 +600,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &val); if (err < 0) { - printk("cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err); + snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err); return err; } val = get_relative_value(cval, val); @@ -546,7 +612,7 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t /* master channel */ err = get_cur_mix_value(cval, 0, &val); if (err < 0) { - printk("cannot get current value for control %d master ch: err = %d\n", cval->control, err); + snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err); return err; } val = get_relative_value(cval, val); @@ -610,12 +676,14 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, 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; int minchn = 0; + control++; /* change from zero-based to 1-based value */ + if (control == USB_FEATURE_GEQ) { /* FIXME: not supported yet */ return; @@ -623,7 +691,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; } cval->chip = state->chip; @@ -631,7 +699,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, cval->id = unitid; cval->control = control; cval->cmask = ctl_mask; - cval->val_type = audio_feature_info[control].type; + cval->val_type = audio_feature_info[control-1].type; if (ctl_mask == 0) cval->channels = 1; /* master channel */ else { @@ -651,22 +719,24 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, cval->max = 1; cval->initialized = 1; } else { - if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 || - get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0) - snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, control); + if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || + get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) + snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, control, unitid); else cval->initialized = 1; } kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (! kctl) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); snd_magic_kfree(cval); return; } kctl->private_free = usb_mixer_elem_free; - if (nameid) + len = check_mapped_name(state, unitid, control, 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 +749,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, * - 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,21 +760,26 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, * 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) - strcpy(kctl->id.name, audio_feature_info[control].name); + if (! len) + strcpy(kctl->id.name, audio_feature_info[control-1].name); break; } @@ -797,7 +872,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, cval->chip = state->chip; cval->ctrlif = state->ctrlif; cval->id = unitid; - cval->control = in_ch; + cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; for (i = 0; i < num_outs; i++) { if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) { @@ -809,24 +884,27 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, } /* get min/max values */ - if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | minchn, &cval->max) < 0 || - get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | minchn, &cval->min) < 0) - snd_printk(KERN_ERR "cannot get min/max values for mixer\n"); + if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || + get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) + snd_printd(KERN_ERR "cannot get min/max values for mixer (id %d)\n", unitid); else cval->initialized = 1; kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (! kctl) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); snd_magic_kfree(cval); return; } 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, 0, 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); @@ -917,51 +995,51 @@ struct procunit_info { }; static struct procunit_value_info updown_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Mode Select", USB_MIXER_U8 }, + { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info prologic_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Mode Select", USB_MIXER_U8 }, + { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info threed_enh_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Spaciousness", USB_MIXER_U8 }, + { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info reverb_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Level", USB_MIXER_U8 }, - { 0x03, "Time", USB_MIXER_U16 }, - { 0x04, "Delay", USB_MIXER_U8 }, + { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, + { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 }, + { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 }, { 0 } }; static struct procunit_value_info chorus_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Level", USB_MIXER_U8 }, - { 0x03, "Rate", USB_MIXER_U16 }, - { 0x04, "Depth", USB_MIXER_U16 }, + { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, + { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, + { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, { 0 } }; static struct procunit_value_info dcr_proc_info[] = { - { 0x01, "Switch", USB_MIXER_BOOLEAN }, - { 0x02, "Ratio", USB_MIXER_U16 }, - { 0x03, "Max Amp", USB_MIXER_S16 }, - { 0x04, "Threshold", USB_MIXER_S16 }, - { 0x05, "Attack Time", USB_MIXER_U16 }, - { 0x06, "Release Time", USB_MIXER_U16 }, + { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN }, + { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 }, + { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 }, + { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, + { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 }, + { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 }, { 0 } }; static struct procunit_info procunits[] = { - { 0x01, "Up Down", updown_proc_info }, - { 0x02, "Dolby Prologic", prologic_proc_info }, - { 0x03, "3D Stereo Extender", threed_enh_proc_info }, - { 0x04, "Reverb", reverb_proc_info }, - { 0x05, "Chorus", chorus_proc_info }, - { 0x06, "DCR", dcr_proc_info }, + { USB_PROC_UPDOWN, "Up Down", updown_proc_info }, + { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info }, + { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info }, + { USB_PROC_REVERB, "Reverb", reverb_proc_info }, + { USB_PROC_CHORUS, "Chorus", chorus_proc_info }, + { USB_PROC_DCR, "DCR", dcr_proc_info }, { 0 }, }; @@ -973,7 +1051,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char 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[] = { @@ -985,7 +1063,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char }; if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) { - snd_printk(KERN_ERR "invalid %s descriptor %d\n", name, unitid); + snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid); return -EINVAL; } @@ -1010,7 +1088,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char continue; cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } cval->chip = state->chip; @@ -1023,29 +1101,39 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char /* get min/max values */ if (get_ctl_value(cval, GET_MAX, cval->control, &cval->max) < 0 || get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0) - snd_printk(KERN_ERR "cannot get min/max values for proc/ext unit\n"); + snd_printd(KERN_ERR "cannot get min/max values for proc/ext control=%d, id=%d\n", cval->control, unitid); + else if (cval->max <= cval->min) + snd_printd(KERN_ERR "invalid min/max values (%d/%d) for proc/ext unit control=%d, id=%d\n", cval->min, cval->max, cval->control, unitid); else cval->initialized = 1; kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); snd_magic_kfree(cval); return -ENOMEM; } 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, cval->control, 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 +1246,7 @@ static void usb_mixer_selector_elem_free(snd_kcontrol_t *kctl) 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; @@ -1175,7 +1263,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; } cval->chip = state->chip; @@ -1196,7 +1284,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned #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"); @@ -1214,7 +1302,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); if (! kctl) { - snd_printk(KERN_ERR "cannot malloc kcontrol"); + snd_printk(KERN_ERR "cannot malloc kcontrol\n"); snd_magic_kfree(cval); return -ENOMEM; } @@ -1222,17 +1310,23 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned kctl->private_free = usb_mixer_selector_elem_free; nameid = desc[desc[0] - 1]; - if (nameid) + len = check_mapped_name(state, unitid, 0, 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", @@ -1290,6 +1384,8 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffe unsigned char *desc; mixer_build_t state; int err; + const struct usbmix_ctl_map *map; + struct usb_device_descriptor *dev = &chip->dev->descriptor; strcpy(chip->card->mixername, "USB Mixer"); @@ -1298,6 +1394,15 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffe state.buffer = buffer; state.buflen = buflen; state.ctrlif = ctrlif; + + /* check the mapping table */ + for (map = usbmix_ctl_maps; map->vendor; map++) { + if (map->vendor == dev->idVendor && map->product == dev->idProduct) { + state.map = map->map; + break; + } + } + desc = NULL; while ((desc = snd_usb_find_csint_desc(buffer, buflen, desc, OUTPUT_TERMINAL, ctrlif, -1)) != NULL) { if (desc[0] < 9) diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c new file mode 100644 index 000000000000..4d9d53102a6b --- /dev/null +++ b/sound/usb/usbmixer_maps.c @@ -0,0 +1,100 @@ +/* + * Additional mixer mapping + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * 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; + int control; +}; + +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[] = { + /* 1: IT pcm */ + { 2, "PCM Playback" }, /* FU */ + /* 3: IT pcm */ + /* 4: IT digital in */ + { 5, "Digital In Playback Source" }, /* SU */ + { 6, "Digital In" }, /* FU */ + /* 7: IT line */ + { 8, "Line Playback" }, /* FU */ + /* 9: IT mic */ + { 10, "Mic Playback" }, /* FU */ + { 11, "Capture Source" }, /* SU */ + { 12, "Capture" }, /* FU */ + /* 13: OT pcm capture */ + /* 14: MU (w/o controls) */ + /* 15: PE (3D enh) */ + /* 16: MU (w/o controls) */ + /* 17: PE (updown) */ /* FIXME: what control? */ + { 18, "Tone Control - Bass", USB_FEATURE_BASS }, /* FU */ + { 18, "Tone Control - Treble", USB_FEATURE_TREBLE }, /* FU */ + { 18, "Master Playback" }, /* FU; others */ + /* 19: OT speaker */ + /* 20: OT headphone */ + { 21, "Digital Out Extension" }, /* EU */ /* FIXME: what? */ + { 22, "Digital Out Playback" }, /* FU */ + { 23, "Digital Out1 Playback" }, /* FU */ /* FIXME: corresponds to 24 */ + /* 24: OT digital out */ + { 25, "Digital Out2 Playback" }, /* FU */ /* FIXME: corresponds to 26 */ + /* 26: OT digital out */ + { 27, "Output Extension" }, /* EU */ /* FIXME: what? */ + /* 28: FU (mute) */ + { 0 } /* terminator */ +}; + + +/* + * Control map entries + */ + +static struct usbmix_ctl_map usbmix_ctl_maps[] = { + { 0x41e, 0x3000, extigy_map }, + { 0 } /* terminator */ +}; + |
