Loading drivers/bluetooth/btusb.c +154 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 #define BTUSB_BCM_PATCHRAM 0x200 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ Loading Loading @@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, /* Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, Loading Loading @@ -1381,6 +1383,154 @@ static int btusb_setup_intel(struct hci_dev *hdev) return 0; } static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); struct usb_device *udev = data->udev; char fw_name[64]; const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; const struct hci_command_hdr *cmd; const u8 *cmd_param; u16 opcode; struct sk_buff *skb; struct hci_rp_read_local_version *ver; long ret; snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", udev->product ? udev->product : "BCM", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); return 0; } /* Reset */ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); goto done; } kfree_skb(skb); /* Read Local Version Info */ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", hdev->name); kfree_skb(skb); ret = -EIO; goto done; } ver = (struct hci_rp_read_local_version *) skb->data; BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); /* Start Download */ skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", hdev->name, ret); goto reset_fw; } kfree_skb(skb); /* 50 msec delay after Download Minidrv completes */ msleep(50); fw_ptr = fw->data; fw_size = fw->size; while (fw_size >= sizeof(*cmd)) { cmd = (struct hci_command_hdr *) fw_ptr; fw_ptr += sizeof(*cmd); fw_size -= sizeof(*cmd); if (fw_size < cmd->plen) { BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, fw_name); ret = -EINVAL; goto reset_fw; } cmd_param = fw_ptr; fw_ptr += cmd->plen; fw_size -= cmd->plen; opcode = le16_to_cpu(cmd->opcode); skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: patch command %04x failed (%ld)", hdev->name, opcode, ret); goto reset_fw; } kfree_skb(skb); } /* 250 msec delay after Launch Ram completes */ msleep(250); reset_fw: /* Reset */ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); goto done; } kfree_skb(skb); /* Read Local Version Info */ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", hdev->name); kfree_skb(skb); ret = -EIO; goto done; } ver = (struct hci_rp_read_local_version *) skb->data; BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); done: release_firmware(fw); return ret; } static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { Loading Loading @@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; if (id->driver_info & BTUSB_BCM_PATCHRAM) hdev->setup = btusb_setup_bcm_patchram; if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; Loading include/net/bluetooth/hci.h +21 −0 Original line number Diff line number Diff line Loading @@ -1054,6 +1054,17 @@ struct hci_cp_write_page_scan_activity { __le16 window; } __packed; #define HCI_OP_READ_TX_POWER 0x0c2d struct hci_cp_read_tx_power { __le16 handle; __u8 type; } __packed; struct hci_rp_read_tx_power { __u8 status; __le16 handle; __s8 tx_power; } __packed; #define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46 struct hci_rp_read_page_scan_type { __u8 status; Loading @@ -1064,6 +1075,16 @@ struct hci_rp_read_page_scan_type { #define PAGE_SCAN_TYPE_STANDARD 0x00 #define PAGE_SCAN_TYPE_INTERLACED 0x01 #define HCI_OP_READ_RSSI 0x1405 struct hci_cp_read_rssi { __le16 handle; } __packed; struct hci_rp_read_rssi { __u8 status; __le16 handle; __s8 rssi; } __packed; #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; Loading include/net/bluetooth/hci_core.h +11 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,10 @@ struct oob_data { /* Default LE RPA expiry time, 15 minutes */ #define HCI_DEFAULT_RPA_TIMEOUT (15 * 60) /* Default min/max age of connection information (1s/3s) */ #define DEFAULT_CONN_INFO_MIN_AGE 1000 #define DEFAULT_CONN_INFO_MAX_AGE 3000 struct amp_assoc { __u16 len; __u16 offset; Loading Loading @@ -200,6 +204,8 @@ struct hci_dev { __u16 le_conn_min_interval; __u16 le_conn_max_interval; __u16 discov_interleaved_timeout; __u16 conn_info_min_age; __u16 conn_info_max_age; __u8 ssp_debug_mode; __u16 devid_source; Loading Loading @@ -374,8 +380,13 @@ struct hci_conn { __u16 setting; __u16 le_conn_min_interval; __u16 le_conn_max_interval; __s8 rssi; __s8 tx_power; __s8 max_tx_power; unsigned long flags; unsigned long conn_info_timestamp; __u8 remote_cap; __u8 remote_auth; __u8 remote_id; Loading include/net/bluetooth/mgmt.h +15 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,9 @@ struct mgmt_cp_load_link_keys { } __packed; #define MGMT_LOAD_LINK_KEYS_SIZE 3 #define MGMT_LTK_UNAUTHENTICATED 0x00 #define MGMT_LTK_AUTHENTICATED 0x01 struct mgmt_ltk_info { struct mgmt_addr_info addr; __u8 type; Loading Loading @@ -409,6 +412,18 @@ struct mgmt_cp_load_irks { } __packed; #define MGMT_LOAD_IRKS_SIZE 2 #define MGMT_OP_GET_CONN_INFO 0x0031 struct mgmt_cp_get_conn_info { struct mgmt_addr_info addr; } __packed; #define MGMT_GET_CONN_INFO_SIZE MGMT_ADDR_INFO_SIZE struct mgmt_rp_get_conn_info { struct mgmt_addr_info addr; __s8 rssi; __s8 tx_power; __s8 max_tx_power; } __packed; #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; Loading include/net/bluetooth/rfcomm.h +3 −3 Original line number Diff line number Diff line Loading @@ -173,7 +173,7 @@ struct rfcomm_dlc { struct sk_buff_head tx_queue; struct timer_list timer; spinlock_t lock; struct mutex lock; unsigned long state; unsigned long flags; atomic_t refcnt; Loading Loading @@ -244,8 +244,8 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); #define rfcomm_dlc_lock(d) spin_lock(&d->lock) #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) #define rfcomm_dlc_lock(d) mutex_lock(&d->lock) #define rfcomm_dlc_unlock(d) mutex_unlock(&d->lock) static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) { Loading Loading
drivers/bluetooth/btusb.c +154 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 #define BTUSB_BCM_PATCHRAM 0x200 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ Loading Loading @@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) }, /* Broadcom devices with vendor specific id */ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, Loading Loading @@ -1381,6 +1383,154 @@ static int btusb_setup_intel(struct hci_dev *hdev) return 0; } static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); struct usb_device *udev = data->udev; char fw_name[64]; const struct firmware *fw; const u8 *fw_ptr; size_t fw_size; const struct hci_command_hdr *cmd; const u8 *cmd_param; u16 opcode; struct sk_buff *skb; struct hci_rp_read_local_version *ver; long ret; snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", udev->product ? udev->product : "BCM", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); return 0; } /* Reset */ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); goto done; } kfree_skb(skb); /* Read Local Version Info */ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", hdev->name); kfree_skb(skb); ret = -EIO; goto done; } ver = (struct hci_rp_read_local_version *) skb->data; BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); /* Start Download */ skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", hdev->name, ret); goto reset_fw; } kfree_skb(skb); /* 50 msec delay after Download Minidrv completes */ msleep(50); fw_ptr = fw->data; fw_size = fw->size; while (fw_size >= sizeof(*cmd)) { cmd = (struct hci_command_hdr *) fw_ptr; fw_ptr += sizeof(*cmd); fw_size -= sizeof(*cmd); if (fw_size < cmd->plen) { BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, fw_name); ret = -EINVAL; goto reset_fw; } cmd_param = fw_ptr; fw_ptr += cmd->plen; fw_size -= cmd->plen; opcode = le16_to_cpu(cmd->opcode); skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: patch command %04x failed (%ld)", hdev->name, opcode, ret); goto reset_fw; } kfree_skb(skb); } /* 250 msec delay after Launch Ram completes */ msleep(250); reset_fw: /* Reset */ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); goto done; } kfree_skb(skb); /* Read Local Version Info */ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", hdev->name); kfree_skb(skb); ret = -EIO; goto done; } ver = (struct hci_rp_read_local_version *) skb->data; BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); done: release_firmware(fw); return ret; } static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { Loading Loading @@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; if (id->driver_info & BTUSB_BCM_PATCHRAM) hdev->setup = btusb_setup_bcm_patchram; if (id->driver_info & BTUSB_INTEL) hdev->setup = btusb_setup_intel; Loading
include/net/bluetooth/hci.h +21 −0 Original line number Diff line number Diff line Loading @@ -1054,6 +1054,17 @@ struct hci_cp_write_page_scan_activity { __le16 window; } __packed; #define HCI_OP_READ_TX_POWER 0x0c2d struct hci_cp_read_tx_power { __le16 handle; __u8 type; } __packed; struct hci_rp_read_tx_power { __u8 status; __le16 handle; __s8 tx_power; } __packed; #define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46 struct hci_rp_read_page_scan_type { __u8 status; Loading @@ -1064,6 +1075,16 @@ struct hci_rp_read_page_scan_type { #define PAGE_SCAN_TYPE_STANDARD 0x00 #define PAGE_SCAN_TYPE_INTERLACED 0x01 #define HCI_OP_READ_RSSI 0x1405 struct hci_cp_read_rssi { __le16 handle; } __packed; struct hci_rp_read_rssi { __u8 status; __le16 handle; __s8 rssi; } __packed; #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; Loading
include/net/bluetooth/hci_core.h +11 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,10 @@ struct oob_data { /* Default LE RPA expiry time, 15 minutes */ #define HCI_DEFAULT_RPA_TIMEOUT (15 * 60) /* Default min/max age of connection information (1s/3s) */ #define DEFAULT_CONN_INFO_MIN_AGE 1000 #define DEFAULT_CONN_INFO_MAX_AGE 3000 struct amp_assoc { __u16 len; __u16 offset; Loading Loading @@ -200,6 +204,8 @@ struct hci_dev { __u16 le_conn_min_interval; __u16 le_conn_max_interval; __u16 discov_interleaved_timeout; __u16 conn_info_min_age; __u16 conn_info_max_age; __u8 ssp_debug_mode; __u16 devid_source; Loading Loading @@ -374,8 +380,13 @@ struct hci_conn { __u16 setting; __u16 le_conn_min_interval; __u16 le_conn_max_interval; __s8 rssi; __s8 tx_power; __s8 max_tx_power; unsigned long flags; unsigned long conn_info_timestamp; __u8 remote_cap; __u8 remote_auth; __u8 remote_id; Loading
include/net/bluetooth/mgmt.h +15 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,9 @@ struct mgmt_cp_load_link_keys { } __packed; #define MGMT_LOAD_LINK_KEYS_SIZE 3 #define MGMT_LTK_UNAUTHENTICATED 0x00 #define MGMT_LTK_AUTHENTICATED 0x01 struct mgmt_ltk_info { struct mgmt_addr_info addr; __u8 type; Loading Loading @@ -409,6 +412,18 @@ struct mgmt_cp_load_irks { } __packed; #define MGMT_LOAD_IRKS_SIZE 2 #define MGMT_OP_GET_CONN_INFO 0x0031 struct mgmt_cp_get_conn_info { struct mgmt_addr_info addr; } __packed; #define MGMT_GET_CONN_INFO_SIZE MGMT_ADDR_INFO_SIZE struct mgmt_rp_get_conn_info { struct mgmt_addr_info addr; __s8 rssi; __s8 tx_power; __s8 max_tx_power; } __packed; #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; Loading
include/net/bluetooth/rfcomm.h +3 −3 Original line number Diff line number Diff line Loading @@ -173,7 +173,7 @@ struct rfcomm_dlc { struct sk_buff_head tx_queue; struct timer_list timer; spinlock_t lock; struct mutex lock; unsigned long state; unsigned long flags; atomic_t refcnt; Loading Loading @@ -244,8 +244,8 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); void rfcomm_dlc_accept(struct rfcomm_dlc *d); struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel); #define rfcomm_dlc_lock(d) spin_lock(&d->lock) #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) #define rfcomm_dlc_lock(d) mutex_lock(&d->lock) #define rfcomm_dlc_unlock(d) mutex_unlock(&d->lock) static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) { Loading