diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
commit | 62b8c978ee6b8d135d9e7953221de58000dba986 (patch) | |
tree | 683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/bluetooth/btmrvl_main.c | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/bluetooth/btmrvl_main.c')
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 295 |
1 files changed, 114 insertions, 181 deletions
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 5cf31c4..9a9f518 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -57,7 +57,8 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) ocf = hci_opcode_ocf(opcode); ogf = hci_opcode_ogf(opcode); - if (priv->btmrvl_dev.sendcmdflag) { + if (ocf == BT_CMD_MODULE_CFG_REQ && + priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; priv->adapter->cmd_complete = true; wake_up_interruptible(&priv->adapter->cmd_wait_q); @@ -115,6 +116,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) adapter->hs_state = HS_ACTIVATED; if (adapter->psmode) adapter->ps_state = PS_SLEEP; + wake_up_interruptible(&adapter->cmd_wait_q); BT_DBG("HS ACTIVATED!"); } else { BT_DBG("HS Enable failed"); @@ -166,50 +168,45 @@ exit: } EXPORT_SYMBOL_GPL(btmrvl_process_event); -static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 cmd_no, - const void *param, u8 len) +int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) { struct sk_buff *skb; - struct hci_command_hdr *hdr; + struct btmrvl_cmd *cmd; + int ret = 0; - skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC); + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); if (skb == NULL) { BT_ERR("No free skb"); return -ENOMEM; } - hdr = (struct hci_command_hdr *)skb_put(skb, HCI_COMMAND_HDR_SIZE); - hdr->opcode = cpu_to_le16(hci_opcode_pack(OGF, cmd_no)); - hdr->plen = len; - - if (len) - memcpy(skb_put(skb, len), param, len); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ)); + cmd->length = 1; + cmd->data[0] = subcmd; bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + skb->dev = (void *) priv->btmrvl_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); priv->btmrvl_dev.sendcmdflag = true; priv->adapter->cmd_complete = false; + BT_DBG("Queue module cfg Command"); + wake_up_interruptible(&priv->main_thread.wait_q); if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, priv->adapter->cmd_complete, - msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) - return -ETIMEDOUT; - - return 0; -} - -int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) -{ - int ret; + msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) { + ret = -ETIMEDOUT; + BT_ERR("module_cfg_cmd(%x): timeout: %d", + subcmd, priv->btmrvl_dev.sendcmdflag); + } - ret = btmrvl_send_sync_cmd(priv, BT_CMD_MODULE_CFG_REQ, &subcmd, 1); - if (ret) - BT_ERR("module_cfg_cmd(%x) failed\n", subcmd); + BT_DBG("module cfg Command done"); return ret; } @@ -217,36 +214,61 @@ EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) { - int ret; - u8 param[2]; + struct sk_buff *skb; + struct btmrvl_cmd *cmd; - param[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; - param[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (!skb) { + BT_ERR("No free skb"); + return -ENOMEM; + } - BT_DBG("Sending HSCFG Command, gpio=0x%x, gap=0x%x", - param[0], param[1]); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, + BT_CMD_HOST_SLEEP_CONFIG)); + cmd->length = 2; + cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; + cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); - ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_CONFIG, param, 2); - if (ret) - BT_ERR("HSCFG command failed\n"); + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - return ret; + skb->dev = (void *) priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0], + cmd->data[1]); + + return 0; } EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd); int btmrvl_enable_ps(struct btmrvl_private *priv) { - int ret; - u8 param; + struct sk_buff *skb; + struct btmrvl_cmd *cmd; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + return -ENOMEM; + } + + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, + BT_CMD_AUTO_SLEEP_MODE)); + cmd->length = 1; if (priv->btmrvl_dev.psmode) - param = BT_PS_ENABLE; + cmd->data[0] = BT_PS_ENABLE; else - param = BT_PS_DISABLE; + cmd->data[0] = BT_PS_DISABLE; - ret = btmrvl_send_sync_cmd(priv, BT_CMD_AUTO_SLEEP_MODE, ¶m, 1); - if (ret) - BT_ERR("PSMODE command failed\n"); + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb->dev = (void *) priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); return 0; } @@ -254,11 +276,37 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps); int btmrvl_enable_hs(struct btmrvl_private *priv) { - int ret; + struct sk_buff *skb; + struct btmrvl_cmd *cmd; + int ret = 0; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + return -ENOMEM; + } - ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0); - if (ret) - BT_ERR("Host sleep enable command failed\n"); + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE)); + cmd->length = 0; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb->dev = (void *) priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue hs enable Command"); + + wake_up_interruptible(&priv->main_thread.wait_q); + + if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q, + priv->adapter->hs_state, + msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) { + ret = -ETIMEDOUT; + BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state, + priv->adapter->ps_state, + priv->adapter->wakeup_tries); + } return ret; } @@ -355,12 +403,26 @@ static void btmrvl_free_adapter(struct btmrvl_private *priv) priv->adapter = NULL; } -static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +static int btmrvl_ioctl(struct hci_dev *hdev, + unsigned int cmd, unsigned long arg) { - struct btmrvl_private *priv = hci_get_drvdata(hdev); + return -ENOIOCTLCMD; +} + +static int btmrvl_send_frame(struct sk_buff *skb) +{ + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct btmrvl_private *priv = NULL; BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len); + if (!hdev) { + BT_ERR("Frame for unknown HCI device"); + return -ENODEV; + } + + priv = hci_get_drvdata(hdev); + if (!test_bit(HCI_RUNNING, &hdev->flags)) { BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags); print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET, @@ -418,137 +480,6 @@ static int btmrvl_open(struct hci_dev *hdev) } /* - * 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) -{ - 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]; - - print_hex_dump_bytes("Calibration data: ", - DUMP_PREFIX_OFFSET, data, BT_CMD_DATA_SIZE); - - ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data, - BT_CMD_DATA_SIZE); - 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) -{ - u8 cal_data[BT_CAL_DATA_SIZE]; - int ret; - - ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data)); - if (ret) - return ret; - - ret = btmrvl_load_cal_data(priv, cal_data); - if (ret) { - BT_ERR("Fail to load 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"); - - priv->btmrvl_dev.psmode = 1; - btmrvl_enable_ps(priv); - - priv->btmrvl_dev.gpio_gap = 0xffff; - btmrvl_send_hscfg_cmd(priv); - - return 0; -} - -/* * This function handles the event generated by firmware, rx data * received from firmware, and tx data sent from kernel. */ @@ -635,12 +566,14 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) priv->btmrvl_dev.hcidev = hdev; hci_set_drvdata(hdev, priv); - hdev->bus = HCI_SDIO; - hdev->open = btmrvl_open; + hdev->bus = HCI_SDIO; + hdev->open = btmrvl_open; hdev->close = btmrvl_close; hdev->flush = btmrvl_flush; - hdev->send = btmrvl_send_frame; - hdev->setup = btmrvl_setup; + hdev->send = btmrvl_send_frame; + hdev->ioctl = btmrvl_ioctl; + + btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); hdev->dev_type = priv->btmrvl_dev.dev_type; |