Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Enable erroneous data reporting if WBS is supported

This change introduces a wide band speech setting which allows higher
level clients to query the local controller support for wide band speech
as well as set the setting state when the radio is powered off.
Internally, this setting controls if erroneous data reporting is enabled
on the controller.

Signed-off-by: Alain Michaud <alainm@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Alain Michaud and committed by
Marcel Holtmann
00bce3fb 55cee73e

+145 -5
+1 -1
drivers/bluetooth/btusb.c
··· 3868 3868 data->isoc = NULL; 3869 3869 3870 3870 if (id->driver_info & BTUSB_WIDEBAND_SPEECH) 3871 - set_bit(HCI_QUIRK_WIDE_BAND_SPEECH_SUPPORTED, &hdev->quirks); 3871 + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); 3872 3872 3873 3873 if (id->driver_info & BTUSB_DIGIANSWER) { 3874 3874 data->cmdreq_type = USB_TYPE_VENDOR;
+15 -1
include/net/bluetooth/hci.h
··· 213 213 * 214 214 * This quirk must be set before hci_register_dev is called. 215 215 */ 216 - HCI_QUIRK_WIDE_BAND_SPEECH_SUPPORTED, 216 + HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, 217 217 }; 218 218 219 219 /* HCI device flags */ ··· 286 286 HCI_FAST_CONNECTABLE, 287 287 HCI_BREDR_ENABLED, 288 288 HCI_LE_SCAN_INTERRUPTED, 289 + HCI_WIDEBAND_SPEECH_ENABLED, 289 290 290 291 HCI_DUT_MODE, 291 292 HCI_VENDOR_DIAG, ··· 1094 1093 struct hci_rp_read_inq_rsp_tx_power { 1095 1094 __u8 status; 1096 1095 __s8 tx_power; 1096 + } __packed; 1097 + 1098 + #define HCI_OP_READ_DEF_ERR_DATA_REPORTING 0x0c5a 1099 + #define ERR_DATA_REPORTING_DISABLED 0x00 1100 + #define ERR_DATA_REPORTING_ENABLED 0x01 1101 + struct hci_rp_read_def_err_data_reporting { 1102 + __u8 status; 1103 + __u8 err_data_reporting; 1104 + } __packed; 1105 + 1106 + #define HCI_OP_WRITE_DEF_ERR_DATA_REPORTING 0x0c5b 1107 + struct hci_cp_write_def_err_data_reporting { 1108 + __u8 err_data_reporting; 1097 1109 } __packed; 1098 1110 1099 1111 #define HCI_OP_SET_EVENT_MASK_PAGE_2 0x0c63
+1
include/net/bluetooth/hci_core.h
··· 260 260 __u8 stored_num_keys; 261 261 __u8 io_capability; 262 262 __s8 inq_tx_power; 263 + __u8 err_data_reporting; 263 264 __u16 page_scan_interval; 264 265 __u16 page_scan_window; 265 266 __u8 page_scan_type;
+3 -1
include/net/bluetooth/mgmt.h
··· 102 102 #define MGMT_SETTING_CONFIGURATION 0x00004000 103 103 #define MGMT_SETTING_STATIC_ADDRESS 0x00008000 104 104 #define MGMT_SETTING_PHY_CONFIGURATION 0x00010000 105 - #define MGMT_SETTING_WIDE_BAND_SPEECH 0x00020000 105 + #define MGMT_SETTING_WIDEBAND_SPEECH 0x00020000 106 106 107 107 #define MGMT_OP_READ_INFO 0x0004 108 108 #define MGMT_READ_INFO_SIZE 0 ··· 671 671 struct mgmt_blocked_key_info keys[0]; 672 672 } __packed; 673 673 #define MGMT_OP_SET_BLOCKED_KEYS_SIZE 2 674 + 675 + #define MGMT_OP_SET_WIDEBAND_SPEECH 0x0047 674 676 675 677 #define MGMT_EV_CMD_COMPLETE 0x0001 676 678 struct mgmt_ev_cmd_complete {
+23
net/bluetooth/hci_core.c
··· 603 603 if (hdev->commands[8] & 0x01) 604 604 hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL); 605 605 606 + if (hdev->commands[18] & 0x02) 607 + hci_req_add(req, HCI_OP_READ_DEF_ERR_DATA_REPORTING, 0, NULL); 608 + 606 609 /* Some older Broadcom based Bluetooth 1.2 controllers do not 607 610 * support the Read Page Scan Type command. Check support for 608 611 * this command in the bit mask of supported commands. ··· 839 836 840 837 hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT, 841 838 sizeof(support), &support); 839 + } 840 + 841 + /* Set erroneous data reporting if supported to the wideband speech 842 + * setting value 843 + */ 844 + if (hdev->commands[18] & 0x04) { 845 + bool enabled = hci_dev_test_flag(hdev, 846 + HCI_WIDEBAND_SPEECH_ENABLED); 847 + 848 + if (enabled != 849 + (hdev->err_data_reporting == ERR_DATA_REPORTING_ENABLED)) { 850 + struct hci_cp_write_def_err_data_reporting cp; 851 + 852 + cp.err_data_reporting = enabled ? 853 + ERR_DATA_REPORTING_ENABLED : 854 + ERR_DATA_REPORTING_DISABLED; 855 + 856 + hci_req_add(req, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING, 857 + sizeof(cp), &cp); 858 + } 842 859 } 843 860 844 861 /* Set Suggested Default Data Length to maximum if supported */
+39
net/bluetooth/hci_event.c
··· 901 901 hdev->inq_tx_power = rp->tx_power; 902 902 } 903 903 904 + static void hci_cc_read_def_err_data_reporting(struct hci_dev *hdev, 905 + struct sk_buff *skb) 906 + { 907 + struct hci_rp_read_def_err_data_reporting *rp = (void *)skb->data; 908 + 909 + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); 910 + 911 + if (rp->status) 912 + return; 913 + 914 + hdev->err_data_reporting = rp->err_data_reporting; 915 + } 916 + 917 + static void hci_cc_write_def_err_data_reporting(struct hci_dev *hdev, 918 + struct sk_buff *skb) 919 + { 920 + __u8 status = *((__u8 *)skb->data); 921 + struct hci_cp_write_def_err_data_reporting *cp; 922 + 923 + BT_DBG("%s status 0x%2.2x", hdev->name, status); 924 + 925 + if (status) 926 + return; 927 + 928 + cp = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING); 929 + if (!cp) 930 + return; 931 + 932 + hdev->err_data_reporting = cp->err_data_reporting; 933 + } 934 + 904 935 static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) 905 936 { 906 937 struct hci_rp_pin_code_reply *rp = (void *) skb->data; ··· 3331 3300 3332 3301 case HCI_OP_READ_INQ_RSP_TX_POWER: 3333 3302 hci_cc_read_inq_rsp_tx_power(hdev, skb); 3303 + break; 3304 + 3305 + case HCI_OP_READ_DEF_ERR_DATA_REPORTING: 3306 + hci_cc_read_def_err_data_reporting(hdev, skb); 3307 + break; 3308 + 3309 + case HCI_OP_WRITE_DEF_ERR_DATA_REPORTING: 3310 + hci_cc_write_def_err_data_reporting(hdev, skb); 3334 3311 break; 3335 3312 3336 3313 case HCI_OP_PIN_CODE_REPLY:
+63 -2
net/bluetooth/mgmt.c
··· 107 107 MGMT_OP_READ_EXT_INFO, 108 108 MGMT_OP_SET_APPEARANCE, 109 109 MGMT_OP_SET_BLOCKED_KEYS, 110 + MGMT_OP_SET_WIDEBAND_SPEECH, 110 111 }; 111 112 112 113 static const u16 mgmt_events[] = { ··· 764 763 if (lmp_sc_capable(hdev)) 765 764 settings |= MGMT_SETTING_SECURE_CONN; 766 765 767 - if (test_bit(HCI_QUIRK_WIDE_BAND_SPEECH_SUPPORTED, 766 + if (test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, 768 767 &hdev->quirks)) 769 - settings |= MGMT_SETTING_WIDE_BAND_SPEECH; 768 + settings |= MGMT_SETTING_WIDEBAND_SPEECH; 770 769 } 771 770 772 771 if (lmp_le_capable(hdev)) { ··· 850 849 if (bacmp(&hdev->static_addr, BDADDR_ANY)) 851 850 settings |= MGMT_SETTING_STATIC_ADDRESS; 852 851 } 852 + 853 + if (hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED)) 854 + settings |= MGMT_SETTING_WIDEBAND_SPEECH; 853 855 854 856 return settings; 855 857 } ··· 3595 3591 3596 3592 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_BLOCKED_KEYS, 3597 3593 err, NULL, 0); 3594 + } 3595 + 3596 + static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev, 3597 + void *data, u16 len) 3598 + { 3599 + struct mgmt_mode *cp = data; 3600 + int err; 3601 + bool changed = false; 3602 + 3603 + BT_DBG("request for %s", hdev->name); 3604 + 3605 + if (!test_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks)) 3606 + return mgmt_cmd_status(sk, hdev->id, 3607 + MGMT_OP_SET_WIDEBAND_SPEECH, 3608 + MGMT_STATUS_NOT_SUPPORTED); 3609 + 3610 + if (cp->val != 0x00 && cp->val != 0x01) 3611 + return mgmt_cmd_status(sk, hdev->id, 3612 + MGMT_OP_SET_WIDEBAND_SPEECH, 3613 + MGMT_STATUS_INVALID_PARAMS); 3614 + 3615 + hci_dev_lock(hdev); 3616 + 3617 + if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) { 3618 + err = mgmt_cmd_status(sk, hdev->id, 3619 + MGMT_OP_SET_WIDEBAND_SPEECH, 3620 + MGMT_STATUS_BUSY); 3621 + goto unlock; 3622 + } 3623 + 3624 + if (hdev_is_powered(hdev) && 3625 + !!cp->val != hci_dev_test_flag(hdev, 3626 + HCI_WIDEBAND_SPEECH_ENABLED)) { 3627 + err = mgmt_cmd_status(sk, hdev->id, 3628 + MGMT_OP_SET_WIDEBAND_SPEECH, 3629 + MGMT_STATUS_REJECTED); 3630 + goto unlock; 3631 + } 3632 + 3633 + if (cp->val) 3634 + changed = !hci_dev_test_and_set_flag(hdev, 3635 + HCI_WIDEBAND_SPEECH_ENABLED); 3636 + else 3637 + changed = hci_dev_test_and_clear_flag(hdev, 3638 + HCI_WIDEBAND_SPEECH_ENABLED); 3639 + 3640 + err = send_settings_rsp(sk, MGMT_OP_SET_WIDEBAND_SPEECH, hdev); 3641 + if (err < 0) 3642 + goto unlock; 3643 + 3644 + if (changed) 3645 + err = new_settings(hdev, sk); 3646 + 3647 + unlock: 3648 + hci_dev_unlock(hdev); 3649 + return err; 3598 3650 } 3599 3651 3600 3652 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, ··· 7054 6994 { set_phy_configuration, MGMT_SET_PHY_CONFIGURATION_SIZE }, 7055 6995 { set_blocked_keys, MGMT_OP_SET_BLOCKED_KEYS_SIZE, 7056 6996 HCI_MGMT_VAR_LEN }, 6997 + { set_wideband_speech, MGMT_SETTING_SIZE }, 7057 6998 }; 7058 6999 7059 7000 void mgmt_index_added(struct hci_dev *hdev)