diff options
author | Jiri Kosina <jkosina@suse.cz> | 2014-02-20 14:54:28 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-02-20 14:54:28 +0100 |
commit | d4263348f796f29546f90802177865dd4379dd0a (patch) | |
tree | adcbdaebae584eee2f32fab95e826e8e49eef385 /drivers/bluetooth | |
parent | be873ac782f5ff5ee6675f83929f4fe6737eead2 (diff) | |
parent | 6d0abeca3242a88cab8232e4acd7e2bf088f3bc2 (diff) | |
download | linux-d4263348f796f29546f90802177865dd4379dd0a.tar.bz2 |
Merge branch 'master' into for-next
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/ath3k.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 25 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 130 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 9 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.h | 2 | ||||
-rw-r--r-- | drivers/bluetooth/btsdio.c | 6 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 54 | ||||
-rw-r--r-- | drivers/bluetooth/hci_vhci.c | 29 |
8 files changed, 125 insertions, 136 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 6bfc1bb318f6..106d1d8e16ad 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -83,10 +83,12 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x3005) }, { USB_DEVICE(0x04CA, 0x3006) }, { USB_DEVICE(0x04CA, 0x3008) }, + { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x13d3, 0x3362) }, { USB_DEVICE(0x0CF3, 0xE004) }, { USB_DEVICE(0x0CF3, 0xE005) }, { USB_DEVICE(0x0930, 0x0219) }, + { USB_DEVICE(0x0930, 0x0220) }, { USB_DEVICE(0x0489, 0xe057) }, { USB_DEVICE(0x13d3, 0x3393) }, { USB_DEVICE(0x0489, 0xe04e) }, @@ -96,6 +98,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x0cf3, 0x3121) }, { USB_DEVICE(0x0cf3, 0xe003) }, + { USB_DEVICE(0x0489, 0xe05f) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -125,10 +128,12 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, @@ -138,6 +143,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index f9d183387f45..7399303d7d99 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -23,8 +23,6 @@ #include <linux/bitops.h> #include <linux/slab.h> #include <net/bluetooth/bluetooth.h> -#include <linux/ctype.h> -#include <linux/firmware.h> #define BTM_HEADER_LEN 4 #define BTM_UPLD_SIZE 2312 @@ -43,8 +41,6 @@ struct btmrvl_thread { struct btmrvl_device { void *card; struct hci_dev *hcidev; - struct device *dev; - const char *cal_data; u8 dev_type; @@ -90,12 +86,12 @@ struct btmrvl_private { #define MRVL_VENDOR_PKT 0xFE -/* Bluetooth commands */ -#define BT_CMD_AUTO_SLEEP_MODE 0x23 -#define BT_CMD_HOST_SLEEP_CONFIG 0x59 -#define BT_CMD_HOST_SLEEP_ENABLE 0x5A -#define BT_CMD_MODULE_CFG_REQ 0x5B -#define BT_CMD_LOAD_CONFIG_DATA 0x61 +/* Vendor specific Bluetooth commands */ +#define BT_CMD_AUTO_SLEEP_MODE 0xFC23 +#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 +#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A +#define BT_CMD_MODULE_CFG_REQ 0xFC5B +#define BT_CMD_LOAD_CONFIG_DATA 0xFC61 /* Sub-commands: Module Bringup/Shutdown Request/Response */ #define MODULE_BRINGUP_REQ 0xF1 @@ -104,6 +100,11 @@ struct btmrvl_private { #define MODULE_SHUTDOWN_REQ 0xF2 +/* Vendor specific Bluetooth events */ +#define BT_EVENT_AUTO_SLEEP_MODE 0x23 +#define BT_EVENT_HOST_SLEEP_CONFIG 0x59 +#define BT_EVENT_HOST_SLEEP_ENABLE 0x5A +#define BT_EVENT_MODULE_CFG_REQ 0x5B #define BT_EVENT_POWER_STATE 0x20 /* Bluetooth Power States */ @@ -111,8 +112,6 @@ struct btmrvl_private { #define BT_PS_DISABLE 0x03 #define BT_PS_SLEEP 0x01 -#define OGF 0x3F - /* Host Sleep states */ #define HS_ACTIVATED 0x01 #define HS_DEACTIVATED 0x00 @@ -121,7 +120,7 @@ struct btmrvl_private { #define PS_SLEEP 0x01 #define PS_AWAKE 0x00 -#define BT_CMD_DATA_SIZE 32 +#define BT_CAL_HDR_LEN 4 #define BT_CAL_DATA_SIZE 28 struct btmrvl_event { diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 5cf31c4fe6d1..1e0320af00c6 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -19,7 +19,7 @@ **/ #include <linux/module.h> - +#include <linux/of.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -50,12 +50,10 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) if (hdr->evt == HCI_EV_CMD_COMPLETE) { struct hci_ev_cmd_complete *ec; - u16 opcode, ocf, ogf; + u16 opcode; ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); - ocf = hci_opcode_ocf(opcode); - ogf = hci_opcode_ogf(opcode); if (priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; @@ -63,9 +61,8 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) wake_up_interruptible(&priv->adapter->cmd_wait_q); } - if (ogf == OGF) { - BT_DBG("vendor event skipped: ogf 0x%4.4x ocf 0x%4.4x", - ogf, ocf); + if (hci_opcode_ogf(opcode) == 0x3F) { + BT_DBG("vendor event skipped: opcode=%#4.4x", opcode); kfree_skb(skb); return false; } @@ -89,7 +86,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } switch (event->data[0]) { - case BT_CMD_AUTO_SLEEP_MODE: + case BT_EVENT_AUTO_SLEEP_MODE: if (!event->data[2]) { if (event->data[1] == BT_PS_ENABLE) adapter->psmode = 1; @@ -102,7 +99,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } break; - case BT_CMD_HOST_SLEEP_CONFIG: + case BT_EVENT_HOST_SLEEP_CONFIG: if (!event->data[3]) BT_DBG("gpio=%x, gap=%x", event->data[1], event->data[2]); @@ -110,7 +107,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) BT_DBG("HSCFG command failed"); break; - case BT_CMD_HOST_SLEEP_ENABLE: + case BT_EVENT_HOST_SLEEP_ENABLE: if (!event->data[1]) { adapter->hs_state = HS_ACTIVATED; if (adapter->psmode) @@ -121,7 +118,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) } break; - case BT_CMD_MODULE_CFG_REQ: + case BT_EVENT_MODULE_CFG_REQ: if (priv->btmrvl_dev.sendcmdflag && event->data[1] == MODULE_BRINGUP_REQ) { BT_DBG("EVENT:%s", @@ -166,7 +163,7 @@ exit: } EXPORT_SYMBOL_GPL(btmrvl_process_event); -static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, +static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode, const void *param, u8 len) { struct sk_buff *skb; @@ -179,7 +176,7 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, } hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE); - hdr->opcode = cpu_to_le16(hci_opcode_pack(OGF, cmd_no)); + hdr->opcode = cpu_to_le16(opcode); hdr->plen = len; if (len) @@ -417,127 +414,62 @@ static int btmrvl_open(struct hci_dev *hdev) return 0; } -/* - * This function parses provided calibration data input. It should contain - * hex bytes separated by space or new line character. Here is an example. - * 00 1C 01 37 FF FF FF FF 02 04 7F 01 - * CE BA 00 00 00 2D C6 C0 00 00 00 00 - * 00 F0 00 00 - */ -static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size) +static int btmrvl_download_cal_data(struct btmrvl_private *priv, + u8 *data, int len) { - const u8 *s = src; - u8 *d = dst; int ret; - u8 tmp[3]; - - tmp[2] = '\0'; - while ((s - src) <= len - 2) { - if (isspace(*s)) { - s++; - continue; - } - - if (isxdigit(*s)) { - if ((d - dst) >= dst_size) { - BT_ERR("calibration data file too big!!!"); - return -EINVAL; - } - - memcpy(tmp, s, 2); - - ret = kstrtou8(tmp, 16, d++); - if (ret < 0) - return ret; - - s += 2; - } else { - return -EINVAL; - } - } - if (d == dst) - return -EINVAL; - - return 0; -} - -static int btmrvl_load_cal_data(struct btmrvl_private *priv, - u8 *config_data) -{ - int i, ret; - u8 data[BT_CMD_DATA_SIZE]; data[0] = 0x00; data[1] = 0x00; data[2] = 0x00; - data[3] = BT_CMD_DATA_SIZE - 4; - - /* Swap cal-data bytes. Each four bytes are swapped. Considering 4 - * byte SDIO header offset, mapping of input and output bytes will be - * {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4}, - * {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */ - for (i = 4; i < BT_CMD_DATA_SIZE; i++) - data[i] = config_data[(i / 4) * 8 - 1 - i]; + data[3] = len; print_hex_dump_bytes("Calibration data: ", - DUMP_PREFIX_OFFSET, data, BT_CMD_DATA_SIZE); + DUMP_PREFIX_OFFSET, data, BT_CAL_HDR_LEN + len); ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data, - BT_CMD_DATA_SIZE); + BT_CAL_HDR_LEN + len); if (ret) BT_ERR("Failed to download caibration data\n"); return 0; } -static int -btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size) +static int btmrvl_cal_data_dt(struct btmrvl_private *priv) { - u8 cal_data[BT_CAL_DATA_SIZE]; + struct device_node *dt_node; + u8 cal_data[BT_CAL_HDR_LEN + BT_CAL_DATA_SIZE]; + const char name[] = "btmrvl_caldata"; + const char property[] = "btmrvl,caldata"; int ret; - ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data)); + dt_node = of_find_node_by_name(NULL, name); + if (!dt_node) + return -ENODEV; + + ret = of_property_read_u8_array(dt_node, property, + cal_data + BT_CAL_HDR_LEN, + BT_CAL_DATA_SIZE); if (ret) return ret; - ret = btmrvl_load_cal_data(priv, cal_data); + BT_DBG("Use cal data from device tree"); + ret = btmrvl_download_cal_data(priv, cal_data, BT_CAL_DATA_SIZE); if (ret) { - BT_ERR("Fail to load calibrate data"); + BT_ERR("Fail to download calibrate data"); return ret; } return 0; } -static int btmrvl_cal_data_config(struct btmrvl_private *priv) -{ - const struct firmware *cfg; - int ret; - const char *cal_data = priv->btmrvl_dev.cal_data; - - if (!cal_data) - return 0; - - ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev); - if (ret < 0) { - BT_DBG("Failed to get %s file, skipping cal data download", - cal_data); - return 0; - } - - ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size); - release_firmware(cfg); - return ret; -} - static int btmrvl_setup(struct hci_dev *hdev) { struct btmrvl_private *priv = hci_get_drvdata(hdev); btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); - if (btmrvl_cal_data_config(priv)) - BT_ERR("Set cal data failed"); + btmrvl_cal_data_dt(priv); priv->btmrvl_dev.psmode = 1; btmrvl_enable_ps(priv); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index fabcf5bb48af..1b52c9f5230d 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -18,6 +18,7 @@ * this warranty disclaimer. **/ +#include <linux/firmware.h> #include <linux/slab.h> #include <linux/mmc/sdio_ids.h> @@ -101,7 +102,6 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { .helper = "mrvl/sd8688_helper.bin", .firmware = "mrvl/sd8688.bin", - .cal_data = NULL, .reg = &btmrvl_reg_8688, .sd_blksz_fw_dl = 64, }; @@ -109,7 +109,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { .helper = NULL, .firmware = "mrvl/sd8787_uapsta.bin", - .cal_data = NULL, .reg = &btmrvl_reg_87xx, .sd_blksz_fw_dl = 256, }; @@ -117,7 +116,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .helper = NULL, .firmware = "mrvl/sd8797_uapsta.bin", - .cal_data = "mrvl/sd8797_caldata.conf", .reg = &btmrvl_reg_87xx, .sd_blksz_fw_dl = 256, }; @@ -125,7 +123,6 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { .helper = NULL, .firmware = "mrvl/sd8897_uapsta.bin", - .cal_data = NULL, .reg = &btmrvl_reg_88xx, .sd_blksz_fw_dl = 256, }; @@ -1007,7 +1004,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, struct btmrvl_sdio_device *data = (void *) id->driver_data; card->helper = data->helper; card->firmware = data->firmware; - card->cal_data = data->cal_data; card->reg = data->reg; card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; } @@ -1036,8 +1032,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func, } card->priv = priv; - priv->btmrvl_dev.dev = &card->func->dev; - priv->btmrvl_dev.cal_data = card->cal_data; /* Initialize the interface specific function pointers */ priv->hw_host_to_card = btmrvl_sdio_host_to_card; @@ -1220,5 +1214,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); -MODULE_FIRMWARE("mrvl/sd8797_caldata.conf"); MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 6872d9ecac07..43d35a609ca9 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -85,7 +85,6 @@ struct btmrvl_sdio_card { u32 ioport; const char *helper; const char *firmware; - const char *cal_data; const struct btmrvl_sdio_card_reg *reg; u16 sd_blksz_fw_dl; u8 rx_unit; @@ -95,7 +94,6 @@ struct btmrvl_sdio_card { struct btmrvl_sdio_device { const char *helper; const char *firmware; - const char *cal_data; const struct btmrvl_sdio_card_reg *reg; u16 sd_blksz_fw_dl; }; diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index b61440aaee65..83f6437dd91d 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -73,6 +73,7 @@ struct btsdio_data { #define REG_CL_INTRD 0x13 /* Interrupt Clear */ #define REG_EN_INTRD 0x14 /* Interrupt Enable */ #define REG_MD_STAT 0x20 /* Bluetooth Mode Status */ +#define REG_MD_SET 0x20 /* Bluetooth Mode Set */ static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb) { @@ -212,7 +213,7 @@ static int btsdio_open(struct hci_dev *hdev) } if (data->func->class == SDIO_CLASS_BT_B) - sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL); + sdio_writeb(data->func, 0x00, REG_MD_SET, NULL); sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL); @@ -333,6 +334,9 @@ static int btsdio_probe(struct sdio_func *func, hdev->flush = btsdio_flush; hdev->send = btsdio_send_frame; + if (func->vendor == 0x0104 && func->device == 0x00c5) + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c0ff34f2d2df..baeaaed299e4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -150,10 +150,12 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, @@ -163,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -223,6 +226,7 @@ static const struct usb_device_id blacklist_table[] = { /* Intel Bluetooth device */ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { } /* Terminating entry */ }; @@ -961,6 +965,45 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev) return 0; } +static int btusb_setup_csr(struct hci_dev *hdev) +{ + struct hci_rp_read_local_version *rp; + struct sk_buff *skb; + int ret; + + BT_DBG("%s", hdev->name); + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); + return -PTR_ERR(skb); + } + + rp = (struct hci_rp_read_local_version *) skb->data; + + if (!rp->status) { + if (le16_to_cpu(rp->manufacturer) != 10) { + /* Clear the reset quirk since this is not an actual + * early Bluetooth 1.1 device from CSR. + */ + clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* These fake CSR controllers have all a broken + * stored link key handling and so just disable it. + */ + set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, + &hdev->quirks); + } + } + + ret = -bt_to_errno(rp->status); + + kfree_skb(skb); + + return ret; +} + struct intel_version { u8 status; u8 hw_platform; @@ -1435,8 +1478,10 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; - if (id->driver_info & BTUSB_INTEL) + if (id->driver_info & BTUSB_INTEL) { + usb_enable_autosuspend(data->udev); hdev->setup = btusb_setup_intel; + } /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); @@ -1459,10 +1504,15 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_CSR) { struct usb_device *udev = data->udev; + u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); /* Old firmware would otherwise execute USB reset */ - if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) + if (bcdDevice < 0x117) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* Fake CSR devices with broken commands */ + if (bcdDevice <= 0x100) + hdev->setup = btusb_setup_csr; } if (id->driver_info & BTUSB_SNIFFER) { diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7b167385a1c4..1ef6990a5c7e 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -141,22 +141,28 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) } static inline ssize_t vhci_get_user(struct vhci_data *data, - const char __user *buf, size_t count) + const struct iovec *iov, + unsigned long count) { + size_t len = iov_length(iov, count); struct sk_buff *skb; __u8 pkt_type, dev_type; + unsigned long i; int ret; - if (count < 2 || count > HCI_MAX_FRAME_SIZE) + if (len < 2 || len > HCI_MAX_FRAME_SIZE) return -EINVAL; - skb = bt_skb_alloc(count, GFP_KERNEL); + skb = bt_skb_alloc(len, GFP_KERNEL); if (!skb) return -ENOMEM; - if (copy_from_user(skb_put(skb, count), buf, count)) { - kfree_skb(skb); - return -EFAULT; + for (i = 0; i < count; i++) { + if (copy_from_user(skb_put(skb, iov[i].iov_len), + iov[i].iov_base, iov[i].iov_len)) { + kfree_skb(skb); + return -EFAULT; + } } pkt_type = *((__u8 *) skb->data); @@ -205,7 +211,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, return -EINVAL; } - return (ret < 0) ? ret : count; + return (ret < 0) ? ret : len; } static inline ssize_t vhci_put_user(struct vhci_data *data, @@ -272,12 +278,13 @@ static ssize_t vhci_read(struct file *file, return ret; } -static ssize_t vhci_write(struct file *file, - const char __user *buf, size_t count, loff_t *pos) +static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long count, loff_t pos) { + struct file *file = iocb->ki_filp; struct vhci_data *data = file->private_data; - return vhci_get_user(data, buf, count); + return vhci_get_user(data, iov, count); } static unsigned int vhci_poll(struct file *file, poll_table *wait) @@ -342,7 +349,7 @@ static int vhci_release(struct inode *inode, struct file *file) static const struct file_operations vhci_fops = { .owner = THIS_MODULE, .read = vhci_read, - .write = vhci_write, + .aio_write = vhci_write, .poll = vhci_poll, .open = vhci_open, .release = vhci_release, |