From acf43d9b5ce09639afa7fb9e23db9f9df79e4635 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sun, 6 Oct 2024 11:11:23 -0400 Subject: [PATCH] Fixes for 6.1 Signed-off-by: Sasha Levin --- ...elease-locks-during-operation-region.patch | 166 + ...pi-pad-fix-crash-in-exit_round_robin.patch | 96 + ...orce_vendor-quirk-for-panasonic-toug.patch | 45 + ...l-return-of-acpi_allocate_zeroed-in-.patch | 41 + ...y-leak-if-acpi_ps_get_next_field-fai.patch | 90 + ...y-leak-if-acpi_ps_get_next_namepath-.patch | 55 + ...ca-iasl-handle-empty-connection_node.patch | 36 + ...sihpi-fix-potential-oob-array-access.patch | 39 + ...break-infinite-midi-input-flush-loop.patch | 60 + ...dd-input-value-sanity-checks-for-sta.patch | 140 + ...dio-add-logitech-audio-profile-quirk.patch | 40 + ...efine-macros-for-quirk-table-entries.patch | 111 + ...eplace-complex-quirk-lines-with-macr.patch | 4000 +++++++++++++++++ ...-support-multiple-control-interfaces.patch | 659 +++ ...a883x-handle-reading-version-failure.patch | 72 + ...rworks-do-not-use-the-term-blacklist.patch | 65 + ...l-rename-sil_blacklist-to-sil_quirks.patch | 61 + ..._iocost-fix-more-out-of-bound-shifts.patch | 80 + ...add-realtek-rtl8852c-support-id-0x04.patch | 67 + ...aximum-length-of-version-string-by-1.patch | 42 + ...mounting-v1-hierarchies-without-cont.patch | 71 + ...ot-call-crypto_alloc_tfm-during-regi.patch | 249 + ...add-null-check-for-afb-in-amdgpu_dm_.patch | 54 + ...add-null-check-for-top_pipe_to_progr.patch | 52 + ...check-null-pointers-before-using-dc-.patch | 46 + ...y-check-stream-before-comparing-them.patch | 41 + ...fix-index-out-of-bounds-in-dcn30-col.patch | 54 + ...fix-index-out-of-bounds-in-dcn30-deg.patch | 55 + ...fix-index-out-of-bounds-in-degamma-h.patch | 55 + ...handle-null-stream_status-in-planes_.patch | 52 + ...initialize-get_bytes_per_element-s-d.patch | 55 + ...e-the-fw_info-is-not-null-before-usi.patch | 36 + .../drm-amdgpu-add-raven1-gfxoff-quirk.patch | 35 + ...low-multiple-bo_handles-chunks-in-on.patch | 49 + ...dgpu-enable-gfxoff-quirk-on-hp-705g4.patch | 38 + ...nchecked-return-value-warning-for-am.patch | 72 + ...-resource-leak-in-criu-restore-queue.patch | 35 + ...low-null-data-in-devcoredump-printer.patch | 144 + ...handle-unknown-family-in-r100_cp_ini.patch | 140 + ...e-after-free-issues-with-crtc-and-pl.patch | 254 ++ ...et-plane-transparency-after-plane-di.patch | 38 + ...use-after-free-in-ext4_ext_show_leaf.patch | 94 + ...et-sb_rdonly-after-filesystem-errors.patch | 56 + ...rch_dir-should-return-a-proper-error.patch | 86 + ...sem-unlock-order-in-ext4_ind_migrate.patch | 55 + ...possible-use-after-free-in-pxafb_tas.patch | 59 + ...dd-support-for-thinkpad-x12-gen-2-kb.patch | 54 + ...allocation-of-memory-in-ice_sched_ad.patch | 61 + ...ost-direct-i-o-invalidate-race-in-io.patch | 49 + ...com-hide-last-lpass-smmu-context-ban.patch | 74 + ...s-reserve-a-domain-id-for-identity-s.patch | 44 + ...otential-lockup-if-qi_submit_sync-ca.patch | 128 + ...in_dev-earlier-for-ioctl-siocsifaddr.patch | 52 + ...dscp-bits-and-ecn-bits-in-netlink_fi.patch | 50 + ...fidx-greater-than-num-leaves-per-dma.patch | 52 + queue-6.1/jfs-fix-uaf-in-dbfreebits.patch | 117 + ...-value-access-of-new_ea-in-ea_buffer.patch | 57 + ...an-shift-out-of-bounds-in-dbfindbits.patch | 35 + ...id-warning-about-potential-string-tr.patch | 79 + ...icon-hip04-fix-of-node-leak-in-probe.patch | 36 + ...s_dsaf_mac-fix-of-node-leak-in-hns_m.patch | 36 + ...n-hns_mdio-fix-of-node-leak-in-probe.patch | 36 + ...2-increase-size-of-queue_name-buffer.patch | 58 + ...tently-use-rcu_replace_pointer-in-ta.patch | 42 + ...ack-prevent-uaf-in-xenvif_flush_hash.patch | 50 + ...e-irqf_no_autoen-flag-in-request_irq.patch | 46 + queue-6.1/nvme-pci-qdepth-1-quirk.patch | 90 + ...actual-buffer-size-in-of_irq_parse_o.patch | 39 + ...issing-caller-address-in-stack-trace.patch | 197 + ...ouchscreen_dmi-add-nanote-next-quirk.patch | 69 + ...stb-do-not-go-into-infinite-loop-if-.patch | 39 + ...use-correct-data-types-from-pseries_.patch | 157 + ...ig-param-to-block-forcing-mem-writes.patch | 200 + ...-clear-error-when-async-specified-wi.patch | 47 + ...arrange-order-of-struct-aac_srb_unit.patch | 112 + ...-prlo-handling-in-direct-attached-to.patch | 113 + ...tialize-buffer-for-msg-in-and-status.patch | 50 + ...si-smartpqi-correct-stream-detection.patch | 50 + ...olibc-avoid-passing-null-to-printf-s.patch | 52 + queue-6.1/series | 96 + ...g-fin_wait2-when-trying-to-find-port.patch | 82 + ...-guard-against-string-buffer-overrun.patch | 53 + ...-protect-against-faulty-max-subleaf-.patch | 68 + ...array-out-of-bound-access-in-soc-sta.patch | 43 + ...ossible-integer-overflow-in-ath9k_ge.patch | 47 + ...se-__skb_set_length-for-resetting-ur.patch | 59 + ...et-correct-chandef-when-starting-cac.patch | 77 + ...fi-mvm-fix-a-race-in-scan-abort-flow.patch | 153 + ...ifi-mac80211-fix-rcu-list-iterations.patch | 84 + ...-disable-tx-worker-during-tx-ba-sess.patch | 47 + ...-hold-dev-mt76.mutex-while-disabling.patch | 41 + ...-memcpy-field-spanning-write-warning.patch | 62 + .../wifi-rtw88-select-want_dev_coredump.patch | 35 + ...rrect-base-ht-rate-mask-for-firmware.patch | 53 + ...andle-allocation-failures-gracefully.patch | 153 + ...i-config-table-identity-mapping-for-.patch | 116 + ...d-memcpy-for-ia32-syscall_get_argume.patch | 71 + 97 files changed, 11651 insertions(+) create mode 100644 queue-6.1/acpi-ec-do-not-release-locks-during-operation-region.patch create mode 100644 queue-6.1/acpi-pad-fix-crash-in-exit_round_robin.patch create mode 100644 queue-6.1/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch create mode 100644 queue-6.1/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch create mode 100644 queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch create mode 100644 queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch create mode 100644 queue-6.1/acpica-iasl-handle-empty-connection_node.patch create mode 100644 queue-6.1/alsa-asihpi-fix-potential-oob-array-access.patch create mode 100644 queue-6.1/alsa-hdsp-break-infinite-midi-input-flush-loop.patch create mode 100644 queue-6.1/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch create mode 100644 queue-6.1/alsa-usb-audio-add-logitech-audio-profile-quirk.patch create mode 100644 queue-6.1/alsa-usb-audio-define-macros-for-quirk-table-entries.patch create mode 100644 queue-6.1/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch create mode 100644 queue-6.1/alsa-usb-audio-support-multiple-control-interfaces.patch create mode 100644 queue-6.1/asoc-codecs-wsa883x-handle-reading-version-failure.patch create mode 100644 queue-6.1/ata-pata_serverworks-do-not-use-the-term-blacklist.patch create mode 100644 queue-6.1/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch create mode 100644 queue-6.1/blk_iocost-fix-more-out-of-bound-shifts.patch create mode 100644 queue-6.1/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch create mode 100644 queue-6.1/bnxt_en-extend-maximum-length-of-version-string-by-1.patch create mode 100644 queue-6.1/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch create mode 100644 queue-6.1/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch create mode 100644 queue-6.1/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch create mode 100644 queue-6.1/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch create mode 100644 queue-6.1/drm-amd-display-check-null-pointers-before-using-dc-.patch create mode 100644 queue-6.1/drm-amd-display-check-stream-before-comparing-them.patch create mode 100644 queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch create mode 100644 queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch create mode 100644 queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch create mode 100644 queue-6.1/drm-amd-display-handle-null-stream_status-in-planes_.patch create mode 100644 queue-6.1/drm-amd-display-initialize-get_bytes_per_element-s-d.patch create mode 100644 queue-6.1/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch create mode 100644 queue-6.1/drm-amdgpu-add-raven1-gfxoff-quirk.patch create mode 100644 queue-6.1/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch create mode 100644 queue-6.1/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch create mode 100644 queue-6.1/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch create mode 100644 queue-6.1/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch create mode 100644 queue-6.1/drm-printer-allow-null-data-in-devcoredump-printer.patch create mode 100644 queue-6.1/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch create mode 100644 queue-6.1/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch create mode 100644 queue-6.1/drm-stm-ltdc-reset-plane-transparency-after-plane-di.patch create mode 100644 queue-6.1/ext4-avoid-use-after-free-in-ext4_ext_show_leaf.patch create mode 100644 queue-6.1/ext4-don-t-set-sb_rdonly-after-filesystem-errors.patch create mode 100644 queue-6.1/ext4-ext4_search_dir-should-return-a-proper-error.patch create mode 100644 queue-6.1/ext4-fix-i_data_sem-unlock-order-in-ext4_ind_migrate.patch create mode 100644 queue-6.1/fbdev-pxafb-fix-possible-use-after-free-in-pxafb_tas.patch create mode 100644 queue-6.1/hid-multitouch-add-support-for-thinkpad-x12-gen-2-kb.patch create mode 100644 queue-6.1/ice-adjust-over-allocation-of-memory-in-ice_sched_ad.patch create mode 100644 queue-6.1/iomap-handle-a-post-direct-i-o-invalidate-race-in-io.patch create mode 100644 queue-6.1/iommu-arm-smmu-qcom-hide-last-lpass-smmu-context-ban.patch create mode 100644 queue-6.1/iommu-vt-d-always-reserve-a-domain-id-for-identity-s.patch create mode 100644 queue-6.1/iommu-vt-d-fix-potential-lockup-if-qi_submit_sync-ca.patch create mode 100644 queue-6.1/ipv4-check-in_dev-earlier-for-ioctl-siocsifaddr.patch create mode 100644 queue-6.1/ipv4-mask-upper-dscp-bits-and-ecn-bits-in-netlink_fi.patch create mode 100644 queue-6.1/jfs-check-if-leafidx-greater-than-num-leaves-per-dma.patch create mode 100644 queue-6.1/jfs-fix-uaf-in-dbfreebits.patch create mode 100644 queue-6.1/jfs-fix-uninit-value-access-of-new_ea-in-ea_buffer.patch create mode 100644 queue-6.1/jfs-ubsan-shift-out-of-bounds-in-dbfindbits.patch create mode 100644 queue-6.1/net-atlantic-avoid-warning-about-potential-string-tr.patch create mode 100644 queue-6.1/net-hisilicon-hip04-fix-of-node-leak-in-probe.patch create mode 100644 queue-6.1/net-hisilicon-hns_dsaf_mac-fix-of-node-leak-in-hns_m.patch create mode 100644 queue-6.1/net-hisilicon-hns_mdio-fix-of-node-leak-in-probe.patch create mode 100644 queue-6.1/net-mvpp2-increase-size-of-queue_name-buffer.patch create mode 100644 queue-6.1/net-sched-consistently-use-rcu_replace_pointer-in-ta.patch create mode 100644 queue-6.1/net-xen-netback-prevent-uaf-in-xenvif_flush_hash.patch create mode 100644 queue-6.1/nfp-use-irqf_no_autoen-flag-in-request_irq.patch create mode 100644 queue-6.1/nvme-pci-qdepth-1-quirk.patch create mode 100644 queue-6.1/of-irq-refer-to-actual-buffer-size-in-of_irq_parse_o.patch create mode 100644 queue-6.1/perf-x86-avoid-missing-caller-address-in-stack-trace.patch create mode 100644 queue-6.1/platform-x86-touchscreen_dmi-add-nanote-next-quirk.patch create mode 100644 queue-6.1/power-reset-brcmstb-do-not-go-into-infinite-loop-if-.patch create mode 100644 queue-6.1/powerpc-pseries-use-correct-data-types-from-pseries_.patch create mode 100644 queue-6.1/proc-add-config-param-to-block-forcing-mem-writes.patch create mode 100644 queue-6.1/rcuscale-provide-clear-error-when-async-specified-wi.patch create mode 100644 queue-6.1/scsi-aacraid-rearrange-order-of-struct-aac_srb_unit.patch create mode 100644 queue-6.1/scsi-lpfc-update-prlo-handling-in-direct-attached-to.patch create mode 100644 queue-6.1/scsi-ncr5380-initialize-buffer-for-msg-in-and-status.patch create mode 100644 queue-6.1/scsi-smartpqi-correct-stream-detection.patch create mode 100644 queue-6.1/selftests-nolibc-avoid-passing-null-to-printf-s.patch create mode 100644 queue-6.1/tcp-avoid-reusing-fin_wait2-when-trying-to-find-port.patch create mode 100644 queue-6.1/tipc-guard-against-string-buffer-overrun.patch create mode 100644 queue-6.1/tools-x86-kcpuid-protect-against-faulty-max-subleaf-.patch create mode 100644 queue-6.1/wifi-ath11k-fix-array-out-of-bound-access-in-soc-sta.patch create mode 100644 queue-6.1/wifi-ath9k-fix-possible-integer-overflow-in-ath9k_ge.patch create mode 100644 queue-6.1/wifi-ath9k_htc-use-__skb_set_length-for-resetting-ur.patch create mode 100644 queue-6.1/wifi-cfg80211-set-correct-chandef-when-starting-cac.patch create mode 100644 queue-6.1/wifi-iwlwifi-mvm-fix-a-race-in-scan-abort-flow.patch create mode 100644 queue-6.1/wifi-mac80211-fix-rcu-list-iterations.patch create mode 100644 queue-6.1/wifi-mt76-mt7915-disable-tx-worker-during-tx-ba-sess.patch create mode 100644 queue-6.1/wifi-mt76-mt7915-hold-dev-mt76.mutex-while-disabling.patch create mode 100644 queue-6.1/wifi-mwifiex-fix-memcpy-field-spanning-write-warning.patch create mode 100644 queue-6.1/wifi-rtw88-select-want_dev_coredump.patch create mode 100644 queue-6.1/wifi-rtw89-correct-base-ht-rate-mask-for-firmware.patch create mode 100644 queue-6.1/x86-ioapic-handle-allocation-failures-gracefully.patch create mode 100644 queue-6.1/x86-kexec-add-efi-config-table-identity-mapping-for-.patch create mode 100644 queue-6.1/x86-syscall-avoid-memcpy-for-ia32-syscall_get_argume.patch diff --git a/queue-6.1/acpi-ec-do-not-release-locks-during-operation-region.patch b/queue-6.1/acpi-ec-do-not-release-locks-during-operation-region.patch new file mode 100644 index 00000000000..e1888ef2026 --- /dev/null +++ b/queue-6.1/acpi-ec-do-not-release-locks-during-operation-region.patch @@ -0,0 +1,166 @@ +From bcacdb5643dd4b20e1a4bb0907c8b635b6c324d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jul 2024 18:26:54 +0200 +Subject: ACPI: EC: Do not release locks during operation region accesses + +From: Rafael J. Wysocki + +[ Upstream commit dc171114926ec390ab90f46534545420ec03e458 ] + +It is not particularly useful to release locks (the EC mutex and the +ACPI global lock, if present) and re-acquire them immediately thereafter +during EC address space accesses in acpi_ec_space_handler(). + +First, releasing them for a while before grabbing them again does not +really help anyone because there may not be enough time for another +thread to acquire them. + +Second, if another thread successfully acquires them and carries out +a new EC write or read in the middle if an operation region access in +progress, it may confuse the EC firmware, especially after the burst +mode has been enabled. + +Finally, manipulating the locks after writing or reading every single +byte of data is overhead that it is better to avoid. + +Accordingly, modify the code to carry out EC address space accesses +entirely without releasing the locks. + +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Hans de Goede +Link: https://patch.msgid.link/12473338.O9o76ZdvQC@rjwysocki.net +Signed-off-by: Sasha Levin +--- + drivers/acpi/ec.c | 55 +++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 49 insertions(+), 6 deletions(-) + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 7589908b358e3..63803091f8b1e 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -797,6 +797,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, + unsigned long tmp; + int ret = 0; + ++ if (t->rdata) ++ memset(t->rdata, 0, t->rlen); ++ + /* start transaction */ + spin_lock_irqsave(&ec->lock, tmp); + /* Enable GPE for command processing (IBF=0/OBF=1) */ +@@ -833,8 +836,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) + + if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) + return -EINVAL; +- if (t->rdata) +- memset(t->rdata, 0, t->rlen); + + mutex_lock(&ec->mutex); + if (ec->global_lock) { +@@ -861,7 +862,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec) + .wdata = NULL, .rdata = &d, + .wlen = 0, .rlen = 1}; + +- return acpi_ec_transaction(ec, &t); ++ return acpi_ec_transaction_unlocked(ec, &t); + } + + static int acpi_ec_burst_disable(struct acpi_ec *ec) +@@ -871,7 +872,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) + .wlen = 0, .rlen = 0}; + + return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ? +- acpi_ec_transaction(ec, &t) : 0; ++ acpi_ec_transaction_unlocked(ec, &t) : 0; + } + + static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) +@@ -887,6 +888,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) + return result; + } + ++static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data) ++{ ++ int result; ++ u8 d; ++ struct transaction t = {.command = ACPI_EC_COMMAND_READ, ++ .wdata = &address, .rdata = &d, ++ .wlen = 1, .rlen = 1}; ++ ++ result = acpi_ec_transaction_unlocked(ec, &t); ++ *data = d; ++ return result; ++} ++ + static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + { + u8 wdata[2] = { address, data }; +@@ -897,6 +911,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) + return acpi_ec_transaction(ec, &t); + } + ++static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data) ++{ ++ u8 wdata[2] = { address, data }; ++ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE, ++ .wdata = wdata, .rdata = NULL, ++ .wlen = 2, .rlen = 0}; ++ ++ return acpi_ec_transaction_unlocked(ec, &t); ++} ++ + int ec_read(u8 addr, u8 *val) + { + int err; +@@ -1304,6 +1328,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + struct acpi_ec *ec = handler_context; + int result = 0, i, bytes = bits / 8; + u8 *value = (u8 *)value64; ++ u32 glk; + + if ((address > 0xFF) || !value || !handler_context) + return AE_BAD_PARAMETER; +@@ -1311,13 +1336,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + if (function != ACPI_READ && function != ACPI_WRITE) + return AE_BAD_PARAMETER; + ++ mutex_lock(&ec->mutex); ++ ++ if (ec->global_lock) { ++ acpi_status status; ++ ++ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); ++ if (ACPI_FAILURE(status)) { ++ result = -ENODEV; ++ goto unlock; ++ } ++ } ++ + if (ec->busy_polling || bits > 8) + acpi_ec_burst_enable(ec); + + for (i = 0; i < bytes; ++i, ++address, ++value) { + result = (function == ACPI_READ) ? +- acpi_ec_read(ec, address, value) : +- acpi_ec_write(ec, address, *value); ++ acpi_ec_read_unlocked(ec, address, value) : ++ acpi_ec_write_unlocked(ec, address, *value); + if (result < 0) + break; + } +@@ -1325,6 +1362,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, + if (ec->busy_polling || bits > 8) + acpi_ec_burst_disable(ec); + ++ if (ec->global_lock) ++ acpi_release_global_lock(glk); ++ ++unlock: ++ mutex_unlock(&ec->mutex); ++ + switch (result) { + case -EINVAL: + return AE_BAD_PARAMETER; +-- +2.43.0 + diff --git a/queue-6.1/acpi-pad-fix-crash-in-exit_round_robin.patch b/queue-6.1/acpi-pad-fix-crash-in-exit_round_robin.patch new file mode 100644 index 00000000000..7caba213f18 --- /dev/null +++ b/queue-6.1/acpi-pad-fix-crash-in-exit_round_robin.patch @@ -0,0 +1,96 @@ +From 51b931c7853ea54f8305da0ff735599f8acd2c12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 25 Aug 2024 23:13:52 +0900 +Subject: ACPI: PAD: fix crash in exit_round_robin() + +From: Seiji Nishikawa + +[ Upstream commit 0a2ed70a549e61c5181bad5db418d223b68ae932 ] + +The kernel occasionally crashes in cpumask_clear_cpu(), which is called +within exit_round_robin(), because when executing clear_bit(nr, addr) with +nr set to 0xffffffff, the address calculation may cause misalignment within +the memory, leading to access to an invalid memory address. + +---------- +BUG: unable to handle kernel paging request at ffffffffe0740618 + ... +CPU: 3 PID: 2919323 Comm: acpi_pad/14 Kdump: loaded Tainted: G OE X --------- - - 4.18.0-425.19.2.el8_7.x86_64 #1 + ... +RIP: 0010:power_saving_thread+0x313/0x411 [acpi_pad] +Code: 89 cd 48 89 d3 eb d1 48 c7 c7 55 70 72 c0 e8 64 86 b0 e4 c6 05 0d a1 02 00 01 e9 bc fd ff ff 45 89 e4 42 8b 04 a5 20 82 72 c0 48 0f b3 05 f4 9c 01 00 42 c7 04 a5 20 82 72 c0 ff ff ff ff 31 +RSP: 0018:ff72a5d51fa77ec8 EFLAGS: 00010202 +RAX: 00000000ffffffff RBX: ff462981e5d8cb80 RCX: 0000000000000000 +RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000246 +RBP: ff46297556959d80 R08: 0000000000000382 R09: ff46297c8d0f38d8 +R10: 0000000000000000 R11: 0000000000000001 R12: 000000000000000e +R13: 0000000000000000 R14: ffffffffffffffff R15: 000000000000000e +FS: 0000000000000000(0000) GS:ff46297a800c0000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: ffffffffe0740618 CR3: 0000007e20410004 CR4: 0000000000771ee0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +PKRU: 55555554 +Call Trace: + ? acpi_pad_add+0x120/0x120 [acpi_pad] + kthread+0x10b/0x130 + ? set_kthread_struct+0x50/0x50 + ret_from_fork+0x1f/0x40 + ... +CR2: ffffffffe0740618 + +crash> dis -lr ffffffffc0726923 + ... +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 114 +0xffffffffc0726918 : mov %r12d,%r12d +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./include/linux/cpumask.h: 325 +0xffffffffc072691b : mov -0x3f8d7de0(,%r12,4),%eax +/usr/src/debug/kernel-4.18.0-425.19.2.el8_7/linux-4.18.0-425.19.2.el8_7.x86_64/./arch/x86/include/asm/bitops.h: 80 +0xffffffffc0726923 : lock btr %rax,0x19cf4(%rip) # 0xffffffffc0740620 + +crash> px tsk_in_cpu[14] +$66 = 0xffffffff + +crash> px 0xffffffffc072692c+0x19cf4 +$99 = 0xffffffffc0740620 + +crash> sym 0xffffffffc0740620 +ffffffffc0740620 (b) pad_busy_cpus_bits [acpi_pad] + +crash> px pad_busy_cpus_bits[0] +$42 = 0xfffc0 +---------- + +To fix this, ensure that tsk_in_cpu[tsk_index] != -1 before calling +cpumask_clear_cpu() in exit_round_robin(), just as it is done in +round_robin_cpu(). + +Signed-off-by: Seiji Nishikawa +Link: https://patch.msgid.link/20240825141352.25280-1-snishika@redhat.com +[ rjw: Subject edit, avoid updates to the same value ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpi_pad.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c +index ec0e22a1e25d6..bfb8ad1e2e855 100644 +--- a/drivers/acpi/acpi_pad.c ++++ b/drivers/acpi/acpi_pad.c +@@ -130,8 +130,10 @@ static void exit_round_robin(unsigned int tsk_index) + { + struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); + +- cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); +- tsk_in_cpu[tsk_index] = -1; ++ if (tsk_in_cpu[tsk_index] != -1) { ++ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus); ++ tsk_in_cpu[tsk_index] = -1; ++ } + } + + static unsigned int idle_pct = 5; /* percentage */ +-- +2.43.0 + diff --git a/queue-6.1/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch b/queue-6.1/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch new file mode 100644 index 00000000000..8fad874df20 --- /dev/null +++ b/queue-6.1/acpi-video-add-force_vendor-quirk-for-panasonic-toug.patch @@ -0,0 +1,45 @@ +From a9a8da2a717076146a052ffa962f3bf8c19afd7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Sep 2024 14:44:19 +0200 +Subject: ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18 + +From: Hans de Goede + +[ Upstream commit eb7b0f12e13ba99e64e3a690c2166895ed63b437 ] + +The Panasonic Toughbook CF-18 advertises both native and vendor backlight +control interfaces. But only the vendor one actually works. + +acpi_video_get_backlight_type() will pick the non working native backlight +by default, add a quirk to select the working vendor backlight instead. + +Signed-off-by: Hans de Goede +Link: https://patch.msgid.link/20240907124419.21195-1-hdegoede@redhat.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/video_detect.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c +index 60b0128a10e86..f7a2ab62c6c20 100644 +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -258,6 +258,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"), + }, + }, ++ { ++ .callback = video_detect_force_vendor, ++ /* Panasonic Toughbook CF-18 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), ++ }, ++ }, + + /* + * Toshiba models with Transflective display, these need to use +-- +2.43.0 + diff --git a/queue-6.1/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch b/queue-6.1/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch new file mode 100644 index 00000000000..bf32e6ce212 --- /dev/null +++ b/queue-6.1/acpica-check-null-return-of-acpi_allocate_zeroed-in-.patch @@ -0,0 +1,41 @@ +From 9edd0cc41eab339d37e8a22748567035506c9644 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jul 2024 14:05:48 +0800 +Subject: ACPICA: check null return of ACPI_ALLOCATE_ZEROED() in + acpi_db_convert_to_package() + +From: Pei Xiao + +[ Upstream commit a5242874488eba2b9062985bf13743c029821330 ] + +ACPICA commit 4d4547cf13cca820ff7e0f859ba83e1a610b9fd0 + +ACPI_ALLOCATE_ZEROED() may fail, elements might be NULL and will cause +NULL pointer dereference later. + +Link: https://github.com/acpica/acpica/commit/4d4547cf +Signed-off-by: Pei Xiao +Link: https://patch.msgid.link/tencent_4A21A2865B8B0A0D12CAEBEB84708EDDB505@qq.com +[ rjw: Subject and changelog edits ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/dbconvert.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c +index 2b84ac093698a..8dbab69320499 100644 +--- a/drivers/acpi/acpica/dbconvert.c ++++ b/drivers/acpi/acpica/dbconvert.c +@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object) + elements = + ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS * + sizeof(union acpi_object)); ++ if (!elements) ++ return (AE_NO_MEMORY); + + this = string; + for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) { +-- +2.43.0 + diff --git a/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch b/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch new file mode 100644 index 00000000000..f37bb46d1dd --- /dev/null +++ b/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_field-fai.patch @@ -0,0 +1,90 @@ +From b49bcf6dc7cf5bff6f0d7cf5f3542982fb4f9fac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Apr 2024 21:50:33 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_field() fails + +From: Armin Wolf + +[ Upstream commit e6169a8ffee8a012badd8c703716e761ce851b15 ] + +ACPICA commit 1280045754264841b119a5ede96cd005bc09b5a7 + +If acpi_ps_get_next_field() fails, the previously created field list +needs to be properly disposed before returning the status code. + +Link: https://github.com/acpica/acpica/commit/12800457 +Signed-off-by: Armin Wolf +[ rjw: Rename local variable to avoid compiler confusion ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/psargs.c | 39 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c +index 919a7aebcc036..418d56203e27a 100644 +--- a/drivers/acpi/acpica/psargs.c ++++ b/drivers/acpi/acpica/psargs.c +@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state); + static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + *parser_state); + ++static void acpi_ps_free_field_list(union acpi_parse_object *start); ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_package_length +@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state + return_PTR(field); + } + ++/******************************************************************************* ++ * ++ * FUNCTION: acpi_ps_free_field_list ++ * ++ * PARAMETERS: start - First Op in field list ++ * ++ * RETURN: None. ++ * ++ * DESCRIPTION: Free all Op objects inside a field list. ++ * ++ ******************************************************************************/ ++ ++static void acpi_ps_free_field_list(union acpi_parse_object *start) ++{ ++ union acpi_parse_object *cur = start; ++ union acpi_parse_object *next; ++ union acpi_parse_object *arg; ++ ++ while (cur) { ++ next = cur->common.next; ++ ++ /* AML_INT_CONNECTION_OP can have a single argument */ ++ ++ arg = acpi_ps_get_arg(cur, 0); ++ if (arg) { ++ acpi_ps_free_op(arg); ++ } ++ ++ acpi_ps_free_op(cur); ++ cur = next; ++ } ++} ++ + /******************************************************************************* + * + * FUNCTION: acpi_ps_get_next_arg +@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + while (parser_state->aml < parser_state->pkg_end) { + field = acpi_ps_get_next_field(parser_state); + if (!field) { ++ if (arg) { ++ acpi_ps_free_field_list(arg); ++ } ++ + return_ACPI_STATUS(AE_NO_MEMORY); + } + +-- +2.43.0 + diff --git a/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch b/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch new file mode 100644 index 00000000000..ae82313d760 --- /dev/null +++ b/queue-6.1/acpica-fix-memory-leak-if-acpi_ps_get_next_namepath-.patch @@ -0,0 +1,55 @@ +From 80db581bc1ab9ebeec0b003c221652d7422aeb3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Apr 2024 20:50:11 +0200 +Subject: ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails + +From: Armin Wolf + +[ Upstream commit 5accb265f7a1b23e52b0ec42313d1e12895552f4 ] + +ACPICA commit 2802af722bbde7bf1a7ac68df68e179e2555d361 + +If acpi_ps_get_next_namepath() fails, the previously allocated +union acpi_parse_object needs to be freed before returning the +status code. + +The issue was first being reported on the Linux ACPI mailing list: + +Link: https://lore.kernel.org/linux-acpi/56f94776-484f-48c0-8855-dba8e6a7793b@yandex.ru/T/ +Link: https://github.com/acpica/acpica/commit/2802af72 +Signed-off-by: Armin Wolf +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/psargs.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c +index f7ec5606098c7..919a7aebcc036 100644 +--- a/drivers/acpi/acpica/psargs.c ++++ b/drivers/acpi/acpica/psargs.c +@@ -820,6 +820,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_NOT_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + } else { + /* Single complex argument, nothing returned */ + +@@ -854,6 +858,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_POSSIBLE_METHOD_CALL); ++ if (ACPI_FAILURE(status)) { ++ acpi_ps_free_op(arg); ++ return_ACPI_STATUS(status); ++ } + + if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + +-- +2.43.0 + diff --git a/queue-6.1/acpica-iasl-handle-empty-connection_node.patch b/queue-6.1/acpica-iasl-handle-empty-connection_node.patch new file mode 100644 index 00000000000..a6efb0d7337 --- /dev/null +++ b/queue-6.1/acpica-iasl-handle-empty-connection_node.patch @@ -0,0 +1,36 @@ +From 064732672c079158ffdf490f56bc803360bfa5ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 23:33:44 +0200 +Subject: ACPICA: iasl: handle empty connection_node + +From: Aleksandrs Vinarskis + +[ Upstream commit a0a2459b79414584af6c46dd8c6f866d8f1aa421 ] + +ACPICA commit 6c551e2c9487067d4b085333e7fe97e965a11625 + +Link: https://github.com/acpica/acpica/commit/6c551e2c +Signed-off-by: Aleksandrs Vinarskis +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + drivers/acpi/acpica/exprep.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c +index 08f06797386af..4daef7530d91b 100644 +--- a/drivers/acpi/acpica/exprep.c ++++ b/drivers/acpi/acpica/exprep.c +@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) + + if (info->connection_node) { + second_desc = info->connection_node->object; ++ if (second_desc == NULL) { ++ break; ++ } + if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = + acpi_ds_get_buffer_arguments(second_desc); +-- +2.43.0 + diff --git a/queue-6.1/alsa-asihpi-fix-potential-oob-array-access.patch b/queue-6.1/alsa-asihpi-fix-potential-oob-array-access.patch new file mode 100644 index 00000000000..86a3bf22dd6 --- /dev/null +++ b/queue-6.1/alsa-asihpi-fix-potential-oob-array-access.patch @@ -0,0 +1,39 @@ +From 67cbd2ff7f9876418e245f074d1b153e55b5559c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:14:42 +0200 +Subject: ALSA: asihpi: Fix potential OOB array access + +From: Takashi Iwai + +[ Upstream commit 7b986c7430a6bb68d523dac7bfc74cbd5b44ef96 ] + +ASIHPI driver stores some values in the static array upon a response +from the driver, and its index depends on the firmware. We shouldn't +trust it blindly. + +This patch adds a sanity check of the array index to fit in the array +size. + +Link: https://patch.msgid.link/20240808091454.30846-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/asihpi/hpimsgx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c +index d0caef2994818..b68e6bfbbfbab 100644 +--- a/sound/pci/asihpi/hpimsgx.c ++++ b/sound/pci/asihpi/hpimsgx.c +@@ -708,7 +708,7 @@ static u16 HPIMSGX__init(struct hpi_message *phm, + phr->error = HPI_ERROR_PROCESSING_MESSAGE; + return phr->error; + } +- if (hr.error == 0) { ++ if (hr.error == 0 && hr.u.s.adapter_index < HPI_MAX_ADAPTERS) { + /* the adapter was created successfully + save the mapping for future use */ + hpi_entry_points[hr.u.s.adapter_index] = entry_point_func; +-- +2.43.0 + diff --git a/queue-6.1/alsa-hdsp-break-infinite-midi-input-flush-loop.patch b/queue-6.1/alsa-hdsp-break-infinite-midi-input-flush-loop.patch new file mode 100644 index 00000000000..a80d42d125b --- /dev/null +++ b/queue-6.1/alsa-hdsp-break-infinite-midi-input-flush-loop.patch @@ -0,0 +1,60 @@ +From 685b0f203ef5883bc98c10280037bca03a20e914 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 11:15:12 +0200 +Subject: ALSA: hdsp: Break infinite MIDI input flush loop + +From: Takashi Iwai + +[ Upstream commit c01f3815453e2d5f699ccd8c8c1f93a5b8669e59 ] + +The current MIDI input flush on HDSP and HDSPM drivers relies on the +hardware reporting the right value. If the hardware doesn't give the +proper value but returns -1, it may be stuck at an infinite loop. + +Add a counter and break if the loop is unexpectedly too long. + +Link: https://patch.msgid.link/20240808091513.31380-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/pci/rme9652/hdsp.c | 6 ++++-- + sound/pci/rme9652/hdspm.c | 6 ++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c +index 65add92c88aa6..cd7bf4d7ca082 100644 +--- a/sound/pci/rme9652/hdsp.c ++++ b/sound/pci/rme9652/hdsp.c +@@ -1298,8 +1298,10 @@ static int snd_hdsp_midi_output_possible (struct hdsp *hdsp, int id) + + static void snd_hdsp_flush_midi_input (struct hdsp *hdsp, int id) + { +- while (snd_hdsp_midi_input_available (hdsp, id)) +- snd_hdsp_midi_read_byte (hdsp, id); ++ int count = 256; ++ ++ while (snd_hdsp_midi_input_available(hdsp, id) && --count) ++ snd_hdsp_midi_read_byte(hdsp, id); + } + + static int snd_hdsp_midi_output_write (struct hdsp_midi *hmidi) +diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c +index fa1812e7a49dc..247f5c52fb090 100644 +--- a/sound/pci/rme9652/hdspm.c ++++ b/sound/pci/rme9652/hdspm.c +@@ -1838,8 +1838,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) + + static void snd_hdspm_flush_midi_input(struct hdspm *hdspm, int id) + { +- while (snd_hdspm_midi_input_available (hdspm, id)) +- snd_hdspm_midi_read_byte (hdspm, id); ++ int count = 256; ++ ++ while (snd_hdspm_midi_input_available(hdspm, id) && --count) ++ snd_hdspm_midi_read_byte(hdspm, id); + } + + static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) +-- +2.43.0 + diff --git a/queue-6.1/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch b/queue-6.1/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch new file mode 100644 index 00000000000..0d43c2b7694 --- /dev/null +++ b/queue-6.1/alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch @@ -0,0 +1,140 @@ +From 70bad5e28d41488af18d91abf102866d423e3ba7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Aug 2024 14:46:50 +0200 +Subject: ALSA: usb-audio: Add input value sanity checks for standard types + +From: Takashi Iwai + +[ Upstream commit 901e85677ec0bb9a69fb9eab1feafe0c4eb7d07e ] + +For an invalid input value that is out of the given range, currently +USB-audio driver corrects the value silently and accepts without +errors. This is no wrong behavior, per se, but the recent kselftest +rather wants to have an error in such a case, hence a different +behavior is expected now. + +This patch adds a sanity check at each control put for the standard +mixer types and returns an error if an invalid value is given. + +Note that this covers only the standard mixer types. The mixer quirks +that have own control callbacks would need different coverage. + +Link: https://patch.msgid.link/20240806124651.28203-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer.c | 35 +++++++++++++++++++++++++++-------- + sound/usb/mixer.h | 1 + + 2 files changed, 28 insertions(+), 8 deletions(-) + +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 34ded71cb8077..49facdf35b159 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -1377,6 +1377,19 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, + + #define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) + ++/* get the max value advertised via control API */ ++static int get_max_exposed(struct usb_mixer_elem_info *cval) ++{ ++ if (!cval->max_exposed) { ++ if (cval->res) ++ cval->max_exposed = ++ DIV_ROUND_UP(cval->max - cval->min, cval->res); ++ else ++ cval->max_exposed = cval->max - cval->min; ++ } ++ return cval->max_exposed; ++} ++ + /* get a feature/mixer unit info */ + static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +@@ -1389,11 +1402,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = cval->channels; +- if (cval->val_type == USB_MIXER_BOOLEAN || +- cval->val_type == USB_MIXER_INV_BOOLEAN) { +- uinfo->value.integer.min = 0; +- uinfo->value.integer.max = 1; +- } else { ++ if (cval->val_type != USB_MIXER_BOOLEAN && ++ cval->val_type != USB_MIXER_INV_BOOLEAN) { + if (!cval->initialized) { + get_min_max_with_quirks(cval, 0, kcontrol); + if (cval->initialized && cval->dBmin >= cval->dBmax) { +@@ -1405,10 +1415,10 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, + &kcontrol->id); + } + } +- uinfo->value.integer.min = 0; +- uinfo->value.integer.max = +- DIV_ROUND_UP(cval->max - cval->min, cval->res); + } ++ ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = get_max_exposed(cval); + return 0; + } + +@@ -1449,6 +1459,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { + struct usb_mixer_elem_info *cval = kcontrol->private_data; ++ int max_val = get_max_exposed(cval); + int c, cnt, val, oval, err; + int changed = 0; + +@@ -1461,6 +1472,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[cnt]; ++ if (val < 0 || val > max_val) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (oval != val) { + snd_usb_set_cur_mix_value(cval, c + 1, cnt, val); +@@ -1474,6 +1487,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[0]; ++ if (val < 0 || val > max_val) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + snd_usb_set_cur_mix_value(cval, 0, 0, val); +@@ -2339,6 +2354,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.integer.value[0]; ++ if (val < 0 || val > get_max_exposed(cval)) ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + set_cur_ctl_value(cval, cval->control << 8, val); +@@ -2701,6 +2718,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, + if (err < 0) + return filter_error(cval, err); + val = ucontrol->value.enumerated.item[0]; ++ if (val < 0 || val >= cval->max) /* here cval->max = # elements */ ++ return -EINVAL; + val = get_abs_value(cval, val); + if (val != oval) { + set_cur_ctl_value(cval, cval->control << 8, val); +diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h +index d43895c1ae5c6..167fbfcf01ace 100644 +--- a/sound/usb/mixer.h ++++ b/sound/usb/mixer.h +@@ -88,6 +88,7 @@ struct usb_mixer_elem_info { + int channels; + int val_type; + int min, max, res; ++ int max_exposed; /* control API exposes the value in 0..max_exposed */ + int dBmin, dBmax; + int cached; + int cache_val[MAX_CHANNELS]; +-- +2.43.0 + diff --git a/queue-6.1/alsa-usb-audio-add-logitech-audio-profile-quirk.patch b/queue-6.1/alsa-usb-audio-add-logitech-audio-profile-quirk.patch new file mode 100644 index 00000000000..3c87204c2db --- /dev/null +++ b/queue-6.1/alsa-usb-audio-add-logitech-audio-profile-quirk.patch @@ -0,0 +1,40 @@ +From 162335cfe799b39b3cbc61b626e5d79941854632 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Sep 2024 15:26:28 +0000 +Subject: ALSA: usb-audio: Add logitech Audio profile quirk + +From: Joshua Pius + +[ Upstream commit a51c925c11d7b855167e64b63eb4378e5adfc11d ] + +Specify shortnames for the following Logitech Devices: Rally bar, Rally +bar mini, Tap, MeetUp and Huddle. + +Signed-off-by: Joshua Pius +Link: https://patch.msgid.link/20240912152635.1859737-1-joshuapius@google.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/card.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 811bda4eeb9cf..74c5a87dff38e 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = { + /* Creative/Toshiba Multimedia Center SB-0500 */ + DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"), + ++ /* Logitech Audio Devices */ ++ DEVICE_NAME(0x046d, 0x0867, "Logitech, Inc.", "Logi-MeetUp"), ++ DEVICE_NAME(0x046d, 0x0874, "Logitech, Inc.", "Logi-Tap-Audio"), ++ DEVICE_NAME(0x046d, 0x087c, "Logitech, Inc.", "Logi-Huddle"), ++ DEVICE_NAME(0x046d, 0x0898, "Logitech, Inc.", "Logi-RB-Audio"), ++ DEVICE_NAME(0x046d, 0x08d2, "Logitech, Inc.", "Logi-RBM-Audio"), + DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"), + + DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"), +-- +2.43.0 + diff --git a/queue-6.1/alsa-usb-audio-define-macros-for-quirk-table-entries.patch b/queue-6.1/alsa-usb-audio-define-macros-for-quirk-table-entries.patch new file mode 100644 index 00000000000..7abf01d35e6 --- /dev/null +++ b/queue-6.1/alsa-usb-audio-define-macros-for-quirk-table-entries.patch @@ -0,0 +1,111 @@ +From 40d03c43e3152dd9a6287fb00673025692e61f14 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:41 +0200 +Subject: ALSA: usb-audio: Define macros for quirk table entries + +From: Takashi Iwai + +[ Upstream commit 0c3ad39b791c2ecf718afcaca30e5ceafa939d5c ] + +Many entries in the USB-audio quirk tables have relatively complex +expressions. For improving the readability, introduce a few macros. +Those are applied in the following patch. + +Link: https://patch.msgid.link/20240814134844.2726-2-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 77 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 77 insertions(+) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index d2aa97a5c438c..a0063caa769c5 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -35,6 +35,83 @@ + .bInterfaceClass = USB_CLASS_AUDIO, \ + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL + ++/* Quirk .driver_info, followed by the definition of the quirk entry; ++ * put like QUIRK_DRIVER_INFO { ... } in each entry of the quirk table ++ */ ++#define QUIRK_DRIVER_INFO \ ++ .driver_info = (unsigned long)&(const struct snd_usb_audio_quirk) ++ ++/* ++ * Macros for quirk data entries ++ */ ++ ++/* Quirk data entry for ignoring the interface */ ++#define QUIRK_DATA_IGNORE(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_IGNORE_INTERFACE ++/* Quirk data entry for a standard audio interface */ ++#define QUIRK_DATA_STANDARD_AUDIO(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_INTERFACE ++/* Quirk data entry for a standard MIDI interface */ ++#define QUIRK_DATA_STANDARD_MIDI(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_STANDARD_INTERFACE ++/* Quirk data entry for a standard mixer interface */ ++#define QUIRK_DATA_STANDARD_MIXER(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_STANDARD_MIXER ++ ++/* Quirk data entry for Yamaha MIDI */ ++#define QUIRK_DATA_MIDI_YAMAHA(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_YAMAHA ++/* Quirk data entry for Edirol UAxx */ ++#define QUIRK_DATA_EDIROL_UAXX(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_AUDIO_EDIROL_UAXX ++/* Quirk data entry for raw bytes interface */ ++#define QUIRK_DATA_RAW_BYTES(_ifno) \ ++ .ifnum = (_ifno), .type = QUIRK_MIDI_RAW_BYTES ++ ++/* Quirk composite array terminator */ ++#define QUIRK_COMPOSITE_END { .ifnum = -1 } ++ ++/* Quirk data entry for composite quirks; ++ * followed by the quirk array that is terminated with QUIRK_COMPOSITE_END ++ * e.g. QUIRK_DATA_COMPOSITE { { quirk1 }, { quirk2 },..., QUIRK_COMPOSITE_END } ++ */ ++#define QUIRK_DATA_COMPOSITE \ ++ .ifnum = QUIRK_ANY_INTERFACE, \ ++ .type = QUIRK_COMPOSITE, \ ++ .data = &(const struct snd_usb_audio_quirk[]) ++ ++/* Quirk data entry for a fixed audio endpoint; ++ * followed by audioformat definition ++ * e.g. QUIRK_DATA_AUDIOFORMAT(n) { .formats = xxx, ... } ++ */ ++#define QUIRK_DATA_AUDIOFORMAT(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_AUDIO_FIXED_ENDPOINT, \ ++ .data = &(const struct audioformat) ++ ++/* Quirk data entry for a fixed MIDI endpoint; ++ * followed by snd_usb_midi_endpoint_info definition ++ * e.g. QUIRK_DATA_MIDI_FIXED_ENDPOINT(n) { .out_cables = x, .in_cables = y } ++ */ ++#define QUIRK_DATA_MIDI_FIXED_ENDPOINT(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_FIXED_ENDPOINT, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++/* Quirk data entry for a MIDIMAN MIDI endpoint */ ++#define QUIRK_DATA_MIDI_MIDIMAN(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_MIDIMAN, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++/* Quirk data entry for a EMAGIC MIDI endpoint */ ++#define QUIRK_DATA_MIDI_EMAGIC(_ifno) \ ++ .ifnum = (_ifno), \ ++ .type = QUIRK_MIDI_EMAGIC, \ ++ .data = &(const struct snd_usb_midi_endpoint_info) ++ ++/* ++ * Here we go... the quirk table definition begins: ++ */ ++ + /* FTDI devices */ + { + USB_DEVICE(0x0403, 0xb8d8), +-- +2.43.0 + diff --git a/queue-6.1/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch b/queue-6.1/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch new file mode 100644 index 00000000000..4f343aa9cc7 --- /dev/null +++ b/queue-6.1/alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch @@ -0,0 +1,4000 @@ +From 513af1d3bc46e0d8213583a4f2b9f66abf6c8cef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Aug 2024 15:48:42 +0200 +Subject: ALSA: usb-audio: Replace complex quirk lines with macros + +From: Takashi Iwai + +[ Upstream commit d79e13f8e8abb5cd3a2a0f9fc9bc3fc750c5b06f ] + +Apply the newly introduced macros for reduce the complex expressions +and cast in the quirk table definitions. It results in a significant +code reduction, too. + +There should be no functional changes. + +Link: https://patch.msgid.link/20240814134844.2726-3-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/quirks-table.h | 2210 ++++++++++---------------------------- + 1 file changed, 593 insertions(+), 1617 deletions(-) + +diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h +index a0063caa769c5..75cde5779f38d 100644 +--- a/sound/usb/quirks-table.h ++++ b/sound/usb/quirks-table.h +@@ -115,7 +115,7 @@ + /* FTDI devices */ + { + USB_DEVICE(0x0403, 0xb8d8), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "STARR LABS", */ + /* .product_name = "Starr Labs MIDI USB device", */ + .ifnum = 0, +@@ -126,10 +126,8 @@ + { + /* Creative BT-D1 */ + USB_DEVICE(0x041e, 0x0005), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 1, +@@ -164,18 +162,11 @@ + */ + { + USB_AUDIO_DEVICE(0x041e, 0x4095), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(2) }, + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .fmt_bits = 16, +@@ -191,9 +182,7 @@ + .rate_table = (unsigned int[]) { 48000 }, + }, + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + }, + }, + }, +@@ -205,31 +194,18 @@ + */ + { + USB_DEVICE(0x0424, 0xb832), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Standard Microsystems Corp.", + .product_name = "HP Wireless Audio", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + /* Mixer */ +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE, +- }, ++ { QUIRK_DATA_IGNORE(0) }, + /* Playback */ +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE, +- }, ++ { QUIRK_DATA_IGNORE(1) }, + /* Capture */ +- { +- .ifnum = 2, +- .type = QUIRK_IGNORE_INTERFACE, +- }, ++ { QUIRK_DATA_IGNORE(2) }, + /* HID Device, .ifnum = 3 */ +- { +- .ifnum = -1, +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -252,20 +228,18 @@ + + #define YAMAHA_DEVICE(id, name) { \ + USB_DEVICE(0x0499, id), \ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \ ++ QUIRK_DRIVER_INFO { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ +- .ifnum = QUIRK_ANY_INTERFACE, \ +- .type = QUIRK_MIDI_YAMAHA \ ++ QUIRK_DATA_MIDI_YAMAHA(QUIRK_ANY_INTERFACE) \ + } \ + } + #define YAMAHA_INTERFACE(id, intf, name) { \ + USB_DEVICE_VENDOR_SPEC(0x0499, id), \ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \ ++ QUIRK_DRIVER_INFO { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ +- .ifnum = intf, \ +- .type = QUIRK_MIDI_YAMAHA \ ++ QUIRK_DATA_MIDI_YAMAHA(intf) \ + } \ + } + YAMAHA_DEVICE(0x1000, "UX256"), +@@ -353,135 +327,67 @@ YAMAHA_DEVICE(0x105d, NULL), + YAMAHA_DEVICE(0x1718, "P-125"), + { + USB_DEVICE(0x0499, 0x1503), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Yamaha", */ + /* .product_name = "MOX6/MOX8", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_YAMAHA +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_MIDI_YAMAHA(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0499, 0x1507), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Yamaha", */ + /* .product_name = "THR10", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_YAMAHA +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_MIDI_YAMAHA(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0499, 0x1509), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Yamaha", */ + /* .product_name = "Steinberg UR22", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_YAMAHA +- }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_MIDI_YAMAHA(3) }, ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0499, 0x150a), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Yamaha", */ + /* .product_name = "THR5A", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_YAMAHA +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_MIDI_YAMAHA(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0499, 0x150c), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Yamaha", */ + /* .product_name = "THR10C", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_YAMAHA +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_MIDI_YAMAHA(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -515,7 +421,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0x0499, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUTODETECT + } +@@ -526,16 +432,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + { + USB_DEVICE(0x0582, 0x0000), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "UA-100", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 4, + .iface = 0, +@@ -550,9 +452,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 1, +@@ -567,106 +467,66 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-4", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0003), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "SC-8850", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x003f, + .in_cables = 0x003f + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0004), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "U-8", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0005, + .in_cables = 0x0005 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -674,152 +534,92 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Has ID 0x0099 when not in "Advanced Driver" mode. + * The UM-2EX has only one input, but we cannot detect this. */ + USB_DEVICE(0x0582, 0x0005), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0007), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "SC-8820", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0008), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "PC-300", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x009d when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0009), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-1", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x000b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "SK-500", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0013, + .in_cables = 0x0013 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -827,31 +627,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* thanks to Emiliano Grilli + * for helping researching this data */ + USB_DEVICE(0x0582, 0x000c), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "SC-D70", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -865,35 +653,23 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * the 96kHz sample rate. + */ + USB_DEVICE(0x0582, 0x0010), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-5", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0013 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0012), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "XV-5050", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -902,12 +678,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0015 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0014), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-880", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -916,74 +690,48 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0017 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0016), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-90", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x000f, + .in_cables = 0x000f + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x001c when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x001b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "MMP-2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x001e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x001d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "V-SYNTH", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -992,12 +740,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0024 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0023), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-550", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x003f, + .in_cables = 0x003f + } +@@ -1010,20 +756,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and no MIDI. + */ + USB_DEVICE(0x0582, 0x0025), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-20", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, +@@ -1038,9 +777,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 2, +@@ -1055,28 +792,22 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0028 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0027), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-20", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1085,12 +816,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x002a when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0029), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "SD-80", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x000f, + .in_cables = 0x000f + } +@@ -1103,39 +832,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * but offers only 16-bit PCM and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-700", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ { QUIRK_DATA_EDIROL_UAXX(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x002e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x002d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "XV-2020", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1144,12 +858,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0030 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x002f), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "VariOS", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } +@@ -1158,12 +870,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0034 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0033), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1175,12 +885,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * later revisions use IDs 0x0054 and 0x00a2. + */ + USB_DEVICE(0x0582, 0x0037), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "Digital Piano", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1193,39 +901,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "BOSS", + .product_name = "GS-10", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ { QUIRK_DATA_STANDARD_MIDI(3) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0041 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "GI-20", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1234,12 +927,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0043 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0042), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "RS-70", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1248,36 +939,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0049 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0047), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + /* in the 96 kHz modes, only interface 1 is there */ +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x004a when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0048), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "UR-80", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1286,35 +965,23 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x004e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x004c), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR-A", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x004f when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x004d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PCR-A", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } +@@ -1326,76 +993,52 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * is standard compliant, but has only 16-bit PCM. + */ + USB_DEVICE(0x0582, 0x0050), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-3FX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0052), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UM-1SX", +- .ifnum = 0, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(0) + } + }, + { + USB_DEVICE(0x0582, 0x0060), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "EXR Series", +- .ifnum = 0, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(0) + } + }, + { + /* has ID 0x0066 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0064), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0067 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0065), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0003 + } +@@ -1404,12 +1047,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x006e when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x006d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "FANTOM-X", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1422,39 +1063,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * offers only 16-bit PCM at 44.1 kHz and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x0074), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-25", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* has ID 0x0076 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0075), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "BOSS", + .product_name = "DR-880", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1463,12 +1089,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x007b when not in "Advanced Driver" mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x007a), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + /* "RD" or "RD-700SX"? */ +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } +@@ -1477,12 +1101,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x0081 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0080), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Roland", + .product_name = "G-70", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1491,12 +1113,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* has ID 0x008c when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x008b), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "PC-50", +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1508,56 +1128,31 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * is standard compliant, but has only 16-bit PCM and no MIDI. + */ + USB_DEVICE(0x0582, 0x00a3), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-4FX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Edirol M-16DX */ + USB_DEVICE(0x0582, 0x00c4), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -1567,37 +1162,22 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * offers only 16-bit PCM at 44.1 kHz and no MIDI. + */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e6), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "EDIROL", + .product_name = "UA-25EX", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_EDIROL_UAXX +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_EDIROL_UAXX(0) }, ++ { QUIRK_DATA_EDIROL_UAXX(1) }, ++ { QUIRK_DATA_EDIROL_UAXX(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Edirol UM-3G */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = 0, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(0) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } +@@ -1606,45 +1186,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* BOSS ME-25 */ + USB_DEVICE(0x0582, 0x0113), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* only 44.1 kHz works at the moment */ + USB_DEVICE(0x0582, 0x0120), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "OCTO-CAPTURE", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 10, + .iface = 0, +@@ -1660,9 +1224,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 12, + .iface = 1, +@@ -1678,40 +1240,26 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* only 44.1 kHz works at the moment */ + USB_DEVICE(0x0582, 0x012f), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "QUAD-CAPTURE", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 4, + .iface = 0, +@@ -1727,9 +1275,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 6, + .iface = 1, +@@ -1745,54 +1291,32 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0582, 0x0159), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-22", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(2) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -1800,19 +1324,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* UA101 and co are supported by another driver */ + { + USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, + { + USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, + { + USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */ +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_NODEV_INTERFACE + }, + }, +@@ -1823,7 +1347,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0x0582, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUTODETECT + } +@@ -1838,12 +1362,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * compliant USB MIDI ports for external MIDI and controls. + */ + USB_DEVICE_VENDOR_SPEC(0x06f8, 0xb000), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Hercules", + .product_name = "DJ Console (WE)", +- .ifnum = 4, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1853,12 +1375,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Midiman/M-Audio devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 2x2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } +@@ -1866,12 +1386,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1011), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 1x1", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1879,12 +1397,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1015), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Keystation", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -1892,12 +1408,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1021), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 4x4", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x000f, + .in_cables = 0x000f + } +@@ -1910,12 +1424,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Thanks to Olaf Giesbrecht + */ + USB_DEVICE_VER(0x0763, 0x1031, 0x0100, 0x0109), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 8x8", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -1923,12 +1435,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 8x8", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x01ff, + .in_cables = 0x01ff + } +@@ -1936,12 +1446,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x1041), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "MidiSport 2x4", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(QUIRK_ANY_INTERFACE) { + .out_cables = 0x000f, + .in_cables = 0x0003 + } +@@ -1949,76 +1457,41 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Quattro", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + /* + * Interfaces 0-2 are "Windows-compatible", 16-bit only, + * and share endpoints with the other interfaces. + * Ignore them. The other interfaces can do 24 bits, + * but captured samples are big-endian (see usbaudio.c). + */ +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 5, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 7, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 8, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 9, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ { QUIRK_DATA_IGNORE(2) }, ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, ++ { QUIRK_DATA_STANDARD_AUDIO(5) }, ++ { QUIRK_DATA_IGNORE(6) }, ++ { QUIRK_DATA_STANDARD_AUDIO(7) }, ++ { QUIRK_DATA_STANDARD_AUDIO(8) }, ++ { ++ QUIRK_DATA_MIDI_MIDIMAN(9) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "AudioPhile", +- .ifnum = 6, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(6) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -2026,12 +1499,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2008), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "Ozone", +- .ifnum = 3, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } +@@ -2039,93 +1510,45 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "M-Audio", + .product_name = "OmniStudio", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 5, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 7, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 8, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 9, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ { QUIRK_DATA_IGNORE(2) }, ++ { QUIRK_DATA_IGNORE(3) }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, ++ { QUIRK_DATA_STANDARD_AUDIO(5) }, ++ { QUIRK_DATA_IGNORE(6) }, ++ { QUIRK_DATA_STANDARD_AUDIO(7) }, ++ { QUIRK_DATA_STANDARD_AUDIO(8) }, ++ { ++ QUIRK_DATA_MIDI_MIDIMAN(9) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x0763, 0x2019), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Ozone Academic", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 3, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2135,21 +1558,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2030), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track C400", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(1) }, + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 2, +@@ -2173,9 +1589,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 3, +@@ -2197,30 +1611,21 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x80, + } + }, +- /* MIDI */ +- { +- .ifnum = -1 /* Interface = 4 */ +- } ++ /* MIDI: Interface = 4*/ ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2031), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track C600", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(1) }, + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2244,9 +1649,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 3, +@@ -2268,29 +1671,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x80, + } + }, +- /* MIDI */ +- { +- .ifnum = -1 /* Interface = 4 */ +- } ++ /* MIDI: Interface = 4 */ ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2080), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track Ultra", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -2312,9 +1706,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2336,28 +1728,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + /* interface 3 (MIDI) is standard compliant */ +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0763, 0x2081), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Fast Track Ultra 8R", */ +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -2379,9 +1762,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -2403,9 +1784,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + /* interface 3 (MIDI) is standard compliant */ +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2413,21 +1792,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Casio devices */ + { + USB_DEVICE(0x07cf, 0x6801), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Casio", + .product_name = "PL-40R", +- .ifnum = 0, +- .type = QUIRK_MIDI_YAMAHA ++ QUIRK_DATA_MIDI_YAMAHA(0) + } + }, + { + /* this ID is used by several devices without a product ID */ + USB_DEVICE(0x07cf, 0x6802), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Casio", + .product_name = "Keyboard", +- .ifnum = 0, +- .type = QUIRK_MIDI_YAMAHA ++ QUIRK_DATA_MIDI_YAMAHA(0) + } + }, + +@@ -2440,23 +1817,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .idVendor = 0x07fd, + .idProduct = 0x0001, + .bDeviceSubClass = 2, +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MOTU", + .product_name = "Fastlane", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_RAW_BYTES(0) }, ++ { QUIRK_DATA_IGNORE(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2464,12 +1831,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Emagic devices */ + { + USB_DEVICE(0x086a, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + .product_name = "Unitor8", +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x80ff, + .in_cables = 0x80ff + } +@@ -2477,12 +1842,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x086a, 0x0002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + /* .product_name = "AMT8", */ +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x80ff, + .in_cables = 0x80ff + } +@@ -2490,12 +1853,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x086a, 0x0003), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Emagic", + /* .product_name = "MT4", */ +- .ifnum = 2, +- .type = QUIRK_MIDI_EMAGIC, +- .data = & (const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_EMAGIC(2) { + .out_cables = 0x800f, + .in_cables = 0x8003 + } +@@ -2505,38 +1866,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* KORG devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0200), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "PANDORA PX5D", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab ST", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + { + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab EX", */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + + /* AKAI devices */ + { + USB_DEVICE(0x09e8, 0x0062), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "AKAI", + .product_name = "MPD16", + .ifnum = 0, +@@ -2547,21 +1905,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Akai MPC Element */ + USB_DEVICE(0x09e8, 0x0021), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_STANDARD_MIDI(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2570,66 +1918,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Steinberg MI2 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x2040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Steinberg MI4 */ + USB_DEVICE_VENDOR_SPEC(0x0a4e, 0x4040), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = & (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2637,34 +1955,31 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* TerraTec devices */ + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0014), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TerraTec", + .product_name = "PHASE 26", +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DATA_STANDARD_MIDI(3) + } + }, + { + USB_DEVICE(0x0ccd, 0x0035), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Miditech", + .product_name = "Play'n Roll", + .ifnum = 0, +@@ -2679,7 +1994,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Novation EMS devices */ + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "ReMOTE Audio/XStation", + .ifnum = 4, +@@ -2688,7 +2003,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x0002), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "Speedio", + .ifnum = 3, +@@ -2697,38 +2012,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + USB_DEVICE(0x1235, 0x000a), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Novation", */ + /* .product_name = "Nocturn", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES ++ QUIRK_DATA_RAW_BYTES(0) + } + }, + { + USB_DEVICE(0x1235, 0x000e), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + /* .vendor_name = "Novation", */ + /* .product_name = "Launchpad", */ +- .ifnum = 0, +- .type = QUIRK_MIDI_RAW_BYTES ++ QUIRK_DATA_RAW_BYTES(0) + } + }, + { + USB_DEVICE(0x1235, 0x0010), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Focusrite", + .product_name = "Saffire 6 USB", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -2755,9 +2061,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, +@@ -2779,28 +2083,19 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_RAW_BYTES(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE(0x1235, 0x0018), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "Twitch", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = & (const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -2819,19 +2114,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 1, +- .type = QUIRK_MIDI_RAW_BYTES +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_RAW_BYTES(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, + { + USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Novation", + .product_name = "ReMOTE25", + .ifnum = 0, +@@ -2843,25 +2133,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* VirusTI Desktop */ + USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 3, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(3) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + }, +- { +- .ifnum = 4, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_IGNORE(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2889,7 +2170,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* QinHeng devices */ + { + USB_DEVICE(0x1a86, 0x752d), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "QinHeng", + .product_name = "CH345", + .ifnum = 1, +@@ -2903,7 +2184,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Miditech devices */ + { + USB_DEVICE(0x4752, 0x0011), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Miditech", + .product_name = "Midistart-2", + .ifnum = 0, +@@ -2915,7 +2196,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* this ID used by both Miditech MidiStudio-2 and CME UF-x */ + USB_DEVICE(0x7104, 0x2202), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .ifnum = 0, + .type = QUIRK_MIDI_CME + } +@@ -2925,20 +2206,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + /* Thanks to Clemens Ladisch */ + USB_DEVICE(0x0dba, 0x1000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "MBox", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]){ +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE{ ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 1, +@@ -2959,9 +2233,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 1, +@@ -2982,9 +2254,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -2992,24 +2262,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* DIGIDESIGN MBOX 2 */ + { + USB_DEVICE(0x0dba, 0x3000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "Mbox 2", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 2, +@@ -3027,15 +2287,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, ++ { QUIRK_DATA_IGNORE(3) }, + { +- .ifnum = 3, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { +- .formats = SNDRV_PCM_FMTBIT_S24_3BE, ++ QUIRK_DATA_AUDIOFORMAT(4) { ++ .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 4, + .altsetting = 2, +@@ -3052,14 +2307,9 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, ++ { QUIRK_DATA_IGNORE(5) }, + { +- .ifnum = 5, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 6, +- .type = QUIRK_MIDI_MIDIMAN, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_MIDIMAN(6) { + .out_ep = 0x02, + .out_cables = 0x0001, + .in_ep = 0x81, +@@ -3067,33 +2317,21 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + /* DIGIDESIGN MBOX 3 */ + { + USB_DEVICE(0x0dba, 0x5000), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Digidesign", + .product_name = "Mbox 3", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_IGNORE(1) }, + { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 2, +@@ -3113,9 +2351,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 3, +@@ -3136,36 +2372,25 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 4, +- .type = QUIRK_MIDI_FIXED_ENDPOINT, +- .data = &(const struct snd_usb_midi_endpoint_info) { ++ QUIRK_DATA_MIDI_FIXED_ENDPOINT(4) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, + { + /* Tascam US122 MKII - playback-only support */ + USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "TASCAM", + .product_name = "US122 MKII", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, +@@ -3186,9 +2411,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3196,20 +2419,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + /* Denon DN-X1600 */ + { + USB_AUDIO_DEVICE(0x154e, 0x500e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Denon", + .product_name = "DN-X1600", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]){ ++ QUIRK_DATA_COMPOSITE{ ++ { QUIRK_DATA_IGNORE(0) }, + { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, +@@ -3230,9 +2446,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, +@@ -3252,13 +2466,8 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = 4, +- .type = QUIRK_MIDI_STANDARD_INTERFACE, +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_MIDI(4) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3267,17 +2476,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + USB_DEVICE(0x045e, 0x0283), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Microsoft", + .product_name = "XboxLive Headset/Xbox Communicator", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { + { + /* playback */ +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 0, +@@ -3293,9 +2498,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + { + /* capture */ +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 1, +@@ -3309,9 +2512,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 16000 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3320,18 +2521,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), + { + USB_DEVICE(0x200c, 0x100b), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 1, +@@ -3350,9 +2544,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3365,28 +2557,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * enabled in create_standard_audio_quirk(). + */ + USB_DEVICE(0x1686, 0x00dd), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- /* Playback */ +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- /* Capture */ +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- /* Midi */ +- .ifnum = 3, +- .type = QUIRK_MIDI_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, /* Playback */ ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, /* Capture */ ++ { QUIRK_DATA_STANDARD_MIDI(3) }, /* Midi */ ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3400,18 +2576,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_MIDI_STANDARD_INTERFACE ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_STANDARD_MIDI(QUIRK_ANY_INTERFACE) + } + }, + + /* Rane SL-1 */ + { + USB_DEVICE(0x13e5, 0x0001), +- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_STANDARD_AUDIO(QUIRK_ANY_INTERFACE) + } + }, + +@@ -3427,24 +2601,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and only the 48 kHz sample rate works for the playback interface. + */ + USB_DEVICE(0x0a12, 0x1243), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- /* Capture */ +- { +- .ifnum = 1, +- .type = QUIRK_IGNORE_INTERFACE, +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, ++ { QUIRK_DATA_IGNORE(1) }, /* Capture */ + /* Playback */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 2, +@@ -3463,9 +2626,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3478,19 +2639,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * even on windows. + */ + USB_DEVICE(0x19b5, 0x0021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 1, +@@ -3509,29 +2663,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- }, ++ QUIRK_COMPOSITE_END + } + } + }, + /* MOTU Microbook II */ + { + USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .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, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(0) }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 6, + .iface = 0, +@@ -3552,9 +2697,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 8, + .iface = 0, +@@ -3575,9 +2718,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3589,14 +2730,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The feedback for the output is the input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0023), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 12, + .iface = 0, +@@ -3613,9 +2750,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 10, + .iface = 0, +@@ -3633,9 +2768,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3678,14 +2811,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * but not for DVS (Digital Vinyl Systems) like in Mixxx. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0017), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // outputs + .iface = 0, +@@ -3702,9 +2831,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // inputs + .iface = 0, +@@ -3722,9 +2849,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3735,14 +2860,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The feedback for the output is the dummy input. + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -3759,9 +2880,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, +@@ -3779,9 +2898,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3792,14 +2909,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * PCM is 6 channels out & 4 channels in @ 44.1 fixed + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000d), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, //Master, Headphones & Booth + .iface = 0, +@@ -3816,9 +2929,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, //2x RCA inputs (CH1 & CH2) + .iface = 0, +@@ -3836,9 +2947,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3850,14 +2959,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The Feedback for the output is the input + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001e), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 4, + .iface = 0, +@@ -3874,9 +2979,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -3894,9 +2997,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3907,14 +3008,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x000a), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, +@@ -3935,9 +3032,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, +@@ -3959,9 +3054,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -3973,14 +3066,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * The Feedback for the output is the input + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0029), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -3997,9 +3086,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 6, + .iface = 0, +@@ -4017,9 +3104,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4037,20 +3122,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + { + USB_AUDIO_DEVICE(0x534d, 0x0021), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MacroSilicon", + .product_name = "MS210x", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(2) }, + { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 3, +@@ -4065,9 +3143,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4085,20 +3161,13 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + { + USB_AUDIO_DEVICE(0x534d, 0x2109), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "MacroSilicon", + .product_name = "MS2109", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_MIXER(2) }, + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_MIXER, +- }, +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(3) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 3, +@@ -4113,9 +3182,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_max = 48000, + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4125,14 +3192,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 8 channels playback & 8 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x017f), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4151,9 +3214,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4173,9 +3234,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4185,14 +3244,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * 10 channels playback & 12 channels capture @ 48kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x001b), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, +@@ -4211,9 +3266,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, +@@ -4231,9 +3284,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4245,14 +3296,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Capture on EP 0x86 + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4272,9 +3319,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, +@@ -4294,9 +3339,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4307,14 +3350,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * and 8 channels in @ 48 fixed (endpoint 0x82). + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x0013), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // outputs + .iface = 0, +@@ -4331,9 +3370,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + } + }, + { +- .ifnum = 0, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, // inputs + .iface = 0, +@@ -4351,9 +3388,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .rate_table = (unsigned int[]) { 48000 } + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4364,28 +3399,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), + */ + USB_DEVICE(0x1395, 0x0300), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { ++ QUIRK_DRIVER_INFO { ++ QUIRK_DATA_COMPOSITE { + // Communication +- { +- .ifnum = 3, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ { QUIRK_DATA_STANDARD_AUDIO(3) }, + // Recording +- { +- .ifnum = 4, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ { QUIRK_DATA_STANDARD_AUDIO(4) }, + // Main +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, +- { +- .ifnum = -1 +- } ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4394,21 +3416,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.0.0 @ 48 kHz) + */ + USB_DEVICE(0x2b53, 0x0023), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4428,9 +3443,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4449,9 +3462,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4460,21 +3471,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.0.0 @ 96 kHz) + */ + USB_DEVICE(0x2b53, 0x0024), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4494,9 +3498,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4515,9 +3517,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4526,21 +3526,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * Fiero SC-01 (firmware v1.1.0) + */ + USB_DEVICE(0x2b53, 0x0031), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Fiero", + .product_name = "SC-01", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = &(const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE +- }, ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_STANDARD_AUDIO(0) }, + /* Playback */ + { +- .ifnum = 1, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(1) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4561,9 +3554,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + }, + /* Capture */ + { +- .ifnum = 2, +- .type = QUIRK_AUDIO_FIXED_ENDPOINT, +- .data = &(const struct audioformat) { ++ QUIRK_DATA_AUDIOFORMAT(2) { + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .channels = 2, + .fmt_bits = 24, +@@ -4583,9 +3574,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), + .clock = 0x29 + } + }, +- { +- .ifnum = -1 +- } ++ QUIRK_COMPOSITE_END + } + } + }, +@@ -4594,27 +3583,14 @@ YAMAHA_DEVICE(0x7010, "UB99"), + * For the standard mode, Mythware XA001AU has ID ffad:a001 + */ + USB_DEVICE_VENDOR_SPEC(0xffad, 0xa001), +- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { ++ QUIRK_DRIVER_INFO { + .vendor_name = "Mythware", + .product_name = "XA001AU", +- .ifnum = QUIRK_ANY_INTERFACE, +- .type = QUIRK_COMPOSITE, +- .data = (const struct snd_usb_audio_quirk[]) { +- { +- .ifnum = 0, +- .type = QUIRK_IGNORE_INTERFACE, +- }, +- { +- .ifnum = 1, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- .ifnum = 2, +- .type = QUIRK_AUDIO_STANDARD_INTERFACE, +- }, +- { +- .ifnum = -1 +- } ++ QUIRK_DATA_COMPOSITE { ++ { QUIRK_DATA_IGNORE(0) }, ++ { QUIRK_DATA_STANDARD_AUDIO(1) }, ++ { QUIRK_DATA_STANDARD_AUDIO(2) }, ++ QUIRK_COMPOSITE_END + } + } + }, +-- +2.43.0 + diff --git a/queue-6.1/alsa-usb-audio-support-multiple-control-interfaces.patch b/queue-6.1/alsa-usb-audio-support-multiple-control-interfaces.patch new file mode 100644 index 00000000000..cfc5e64ab15 --- /dev/null +++ b/queue-6.1/alsa-usb-audio-support-multiple-control-interfaces.patch @@ -0,0 +1,659 @@ +From 3a84e7746b37d4d8dce8d7d4f9f64542cbf68612 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Aug 2024 17:29:56 -0700 +Subject: ALSA: usb-audio: Support multiple control interfaces + +From: Karol Kosik + +[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ] + +Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'. +The problem stems from the driver not being able to find input/output +terminals required to configure audio streaming. The information about +those terminals is stored in AudioControl Interface. Numark device +contains 2 AudioControl Interfaces and the driver checks only one of them. + +According to the USB standard, a device can have multiple audio functions, +each represented by Audio Interface Collection. Every audio function is +considered to be closed box and will contain unique AudioControl Interface +and zero or more AudioStreaming and MIDIStreaming Interfaces. + +The Numark device adheres to the standard and defines two audio functions: +- MIDIStreaming function +- AudioStreaming function +It starts with MIDI function, followed by the audio function. The driver +saves the first AudioControl Interface in `snd_usb_audio` structure +associated with the entire device. It then attempts to use this interface +to query for terminals and clocks. However, this fails because the correct +information is stored in the second AudioControl Interface, defined in the +second Audio Interface Collection. + +This patch introduces a structure holding association between each +MIDI/Audio Interface and its corresponding AudioControl Interface, +instead of relying on AudioControl Interface defined for the entire +device. This structure is populated during usb probing phase and leveraged +later when querying for terminals and when sending USB requests. + +Alternative solutions considered include: +- defining a quirk for Numark where the order of interface is manually +changed, or terminals are hardcoded in the driver. This solution would +have fixed only this model, though it seems that device is USB compliant, +and it also seems that other devices from this company may be affected. +What's more, it looks like products from other manufacturers have similar +problems, i.e. Rane One DJ console +- keeping a list of all AudioControl Interfaces and querying all of them +to find required information. That would have solved my problem and have +low probability of breaking other devices, as we would always start with +the same logic of querying first AudioControl Interface. This solution +would not have followed the standard though. + +This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds +the first AudioControl Interface, and uses it as a fallback when some +interfaces are not parsed correctly and lack an associated AudioControl +Interface, i.e., when configured via quirks. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865 +Signed-off-by: Karol Kosik +Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/card.c | 2 ++ + sound/usb/clock.c | 62 ++++++++++++++++++++++++-------------- + sound/usb/format.c | 6 ++-- + sound/usb/helper.c | 34 +++++++++++++++++++++ + sound/usb/helper.h | 10 ++++-- + sound/usb/mixer.c | 2 +- + sound/usb/mixer_quirks.c | 17 ++++++----- + sound/usb/mixer_scarlett.c | 4 +-- + sound/usb/power.c | 3 +- + sound/usb/power.h | 1 + + sound/usb/stream.c | 21 ++++++++----- + sound/usb/usbaudio.h | 12 ++++++++ + 12 files changed, 127 insertions(+), 47 deletions(-) + +diff --git a/sound/usb/card.c b/sound/usb/card.c +index 26268ffb82742..811bda4eeb9cf 100644 +--- a/sound/usb/card.c ++++ b/sound/usb/card.c +@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int + return -EINVAL; + } + ++ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif); ++ + if (! snd_usb_parse_audio_interface(chip, interface)) { + usb_set_interface(dev, interface, 0); /* reset the current interface */ + return usb_driver_claim_interface(&usb_audio_driver, iface, +diff --git a/sound/usb/clock.c b/sound/usb/clock.c +index a676ad093d189..6f0693c428b0b 100644 +--- a/sound/usb/clock.c ++++ b/sound/usb/clock.c +@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto) + } + + #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \ +-static obj *name(struct snd_usb_audio *chip, int id, int proto) \ ++static obj *name(struct snd_usb_audio *chip, int id, \ ++ const struct audioformat *fmt) \ + { \ +- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \ +- proto == UAC_VERSION_3 ? (type3) : (type2), \ +- proto); \ ++ struct usb_host_interface *ctrl_intf = \ ++ snd_usb_find_ctrl_interface(chip, fmt->iface); \ ++ return find_uac_clock_desc(ctrl_intf, id, validator, \ ++ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \ ++ fmt->protocol); \ + } + + DEFINE_FIND_HELPER(snd_usb_find_clock_source, +@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, + union uac23_clock_multiplier_desc, validate_clock_multiplier, + UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER); + +-static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) ++static int uac_clock_selector_get_val(struct snd_usb_audio *chip, ++ int selector_id, int iface_no) + { ++ struct usb_host_interface *ctrl_intf; + unsigned char buf; + int ret; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + UAC2_CX_CLOCK_SELECTOR << 8, +- snd_usb_ctrl_intf(chip) | (selector_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8), + &buf, sizeof(buf)); + + if (ret < 0) +@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i + return buf; + } + +-static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id, +- unsigned char pin) ++static int uac_clock_selector_set_val(struct snd_usb_audio *chip, ++ int selector_id, unsigned char pin, int iface_no) + { ++ struct usb_host_interface *ctrl_intf; + int ret; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + UAC2_CX_CLOCK_SELECTOR << 8, +- snd_usb_ctrl_intf(chip) | (selector_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8), + &pin, sizeof(pin)); + if (ret < 0) + return ret; +@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i + return -EINVAL; + } + +- ret = uac_clock_selector_get_val(chip, selector_id); ++ ret = uac_clock_selector_get_val(chip, selector_id, iface_no); + if (ret < 0) + return ret; + +@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, + unsigned char data; + struct usb_device *dev = chip->dev; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt); + if (!cs_desc) + return false; + +@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, +- snd_usb_ctrl_intf(chip) | (source_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8), + &data, sizeof(data)); + if (err < 0) { + dev_warn(&dev->dev, +@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, + struct usb_device *dev = chip->dev; + u32 bmControls; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt); + if (!cs_desc) + return false; + +@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_CLOCK_VALID << 8, +- snd_usb_ctrl_intf(chip) | (source_id << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8), + &data, sizeof(data)); + + if (err < 0) { +@@ -272,7 +284,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + } + + /* first, see if the ID we're looking at is a clock source already */ +- source = snd_usb_find_clock_source(chip, entity_id, proto); ++ source = snd_usb_find_clock_source(chip, entity_id, fmt); + if (source) { + entity_id = GET_VAL(source, proto, bClockID); + if (validate && !uac_clock_source_is_valid(chip, fmt, +@@ -285,7 +297,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + return entity_id; + } + +- selector = snd_usb_find_clock_selector(chip, entity_id, proto); ++ selector = snd_usb_find_clock_selector(chip, entity_id, fmt); + if (selector) { + pins = GET_VAL(selector, proto, bNrInPins); + clock_id = GET_VAL(selector, proto, bClockID); +@@ -299,7 +311,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + + /* the entity ID we are looking at is a selector. + * find out what it currently selects */ +- ret = uac_clock_selector_get_val(chip, clock_id); ++ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface); + if (ret < 0) { + if (!chip->autoclock) + return ret; +@@ -327,7 +339,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + /* Skip setting clock selector again for some devices */ + if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR) + return ret; +- err = uac_clock_selector_set_val(chip, entity_id, cur); ++ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface); + if (err < 0) { + if (pins == 1) { + usb_audio_dbg(chip, +@@ -355,7 +367,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + if (ret < 0) + continue; + +- err = uac_clock_selector_set_val(chip, entity_id, i); ++ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface); + if (err < 0) + continue; + +@@ -369,7 +381,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, + } + + /* FIXME: multipliers only act as pass-thru element for now */ +- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto); ++ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt); + if (multiplier) + return __uac_clock_find_source(chip, fmt, + GET_VAL(multiplier, proto, bCSourceID), +@@ -469,11 +481,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, + struct usb_device *dev = chip->dev; + __le32 data; + int err; ++ struct usb_host_interface *ctrl_intf; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface); + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + &data, sizeof(data)); + if (err < 0) { + dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", +@@ -502,8 +516,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + __le32 data; + int err; + union uac23_clock_source_desc *cs_desc; ++ struct usb_host_interface *ctrl_intf; + +- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol); ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface); ++ cs_desc = snd_usb_find_clock_source(chip, clock, fmt); + + if (!cs_desc) + return 0; +@@ -522,7 +538,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + &data, sizeof(data)); + if (err < 0) + return err; +diff --git a/sound/usb/format.c b/sound/usb/format.c +index 3b45d0ee76938..61c4aca8be09e 100644 +--- a/sound/usb/format.c ++++ b/sound/usb/format.c +@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + unsigned char tmp[2], *data; + int nr_triplets, data_size, ret = 0, ret_l6; + int clock = snd_usb_clock_find_source(chip, fp, false); ++ struct usb_host_interface *ctrl_intf; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface); + if (clock < 0) { + dev_err(&dev->dev, + "%s(): unable to find clock source (clock %d)\n", +@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + tmp, sizeof(tmp)); + + if (ret < 0) { +@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, + ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + UAC2_CS_CONTROL_SAM_FREQ << 8, +- snd_usb_ctrl_intf(chip) | (clock << 8), ++ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8), + data, data_size); + + if (ret < 0) { +diff --git a/sound/usb/helper.c b/sound/usb/helper.c +index a4410267bf701..f582a2ced3fd1 100644 +--- a/sound/usb/helper.c ++++ b/sound/usb/helper.c +@@ -131,3 +131,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting + return NULL; + return usb_altnum_to_altsetting(iface, altsetting); + } ++ ++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum, ++ int ctrlif) ++{ ++ struct usb_device *dev = chip->dev; ++ struct usb_host_interface *host_iface; ++ ++ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) { ++ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n"); ++ return -EINVAL; ++ } ++ ++ /* find audiocontrol interface */ ++ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; ++ ++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum; ++ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface; ++ chip->num_intf_to_ctrl++; ++ ++ return 0; ++} ++ ++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip, ++ int ifnum) ++{ ++ int i; ++ ++ for (i = 0; i < chip->num_intf_to_ctrl; ++i) ++ if (chip->intf_to_ctrl[i].interface == ifnum) ++ return chip->intf_to_ctrl[i].ctrl_intf; ++ ++ /* Fallback to first audiocontrol interface */ ++ return chip->ctrl_intf; ++} +diff --git a/sound/usb/helper.h b/sound/usb/helper.h +index e2b51ec96ec62..0372e050b3dc4 100644 +--- a/sound/usb/helper.h ++++ b/sound/usb/helper.h +@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, + struct usb_host_interface * + snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting); + ++int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum, ++ int ctrlif); ++ ++struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip, ++ int ifnum); ++ + /* + * retrieve usb_interface descriptor from the host interface + * (conditional for compatibility with the older API) +@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting + + #define snd_usb_get_speed(dev) ((dev)->speed) + +-static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) ++static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf) + { +- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; ++ return get_iface_desc(ctrl_intf)->bInterfaceNumber; + } + + /* in validate.c */ +diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c +index 49facdf35b159..7bda8e9a93deb 100644 +--- a/sound/usb/mixer.c ++++ b/sound/usb/mixer.c +@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(state->chip), ++ snd_usb_ctrl_intf(state->mixer->hostif), + &c_header, sizeof(c_header)); + if (err < 0) + goto error; +diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c +index c8d48566e1759..2323504339328 100644 +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + pval & 0xff00, +- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), ++ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8), + value, 2); + if (err < 0) + return err; +@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, +- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), ++ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8), + value, 2); + snd_usb_unlock_shutdown(chip); + return err; +@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer) + return 0; + } + +-static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) ++static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id) + { ++ struct snd_usb_audio *chip = mixer->chip; + u16 buf = 0; + + snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + (UAC_FU_VOLUME << 8) | ch, +- snd_usb_ctrl_intf(chip) | (id << 8), ++ snd_usb_ctrl_intf(mixer->hostif) | (id << 8), + &buf, 2); + } + + static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) + { + /* fix to 0dB playback volumes */ +- dell_dock_init_vol(mixer->chip, 1, 16); +- dell_dock_init_vol(mixer->chip, 2, 16); +- dell_dock_init_vol(mixer->chip, 1, 19); +- dell_dock_init_vol(mixer->chip, 2, 19); ++ dell_dock_init_vol(mixer, 1, 16); ++ dell_dock_init_vol(mixer, 2, 16); ++ dell_dock_init_vol(mixer, 1, 19); ++ dell_dock_init_vol(mixer, 2, 19); + return 0; + } + +diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c +index 0d6e4f15bf77c..ff548041679bb 100644 +--- a/sound/usb/mixer_scarlett.c ++++ b/sound/usb/mixer_scarlett.c +@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, + struct snd_usb_audio *chip = elem->head.mixer->chip; + unsigned char buf[2 * MAX_CHANNELS] = {0, }; + int wValue = (elem->control << 8) | elem->idx_off; +- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); ++ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8); + int err; + + err = snd_usb_ctl_msg(chip->dev, +@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | +- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) | ++ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) | + (0x29 << 8), sample_rate_buffer, 4); + if (err < 0) + return err; +diff --git a/sound/usb/power.c b/sound/usb/power.c +index 606a2cb23eab6..66bd4daa68fd5 100644 +--- a/sound/usb/power.c ++++ b/sound/usb/power.c +@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, + le16_to_cpu(pd_desc->waRecoveryTime1); + pd->pd_d2d0_rec = + le16_to_cpu(pd_desc->waRecoveryTime2); ++ pd->ctrl_iface = ctrl_iface; + return pd; + } + } +@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip, + unsigned char current_state; + int err, idx; + +- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8); ++ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8); + + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_CUR, +diff --git a/sound/usb/power.h b/sound/usb/power.h +index 396e3e51440a7..1fa92ad0ca925 100644 +--- a/sound/usb/power.h ++++ b/sound/usb/power.h +@@ -6,6 +6,7 @@ struct snd_usb_power_domain { + int pd_id; /* UAC3 Power Domain ID */ + int pd_d1d0_rec; /* D1 to D0 recovery time */ + int pd_d2d0_rec; /* D2 to D0 recovery time */ ++ struct usb_host_interface *ctrl_iface; /* Control interface */ + }; + + enum { +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index e14c725acebf2..d70c140813d68 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + struct usb_device *dev = chip->dev; + struct uac_format_type_i_continuous_descriptor *fmt; + unsigned int num_channels = 0, chconfig = 0; ++ struct usb_host_interface *ctrl_intf; + struct audioformat *fp; + int clock = 0; + u64 format; + ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); ++ + /* get audio formats */ + if (protocol == UAC_VERSION_1) { + struct uac1_as_header_descriptor *as = +@@ -740,7 +743,7 @@ 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, ++ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (iterm) { +@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + * lookup the terminal associated to this interface + * to extract the clock + */ +- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, ++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (input_term) { +@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + goto found_clock; + } + +- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, ++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + protocol); + if (output_term) { +@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + struct uac3_cluster_header_descriptor *cluster; + struct uac3_as_header_descriptor *as = NULL; + struct uac3_hc_descriptor_header hc_header; ++ struct usb_host_interface *ctrl_intf; + struct snd_pcm_chmap_elem *chmap; + struct snd_usb_power_domain *pd; + unsigned char badd_profile; +@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + int err; + + badd_profile = chip->badd_profile; ++ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no); + + if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { + unsigned int maxpacksize = +@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(chip), ++ snd_usb_ctrl_intf(ctrl_intf), + &hc_header, sizeof(hc_header)); + if (err < 0) + return ERR_PTR(err); +@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, +- snd_usb_ctrl_intf(chip), ++ snd_usb_ctrl_intf(ctrl_intf), + cluster, wLength); + if (err < 0) { + kfree(cluster); +@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + * lookup the terminal associated to this interface + * to extract the clock + */ +- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, ++ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + UAC_VERSION_3); + if (input_term) { +@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + goto found_clock; + } + +- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, ++ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf, + as->bTerminalLink, + UAC_VERSION_3); + if (output_term) { +@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + UAC_VERSION_3, + iface_no); + +- pd = snd_usb_find_power_domain(chip->ctrl_intf, ++ pd = snd_usb_find_power_domain(ctrl_intf, + as->bTerminalLink); + + /* ok, let's parse further... */ +diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h +index f5a8dca66457f..1f56a07827aa7 100644 +--- a/sound/usb/usbaudio.h ++++ b/sound/usb/usbaudio.h +@@ -21,6 +21,15 @@ struct media_intf_devnode; + + #define MAX_CARD_INTERFACES 16 + ++/* ++ * Structure holding assosiation between Audio Control Interface ++ * and given Streaming or Midi Interface. ++ */ ++struct snd_intf_to_ctrl { ++ u8 interface; ++ struct usb_host_interface *ctrl_intf; ++}; ++ + struct snd_usb_audio { + int index; + struct usb_device *dev; +@@ -61,6 +70,9 @@ struct snd_usb_audio { + struct usb_host_interface *ctrl_intf; /* the audio control interface */ + struct media_device *media_dev; + struct media_intf_devnode *ctl_intf_media_devnode; ++ ++ unsigned int num_intf_to_ctrl; ++ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES]; + }; + + #define USB_AUDIO_IFACE_UNUSED ((void *)-1L) +-- +2.43.0 + diff --git a/queue-6.1/asoc-codecs-wsa883x-handle-reading-version-failure.patch b/queue-6.1/asoc-codecs-wsa883x-handle-reading-version-failure.patch new file mode 100644 index 00000000000..2d7a49d4d67 --- /dev/null +++ b/queue-6.1/asoc-codecs-wsa883x-handle-reading-version-failure.patch @@ -0,0 +1,72 @@ +From fa997f16c7c2881236fac94dc23f583e2434a577 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jul 2024 15:52:31 +0200 +Subject: ASoC: codecs: wsa883x: Handle reading version failure + +From: Krzysztof Kozlowski + +[ Upstream commit 2fbf16992e5aa14acf0441320033a01a32309ded ] + +If reading version and variant from registers fails (which is unlikely +but possible, because it is a read over bus), the driver will proceed +and perform device configuration based on uninitialized stack variables. +Handle it a bit better - bail out without doing any init and failing the +update status Soundwire callback. + +Signed-off-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20240710-asoc-wsa88xx-version-v1-2-f1c54966ccde@linaro.org +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/wsa883x.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c +index f4b81ebab3537..639fb77170ac8 100644 +--- a/sound/soc/codecs/wsa883x.c ++++ b/sound/soc/codecs/wsa883x.c +@@ -1002,15 +1002,19 @@ static const struct reg_sequence reg_init[] = { + {WSA883X_GMAMP_SUP1, 0xE2}, + }; + +-static void wsa883x_init(struct wsa883x_priv *wsa883x) ++static int wsa883x_init(struct wsa883x_priv *wsa883x) + { + struct regmap *regmap = wsa883x->regmap; +- int variant, version; ++ int variant, version, ret; + +- regmap_read(regmap, WSA883X_OTP_REG_0, &variant); ++ ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); ++ if (ret) ++ return ret; + wsa883x->variant = variant & WSA883X_ID_MASK; + +- regmap_read(regmap, WSA883X_CHIP_ID0, &version); ++ ret = regmap_read(regmap, WSA883X_CHIP_ID0, &version); ++ if (ret) ++ return ret; + wsa883x->version = version; + + switch (wsa883x->variant) { +@@ -1045,6 +1049,8 @@ static void wsa883x_init(struct wsa883x_priv *wsa883x) + WSA883X_DRE_OFFSET_MASK, + wsa883x->comp_offset); + } ++ ++ return 0; + } + + static int wsa883x_update_status(struct sdw_slave *slave, +@@ -1053,7 +1059,7 @@ static int wsa883x_update_status(struct sdw_slave *slave, + struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) +- wsa883x_init(wsa883x); ++ return wsa883x_init(wsa883x); + + return 0; + } +-- +2.43.0 + diff --git a/queue-6.1/ata-pata_serverworks-do-not-use-the-term-blacklist.patch b/queue-6.1/ata-pata_serverworks-do-not-use-the-term-blacklist.patch new file mode 100644 index 00000000000..59ae1db323e --- /dev/null +++ b/queue-6.1/ata-pata_serverworks-do-not-use-the-term-blacklist.patch @@ -0,0 +1,65 @@ +From 6743c54e28297f4be38d8619a63b80e7c3c198bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 10:58:36 +0900 +Subject: ata: pata_serverworks: Do not use the term blacklist + +From: Damien Le Moal + +[ Upstream commit 858048568c9e3887d8b19e101ee72f129d65cb15 ] + +Let's not use the term blacklist in the function +serverworks_osb4_filter() documentation comment and rather simply refer +to what that function looks at: the list of devices with groken UDMA5. + +While at it, also constify the values of the csb_bad_ata100 array. + +Of note is that all of this should probably be handled using libata +quirk mechanism but it is unclear if these UDMA5 quirks are specific +to this controller only. + +Signed-off-by: Damien Le Moal +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + drivers/ata/pata_serverworks.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c +index c0bc4af0d1960..804c74ce3c1df 100644 +--- a/drivers/ata/pata_serverworks.c ++++ b/drivers/ata/pata_serverworks.c +@@ -46,10 +46,11 @@ + #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ + #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ + +-/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 +- * can overrun their FIFOs when used with the CSB5 */ +- +-static const char *csb_bad_ata100[] = { ++/* ++ * Seagate Barracuda ATA IV Family drives in UDMA mode 5 ++ * can overrun their FIFOs when used with the CSB5. ++ */ ++static const char * const csb_bad_ata100[] = { + "ST320011A", + "ST340016A", + "ST360021A", +@@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in + * @adev: ATA device + * @mask: Mask of proposed modes + * +- * Check the blacklist and disable UDMA5 if matched ++ * Check the list of devices with broken UDMA5 and ++ * disable UDMA5 if matched. + */ +- +-static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask) ++static unsigned int serverworks_csb_filter(struct ata_device *adev, ++ unsigned int mask) + { + const char *p; + char model_num[ATA_ID_PROD_LEN + 1]; +-- +2.43.0 + diff --git a/queue-6.1/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch b/queue-6.1/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch new file mode 100644 index 00000000000..cc1e79fa097 --- /dev/null +++ b/queue-6.1/ata-sata_sil-rename-sil_blacklist-to-sil_quirks.patch @@ -0,0 +1,61 @@ +From a960ca098c5dedc69f9bb875abd18fe04e750c47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 11:14:11 +0900 +Subject: ata: sata_sil: Rename sil_blacklist to sil_quirks + +From: Damien Le Moal + +[ Upstream commit 93b0f9e11ce511353c65b7f924cf5f95bd9c3aba ] + +Rename the array sil_blacklist to sil_quirks as this name is more +neutral and is also consistent with how this driver define quirks with +the SIL_QUIRK_XXX flags. + +Signed-off-by: Damien Le Moal +Reviewed-by: Niklas Cassel +Reviewed-by: Igor Pylypiv +Signed-off-by: Sasha Levin +--- + drivers/ata/sata_sil.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c +index 3b989a52879d9..f412b8d71252f 100644 +--- a/drivers/ata/sata_sil.c ++++ b/drivers/ata/sata_sil.c +@@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = { + static const struct sil_drivelist { + const char *product; + unsigned int quirk; +-} sil_blacklist [] = { ++} sil_quirks[] = { + { "ST320012AS", SIL_QUIRK_MOD15WRITE }, + { "ST330013AS", SIL_QUIRK_MOD15WRITE }, + { "ST340017AS", SIL_QUIRK_MOD15WRITE }, +@@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap) + * list, and apply the fixups to only the specific + * devices/hosts/firmwares that need it. + * +- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted +- * The Maxtor quirk is in the blacklist, but I'm keeping the original ++ * 20040111 - Seagate drives affected by the Mod15Write bug are quirked ++ * The Maxtor quirk is in sil_quirks, but I'm keeping the original + * pessimistic fix for the following reasons... + * - There seems to be less info on it, only one device gleaned off the + * Windows driver, maybe only one is affected. More info would be greatly +@@ -620,9 +620,9 @@ static void sil_dev_config(struct ata_device *dev) + + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + +- for (n = 0; sil_blacklist[n].product; n++) +- if (!strcmp(sil_blacklist[n].product, model_num)) { +- quirks = sil_blacklist[n].quirk; ++ for (n = 0; sil_quirks[n].product; n++) ++ if (!strcmp(sil_quirks[n].product, model_num)) { ++ quirks = sil_quirks[n].quirk; + break; + } + +-- +2.43.0 + diff --git a/queue-6.1/blk_iocost-fix-more-out-of-bound-shifts.patch b/queue-6.1/blk_iocost-fix-more-out-of-bound-shifts.patch new file mode 100644 index 00000000000..3cb8852f590 --- /dev/null +++ b/queue-6.1/blk_iocost-fix-more-out-of-bound-shifts.patch @@ -0,0 +1,80 @@ +From 09cc051670489e1f56fd013b01f5deefe067f439 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Aug 2024 08:41:36 -0700 +Subject: blk_iocost: fix more out of bound shifts + +From: Konstantin Ovsepian + +[ Upstream commit 9bce8005ec0dcb23a58300e8522fe4a31da606fa ] + +Recently running UBSAN caught few out of bound shifts in the +ioc_forgive_debts() function: + +UBSAN: shift-out-of-bounds in block/blk-iocost.c:2142:38 +shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long +long') +... +UBSAN: shift-out-of-bounds in block/blk-iocost.c:2144:30 +shift exponent 80 is too large for 64-bit type 'u64' (aka 'unsigned long +long') +... +Call Trace: + +dump_stack_lvl+0xca/0x130 +__ubsan_handle_shift_out_of_bounds+0x22c/0x280 +? __lock_acquire+0x6441/0x7c10 +ioc_timer_fn+0x6cec/0x7750 +? blk_iocost_init+0x720/0x720 +? call_timer_fn+0x5d/0x470 +call_timer_fn+0xfa/0x470 +? blk_iocost_init+0x720/0x720 +__run_timer_base+0x519/0x700 +... + +Actual impact of this issue was not identified but I propose to fix the +undefined behaviour. +The proposed fix to prevent those out of bound shifts consist of +precalculating exponent before using it the shift operations by taking +min value from the actual exponent and maximum possible number of bits. + +Reported-by: Breno Leitao +Signed-off-by: Konstantin Ovsepian +Acked-by: Tejun Heo +Link: https://lore.kernel.org/r/20240822154137.2627818-1-ovs@ovs.to +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-iocost.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/block/blk-iocost.c b/block/blk-iocost.c +index 64b594d660b79..772e909e9fbfd 100644 +--- a/block/blk-iocost.c ++++ b/block/blk-iocost.c +@@ -2057,7 +2057,7 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + struct ioc_now *now) + { + struct ioc_gq *iocg; +- u64 dur, usage_pct, nr_cycles; ++ u64 dur, usage_pct, nr_cycles, nr_cycles_shift; + + /* if no debtor, reset the cycle */ + if (!nr_debtors) { +@@ -2119,10 +2119,12 @@ static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors, + old_debt = iocg->abs_vdebt; + old_delay = iocg->delay; + ++ nr_cycles_shift = min_t(u64, nr_cycles, BITS_PER_LONG - 1); + if (iocg->abs_vdebt) +- iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles ?: 1; ++ iocg->abs_vdebt = iocg->abs_vdebt >> nr_cycles_shift ?: 1; ++ + if (iocg->delay) +- iocg->delay = iocg->delay >> nr_cycles ?: 1; ++ iocg->delay = iocg->delay >> nr_cycles_shift ?: 1; + + iocg_kick_waitq(iocg, true, now); + +-- +2.43.0 + diff --git a/queue-6.1/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch b/queue-6.1/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch new file mode 100644 index 00000000000..688aa1c8ab0 --- /dev/null +++ b/queue-6.1/bluetooth-btusb-add-realtek-rtl8852c-support-id-0x04.patch @@ -0,0 +1,67 @@ +From 71f883af4bbf8e467072044048e0c5adb8401f2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Aug 2024 16:58:22 +0800 +Subject: Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122 + +From: Hilda Wu + +[ Upstream commit bdf9557f70e7512bb2f754abf90d9e9958745316 ] + +Add the support ID (0x0489, 0xe122) to usb_device_id table for +Realtek RTL8852C. + +The device info from /sys/kernel/debug/usb/devices as below. + +T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 +D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e122 Rev= 0.00 +S: Manufacturer=Realtek +S: Product=Bluetooth Radio +S: SerialNumber=00e04c000001 +C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms +E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms + +Signed-off-by: Hilda Wu +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btusb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index dc5150f677236..ca5828a274cdd 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -531,6 +531,8 @@ static const struct usb_device_id blacklist_table[] = { + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, ++ { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK | ++ BTUSB_WIDEBAND_SPEECH }, + + /* Realtek 8852BE Bluetooth devices */ + { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK | +-- +2.43.0 + diff --git a/queue-6.1/bnxt_en-extend-maximum-length-of-version-string-by-1.patch b/queue-6.1/bnxt_en-extend-maximum-length-of-version-string-by-1.patch new file mode 100644 index 00000000000..27fca2eadd1 --- /dev/null +++ b/queue-6.1/bnxt_en-extend-maximum-length-of-version-string-by-1.patch @@ -0,0 +1,42 @@ +From 794a42287d9d438ec9e66708562735b825a0ef5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Aug 2024 15:32:55 +0100 +Subject: bnxt_en: Extend maximum length of version string by 1 byte + +From: Simon Horman + +[ Upstream commit ffff7ee843c351ce71d6e0d52f0f20bea35e18c9 ] + +This corrects an out-by-one error in the maximum length of the package +version string. The size argument of snprintf includes space for the +trailing '\0' byte, so there is no need to allow extra space for it by +reducing the value of the size argument by 1. + +Found by inspection. +Compile tested only. + +Signed-off-by: Simon Horman +Reviewed-by: Michael Chan +Link: https://patch.msgid.link/20240813-bnxt-str-v2-1-872050a157e7@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +index 7260b4671ecca..799adba0034a4 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +@@ -2980,7 +2980,7 @@ static void bnxt_get_pkgver(struct net_device *dev) + + if (!bnxt_get_pkginfo(dev, buf, sizeof(buf))) { + len = strlen(bp->fw_ver_str); +- snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len - 1, ++ snprintf(bp->fw_ver_str + len, FW_VER_STR_LEN - len, + "/pkg %s", buf); + } + } +-- +2.43.0 + diff --git a/queue-6.1/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch b/queue-6.1/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch new file mode 100644 index 00000000000..67bd2c4c650 --- /dev/null +++ b/queue-6.1/cgroup-disallow-mounting-v1-hierarchies-without-cont.patch @@ -0,0 +1,71 @@ +From a235525004b0e70293fb65cbc467b063029d4ebe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Sep 2024 18:32:22 +0200 +Subject: cgroup: Disallow mounting v1 hierarchies without controller + implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Koutný + +[ Upstream commit 3c41382e920f1dd5c9f432948fe799c07af1cced ] + +The configs that disable some v1 controllers would still allow mounting +them but with no controller-specific files. (Making such hierarchies +equivalent to named v1 hierarchies.) To achieve behavior consistent with +actual out-compilation of a whole controller, the mounts should treat +respective controllers as non-existent. + +Wrap implementation into a helper function, leverage legacy_files to +detect compiled out controllers. The effect is that mounts on v1 would +fail and produce a message like: + [ 1543.999081] cgroup: Unknown subsys name 'memory' + +Signed-off-by: Michal Koutný +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/cgroup-v1.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c +index c2d28ffee3b7b..6ce0674cff282 100644 +--- a/kernel/cgroup/cgroup-v1.c ++++ b/kernel/cgroup/cgroup-v1.c +@@ -46,6 +46,12 @@ bool cgroup1_ssid_disabled(int ssid) + return cgroup_no_v1_mask & (1 << ssid); + } + ++static bool cgroup1_subsys_absent(struct cgroup_subsys *ss) ++{ ++ /* Check also dfl_cftypes for file-less controllers, i.e. perf_event */ ++ return ss->legacy_cftypes == NULL && ss->dfl_cftypes; ++} ++ + /** + * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from' + * @from: attach to all cgroups of a given task +@@ -932,7 +938,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param) + if (ret != -ENOPARAM) + return ret; + for_each_subsys(ss, i) { +- if (strcmp(param->key, ss->legacy_name)) ++ if (strcmp(param->key, ss->legacy_name) || ++ cgroup1_subsys_absent(ss)) + continue; + if (!cgroup_ssid_enabled(i) || cgroup1_ssid_disabled(i)) + return invalfc(fc, "Disabled controller '%s'", +@@ -1024,7 +1031,8 @@ static int check_cgroupfs_options(struct fs_context *fc) + mask = ~((u16)1 << cpuset_cgrp_id); + #endif + for_each_subsys(ss, i) +- if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i)) ++ if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i) && ++ !cgroup1_subsys_absent(ss)) + enabled |= 1 << i; + + ctx->subsys_mask &= enabled; +-- +2.43.0 + diff --git a/queue-6.1/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch b/queue-6.1/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch new file mode 100644 index 00000000000..b8fc47d3a6f --- /dev/null +++ b/queue-6.1/crypto-simd-do-not-call-crypto_alloc_tfm-during-regi.patch @@ -0,0 +1,249 @@ +From f991f533a14c5502dd29455545f003c51adf8434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 17 Aug 2024 14:58:35 +0800 +Subject: crypto: simd - Do not call crypto_alloc_tfm during registration + +From: Herbert Xu + +[ Upstream commit 3c44d31cb34ce4eb8311a2e73634d57702948230 ] + +Algorithm registration is usually carried out during module init, +where as little work as possible should be carried out. The SIMD +code violated this rule by allocating a tfm, this then triggers a +full test of the algorithm which may dead-lock in certain cases. + +SIMD is only allocating the tfm to get at the alg object, which is +in fact already available as it is what we are registering. Use +that directly and remove the crypto_alloc_tfm call. + +Also remove some obsolete and unused SIMD API. + +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + arch/arm/crypto/aes-ce-glue.c | 2 +- + arch/arm/crypto/aes-neonbs-glue.c | 2 +- + crypto/simd.c | 76 ++++++------------------------- + include/crypto/internal/simd.h | 12 +---- + 4 files changed, 19 insertions(+), 73 deletions(-) + +diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c +index b668c97663ec0..f5b66f4cf45d9 100644 +--- a/arch/arm/crypto/aes-ce-glue.c ++++ b/arch/arm/crypto/aes-ce-glue.c +@@ -711,7 +711,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/arch/arm/crypto/aes-neonbs-glue.c b/arch/arm/crypto/aes-neonbs-glue.c +index f00f042ef3570..0ca94b90bc4ec 100644 +--- a/arch/arm/crypto/aes-neonbs-glue.c ++++ b/arch/arm/crypto/aes-neonbs-glue.c +@@ -539,7 +539,7 @@ static int __init aes_init(void) + algname = aes_algs[i].base.cra_name + 2; + drvname = aes_algs[i].base.cra_driver_name + 2; + basename = aes_algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(aes_algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto unregister_simds; +diff --git a/crypto/simd.c b/crypto/simd.c +index edaa479a1ec5e..d109866641a26 100644 +--- a/crypto/simd.c ++++ b/crypto/simd.c +@@ -136,27 +136,19 @@ static int simd_skcipher_init(struct crypto_skcipher *tfm) + return 0; + } + +-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, ++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg, ++ const char *algname, + const char *drvname, + const char *basename) + { + struct simd_skcipher_alg *salg; +- struct crypto_skcipher *tfm; +- struct skcipher_alg *ialg; + struct skcipher_alg *alg; + int err; + +- tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_skcipher_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -195,30 +187,16 @@ struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_skcipher(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; ++ goto out; + } + EXPORT_SYMBOL_GPL(simd_skcipher_create_compat); + +-struct simd_skcipher_alg *simd_skcipher_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_skcipher_create_compat(algname, drvname, basename); +-} +-EXPORT_SYMBOL_GPL(simd_skcipher_create); +- + void simd_skcipher_free(struct simd_skcipher_alg *salg) + { + crypto_unregister_skcipher(&salg->alg); +@@ -246,7 +224,7 @@ int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_skcipher_create_compat(algname, drvname, basename); ++ simd = simd_skcipher_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +@@ -383,27 +361,19 @@ static int simd_aead_init(struct crypto_aead *tfm) + return 0; + } + +-struct simd_aead_alg *simd_aead_create_compat(const char *algname, +- const char *drvname, +- const char *basename) ++static struct simd_aead_alg *simd_aead_create_compat(struct aead_alg *ialg, ++ const char *algname, ++ const char *drvname, ++ const char *basename) + { + struct simd_aead_alg *salg; +- struct crypto_aead *tfm; +- struct aead_alg *ialg; + struct aead_alg *alg; + int err; + +- tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL, +- CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return ERR_CAST(tfm); +- +- ialg = crypto_aead_alg(tfm); +- + salg = kzalloc(sizeof(*salg), GFP_KERNEL); + if (!salg) { + salg = ERR_PTR(-ENOMEM); +- goto out_put_tfm; ++ goto out; + } + + salg->ialg_name = basename; +@@ -442,36 +412,20 @@ struct simd_aead_alg *simd_aead_create_compat(const char *algname, + if (err) + goto out_free_salg; + +-out_put_tfm: +- crypto_free_aead(tfm); ++out: + return salg; + + out_free_salg: + kfree(salg); + salg = ERR_PTR(err); +- goto out_put_tfm; +-} +-EXPORT_SYMBOL_GPL(simd_aead_create_compat); +- +-struct simd_aead_alg *simd_aead_create(const char *algname, +- const char *basename) +-{ +- char drvname[CRYPTO_MAX_ALG_NAME]; +- +- if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= +- CRYPTO_MAX_ALG_NAME) +- return ERR_PTR(-ENAMETOOLONG); +- +- return simd_aead_create_compat(algname, drvname, basename); ++ goto out; + } +-EXPORT_SYMBOL_GPL(simd_aead_create); + +-void simd_aead_free(struct simd_aead_alg *salg) ++static void simd_aead_free(struct simd_aead_alg *salg) + { + crypto_unregister_aead(&salg->alg); + kfree(salg); + } +-EXPORT_SYMBOL_GPL(simd_aead_free); + + int simd_register_aeads_compat(struct aead_alg *algs, int count, + struct simd_aead_alg **simd_algs) +@@ -493,7 +447,7 @@ int simd_register_aeads_compat(struct aead_alg *algs, int count, + algname = algs[i].base.cra_name + 2; + drvname = algs[i].base.cra_driver_name + 2; + basename = algs[i].base.cra_driver_name; +- simd = simd_aead_create_compat(algname, drvname, basename); ++ simd = simd_aead_create_compat(algs + i, algname, drvname, basename); + err = PTR_ERR(simd); + if (IS_ERR(simd)) + goto err_unregister; +diff --git a/include/crypto/internal/simd.h b/include/crypto/internal/simd.h +index d2316242a9884..be97b97a75dd2 100644 +--- a/include/crypto/internal/simd.h ++++ b/include/crypto/internal/simd.h +@@ -14,11 +14,10 @@ + struct simd_skcipher_alg; + struct skcipher_alg; + +-struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, ++struct simd_skcipher_alg *simd_skcipher_create_compat(struct skcipher_alg *ialg, ++ const char *algname, + const char *drvname, + const char *basename); +-struct simd_skcipher_alg *simd_skcipher_create(const char *algname, +- const char *basename); + void simd_skcipher_free(struct simd_skcipher_alg *alg); + + int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, +@@ -32,13 +31,6 @@ void simd_unregister_skciphers(struct skcipher_alg *algs, int count, + struct simd_aead_alg; + struct aead_alg; + +-struct simd_aead_alg *simd_aead_create_compat(const char *algname, +- const char *drvname, +- const char *basename); +-struct simd_aead_alg *simd_aead_create(const char *algname, +- const char *basename); +-void simd_aead_free(struct simd_aead_alg *alg); +- + int simd_register_aeads_compat(struct aead_alg *algs, int count, + struct simd_aead_alg **simd_algs); + +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch b/queue-6.1/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch new file mode 100644 index 00000000000..89b993657ee --- /dev/null +++ b/queue-6.1/drm-amd-display-add-null-check-for-afb-in-amdgpu_dm_.patch @@ -0,0 +1,54 @@ +From ca6a321970520784e44de8e91b3972e318e27936 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Aug 2024 12:35:13 +0530 +Subject: drm/amd/display: Add null check for 'afb' in + amdgpu_dm_plane_handle_cursor_update (v2) + +From: Srinivasan Shanmugam + +[ Upstream commit cd9e9e0852d501f169aa3bb34e4b413d2eb48c37 ] + +This commit adds a null check for the 'afb' variable in the +amdgpu_dm_plane_handle_cursor_update function. Previously, 'afb' was +assumed to be null, but was used later in the code without a null check. +This could potentially lead to a null pointer dereference. + +Changes since v1: +- Moved the null check for 'afb' to the line where 'afb' is used. (Alex) + +Fixes the below: +drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_plane.c:1298 amdgpu_dm_plane_handle_cursor_update() error: we previously assumed 'afb' could be null (see line 1252) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Co-developed-by: Alex Hung +Signed-off-by: Alex Hung +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +index 08b10df93c317..df4cbf81c6b50 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +@@ -1281,7 +1281,8 @@ void handle_cursor_update(struct drm_plane *plane, + adev->dm.dc->caps.color.dpp.gamma_corr) + attributes.attribute_flags.bits.ENABLE_CURSOR_DEGAMMA = 1; + +- attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; ++ if (afb) ++ attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0]; + + if (crtc_state->stream) { + mutex_lock(&adev->dm.dc_lock); +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch b/queue-6.1/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch new file mode 100644 index 00000000000..0d9e970df7a --- /dev/null +++ b/queue-6.1/drm-amd-display-add-null-check-for-top_pipe_to_progr.patch @@ -0,0 +1,52 @@ +From 60aaaf630b083a3b9585965e92ba4393ead1ae0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Jul 2024 07:23:48 +0530 +Subject: drm/amd/display: Add null check for top_pipe_to_program in + commit_planes_for_stream + +From: Srinivasan Shanmugam + +[ Upstream commit 66d71a72539e173a9b00ca0b1852cbaa5f5bf1ad ] + +This commit addresses a null pointer dereference issue in the +`commit_planes_for_stream` function at line 4140. The issue could occur +when `top_pipe_to_program` is null. + +The fix adds a check to ensure `top_pipe_to_program` is not null before +accessing its stream_res. This prevents a null pointer dereference. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc.c:4140 commit_planes_for_stream() error: we previously assumed 'top_pipe_to_program' could be null (see line 3906) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index d7bca680805d3..b424465238afc 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -3727,7 +3727,8 @@ static void commit_planes_for_stream(struct dc *dc, + } + + if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed) +- if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { ++ if (top_pipe_to_program && ++ top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) { + top_pipe_to_program->stream_res.tg->funcs->wait_for_state( + top_pipe_to_program->stream_res.tg, + CRTC_STATE_VACTIVE); +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-check-null-pointers-before-using-dc-.patch b/queue-6.1/drm-amd-display-check-null-pointers-before-using-dc-.patch new file mode 100644 index 00000000000..502ec8d2a4d --- /dev/null +++ b/queue-6.1/drm-amd-display-check-null-pointers-before-using-dc-.patch @@ -0,0 +1,46 @@ +From ac6276e7b20671e089dde87c1dd1180ac0d46324 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Jul 2024 15:29:09 -0600 +Subject: drm/amd/display: Check null pointers before using dc->clk_mgr + +From: Alex Hung + +[ Upstream commit 95d9e0803e51d5a24276b7643b244c7477daf463 ] + +[WHY & HOW] +dc->clk_mgr is null checked previously in the same function, indicating +it might be null. + +Passing "dc" to "dc->hwss.apply_idle_power_optimizations", which +dereferences null "dc->clk_mgr". (The function pointer resolves to +"dcn35_apply_idle_power_optimizations".) + +This fixes 1 FORWARD_NULL issue reported by Coverity. + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Alex Hung +Signed-off-by: Tom Chung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index b424465238afc..2d514e2e91a04 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -4516,7 +4516,8 @@ void dc_allow_idle_optimizations(struct dc *dc, bool allow) + if (allow == dc->idle_optimizations_allowed) + return; + +- if (dc->hwss.apply_idle_power_optimizations && dc->hwss.apply_idle_power_optimizations(dc, allow)) ++ if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL && ++ dc->hwss.apply_idle_power_optimizations(dc, allow)) + dc->idle_optimizations_allowed = allow; + } + +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-check-stream-before-comparing-them.patch b/queue-6.1/drm-amd-display-check-stream-before-comparing-them.patch new file mode 100644 index 00000000000..c9f53461614 --- /dev/null +++ b/queue-6.1/drm-amd-display-check-stream-before-comparing-them.patch @@ -0,0 +1,41 @@ +From 8e99799494decc452815192b5f30e1055db1a08f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jun 2024 20:05:14 -0600 +Subject: drm/amd/display: Check stream before comparing them + +From: Alex Hung + +[ Upstream commit 35ff747c86767937ee1e0ca987545b7eed7a0810 ] + +[WHAT & HOW] +amdgpu_dm can pass a null stream to dc_is_stream_unchanged. It is +necessary to check for null before dereferencing them. + +This fixes 1 FORWARD_NULL issue reported by Coverity. + +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Jerry Zuo +Signed-off-by: Alex Hung +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index d4ba81f36ded1..8b27fe2f5ab19 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1915,6 +1915,8 @@ static bool are_stream_backends_same( + bool dc_is_stream_unchanged( + struct dc_stream_state *old_stream, struct dc_stream_state *stream) + { ++ if (!old_stream || !stream) ++ return false; + + if (!are_stream_backends_same(old_stream, stream)) + return false; +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch new file mode 100644 index 00000000000..0783eb4678f --- /dev/null +++ b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-col.patch @@ -0,0 +1,54 @@ +From b04f13a0c60785c723259d77238a8711c87db444 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 18:05:20 +0530 +Subject: drm/amd/display: Fix index out of bounds in DCN30 color + transformation + +From: Srinivasan Shanmugam + +[ Upstream commit d81873f9e715b72d4f8d391c8eb243946f784dfc ] + +This commit addresses a potential index out of bounds issue in the +`cm3_helper_translate_curve_to_hw_format` function in the DCN30 color +management module. The issue could occur when the index 'i' exceeds the +number of transfer function points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds, the function returns +false to indicate an error. + +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:180 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:181 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:182 cm3_helper_translate_curve_to_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +index e0b1fc92ed186..62c02adae7e76 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +@@ -178,6 +178,8 @@ bool cm3_helper_translate_curve_to_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch new file mode 100644 index 00000000000..6a47faa1c2e --- /dev/null +++ b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-dcn30-deg.patch @@ -0,0 +1,55 @@ +From 63007547aee4b55aa042f55395790147efa04049 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 18:44:02 +0530 +Subject: drm/amd/display: Fix index out of bounds in DCN30 degamma hardware + format translation + +From: Srinivasan Shanmugam + +[ Upstream commit bc50b614d59990747dd5aeced9ec22f9258991ff ] + +This commit addresses a potential index out of bounds issue in the +`cm3_helper_translate_curve_to_degamma_hw_format` function in the DCN30 +color management module. The issue could occur when the index 'i' +exceeds the number of transfer function points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds, the function returns +false to indicate an error. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:338 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:339 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn30/dcn30_cm_common.c:340 cm3_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +index e0df9b0065f9c..e0b1fc92ed186 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +@@ -355,6 +355,8 @@ bool cm3_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch new file mode 100644 index 00000000000..54c188b49d8 --- /dev/null +++ b/queue-6.1/drm-amd-display-fix-index-out-of-bounds-in-degamma-h.patch @@ -0,0 +1,55 @@ +From 411aa331591e2f9c3504c1c8a74fc85996d911c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Jul 2024 17:48:27 +0530 +Subject: drm/amd/display: Fix index out of bounds in degamma hardware format + translation + +From: Srinivasan Shanmugam + +[ Upstream commit b7e99058eb2e86aabd7a10761e76cae33d22b49f ] + +Fixes index out of bounds issue in +`cm_helper_translate_curve_to_degamma_hw_format` function. The issue +could occur when the index 'i' exceeds the number of transfer function +points (TRANSFER_FUNC_POINTS). + +The fix adds a check to ensure 'i' is within bounds before accessing the +transfer function points. If 'i' is out of bounds the function returns +false to indicate an error. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:594 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.red' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:595 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.green' 1025 <= s32max +drivers/gpu/drm/amd/amdgpu/../display/dc/dcn10/dcn10_cm_common.c:596 cm_helper_translate_curve_to_degamma_hw_format() error: buffer overflow 'output_tf->tf_pts.blue' 1025 <= s32max + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +index c0372aa4ec838..684e30f9cf898 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +@@ -571,6 +571,8 @@ bool cm_helper_translate_curve_to_degamma_hw_format( + i += increment) { + if (j == hw_points - 1) + break; ++ if (i >= TRANSFER_FUNC_POINTS) ++ return false; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-handle-null-stream_status-in-planes_.patch b/queue-6.1/drm-amd-display-handle-null-stream_status-in-planes_.patch new file mode 100644 index 00000000000..6ca01dbb2bb --- /dev/null +++ b/queue-6.1/drm-amd-display-handle-null-stream_status-in-planes_.patch @@ -0,0 +1,52 @@ +From 5a57c658e858f6ff9e038f39fe7ea728e07945b9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Jul 2024 19:31:55 +0530 +Subject: drm/amd/display: Handle null 'stream_status' in + 'planes_changed_for_existing_stream' + +From: Srinivasan Shanmugam + +[ Upstream commit 8141f21b941710ecebe49220b69822cab3abd23d ] + +This commit adds a null check for 'stream_status' in the function +'planes_changed_for_existing_stream'. Previously, the code assumed +'stream_status' could be null, but did not handle the case where it was +actually null. This could lead to a null pointer dereference. + +Reported by smatch: +drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:3784 planes_changed_for_existing_stream() error: we previously assumed 'stream_status' could be null (see line 3774) + +Cc: Tom Chung +Cc: Rodrigo Siqueira +Cc: Roman Li +Cc: Alex Hung +Cc: Aurabindo Pillai +Cc: Harry Wentland +Cc: Hamza Mahfooz +Signed-off-by: Srinivasan Shanmugam +Reviewed-by: Tom Chung +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 29400db42bb2d..d4ba81f36ded1 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -2634,8 +2634,10 @@ static bool planes_changed_for_existing_stream(struct dc_state *context, + } + } + +- if (!stream_status) ++ if (!stream_status) { + ASSERT(0); ++ return false; ++ } + + for (i = 0; i < set_count; i++) + if (set[i].stream == stream) +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-display-initialize-get_bytes_per_element-s-d.patch b/queue-6.1/drm-amd-display-initialize-get_bytes_per_element-s-d.patch new file mode 100644 index 00000000000..1d79113260d --- /dev/null +++ b/queue-6.1/drm-amd-display-initialize-get_bytes_per_element-s-d.patch @@ -0,0 +1,55 @@ +From 07df26b065eefaf4cd7eb005f3d0397cb4697f2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Jul 2024 09:57:01 -0600 +Subject: drm/amd/display: Initialize get_bytes_per_element's default to 1 + +From: Alex Hung + +[ Upstream commit 4067f4fa0423a89fb19a30b57231b384d77d2610 ] + +Variables, used as denominators and maybe not assigned to other values, +should not be 0. bytes_per_element_y & bytes_per_element_c are +initialized by get_bytes_per_element() which should never return 0. + +This fixes 10 DIVIDE_BY_ZERO issues reported by Coverity. + +Signed-off-by: Alex Hung +Reviewed-by: Aurabindo Pillai +Tested-by: Daniel Wheeler +Signed-off-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c | 2 +- + .../gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +index 0fc9f3e3ffaef..f603486af6e30 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +@@ -78,7 +78,7 @@ static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +index 618f4b682ab1b..9f28e4d3c664c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +@@ -53,7 +53,7 @@ static void calculate_ttu_cursor( + + static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) + { +- unsigned int ret_val = 0; ++ unsigned int ret_val = 1; + + if (source_format == dm_444_16) { + if (!is_chroma) +-- +2.43.0 + diff --git a/queue-6.1/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch b/queue-6.1/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch new file mode 100644 index 00000000000..7b9e588cf64 --- /dev/null +++ b/queue-6.1/drm-amd-pm-ensure-the-fw_info-is-not-null-before-usi.patch @@ -0,0 +1,36 @@ +From 907bd28350e757ede6de15f7278af39b881201ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 7 Aug 2024 17:15:12 +0800 +Subject: drm/amd/pm: ensure the fw_info is not null before using it + +From: Tim Huang + +[ Upstream commit 186fb12e7a7b038c2710ceb2fb74068f1b5d55a4 ] + +This resolves the dereference null return value warning +reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +index 182118e3fd5f3..2ca93a1f0b8e1 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +@@ -1185,6 +1185,8 @@ static int init_overdrive_limits(struct pp_hwmgr *hwmgr, + fw_info = smu_atom_get_data_table(hwmgr->adev, + GetIndexIntoMasterTable(DATA, FirmwareInfo), + &size, &frev, &crev); ++ PP_ASSERT_WITH_CODE(fw_info != NULL, ++ "Missing firmware info!", return -EINVAL); + + if ((fw_info->ucTableFormatRevision == 1) + && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4))) +-- +2.43.0 + diff --git a/queue-6.1/drm-amdgpu-add-raven1-gfxoff-quirk.patch b/queue-6.1/drm-amdgpu-add-raven1-gfxoff-quirk.patch new file mode 100644 index 00000000000..6ea83c081a3 --- /dev/null +++ b/queue-6.1/drm-amdgpu-add-raven1-gfxoff-quirk.patch @@ -0,0 +1,35 @@ +From fcb5a34f72eda9f17af2a07c9ae129d819ce0cdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:25:54 +0800 +Subject: drm/amdgpu: add raven1 gfxoff quirk + +From: Peng Liu + +[ Upstream commit 0126c0ae11e8b52ecfde9d1b174ee2f32d6c3a5d ] + +Fix screen corruption with openkylin. + +Link: https://bbs.openkylin.top/t/topic/171497 +Signed-off-by: Peng Liu +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index 6a1fe21685149..b977431c13b8d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1173,6 +1173,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = { + { 0x1002, 0x15dd, 0x1002, 0x15dd, 0xc6 }, + /* Apple MacBook Pro (15-inch, 2019) Radeon Pro Vega 20 4 GB */ + { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 }, ++ /* https://bbs.openkylin.top/t/topic/171497 */ ++ { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 }, + { 0, 0, 0, 0, 0 }, + }; + +-- +2.43.0 + diff --git a/queue-6.1/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch b/queue-6.1/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch new file mode 100644 index 00000000000..73c25f0bdc0 --- /dev/null +++ b/queue-6.1/drm-amdgpu-disallow-multiple-bo_handles-chunks-in-on.patch @@ -0,0 +1,49 @@ +From ccbdb009c6a0a311e022e9080360cfa42a4c3f80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Jul 2024 11:54:30 +0200 +Subject: drm/amdgpu: disallow multiple BO_HANDLES chunks in one submit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Pierre-Eric Pelloux-Prayer + +[ Upstream commit fec5f8e8c6bcf83ed7a392801d7b44c5ecfc1e82 ] + +Before this commit, only submits with both a BO_HANDLES chunk and a +'bo_list_handle' would be rejected (by amdgpu_cs_parser_bos). + +But if UMD sent multiple BO_HANDLES, what would happen is: +* only the last one would be really used +* all the others would leak memory as amdgpu_cs_p1_bo_handles would + overwrite the previous p->bo_list value + +This commit rejects submissions with multiple BO_HANDLES chunks to +match the implementation of the parser. + +Signed-off-by: Pierre-Eric Pelloux-Prayer +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 133e4e03c143c..91c5bb79e1678 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -257,6 +257,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, + if (size < sizeof(struct drm_amdgpu_bo_list_in)) + goto free_partial_kdata; + ++ /* Only a single BO list is allowed to simplify handling. */ ++ if (p->bo_list) ++ ret = -EINVAL; ++ + ret = amdgpu_cs_p1_bo_handles(p, p->chunks[i].kdata); + if (ret) + goto free_partial_kdata; +-- +2.43.0 + diff --git a/queue-6.1/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch b/queue-6.1/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch new file mode 100644 index 00000000000..dd1e2020201 --- /dev/null +++ b/queue-6.1/drm-amdgpu-enable-gfxoff-quirk-on-hp-705g4.patch @@ -0,0 +1,38 @@ +From 6a0bd30882e04cfada7d95df3d0085d9447aca7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Aug 2024 15:27:08 +0800 +Subject: drm/amdgpu: enable gfxoff quirk on HP 705G4 + +From: Peng Liu + +[ Upstream commit 2c7795e245d993bcba2f716a8c93a5891ef910c9 ] + +Enabling gfxoff quirk results in perfectly usable +graphical user interface on HP 705G4 DM with R5 2400G. + +Without the quirk, X server is completely unusable as +every few seconds there is gpu reset due to ring gfx timeout. + +Signed-off-by: Peng Liu +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index b977431c13b8d..3cec6a145a5c8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1175,6 +1175,8 @@ static const struct amdgpu_gfxoff_quirk amdgpu_gfxoff_quirk_list[] = { + { 0x1002, 0x69af, 0x106b, 0x019a, 0xc0 }, + /* https://bbs.openkylin.top/t/topic/171497 */ + { 0x1002, 0x15d8, 0x19e5, 0x3e14, 0xc2 }, ++ /* HP 705G4 DM with R5 2400G */ ++ { 0x1002, 0x15dd, 0x103c, 0x8464, 0xd6 }, + { 0, 0, 0, 0, 0 }, + }; + +-- +2.43.0 + diff --git a/queue-6.1/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch b/queue-6.1/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch new file mode 100644 index 00000000000..c098c7062ee --- /dev/null +++ b/queue-6.1/drm-amdgpu-fix-unchecked-return-value-warning-for-am.patch @@ -0,0 +1,72 @@ +From 579d6f703fbf560720709d6c46917a6796afcb88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 10:38:37 +0800 +Subject: drm/amdgpu: fix unchecked return value warning for amdgpu_gfx + +From: Tim Huang + +[ Upstream commit c0277b9d7c2ee9ee5dbc948548984f0fbb861301 ] + +This resolves the unchecded return value warning reported by Coverity. + +Signed-off-by: Tim Huang +Reviewed-by: Jesse Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index e9e0e7328c4e1..6b818c6c9a4c2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -676,8 +676,11 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r + int r; + + if (amdgpu_ras_is_supported(adev, ras_block->block)) { +- if (!amdgpu_persistent_edc_harvesting_supported(adev)) +- amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (!amdgpu_persistent_edc_harvesting_supported(adev)) { ++ r = amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); ++ if (r) ++ return r; ++ } + + r = amdgpu_ras_block_late_init(adev, ras_block); + if (r) +@@ -758,7 +761,10 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg) + pr_err("critical bug! too many kiq readers\n"); + goto failed_unlock; + } +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_rreg(ring, reg, reg_val_offs); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -824,7 +830,10 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + } + + spin_lock_irqsave(&kiq->ring_lock, flags); +- amdgpu_ring_alloc(ring, 32); ++ r = amdgpu_ring_alloc(ring, 32); ++ if (r) ++ goto failed_unlock; ++ + amdgpu_ring_emit_wreg(ring, reg, v); + r = amdgpu_fence_emit_polling(ring, &seq, MAX_KIQ_REG_WAIT); + if (r) +@@ -860,6 +869,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) + + failed_undo: + amdgpu_ring_undo(ring); ++failed_unlock: + spin_unlock_irqrestore(&kiq->ring_lock, flags); + failed_kiq_write: + dev_err(adev->dev, "failed to write reg:%x\n", reg); +-- +2.43.0 + diff --git a/queue-6.1/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch b/queue-6.1/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch new file mode 100644 index 00000000000..3527c8803f6 --- /dev/null +++ b/queue-6.1/drm-amdkfd-fix-resource-leak-in-criu-restore-queue.patch @@ -0,0 +1,35 @@ +From 01439c68fe16592b33d6b80f59808f63d9cb2d88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Sep 2024 11:29:55 +0800 +Subject: drm/amdkfd: Fix resource leak in criu restore queue + +From: Jesse Zhang + +[ Upstream commit aa47fe8d3595365a935921a90d00bc33ee374728 ] + +To avoid memory leaks, release q_extra_data when exiting the restore queue. +v2: Correct the proto (Alex) + +Signed-off-by: Jesse Zhang +Reviewed-by: Tim Huang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index 4236539d9f932..99aa8a8399d69 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -890,6 +890,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, + pr_debug("Queue id %d was restored successfully\n", queue_id); + + kfree(q_data); ++ kfree(q_extra_data); + + return ret; + } +-- +2.43.0 + diff --git a/queue-6.1/drm-printer-allow-null-data-in-devcoredump-printer.patch b/queue-6.1/drm-printer-allow-null-data-in-devcoredump-printer.patch new file mode 100644 index 00000000000..cb16e161ba3 --- /dev/null +++ b/queue-6.1/drm-printer-allow-null-data-in-devcoredump-printer.patch @@ -0,0 +1,144 @@ +From a99fb360bdaa3d81afbc39f3119d61775dabc2d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Aug 2024 08:41:17 -0700 +Subject: drm/printer: Allow NULL data in devcoredump printer + +From: Matthew Brost + +[ Upstream commit 53369581dc0c68a5700ed51e1660f44c4b2bb524 ] + +We want to determine the size of the devcoredump before writing it out. +To that end, we will run the devcoredump printer with NULL data to get +the size, alloc data based on the generated offset, then run the +devcorecump again with a valid data pointer to print. This necessitates +not writing data to the data pointer on the initial pass, when it is +NULL. + +v5: + - Better commit message (Jonathan) + - Add kerenl doc with examples (Jani) + +Cc: Maarten Lankhorst +Acked-by: Maarten Lankhorst +Signed-off-by: Matthew Brost +Reviewed-by: Jonathan Cavitt +Link: https://patchwork.freedesktop.org/patch/msgid/20240801154118.2547543-3-matthew.brost@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_print.c | 13 +++++---- + include/drm/drm_print.h | 54 ++++++++++++++++++++++++++++++++++++- + 2 files changed, 61 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c +index 5b93c11895bb1..aab76334083e8 100644 +--- a/drivers/gpu/drm/drm_print.c ++++ b/drivers/gpu/drm/drm_print.c +@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + copy = iterator->remain; + + /* Copy out the bit of the string that we need */ +- memcpy(iterator->data, +- str + (iterator->start - iterator->offset), copy); ++ if (iterator->data) ++ memcpy(iterator->data, ++ str + (iterator->start - iterator->offset), copy); + + iterator->offset = iterator->start + copy; + iterator->remain -= copy; +@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str) + + len = min_t(ssize_t, strlen(str), iterator->remain); + +- memcpy(iterator->data + pos, str, len); ++ if (iterator->data) ++ memcpy(iterator->data + pos, str, len); + + iterator->offset += len; + iterator->remain -= len; +@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf) + if ((iterator->offset >= iterator->start) && (len < iterator->remain)) { + ssize_t pos = iterator->offset - iterator->start; + +- snprintf(((char *) iterator->data) + pos, +- iterator->remain, "%pV", vaf); ++ if (iterator->data) ++ snprintf(((char *) iterator->data) + pos, ++ iterator->remain, "%pV", vaf); + + iterator->offset += len; + iterator->remain -= len; +diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h +index 094ded23534c7..1af4a55c33c44 100644 +--- a/include/drm/drm_print.h ++++ b/include/drm/drm_print.h +@@ -122,7 +122,8 @@ drm_vprintf(struct drm_printer *p, const char *fmt, va_list *va) + + /** + * struct drm_print_iterator - local struct used with drm_printer_coredump +- * @data: Pointer to the devcoredump output buffer ++ * @data: Pointer to the devcoredump output buffer, can be NULL if using ++ * drm_printer_coredump to determine size of devcoredump + * @start: The offset within the buffer to start writing + * @remain: The number of bytes to write for this iteration + */ +@@ -167,6 +168,57 @@ struct drm_print_iterator { + * coredump_read, ...) + * } + * ++ * The above example has a time complexity of O(N^2), where N is the size of the ++ * devcoredump. This is acceptable for small devcoredumps but scales poorly for ++ * larger ones. ++ * ++ * Another use case for drm_coredump_printer is to capture the devcoredump into ++ * a saved buffer before the dev_coredump() callback. This involves two passes: ++ * one to determine the size of the devcoredump and another to print it to a ++ * buffer. Then, in dev_coredump(), copy from the saved buffer into the ++ * devcoredump read buffer. ++ * ++ * For example:: ++ * ++ * char *devcoredump_saved_buffer; ++ * ++ * ssize_t __coredump_print(char *buffer, ssize_t count, ...) ++ * { ++ * struct drm_print_iterator iter; ++ * struct drm_printer p; ++ * ++ * iter.data = buffer; ++ * iter.start = 0; ++ * iter.remain = count; ++ * ++ * p = drm_coredump_printer(&iter); ++ * ++ * drm_printf(p, "foo=%d\n", foo); ++ * ... ++ * return count - iter.remain; ++ * } ++ * ++ * void coredump_print(...) ++ * { ++ * ssize_t count; ++ * ++ * count = __coredump_print(NULL, INT_MAX, ...); ++ * devcoredump_saved_buffer = kvmalloc(count, GFP_KERNEL); ++ * __coredump_print(devcoredump_saved_buffer, count, ...); ++ * } ++ * ++ * void coredump_read(char *buffer, loff_t offset, size_t count, ++ * void *data, size_t datalen) ++ * { ++ * ... ++ * memcpy(buffer, devcoredump_saved_buffer + offset, count); ++ * ... ++ * } ++ * ++ * The above example has a time complexity of O(N*2), where N is the size of the ++ * devcoredump. This scales better than the previous example for larger ++ * devcoredumps. ++ * + * RETURNS: + * The &drm_printer object + */ +-- +2.43.0 + diff --git a/queue-6.1/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch b/queue-6.1/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch new file mode 100644 index 00000000000..7b16e04dfa2 --- /dev/null +++ b/queue-6.1/drm-radeon-r100-handle-unknown-family-in-r100_cp_ini.patch @@ -0,0 +1,140 @@ +From a22781d88465d0c56a8c7be32a550f165766aaa0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 30 Jul 2024 17:58:12 +0200 +Subject: drm/radeon/r100: Handle unknown family in r100_cp_init_microcode() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Geert Uytterhoeven + +[ Upstream commit c6dbab46324b1742b50dc2fb5c1fee2c28129439 ] + +With -Werror: + + In function ‘r100_cp_init_microcode’, + inlined from ‘r100_cp_init’ at drivers/gpu/drm/radeon/r100.c:1136:7: + include/linux/printk.h:465:44: error: ‘%s’ directive argument is null [-Werror=format-overflow=] + 465 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__) + | ^ + include/linux/printk.h:437:17: note: in definition of macro ‘printk_index_wrap’ + 437 | _p_func(_fmt, ##__VA_ARGS__); \ + | ^~~~~~~ + include/linux/printk.h:508:9: note: in expansion of macro ‘printk’ + 508 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) + | ^~~~~~ + drivers/gpu/drm/radeon/r100.c:1062:17: note: in expansion of macro ‘pr_err’ + 1062 | pr_err("radeon_cp: Failed to load firmware \"%s\"\n", fw_name); + | ^~~~~~ + +Fix this by converting the if/else if/... construct into a proper +switch() statement with a default to handle the error case. + +As a bonus, the generated code is ca. 100 bytes smaller (with gcc 11.4.0 +targeting arm32). + +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/radeon/r100.c | 70 ++++++++++++++++++++++------------- + 1 file changed, 45 insertions(+), 25 deletions(-) + +diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c +index f336b5b3b11f4..42605e2765f8f 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -1015,45 +1015,65 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) + + DRM_DEBUG_KMS("\n"); + +- if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) || +- (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) || +- (rdev->family == CHIP_RS200)) { ++ switch (rdev->family) { ++ case CHIP_R100: ++ case CHIP_RV100: ++ case CHIP_RV200: ++ case CHIP_RS100: ++ case CHIP_RS200: + DRM_INFO("Loading R100 Microcode\n"); + fw_name = FIRMWARE_R100; +- } else if ((rdev->family == CHIP_R200) || +- (rdev->family == CHIP_RV250) || +- (rdev->family == CHIP_RV280) || +- (rdev->family == CHIP_RS300)) { ++ break; ++ ++ case CHIP_R200: ++ case CHIP_RV250: ++ case CHIP_RV280: ++ case CHIP_RS300: + DRM_INFO("Loading R200 Microcode\n"); + fw_name = FIRMWARE_R200; +- } else if ((rdev->family == CHIP_R300) || +- (rdev->family == CHIP_R350) || +- (rdev->family == CHIP_RV350) || +- (rdev->family == CHIP_RV380) || +- (rdev->family == CHIP_RS400) || +- (rdev->family == CHIP_RS480)) { ++ break; ++ ++ case CHIP_R300: ++ case CHIP_R350: ++ case CHIP_RV350: ++ case CHIP_RV380: ++ case CHIP_RS400: ++ case CHIP_RS480: + DRM_INFO("Loading R300 Microcode\n"); + fw_name = FIRMWARE_R300; +- } else if ((rdev->family == CHIP_R420) || +- (rdev->family == CHIP_R423) || +- (rdev->family == CHIP_RV410)) { ++ break; ++ ++ case CHIP_R420: ++ case CHIP_R423: ++ case CHIP_RV410: + DRM_INFO("Loading R400 Microcode\n"); + fw_name = FIRMWARE_R420; +- } else if ((rdev->family == CHIP_RS690) || +- (rdev->family == CHIP_RS740)) { ++ break; ++ ++ case CHIP_RS690: ++ case CHIP_RS740: + DRM_INFO("Loading RS690/RS740 Microcode\n"); + fw_name = FIRMWARE_RS690; +- } else if (rdev->family == CHIP_RS600) { ++ break; ++ ++ case CHIP_RS600: + DRM_INFO("Loading RS600 Microcode\n"); + fw_name = FIRMWARE_RS600; +- } else if ((rdev->family == CHIP_RV515) || +- (rdev->family == CHIP_R520) || +- (rdev->family == CHIP_RV530) || +- (rdev->family == CHIP_R580) || +- (rdev->family == CHIP_RV560) || +- (rdev->family == CHIP_RV570)) { ++ break; ++ ++ case CHIP_RV515: ++ case CHIP_R520: ++ case CHIP_RV530: ++ case CHIP_R580: ++ case CHIP_RV560: ++ case CHIP_RV570: + DRM_INFO("Loading R500 Microcode\n"); + fw_name = FIRMWARE_R520; ++ break; ++ ++ default: ++ DRM_ERROR("Unsupported Radeon family %u\n", rdev->family); ++ return -EINVAL; + } + + err = request_firmware(&rdev->me_fw, fw_name, rdev->dev); +-- +2.43.0 + diff --git a/queue-6.1/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch b/queue-6.1/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch new file mode 100644 index 00000000000..939f52318fc --- /dev/null +++ b/queue-6.1/drm-stm-avoid-use-after-free-issues-with-crtc-and-pl.patch @@ -0,0 +1,254 @@ +From 9ac01690cd4042b151ce2fe7170e59cf00e8465c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Feb 2024 15:50:40 +0300 +Subject: drm/stm: Avoid use-after-free issues with crtc and plane +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Katya Orlova + +[ Upstream commit 19dd9780b7ac673be95bf6fd6892a184c9db611f ] + +ltdc_load() calls functions drm_crtc_init_with_planes(), +drm_universal_plane_init() and drm_encoder_init(). These functions +should not be called with parameters allocated with devm_kzalloc() +to avoid use-after-free issues [1]. + +Use allocations managed by the DRM framework. + +Found by Linux Verification Center (linuxtesting.org). + +[1] +https://lore.kernel.org/lkml/u366i76e3qhh3ra5oxrtngjtm2u5lterkekcz6y2jkndhuxzli@diujon4h7qwb/ + +Signed-off-by: Katya Orlova +Acked-by: Raphaël Gallais-Pou +Link: https://patchwork.freedesktop.org/patch/msgid/20240216125040.8968-1-e.orlova@ispras.ru +Signed-off-by: Raphael Gallais-Pou +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/stm/drv.c | 3 +- + drivers/gpu/drm/stm/ltdc.c | 73 ++++++++++---------------------------- + 2 files changed, 20 insertions(+), 56 deletions(-) + +diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c +index 77b1b10456f52..7a3f1b4020292 100644 +--- a/drivers/gpu/drm/stm/drv.c ++++ b/drivers/gpu/drm/stm/drv.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include "ltdc.h" + +@@ -74,7 +75,7 @@ static int drv_load(struct drm_device *ddev) + + DRM_DEBUG("%s\n", __func__); + +- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); ++ ldev = drmm_kzalloc(ddev, sizeof(*ldev), GFP_KERNEL); + if (!ldev) + return -ENOMEM; + +diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c +index b8c1636168cfa..1d22afcf34ba7 100644 +--- a/drivers/gpu/drm/stm/ltdc.c ++++ b/drivers/gpu/drm/stm/ltdc.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include