linux下的蓝牙驱动程序详解

版权声明:本文为博主原创文章,转载请注明出处! https://blog.csdn.net/gotowu/article/details/46687633

1、首先要做Bluez协议栈的移植,这样在开发板上才可以用hciconfig, hcitool等命令。关于bluez协议栈的移植步骤网上很多。

2、该驱动是USB蓝牙设备驱动,分析根据蓝牙驱动的写的顺序进行。因为只是要做数据的传输,所以讲用于语音的等时传输部分去掉了。

首先,定义一个结构体


 
 
  1. struct bcm_data ={
  2. struct usb_endpoint_descriptor *intr_ep;
  3. struct usb_endpoint_descriptor *bulk_tx_ep; //批量传输的收端点
  4. struct usb_endpoint_descriptor *bulk_rx_ep; //批量传输的收端点
  5. struct usb_anchor tx_anchor; //用于阻塞操作
  6. struct usb_anchor intr_anchor;
  7. struct usb_anchor bulk_anchor;
  8. struct usb_device *udev;
  9. struct usb_interface *intf;
  10. unsigned long flags;
  11. __u8 cmdreq_type;
  12. }

接下来是入口函数和出口函数


 
 
  1. static int __ init bcm_driver_init(void)
  2. {
  3. usb_register(&bcm_driver);
  4. return 0;
  5. }
  6. static void __ exit bcm_driver_exit(void)
  7. {
  8. usb_deregister(&bcm_driver);
  9. }
  10. module_init(bcm_driver_init);
  11. module_exit(bcm_driver_exit);
  12. MODULE_LICENSE( "GPL");
  13. MODULE_AUTHOR( "WillwWu")

入口函数和出口函数是对该USB设备进行注册和注销的操作。

然后是定义struct usb_driver,并对其成员进行填充。


 
 
  1. static struct usb_driver bcm_driver={
  2. .name = "BCMT",
  3. .probe = bcm_probe, //探测函数
  4. .disconnect = bcm_disconnect,
  5. .id_table = bcm_table, //所支持的USB设备表
  6. .supports_autosuspend = 1, //支持自动挂起,若是设置为0则不支持
  7. .disable_hub_initiated_lpm = 1, //允许低功率态的传输
  8. };

支持的USB设备表


 
 
  1. static usb_device_id bcm_table[]={
  2. { USB_DEVICE( 0x0a5c, 0x2148)},
  3. {},
  4. }
  5. MODULE_DEVICE_TABLE(usb, bcm_table);

MODULE_DEVICE_TABLE用于输出到用户空间,以便于知道支持什么设备,第一个参数是所支持的类型,此处为USB。

下面来看看探测函数


 
 
  1. static int bcm_probe (struct usb_interface *intf ,const struct usb_device_id * id)
  2. {
  3. struct usb_endpoint_descriptor *ep_desc;
  4. struct hci_dev *hdev;
  5. struct bcm_data *data;
  6. int i,err;
  7. if(intf->cur_altsetting->desc.bInterfaceNumber != 0) //该接口的编号,端点0保留
  8. return -ENODEV;
  9. data=kzalloc( sizeof(*data) , GFP_KERNEL)
  10. if(!data)
  11. return -ENOMEM;
  12. for(i= 0;i<intf->cur_altsetting->desc.bNumEndpoints;i++){ //对端点描述符进行分配
  13. ep_desc = &intf->cur_altsetting->endpoint[i].desc;
  14. if(!data->intr_ep && usb_endpoint_is_int_in(ep_desc)){
  15. data->intr_ep=ep_desc;
  16. }
  17. if(!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)){
  18. data->bulk_tx_ep=ep_desc;
  19. }
  20. if(!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)){
  21. data->bulk_rx_ep=ep_desc;
  22. }
  23. if(!data->intr_ep||!data->bulk_tx_ep||!data->bulk_rx_ep){
  24. kfree(data);
  25. return -ENODEV;
  26. }
  27. }
  28. data->cmdreq_type=USB_TYPE_CLASS;
  29. data->udev=interface_to_usbdev(intf); //从接口描述符获取usb_device结构体信息并赋值
  30. data->intf=intf;
  31. init_usb_anchor(&data->tx_anchor); //初始化阻塞
  32. init_usb_anchor(&data->intr_anchor);
  33. init_usb_anchor(&data->bulk_anchor);
  34. hdev=hci_alloc_dev(); //申请一个hci_dev
  35. if(!hdev){
  36. kfree(data);
  37. return -ENOMEM;
  38. }
  39. hdev->bus = HCI_USB;
  40. hci_set_drvdata(hdev, data); //将data中的数据保存到hdev中
  41. data->hdev=hdev;
  42. SET_HCIDEV_DEV(hdev, intf->dev);
  43. /*设置hdev的各成员的函数指针*/
  44. hdev->open = bcm_open;
  45. hdev->close = bcm_close;
  46. hdev->flush = bcm_flush
  47. hdev->send =bcm_send;
  48. if (!reset)
  49. set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
  50. err=hci_register_dev(hdev) //注册hci_dev
  51. if (err < 0) {
  52. hci_free_dev(hdev);
  53. kfree(data);
  54. return err;
  55. }
  56. usb_set_intfdata(intf, data); //将data中的数据保存到intf中
  57. return 0;
  58. }

要区分一下的是:

bNumInterfaces : 配置所支持的接口数.指该配置配备的接口数量,也表示该配置下接口描述符数量.

bInterfaceNumber: 该接口的编号.

bNumEndpoint : 使用的端点数目.端点0除外.


 
 
  1. static void bcm_disconnect(struct usb_interface *intf)
  2. {
  3. struct bcm_data *data;
  4. struct hci_dev *hdev;
  5. if(!data)
  6. return ;
  7. hdev = data->hdev;
  8. intf = data->intf;
  9. usb_set_intfdata(intf, NULL);
  10. hci_unregister_dev( hdev);
  11. hci_free_dev( hdev);
  12. kfree(data);
  13. }

该函数所做的就是对probe函数中的注册等一系列操作的反操作。


 
 
  1. static int bcm_open(struct hci_dev *hdev)
  2. {
  3. ……
  4. if(test_and_set_bit(HCI_RUNNING, &hdev->flags))
  5. return 0;
  6. if(test_and_set_bit(BCM_INTR_RUNNING,&data->flags)) //BCM_INTR_RUNNING=0
  7. return 0;
  8. err=bcm_submit_intr_urb(hdev,GFP_KERNEL);
  9. if(err< 0)
  10. goto error;
  11. set_bit(BCM_BULK_RUNNING,&data->flags); //BCM_BULK_RUNNING=1
  12. err=bcm_submit_bulk_urb(hdev,GFP_KERNEL);
  13. ……
  14. error:
  15. clear_bit(HCI_RUNNING, &hdev->flags);
  16. clear_bit(BCM_INTR_RUNNING,&data->flags);
  17. clear_bit(BCM_BULK_RUNNING,&data->flags);
  18. return err;
  19. }

这个函数是probe中对hdev结构体成员的填充的。主要做就是设置data中的flags参数。其中要说的是set_bit函数,例如set(0,&a)指的是对a中的第0位设置为1.

这个函数的作用其实也是在做接收函数的初始化的操作,首先我们先看看err=bcm_submit_intr_urb(hdev,GFP_KERNEL);


 
 
  1. static int bcm_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
  2. {
  3. struct bcm_data *data=hci_get_drvdata(hdev) //获取data数据
  4. struct urb * urb;
  5. unsigned char *buf;
  6. unsigned int pipe;
  7. int err,size;
  8. if (!data->intr_ep)
  9. return -ENODEV;
  10. urb=usb_alloc_urb( 0, mem_flags); 分配一个 urb
  11. if (!urb)
  12. return -ENOMEM;
  13. size=le16_to_cpu(data->intr_ep->wMaxPacketSize); //设置最大包的长度大小
  14. buf=kzalloc(size, mem_flags); //分配一个缓冲区
  15. pipe=usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress); //设置USB的接收端点
  16. usb_fill_int_urb(urb, data->udev, pipe, buf, size, bcm_intr_complete, hdev ,data->intr_ep->bInterval); //这个时候就要对urb进行填充了,使用了中断urb
  17. urb->transfer_flags |=URB_FREE_BUFFER; //Free transfer buffer with the URB
  18. usb_anchor_urb(urb, &data->intr_anchor);
  19. err = usb_submit_urb(urb, mem_flags); //将填充的urb提交给usb core处理。
  20. if(err< 0)
  21. usb_unanchor_urb(urb);
  22. usb_free_urb(urb); //防止重复提交,先进行释放。
  23. return err;
  24. }

在usb_fill_int_urb中有个回调函数,当提交了urb后,将调用该回调函数bcm_intr_complete。


 
 
  1. static void bcm_intr_complete(struct urb *)
  2. {
  3. struct hci_dev *hdev = urb->context;
  4. struct bcm_data *data = hci_get_drvdata(hdev);
  5. int err;
  6. if(test_bit(HCI_RUNNING, &hdev->flags))
  7. return
  8. /*判断urb是否发送成功,若status为0,则表示数据被发送或者接受成功*/
  9. if(urb->status== 0){
  10. hdev->stat.byte_rx+=urb->actual_length;
  11. if(hci_recv_fragment( hdev,HCI_EVENT_PKT, urb->transfer_buffer, urb->actual_length)< 0)
  12. hdev->stat.err_rx++;
  13. }
  14. if(!test_bit(BCM_INTR_RUNNING, &data->flags));
  15. return;
  16. usb_anchor_urb(urb, &data->intr_anchor);
  17. err=usb_submit_urb(urb, GFP_KERNEL);
  18. if(err< 0){
  19. usb_unanchor_urb(urb);
  20. }
  21. }

帧的类型:

1) HCI_EVENT_PKT:     hci_event_packet() 处理来自Controller的事件 

2) HCI_ACLDATA_PKT: hci_acldata_packet() 处理ACL类型的数据包 

3) HCI_SCODATA_PKT: hci_scodata_packet() 处理SCO类型的数据包

hci_recv_fragment是bt协议栈数据接收函数。 hci_recv_fragmen 将数据帧放到hci_dev->rx_q链表尾部


 
 
  1. int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
  2. {
  3. int rem = 0;
  4. if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
  5. return -EILSEQ;
  6. while (count) {
  7. rem = hci_reassembly(hdev, type, data, count, type - 1);
  8. if (rem < 0)
  9. return rem;
  10. data += (count - rem);
  11. count = rem;
  12. }
  13. return rem;
  14. }

下面是批量传输的bulk_urb的初始化操作


 
 
  1. static int bcm_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
  2. {
  3. struct bcm_data *data=hci_get_drvdata(hdev);
  4. struct urb *urb;
  5. unsigned *buf;
  6. unsigned int pipe;
  7. int err,size = HCI_MAX_FRAME_SIZE;
  8. if(!data->bulk_rx_ep)
  9. return -ENODEV;
  10. urb=usb_alloc_urb( 0, mem_flags);
  11. if(!urb)
  12. return -ENOMEM;
  13. buf=kzalloc(size, mem_flags);
  14. pipe=usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
  15. usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, bcm_bulk_complete, hdev);
  16. usb_anchor_urb(urb, &data->bulk_anchor);
  17. err=usb_submit_urb(urb, mem_flags);
  18. if(err< 0)
  19. usb_unanchor_urb( urb)
  20. usb_free_urb(urb);
  21. return err;
  22. }

该函数的操作与上面那个中断的几乎相同,就是在usb_fill_bulk_urb时使用了批量urb。


 
 
  1. static void bcm_bulk_complete(struct urb *)
  2. {
  3. struct hci_dev *hdev = urb->context;
  4. struct bcm_data *data = hci_get_drvdata(hdev);
  5. int err;
  6. if(test_bit(HCI_RUNNING, &hdev->flags))
  7. return
  8. if(urb->status== 0){
  9. hdev->stat.byte_rx+=urb->actual_length;
  10. if(hci_recv_fragment( hdev,HCI_ACLDATA_PKT, urb->transfer_buffer, urb->actual_length)< 0)
  11. hdev->stat.err_rx++;
  12. }
  13. if(!test_bit(BCM_BULK_RUNNING, &data->flags));
  14. return;
  15. usb_anchor_urb(urb,& data->bulk_anchor);
  16. err=usb_submit_urb(urb, GFP_KERNEL);
  17. if(err< 0){
  18. usb_unanchor_urb(urb);
  19. }
  20. }

此处也与中断的一样。

下面来看看对于发送函数时如何进行操作的。在Linux中,定义了五种HCI数据包类型 

COMMAND/ACLDATA/SCODATA/EVENT/VENDOR,我们此处只对其中的COMMAND和ACLDATA进行发送。bcm_send用于提供给HCI去发送数据包。


 
 
  1. static int bcm_send (struct sk_buff *skb)
  2. {
  3. struct hci_dev *hdev = (struct hci_dev *) skb->dev;
  4. struct bcm_data *data=hci_get_drvdata( hdev);
  5. struct urb *urb;
  6. struct usb_ctrlrequest *cr;
  7. unsigned int pipe;
  8. if(!test_bit(HCI_RUNNING,&hdev->flags)) //每一步都要首先检测是否正在运行
  9. return -EBUSY;
  10. switch(bt_cb(skb)->pkt_type){ //从skb中的控制buffer中取出包的类型
  11. case HCI_COMMAND_PKT:
  12. urb=usb_alloc_urb( 0, GFP_ATOMIC);
  13. if(!urb)
  14. return -ENOMEM;
  15. cr=kmalloc( sizeof(*cr), GFP_ATOMIC);
  16. if(!cr){
  17. usb_free_urb(urb);
  18. return -ENOMEM;
  19. }
  20. cr->bRequestType = data->cmdreq_type;
  21. cr->bRequest = 0;
  22. cr->wIndex = 0;
  23. cr->wValue = 0;
  24. cr->wLength = __cpu_to_le16(skb->len);
  25. pipe = usb_sndctrlpipe(data->udev, 0x00);
  26. /*填充控制URB,这里我们需要注意的是,此处的数据缓冲区和数据的长度,都是由skb中的结构体成员进行设置的*/
  27. usb_fill_control_urb(urb, data->udev, pipe, ( void *) cr,skb->data, skb->len, bcm_tx_complete, skb);
  28. hdev->stat.cmd_tx++;
  29. break;
  30. case HCI_ACLDATA_PKT
  31. urb=usb_alloc_urb( 0, GFP_ATOMIC);
  32. if(!urb)
  33. return -ENOMEM;
  34. pipe=usb_sndbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
  35. usb_fill_bulk_urb( urb, data->udev, pipe, skb->data, skb->len, bcm_tx_complete, skb); //填充批量URB
  36. hdev->stat.acl_tx++;
  37. break;
  38. default:
  39. return -EILSEQ;
  40. }
  41. usb_anchor_urb(urb, &data->tx_anchor);
  42. err=usb_submit_urb(urb,GFP_ATOMIC);
  43. if(err< 0){
  44. kfree(urb->setup_packet);
  45. usb_unanchor_urb(urb);
  46. }
  47. return err;
  48. }

首先我们要来看看struct sk_buff 这个结构体。

sk_buff是Linux网络代码中最重要的结构体之一。它是Linux在其协议栈里传送的结构体,也就是所谓的“包”,在他里面包含了各层协议的头部,比如ethernet, ip ,tcp ,udp等等。并且他是一个复杂的双向链表,在他结构中有next和prev指针,分别指向链表的下一个节点和前一个节点.

此处的回调函数是bcm_tx_complete


 
 
  1. static void bcm_tx_complete(struct urb *)
  2. {
  3. struct sk_buff *skb=urb->context;
  4. struct hci_dev *hdev = (struct hci_dev *)skb->dev;
  5. struct bcm_data *data= hci_get_drvdata(hdev);
  6. if(!test_bit(HCI_RUNNING,&hdev->flags));
  7. goto done ;
  8. if(!urb->status)
  9. hdev->stat.byte_tx+=urb->transfer_buffer_length;
  10. else
  11. hdev->stat.err_tx++;
  12. done:
  13. kfree(urb->setup_packet);
  14. kfree_skb(skb);
  15. }

最后是close函数


 
 
  1. static int bcm_close(struct hci_dev *hdev)
  2. {
  3. struct bcm_data *data = hci_get_drvdata(hdev);
  4. if(!test_and_clear_bit(HCI_RUNNING,&hdev->flags))
  5. return 0;
  6. clear_bit(BCM_INTR_RUNNING, &data->flags);
  7. clear_bit(BCM_BULK_RUNNING, &data->flags);
  8. data->intf->needs_remote_wakeup= 0;
  9. return 0;
  10. }

就是针对data的flags进行位清零设置。

最后


 
 
  1. static int bcm_flush (struct hci_dev *hdev)
  2. {
  3. struct bcm_data *data=hci_get_drvdata( hdev)
  4. usb_kill_anchored_urbs(& data-> tx_anchor); //取消传输请求
  5. return 0;
  6. }




文章来源:https://blog.csdn.net/gotowu/article/details/46687633

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值