Loading sound/drivers/dummy.c +180 −110 Original line number Diff line number Diff line Loading @@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); #define MAX_PCM_SUBSTREAMS 128 #define MAX_MIDI_DEVICES 2 #if 0 /* emu10k1 emulation */ #define MAX_BUFFER_SIZE (128 * 1024) static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) { int err; err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); if (err < 0) return err; return 0; } #define add_playback_constraints emu10k1_playback_constraints #endif #if 0 /* RME9652 emulation */ #define MAX_BUFFER_SIZE (26 * 64 * 1024) #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE #define USE_CHANNELS_MIN 26 #define USE_CHANNELS_MAX 26 #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 2 #endif #if 0 /* ICE1712 emulation */ #define MAX_BUFFER_SIZE (256 * 1024) #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE #define USE_CHANNELS_MIN 10 #define USE_CHANNELS_MAX 10 #define USE_PERIODS_MIN 1 #define USE_PERIODS_MAX 1024 #endif #if 0 /* UDA1341 emulation */ #define MAX_BUFFER_SIZE (16380) #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 255 #endif #if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_RATE SNDRV_PCM_RATE_48000 #define USE_RATE_MIN 48000 #define USE_RATE_MAX 48000 #endif #if 0 /* CA0106 */ #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) #define USE_RATE_MIN 48000 #define USE_RATE_MAX 192000 #define MAX_BUFFER_SIZE ((65536-64)*8) #define MAX_PERIOD_SIZE (65536-64) #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 8 #endif /* defaults */ #ifndef MAX_BUFFER_SIZE #define MAX_BUFFER_SIZE (64*1024) #endif #ifndef MAX_PERIOD_SIZE #define MIN_PERIOD_SIZE 64 #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE #endif #ifndef USE_FORMATS #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) #endif #ifndef USE_RATE #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 #define USE_RATE_MIN 5500 #define USE_RATE_MAX 48000 #endif #ifndef USE_CHANNELS_MIN #define USE_CHANNELS_MIN 1 #endif #ifndef USE_CHANNELS_MAX #define USE_CHANNELS_MAX 2 #endif #ifndef USE_PERIODS_MIN #define USE_PERIODS_MIN 1 #endif #ifndef USE_PERIODS_MAX #define USE_PERIODS_MAX 1024 #endif #ifndef add_playback_constraints #define add_playback_constraints(x) 0 #endif #ifndef add_capture_constraints #define add_capture_constraints(x) 0 #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; Loading @@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for dummy soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Soundcard model."); module_param_array(pcm_devs, int, NULL, 0444); MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); module_param_array(pcm_substreams, int, NULL, 0444); Loading Loading @@ -193,15 +109,120 @@ struct dummy_timer_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); }; struct dummy_model { const char *name; int (*playback_constraints)(struct snd_pcm_runtime *runtime); int (*capture_constraints)(struct snd_pcm_runtime *runtime); u64 formats; size_t buffer_bytes_max; size_t period_bytes_min; size_t period_bytes_max; unsigned int periods_min; unsigned int periods_max; unsigned int rates; unsigned int rate_min; unsigned int rate_max; unsigned int channels_min; unsigned int channels_max; }; struct snd_dummy { struct snd_card *card; struct dummy_model *model; struct snd_pcm *pcm; struct snd_pcm_hardware pcm_hw; spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; const struct dummy_timer_ops *timer_ops; }; /* * card models */ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) { int err; err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); if (err < 0) return err; return 0; } struct dummy_model model_emu10k1 = { .name = "emu10k1", .playback_constraints = emu10k1_playback_constraints, .buffer_bytes_max = 128 * 1024, }; struct dummy_model model_rme9652 = { .name = "rme9652", .buffer_bytes_max = 26 * 64 * 1024, .formats = SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 26, .channels_max = 26, .periods_min = 2, .periods_max = 2, }; struct dummy_model model_ice1712 = { .name = "ice1712", .buffer_bytes_max = 256 * 1024, .formats = SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 10, .channels_max = 10, .periods_min = 1, .periods_max = 1024, }; struct dummy_model model_uda1341 = { .name = "uda1341", .buffer_bytes_max = 16380, .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, .channels_max = 2, .periods_min = 2, .periods_max = 255, }; struct dummy_model model_ac97 = { .name = "ac97", .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, }; struct dummy_model model_ca0106 = { .name = "ca0106", .formats = SNDRV_PCM_FMTBIT_S16_LE, .buffer_bytes_max = ((65536-64)*8), .period_bytes_max = (65536-64), .periods_min = 2, .periods_max = 8, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000, .rate_min = 48000, .rate_max = 192000, }; struct dummy_model *dummy_models[] = { &model_emu10k1, &model_rme9652, &model_ice1712, &model_uda1341, &model_ac97, &model_ca0106, NULL }; /* * system timer interface */ Loading Loading @@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { .channels_min = USE_CHANNELS_MIN, .channels_max = USE_CHANNELS_MAX, .buffer_bytes_max = MAX_BUFFER_SIZE, .period_bytes_min = 64, .period_bytes_min = MIN_PERIOD_SIZE, .period_bytes_max = MAX_PERIOD_SIZE, .periods_min = USE_PERIODS_MIN, .periods_max = USE_PERIODS_MAX, Loading Loading @@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) static int dummy_pcm_open(struct snd_pcm_substream *substream) { struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct dummy_model *model = dummy->model; struct snd_pcm_runtime *runtime = substream->runtime; int err; Loading @@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) if (err < 0) return err; runtime->hw = dummy_pcm_hardware; runtime->hw = dummy->pcm_hw; if (substream->pcm->device & 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; Loading @@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = add_playback_constraints(substream->runtime); else err = add_capture_constraints(substream->runtime); if (model == NULL) return 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (model->playback_constraints) err = model->playback_constraints(substream->runtime); } else { if (model->capture_constraints) err = model->capture_constraints(substream->runtime); } if (err < 0) { dummy->timer_ops->free(substream); return err; Loading Loading @@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) /* * proc interface */ static void print_formats(struct snd_info_buffer *buffer) static void print_formats(struct snd_dummy *dummy, struct snd_info_buffer *buffer) { int i; for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { if (dummy_pcm_hardware.formats & (1ULL << i)) if (dummy->pcm_hw.formats & (1ULL << i)) snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); } } static void print_rates(struct snd_info_buffer *buffer) static void print_rates(struct snd_dummy *dummy, struct snd_info_buffer *buffer) { static int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, Loading @@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer) }; int i; if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS) snd_iprintf(buffer, " continuous"); if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT) snd_iprintf(buffer, " knot"); for (i = 0; i < ARRAY_SIZE(rates); i++) if (dummy_pcm_hardware.rates & (1 << i)) if (dummy->pcm_hw.rates & (1 << i)) snd_iprintf(buffer, " %d", rates[i]); } #define get_dummy_int_ptr(ofs) \ (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) #define get_dummy_ll_ptr(ofs) \ (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) #define get_dummy_int_ptr(dummy, ofs) \ (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs)) #define get_dummy_ll_ptr(dummy, ofs) \ (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs)) struct dummy_hw_field { const char *name; Loading Loading @@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = { static void dummy_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dummy *dummy = entry->private_data; int i; for (i = 0; i < ARRAY_SIZE(fields); i++) { snd_iprintf(buffer, "%s ", fields[i].name); if (fields[i].size == sizeof(int)) snd_iprintf(buffer, fields[i].format, *get_dummy_int_ptr(fields[i].offset)); *get_dummy_int_ptr(dummy, fields[i].offset)); else snd_iprintf(buffer, fields[i].format, *get_dummy_ll_ptr(fields[i].offset)); *get_dummy_ll_ptr(dummy, fields[i].offset)); if (!strcmp(fields[i].name, "formats")) print_formats(buffer); print_formats(dummy, buffer); else if (!strcmp(fields[i].name, "rates")) print_rates(buffer); print_rates(dummy, buffer); snd_iprintf(buffer, "\n"); } } Loading @@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry, static void dummy_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dummy *dummy = entry->private_data; char line[64]; while (!snd_info_get_line(buffer, line, sizeof(line))) { Loading @@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry, if (strict_strtoull(item, 0, &val)) continue; if (fields[i].size == sizeof(int)) *get_dummy_int_ptr(fields[i].offset) = val; *get_dummy_int_ptr(dummy, fields[i].offset) = val; else *get_dummy_ll_ptr(fields[i].offset) = val; *get_dummy_ll_ptr(dummy, fields[i].offset) = val; } } Loading @@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) snd_info_set_text_ops(entry, chip, dummy_proc_read); entry->c.text.write = dummy_proc_write; entry->mode |= S_IWUSR; entry->private_data = chip; } } #else Loading @@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_dummy *dummy; struct dummy_model *m = NULL, **mdl; int idx, err; int dev = devptr->id; Loading @@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) return err; dummy = card->private_data; dummy->card = card; for (mdl = dummy_models; *mdl && model[dev]; mdl++) { if (strcmp(model[dev], (*mdl)->name) == 0) { printk(KERN_INFO "snd-dummy: Using model '%s' for card %i\n", (*mdl)->name, card->number); m = dummy->model = *mdl; break; } } for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { if (pcm_substreams[dev] < 1) pcm_substreams[dev] = 1; Loading @@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) if (err < 0) goto __nodev; } dummy->pcm_hw = dummy_pcm_hardware; if (m) { if (m->formats) dummy->pcm_hw.formats = m->formats; if (m->buffer_bytes_max) dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max; if (m->period_bytes_min) dummy->pcm_hw.period_bytes_min = m->period_bytes_min; if (m->period_bytes_max) dummy->pcm_hw.period_bytes_max = m->period_bytes_max; if (m->periods_min) dummy->pcm_hw.periods_min = m->periods_min; if (m->periods_max) dummy->pcm_hw.periods_max = m->periods_max; if (m->rates) dummy->pcm_hw.rates = m->rates; if (m->rate_min) dummy->pcm_hw.rate_min = m->rate_min; if (m->rate_max) dummy->pcm_hw.rate_max = m->rate_max; if (m->channels_min) dummy->pcm_hw.channels_min = m->channels_min; if (m->channels_max) dummy->pcm_hw.channels_max = m->channels_max; } err = snd_card_dummy_new_mixer(dummy); if (err < 0) goto __nodev; Loading sound/usb/usbmixer.c +76 −49 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ struct usb_mixer_elem_info { int channels; int val_type; int min, max, res; int dBmin, dBmax; int cached; int cache_val[MAX_CHANNELS]; u8 initialized; Loading Loading @@ -209,42 +210,50 @@ enum { */ #include "usbmixer_maps.c" /* get the mapped name if the unit matches */ static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) static const struct usbmix_name_map * find_map(struct mixer_build *state, int unitid, int control) { const struct usbmix_name_map *p; const struct usbmix_name_map *p = state->map; if (! state->map) return 0; if (!p) return NULL; for (p = state->map; p->id; p++) { if (p->id == unitid && p->name && (! control || ! p->control || control == p->control)) { buflen--; return strlcpy(buf, p->name, buflen); if (p->id == unitid && (!control || !p->control || control == p->control)) return p; } return NULL; } /* get the mapped name if the unit matches */ static int check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) { if (!p || !p->name) return 0; buflen--; return strlcpy(buf, p->name, buflen); } /* check whether the control should be ignored */ static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) static inline int check_ignored_ctl(const struct usbmix_name_map *p) { const struct usbmix_name_map *p; if (! state->map) if (!p || p->name || p->dB) return 0; for (p = state->map; p->id; p++) { if (p->id == unitid && ! p->name && (! control || ! p->control || control == p->control)) { /* printk(KERN_DEBUG "ignored control %d:%d\n", unitid, control); */ return 1; } /* dB mapping */ static inline void check_mapped_dB(const struct usbmix_name_map *p, struct usb_mixer_elem_info *cval) { if (p && p->dB) { cval->dBmin = p->dB->min; cval->dBmax = p->dB->max; } return 0; } /* get the mapped selector source name */ Loading Loading @@ -481,20 +490,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, if (size < sizeof(scale)) return -ENOMEM; /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; if (scale[3] <= scale[2]) { /* something is wrong; assume it's either from/to 0dB */ if (scale[2] < 0) scale[3] = 0; else if (scale[2] > 0) scale[2] = 0; else /* totally crap, return an error */ return -EINVAL; } scale[2] = cval->dBmin; scale[3] = cval->dBmax; if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; Loading Loading @@ -735,6 +732,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->min = default_min; cval->max = cval->min + 1; cval->res = 1; cval->dBmin = cval->dBmax = 0; if (cval->val_type == USB_MIXER_BOOLEAN || cval->val_type == USB_MIXER_INV_BOOLEAN) { Loading Loading @@ -802,6 +800,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->initialized = 1; } /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; if (cval->dBmin > cval->dBmax) { /* something is wrong; assume it's either from/to 0dB */ if (cval->dBmin < 0) cval->dBmax = 0; else if (cval->dBmin > 0) cval->dBmin = 0; if (cval->dBmin > cval->dBmax) { /* totally crap, return an error */ return -EINVAL; } } return 0; } Loading Loading @@ -927,6 +943,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, int nameid = desc[desc[0] - 1]; struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; const struct usbmix_name_map *map; control++; /* change from zero-based to 1-based value */ Loading @@ -935,7 +952,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, return; } if (check_ignored_ctl(state, unitid, control)) map = find_map(state, unitid, control); if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -969,10 +987,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, 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)); len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); switch (control) { case USB_FEATURE_MUTE: Loading Loading @@ -1010,6 +1029,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; check_mapped_dB(map, cval); } break; Loading Loading @@ -1137,8 +1157,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, unsigned int num_outs = desc[5 + input_pins]; unsigned int i, len; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -1167,7 +1189,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, 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) Loading Loading @@ -1382,6 +1404,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned int i, err, nameid, type, len; struct procunit_info *info; struct procunit_value_info *valinfo; const struct usbmix_name_map *map; static struct procunit_value_info default_value_info[] = { { 0x01, "Switch", USB_MIXER_BOOLEAN }, { 0 } Loading Loading @@ -1411,7 +1434,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned /* FIXME: bitmap might be longer than 8bit */ if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) continue; if (check_ignored_ctl(state, unitid, valinfo->control)) map = find_map(state, unitid, valinfo->control); if (check_ignored_ctl(map)) continue; cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { Loading Loading @@ -1452,8 +1476,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned } kctl->private_free = usb_mixer_elem_free; if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) ; if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) /* nothing */ ; else if (info->name) strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); else { Loading Loading @@ -1592,6 +1617,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi int err; struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; char **namelist; if (! num_ins || desc[0] < 5 + num_ins) { Loading @@ -1607,7 +1633,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi if (num_ins == 1) /* only one ? nonsense! */ return 0; if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return 0; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -1662,7 +1689,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi kctl->private_free = usb_mixer_selector_elem_free; nameid = desc[desc[0] - 1]; len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (len) ; else if (nameid) Loading sound/usb/usbmixer_maps.c +17 −6 Original line number Diff line number Diff line Loading @@ -19,11 +19,16 @@ * */ struct usbmix_dB_map { u32 min; u32 max; }; struct usbmix_name_map { int id; const char *name; int control; struct usbmix_dB_map *dB; }; struct usbmix_selector_map { Loading Loading @@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { { 8, "Line Playback" }, /* FU */ /* 9: IT mic */ { 10, "Mic Playback" }, /* FU */ { 11, "Capture Input Source" }, /* SU */ { 11, "Capture Source" }, /* SU */ { 12, "Capture" }, /* FU */ /* 13: OT pcm capture */ /* 14: MU (w/o controls) */ Loading Loading @@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { * e.g. no Master and fake PCM volume * Pavel Mihaylov <bin@bash.info> */ static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ static struct usbmix_name_map mp3plus_map[] = { /* 1: IT pcm */ /* 2: IT mic */ Loading @@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { /* 5: OT digital out */ /* 6: OT speaker */ /* 7: OT pcm capture */ { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ { 8, "Capture Source" }, /* FU, default PCM Capture Source */ /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ { 9, "Master Playback" }, /* FU, default Speaker 1 */ /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 }, /* FU, Mic Capture */ { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ { 11, "Line Capture" }, /* FU, default PCM Capture */ { 11, "Line Capture", .dB = &mp3plus_dB_2 }, /* FU, default PCM Capture */ { 12, "Digital In Playback" }, /* FU, default PCM 1 */ /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ { 14, "Line Playback" }, /* FU, default Speaker */ { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 }, /* FU, default Mic Playback */ { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */ /* 15: MU */ { 0 } /* terminator */ }; Loading Loading
sound/drivers/dummy.c +180 −110 Original line number Diff line number Diff line Loading @@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); #define MAX_PCM_SUBSTREAMS 128 #define MAX_MIDI_DEVICES 2 #if 0 /* emu10k1 emulation */ #define MAX_BUFFER_SIZE (128 * 1024) static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) { int err; err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); if (err < 0) return err; return 0; } #define add_playback_constraints emu10k1_playback_constraints #endif #if 0 /* RME9652 emulation */ #define MAX_BUFFER_SIZE (26 * 64 * 1024) #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE #define USE_CHANNELS_MIN 26 #define USE_CHANNELS_MAX 26 #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 2 #endif #if 0 /* ICE1712 emulation */ #define MAX_BUFFER_SIZE (256 * 1024) #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE #define USE_CHANNELS_MIN 10 #define USE_CHANNELS_MAX 10 #define USE_PERIODS_MIN 1 #define USE_PERIODS_MAX 1024 #endif #if 0 /* UDA1341 emulation */ #define MAX_BUFFER_SIZE (16380) #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 255 #endif #if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_RATE SNDRV_PCM_RATE_48000 #define USE_RATE_MIN 48000 #define USE_RATE_MAX 48000 #endif #if 0 /* CA0106 */ #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE #define USE_CHANNELS_MIN 2 #define USE_CHANNELS_MAX 2 #define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) #define USE_RATE_MIN 48000 #define USE_RATE_MAX 192000 #define MAX_BUFFER_SIZE ((65536-64)*8) #define MAX_PERIOD_SIZE (65536-64) #define USE_PERIODS_MIN 2 #define USE_PERIODS_MAX 8 #endif /* defaults */ #ifndef MAX_BUFFER_SIZE #define MAX_BUFFER_SIZE (64*1024) #endif #ifndef MAX_PERIOD_SIZE #define MIN_PERIOD_SIZE 64 #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE #endif #ifndef USE_FORMATS #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) #endif #ifndef USE_RATE #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 #define USE_RATE_MIN 5500 #define USE_RATE_MAX 48000 #endif #ifndef USE_CHANNELS_MIN #define USE_CHANNELS_MIN 1 #endif #ifndef USE_CHANNELS_MAX #define USE_CHANNELS_MAX 2 #endif #ifndef USE_PERIODS_MIN #define USE_PERIODS_MIN 1 #endif #ifndef USE_PERIODS_MAX #define USE_PERIODS_MAX 1024 #endif #ifndef add_playback_constraints #define add_playback_constraints(x) 0 #endif #ifndef add_capture_constraints #define add_capture_constraints(x) 0 #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; Loading @@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for dummy soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Soundcard model."); module_param_array(pcm_devs, int, NULL, 0444); MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); module_param_array(pcm_substreams, int, NULL, 0444); Loading Loading @@ -193,15 +109,120 @@ struct dummy_timer_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); }; struct dummy_model { const char *name; int (*playback_constraints)(struct snd_pcm_runtime *runtime); int (*capture_constraints)(struct snd_pcm_runtime *runtime); u64 formats; size_t buffer_bytes_max; size_t period_bytes_min; size_t period_bytes_max; unsigned int periods_min; unsigned int periods_max; unsigned int rates; unsigned int rate_min; unsigned int rate_max; unsigned int channels_min; unsigned int channels_max; }; struct snd_dummy { struct snd_card *card; struct dummy_model *model; struct snd_pcm *pcm; struct snd_pcm_hardware pcm_hw; spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; const struct dummy_timer_ops *timer_ops; }; /* * card models */ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) { int err; err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); if (err < 0) return err; return 0; } struct dummy_model model_emu10k1 = { .name = "emu10k1", .playback_constraints = emu10k1_playback_constraints, .buffer_bytes_max = 128 * 1024, }; struct dummy_model model_rme9652 = { .name = "rme9652", .buffer_bytes_max = 26 * 64 * 1024, .formats = SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 26, .channels_max = 26, .periods_min = 2, .periods_max = 2, }; struct dummy_model model_ice1712 = { .name = "ice1712", .buffer_bytes_max = 256 * 1024, .formats = SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 10, .channels_max = 10, .periods_min = 1, .periods_max = 1024, }; struct dummy_model model_uda1341 = { .name = "uda1341", .buffer_bytes_max = 16380, .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, .channels_max = 2, .periods_min = 2, .periods_max = 255, }; struct dummy_model model_ac97 = { .name = "ac97", .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, }; struct dummy_model model_ca0106 = { .name = "ca0106", .formats = SNDRV_PCM_FMTBIT_S16_LE, .buffer_bytes_max = ((65536-64)*8), .period_bytes_max = (65536-64), .periods_min = 2, .periods_max = 8, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000, .rate_min = 48000, .rate_max = 192000, }; struct dummy_model *dummy_models[] = { &model_emu10k1, &model_rme9652, &model_ice1712, &model_uda1341, &model_ac97, &model_ca0106, NULL }; /* * system timer interface */ Loading Loading @@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { .channels_min = USE_CHANNELS_MIN, .channels_max = USE_CHANNELS_MAX, .buffer_bytes_max = MAX_BUFFER_SIZE, .period_bytes_min = 64, .period_bytes_min = MIN_PERIOD_SIZE, .period_bytes_max = MAX_PERIOD_SIZE, .periods_min = USE_PERIODS_MIN, .periods_max = USE_PERIODS_MAX, Loading Loading @@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) static int dummy_pcm_open(struct snd_pcm_substream *substream) { struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct dummy_model *model = dummy->model; struct snd_pcm_runtime *runtime = substream->runtime; int err; Loading @@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) if (err < 0) return err; runtime->hw = dummy_pcm_hardware; runtime->hw = dummy->pcm_hw; if (substream->pcm->device & 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; Loading @@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) err = add_playback_constraints(substream->runtime); else err = add_capture_constraints(substream->runtime); if (model == NULL) return 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (model->playback_constraints) err = model->playback_constraints(substream->runtime); } else { if (model->capture_constraints) err = model->capture_constraints(substream->runtime); } if (err < 0) { dummy->timer_ops->free(substream); return err; Loading Loading @@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) /* * proc interface */ static void print_formats(struct snd_info_buffer *buffer) static void print_formats(struct snd_dummy *dummy, struct snd_info_buffer *buffer) { int i; for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { if (dummy_pcm_hardware.formats & (1ULL << i)) if (dummy->pcm_hw.formats & (1ULL << i)) snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); } } static void print_rates(struct snd_info_buffer *buffer) static void print_rates(struct snd_dummy *dummy, struct snd_info_buffer *buffer) { static int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, Loading @@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer) }; int i; if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS) snd_iprintf(buffer, " continuous"); if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT) snd_iprintf(buffer, " knot"); for (i = 0; i < ARRAY_SIZE(rates); i++) if (dummy_pcm_hardware.rates & (1 << i)) if (dummy->pcm_hw.rates & (1 << i)) snd_iprintf(buffer, " %d", rates[i]); } #define get_dummy_int_ptr(ofs) \ (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) #define get_dummy_ll_ptr(ofs) \ (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) #define get_dummy_int_ptr(dummy, ofs) \ (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs)) #define get_dummy_ll_ptr(dummy, ofs) \ (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs)) struct dummy_hw_field { const char *name; Loading Loading @@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = { static void dummy_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dummy *dummy = entry->private_data; int i; for (i = 0; i < ARRAY_SIZE(fields); i++) { snd_iprintf(buffer, "%s ", fields[i].name); if (fields[i].size == sizeof(int)) snd_iprintf(buffer, fields[i].format, *get_dummy_int_ptr(fields[i].offset)); *get_dummy_int_ptr(dummy, fields[i].offset)); else snd_iprintf(buffer, fields[i].format, *get_dummy_ll_ptr(fields[i].offset)); *get_dummy_ll_ptr(dummy, fields[i].offset)); if (!strcmp(fields[i].name, "formats")) print_formats(buffer); print_formats(dummy, buffer); else if (!strcmp(fields[i].name, "rates")) print_rates(buffer); print_rates(dummy, buffer); snd_iprintf(buffer, "\n"); } } Loading @@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry, static void dummy_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dummy *dummy = entry->private_data; char line[64]; while (!snd_info_get_line(buffer, line, sizeof(line))) { Loading @@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry, if (strict_strtoull(item, 0, &val)) continue; if (fields[i].size == sizeof(int)) *get_dummy_int_ptr(fields[i].offset) = val; *get_dummy_int_ptr(dummy, fields[i].offset) = val; else *get_dummy_ll_ptr(fields[i].offset) = val; *get_dummy_ll_ptr(dummy, fields[i].offset) = val; } } Loading @@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) snd_info_set_text_ops(entry, chip, dummy_proc_read); entry->c.text.write = dummy_proc_write; entry->mode |= S_IWUSR; entry->private_data = chip; } } #else Loading @@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) { struct snd_card *card; struct snd_dummy *dummy; struct dummy_model *m = NULL, **mdl; int idx, err; int dev = devptr->id; Loading @@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) return err; dummy = card->private_data; dummy->card = card; for (mdl = dummy_models; *mdl && model[dev]; mdl++) { if (strcmp(model[dev], (*mdl)->name) == 0) { printk(KERN_INFO "snd-dummy: Using model '%s' for card %i\n", (*mdl)->name, card->number); m = dummy->model = *mdl; break; } } for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { if (pcm_substreams[dev] < 1) pcm_substreams[dev] = 1; Loading @@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) if (err < 0) goto __nodev; } dummy->pcm_hw = dummy_pcm_hardware; if (m) { if (m->formats) dummy->pcm_hw.formats = m->formats; if (m->buffer_bytes_max) dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max; if (m->period_bytes_min) dummy->pcm_hw.period_bytes_min = m->period_bytes_min; if (m->period_bytes_max) dummy->pcm_hw.period_bytes_max = m->period_bytes_max; if (m->periods_min) dummy->pcm_hw.periods_min = m->periods_min; if (m->periods_max) dummy->pcm_hw.periods_max = m->periods_max; if (m->rates) dummy->pcm_hw.rates = m->rates; if (m->rate_min) dummy->pcm_hw.rate_min = m->rate_min; if (m->rate_max) dummy->pcm_hw.rate_max = m->rate_max; if (m->channels_min) dummy->pcm_hw.channels_min = m->channels_min; if (m->channels_max) dummy->pcm_hw.channels_max = m->channels_max; } err = snd_card_dummy_new_mixer(dummy); if (err < 0) goto __nodev; Loading
sound/usb/usbmixer.c +76 −49 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ struct usb_mixer_elem_info { int channels; int val_type; int min, max, res; int dBmin, dBmax; int cached; int cache_val[MAX_CHANNELS]; u8 initialized; Loading Loading @@ -209,42 +210,50 @@ enum { */ #include "usbmixer_maps.c" /* get the mapped name if the unit matches */ static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) static const struct usbmix_name_map * find_map(struct mixer_build *state, int unitid, int control) { const struct usbmix_name_map *p; const struct usbmix_name_map *p = state->map; if (! state->map) return 0; if (!p) return NULL; for (p = state->map; p->id; p++) { if (p->id == unitid && p->name && (! control || ! p->control || control == p->control)) { buflen--; return strlcpy(buf, p->name, buflen); if (p->id == unitid && (!control || !p->control || control == p->control)) return p; } return NULL; } /* get the mapped name if the unit matches */ static int check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) { if (!p || !p->name) return 0; buflen--; return strlcpy(buf, p->name, buflen); } /* check whether the control should be ignored */ static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) static inline int check_ignored_ctl(const struct usbmix_name_map *p) { const struct usbmix_name_map *p; if (! state->map) if (!p || p->name || p->dB) return 0; for (p = state->map; p->id; p++) { if (p->id == unitid && ! p->name && (! control || ! p->control || control == p->control)) { /* printk(KERN_DEBUG "ignored control %d:%d\n", unitid, control); */ return 1; } /* dB mapping */ static inline void check_mapped_dB(const struct usbmix_name_map *p, struct usb_mixer_elem_info *cval) { if (p && p->dB) { cval->dBmin = p->dB->min; cval->dBmax = p->dB->max; } return 0; } /* get the mapped selector source name */ Loading Loading @@ -481,20 +490,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, if (size < sizeof(scale)) return -ENOMEM; /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; if (scale[3] <= scale[2]) { /* something is wrong; assume it's either from/to 0dB */ if (scale[2] < 0) scale[3] = 0; else if (scale[2] > 0) scale[2] = 0; else /* totally crap, return an error */ return -EINVAL; } scale[2] = cval->dBmin; scale[3] = cval->dBmax; if (copy_to_user(_tlv, scale, sizeof(scale))) return -EFAULT; return 0; Loading Loading @@ -735,6 +732,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->min = default_min; cval->max = cval->min + 1; cval->res = 1; cval->dBmin = cval->dBmax = 0; if (cval->val_type == USB_MIXER_BOOLEAN || cval->val_type == USB_MIXER_INV_BOOLEAN) { Loading Loading @@ -802,6 +800,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->initialized = 1; } /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; if (cval->dBmin > cval->dBmax) { /* something is wrong; assume it's either from/to 0dB */ if (cval->dBmin < 0) cval->dBmax = 0; else if (cval->dBmin > 0) cval->dBmin = 0; if (cval->dBmin > cval->dBmax) { /* totally crap, return an error */ return -EINVAL; } } return 0; } Loading Loading @@ -927,6 +943,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, int nameid = desc[desc[0] - 1]; struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; const struct usbmix_name_map *map; control++; /* change from zero-based to 1-based value */ Loading @@ -935,7 +952,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, return; } if (check_ignored_ctl(state, unitid, control)) map = find_map(state, unitid, control); if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -969,10 +987,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, 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)); len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); switch (control) { case USB_FEATURE_MUTE: Loading Loading @@ -1010,6 +1029,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; check_mapped_dB(map, cval); } break; Loading Loading @@ -1137,8 +1157,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, unsigned int num_outs = desc[5 + input_pins]; unsigned int i, len; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -1167,7 +1189,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, } kctl->private_free = usb_mixer_elem_free; len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, 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) Loading Loading @@ -1382,6 +1404,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned int i, err, nameid, type, len; struct procunit_info *info; struct procunit_value_info *valinfo; const struct usbmix_name_map *map; static struct procunit_value_info default_value_info[] = { { 0x01, "Switch", USB_MIXER_BOOLEAN }, { 0 } Loading Loading @@ -1411,7 +1434,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned /* FIXME: bitmap might be longer than 8bit */ if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) continue; if (check_ignored_ctl(state, unitid, valinfo->control)) map = find_map(state, unitid, valinfo->control); if (check_ignored_ctl(map)) continue; cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { Loading Loading @@ -1452,8 +1476,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned } kctl->private_free = usb_mixer_elem_free; if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) ; if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) /* nothing */ ; else if (info->name) strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); else { Loading Loading @@ -1592,6 +1617,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi int err; struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; char **namelist; if (! num_ins || desc[0] < 5 + num_ins) { Loading @@ -1607,7 +1633,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi if (num_ins == 1) /* only one ? nonsense! */ return 0; if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return 0; cval = kzalloc(sizeof(*cval), GFP_KERNEL); Loading Loading @@ -1662,7 +1689,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi kctl->private_free = usb_mixer_selector_elem_free; nameid = desc[desc[0] - 1]; len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (len) ; else if (nameid) Loading
sound/usb/usbmixer_maps.c +17 −6 Original line number Diff line number Diff line Loading @@ -19,11 +19,16 @@ * */ struct usbmix_dB_map { u32 min; u32 max; }; struct usbmix_name_map { int id; const char *name; int control; struct usbmix_dB_map *dB; }; struct usbmix_selector_map { Loading Loading @@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { { 8, "Line Playback" }, /* FU */ /* 9: IT mic */ { 10, "Mic Playback" }, /* FU */ { 11, "Capture Input Source" }, /* SU */ { 11, "Capture Source" }, /* SU */ { 12, "Capture" }, /* FU */ /* 13: OT pcm capture */ /* 14: MU (w/o controls) */ Loading Loading @@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { * e.g. no Master and fake PCM volume * Pavel Mihaylov <bin@bash.info> */ static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ static struct usbmix_name_map mp3plus_map[] = { /* 1: IT pcm */ /* 2: IT mic */ Loading @@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { /* 5: OT digital out */ /* 6: OT speaker */ /* 7: OT pcm capture */ { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ { 8, "Capture Source" }, /* FU, default PCM Capture Source */ /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ { 9, "Master Playback" }, /* FU, default Speaker 1 */ /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 }, /* FU, Mic Capture */ { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ { 11, "Line Capture" }, /* FU, default PCM Capture */ { 11, "Line Capture", .dB = &mp3plus_dB_2 }, /* FU, default PCM Capture */ { 12, "Digital In Playback" }, /* FU, default PCM 1 */ /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ { 14, "Line Playback" }, /* FU, default Speaker */ { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 }, /* FU, default Mic Playback */ { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */ /* 15: MU */ { 0 } /* terminator */ }; Loading