https://blog.csdn.net/absurd/article/details/1852337
HCI在主机端的驱动主要是为上层提供一个统一的接口,让上层协议不依赖于具体硬件的实现。HCI在硬件中的固件与HCI在主机端的驱动通信方式有多种,比如像UART、USB和PC Card等等。
drivers/bluetooth/bfusb.c
static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *id){
const struct firmware *firmware;
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_endpoint *bulk_out_ep;
struct usb_host_endpoint *bulk_in_ep;
struct hci_dev *hdev;
struct bfusb_data *data;
/* Check number of endpoints */
if (intf->cur_altsetting->desc.bNumEndpoints < 2)
return -EIO;
bulk_out_ep = &intf->cur_altsetting->endpoint[0];
bulk_in_ep = &intf->cur_altsetting->endpoint[1];
if (!bulk_out_ep || !bulk_in_ep) {
BT_ERR("Bulk endpoints not found");
goto done;
}
/* Initialize control structure and load firmware */
data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for control structure");
goto done;
}
data->udev = udev;
data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
rwlock_init(&data->lock);
data->reassembly = NULL;
skb_queue_head_init(&data->transmit_q);
skb_queue_head_init(&data->pending_q);
skb_queue_head_init(&data->completed_q);
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
goto done;
}
if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
BT_ERR("Firmware loading failed");
goto release;
}
release_firmware(firmware);
/* Initialize and register HCI device */
hdev = hci_alloc_dev();
if (!hdev) {
BT_ERR("Can't allocate HCI device");
goto done;
}
data->hdev = hdev;
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = bfusb_open;
hdev->close = bfusb_close;
hdev->flush = bfusb_flush;
hdev->send = bfusb_send_frame;
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
if (hci_register_dev(hdev) < 0) {//在hci_core.c注册HCI设备
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
goto done;
}
usb_set_intfdata(intf, data);
return 0;
release:
release_firmware(firmware);
done:
return -EIO;
}
hci_core.c相当于一个框架,用于把各种具体通信方式胶合起来,并提供一些公共函数的实现。
//负责发送CMD的任务
static void hci_cmd_work(struct work_struct *work){
struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
struct sk_buff *skb;
/* Send queued commands */
if (atomic_read(&hdev->cmd_cnt)) {
skb = skb_dequeue(&hdev->cmd_q);//从hdev->cmd_q队列中取CMD
if (!skb)
return;
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(hdev, skb);//调用hci_send_frame把CMD发送出去
if (test_bit(HCI_RESET, &hdev->flags))
cancel_delayed_work(&hdev->cmd_timer);
else
schedule_delayed_work(&hdev->cmd_timer, HCI_CMD_TIMEOUT);
} else {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
}
}
//负责发送数据的任务
static void hci_tx_work(struct work_struct *work){
struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work);
struct sk_buff *skb;
if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
/* Schedule queues and send stuff to HCI driver */
hci_sched_acl(hdev);//发送所有connection中的ACL数据
hci_sched_sco(hdev);//发送所有connection中的SCO数据
hci_sched_esco(hdev);
hci_sched_le(hdev);
}
/* Send next queued raw (unknown type) packet */
while ((skb = skb_dequeue(&hdev->raw_q)))//发送hdev->raw_q中的数据包
hci_send_frame(hdev, skb);
}
//负责接收数据的任务
static void hci_rx_work(struct work_struct *work){
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
struct sk_buff *skb;
while ((skb = skb_dequeue(&hdev->rx_q))) { //从hdev->rx_q队列中取数据
/* Send copy to monitor */
hci_send_to_monitor(hdev, skb);
if (atomic_read(&hdev->promisc)) {
/* Send copy to the sockets */
hci_send_to_sock(hdev, skb);
}
if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
kfree_skb(skb);
continue;
}
if (test_bit(HCI_INIT, &hdev->flags)) {
/* Don't process data packets in this states. */
switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_SCODATA_PKT:
kfree_skb(skb);
continue;
}
}
/* Process frame */
switch (bt_cb(skb)->pkt_type) { //根据数据的类型调用上层函数处理
case HCI_EVENT_PKT://如连接建立或断开,认证和加密等事件,控制协议状态改变。
BT_DBG("%s Event packet", hdev->name);
hci_event_packet(hdev, skb);
break;
case HCI_ACLDATA_PKT://异步非连接的数据包,提交给上层的L2CAP协议处理
BT_DBG("%s ACL data packet", hdev->name);
hci_acldata_packet(hdev, skb);
break;
case HCI_SCODATA_PKT://同步面向连接的数据包,提交给上层的SCO协议处理
BT_DBG("%s SCO data packet", hdev->name);
hci_scodata_packet(hdev, skb);
break;
default:
kfree_skb(skb);
break;
}
}
}
//注册上层协议
int hci_register_cb(struct hci_cb *cb){
mutex_lock(&hci_cb_list_lock);
list_add_tail(&cb->list, &hci_cb_list);
mutex_unlock(&hci_cb_list_lock);
return 0;
}
//注销上层协议
int hci_unregister_cb(struct hci_cb *cb){
mutex_lock(&hci_cb_list_lock);
list_del(&cb->list);
mutex_unlock(&hci_cb_list_lock);
return 0;
}
//发送SCO数据包
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb){
struct hci_dev *hdev = conn->hdev;
struct hci_sco_hdr hdr;
hdr.handle = cpu_to_le16(conn->handle);
hdr.dlen = skb->len;
skb_push(skb, HCI_SCO_HDR_SIZE);
skb_reset_transport_header(skb);
memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
skb_queue_tail(&conn->data_q, skb);//把要发送的数据包放入conn->data_q队列
queue_work(hdev->workqueue, &hdev->tx_work);//调度发送任务去发送
}
//发送ACL数据包
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags){
struct hci_dev *hdev = chan->conn->hdev;
hci_queue_acl(chan, &chan->data_q, skb, flags);//把要发送的数据包放入chan->data_q队列
queue_work(hdev->workqueue, &hdev->tx_work);//调度发送任务去发送
}
//发送命令数据
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, const void *param){
struct sk_buff *skb;
skb = hci_prepare_cmd(hdev, opcode, plen, param);
if (!skb) {
BT_ERR("%s no memory for command", hdev->name);
return -ENOMEM;
}
/* Stand-alone HCI commands must be flagged as single-command requests.*/
bt_cb(skb)->hci.req_start = true;
skb_queue_tail(&hdev->cmd_q, skb);//把要发送的数据包放入hdev->cmd_q队列
queue_work(hdev->workqueue, &hdev->cmd_work);//调度命令发送任务去发送
return 0;
}
net/hci_sock.c
给上层提供一个socket接口,应用程序可以通过socket的方式来访问HCI。
//初始化sock
int __init hci_sock_init(void){
int err;
err = proto_register(&hci_sk_proto, 0);
if (err < 0)
return err;
err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);//注册了BTPROTO_HCI类型family
if (err < 0) {
BT_ERR("HCI socket registration failed");
goto error;
}
err = bt_procfs_init(&init_net, "hci", &hci_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create HCI proc file");
bt_sock_unregister(BTPROTO_HCI);
goto error;
}
return 0;
error:
proto_unregister(&hci_sk_proto);
return err;
}
//创建sock的函数
static int hci_sock_create(struct net *net, struct socket *sock, int protocol,int kern){
struct sock *sk;
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
sock->ops = &hci_sock_ops;//sock的ops指向hci_sock_ops
sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, kern);
if (!sk)
return -ENOMEM;
sock_init_data(sock, sk);
sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = protocol;
sock->state = SS_UNCONNECTED;
sk->sk_state = BT_OPEN;
bt_sock_link(&hci_sk_list, sk);
return 0;
}
static const struct proto_ops hci_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = hci_sock_release,
.bind = hci_sock_bind,
.getname = hci_sock_getname,
.sendmsg = hci_sock_sendmsg,
.recvmsg = hci_sock_recvmsg,
.ioctl = hci_sock_ioctl,
.poll = datagram_poll,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = hci_sock_setsockopt,
.getsockopt = hci_sock_getsockopt,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.mmap = sock_no_mmap
};
L2CAP是HCI之上的协议,提供诸如QoS,分组,多路复用,分段和组装之类的功能。
l2cap_sock.c
//创建sock的函数
static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern){
struct sock *sk;
sock->state = SS_UNCONNECTED;
if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
return -EPERM;
sock->ops = &l2cap_sock_ops;//sock的ops指向l2cap_sock_ops。
sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
if (!sk)
return -ENOMEM;
l2cap_sock_init(sk, NULL);
bt_sock_link(&l2cap_sk_list, sk);
return 0;
}
static const struct proto_ops l2cap_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = l2cap_sock_release,
.bind = l2cap_sock_bind,
.connect = l2cap_sock_connect,
.listen = l2cap_sock_listen,
.accept = l2cap_sock_accept,
.getname = l2cap_sock_getname,
.sendmsg = l2cap_sock_sendmsg,
.recvmsg = l2cap_sock_recvmsg,
.poll = bt_sock_poll,
.ioctl = bt_sock_ioctl,
.mmap = sock_no_mmap,
.socketpair = sock_no_socketpair,
.shutdown = l2cap_sock_shutdown,
.setsockopt = l2cap_sock_setsockopt,
.getsockopt = l2cap_sock_getsockopt
};
//把消息传递给下层的设备
static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len){
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
int err;
err = sock_error(sk);
if (err)
return err;
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
if (sk->sk_state != BT_CONNECTED)
return -ENOTCONN;
lock_sock(sk);
err = bt_sock_wait_ready(sk, msg->msg_flags);
release_sock(sk);
if (err)
return err;
l2cap_chan_lock(chan);
err = l2cap_chan_send(chan, msg, len);//通过l2cap_do_send-->hci_send_acl发送消息
l2cap_chan_unlock(chan);
return err;
}
SCO也是运行在HCI之上的协议,它是面向连接的可靠的传输方式,主要用于声音数据传输。
net/sco.c
//创建sock的函数
static int sco_sock_create(struct net *net, struct socket *sock, int protocol, int kern){
struct sock *sk;
sock->state = SS_UNCONNECTED;
if (sock->type != SOCK_SEQPACKET)
return -ESOCKTNOSUPPORT;
sock->ops = &sco_sock_ops;//sock的ops指向sco_sock_ops
sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
if (!sk)
return -ENOMEM;
sco_sock_init(sk, NULL);
return 0;
}
static const struct proto_ops sco_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = sco_sock_release,
.bind = sco_sock_bind,
.connect = sco_sock_connect,
.listen = sco_sock_listen,
.accept = sco_sock_accept,
.getname = sco_sock_getname,
.sendmsg = sco_sock_sendmsg,
.recvmsg = sco_sock_recvmsg,
.poll = bt_sock_poll,
.ioctl = bt_sock_ioctl,
.mmap = sock_no_mmap,
.socketpair = sock_no_socketpair,
.shutdown = sco_sock_shutdown,
.setsockopt = sco_sock_setsockopt,
.getsockopt = sco_sock_getsockopt
};
//把消息传递给下层的设备
static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len){
struct sock *sk = sock->sk;
int err;
err = sock_error(sk);
if (err)
return err;
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
lock_sock(sk);
if (sk->sk_state == BT_CONNECTED)
err = sco_send_frame(sk, msg, len);//通过调用hci_send_sco发送消息
else
err = -ENOTCONN;
release_sock(sk);
return err;
}