Search Linux Wireless

Re: [PATCH v5 2/2] Bluetooth: btmrvl: add calibration data download support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Bing,

> A text file containing calibration data in hex format can
> be provided at following path:
> 
> /lib/firmware/mrvl/sd8797_caldata.conf
> 
> The data will be downloaded to firmware during initialization.
> 
> Reviewed-by: Mike Frysinger <vapier@xxxxxxxxxxxx>
> Signed-off-by: Amitkumar Karwar <akarwar@xxxxxxxxxxx>
> Signed-off-by: Bing Zhao <bzhao@xxxxxxxxxxx>
> Signed-off-by: Hyuckjoo Lee <hyuckjoo.lee@xxxxxxxxxxx>
> ---
> v2: Remove module parameter. The calibration data will be downloaded
>    only when the device speicific data file is provided.
>    (Marcel Holtmann)
> v3: Fix crash (misaligned memory access) on ARM
> v4: Simplify white space parsing and save some CPU cycles (Mike Frysinger)
> v5: Improvements in cal data parsing logic. Add explanatory comments.
>    Replace GFP_ATOMIC flag with GFP_KERNEL (Mike Frysinger)
> 
> drivers/bluetooth/btmrvl_drv.h  |   10 +++-
> drivers/bluetooth/btmrvl_main.c |  144 ++++++++++++++++++++++++++++++++++++++-
> drivers/bluetooth/btmrvl_sdio.c |    9 ++-
> drivers/bluetooth/btmrvl_sdio.h |    2 +
> 4 files changed, 161 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
> index e776b8b..dcd3468 100644
> --- a/drivers/bluetooth/btmrvl_drv.h
> +++ b/drivers/bluetooth/btmrvl_drv.h
> @@ -23,6 +23,8 @@
> #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
> @@ -41,6 +43,8 @@ struct btmrvl_thread {
> struct btmrvl_device {
> 	void *card;
> 	struct hci_dev *hcidev;
> +	struct device *dev;
> +	const char *cal_data;
> 
> 	u8 dev_type;
> 
> @@ -92,6 +96,7 @@ struct btmrvl_private {
> #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
> 
> /* Sub-commands: Module Bringup/Shutdown Request/Response */
> #define MODULE_BRINGUP_REQ		0xF1
> @@ -117,10 +122,13 @@ struct btmrvl_private {
> #define PS_SLEEP			0x01
> #define PS_AWAKE			0x00
> 
> +#define BT_CMD_DATA_SIZE		32
> +#define BT_CAL_DATA_SIZE		28
> +
> struct btmrvl_cmd {
> 	__le16 ocf_ogf;
> 	u8 length;
> -	u8 data[4];
> +	u8 data[BT_CMD_DATA_SIZE];
> } __packed;
> 
> struct btmrvl_event {
> diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
> index e352f8e..6eea188 100644
> --- a/drivers/bluetooth/btmrvl_main.c
> +++ b/drivers/bluetooth/btmrvl_main.c
> @@ -57,8 +57,9 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)
> 		ocf = hci_opcode_ocf(opcode);
> 		ogf = hci_opcode_ogf(opcode);
> 
> -		if (ocf == BT_CMD_MODULE_CFG_REQ &&
> -					priv->btmrvl_dev.sendcmdflag) {
> +		if ((ocf == BT_CMD_MODULE_CFG_REQ ||
> +		     ocf == BT_CMD_LOAD_CONFIG_DATA) &&
> +		    priv->btmrvl_dev.sendcmdflag) {
> 			priv->btmrvl_dev.sendcmdflag = false;
> 			priv->adapter->cmd_complete = true;
> 			wake_up_interruptible(&priv->adapter->cmd_wait_q);
> @@ -479,6 +480,142 @@ 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)
> +{
> +	const u8 *s = src;
> +	u8 *d = dst;
> +	int ret;
> +	u8 tmp[3];
> +
> +	tmp[2] = '\0';
> +	while ((s - src) <= len - 2) {
> +		if (isspace(*s) || *s == '\n') {
> +			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)
> +{
> +	struct sk_buff *skb;
> +	struct btmrvl_cmd *cmd;
> +	int i;
> +
> +	skb = bt_skb_alloc(sizeof(*cmd), GFP_KERNEL);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct btmrvl_cmd *)skb->data;
> +	cmd->ocf_ogf =
> +		cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_LOAD_CONFIG_DATA));
> +	cmd->length = BT_CMD_DATA_SIZE;
> +	cmd->data[0] = 0x00;
> +	cmd->data[1] = 0x00;
> +	cmd->data[2] = 0x00;
> +	cmd->data[3] = BT_CMD_DATA_SIZE - 4;

why not use __hci_cmd_sync() here. It is designed to be used from ->setup() where it is guaranteed that the HCI request lock is held. And it is guaranteed that ->setup() is executed in a workqueue.

Regards

Marcel

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux