# hcidump -x
< HCI Command: Vendor (0x3f|0x0280) plen 5
09 01 00 00 00
> HCI Event: Command Status (0x0f) plen 4
00 01 80 FE
> HCI Event: Command Complete (0x0e) plen 6
01 80 FE 00 09 00
< HCI Command: Vendor (0x3f|0x0280) plen 5
03 7C A5 01 00
> HCI Event: Command Status (0x0f) plen 4
00 01 80 FE
> HCI Event: Command Complete (0x0e) plen 10
01 80 FE FF 03 15 7C A5 01 00


< 表示發出hci命令
> 表示收到回應


hcidump從kernel接收原始資料,對應kernel中send_general_cmd的3個kvec,包含三部分:
第一部分kvec[0]: packet類型
第二部分kvec[1]: 為message header,包含opcode和data length。hcidump顯示的0x3f|0x0280中,前面部分為opcode的高6bit,表示ogf,後面為低10bit,表示ocf
第三部分kvec[2]: hcidump列印出的buffer。在發出的命令中,第一個位元組表示表示命令idx,後面的四個位元組表示val


藍牙驅動會在發送命令後用kernel_recvmsg從kernel socket接收消息。接收的消息可能如下所示:
Response: 04 0e 0a 01 80 fe 00 03 00 7c a5 01 00
Event: 04 ff 05 82 00 00 00 00
對這個消息的解釋視vendor做法。對於我現在做的這個產品來說,它是這樣解析這些消息的:
buf[1]: 0e表示命令的response,ff表示event
buf[2]:表示長度
buf[3]~buf[n]:為hcidump列印出的buffer


static int xxxxx_hci_send_general_cmd(struct mrvl8xxx_device *dev, uint8_t ogf,
uint32_t ocf, uint8_t idx, uint32_t val, uint32_t len)
{
struct socket *sock = dev->sock;
uint8_t type = HCI_COMMAND_PKT;
struct kvec vec[3];
struct hci_command_hdr hc;
struct msghdr msg;
char cmdbuf[8];
uint8_t cmdlen;
int err = 0;


dev->request.idx = idx;
dev->request.val = val;
dev->request.len = len;


cmdbuf[0] = idx;
memcpy(&cmdbuf[1], &val, len);
cmdlen = len + 1;


hc.opcode = ((ogf & OGF_MASK) << OGF_SHIFT | (ocf & OCF_MASK));
hc.plen = cmdlen;


vec[0].iov_base = &type;
vec[0].iov_len = 1;


vec[1].iov_base = &hc;
vec[1].iov_len = HCI_COMMAND_HDR_SIZE;


vec[2].iov_base = cmdbuf;
vec[2].iov_len = cmdlen;


memset(&msg, 0, sizeof(msg));


err = kernel_sendmsg(sock, &msg, vec, 3, cmdlen+4);
if (err < 0)
printk(KERN_ERR "[fm] mrvl8xxx_hci_sendcmd: failed to kernel_sendmsg, return: %d\n", err);


return err;
}

shadow 发表在 痞客邦 PIXNET 留言(0) 引用(0) 人气()