diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/usbaudio.c | 54 | ||||
-rw-r--r-- | sound/usb/usbmixer.c | 27 | ||||
-rw-r--r-- | sound/usb/usbmixer_maps.c | 24 | ||||
-rw-r--r-- | sound/usb/usbquirks.h | 5 |
4 files changed, 106 insertions, 4 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 1b7f499c549..49248fa7aef 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -68,7 +68,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ -static int nrpacks = 4; /* max. number of packets per urb */ +static int nrpacks = 8; /* max. number of packets per urb */ static int async_unlink = 1; static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ @@ -100,7 +100,7 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); * */ -#define MAX_PACKS 10 +#define MAX_PACKS 20 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ #define MAX_URBS 8 #define SYNC_URBS 4 /* always four urbs for sync */ @@ -123,6 +123,7 @@ struct audioformat { unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ + unsigned int needs_knot; /* any unusual rates? */ }; struct snd_usb_substream; @@ -1759,6 +1760,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) } channels[f->format] |= (1 << f->channels); rates[f->format] |= f->rates; + /* needs knot? */ + if (f->needs_knot) + goto __out; } /* check whether channels and rates match for all formats */ cmaster = rmaster = 0; @@ -1799,6 +1803,38 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) return err; } +/* + * If the device supports unusual bit rates, does the request meet these? + */ +static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, + struct snd_usb_substream *subs) +{ + struct list_head *p; + struct snd_pcm_hw_constraint_list constraints_rates; + int err; + + list_for_each(p, &subs->fmt_list) { + struct audioformat *fp; + fp = list_entry(p, struct audioformat, list); + + if (!fp->needs_knot) + continue; + + constraints_rates.count = fp->nr_rates; + constraints_rates.list = fp->rate_table; + constraints_rates.mask = 0; + + err = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + if (err < 0) + return err; + } + + return 0; +} + /* * set up the runtime hardware information. @@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) return err; + if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) + return err; } return 0; } @@ -2049,7 +2087,7 @@ static struct usb_driver usb_audio_driver = { }; -#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS) +#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS) /* * proc interface for list the supported pcm formats @@ -2406,6 +2444,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; + int found; if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", chip->dev->devnum, fp->iface, fp->altsetting); @@ -2428,6 +2467,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform return -1; } + fp->needs_knot = 0; fp->nr_rates = nr_rates; fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { @@ -2436,13 +2476,19 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform fp->rate_min = rate; else if (rate > fp->rate_max) fp->rate_max = rate; + found = 0; for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { if (rate == conv_rates[c]) { + found = 1; fp->rates |= (1 << c); break; } } + if (!found) + fp->needs_knot = 1; } + if (fp->needs_knot) + fp->rates |= SNDRV_PCM_RATE_KNOT; } else { /* continuous rates */ fp->rates = SNDRV_PCM_RATE_CONTINUOUS; @@ -3499,7 +3545,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) } usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); - snd_card_free(card); + snd_card_free_when_closed(card); } else { mutex_unlock(®ister_mutex); } diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 491e975a0c8..e516d6adbb2 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -37,6 +37,7 @@ #include <sound/control.h> #include <sound/hwdep.h> #include <sound/info.h> +#include <sound/tlv.h> #include "usbaudio.h" @@ -416,6 +417,26 @@ static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channe return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); } +/* + * TLV callback for mixer volume controls + */ +static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *_tlv) +{ + struct usb_mixer_elem_info *cval = kcontrol->private_data; + DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); + + 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->res) * 100) / 256; + if (copy_to_user(_tlv, scale, sizeof(scale))) + return -EFAULT; + return 0; +} /* * parser routines begin here... @@ -933,6 +954,12 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, } strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", sizeof(kctl->id.name)); + if (control == USB_FEATURE_VOLUME) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } break; default: diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 37accb68652..7c4dcb3f436 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -234,6 +234,26 @@ static struct usbmix_name_map justlink_map[] = { { 0 } /* terminator */ }; +/* TerraTec Aureon 5.1 MkII USB */ +static struct usbmix_name_map aureon_51_2_map[] = { + /* 1: IT USB */ + /* 2: IT Mic */ + /* 3: IT Line */ + /* 4: IT SPDIF */ + /* 5: OT SPDIF */ + /* 6: OT Speaker */ + /* 7: OT USB */ + { 8, "Capture Source" }, /* SU */ + { 9, "Master Playback" }, /* FU */ + { 10, "Mic Capture" }, /* FU */ + { 11, "Line Capture" }, /* FU */ + { 12, "IEC958 In Capture" }, /* FU */ + { 13, "Mic Playback" }, /* FU */ + { 14, "Line Playback" }, /* FU */ + /* 15: MU */ + {} /* terminator */ +}; + /* * Control map entries */ @@ -276,6 +296,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x0c45, 0x1158), .map = justlink_map, }, + { + .id = USB_ID(0x0ccd, 0x0028), + .map = aureon_51_2_map, + }, { 0 } /* terminator */ }; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 9351846d7a9..a7e9563a01d 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -123,6 +123,10 @@ YAMAHA_DEVICE(0x103e, NULL), YAMAHA_DEVICE(0x103f, NULL), YAMAHA_DEVICE(0x1040, NULL), YAMAHA_DEVICE(0x1041, NULL), +YAMAHA_DEVICE(0x1042, NULL), +YAMAHA_DEVICE(0x1043, NULL), +YAMAHA_DEVICE(0x1044, NULL), +YAMAHA_DEVICE(0x1045, NULL), YAMAHA_DEVICE(0x2000, "DGP-7"), YAMAHA_DEVICE(0x2001, "DGP-5"), YAMAHA_DEVICE(0x2002, NULL), @@ -141,6 +145,7 @@ YAMAHA_DEVICE(0x500b, "DME64N"), YAMAHA_DEVICE(0x500c, "DME24N"), YAMAHA_DEVICE(0x500d, NULL), YAMAHA_DEVICE(0x500e, NULL), +YAMAHA_DEVICE(0x500f, NULL), YAMAHA_DEVICE(0x7000, "DTX"), YAMAHA_DEVICE(0x7010, "UB99"), #undef YAMAHA_DEVICE |