summaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/ath3k.c29
-rw-r--r--drivers/bluetooth/btmrvl_drv.h1
-rw-r--r--drivers/bluetooth/btmrvl_main.c24
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c16
-rw-r--r--drivers/bluetooth/btusb.c34
-rw-r--r--drivers/bluetooth/hci_ldisc.c25
-rw-r--r--drivers/bluetooth/hci_uart.h1
7 files changed, 107 insertions, 23 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 230c552daf91..a0d7355ef127 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -27,6 +27,7 @@
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/usb.h>
+#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#define VERSION "1.0"
@@ -50,12 +51,12 @@
#define ATH3K_NAME_LEN 0xFF
struct ath3k_version {
- unsigned int rom_version;
- unsigned int build_version;
- unsigned int ram_version;
- unsigned char ref_clock;
- unsigned char reserved[0x07];
-};
+ __le32 rom_version;
+ __le32 build_version;
+ __le32 ram_version;
+ __u8 ref_clock;
+ __u8 reserved[7];
+} __packed;
static const struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 */
@@ -349,7 +350,8 @@ static int ath3k_load_patch(struct usb_device *udev)
unsigned char fw_state;
char filename[ATH3K_NAME_LEN] = {0};
const struct firmware *firmware;
- struct ath3k_version fw_version, pt_version;
+ struct ath3k_version fw_version;
+ __u32 pt_rom_version, pt_build_version;
int ret;
ret = ath3k_get_state(udev, &fw_state);
@@ -370,7 +372,7 @@ static int ath3k_load_patch(struct usb_device *udev)
}
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
- le32_to_cpu(fw_version.rom_version));
+ le32_to_cpu(fw_version.rom_version));
ret = request_firmware(&firmware, filename, &udev->dev);
if (ret < 0) {
@@ -378,12 +380,13 @@ static int ath3k_load_patch(struct usb_device *udev)
return ret;
}
- pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
- pt_version.build_version = *(int *)
- (firmware->data + firmware->size - 4);
+ pt_rom_version = get_unaligned_le32(firmware->data +
+ firmware->size - 8);
+ pt_build_version = get_unaligned_le32(firmware->data +
+ firmware->size - 4);
- if ((pt_version.rom_version != fw_version.rom_version) ||
- (pt_version.build_version <= fw_version.build_version)) {
+ if (pt_rom_version != le32_to_cpu(fw_version.rom_version) ||
+ pt_build_version <= le32_to_cpu(fw_version.build_version)) {
BT_ERR("Patch file version did not match with firmware");
release_firmware(firmware);
return -EINVAL;
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index caf684119a4e..38ad66289ad6 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -91,6 +91,7 @@ struct btmrvl_private {
/* Vendor specific Bluetooth commands */
#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03
+#define BT_CMD_SET_BDADDR 0xFC22
#define BT_CMD_AUTO_SLEEP_MODE 0xFC23
#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59
#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index cc65fd2fe856..bae8e6a0ecf6 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -539,6 +539,29 @@ static int btmrvl_setup(struct hci_dev *hdev)
return 0;
}
+static int btmrvl_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+{
+ struct sk_buff *skb;
+ long ret;
+ u8 buf[8];
+
+ buf[0] = MRVL_VENDOR_PKT;
+ buf[1] = sizeof(bdaddr_t);
+ memcpy(buf + 2, bdaddr, sizeof(bdaddr_t));
+
+ skb = __hci_cmd_sync(hdev, BT_CMD_SET_BDADDR, sizeof(buf), buf,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ BT_ERR("%s: changing btmrvl device address failed (%ld)",
+ hdev->name, ret);
+ return ret;
+ }
+ kfree_skb(skb);
+
+ return 0;
+}
+
/*
* This function handles the event generated by firmware, rx data
* received from firmware, and tx data sent from kernel.
@@ -632,6 +655,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
hdev->flush = btmrvl_flush;
hdev->send = btmrvl_send_frame;
hdev->setup = btmrvl_setup;
+ hdev->set_bdaddr = btmrvl_set_bdaddr;
hdev->dev_type = priv->btmrvl_dev.dev_type;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index efff06438b02..3e683b153259 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -1169,6 +1169,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
}
priv = card->priv;
+ hcidev = priv->btmrvl_dev.hcidev;
+ BT_DBG("%s: SDIO suspend", hcidev->name);
+ hci_suspend_dev(hcidev);
+ skb_queue_purge(&priv->adapter->tx_queue);
if (priv->adapter->hs_state != HS_ACTIVATED) {
if (btmrvl_enable_hs(priv)) {
@@ -1176,10 +1180,6 @@ static int btmrvl_sdio_suspend(struct device *dev)
return -EBUSY;
}
}
- hcidev = priv->btmrvl_dev.hcidev;
- BT_DBG("%s: SDIO suspend", hcidev->name);
- hci_suspend_dev(hcidev);
- skb_queue_purge(&priv->adapter->tx_queue);
priv->adapter->is_suspended = true;
@@ -1221,13 +1221,13 @@ static int btmrvl_sdio_resume(struct device *dev)
return 0;
}
- priv->adapter->is_suspended = false;
- hcidev = priv->btmrvl_dev.hcidev;
- BT_DBG("%s: SDIO resume", hcidev->name);
- hci_resume_dev(hcidev);
priv->hw_wakeup_firmware(priv);
priv->adapter->hs_state = HS_DEACTIVATED;
+ hcidev = priv->btmrvl_dev.hcidev;
BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name);
+ priv->adapter->is_suspended = false;
+ BT_DBG("%s: SDIO resume", hcidev->name);
+ hci_resume_dev(hcidev);
return 0;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index ed7b33b06b43..292c38e8aa17 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -48,6 +48,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL 0x100
#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 */
@@ -113,6 +114,9 @@ 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) },
@@ -242,6 +246,10 @@ static const struct usb_device_id blacklist_table[] = {
{ 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 */
};
@@ -1455,6 +1463,29 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
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)
@@ -1766,6 +1797,9 @@ static int btusb_probe(struct usb_interface *intf,
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);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index e00f8f5b5c8e..dc487b5d1156 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -431,6 +431,9 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+ if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
+ set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
+
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
@@ -477,6 +480,22 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
return 0;
}
+static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
+{
+ unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) |
+ BIT(HCI_UART_RESET_ON_INIT) |
+ BIT(HCI_UART_CREATE_AMP) |
+ BIT(HCI_UART_INIT_PENDING) |
+ BIT(HCI_UART_EXT_CONFIG);
+
+ if ((flags & ~valid_flags))
+ return -EINVAL;
+
+ hu->hdev_flags = flags;
+
+ return 0;
+}
+
/* hci_uart_tty_ioctl()
*
* Process IOCTL system call for the tty device.
@@ -520,14 +539,16 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
return -EUNATCH;
case HCIUARTGETDEVICE:
- if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+ if (test_bit(HCI_UART_REGISTERED, &hu->flags))
return hu->hdev->id;
return -EUNATCH;
case HCIUARTSETFLAGS:
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
return -EBUSY;
- hu->hdev_flags = arg;
+ err = hci_uart_set_flags(hu, arg);
+ if (err)
+ return err;
break;
case HCIUARTGETFLAGS:
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 12df101ca942..247488edcbf9 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -48,6 +48,7 @@
#define HCI_UART_RESET_ON_INIT 1
#define HCI_UART_CREATE_AMP 2
#define HCI_UART_INIT_PENDING 3
+#define HCI_UART_EXT_CONFIG 4
struct hci_uart;
OpenPOWER on IntegriCloud