Skip to content

Commit

Permalink
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/bluetooth/bluetooth-next

Conflicts:
	drivers/bluetooth/btusb.c
  • Loading branch information
John W. Linville committed May 29, 2014
2 parents 737be10 + d7b2545 commit a5eb1ae
Show file tree
Hide file tree
Showing 13 changed files with 653 additions and 124 deletions.
155 changes: 154 additions & 1 deletion drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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) },
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;

Expand Down
21 changes: 21 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions include/net/bluetooth/mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions include/net/bluetooth/rfcomm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>

#include "smp.h"
#include "a2mp.h"
Expand Down Expand Up @@ -407,6 +408,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->io_capability = hdev->io_capability;
conn->remote_auth = 0xff;
conn->key_type = 0xff;
conn->tx_power = HCI_TX_POWER_INVALID;
conn->max_tx_power = HCI_TX_POWER_INVALID;

set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
Expand Down
Loading

0 comments on commit a5eb1ae

Please sign in to comment.