diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/card.c | 3 | ||||
-rw-r--r-- | sound/usb/card.h | 1 | ||||
-rw-r--r-- | sound/usb/format.c | 2 | ||||
-rw-r--r-- | sound/usb/line6/driver.c | 4 | ||||
-rw-r--r-- | sound/usb/line6/pod.c | 3 | ||||
-rw-r--r-- | sound/usb/mixer.c | 42 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 6 | ||||
-rw-r--r-- | sound/usb/pcm.c | 13 | ||||
-rw-r--r-- | sound/usb/proc.c | 14 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 71 | ||||
-rw-r--r-- | sound/usb/quirks.c | 121 | ||||
-rw-r--r-- | sound/usb/stream.c | 36 | ||||
-rw-r--r-- | sound/usb/usx2y/usbusx2yaudio.c | 21 | ||||
-rw-r--r-- | sound/usb/usx2y/usx2yhwdeppcm.c | 19 |
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; } |