2008年10月29日星期三

Bluetooth HCI Event的处理

作者:Sam(甄峰) sam_code@hotmail.com

1.当Bluetooth USB dongle插入USB接口时,driver/bluetooth/hci_usb.c中probe程序被调用。probe会调用hci_register_dev()--〉tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
将hci_rx_task() 连上rx_task->func.
2.同样在Bluetooth USB dongle插入时,hdev->open = hci_usb_open; 当USB Dongle被UP时,这个function被调用。它调用hci_usb_intr_rx_submit(),它注册URB完成处理程序,hci_usb_rx_complete。
当有URB出现时, hci_usb_rx_complete ->__recv_frame() ->hci_recv_frame()->hci_sched_rx(hdev);->hci_sched_rx() ->tasklet_schedule(&hdev->rx_task)
tasklet_schedule():
将这个tasklet放在 tasklet_vec链表的头部,并唤醒后台线程ksoftirqd。当后台线程ksoftirqd运行调用__do_softirq时,会执行在中断向量表softirq_vec里中断号TASKLET_SOFTIRQ对应的tasklet_action函数,然后tasklet_action遍历 tasklet_vec链表,调用每个tasklet的函数完成软中断操作。
也就是调用hci_rx_task()

也就是:当有URB时,会最终调用到hci_rx_task()

当包类型为 HCI Event时,则调用hci_event_packet()
在hci_event_packet()中,会判断是何种Event.并处理之。

下面以HCI_EV_DISCONN_COMPLETE为例子看Event如何被处理。这个Event表明连接断掉了。reason则表示断掉的原因。

HCI_EV_DISCONN_COMPLETE Event使用处理程序hci_disconn_complete_evt来处理,下面详细讲解:

1.hci_dev_lock():使用自旋锁得到资源。

2.hci_conn_hash_lookup_handle():从连接队列中找出对应连接。注:当有ACL或SOC连接时,这个连接就会被加入连接链表。

3.这个连接的state改为BT_CLOSED。

4.hci_proto_disconn_ind(): 调用全局变量hci_proto中的disconn_ind()。

注:在L2cap protocol insmod时,hci_register_proto()被调用。全局变量hci_proto则被赋值。disconn_ind=l2cap_disconn_ind;

所以当HCI层得到Disconnect时,会通知l2cap层做删除channel等工作。

且因为state改为BT_CLOSED. 所以在l2cap 层调用poll(最终调用bt_sock_poll)时会发现POLLHUP被置位。

这样l2cap应用程序就能够知道连接已经断开了。

没有评论: