Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46beb6ea authored by Jian-Hong Pan's avatar Jian-Hong Pan Committed by Greg Kroah-Hartman
Browse files

Bluetooth: btrtl: HCI reset on close for Realtek BT chip

[ Upstream commit 7af3f558aca74f2ee47b173f1c27f6bb9a5b5561 ]

Realtek RTL8822BE BT chip on ASUS X420FA cannot be turned on correctly
after on-off several times. Bluetooth daemon sets BT mode failed when
this issue happens. Scanning must be active while turning off for this
bug to be hit.

bluetoothd[1576]: Failed to set mode: Failed (0x03)

If BT is turned off, then turned on again, it works correctly again.

According to the vendor driver, the HCI_QUIRK_RESET_ON_CLOSE flag is set
during probing. So, this patch makes Realtek's BT reset on close to fix
this issue.

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


Signed-off-by: default avatarJian-Hong Pan <jian-hong@endlessm.com>
Reviewed-by: default avatarDaniel Drake <drake@endlessm.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 8ffd7ba9
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -639,6 +639,26 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
}
EXPORT_SYMBOL_GPL(btrtl_setup_realtek);

int btrtl_shutdown_realtek(struct hci_dev *hdev)
{
	struct sk_buff *skb;
	int ret;

	/* According to the vendor driver, BT must be reset on close to avoid
	 * firmware crash.
	 */
	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		bt_dev_err(hdev, "HCI reset during shutdown failed");
		return ret;
	}
	kfree_skb(skb);

	return 0;
}
EXPORT_SYMBOL_GPL(btrtl_shutdown_realtek);

static unsigned int btrtl_convert_baudrate(u32 device_baudrate)
{
	switch (device_baudrate) {
+6 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ void btrtl_free(struct btrtl_device_info *btrtl_dev);
int btrtl_download_firmware(struct hci_dev *hdev,
			    struct btrtl_device_info *btrtl_dev);
int btrtl_setup_realtek(struct hci_dev *hdev);
int btrtl_shutdown_realtek(struct hci_dev *hdev);
int btrtl_get_uart_settings(struct hci_dev *hdev,
			    struct btrtl_device_info *btrtl_dev,
			    unsigned int *controller_baudrate,
@@ -93,6 +94,11 @@ static inline int btrtl_setup_realtek(struct hci_dev *hdev)
	return -EOPNOTSUPP;
}

static inline int btrtl_shutdown_realtek(struct hci_dev *hdev)
{
	return -EOPNOTSUPP;
}

static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
					  struct btrtl_device_info *btrtl_dev,
					  unsigned int *controller_baudrate,
+1 −0
Original line number Diff line number Diff line
@@ -3128,6 +3128,7 @@ static int btusb_probe(struct usb_interface *intf,
#ifdef CONFIG_BT_HCIBTUSB_RTL
	if (id->driver_info & BTUSB_REALTEK) {
		hdev->setup = btrtl_setup_realtek;
		hdev->shutdown = btrtl_shutdown_realtek;

		/* Realtek devices lose their updated firmware over suspend,
		 * but the USB hub doesn't notice any status change.