summaryrefslogtreecommitdiff
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usbaudio.c54
-rw-r--r--sound/usb/usbmixer.c27
-rw-r--r--sound/usb/usbmixer_maps.c24
-rw-r--r--sound/usb/usbquirks.h5
4 files changed, 106 insertions, 4 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 1b7f499c549d..49248fa7aef4 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(&register_mutex);
- snd_card_free(card);
+ snd_card_free_when_closed(card);
} else {
mutex_unlock(&register_mutex);
}
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 491e975a0c87..e516d6adbb22 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 37accb68652d..7c4dcb3f436a 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 9351846d7a9d..a7e9563a01df 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