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

Commit a5eb1aeb authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Conflicts:
	drivers/bluetooth/btusb.c
parents 737be10d d7b25450
Loading
Loading
Loading
Loading
+154 −1
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_WRONG_SCO_MTU	0x40
#define BTUSB_WRONG_SCO_MTU	0x40
#define BTUSB_ATH3012		0x80
#define BTUSB_ATH3012		0x80
#define BTUSB_INTEL		0x100
#define BTUSB_INTEL		0x100
#define BTUSB_BCM_PATCHRAM	0x200


static const struct usb_device_id btusb_table[] = {
static const struct usb_device_id btusb_table[] = {
	/* Generic Bluetooth USB device */
	/* Generic Bluetooth USB device */
@@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = {
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },


	/* Broadcom devices with vendor specific id */
	/* 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 */
	/* Belkin F8065bf - Broadcom based */
	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
@@ -1381,6 +1383,154 @@ static int btusb_setup_intel(struct hci_dev *hdev)
	return 0;
	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,
static int btusb_probe(struct usb_interface *intf,
				const struct usb_device_id *id)
				const struct usb_device_id *id)
{
{
@@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf,
	if (id->driver_info & BTUSB_BCM92035)
	if (id->driver_info & BTUSB_BCM92035)
		hdev->setup = btusb_setup_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)
	if (id->driver_info & BTUSB_INTEL)
		hdev->setup = btusb_setup_intel;
		hdev->setup = btusb_setup_intel;


+21 −0
Original line number Original line Diff line number Diff line
@@ -1054,6 +1054,17 @@ struct hci_cp_write_page_scan_activity {
	__le16   window;
	__le16   window;
} __packed;
} __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
#define HCI_OP_READ_PAGE_SCAN_TYPE	0x0c46
struct hci_rp_read_page_scan_type {
struct hci_rp_read_page_scan_type {
	__u8     status;
	__u8     status;
@@ -1064,6 +1075,16 @@ struct hci_rp_read_page_scan_type {
	#define PAGE_SCAN_TYPE_STANDARD		0x00
	#define PAGE_SCAN_TYPE_STANDARD		0x00
	#define PAGE_SCAN_TYPE_INTERLACED	0x01
	#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
#define HCI_OP_READ_LOCAL_AMP_INFO	0x1409
struct hci_rp_read_local_amp_info {
struct hci_rp_read_local_amp_info {
	__u8     status;
	__u8     status;
+11 −0
Original line number Original line Diff line number Diff line
@@ -145,6 +145,10 @@ struct oob_data {
/* Default LE RPA expiry time, 15 minutes */
/* Default LE RPA expiry time, 15 minutes */
#define HCI_DEFAULT_RPA_TIMEOUT		(15 * 60)
#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 {
struct amp_assoc {
	__u16	len;
	__u16	len;
	__u16	offset;
	__u16	offset;
@@ -200,6 +204,8 @@ struct hci_dev {
	__u16		le_conn_min_interval;
	__u16		le_conn_min_interval;
	__u16		le_conn_max_interval;
	__u16		le_conn_max_interval;
	__u16		discov_interleaved_timeout;
	__u16		discov_interleaved_timeout;
	__u16		conn_info_min_age;
	__u16		conn_info_max_age;
	__u8		ssp_debug_mode;
	__u8		ssp_debug_mode;


	__u16		devid_source;
	__u16		devid_source;
@@ -374,8 +380,13 @@ struct hci_conn {
	__u16		setting;
	__u16		setting;
	__u16		le_conn_min_interval;
	__u16		le_conn_min_interval;
	__u16		le_conn_max_interval;
	__u16		le_conn_max_interval;
	__s8		rssi;
	__s8		tx_power;
	__s8		max_tx_power;
	unsigned long	flags;
	unsigned long	flags;


	unsigned long	conn_info_timestamp;

	__u8		remote_cap;
	__u8		remote_cap;
	__u8		remote_auth;
	__u8		remote_auth;
	__u8		remote_id;
	__u8		remote_id;
+15 −0
Original line number Original line Diff line number Diff line
@@ -181,6 +181,9 @@ struct mgmt_cp_load_link_keys {
} __packed;
} __packed;
#define MGMT_LOAD_LINK_KEYS_SIZE	3
#define MGMT_LOAD_LINK_KEYS_SIZE	3


#define MGMT_LTK_UNAUTHENTICATED	0x00
#define MGMT_LTK_AUTHENTICATED		0x01

struct mgmt_ltk_info {
struct mgmt_ltk_info {
	struct mgmt_addr_info addr;
	struct mgmt_addr_info addr;
	__u8	type;
	__u8	type;
@@ -409,6 +412,18 @@ struct mgmt_cp_load_irks {
} __packed;
} __packed;
#define MGMT_LOAD_IRKS_SIZE		2
#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
#define MGMT_EV_CMD_COMPLETE		0x0001
struct mgmt_ev_cmd_complete {
struct mgmt_ev_cmd_complete {
	__le16	opcode;
	__le16	opcode;
+3 −3
Original line number Original line Diff line number Diff line
@@ -173,7 +173,7 @@ struct rfcomm_dlc {
	struct sk_buff_head   tx_queue;
	struct sk_buff_head   tx_queue;
	struct timer_list     timer;
	struct timer_list     timer;


	spinlock_t    lock;
	struct mutex  lock;
	unsigned long state;
	unsigned long state;
	unsigned long flags;
	unsigned long flags;
	atomic_t      refcnt;
	atomic_t      refcnt;
@@ -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);
void rfcomm_dlc_accept(struct rfcomm_dlc *d);
struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel);
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_lock(d)     mutex_lock(&d->lock)
#define rfcomm_dlc_unlock(d)   spin_unlock(&d->lock)
#define rfcomm_dlc_unlock(d)   mutex_unlock(&d->lock)


static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
{
{
Loading