diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-07-24 16:21:27 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-07-24 16:21:27 +0200 |
| commit | 8f9aa2c90530ab92301a82231ae44f3722becd93 (patch) | |
| tree | fb282e955b0a880b07131a135257fe3ec764e928 /sound/usb | |
| parent | 93467b31bec6da512b51544e5e4584f2745e995e (diff) | |
| parent | 155b42bec9cbb6b8cdc47dd9bd09503a81fbe493 (diff) | |
Merge v7.1.5linux-rolling-stable
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound/usb')
| -rw-r--r-- | sound/usb/fcp.c | 2 | ||||
| -rw-r--r-- | sound/usb/midi2.c | 5 | ||||
| -rw-r--r-- | sound/usb/mixer_scarlett2.c | 201 | ||||
| -rw-r--r-- | sound/usb/qcom/mixer_usb_offload.c | 2 | ||||
| -rw-r--r-- | sound/usb/qcom/qc_audio_offload.c | 30 |
5 files changed, 212 insertions, 28 deletions
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c index 0fc4d063c48a..c45dbe4d4532 100644 --- a/sound/usb/fcp.c +++ b/sound/usb/fcp.c @@ -1083,6 +1083,8 @@ static int fcp_find_fc_interface(struct usb_mixer_interface *mixer) if (desc->bInterfaceClass != 255) continue; + if (desc->bNumEndpoints < 1) + continue; epd = get_endpoint(intf->altsetting, 0); private->bInterfaceNumber = desc->bInterfaceNumber; diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c index 04aeb9052f13..3ec633291772 100644 --- a/sound/usb/midi2.c +++ b/sound/usb/midi2.c @@ -470,6 +470,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi, static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep) { list_del(&ep->list); + if (!ep->disconnected) { + ep->disconnected = 1; + kill_midi_urbs(ep, false); + drain_urb_queue(ep); + } free_midi_urbs(ep); kfree(ep); } diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index a4fac4652201..d7b8c204110c 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -612,6 +612,20 @@ struct scarlett2_config_set { const struct scarlett2_config items[SCARLETT2_CONFIG_COUNT]; }; +/* Map firmware versions to config sets per-device. + * + * Each device lists one or more entries, sorted in ascending order of + * from_firmware_version. At probe time the running firmware version + * is looked up against this list and the last entry whose + * from_firmware_version is <= the running version is selected. + * + * The list is terminated by a sentinel entry with config_set == NULL. + */ +struct scarlett2_config_set_entry { + u16 from_firmware_version; + const struct scarlett2_config_set *config_set; +}; + /* Input gain TLV dB ranges */ static const DECLARE_TLV_DB_MINMAX( @@ -923,6 +937,63 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = { } }; +/* 2i2 Gen 4, firmware version 2417 and above + * + * Firmware 2417 shifted DIRECT_MONITOR_GAIN by 4 bytes; all other + * offsets are unchanged from scarlett2_config_set_gen4_2i2. + */ +static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2_2417 = { + .notifications = scarlett4_2i2_notifications, + .param_buf_addr = 0xfc, + .input_gain_tlv = db_scale_gen4_gain, + .autogain_status_texts = scarlett2_autogain_status_gen4, + .items = { + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x49, .size = 8, .activate = 4 }, + + [SCARLETT2_CONFIG_DIRECT_MONITOR] = { + .offset = 0x14a, .size = 8, .activate = 16, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { + .offset = 0x135, .size = 8, .activate = 10, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { + .offset = 0x137, .size = 8 }, + + [SCARLETT2_CONFIG_AG_MEAN_TARGET] = { + .offset = 0x131, .size = 8, .activate = 29, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AG_PEAK_TARGET] = { + .offset = 0x132, .size = 8, .activate = 30, .pbuf = 1 }, + + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x48, .size = 8, .activate = 11, .pbuf = 1, + .mute = 1 }, + + [SCARLETT2_CONFIG_INPUT_GAIN] = { + .offset = 0x4b, .size = 8, .activate = 12, .pbuf = 1 }, + + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { + .offset = 0x3c, .size = 8, .activate = 13, .pbuf = 1, + .mute = 1 }, + + [SCARLETT2_CONFIG_SAFE_SWITCH] = { + .offset = 0x147, .size = 8, .activate = 14, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AIR_SWITCH] = { + .offset = 0x3e, .size = 8, .activate = 15, .pbuf = 1 }, + + [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = { + .offset = 0x14b, .size = 8, .activate = 17, .pbuf = 1 }, + + [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = { + .offset = 0x14e, .size = 8, .activate = 18, .pbuf = 1 }, + + [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = { + .offset = 0x2a4, .size = 16, .activate = 36 } + } +}; + /* 4i4 Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { .notifications = scarlett4_4i4_notifications, @@ -1100,8 +1171,8 @@ struct scarlett2_meter_entry { }; struct scarlett2_device_info { - /* which set of configuration parameters the device uses */ - const struct scarlett2_config_set *config_set; + /* which sets of configuration parameters the device uses */ + const struct scarlett2_config_set_entry *config_sets; /* minimum firmware version required */ u16 min_firmware_version; @@ -1343,7 +1414,10 @@ struct scarlett2_data { /*** Model-specific data ***/ static const struct scarlett2_device_info s6i6_gen2_info = { - .config_set = &scarlett2_config_set_gen2a, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen2a }, + { } + }, .level_input_count = 2, .pad_input_count = 2, @@ -1393,7 +1467,10 @@ static const struct scarlett2_device_info s6i6_gen2_info = { }; static const struct scarlett2_device_info s18i8_gen2_info = { - .config_set = &scarlett2_config_set_gen2a, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen2a }, + { } + }, .level_input_count = 2, .pad_input_count = 4, @@ -1446,7 +1523,10 @@ static const struct scarlett2_device_info s18i8_gen2_info = { }; static const struct scarlett2_device_info s18i20_gen2_info = { - .config_set = &scarlett2_config_set_gen2b, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen2b }, + { } + }, .line_out_descrs = { "Monitor L", @@ -1503,7 +1583,10 @@ static const struct scarlett2_device_info s18i20_gen2_info = { }; static const struct scarlett2_device_info solo_gen3_info = { - .config_set = &scarlett2_config_set_gen3a, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3a }, + { } + }, .level_input_count = 1, .level_input_first = 1, .air_input_count = 1, @@ -1513,7 +1596,10 @@ static const struct scarlett2_device_info solo_gen3_info = { }; static const struct scarlett2_device_info s2i2_gen3_info = { - .config_set = &scarlett2_config_set_gen3a, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3a }, + { } + }, .level_input_count = 2, .air_input_count = 2, .phantom_count = 1, @@ -1522,7 +1608,10 @@ static const struct scarlett2_device_info s2i2_gen3_info = { }; static const struct scarlett2_device_info s4i4_gen3_info = { - .config_set = &scarlett2_config_set_gen3b, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3b }, + { } + }, .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, @@ -1571,7 +1660,10 @@ static const struct scarlett2_device_info s4i4_gen3_info = { }; static const struct scarlett2_device_info s8i6_gen3_info = { - .config_set = &scarlett2_config_set_gen3b, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3b }, + { } + }, .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, @@ -1637,7 +1729,10 @@ static const char * const scarlett2_spdif_s18i8_gen3_texts[] = { }; static const struct scarlett2_device_info s18i8_gen3_info = { - .config_set = &scarlett2_config_set_gen3c, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3c }, + { } + }, .has_speaker_switching = 1, .level_input_count = 2, .pad_input_count = 4, @@ -1729,7 +1824,10 @@ static const char * const scarlett2_spdif_s18i20_gen3_texts[] = { }; static const struct scarlett2_device_info s18i20_gen3_info = { - .config_set = &scarlett2_config_set_gen3c, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_gen3c }, + { } + }, .has_speaker_switching = 1, .has_talkback = 1, .level_input_count = 2, @@ -1803,7 +1901,10 @@ static const struct scarlett2_device_info s18i20_gen3_info = { }; static const struct scarlett2_device_info vocaster_one_info = { - .config_set = &scarlett2_config_set_vocaster, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 1769, &scarlett2_config_set_vocaster }, + { } + }, .min_firmware_version = 1769, .has_devmap = 1, @@ -1847,7 +1948,10 @@ static const struct scarlett2_device_info vocaster_one_info = { }; static const struct scarlett2_device_info vocaster_two_info = { - .config_set = &scarlett2_config_set_vocaster, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 1769, &scarlett2_config_set_vocaster }, + { } + }, .min_firmware_version = 1769, .has_devmap = 1, @@ -1892,7 +1996,10 @@ static const struct scarlett2_device_info vocaster_two_info = { }; static const struct scarlett2_device_info solo_gen4_info = { - .config_set = &scarlett2_config_set_gen4_solo, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 2115, &scarlett2_config_set_gen4_solo }, + { } + }, .min_firmware_version = 2115, .has_devmap = 1, @@ -1947,7 +2054,11 @@ static const struct scarlett2_device_info solo_gen4_info = { }; static const struct scarlett2_device_info s2i2_gen4_info = { - .config_set = &scarlett2_config_set_gen4_2i2, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 2115, &scarlett2_config_set_gen4_2i2 }, + { 2417, &scarlett2_config_set_gen4_2i2_2417 }, + { } + }, .min_firmware_version = 2115, .has_devmap = 1, @@ -2002,7 +2113,10 @@ static const struct scarlett2_device_info s2i2_gen4_info = { }; static const struct scarlett2_device_info s4i4_gen4_info = { - .config_set = &scarlett2_config_set_gen4_4i4, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 2089, &scarlett2_config_set_gen4_4i4 }, + { } + }, .min_firmware_version = 2089, .has_devmap = 1, @@ -2051,7 +2165,10 @@ static const struct scarlett2_device_info s4i4_gen4_info = { }; static const struct scarlett2_device_info clarett_2pre_info = { - .config_set = &scarlett2_config_set_clarett, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_clarett }, + { } + }, .level_input_count = 2, .air_input_count = 2, @@ -2107,7 +2224,10 @@ static const char * const scarlett2_spdif_clarett_texts[] = { }; static const struct scarlett2_device_info clarett_4pre_info = { - .config_set = &scarlett2_config_set_clarett, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_clarett }, + { } + }, .level_input_count = 2, .air_input_count = 4, @@ -2163,7 +2283,10 @@ static const struct scarlett2_device_info clarett_4pre_info = { }; static const struct scarlett2_device_info clarett_8pre_info = { - .config_set = &scarlett2_config_set_clarett, + .config_sets = (const struct scarlett2_config_set_entry[]) { + { 0, &scarlett2_config_set_clarett }, + { } + }, .level_input_count = 2, .air_input_count = 8, @@ -8211,10 +8334,32 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) /*** Initialisation ***/ +/* Select the config_set matching the running firmware version. + * + * The device info's config_sets array is ordered by ascending + * from_firmware_version; pick the last entry whose version is <= the + * running firmware version. If the running firmware is older than the + * first entry's from_firmware_version (i.e. older than the driver's + * minimum supported version for this device), the first entry's + * config_set is selected anyway so firmware updates can still be done + * (requires only the ACK handler), but the usual mixer controls + * aren't created. + */ +static void scarlett2_resolve_config_set(struct scarlett2_data *private) +{ + const struct scarlett2_config_set_entry *entry = + private->info->config_sets; + + private->config_set = entry->config_set; + for (entry++; entry->config_set; entry++) + if (entry->from_firmware_version <= private->firmware_version) + private->config_set = entry->config_set; +} + static void scarlett2_count_io(struct scarlett2_data *private) { const struct scarlett2_device_info *info = private->info; - const struct scarlett2_config_set *config_set = info->config_set; + const struct scarlett2_config_set *config_set = private->config_set; const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int port_type, srcs = 0, dsts = 0, i; @@ -8311,9 +8456,14 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer, mixer->private_suspend = scarlett2_private_suspend; private->info = entry->info; - private->config_set = entry->info->config_set; + + /* Set config_set to the first entry's config_set so the + * notify handler has a valid pointer while USB init runs; it + * is re-resolved once the firmware version has been read. + */ + private->config_set = entry->info->config_sets[0].config_set; + private->series_name = entry->series_name; - scarlett2_count_io(private); private->scarlett2_seq = 0; private->mixer = mixer; @@ -8717,6 +8867,13 @@ static int snd_scarlett2_controls_create( if (err < 0) return err; + /* Now that the firmware version is known, pick the matching + * config_set + */ + scarlett2_resolve_config_set(private); + + scarlett2_count_io(private); + /* Get the upgrade & settings flash segment numbers */ err = scarlett2_get_flash_segment_nums(mixer); if (err < 0) diff --git a/sound/usb/qcom/mixer_usb_offload.c b/sound/usb/qcom/mixer_usb_offload.c index 2adeb64f4d33..005138714f72 100644 --- a/sound/usb/qcom/mixer_usb_offload.c +++ b/sound/usb/qcom/mixer_usb_offload.c @@ -113,7 +113,7 @@ int snd_usb_offload_create_ctl(struct snd_usb_audio *chip, struct device *bedev) struct snd_usb_substream *subs; struct snd_usb_stream *as; char ctl_name[48]; - int ret; + int ret = 0; list_for_each_entry(as, &chip->pcm_list, list) { subs = &as->substream[SNDRV_PCM_STREAM_PLAYBACK]; diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c index a0009503b2c5..ed833a43db63 100644 --- a/sound/usb/qcom/qc_audio_offload.c +++ b/sound/usb/qcom/qc_audio_offload.c @@ -794,15 +794,23 @@ static void qmi_stop_session(void) continue; } /* Release XHCI endpoints */ - if (info->data_ep_pipe) + if (info->data_ep_pipe) { ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, info->data_ep_pipe); - xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, ep); + if (ep) + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, + ep); + info->data_ep_pipe = 0; + } - if (info->sync_ep_pipe) + if (info->sync_ep_pipe) { ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, info->sync_ep_pipe); - xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, ep); + if (ep) + xhci_sideband_remove_endpoint(uadev[pcm_card_num].sb, + ep); + info->sync_ep_pipe = 0; + } disable_audio_stream(subs); } @@ -1157,6 +1165,7 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs, tr_pa = page_to_phys(pg); mem_info->dma = sg_dma_address(sgt->sgl); sg_free_table(sgt); + kfree(sgt); /* data transfer ring */ iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa, @@ -1226,6 +1235,7 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs, er_pa = page_to_phys(pg); mem_info->dma = sg_dma_address(sgt->sgl); sg_free_table(sgt); + kfree(sgt); iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa, PAGE_SIZE); @@ -1615,8 +1625,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, if (req_msg->service_interval_valid) { ret = get_data_interval_from_si(subs, req_msg->service_interval); - if (ret == -EINVAL) + if (ret == -EINVAL) { + if (req_msg->enable) { + guard(mutex)(&chip->mutex); + subs->opened = 0; + } goto response; + } datainterval = ret; } @@ -1637,6 +1652,11 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, subs->opened = 0; } } else { + if (info_idx < 0) { + ret = -EINVAL; + goto response; + } + info = &uadev[pcm_card_num].info[info_idx]; if (info->data_ep_pipe) { ep = usb_pipe_endpoint(uadev[pcm_card_num].udev, |
