Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] Bluetooth: ISO: avoid NULL deref of conn in iso_conn_big_sync()
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz,
	iulia.tanasescu, stable
In-Reply-To: <20260621162305.219763-1-meatuni001@gmail.com>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Sun, 21 Jun 2026 21:23:05 +0500 you wrote:
> iso_conn_big_sync() drops the socket lock to call hci_get_route() and
> then re-acquires it, but dereferences iso_pi(sk)->conn->hcon afterwards
> without re-checking that conn is still valid.
> 
> While the lock is dropped, the connection can be torn down under the
> same socket lock: iso_disconn_cfm() -> iso_conn_del() -> iso_chan_del()
> sets iso_pi(sk)->conn to NULL (and the broadcast teardown path can also
> clear conn->hcon on its own). When iso_conn_big_sync() re-acquires the
> lock and reads conn->hcon, conn may be NULL, causing a NULL pointer
> dereference (hcon is the first member of struct iso_conn).
> 
> [...]

Here is the summary with links:
  - Bluetooth: ISO: avoid NULL deref of conn in iso_conn_big_sync()
    https://git.kernel.org/bluetooth/bluetooth-next/c/a0ac2b200be1

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH v2] Bluetooth: btnxpuart: Fix out-of-bounds firmware read in nxp_recv_fw_req_v3()
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Maoyi Xie
  Cc: amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
	ilpo.jarvinen, linux-bluetooth, linux-kernel
In-Reply-To: <178168541269.2821257.9969892285942248117@maoyixie.com>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Wed, 17 Jun 2026 16:36:52 +0800 you wrote:
> During the v3 firmware download the controller sends a v3_data_req with a
> 32 bit offset and a 16 bit len. nxp_recv_fw_req_v3() checks only the lower
> bound of the offset and then sends firmware from that offset.
> 
>   nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
>   serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
>                           nxpdev->fw_dnld_v3_offset, len);
> 
> [...]

Here is the summary with links:
  - [v2] Bluetooth: btnxpuart: Fix out-of-bounds firmware read in nxp_recv_fw_req_v3()
    https://git.kernel.org/bluetooth/bluetooth-next/c/25c286d75821

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH] Bluetooth: simplify force_no_mitm_write() with kstrtobool_from_user()
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Dmitry Antipov; +Cc: luiz.dentz, marcel, linux-bluetooth
In-Reply-To: <20260617153019.981515-1-dmantipov@yandex.ru>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Wed, 17 Jun 2026 18:30:19 +0300 you wrote:
> Simplify 'force_no_mitm_write()' by using the convenient
> 'kstrtobool_from_user()'.
> 
> Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> ---
>  net/bluetooth/hci_debugfs.c | 12 ++++--------
>  1 file changed, 4 insertions(+), 8 deletions(-)

Here is the summary with links:
  - Bluetooth: simplify force_no_mitm_write() with kstrtobool_from_user()
    https://git.kernel.org/bluetooth/bluetooth-next/c/f529eaa118a9

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH v2 0/5] Bluetooth: enable context analysis
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Pauli Virtanen; +Cc: linux-bluetooth
In-Reply-To: <cover.1781432726.git.pav@iki.fi>

Hello:

This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Sun, 14 Jun 2026 13:27:01 +0300 you wrote:
> v2:
> - Add annotations to RFCOMM
> - Enable analysis also for BNEP, RFCOMM, HIDP
> 
> ***
> 
> Set up compiler context analysis that generate compiler warnings on
> problems that Clang -Wthread-safety can detect:
> 
> [...]

Here is the summary with links:
  - [v2,1/5] Bluetooth: af_bluetooth: Add minimal context analysis annotations
    https://git.kernel.org/bluetooth/bluetooth-next/c/077b1a4fdaa3
  - [v2,2/5] Bluetooth: hci_core: Add minimal context analysis annotations
    https://git.kernel.org/bluetooth/bluetooth-next/c/2f798c97b743
  - [v2,3/5] Bluetooth: L2CAP: Add minimal context analysis annotations
    https://git.kernel.org/bluetooth/bluetooth-next/c/a9cdc2959c77
  - [v2,4/5] Bluetooth: RFCOMM: Add minimal context analysis annotations
    https://git.kernel.org/bluetooth/bluetooth-next/c/14cb114880c7
  - [v2,5/5] Bluetooth: enable context analysis
    https://git.kernel.org/bluetooth/bluetooth-next/c/9218167503ef

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH v6 1/2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Siwei Zhang; +Cc: luiz.dentz, pav, xiaowu.417, linux-bluetooth
In-Reply-To: <20260615153527.1583705-1-oss@fourdim.xyz>

Hello:

This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Mon, 15 Jun 2026 11:33:05 -0400 you wrote:
> hci_abort_conn() read hci_skb_event(hdev->sent_cmd) when a connection
> was pending, but hdev->sent_cmd can be NULL while req_status is still
> HCI_REQ_PEND, leading to a NULL pointer dereference and a general
> protection fault from the hci_rx_work() receive path.
> 
> Instead of inspecting hdev->sent_cmd, track the in-flight create
> connection command with a new per-connection HCI_CONN_CREATE flag and
> route all cancellation through hci_cancel_connect_sync(), which
> dispatches to a dedicated per-type cancel function. The create command
> is in exactly one of two states: still queued, or in flight. The cancel
> function holds cmd_sync_work_lock across the whole decision: the worker
> takes this lock to dequeue every entry, so while it is held a queued
> command cannot start running and an in-flight command cannot complete
> and let the next command become pending. This keeps the flag test and
> hci_cmd_sync_cancel() atomic with respect to the worker, so a queued
> command is simply dequeued, and an in-flight command owned by this
> connection is cancelled without the risk of cancelling an unrelated
> command that became pending in the meantime. CIS uses the same flag
> mechanism via HCI_CONN_CREATE_CIS but cannot be dequeued per-connection.
> 
> [...]

Here is the summary with links:
  - [v6,1/2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
    https://git.kernel.org/bluetooth/bluetooth-next/c/76c2d047410b
  - [v6,2/2] Bluetooth: hci_sync: Remove unused hci_cmd_sync_dequeue_once()
    https://git.kernel.org/bluetooth/bluetooth-next/c/8047d832767f

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH] Bluetooth: L2CAP: validate option length before reading conf opt value
From: patchwork-bot+bluetooth @ 2026-06-22 17:00 UTC (permalink / raw)
  To: Muhammad Bilal; +Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, stable
In-Reply-To: <20260620195635.41765-1-meatuni001@gmail.com>

Hello:

This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Sun, 21 Jun 2026 00:56:35 +0500 you wrote:
> l2cap_get_conf_opt() derives the option length from the
> attacker-controlled opt->len field and immediately dereferences
> opt->val (as u8, get_unaligned_le16() or get_unaligned_le32(), or a
> raw pointer for the default case) before any caller has confirmed
> that opt->len bytes are present in the buffer. The callers
> (l2cap_parse_conf_req(), l2cap_parse_conf_rsp() and
> l2cap_conf_rfc_get()) only detect a malformed option afterwards, once
> the running length has gone negative, by which point the
> out-of-bounds read has already executed.
> 
> [...]

Here is the summary with links:
  - Bluetooth: L2CAP: validate option length before reading conf opt value
    https://git.kernel.org/bluetooth/bluetooth-next/c/64522263b6e3

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [Bug 221681] New: hid_magicmouse: Bluetooth battery reporting stuck at 4% for Apple Magic Trackpad (USB-C) on Linux 7.0.0.22-generic
From: bugzilla-daemon @ 2026-06-22 16:56 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221681

            Bug ID: 221681
           Summary: hid_magicmouse: Bluetooth battery reporting stuck at
                    4% for Apple Magic Trackpad (USB-C) on Linux
                    7.0.0.22-generic
           Product: Drivers
           Version: 2.5
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P3
         Component: Bluetooth
          Assignee: linux-bluetooth@vger.kernel.org
          Reporter: pageau.hunter.c@gmail.com
        Regression: No

The hid_magicmouse driver incorrectly reports battery level as 4% for the
Apple Magic Trackpad (USB-C) when connected over Bluetooth.
The value appears to be a hardcoded default — it never updates, and no
battery-related activity appears in dmesg after the device connects.

This is distinct from the Magic Trackpad 2 USB battery fix merged before
Linux 7.0-rc3. That fix does not appear to cover the Bluetooth path.

DEVICE
  Model:   Apple Inc. Magic Trackpad (USB-C)
  Serial:  d0:c0:50:b8:66:86
  Connect: Bluetooth HID v3.19 (UUID 0x1124, classic BT, not BLE)

KERNEL
  7.0.0-22-generic (Ubuntu 26.04 LTS)
  Driver: hid_magicmouse
  Module:
/lib/modules/7.0.0-22-generic/kernel/drivers/hid/hid-magicmouse.ko.zst
  srcversion: CB57FC5C3E5315DB93BD466

SYMPTOMS
  /sys/class/power_supply/hid-d0:c0:50:b8:66:86-battery/capacity: 4
  upower reports: percentage 4%, warning-level: critical, state: discharging
  upower updated timestamp is current (not stale/1970 epoch)

  dmesg on connect shows NO battery-related output from magicmouse driver:

    [129671.910588] hid-generic 0005:004C:0324.004E: unknown main item tag 0x0
    [129671.910684] input: Hunter's Magic Trackpad Mouse as
/devices/virtual/misc/uhid/0005:004C:0324.004E/input/input164
    [129671.910779] input: Hunter's Magic Trackpad as
/devices/virtual/misc/uhid/0005:004C:0324.004E/input/input165
    [129671.910822] hid-generic 0005:004C:0324.004E: input,hidraw7: BLUETOOTH
HID v3.19 Mouse [Hunter's Magic Trackpad] on 88:63:df:8a:6c:87
    [129672.078299] magicmouse 0005:004C:0324.004E: unknown main item tag 0x0
    [129672.078384] input: Apple Inc. Magic Trackpad as
/devices/virtual/misc/uhid/0005:004C:0324.004E/input/input166
    [129672.078443] magicmouse 0005:004C:0324.004E: input,hidraw7: BLUETOOTH
HID v3.19 Mouse [Hunter's Magic Trackpad] on 88:63:df:8a:6c:87

  No "battery" string appears anywhere in dmesg output filtered for
  magic|magicmouse|hid_magic|hid|bluetooth|battery.

POWER SUPPLY UEVENT
  POWER_SUPPLY_NAME=hid-d0:c0:50:b8:66:86-battery
  POWER_SUPPLY_TYPE=Battery
  POWER_SUPPLY_STATUS=Discharging
  POWER_SUPPLY_PRESENT=1
  POWER_SUPPLY_ONLINE=1
  POWER_SUPPLY_CAPACITY=4

NOTES
  - The device is rechargeable and was not actually at 4% (trackpad functions
    normally with no low-battery behavior)
  - bluetoothctl does not show a Battery Percentage line, which is expected
    for HID-over-BT classic devices (not a regression)
  - /sys/kernel/debug/hid/0005:004C:0324.004E/rdesc was not accessible
  - lsmod confirms hid_magicmouse is loaded and bound to the device

EXPECTED
  Battery level is polled from device and reported accurately in
  /sys/class/power_supply/.../capacity

ACTUAL
  Capacity stuck at 4% from connect time, never updated. Driver emits no
  battery-related log output.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* [PATCH BlueZ v2] a2dp: Fix handling of codec capability storage
From: Luiz Augusto von Dentz @ 2026-06-22 15:56 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Codec capability is one byte long (max 255) the storage format is
02hhx which means each byte ends up as 2 characters so the buffer
needs to be doubled in order to handle capabilities of that size.

Reported-by:  p0her (_@p0her_) in TeamH4C working with TrendAI Zero Day Initiative
Reported-by: Michael Bommarito <michael.bommarito@gmail.com>
---
 profiles/audio/a2dp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index a5e002784c02..c8adc3122563 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -971,7 +971,7 @@ static void store_remote_sep(void *data, void *user_data)
 {
 	struct a2dp_remote_sep *sep = data;
 	GKeyFile *key_file = user_data;
-	char seid[4], value[256];
+	char seid[4], value[9 + 512];
 	struct avdtp_service_capability *service = avdtp_get_codec(sep->sep);
 	struct avdtp_media_codec_capability *codec;
 	unsigned int i;
@@ -2373,7 +2373,7 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 		uint8_t codec;
 		uint8_t delay_reporting;
 		GSList *l = NULL;
-		char caps[256];
+		char caps[513];
 		uint8_t data[128];
 		int i, size;
 
@@ -2386,10 +2386,10 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 			continue;
 
 		/* Try loading with delay_reporting first */
-		if (sscanf(value, "%02hhx:%02hhx:%02hhx:%s", &type, &codec,
+		if (sscanf(value, "%02hhx:%02hhx:%02hhx:%512s", &type, &codec,
 					&delay_reporting, caps) != 4) {
 			/* Try old format */
-			if (sscanf(value, "%02hhx:%02hhx:%s", &type, &codec,
+			if (sscanf(value, "%02hhx:%02hhx:%512s", &type, &codec,
 								caps) != 3) {
 				warn("Unable to load Endpoint: seid %u", rseid);
 				g_free(value);
@@ -2398,7 +2398,7 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
 			delay_reporting = false;
 		}
 
-		for (i = 0, size = strlen(caps); i < size; i += 2) {
+		for (i = 0, size = strlen(caps); i < size && i >= 2; i += 2) {
 			uint8_t *tmp = data + i / 2;
 
 			if (sscanf(caps + i, "%02hhx", tmp) != 1) {
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 2/8] power: sequencing: pcie-m2: Add PCI ID for NXP 88W9098 and AW693 Bluetooth
From: Manivannan Sadhasivam @ 2026-06-22 15:42 UTC (permalink / raw)
  To: Sherry Sun (OSS)
  Cc: robh, krzk+dt, conor+dt, Frank.Li, s.hauer, kernel, festevam,
	amitkumar.karwar, neeraj.sanjaykale, marcel, luiz.dentz,
	hongxing.zhu, l.stach, lpieralisi, kwilczynski, bhelgaas, brgl,
	imx, linux-pci, linux-arm-kernel, devicetree, linux-kernel,
	linux-bluetooth, linux-pm, sherry.sun
In-Reply-To: <20260618101047.4185497-3-sherry.sun@oss.nxp.com>

On Thu, Jun 18, 2026 at 06:10:41PM +0800, Sherry Sun (OSS) wrote:
> From: Sherry Sun <sherry.sun@nxp.com>
> 
> 88W9098 is a NXP Wi-Fi/BT combo chip with PCI device ID 0x2b43 under
> Marvell Extended vendor ID. AW693 is a NXP Wi-Fi/BT combo chip with
> PCI device ID 0x3003 under NXP/Philips vendor ID.
> 
> Add both chips to pwrseq_m2_pci_ids[] so that the pwrseq-pcie-m2 driver
> can create the Bluetooth serdev device when these cards are inserted into
> a PCIe M.2 Key E connector.
> 
> Both chips use "nxp,88w8987-bt" as the serdev compatible string, which
> is the entry point for the btnxpuart driver. The driver identifies the
> actual chip variant at runtime via chip ID auto-detection and loads the
> appropriate firmware accordingly.
> 
> Signed-off-by: Sherry Sun <sherry.sun@nxp.com>

Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>

- Mani

> ---
>  drivers/power/sequencing/pwrseq-pcie-m2.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c
> index 94c3f4b7ee36..9217ffcfa6e5 100644
> --- a/drivers/power/sequencing/pwrseq-pcie-m2.c
> +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c
> @@ -186,6 +186,10 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
>  }
>  
>  static const struct pci_device_id pwrseq_m2_pci_ids[] = {
> +	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x2b43),
> +	  .driver_data = (kernel_ulong_t)"nxp,88w8987-bt" },
> +	{ PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, 0x3003),
> +	  .driver_data = (kernel_ulong_t)"nxp,88w8987-bt" },
>  	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107),
>  	  .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" },
>  	{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1103),
> -- 
> 2.50.1
> 

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply

* Re: [PATCH 08/13] Bluetooth: hci_sync: Fix return value of hci_reset_sync()
From: Luiz Augusto von Dentz @ 2026-06-22 15:35 UTC (permalink / raw)
  To: Zijun Hu
  Cc: Marcel Holtmann, Rocky Liao, Bartosz Golaszewski,
	Ben Young Tae Kim, Balakrishna Godavarthi, Matthias Kaehlcke,
	Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm
In-Reply-To: <20260622-bt_bugfix-v1-8-11f936d84e72@oss.qualcomm.com>

Hi Zijun,

On Mon, Jun 22, 2026 at 10:52 AM Zijun Hu <zijun.hu@oss.qualcomm.com> wrote:
>
> hci_reset_sync() may return positive HCI status byte as-is, but callers
> in the chain hci_reset_sync() -> hci_init0_sync() -> hci_unconf_init_sync()
> check errors with < 0, so a positive status is silently ignored.
>
> Fix by converting positive HCI status to a negative errno using
> bt_to_errno().
>
> Fixes: d0b137062b2d ("Bluetooth: hci_sync: Rework init stages")
> Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
> ---
>  net/bluetooth/hci_sync.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index fce9f9526cb5..601d44ef975f 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -3678,8 +3678,10 @@ int hci_reset_sync(struct hci_dev *hdev)
>
>         err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
>                                     HCI_CMD_TIMEOUT);
> +       if (err < 0)
> +               return err;
>
> -       return err;
> +       return -bt_to_errno(err);
>  }

There seem to be 2 consecutive changes to hci_reset_sync that conflict
with each other, also the expectation should be that positive errors
are HCI errors and negative errors are stack generated ones, so the
callers should really check `err` and not `err < 0`.

>  static int hci_init0_sync(struct hci_dev *hdev)
>
> --
> 2.34.1
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH 04/13] Bluetooth: btusb: QCA: Do not populate devcoredump fields on ATH3012 or QCA_ROME
From: Dmitry Baryshkov @ 2026-06-22 15:31 UTC (permalink / raw)
  To: Zijun Hu
  Cc: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke, Zijun Hu, linux-bluetooth, linux-kernel,
	Luiz Augusto von Dentz, linux-arm-msm
In-Reply-To: <20260622-bt_bugfix-v1-4-11f936d84e72@oss.qualcomm.com>

On Mon, Jun 22, 2026 at 07:52:17AM -0700, Zijun Hu wrote:
> Devcoredump is disabled on ATH3012 or QCA_ROME, but btusb_setup_qca()
> used by both unconditionally populates those two devcoredump fields.
> 
> Fix by populating devcoredump fields only for BTUSB_QCA_WCN6855 devices,
> which are the only ones that enable devcoredump.

Why? Wouldn't it be better to enable devcoredump for all platforms?

> 
> Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
> ---
>  drivers/bluetooth/btusb.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 6a90f012b226..184a87d1234c 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -3708,8 +3708,10 @@ static int btusb_setup_qca(struct hci_dev *hdev)
>  	if (err < 0)
>  		return err;
>  
> -	btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
> -	btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
> +	if (btdata->match_id->driver_info & BTUSB_QCA_WCN6855) {
> +		btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
> +		btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
> +	}
>  
>  	if (!(status & QCA_SYSCFG_UPDATED)) {
>  		err = btusb_setup_qca_load_nvm(hdev, &ver, info);
> 
> -- 
> 2.34.1
> 

-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH 02/13] Bluetooth: btusb: Use & instead of == to test bitflag BTUSB_IGNORE
From: Dmitry Baryshkov @ 2026-06-22 15:30 UTC (permalink / raw)
  To: Zijun Hu
  Cc: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke, Zijun Hu, linux-bluetooth, linux-kernel,
	Luiz Augusto von Dentz, linux-arm-msm
In-Reply-To: <20260622-bt_bugfix-v1-2-11f936d84e72@oss.qualcomm.com>

On Mon, Jun 22, 2026 at 07:52:15AM -0700, Zijun Hu wrote:
> The driver_info field is a bitmask, so use & instead of == to test the
> BTUSB_IGNORE bitflag against it, which is consistent with how the other
> flags are tested.
> 
> Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
> ---
>  drivers/bluetooth/btusb.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH 01/13] Bluetooth: btusb: Initialize @priv_size at declaration in btusb_probe()
From: Dmitry Baryshkov @ 2026-06-22 15:30 UTC (permalink / raw)
  To: Zijun Hu
  Cc: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke, Zijun Hu, linux-bluetooth, linux-kernel,
	Luiz Augusto von Dentz, linux-arm-msm
In-Reply-To: <20260622-bt_bugfix-v1-1-11f936d84e72@oss.qualcomm.com>

On Mon, Jun 22, 2026 at 07:52:14AM -0700, Zijun Hu wrote:
> Initialize @priv_size at declaration to reduce a redundant assignment.

This is obvious from the commit. Please tell us, why?

> 
> Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
> ---
>  drivers/bluetooth/btusb.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 7f14ce96319b..5209e2418493 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -4082,7 +4082,7 @@ static int btusb_probe(struct usb_interface *intf,
>  	struct btusb_data *data;
>  	struct hci_dev *hdev;
>  	unsigned ifnum_base;
> -	int err, priv_size;
> +	int err, priv_size = 0;
>  
>  	BT_DBG("intf %p id %p", intf, id);
>  
> @@ -4152,8 +4152,6 @@ static int btusb_probe(struct usb_interface *intf,
>  	init_usb_anchor(&data->ctrl_anchor);
>  	spin_lock_init(&data->rxlock);
>  
> -	priv_size = 0;
> -
>  	data->recv_event = hci_recv_frame;
>  	data->recv_bulk = btusb_recv_bulk;
>  
> 
> -- 
> 2.34.1
> 

-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH BlueZ 1/2] audio: harden a2dp parsers
From: Pauli Virtanen @ 2026-06-22 15:26 UTC (permalink / raw)
  To: Geraldo Netto, linux-bluetooth
In-Reply-To: <20260620191735.2675946-2-geraldonetto@gmail.com>

Hi,

la, 2026-06-20 kello 21:17 +0200, Geraldo Netto kirjoitti:
> ---
>  Makefile.am                   |   7 +
>  Makefile.plugins              |   1 +
>  profiles/audio/a2dp-helpers.c | 136 ++++++++++++++++
>  profiles/audio/a2dp-helpers.h |  20 +++
>  profiles/audio/a2dp.c         |  86 +++++-----
>  unit/test-a2dp.c              | 288 ++++++++++++++++++++++++++++++++++
>  6 files changed, 489 insertions(+), 49 deletions(-)

This seems to be mixing style changes (eg NULL -> (GSourceFunc) NULL)
and other changes.

Generally it's better to separate the two, and commit messages should
make clear why you are changing things.

In this case also not clear to me the style changes are needed. The
NULL cast is probably not needed, the uint8_t delay_reporting; variable
doesn't seem to be used later.

>  create mode 100644 profiles/audio/a2dp-helpers.c
>  create mode 100644 profiles/audio/a2dp-helpers.h
>  create mode 100644 unit/test-a2dp.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index 76c4ab5d4..35871cc57 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -642,6 +642,13 @@ unit_test_avdtp_SOURCES = unit/test-avdtp.c \
>  				unit/avdtp.c unit/avdtp.h
>  unit_test_avdtp_LDADD = src/libshared-glib.la $(GLIB_LIBS)
>  
> +unit_tests += unit/test-a2dp
> +
> +unit_test_a2dp_SOURCES = unit/test-a2dp.c \
> +				profiles/audio/a2dp-helpers.c \
> +				profiles/audio/a2dp-helpers.h
> +unit_test_a2dp_LDADD = src/libshared-glib.la $(GLIB_LIBS) $(DBUS_LIBS)
> +
>  unit_tests += unit/test-avctp
>  
>  unit_test_avctp_SOURCES = unit/test-avctp.c \
> diff --git a/Makefile.plugins b/Makefile.plugins
> index ac667beda..57400d877 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -27,6 +27,7 @@ builtin_modules += a2dp
>  builtin_sources += profiles/audio/source.h profiles/audio/source.c \
>  			profiles/audio/sink.h profiles/audio/sink.c \
>  			profiles/audio/a2dp.h profiles/audio/a2dp.c \
> +			profiles/audio/a2dp-helpers.h profiles/audio/a2dp-helpers.c \
>  			profiles/audio/avdtp.h profiles/audio/avdtp.c \
>  			profiles/audio/a2dp-codecs.h
>  endif
> diff --git a/profiles/audio/a2dp-helpers.c b/profiles/audio/a2dp-helpers.c
> new file mode 100644
> index 000000000..035236df6
> --- /dev/null
> +++ b/profiles/audio/a2dp-helpers.c
> @@ -0,0 +1,136 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdbool.h>
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include <dbus/dbus.h>
> +#include <glib.h>
> +
> +#include "a2dp-helpers.h"
> +
> +static bool parse_hex_byte(const char **value, uint8_t *byte)
> +{
> +	int high;
> +	int low;
> +
> +	if ((*value)[0] == '\0' || (*value)[1] == '\0')
> +		return false;
> +
> +	high = g_ascii_xdigit_value((*value)[0]);
> +	low = g_ascii_xdigit_value((*value)[1]);
> +	if (high < 0 || low < 0)
> +		return false;
> +
> +	*byte = high << 4 | low;
> +	*value += 2;
> +
> +	return true;
> +}
> +
> +static bool parse_colon(const char **value)
> +{
> +	if (**value != ':')
> +		return false;
> +
> +	(*value)++;
> +
> +	return true;
> +}
> +
> +static bool parse_caps(const char *value, uint8_t *caps, size_t caps_len,
> +								size_t *size)
> +{
> +	size_t len;
> +	size_t i;
> +
> +	if (!value || !caps || !size)
> +		return false;
> +
> +	*size = 0;
> +
> +	len = strlen(value);
> +	if (!len || len % 2 || len / 2 > caps_len)
> +		return false;
> +
> +	for (i = 0; i < len; i++) {
> +		if (!g_ascii_isxdigit(value[i]))
> +			return false;
> +	}
> +
> +	for (i = 0; i < len; i += 2) {
> +		const char *pos = value + i;
> +
> +		parse_hex_byte(&pos, &caps[i / 2]);
> +	}
> +
> +	*size = len / 2;
> +
> +	return true;
> +}
> +
> +bool a2dp_parse_capabilities_array(DBusMessageIter *value,
> +					uint8_t **caps, int *size)
> +{
> +	DBusMessageIter array;
> +
> +	if (!value || !caps || !size)
> +		return false;
> +
> +	*caps = NULL;
> +	*size = 0;
> +
> +	if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
> +		return false;
> +
> +	if (dbus_message_iter_get_element_type(value) != DBUS_TYPE_BYTE)
> +		return false;
> +
> +	dbus_message_iter_recurse(value, &array);
> +	dbus_message_iter_get_fixed_array(&array, caps, size);
> +
> +	return *caps && *size > 0;
> +}
> +
> +bool a2dp_parse_persisted_endpoint(const char *value, uint8_t *type,
> +					uint8_t *codec,
> +					bool *delay_reporting,
> +					uint8_t *caps, size_t caps_len,
> +					size_t *size)
> +{
> +	const char *pos;
> +	uint8_t delay = 0;
> +
> +	if (!value || !type || !codec || !delay_reporting || !size)
> +		return false;
> +
> +	*size = 0;
> +
> +	pos = value;
> +	if (!parse_hex_byte(&pos, type) || !parse_colon(&pos))
> +		return false;
> +
> +	if (!parse_hex_byte(&pos, codec) || !parse_colon(&pos))
> +		return false;
> +
> +	if (pos[0] != '\0' && pos[1] != '\0' &&
> +			g_ascii_isxdigit(pos[0]) && g_ascii_isxdigit(pos[1]) &&
> +			pos[2] == ':') {
> +		parse_hex_byte(&pos, &delay);
> +		parse_colon(&pos);
> +		if (delay > 1)
> +			return false;
> +	}
> +
> +	if (!parse_caps(pos, caps, caps_len, size))
> +		return false;
> +
> +	*delay_reporting = delay;
> +
> +	return true;
> +}
> diff --git a/profiles/audio/a2dp-helpers.h b/profiles/audio/a2dp-helpers.h
> new file mode 100644
> index 000000000..a5c90c516
> --- /dev/null
> +++ b/profiles/audio/a2dp-helpers.h
> @@ -0,0 +1,20 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#ifndef BLUEZ_A2DP_HELPERS_H
> +#define BLUEZ_A2DP_HELPERS_H
> +
> +#include <stdbool.h>
> +#include <stddef.h>
> +#include <stdint.h>
> +
> +#include <dbus/dbus.h>
> +
> +bool a2dp_parse_capabilities_array(DBusMessageIter *value,
> +					uint8_t **caps, int *size);
> +bool a2dp_parse_persisted_endpoint(const char *value, uint8_t *type,
> +					uint8_t *codec,
> +					bool *delay_reporting,
> +					uint8_t *caps, size_t caps_len,
> +					size_t *size);
> +
> +#endif /* BLUEZ_A2DP_HELPERS_H */
> diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
> index a5e002784..0999436c5 100644
> --- a/profiles/audio/a2dp.c
> +++ b/profiles/audio/a2dp.c
> @@ -52,6 +52,7 @@
>  #include "sink.h"
>  #include "source.h"
>  #include "a2dp.h"
> +#include "a2dp-helpers.h"
>  #include "a2dp-codecs.h"
>  #include "media.h"
>  
> @@ -689,7 +690,7 @@ static void stream_state_changed(struct avdtp_stream *stream,
>  		if (err < 0 && err != -EINPROGRESS) {
>  			error("avdtp_start: %s (%d)", strerror(-err), -err);
>  			finalize_setup_errno(setup, err, finalize_resume,
> -									NULL);
> +							(GSourceFunc) NULL);
>  			return;
>  		}
>  
> @@ -942,7 +943,8 @@ static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code)
>  
>  	if (error_code != 0) {
>  		setup->stream = NULL;
> -		finalize_setup_errno(setup, -EPERM, finalize_config, NULL);
> +		finalize_setup_errno(setup, -EPERM, finalize_config,
> +							(GSourceFunc) NULL);
>  		goto done;
>  	}
>  
> @@ -954,7 +956,7 @@ static void endpoint_open_cb(struct a2dp_setup *setup, uint8_t error_code)
>  
>  	error("avdtp_open %s (%d)", strerror(-err), -err);
>  	setup->stream = NULL;
> -	finalize_setup_errno(setup, err, finalize_config, NULL);
> +	finalize_setup_errno(setup, err, finalize_config, (GSourceFunc) NULL);
>  done:
>  	setup_unref(setup);
>  }
> @@ -974,6 +976,7 @@ static void store_remote_sep(void *data, void *user_data)
>  	char seid[4], value[256];
>  	struct avdtp_service_capability *service = avdtp_get_codec(sep->sep);
>  	struct avdtp_media_codec_capability *codec;
> +	uint8_t delay_reporting;
>  	unsigned int i;
>  	ssize_t offset;
>  
> @@ -981,12 +984,13 @@ static void store_remote_sep(void *data, void *user_data)
>  		return;
>  
>  	codec = (void *) service->data;
> +	delay_reporting = avdtp_get_delay_reporting(sep->sep);
>  
>  	sprintf(seid, "%02hhx", avdtp_get_seid(sep->sep));
>  
>  	offset = sprintf(value, "%02hhx:%02hhx:%02hhx:",
>  			avdtp_get_type(sep->sep), codec->media_codec_type,
> -			avdtp_get_delay_reporting(sep->sep));
> +			delay_reporting);
>  
>  	for (i = 0; i < service->length - sizeof(*codec); i++)
>  		offset += sprintf(value + offset, "%02hhx", codec->data[i]);
> @@ -1139,7 +1143,8 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
>  			return;
>  
>  		setup->stream = NULL;
> -		finalize_setup_errno(setup, -EPERM, finalize_config, NULL);
> +		finalize_setup_errno(setup, -EPERM, finalize_config,
> +							(GSourceFunc) NULL);
>  		setup_unref(setup);
>  		return;
>  	}
> @@ -1148,7 +1153,8 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
>  	if (ret < 0) {
>  		error("avdtp_open %s (%d)", strerror(-ret), -ret);
>  		setup->stream = NULL;
> -		finalize_setup_errno(setup, ret, finalize_config, NULL);
> +		finalize_setup_errno(setup, ret, finalize_config,
> +							(GSourceFunc) NULL);
>  	}
>  }
>  
> @@ -1431,7 +1437,8 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
>  	if (start_err < 0 && start_err != -EINPROGRESS) {
>  		error("avdtp_start: %s (%d)", strerror(-start_err),
>  								-start_err);
> -		finalize_setup_errno(setup, start_err, finalize_resume, NULL);
> +		finalize_setup_errno(setup, start_err, finalize_resume,
> +							(GSourceFunc) NULL);
>  	}
>  
>  	return TRUE;
> @@ -1483,7 +1490,8 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
>  	start_err = avdtp_start(session, a2dp_stream->stream);
>  	if (start_err < 0 && start_err != -EINPROGRESS) {
>  		error("avdtp_start: %s (%d)", strerror(-start_err), -start_err);
> -		finalize_setup_errno(setup, start_err, finalize_suspend, NULL);
> +		finalize_setup_errno(setup, start_err, finalize_suspend,
> +							(GSourceFunc) NULL);
>  	}
>  }
>  
> @@ -1504,7 +1512,7 @@ static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
>  		return TRUE;
>  
>  	finalize_setup_errno(setup, -ECONNRESET, finalize_suspend,
> -							finalize_resume, NULL);
> +					finalize_resume, (GSourceFunc) NULL);
>  
>  	return TRUE;
>  }
> @@ -1572,7 +1580,8 @@ static gboolean a2dp_reconfigure(gpointer data)
>  	return FALSE;
>  
>  failed:
> -	finalize_setup_errno(setup, posix_err, finalize_config, NULL);
> +	finalize_setup_errno(setup, posix_err, finalize_config,
> +							(GSourceFunc) NULL);
>  	return FALSE;
>  }
>  
> @@ -1648,8 +1657,8 @@ static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
>  		return;
>  
>  	finalize_setup_errno(setup, -ECONNRESET, finalize_suspend,
> -							finalize_resume,
> -							finalize_config, NULL);
> +					finalize_resume, finalize_config,
> +					(GSourceFunc) NULL);
>  
>  	return;
>  }
> @@ -1901,7 +1910,8 @@ static void channel_free(void *data)
>  		setup->chan = NULL;
>  		setup_ref(setup);
>  		/* Finalize pending commands before we NULL setup->session */
> -		finalize_setup_errno(setup, -ENOTCONN, finalize_all, NULL);
> +		finalize_setup_errno(setup, -ENOTCONN, finalize_all,
> +							(GSourceFunc) NULL);
>  		avdtp_unref(setup->session);
>  		setup->session = NULL;
>  		setup_unref(setup);
> @@ -1991,10 +2001,12 @@ static struct a2dp_sep *find_sep(struct a2dp_server *server, uint8_t type,
>  
>  static int parse_properties(DBusMessageIter *props, uint8_t **caps, int *size)
>  {
> +	*caps = NULL;
> +	*size = 0;
> +
>  	while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) {
>  		const char *key;
>  		DBusMessageIter value, entry;
> -		int var;
>  
>  		dbus_message_iter_recurse(props, &entry);
>  		dbus_message_iter_get_basic(&entry, &key);
> @@ -2002,15 +2014,10 @@ static int parse_properties(DBusMessageIter *props, uint8_t **caps, int *size)
>  		dbus_message_iter_next(&entry);
>  		dbus_message_iter_recurse(&entry, &value);
>  
> -		var = dbus_message_iter_get_arg_type(&value);
>  		if (strcasecmp(key, "Capabilities") == 0) {
> -			DBusMessageIter array;
> -
> -			if (var != DBUS_TYPE_ARRAY)
> +			if (!a2dp_parse_capabilities_array(&value, caps, size))
>  				return -EINVAL;
>  
> -			dbus_message_iter_recurse(&value, &array);
> -			dbus_message_iter_get_fixed_array(&array, caps, size);
>  			return 0;
>  		}
>  
> @@ -2130,7 +2137,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
>  	struct avdtp_media_codec_capability *codec;
>  	DBusMessageIter args, props;
>  	const char *sender, *path;
> -	uint8_t *caps;
> +	uint8_t *caps = NULL;
>  	int err, size = 0;
>  
>  	sender = dbus_message_get_sender(msg);
> @@ -2371,11 +2378,10 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
>  	for (; *seids; seids++) {
>  		uint8_t type;
>  		uint8_t codec;
> -		uint8_t delay_reporting;
> +		bool delay_reporting;
>  		GSList *l = NULL;
> -		char caps[256];
>  		uint8_t data[128];
> -		int i, size;
> +		size_t size;
>  
>  		if (sscanf(*seids, "%02hhx", &rseid) != 1)
>  			continue;
> @@ -2385,34 +2391,16 @@ static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
>  		if (!value)
>  			continue;
>  
> -		/* Try loading with delay_reporting first */
> -		if (sscanf(value, "%02hhx:%02hhx:%02hhx:%s", &type, &codec,
> -					&delay_reporting, caps) != 4) {
> -			/* Try old format */
> -			if (sscanf(value, "%02hhx:%02hhx:%s", &type, &codec,
> -								caps) != 3) {
> -				warn("Unable to load Endpoint: seid %u", rseid);
> -				g_free(value);
> -				continue;
> -			}
> -			delay_reporting = false;
> -		}
> -
> -		for (i = 0, size = strlen(caps); i < size; i += 2) {
> -			uint8_t *tmp = data + i / 2;
> -
> -			if (sscanf(caps + i, "%02hhx", tmp) != 1) {
> -				warn("Unable to load Endpoint: seid %u", rseid);
> -				break;
> -			}
> +		if (!a2dp_parse_persisted_endpoint(value, &type, &codec,
> +						&delay_reporting, data,
> +						sizeof(data), &size)) {
> +			warn("Unable to load Endpoint: seid %u", rseid);
> +			g_free(value);
> +			continue;
>  		}
> -
>  		g_free(value);
>  
> -		if (i != size)
> -			continue;
> -
> -		caps_add_codec(&l, codec, data, size / 2);
> +		caps_add_codec(&l, codec, data, size);
>  
>  		rsep = avdtp_register_remote_sep(chan->session, rseid, type, l,
>  							delay_reporting);
> diff --git a/unit/test-a2dp.c b/unit/test-a2dp.c
> new file mode 100644
> index 000000000..2f7bd7bbc
> --- /dev/null
> +++ b/unit/test-a2dp.c
> @@ -0,0 +1,288 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include <dbus/dbus.h>
> +#include <glib.h>
> +
> +#include "profiles/audio/a2dp-helpers.h"
> +
> +static DBusMessage *new_method_call(void)
> +{
> +	return dbus_message_new_method_call("org.bluez.test",
> +						"/org/bluez/test",
> +						"org.bluez.test",
> +						"Test");
> +}
> +
> +static void append_byte_array(DBusMessage *msg, const uint8_t *data, int size)
> +{
> +	DBusMessageIter iter;
> +	DBusMessageIter array;
> +
> +	dbus_message_iter_init_append(msg, &iter);
> +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> +						DBUS_TYPE_BYTE_AS_STRING,
> +						&array);
> +	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
> +						&data, size);
> +	dbus_message_iter_close_container(&iter, &array);
> +}
> +
> +static void append_string_array(DBusMessage *msg)
> +{
> +	DBusMessageIter iter;
> +	DBusMessageIter array;
> +	const char *value = "not-bytes";
> +
> +	dbus_message_iter_init_append(msg, &iter);
> +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
> +						DBUS_TYPE_STRING_AS_STRING,
> +						&array);
> +	dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &value);
> +	dbus_message_iter_close_container(&iter, &array);
> +}
> +
> +static void test_capabilities_array_accepts_byte_array(void)
> +{
> +	DBusMessage *msg = new_method_call();
> +	DBusMessageIter iter;
> +	const uint8_t bytes[] = { 0x11, 0x22, 0x33 };
> +	uint8_t *caps = NULL;
> +	int size = 0;
> +
> +	g_assert_nonnull(msg);
> +
> +	append_byte_array(msg, bytes, sizeof(bytes));
> +	g_assert_true(dbus_message_iter_init(msg, &iter));
> +	g_assert_true(a2dp_parse_capabilities_array(&iter, &caps, &size));
> +	g_assert_cmpint(size, ==, 3);
> +	g_assert_nonnull(caps);
> +	g_assert_cmpint(memcmp(caps, bytes, sizeof(bytes)), ==, 0);
> +
> +	dbus_message_unref(msg);
> +}
> +
> +static void test_capabilities_array_rejects_wrong_element_type(void)
> +{
> +	DBusMessage *msg = new_method_call();
> +	DBusMessageIter iter;
> +	uint8_t *caps = (void *) 0x01;
> +	int size = 1;
> +
> +	g_assert_nonnull(msg);
> +
> +	append_string_array(msg);
> +	g_assert_true(dbus_message_iter_init(msg, &iter));
> +	g_assert_false(a2dp_parse_capabilities_array(&iter, &caps, &size));
> +	g_assert_null(caps);
> +	g_assert_cmpint(size, ==, 0);
> +
> +	dbus_message_unref(msg);
> +}
> +
> +static void test_capabilities_array_rejects_empty_array(void)
> +{
> +	DBusMessage *msg = new_method_call();
> +	DBusMessageIter iter;
> +	uint8_t *caps = (void *) 0x01;
> +	int size = 1;
> +
> +	g_assert_nonnull(msg);
> +
> +	append_byte_array(msg, NULL, 0);
> +	g_assert_true(dbus_message_iter_init(msg, &iter));
> +	g_assert_false(a2dp_parse_capabilities_array(&iter, &caps, &size));
> +	g_assert_cmpint(size, ==, 0);
> +
> +	dbus_message_unref(msg);
> +}
> +
> +static void test_capabilities_array_rejects_missing_iter(void)
> +{
> +	uint8_t *caps = (void *) 0x01;
> +	int size = 1;
> +
> +	g_assert_false(a2dp_parse_capabilities_array(NULL, &caps, &size));
> +}
> +
> +static void test_capabilities_array_rejects_non_array(void)
> +{
> +	DBusMessage *msg = new_method_call();
> +	DBusMessageIter iter;
> +	const char *value = "not-array";
> +	uint8_t *caps = (void *) 0x01;
> +	int size = 1;
> +
> +	g_assert_nonnull(msg);
> +
> +	dbus_message_iter_init_append(msg, &iter);
> +	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &value);
> +	g_assert_true(dbus_message_iter_init(msg, &iter));
> +	g_assert_false(a2dp_parse_capabilities_array(&iter, &caps, &size));
> +	g_assert_null(caps);
> +	g_assert_cmpint(size, ==, 0);
> +
> +	dbus_message_unref(msg);
> +}
> +
> +static void assert_endpoint(const char *value, uint8_t expected_type,
> +				uint8_t expected_codec,
> +				bool expected_delay,
> +				const uint8_t *expected_caps,
> +				size_t expected_size)
> +{
> +	uint8_t type = 0xff;
> +	uint8_t codec = 0xff;
> +	bool delay_reporting = true;
> +	uint8_t caps[128];
> +	size_t size = 0;
> +
> +	memset(caps, 0xa5, sizeof(caps));
> +
> +	g_assert_true(a2dp_parse_persisted_endpoint(value, &type, &codec,
> +							&delay_reporting,
> +							caps, sizeof(caps),
> +							&size));
> +	g_assert_cmpint(type, ==, expected_type);
> +	g_assert_cmpint(codec, ==, expected_codec);
> +	g_assert_cmpint(delay_reporting, ==, expected_delay);
> +	g_assert_cmpuint(size, ==, expected_size);
> +	g_assert_cmpint(memcmp(caps, expected_caps, expected_size), ==, 0);
> +}
> +
> +static void test_endpoint_parser_accepts_current_format(void)
> +{
> +	const uint8_t caps[] = { 0x11, 0x22, 0x33 };
> +
> +	assert_endpoint("00:40:01:112233", 0x00, 0x40, true, caps,
> +							sizeof(caps));
> +}
> +
> +static void test_endpoint_parser_accepts_old_format(void)
> +{
> +	const uint8_t caps[] = { 0xaa, 0xbb };
> +
> +	assert_endpoint("01:02:aabb", 0x01, 0x02, false, caps, sizeof(caps));
> +}
> +
> +static void assert_endpoint_rejected(const char *value)
> +{
> +	uint8_t type = 0xff;
> +	uint8_t codec = 0xff;
> +	bool delay_reporting = true;
> +	uint8_t caps[4] = { 0xa5, 0xa5, 0xa5, 0xa5 };
> +	size_t size = 7;
> +
> +	g_assert_false(a2dp_parse_persisted_endpoint(value, &type, &codec,
> +							&delay_reporting,
> +							caps, sizeof(caps),
> +							&size));
> +	g_assert_cmpint(caps[0], ==, 0xa5);
> +	g_assert_cmpint(caps[1], ==, 0xa5);
> +	g_assert_cmpint(caps[2], ==, 0xa5);
> +	g_assert_cmpint(caps[3], ==, 0xa5);
> +}
> +
> +static void test_endpoint_parser_rejects_invalid_fields(void)
> +{
> +	assert_endpoint_rejected(NULL);
> +	assert_endpoint_rejected("");
> +	assert_endpoint_rejected("00:40");
> +	assert_endpoint_rejected("00:40:");
> +	assert_endpoint_rejected("00:40:01:");
> +	assert_endpoint_rejected("00:40:02:aabb");
> +	assert_endpoint_rejected("00:40:01:aab");
> +	assert_endpoint_rejected("00:40:01:aazz");
> +	assert_endpoint_rejected("00:40:01:aa:bb");
> +	assert_endpoint_rejected("00:40:aabb:");
> +	assert_endpoint_rejected("xx:40:01:aabb");
> +}
> +
> +static void test_endpoint_parser_rejects_missing_output_buffer(void)
> +{
> +	uint8_t type;
> +	uint8_t codec;
> +	bool delay_reporting;
> +	size_t size;
> +
> +	g_assert_false(a2dp_parse_persisted_endpoint("00:40:01:aabb",
> +							&type, &codec,
> +							&delay_reporting,
> +							NULL, 0, &size));
> +}
> +
> +static void test_endpoint_parser_rejects_oversized_caps(void)
> +{
> +	char value[sizeof("00:40:01:") + 16];
> +
> +	memset(value, 'a', sizeof(value));
> +	memcpy(value, "00:40:01:", strlen("00:40:01:"));
> +	value[sizeof(value) - 1] = '\0';
> +
> +	assert_endpoint_rejected(value);
> +}
> +
> +static void test_endpoint_parser_fuzz_cases_keep_bounds(void)
> +{
> +	static const char alphabet[] = "0123456789abcdefABCDEF:gZ";
> +	unsigned int i;
> +
> +	for (i = 0; i < 4096; i++) {
> +		char value[16];
> +		uint8_t type;
> +		uint8_t codec;
> +		bool delay_reporting;
> +		uint8_t caps[6] = { 0, 0, 0, 0, 0xcc, 0xdd };
> +		size_t size;
> +		size_t len = i % (sizeof(value) - 1);
> +		size_t j;
> +
> +		for (j = 0; j < len; j++)
> +			value[j] = alphabet[(i + j * 7) %
> +						(sizeof(alphabet) - 1)];
> +		value[len] = '\0';
> +
> +		a2dp_parse_persisted_endpoint(value, &type, &codec,
> +						&delay_reporting, caps, 4,
> +						&size);
> +		g_assert_cmpint(caps[4], ==, 0xcc);
> +		g_assert_cmpint(caps[5], ==, 0xdd);
> +	}
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	g_test_init(&argc, &argv, NULL);
> +
> +	g_test_add_func("/a2dp/capabilities/byte-array",
> +			test_capabilities_array_accepts_byte_array);
> +	g_test_add_func("/a2dp/capabilities/wrong-element-type",
> +			test_capabilities_array_rejects_wrong_element_type);
> +	g_test_add_func("/a2dp/capabilities/empty-array",
> +			test_capabilities_array_rejects_empty_array);
> +	g_test_add_func("/a2dp/capabilities/missing-iter",
> +			test_capabilities_array_rejects_missing_iter);
> +	g_test_add_func("/a2dp/capabilities/non-array",
> +			test_capabilities_array_rejects_non_array);
> +	g_test_add_func("/a2dp/endpoint/current-format",
> +			test_endpoint_parser_accepts_current_format);
> +	g_test_add_func("/a2dp/endpoint/old-format",
> +			test_endpoint_parser_accepts_old_format);
> +	g_test_add_func("/a2dp/endpoint/invalid-fields",
> +			test_endpoint_parser_rejects_invalid_fields);
> +	g_test_add_func("/a2dp/endpoint/missing-output-buffer",
> +			test_endpoint_parser_rejects_missing_output_buffer);
> +	g_test_add_func("/a2dp/endpoint/oversized-caps",
> +			test_endpoint_parser_rejects_oversized_caps);
> +	g_test_add_func("/a2dp/endpoint/fuzz-bounds",
> +			test_endpoint_parser_fuzz_cases_keep_bounds);
> +
> +	return g_test_run();
> +}

-- 
Pauli Virtanen

^ permalink raw reply

* [PATCH 13/13] Bluetooth: btqca: Fix qca_set_bdaddr() using wrong HCI event type
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

EDL_WRITE_BD_ADDR_OPCODE (0xFC14) returns a command complete event,
not a VSE, but qca_set_bdaddr() waits for HCI_EV_VENDOR.

Fix by passing 0 as the event parameter to __hci_cmd_sync_ev() to
wait for the command complete event instead.

Fixes: 5c0a1001c8be ("Bluetooth: hci_qca: Add helper to set device address")
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btqca.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 875216e15603..f3487de813c2 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -1011,8 +1011,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 	baswap(&bdaddr_swapped, bdaddr);
 
 	skb = __hci_cmd_sync_ev(hdev, EDL_WRITE_BD_ADDR_OPCODE, 6,
-				&bdaddr_swapped, HCI_EV_VENDOR,
-				HCI_INIT_TIMEOUT);
+				&bdaddr_swapped, 0, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
 		bt_dev_err(hdev, "QCA Change address cmd failed (%d)", err);

-- 
2.34.1


^ permalink raw reply related

* [PATCH 12/13] Bluetooth: btqca: Fix undetected error HCI status in qca_send_reset()
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

qca_send_reset() uses __hci_cmd_sync() which returns an skb but never
reads the HCI status byte from skb->data[0], so a non-zero error status
returned by the controller is silently ignored.

Fix by replacing qca_send_reset() with __hci_reset_sync() which
properly extracts and converts the HCI status byte to a negative errno.

Fixes: 83e81961ff7e ("Bluetooth: btqca: Introduce generic QCA ROME support")
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btqca.c | 22 ++--------------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 04ebe290bc78..875216e15603 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -190,25 +190,6 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev)
 	return err;
 }
 
-static int qca_send_reset(struct hci_dev *hdev)
-{
-	struct sk_buff *skb;
-	int err;
-
-	bt_dev_dbg(hdev, "QCA HCI_RESET");
-
-	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
-		err = PTR_ERR(skb);
-		bt_dev_err(hdev, "QCA Reset failed (%d)", err);
-		return err;
-	}
-
-	kfree_skb(skb);
-
-	return 0;
-}
-
 static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
 {
 	u8 cmd;
@@ -990,7 +971,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
 	}
 
 	/* Perform HCI reset */
-	err = qca_send_reset(hdev);
+	bt_dev_dbg(hdev, "QCA HCI_RESET");
+	err = __hci_reset_sync(hdev);
 	if (err < 0) {
 		bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err);
 		return err;

-- 
2.34.1


^ permalink raw reply related

* [PATCH 11/13] Bluetooth: btusb: Move struct btusb_data and macros into btusb.h
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

btusb.c is growing large as vendor-specific code accumulates. Ideally,
btusb.c contains only the default implementation while vendor-specific
code lives in separate files for easier maintenance.

The newly added btusb.h also reduces unnecessary data copies in hooks
like btusb_mtk_setup().

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 119 +--------------------------------------
 drivers/bluetooth/btusb.h | 139 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+), 118 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 21e125db1b1f..0d0bd7b559c6 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci_drv.h>
 
+#include "btusb.h"
 #include "btintel.h"
 #include "btbcm.h"
 #include "btrtl.h"
@@ -38,36 +39,6 @@ static bool reset = true;
 
 static struct usb_driver btusb_driver;
 
-#define BTUSB_IGNORE			BIT(0)
-#define BTUSB_DIGIANSWER		BIT(1)
-#define BTUSB_CSR			BIT(2)
-#define BTUSB_SNIFFER			BIT(3)
-#define BTUSB_BCM92035			BIT(4)
-#define BTUSB_BROKEN_ISOC		BIT(5)
-#define BTUSB_WRONG_SCO_MTU		BIT(6)
-#define BTUSB_ATH3012			BIT(7)
-#define BTUSB_INTEL_COMBINED		BIT(8)
-#define BTUSB_INTEL_BOOT		BIT(9)
-#define BTUSB_BCM_PATCHRAM		BIT(10)
-#define BTUSB_MARVELL			BIT(11)
-#define BTUSB_SWAVE			BIT(12)
-#define BTUSB_AMP			BIT(13)
-#define BTUSB_QCA_ROME			BIT(14)
-#define BTUSB_BCM_APPLE			BIT(15)
-#define BTUSB_REALTEK			BIT(16)
-#define BTUSB_BCM2045			BIT(17)
-#define BTUSB_IFNUM_2			BIT(18)
-#define BTUSB_CW6622			BIT(19)
-#define BTUSB_MEDIATEK			BIT(20)
-#define BTUSB_WIDEBAND_SPEECH		BIT(21)
-#define BTUSB_INVALID_LE_STATES		BIT(22)
-#define BTUSB_QCA_WCN6855		BIT(23)
-#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED	BIT(24)
-#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
-#define BTUSB_INTEL_NO_WBS_SUPPORT	BIT(26)
-#define BTUSB_ACTIONS_SEMI		BIT(27)
-#define BTUSB_BARROT			BIT(28)
-
 static const struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
@@ -943,94 +914,6 @@ struct btqca_data {
 	struct qca_dump_info qca_dump;
 };
 
-#define BTUSB_MAX_ISOC_FRAMES	10
-
-#define BTUSB_INTR_RUNNING	0
-#define BTUSB_BULK_RUNNING	1
-#define BTUSB_ISOC_RUNNING	2
-#define BTUSB_SUSPENDING	3
-#define BTUSB_DID_ISO_RESUME	4
-#define BTUSB_BOOTLOADER	5
-#define BTUSB_DOWNLOADING	6
-#define BTUSB_FIRMWARE_LOADED	7
-#define BTUSB_FIRMWARE_FAILED	8
-#define BTUSB_BOOTING		9
-#define BTUSB_DIAG_RUNNING	10
-#define BTUSB_OOB_WAKE_ENABLED	11
-#define BTUSB_HW_RESET_ACTIVE	12
-#define BTUSB_TX_WAIT_VND_EVT	13
-#define BTUSB_WAKEUP_AUTOSUSPEND	14
-#define BTUSB_USE_ALT3_FOR_WBS	15
-#define BTUSB_ALT6_CONTINUOUS_TX	16
-#define BTUSB_HW_SSR_ACTIVE	17
-
-struct btusb_data {
-	struct hci_dev       *hdev;
-	struct usb_device    *udev;
-	struct usb_interface *intf;
-	struct usb_interface *isoc;
-	struct usb_interface *diag;
-	unsigned isoc_ifnum;
-
-	unsigned long flags;
-
-	bool poll_sync;
-	int intr_interval;
-	struct work_struct  work;
-	struct work_struct  waker;
-	struct delayed_work rx_work;
-
-	struct sk_buff_head acl_q;
-
-	struct usb_anchor deferred;
-	struct usb_anchor tx_anchor;
-	int tx_in_flight;
-	spinlock_t txlock;
-
-	struct usb_anchor intr_anchor;
-	struct usb_anchor bulk_anchor;
-	struct usb_anchor isoc_anchor;
-	struct usb_anchor diag_anchor;
-	struct usb_anchor ctrl_anchor;
-	spinlock_t rxlock;
-
-	struct sk_buff *evt_skb;
-	struct sk_buff *acl_skb;
-	struct sk_buff *sco_skb;
-
-	struct usb_endpoint_descriptor *intr_ep;
-	struct usb_endpoint_descriptor *bulk_tx_ep;
-	struct usb_endpoint_descriptor *bulk_rx_ep;
-	struct usb_endpoint_descriptor *isoc_tx_ep;
-	struct usb_endpoint_descriptor *isoc_rx_ep;
-	struct usb_endpoint_descriptor *diag_tx_ep;
-	struct usb_endpoint_descriptor *diag_rx_ep;
-
-	struct gpio_desc *reset_gpio;
-
-	__u8 cmdreq_type;
-	__u8 cmdreq;
-
-	unsigned int sco_num;
-	unsigned int air_mode;
-	bool usb_alt6_packet_flow;
-	int isoc_altsetting;
-	int suspend_count;
-	const struct usb_device_id *match_id;
-
-	int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
-	int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
-	int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
-
-	int (*setup_on_usb)(struct hci_dev *hdev);
-
-	int (*suspend)(struct hci_dev *hdev);
-	int (*resume)(struct hci_dev *hdev);
-	int (*disconnect)(struct hci_dev *hdev);
-
-	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
-};
-
 static void btusb_reset(struct hci_dev *hdev)
 {
 	struct btusb_data *data;
diff --git a/drivers/bluetooth/btusb.h b/drivers/bluetooth/btusb.h
new file mode 100644
index 000000000000..ad13c7d44836
--- /dev/null
+++ b/drivers/bluetooth/btusb.h
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
+ */
+
+#ifndef __BTUSB_H
+#define __BTUSB_H
+
+#include <linux/usb.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/gpio/consumer.h>
+#include <net/bluetooth/hci_core.h>
+
+/* driver_info flags */
+#define BTUSB_IGNORE			BIT(0)
+#define BTUSB_DIGIANSWER		BIT(1)
+#define BTUSB_CSR			BIT(2)
+#define BTUSB_SNIFFER			BIT(3)
+#define BTUSB_BCM92035			BIT(4)
+#define BTUSB_BROKEN_ISOC		BIT(5)
+#define BTUSB_WRONG_SCO_MTU		BIT(6)
+#define BTUSB_ATH3012			BIT(7)
+#define BTUSB_INTEL_COMBINED		BIT(8)
+#define BTUSB_INTEL_BOOT		BIT(9)
+#define BTUSB_BCM_PATCHRAM		BIT(10)
+#define BTUSB_MARVELL			BIT(11)
+#define BTUSB_SWAVE			BIT(12)
+#define BTUSB_AMP			BIT(13)
+#define BTUSB_QCA_ROME			BIT(14)
+#define BTUSB_BCM_APPLE			BIT(15)
+#define BTUSB_REALTEK			BIT(16)
+#define BTUSB_BCM2045			BIT(17)
+#define BTUSB_IFNUM_2			BIT(18)
+#define BTUSB_CW6622			BIT(19)
+#define BTUSB_MEDIATEK			BIT(20)
+#define BTUSB_WIDEBAND_SPEECH		BIT(21)
+#define BTUSB_INVALID_LE_STATES		BIT(22)
+#define BTUSB_QCA_WCN6855		BIT(23)
+#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED	BIT(24)
+#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
+#define BTUSB_INTEL_NO_WBS_SUPPORT	BIT(26)
+#define BTUSB_ACTIONS_SEMI		BIT(27)
+#define BTUSB_BARROT			BIT(28)
+
+#define BTUSB_MAX_ISOC_FRAMES	10
+
+/* btusb_data flags */
+#define BTUSB_INTR_RUNNING	0
+#define BTUSB_BULK_RUNNING	1
+#define BTUSB_ISOC_RUNNING	2
+#define BTUSB_SUSPENDING	3
+#define BTUSB_DID_ISO_RESUME	4
+#define BTUSB_BOOTLOADER	5
+#define BTUSB_DOWNLOADING	6
+#define BTUSB_FIRMWARE_LOADED	7
+#define BTUSB_FIRMWARE_FAILED	8
+#define BTUSB_BOOTING		9
+#define BTUSB_DIAG_RUNNING	10
+#define BTUSB_OOB_WAKE_ENABLED	11
+#define BTUSB_HW_RESET_ACTIVE	12
+#define BTUSB_TX_WAIT_VND_EVT	13
+#define BTUSB_WAKEUP_AUTOSUSPEND	14
+#define BTUSB_USE_ALT3_FOR_WBS	15
+#define BTUSB_ALT6_CONTINUOUS_TX	16
+#define BTUSB_HW_SSR_ACTIVE	17
+
+struct btusb_data {
+	struct hci_dev       *hdev;
+	struct usb_device    *udev;
+	struct usb_interface *intf;
+	struct usb_interface *isoc;
+	struct usb_interface *diag;
+	unsigned int isoc_ifnum;
+
+	unsigned long flags;
+
+	bool poll_sync;
+	int intr_interval;
+	struct work_struct  work;
+	struct work_struct  waker;
+	struct delayed_work rx_work;
+
+	struct sk_buff_head acl_q;
+
+	struct usb_anchor deferred;
+	struct usb_anchor tx_anchor;
+	int tx_in_flight;
+	spinlock_t txlock;
+
+	struct usb_anchor intr_anchor;
+	struct usb_anchor bulk_anchor;
+	struct usb_anchor isoc_anchor;
+	struct usb_anchor diag_anchor;
+	struct usb_anchor ctrl_anchor;
+	spinlock_t rxlock;
+
+	struct sk_buff *evt_skb;
+	struct sk_buff *acl_skb;
+	struct sk_buff *sco_skb;
+
+	struct usb_endpoint_descriptor *intr_ep;
+	struct usb_endpoint_descriptor *bulk_tx_ep;
+	struct usb_endpoint_descriptor *bulk_rx_ep;
+	struct usb_endpoint_descriptor *isoc_tx_ep;
+	struct usb_endpoint_descriptor *isoc_rx_ep;
+	struct usb_endpoint_descriptor *diag_tx_ep;
+	struct usb_endpoint_descriptor *diag_rx_ep;
+
+	struct gpio_desc *reset_gpio;
+
+	__u8 cmdreq_type;
+	__u8 cmdreq;
+
+	unsigned int sco_num;
+	unsigned int air_mode;
+	bool usb_alt6_packet_flow;
+	int isoc_altsetting;
+	int suspend_count;
+	const struct usb_device_id *match_id;
+
+	int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
+	int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
+	int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
+
+	int (*setup_on_usb)(struct hci_dev *hdev);
+
+	int (*suspend)(struct hci_dev *hdev);
+	int (*resume)(struct hci_dev *hdev);
+	int (*disconnect)(struct hci_dev *hdev);
+
+	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
+};
+
+#endif /* __BTUSB_H */

-- 
2.34.1


^ permalink raw reply related

* [PATCH 10/13] Bluetooth: btusb: Simplify btusb_shutdown_qca() by using __hci_reset_sync()
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

Use the new __hci_reset_sync() API instead of open-coding the HCI reset.

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e78277e24cd8..21e125db1b1f 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3900,16 +3900,13 @@ static bool btusb_wakeup(struct hci_dev *hdev)
 
 static int btusb_shutdown_qca(struct hci_dev *hdev)
 {
-	struct sk_buff *skb;
+	int err;
 
-	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
-	if (IS_ERR(skb)) {
+	err = __hci_reset_sync(hdev);
+	if (err)
 		bt_dev_err(hdev, "HCI reset during shutdown failed");
-		return PTR_ERR(skb);
-	}
-	kfree_skb(skb);
 
-	return 0;
+	return err;
 }
 
 static ssize_t force_poll_sync_read(struct file *file, char __user *user_buf,

-- 
2.34.1


^ permalink raw reply related

* [PATCH 09/13] Bluetooth: hci_sync: Add __hci_reset_sync() for device driver
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

Many vendor drivers have requirements to send a raw HCI reset
synchronously with HCI_INIT_TIMEOUT.

Add a dedicated API for them to use.

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 include/net/bluetooth/hci_sync.h |  1 +
 net/bluetooth/hci_sync.c         | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
index 73e494b2591d..7005fc9f257a 100644
--- a/include/net/bluetooth/hci_sync.h
+++ b/include/net/bluetooth/hci_sync.h
@@ -59,6 +59,7 @@ int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
 int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
 			     const void *param, u8 event, u32 timeout,
 			     struct sock *sk);
+int __hci_reset_sync(struct hci_dev *hdev);
 int hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
 			const void *param, u32 timeout);
 
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 601d44ef975f..40c9725585cb 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -3684,6 +3684,20 @@ int hci_reset_sync(struct hci_dev *hdev)
 	return -bt_to_errno(err);
 }
 
+/* Send a raw HCI reset for use by vendor drivers */
+int __hci_reset_sync(struct hci_dev *hdev)
+{
+	int err;
+
+	err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
+				    HCI_INIT_TIMEOUT);
+	if (err < 0)
+		return err;
+
+	return -bt_to_errno(err);
+}
+EXPORT_SYMBOL(__hci_reset_sync);
+
 static int hci_init0_sync(struct hci_dev *hdev)
 {
 	int err;

-- 
2.34.1


^ permalink raw reply related

* [PATCH 07/13] Bluetooth: hci_sync: Simplify hci_reset_sync()
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

Return err directly instead of using an if/return pattern.

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 net/bluetooth/hci_sync.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 3be8c3581c6c..fce9f9526cb5 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -3678,10 +3678,8 @@ int hci_reset_sync(struct hci_dev *hdev)
 
 	err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
 				    HCI_CMD_TIMEOUT);
-	if (err)
-		return err;
 
-	return 0;
+	return err;
 }
 
 static int hci_init0_sync(struct hci_dev *hdev)

-- 
2.34.1


^ permalink raw reply related

* [PATCH 08/13] Bluetooth: hci_sync: Fix return value of hci_reset_sync()
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

hci_reset_sync() may return positive HCI status byte as-is, but callers
in the chain hci_reset_sync() -> hci_init0_sync() -> hci_unconf_init_sync()
check errors with < 0, so a positive status is silently ignored.

Fix by converting positive HCI status to a negative errno using
bt_to_errno().

Fixes: d0b137062b2d ("Bluetooth: hci_sync: Rework init stages")
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 net/bluetooth/hci_sync.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index fce9f9526cb5..601d44ef975f 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -3678,8 +3678,10 @@ int hci_reset_sync(struct hci_dev *hdev)
 
 	err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
 				    HCI_CMD_TIMEOUT);
+	if (err < 0)
+		return err;
 
-	return err;
+	return -bt_to_errno(err);
 }
 
 static int hci_init0_sync(struct hci_dev *hdev)

-- 
2.34.1


^ permalink raw reply related

* [PATCH 05/13] Bluetooth: btusb: QCA: move qca_dump out of struct btusb_data
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

'struct btusb_data' ideally should not include vendor specific
fields, but it currently includes the QCA devcoredump member
'struct qca_dump_info qca_dump'.

Fix by moving it into hci_dev private area accessed by hci_get_priv().

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 56 ++++++++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 22 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 184a87d1234c..6f965c313dff 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -939,6 +939,10 @@ struct qca_dump_info {
 	u16 ram_dump_seqno;
 };
 
+struct btqca_data {
+	struct qca_dump_info qca_dump;
+};
+
 #define BTUSB_MAX_ISOC_FRAMES	10
 
 #define BTUSB_INTR_RUNNING	0
@@ -1025,8 +1029,6 @@ struct btusb_data {
 	int (*disconnect)(struct hci_dev *hdev);
 
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
-
-	struct qca_dump_info qca_dump;
 };
 
 static void btusb_reset(struct hci_dev *hdev)
@@ -3116,14 +3118,15 @@ struct qca_dump_hdr {
 static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	char buf[128];
-	struct btusb_data *btdata = hci_get_drvdata(hdev);
+	struct btqca_data *btqca_data = hci_get_priv(hdev);
+	struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
 
 	snprintf(buf, sizeof(buf), "Controller Name: 0x%x\n",
-			btdata->qca_dump.controller_id);
+			qca_dump_ptr->controller_id);
 	skb_put_data(skb, buf, strlen(buf));
 
 	snprintf(buf, sizeof(buf), "Firmware Version: 0x%x\n",
-			btdata->qca_dump.fw_version);
+			qca_dump_ptr->fw_version);
 	skb_put_data(skb, buf, strlen(buf));
 
 	snprintf(buf, sizeof(buf), "Driver: %s\nVendor: qca\n",
@@ -3131,7 +3134,7 @@ static void btusb_dump_hdr_qca(struct hci_dev *hdev, struct sk_buff *skb)
 	skb_put_data(skb, buf, strlen(buf));
 
 	snprintf(buf, sizeof(buf), "VID: 0x%x\nPID:0x%x\n",
-			btdata->qca_dump.id_vendor, btdata->qca_dump.id_product);
+			qca_dump_ptr->id_vendor, qca_dump_ptr->id_product);
 	skb_put_data(skb, buf, strlen(buf));
 
 	snprintf(buf, sizeof(buf), "Lmp Subversion: 0x%x\n",
@@ -3160,6 +3163,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
 
 	struct qca_dump_hdr *dump_hdr;
 	struct btusb_data *btdata = hci_get_drvdata(hdev);
+	struct btqca_data *btqca_data = hci_get_priv(hdev);
+	struct qca_dump_info *qca_dump_ptr = &btqca_data->qca_dump;
 	struct usb_device *udev = btdata->udev;
 
 	pkt_type = hci_skb_pkt_type(skb);
@@ -3187,8 +3192,8 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
 			goto out;
 		}
 
-		btdata->qca_dump.ram_dump_size = dump_size;
-		btdata->qca_dump.ram_dump_seqno = 0;
+		qca_dump_ptr->ram_dump_size = dump_size;
+		qca_dump_ptr->ram_dump_seqno = 0;
 
 		skb_pull(skb, offsetof(struct qca_dump_hdr, data0));
 
@@ -3200,29 +3205,29 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
 		skb_pull(skb, offsetof(struct qca_dump_hdr, data));
 	}
 
-	if (!btdata->qca_dump.ram_dump_size) {
+	if (!qca_dump_ptr->ram_dump_size) {
 		ret = -EINVAL;
 		bt_dev_err(hdev, "memdump is not active");
 		goto out;
 	}
 
-	if ((seqno > btdata->qca_dump.ram_dump_seqno + 1) && (seqno != QCA_LAST_SEQUENCE_NUM)) {
-		dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - btdata->qca_dump.ram_dump_seqno - 1);
+	if ((seqno > qca_dump_ptr->ram_dump_seqno + 1) && seqno != QCA_LAST_SEQUENCE_NUM) {
+		dump_size = QCA_MEMDUMP_PKT_SIZE * (seqno - qca_dump_ptr->ram_dump_seqno - 1);
 		hci_devcd_append_pattern(hdev, 0x0, dump_size);
 		bt_dev_err(hdev,
 			   "expected memdump seqno(%u) is not received(%u)\n",
-			   btdata->qca_dump.ram_dump_seqno, seqno);
-		btdata->qca_dump.ram_dump_seqno = seqno;
+			   qca_dump_ptr->ram_dump_seqno, seqno);
+		qca_dump_ptr->ram_dump_seqno = seqno;
 		kfree_skb(skb);
 		return ret;
 	}
 
 	hci_devcd_append(hdev, skb);
-	btdata->qca_dump.ram_dump_seqno++;
+	qca_dump_ptr->ram_dump_seqno++;
 	if (seqno == QCA_LAST_SEQUENCE_NUM) {
 		bt_dev_info(hdev,
 				"memdump done: pkts(%u), total(%u)\n",
-				btdata->qca_dump.ram_dump_seqno, btdata->qca_dump.ram_dump_size);
+				qca_dump_ptr->ram_dump_seqno, qca_dump_ptr->ram_dump_size);
 
 		hci_devcd_complete(hdev);
 		goto out;
@@ -3230,10 +3235,10 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
 	return ret;
 
 out:
-	if (btdata->qca_dump.ram_dump_size)
+	if (qca_dump_ptr->ram_dump_size)
 		usb_enable_autosuspend(udev);
-	btdata->qca_dump.ram_dump_size = 0;
-	btdata->qca_dump.ram_dump_seqno = 0;
+	qca_dump_ptr->ram_dump_size = 0;
+	qca_dump_ptr->ram_dump_seqno = 0;
 	clear_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
 
 	if (ret < 0)
@@ -3709,8 +3714,10 @@ static int btusb_setup_qca(struct hci_dev *hdev)
 		return err;
 
 	if (btdata->match_id->driver_info & BTUSB_QCA_WCN6855) {
-		btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
-		btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
+		struct btqca_data *btqca_data = hci_get_priv(hdev);
+
+		btqca_data->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
+		btqca_data->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
 	}
 
 	if (!(status & QCA_SYSCFG_UPDATED)) {
@@ -4174,6 +4181,9 @@ static int btusb_probe(struct usb_interface *intf,
 	} else if (id->driver_info & BTUSB_MEDIATEK) {
 		/* Allocate extra space for Mediatek device */
 		priv_size += sizeof(struct btmtk_data);
+	} else if (id->driver_info & BTUSB_QCA_WCN6855) {
+		/* Allocate extra space for QCA WCN6855 device */
+		priv_size += sizeof(struct btqca_data);
 	}
 
 	data->recv_acl = hci_recv_frame;
@@ -4316,8 +4326,10 @@ static int btusb_probe(struct usb_interface *intf,
 	}
 
 	if (id->driver_info & BTUSB_QCA_WCN6855) {
-		data->qca_dump.id_vendor = id->idVendor;
-		data->qca_dump.id_product = id->idProduct;
+		struct btqca_data *btqca_data = hci_get_priv(hdev);
+
+		btqca_data->qca_dump.id_vendor = id->idVendor;
+		btqca_data->qca_dump.id_product = id->idProduct;
 		data->recv_event = btusb_recv_evt_qca;
 		data->recv_acl = btusb_recv_acl_qca;
 		hci_devcd_register(hdev, btusb_coredump_qca, btusb_dump_hdr_qca, NULL);

-- 
2.34.1


^ permalink raw reply related

* [PATCH 06/13] Bluetooth: btusb: Fix BD_ADDR byte order in btusb_set_bdaddr_wcn6855()
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

For VSC 0xfc14 to set BD_ADDR, the endianness of the BDA parameter is
opposite to other HCI commands like HCI_Create_Connection, but
btusb_set_bdaddr_wcn6855() sends the address without swapping byte
order, resulting in a wrong BD_ADDR being set.

Fix by swapping the input address before issuing the command.

Fixes: b40f58b97386 ("Bluetooth: btusb: Add Qualcomm Bluetooth SoC WCN6855 support")
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6f965c313dff..e78277e24cd8 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3075,14 +3075,15 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
 static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
 				const bdaddr_t *bdaddr)
 {
+	bdaddr_t bdaddr_swapped;
 	struct sk_buff *skb;
-	u8 buf[6];
 	long ret;
 
-	memcpy(buf, bdaddr, sizeof(bdaddr_t));
+	baswap(&bdaddr_swapped, bdaddr);
 
-	skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf,
-				HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
+	skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(bdaddr_swapped),
+				&bdaddr_swapped, HCI_EV_CMD_COMPLETE,
+				HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
 		bt_dev_err(hdev, "Change address command failed (%ld)", ret);

-- 
2.34.1


^ permalink raw reply related

* [PATCH 04/13] Bluetooth: btusb: QCA: Do not populate devcoredump fields on ATH3012 or QCA_ROME
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

Devcoredump is disabled on ATH3012 or QCA_ROME, but btusb_setup_qca()
used by both unconditionally populates those two devcoredump fields.

Fix by populating devcoredump fields only for BTUSB_QCA_WCN6855 devices,
which are the only ones that enable devcoredump.

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6a90f012b226..184a87d1234c 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3708,8 +3708,10 @@ static int btusb_setup_qca(struct hci_dev *hdev)
 	if (err < 0)
 		return err;
 
-	btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
-	btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
+	if (btdata->match_id->driver_info & BTUSB_QCA_WCN6855) {
+		btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
+		btdata->qca_dump.controller_id = le32_to_cpu(ver.rom_version);
+	}
 
 	if (!(status & QCA_SYSCFG_UPDATED)) {
 		err = btusb_setup_qca_load_nvm(hdev, &ver, info);

-- 
2.34.1


^ permalink raw reply related

* [PATCH 03/13] Bluetooth: btusb: Record matched usb_device_id into btusb_data
From: Zijun Hu @ 2026-06-22 14:52 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Rocky Liao,
	Bartosz Golaszewski, Ben Young Tae Kim, Balakrishna Godavarthi,
	Matthias Kaehlcke
  Cc: Zijun Hu, linux-bluetooth, linux-kernel, Luiz Augusto von Dentz,
	linux-arm-msm, Zijun Hu
In-Reply-To: <20260622-bt_bugfix-v1-0-11f936d84e72@oss.qualcomm.com>

Add @match_id to btusb_data to record the matched usb_device_id
which will be used later.

Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
 drivers/bluetooth/btusb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index fa6a223d472d..6a90f012b226 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1012,6 +1012,7 @@ struct btusb_data {
 	bool usb_alt6_packet_flow;
 	int isoc_altsetting;
 	int suspend_count;
+	const struct usb_device_id *match_id;
 
 	int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
 	int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
@@ -4119,6 +4120,7 @@ static int btusb_probe(struct usb_interface *intf,
 	if (!data)
 		return -ENOMEM;
 
+	data->match_id = id;
 	err = usb_find_common_endpoints(intf->cur_altsetting, &data->bulk_rx_ep,
 					&data->bulk_tx_ep, &data->intr_ep, NULL);
 	if (err)

-- 
2.34.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox