aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/card.c3
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/format.c2
-rw-r--r--sound/usb/line6/driver.c4
-rw-r--r--sound/usb/line6/pod.c3
-rw-r--r--sound/usb/mixer.c42
-rw-r--r--sound/usb/mixer_quirks.c6
-rw-r--r--sound/usb/pcm.c13
-rw-r--r--sound/usb/proc.c14
-rw-r--r--sound/usb/quirks-table.h71
-rw-r--r--sound/usb/quirks.c121
-rw-r--r--sound/usb/stream.c36
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c21
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c19
14 files changed, 273 insertions, 83 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index a105947eaf55..719e10034553 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -246,7 +246,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
h1 = snd_usb_find_csint_desc(host_iface->extra,
host_iface->extralen,
NULL, UAC_HEADER);
- if (!h1) {
+ if (!h1 || h1->bLength < sizeof(*h1)) {
dev_err(&dev->dev, "cannot find UAC_HEADER\n");
return -EINVAL;
}
@@ -811,7 +811,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
if (!chip->num_suspended_intf++) {
list_for_each_entry(as, &chip->pcm_list, list) {
- snd_pcm_suspend_all(as->pcm);
snd_usb_pcm_suspend(as);
as->substream[0].need_setup_ep =
as->substream[1].need_setup_ep = true;
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ac785d15ced4..79fa2a19fb7b 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -14,6 +14,7 @@ struct audioformat {
u64 formats; /* ALSA format bits */
unsigned int channels; /* # channels */
unsigned int fmt_type; /* USB audio format type (1-3) */
+ unsigned int fmt_bits; /* number of significant bits */
unsigned int frame_size; /* samples per frame for non-audio */
int iface; /* interface number */
unsigned char altsetting; /* corresponding alternate setting */
diff --git a/sound/usb/format.c b/sound/usb/format.c
index fd13ac11b136..3ee7d6f853b7 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -87,6 +87,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
}
}
+ fp->fmt_bits = sample_width;
+
if ((pcm_formats == 0) &&
(format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
/* some devices don't define this correctly... */
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index c1376bfdc90b..7afe8fae4939 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -849,10 +849,8 @@ int line6_suspend(struct usb_interface *interface, pm_message_t message)
if (line6->properties->capabilities & LINE6_CAP_CONTROL)
line6_stop_listen(line6);
- if (line6pcm != NULL) {
- snd_pcm_suspend_all(line6pcm->pcm);
+ if (line6pcm != NULL)
line6pcm->flags = 0;
- }
return 0;
}
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
index 020c81818951..ce45b6dab651 100644
--- a/sound/usb/line6/pod.c
+++ b/sound/usb/line6/pod.c
@@ -320,7 +320,8 @@ static void pod_startup4(struct work_struct *work)
line6_read_serial_number(&pod->line6, &pod->serial_number);
/* ALSA audio interface: */
- snd_card_register(line6->card);
+ if (snd_card_register(line6->card))
+ dev_err(line6->ifcdev, "Failed to register POD card.\n");
}
/* POD special files: */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index c63c84b54969..73d7dff425c1 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -753,8 +753,9 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
struct uac_mixer_unit_descriptor *desc)
{
int mu_channels;
+ void *c;
- if (desc->bLength < 11)
+ if (desc->bLength < sizeof(*desc))
return -EINVAL;
if (!desc->bNrInPins)
return -EINVAL;
@@ -763,6 +764,8 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
case UAC_VERSION_1:
case UAC_VERSION_2:
default:
+ if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1)
+ return 0; /* no bmControls -> skip */
mu_channels = uac_mixer_unit_bNrChannels(desc);
break;
case UAC_VERSION_3:
@@ -772,7 +775,11 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
}
if (!mu_channels)
- return -EINVAL;
+ return 0;
+
+ c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
+ if (c - (void *)desc + (mu_channels - 1) / 8 >= desc->bLength)
+ return 0; /* no bmControls -> skip */
return mu_channels;
}
@@ -944,7 +951,7 @@ static int check_input_term(struct mixer_build *state, int id,
struct uac_mixer_unit_descriptor *d = p1;
err = uac_mixer_unit_get_channels(state, d);
- if (err < 0)
+ if (err <= 0)
return err;
term->channels = err;
@@ -1828,7 +1835,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
{
int channels, i, j;
struct usb_audio_term iterm;
- unsigned int master_bits, first_ch_bits;
+ unsigned int master_bits;
int err, csize;
struct uac_feature_unit_descriptor *hdr = _ftr;
__u8 *bmaControls;
@@ -1919,10 +1926,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
break;
}
- if (channels > 0)
- first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
- else
- first_ch_bits = 0;
if (state->mixer->protocol == UAC_VERSION_1) {
/* check all control types */
@@ -2068,11 +2071,15 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid,
if (state->mixer->protocol == UAC_VERSION_2) {
struct uac2_input_terminal_descriptor *d_v2 = raw_desc;
+ if (d_v2->bLength < sizeof(*d_v2))
+ return -EINVAL;
control = UAC2_TE_CONNECTOR;
term_id = d_v2->bTerminalID;
bmctls = le16_to_cpu(d_v2->bmControls);
} else if (state->mixer->protocol == UAC_VERSION_3) {
struct uac3_input_terminal_descriptor *d_v3 = raw_desc;
+ if (d_v3->bLength < sizeof(*d_v3))
+ return -EINVAL;
control = UAC3_TE_INSERTION;
term_id = d_v3->bTerminalID;
bmctls = le32_to_cpu(d_v3->bmControls);
@@ -2118,7 +2125,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
if (err < 0)
continue;
/* no bmControls field (e.g. Maya44) -> ignore */
- if (desc->bLength <= 10 + input_pins)
+ if (!num_outs)
continue;
err = check_input_term(state, desc->baSourceID[pin], &iterm);
if (err < 0)
@@ -2314,7 +2321,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
char *name)
{
struct uac_processing_unit_descriptor *desc = raw_desc;
- int num_ins = desc->bNrInPins;
+ int num_ins;
struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl;
int i, err, nameid, type, len;
@@ -2329,7 +2336,13 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
0, NULL, default_value_info
};
- if (desc->bLength < 13 || desc->bLength < 13 + num_ins ||
+ if (desc->bLength < 13) {
+ usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
+ return -EINVAL;
+ }
+
+ num_ins = desc->bNrInPins;
+ if (desc->bLength < 13 + num_ins ||
desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
return -EINVAL;
@@ -3428,7 +3441,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
.dev_free = snd_usb_mixer_dev_free
};
struct usb_mixer_interface *mixer;
- struct snd_info_entry *entry;
int err;
strcpy(chip->card->mixername, "USB Mixer");
@@ -3484,9 +3496,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
if (err < 0)
goto _error;
- if (list_empty(&chip->mixer_list) &&
- !snd_card_proc_new(chip->card, "usbmixer", &entry))
- snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read);
+ if (list_empty(&chip->mixer_list))
+ snd_card_ro_proc_new(chip->card, "usbmixer", chip,
+ snd_usb_mixer_proc_read);
list_add(&mixer->list, &chip->mixer_list);
return 0;
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 85ae0ff2382a..a751a18ca4c2 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -2195,7 +2195,6 @@ static int snd_rme_controls_create(struct usb_mixer_interface *mixer)
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
{
int err = 0;
- struct snd_info_entry *entry;
err = snd_usb_soundblaster_remote_init(mixer);
if (err < 0)
@@ -2214,9 +2213,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_audigy2nx_controls_create(mixer);
if (err < 0)
break;
- if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
- snd_info_set_text_ops(entry, mixer,
- snd_audigy2nx_proc_read);
+ snd_card_ro_proc_new(mixer->chip->card, "audigy2nx",
+ mixer, snd_audigy2nx_proc_read);
break;
/* EMU0204 */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 382847154227..056af0a57b22 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -314,6 +314,9 @@ static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
return 0;
}
+/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk
+ * applies. Returns 1 if a quirk was found.
+ */
static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
struct usb_device *dev,
struct usb_interface_descriptor *altsd,
@@ -351,6 +354,10 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
ep = 0x81;
ifnum = 1;
goto add_sync_ep_from_ifnum;
+ case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */
+ ep = 0x84;
+ ifnum = 0;
+ goto add_sync_ep_from_ifnum;
}
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
@@ -384,7 +391,7 @@ add_sync_ep:
subs->data_endpoint->sync_master = subs->sync_endpoint;
- return 0;
+ return 1;
}
static int set_sync_endpoint(struct snd_usb_substream *subs,
@@ -423,6 +430,10 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
if (err < 0)
return err;
+ /* endpoint set by quirk */
+ if (err > 0)
+ return 0;
+
if (altsd->bNumEndpoints < 2)
return 0;
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index 0ac89e294d31..ef9190530fd2 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -61,11 +61,10 @@ static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_
void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
{
- struct snd_info_entry *entry;
- if (!snd_card_proc_new(chip->card, "usbbus", &entry))
- snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
- if (!snd_card_proc_new(chip->card, "usbid", &entry))
- snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
+ snd_card_ro_proc_new(chip->card, "usbbus", chip,
+ proc_audio_usbbus_read);
+ snd_card_ro_proc_new(chip->card, "usbid", chip,
+ proc_audio_usbid_read);
}
/*
@@ -110,6 +109,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
if (subs->speed != USB_SPEED_FULL)
snd_iprintf(buffer, " Data packet interval: %d us\n",
125 * (1 << fp->datainterval));
+ snd_iprintf(buffer, " Bits: %d\n", fp->fmt_bits);
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
// snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes);
}
@@ -167,12 +167,10 @@ static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_b
void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream)
{
- struct snd_info_entry *entry;
char name[32];
struct snd_card *card = stream->chip->card;
sprintf(name, "stream%d", stream->pcm_index);
- if (!snd_card_proc_new(card, name, &entry))
- snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
+ snd_card_ro_proc_new(card, name, stream, proc_pcm_format_read);
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 37fc0447c071..86e80916a029 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3326,6 +3326,9 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
}
}
},
+ {
+ .ifnum = -1
+ },
}
}
},
@@ -3369,6 +3372,9 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
}
}
},
+ {
+ .ifnum = -1
+ },
}
}
},
@@ -3392,5 +3398,70 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
.ifnum = QUIRK_NO_INTERFACE
}
},
+/* MOTU Microbook II */
+{
+ USB_DEVICE(0x07fd, 0x0004),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .vendor_name = "MOTU",
+ .product_name = "MicroBookII",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
+ },
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 6,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = 0,
+ .endpoint = 0x84,
+ .rates = SNDRV_PCM_RATE_96000,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rate_min = 96000,
+ .rate_max = 96000,
+ .nr_rates = 1,
+ .maxpacksize = 0x00d8,
+ .rate_table = (unsigned int[]) {
+ 96000
+ }
+ }
+ },
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 8,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = 0,
+ .endpoint = 0x03,
+ .rates = SNDRV_PCM_RATE_96000,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rate_min = 96000,
+ .rate_max = 96000,
+ .nr_rates = 1,
+ .maxpacksize = 0x0120,
+ .rate_table = (unsigned int[]) {
+ 96000
+ }
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
#undef USB_DEVICE_VENDOR_SPEC
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 96340f23f86d..e6ce1bbe6ca6 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -768,7 +768,7 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
* REG1: PLL binary search enable, soft mute enable.
*/
CM6206_REG1_PLLBIN_EN |
- CM6206_REG1_SOFT_MUTE_EN |
+ CM6206_REG1_SOFT_MUTE_EN,
/*
* REG2: enable output drivers,
* select front channels to the headphone output,
@@ -1000,6 +1000,105 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
return 0;
}
+
+#define MICROBOOK_BUF_SIZE 128
+
+static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
+ int buf_size, int *length)
+{
+ int err, actual_length;
+
+ err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
+ &actual_length, 1000);
+ if (err < 0)
+ return err;
+
+ print_hex_dump(KERN_DEBUG, "MicroBookII snd: ", DUMP_PREFIX_NONE, 16, 1,
+ buf, actual_length, false);
+
+ memset(buf, 0, buf_size);
+
+ err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
+ &actual_length, 1000);
+ if (err < 0)
+ return err;
+
+ print_hex_dump(KERN_DEBUG, "MicroBookII rcv: ", DUMP_PREFIX_NONE, 16, 1,
+ buf, actual_length, false);
+
+ *length = actual_length;
+ return 0;
+}
+
+static int snd_usb_motu_microbookii_boot_quirk(struct usb_device *dev)
+{
+ int err, actual_length, poll_attempts = 0;
+ static const u8 set_samplerate_seq[] = { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0b, 0x14,
+ 0x00, 0x00, 0x00, 0x01 };
+ static const u8 poll_ready_seq[] = { 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x0b, 0x18 };
+ u8 *buf = kzalloc(MICROBOOK_BUF_SIZE, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ dev_info(&dev->dev, "Waiting for MOTU Microbook II to boot up...\n");
+
+ /* First we tell the device which sample rate to use. */
+ memcpy(buf, set_samplerate_seq, sizeof(set_samplerate_seq));
+ actual_length = sizeof(set_samplerate_seq);
+ err = snd_usb_motu_microbookii_communicate(dev, buf, MICROBOOK_BUF_SIZE,
+ &actual_length);
+
+ if (err < 0) {
+ dev_err(&dev->dev,
+ "failed setting the sample rate for Motu MicroBook II: %d\n",
+ err);
+ goto free_buf;
+ }
+
+ /* Then we poll every 100 ms until the device informs of its readiness. */
+ while (true) {
+ if (++poll_attempts > 100) {
+ dev_err(&dev->dev,
+ "failed booting Motu MicroBook II: timeout\n");
+ err = -ENODEV;
+ goto free_buf;
+ }
+
+ memset(buf, 0, MICROBOOK_BUF_SIZE);
+ memcpy(buf, poll_ready_seq, sizeof(poll_ready_seq));
+
+ actual_length = sizeof(poll_ready_seq);
+ err = snd_usb_motu_microbookii_communicate(
+ dev, buf, MICROBOOK_BUF_SIZE, &actual_length);
+ if (err < 0) {
+ dev_err(&dev->dev,
+ "failed booting Motu MicroBook II: communication error %d\n",
+ err);
+ goto free_buf;
+ }
+
+ /* the device signals its readiness through a message of the
+ * form
+ * XX 06 00 00 00 00 0b 18 00 00 00 01
+ * If the device is not yet ready to accept audio data, the
+ * last byte of that sequence is 00.
+ */
+ if (actual_length == 12 && buf[actual_length - 1] == 1)
+ break;
+
+ msleep(100);
+ }
+
+ dev_info(&dev->dev, "MOTU MicroBook II ready\n");
+
+free_buf:
+ kfree(buf);
+ return err;
+}
+
/*
* Setup quirks
*/
@@ -1177,6 +1276,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
return snd_usb_gamecon780_boot_quirk(dev);
case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */
return snd_usb_axefx3_boot_quirk(dev);
+ case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */
+ return snd_usb_motu_microbookii_boot_quirk(dev);
}
return 0;
@@ -1479,10 +1580,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
/* XMOS based USB DACs */
switch (chip->usb_id) {
case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */
- case USB_ID(0x20b1, 0x0002): /* Wyred 4 Sound DAC-2 DSD */
- case USB_ID(0x20b1, 0x2004): /* Matrix Audio X-SPDIF 2 */
- case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
- case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */
case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */
case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */
@@ -1492,22 +1589,13 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
- case USB_ID(0x152a, 0x85de): /* SMSL D1 DAC */
- case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */
case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */
+ case USB_ID(0x10cb, 0x0103): /* The Bit Opus #3; with fp->dsd_raw */
case USB_ID(0x16b0, 0x06b2): /* NuPrime DAC-10 */
+ case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */
case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */
case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */
case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */
- case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */
- case USB_ID(0x20b1, 0x2005): /* Denafrips Ares DAC */
- case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
- case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */
- case USB_ID(0x20b1, 0x3021): /* Eastern El. MiniMax Tube DAC Supreme */
- case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */
- case USB_ID(0x20b1, 0x302d): /* Unison Research Unico CD Due */
- case USB_ID(0x20b1, 0x307b): /* CH Precision C1 DAC */
- case USB_ID(0x20b1, 0x3086): /* Singxer F-1 converter board */
case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */
case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */
case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */
@@ -1566,6 +1654,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
case 0x20b1: /* XMOS based devices */
case 0x152a: /* Thesycon devices */
case 0x25ce: /* Mytek devices */
+ case 0x2ab6: /* T+A devices */
if (fp->dsd_raw)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 67cf849aa16b..d9e3de495c16 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -596,12 +596,8 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT);
if (!csep || csep->bLength < 7 ||
- csep->bDescriptorSubtype != UAC_EP_GENERAL) {
- usb_audio_warn(chip,
- "%u:%d : no or invalid class specific endpoint descriptor\n",
- iface_no, altsd->bAlternateSetting);
- return 0;
- }
+ csep->bDescriptorSubtype != UAC_EP_GENERAL)
+ goto error;
if (protocol == UAC_VERSION_1) {
attributes = csep->bmAttributes;
@@ -609,6 +605,8 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct uac2_iso_endpoint_descriptor *csep2 =
(struct uac2_iso_endpoint_descriptor *) csep;
+ if (csep2->bLength < sizeof(*csep2))
+ goto error;
attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
/* emulate the endpoint attributes of a v1 device */
@@ -618,12 +616,20 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct uac3_iso_endpoint_descriptor *csep3 =
(struct uac3_iso_endpoint_descriptor *) csep;
+ if (csep3->bLength < sizeof(*csep3))
+ goto error;
/* emulate the endpoint attributes of a v1 device */
if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH)
attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
}
return attributes;
+
+ error:
+ usb_audio_warn(chip,
+ "%u:%d : no or invalid class specific endpoint descriptor\n",
+ iface_no, altsd->bAlternateSetting);
+ return 0;
}
/* find an input terminal descriptor (either UAC1 or UAC2) with the given
@@ -631,13 +637,17 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
*/
static void *
snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
- int terminal_id)
+ int terminal_id, bool uac23)
{
struct uac2_input_terminal_descriptor *term = NULL;
+ size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) :
+ sizeof(struct uac_input_terminal_descriptor);
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_INPUT_TERMINAL))) {
+ if (term->bLength < minlen)
+ continue;
if (term->bTerminalID == terminal_id)
return term;
}
@@ -655,7 +665,8 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_OUTPUT_TERMINAL))) {
- if (term->bTerminalID == terminal_id)
+ if (term->bLength >= sizeof(*term) &&
+ term->bTerminalID == terminal_id)
return term;
}
@@ -729,7 +740,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
format = le16_to_cpu(as->wFormatTag); /* remember the format value */
iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
- as->bTerminalLink);
+ as->bTerminalLink,
+ false);
if (iterm) {
num_channels = iterm->bNrChannels;
chconfig = le16_to_cpu(iterm->wChannelConfig);
@@ -764,7 +776,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
* to extract the clock
*/
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
- as->bTerminalLink);
+ as->bTerminalLink,
+ true);
if (input_term) {
clock = input_term->bCSourceID;
if (!chconfig && (num_channels == input_term->bNrChannels))
@@ -998,7 +1011,8 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
* to extract the clock
*/
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
- as->bTerminalLink);
+ as->bTerminalLink,
+ true);
if (input_term) {
clock = input_term->bCSourceID;
goto found_clock;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 2b833054e3b0..58974d094b27 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -981,18 +981,17 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint,
sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs);
- if ((playback_endpoint &&
- 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 64*1024, 128*1024))) ||
- 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 64*1024, 128*1024))) {
- snd_usX2Y_pcm_private_free(pcm);
- return err;
+ if (playback_endpoint) {
+ snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 64*1024, 128*1024);
}
+
+ snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 64*1024, 128*1024);
usX2Y(card)->pcm_devs++;
return 0;
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 4fd9276b8e50..714cf50d4a4c 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -736,17 +736,14 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card)
pcm->info_flags = 0;
sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
- if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 64*1024, 128*1024)) ||
- 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 64*1024, 128*1024))) {
- return err;
- }
-
+ snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 64*1024, 128*1024);
+ snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 64*1024, 128*1024);
return 0;
}