|
@@ -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);
|