diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
| -rw-r--r-- | drivers/bluetooth/btusb.c | 221 | 
1 files changed, 192 insertions, 29 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 6250fc2fb93a..292c38e8aa17 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -30,9 +30,6 @@  #define VERSION "0.6" -static bool ignore_dga; -static bool ignore_csr; -static bool ignore_sniffer;  static bool disable_scofix;  static bool force_scofix; @@ -49,7 +46,9 @@ 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 +#define BTUSB_INTEL_BOOT	0x200 +#define BTUSB_BCM_PATCHRAM	0x400 +#define BTUSB_MARVELL		0x800  static const struct usb_device_id btusb_table[] = {  	/* Generic Bluetooth USB device */ @@ -115,12 +114,19 @@ static const struct usb_device_id btusb_table[] = {  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),  	  .driver_info = BTUSB_BCM_PATCHRAM }, +	/* ASUSTek Computer - Broadcom based */ +	{ USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) }, +  	/* Belkin F8065bf - Broadcom based */  	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },  	/* IMC Networks - Broadcom based */  	{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, +	/* Intel Bluetooth USB Bootloader (RAM module) */ +	{ USB_DEVICE(0x8087, 0x0a5a), +	  .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, +  	{ }	/* Terminating entry */  }; @@ -175,6 +181,7 @@ static const struct usb_device_id blacklist_table[] = {  	{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },  	{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, +	{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },  	/* Atheros AR5BBU12 with sflash firmware */  	{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -228,15 +235,21 @@ static const struct usb_device_id blacklist_table[] = {  	{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },  	/* CSR BlueCore Bluetooth Sniffer */ -	{ USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER }, +	{ USB_DEVICE(0x0a12, 0x0002), +	  .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },  	/* Frontline ComProbe Bluetooth Sniffer */ -	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER }, +	{ USB_DEVICE(0x16d3, 0x0002), +	  .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },  	/* Intel Bluetooth device */  	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },  	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, +	/* Marvell device */ +	{ USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, +	{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, +  	{ }	/* Terminating entry */  }; @@ -1182,6 +1195,51 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,  	return 0;  } +#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) + +static int btusb_check_bdaddr_intel(struct hci_dev *hdev) +{ +	struct sk_buff *skb; +	struct hci_rp_read_bd_addr *rp; + +	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, +			     HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		BT_ERR("%s reading Intel device address failed (%ld)", +		       hdev->name, PTR_ERR(skb)); +		return PTR_ERR(skb); +	} + +	if (skb->len != sizeof(*rp)) { +		BT_ERR("%s Intel device address length mismatch", hdev->name); +		kfree_skb(skb); +		return -EIO; +	} + +	rp = (struct hci_rp_read_bd_addr *) skb->data; +	if (rp->status) { +		BT_ERR("%s Intel device address result failed (%02x)", +		       hdev->name, rp->status); +		kfree_skb(skb); +		return -bt_to_errno(rp->status); +	} + +	/* For some Intel based controllers, the default Bluetooth device +	 * address 00:03:19:9E:8B:00 can be found. These controllers are +	 * fully operational, but have the danger of duplicate addresses +	 * and that in turn can cause problems with Bluetooth operation. +	 */ +	if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) { +		BT_ERR("%s found Intel default device address (%pMR)", +		       hdev->name, &rp->bdaddr); +		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); +	} + +	kfree_skb(skb); + +	return 0; +} +  static int btusb_setup_intel(struct hci_dev *hdev)  {  	struct sk_buff *skb; @@ -1254,6 +1312,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)  		BT_INFO("%s: Intel device is already patched. patch num: %02x",  			hdev->name, ver->fw_patch_num);  		kfree_skb(skb); +		btusb_check_bdaddr_intel(hdev);  		return 0;  	} @@ -1266,6 +1325,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)  	fw = btusb_setup_intel_get_fw(hdev, ver);  	if (!fw) {  		kfree_skb(skb); +		btusb_check_bdaddr_intel(hdev);  		return 0;  	}  	fw_ptr = fw->data; @@ -1345,6 +1405,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)  	BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",  		hdev->name); +	btusb_check_bdaddr_intel(hdev);  	return 0;  exit_mfg_disable: @@ -1359,6 +1420,8 @@ exit_mfg_disable:  	kfree_skb(skb);  	BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); + +	btusb_check_bdaddr_intel(hdev);  	return 0;  exit_mfg_deactivate: @@ -1379,9 +1442,52 @@ exit_mfg_deactivate:  	BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",  		hdev->name); +	btusb_check_bdaddr_intel(hdev); +	return 0; +} + +static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ +	struct sk_buff *skb; +	long ret; + +	skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		BT_ERR("%s: changing Intel device address failed (%ld)", +			hdev->name, ret); +		return ret; +	} +	kfree_skb(skb); +  	return 0;  } +static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, +				    const bdaddr_t *bdaddr) +{ +	struct sk_buff *skb; +	u8 buf[8]; +	long ret; + +	buf[0] = 0xfe; +	buf[1] = sizeof(bdaddr_t); +	memcpy(buf + 2, bdaddr, sizeof(bdaddr_t)); + +	skb = __hci_cmd_sync(hdev, 0xfc22, sizeof(buf), buf, HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		BT_ERR("%s: changing Marvell device address failed (%ld)", +		       hdev->name, ret); +		return ret; +	} +	kfree_skb(skb); + +	return 0; +} + +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) +  static int btusb_setup_bcm_patchram(struct hci_dev *hdev)  {  	struct btusb_data *data = hci_get_drvdata(hdev); @@ -1395,6 +1501,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)  	u16 opcode;  	struct sk_buff *skb;  	struct hci_rp_read_local_version *ver; +	struct hci_rp_read_bd_addr *bda;  	long ret;  	snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", @@ -1404,8 +1511,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)  	ret = request_firmware(&fw, fw_name, &hdev->dev);  	if (ret < 0) { -		BT_INFO("%s: BCM: patch %s not found", hdev->name, -			fw_name); +		BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name);  		return 0;  	} @@ -1524,12 +1630,67 @@ reset_fw:  		ver->lmp_ver, ver->lmp_subver);  	kfree_skb(skb); +	/* Read BD Address */ +	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, +			     HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", +			hdev->name, ret); +		goto done; +	} + +	if (skb->len != sizeof(*bda)) { +		BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", +			hdev->name); +		kfree_skb(skb); +		ret = -EIO; +		goto done; +	} + +	bda = (struct hci_rp_read_bd_addr *) skb->data; +	if (bda->status) { +		BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", +		       hdev->name, bda->status); +		kfree_skb(skb); +		ret = -bt_to_errno(bda->status); +		goto done; +	} + +	/* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller +	 * with no configured address. +	 */ +	if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { +		BT_INFO("%s: BCM: using default device address (%pMR)", +			hdev->name, &bda->bdaddr); +		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); +	} + +	kfree_skb(skb); +  done:  	release_firmware(fw);  	return ret;  } +static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ +	struct sk_buff *skb; +	long ret; + +	skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		BT_ERR("%s: BCM: Change address command failed (%ld)", +			hdev->name, ret); +		return ret; +	} +	kfree_skb(skb); + +	return 0; +} +  static int btusb_probe(struct usb_interface *intf,  				const struct usb_device_id *id)  { @@ -1554,15 +1715,6 @@ static int btusb_probe(struct usb_interface *intf,  	if (id->driver_info == BTUSB_IGNORE)  		return -ENODEV; -	if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER) -		return -ENODEV; - -	if (ignore_csr && id->driver_info & BTUSB_CSR) -		return -ENODEV; - -	if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) -		return -ENODEV; -  	if (id->driver_info & BTUSB_ATH3012) {  		struct usb_device *udev = interface_to_usbdev(intf); @@ -1635,11 +1787,21 @@ 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) +	if (id->driver_info & BTUSB_BCM_PATCHRAM) {  		hdev->setup = btusb_setup_bcm_patchram; +		hdev->set_bdaddr = btusb_set_bdaddr_bcm; +	} -	if (id->driver_info & BTUSB_INTEL) +	if (id->driver_info & BTUSB_INTEL) {  		hdev->setup = btusb_setup_intel; +		hdev->set_bdaddr = btusb_set_bdaddr_intel; +	} + +	if (id->driver_info & BTUSB_MARVELL) +		hdev->set_bdaddr = btusb_set_bdaddr_marvell; + +	if (id->driver_info & BTUSB_INTEL_BOOT) +		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);  	/* Interface numbers are hardcoded in the specification */  	data->isoc = usb_ifnum_to_if(data->udev, 1); @@ -1679,8 +1841,18 @@ static int btusb_probe(struct usb_interface *intf,  		/* New sniffer firmware has crippled HCI interface */  		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)  			set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); +	} -		data->isoc = NULL; +	if (id->driver_info & BTUSB_INTEL_BOOT) { +		/* A bug in the bootloader causes that interrupt interface is +		 * only enabled after receiving SetInterface(0, AltSetting=0). +		 */ +		err = usb_set_interface(data->udev, 0, 0); +		if (err < 0) { +			BT_ERR("failed to set interface 0, alt 0 %d", err); +			hci_free_dev(hdev); +			return err; +		}  	}  	if (data->isoc) { @@ -1845,15 +2017,6 @@ static struct usb_driver btusb_driver = {  module_usb_driver(btusb_driver); -module_param(ignore_dga, bool, 0644); -MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); - -module_param(ignore_csr, bool, 0644); -MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); - -module_param(ignore_sniffer, bool, 0644); -MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); -  module_param(disable_scofix, bool, 0644);  MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");  |