linux下的蓝牙驱动程序详解

http://blog.csdn.net/gotowu/article/details/46687633


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

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

首先,定义一个结构体

[cpp]  view plain  copy
  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.   
  6.     struct usb_anchor tx_anchor;             //用于阻塞操作  
  7.     struct usb_anchor intr_anchor;  
  8.     struct usb_anchor bulk_anchor;  
  9.   
  10.     struct usb_device *udev;  
  11.     struct usb_interface *intf;  
  12.   
  13.     unsigned long flags;  
  14.   
  15.     __u8 cmdreq_type;  
  16. }  

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

[cpp]  view plain  copy
  1. static int __init bcm_driver_init(void)  
  2. {  
  3.     usb_register(&bcm_driver);  
  4.     return 0;  
  5. }  
  6.   
  7. static void __exit bcm_driver_exit(void)  
  8. {  
  9.     usb_deregister(&bcm_driver);  
  10. }  
  11. module_init(bcm_driver_init);  
  12. module_exit(bcm_driver_exit);  
  13. MODULE_LICENSE("GPL");  
  14. MODULE_AUTHOR("WillwWu")  

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

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

[cpp]  view plain  copy
  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设备表

[cpp]  view plain  copy
  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

下面来看看探测函数

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

要区分一下的是:

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

bInterfaceNumber: 该接口的编号.

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

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

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

[cpp]  view plain  copy
  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函数,例如set0&a)指的是对a中的第0位设置为1.

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

[cpp]  view plain  copy
  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.   
  9.     if (!data->intr_ep)  
  10.         return -ENODEV;  
  11.     urb=usb_alloc_urb(0, mem_flags);    分配一个urb  
  12.     if(!urb)  
  13.         return -ENOMEM;  
  14.     size=le16_to_cpu(data->intr_ep->wMaxPacketSize);   //设置最大包的长度大小  
  15.     buf=kzalloc(size, mem_flags);                 //分配一个缓冲区  
  16.     pipe=usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress); //设置USB的接收端点  
  17.     usb_fill_int_urb(urb, data->udev, pipe, buf, size, bcm_intr_complete, hdev ,data->intr_ep->bInterval);     //这个时候就要对urb进行填充了,使用了中断urb  
  18.     urb->transfer_flags |=URB_FREE_BUFFER;//Free transfer buffer with the URB  
  19.     usb_anchor_urb(urb, &data->intr_anchor);  
  20.     err = usb_submit_urb(urb, mem_flags); //将填充的urb提交给usb core处理。  
  21.     if(err<0)  
  22.         usb_unanchor_urb(urb);  
  23.     usb_free_urb(urb);   //防止重复提交,先进行释放。  
  24.     return err;  
  25. }  

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

[cpp]  view plain  copy
  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.   
  7.     if(test_bit(HCI_RUNNING, &hdev->flags))  
  8.         return   
  9. /*判断urb是否发送成功,若status为0,则表示数据被发送或者接受成功*/  
  10.     if(urb->status==0){  
  11.         hdev->stat.byte_rx+=urb->actual_length;  
  12.         if(hci_recv_fragment( hdev,HCI_EVENT_PKT, urb->transfer_buffer, urb->actual_length)<0)  
  13.             hdev->stat.err_rx++;  
  14.         }  
  15.     if(!test_bit(BCM_INTR_RUNNING, &data->flags));  
  16.         return;  
  17.     usb_anchor_urb(urb, &data->intr_anchor);  
  18.     err=usb_submit_urb(urb, GFP_KERNEL);  
  19.     if(err<0){  
  20.         usb_unanchor_urb(urb);  
  21.     }  
  22. }  

帧的类型:

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_fragmentbt协议栈数据接收函数。 hci_recv_fragmen 将数据帧放到hci_dev->rx_q链表尾部

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

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

[cpp]  view plain  copy
  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.   
  9.     if(!data->bulk_rx_ep)  
  10.         return -ENODEV;  
  11.     urb=usb_alloc_urb(0, mem_flags);  
  12.     if(!urb)  
  13.         return -ENOMEM;  
  14.     buf=kzalloc(size, mem_flags);  
  15.     pipe=usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);  
  16.     usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, bcm_bulk_complete, hdev);  
  17.     usb_anchor_urb(urb, &data->bulk_anchor);  
  18.     err=usb_submit_urb(urb, mem_flags);  
  19.     if(err<0)  
  20.         usb_unanchor_urb( urb)  
  21.     usb_free_urb(urb);  
  22.     return err;  
  23.   
  24. }  

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

[cpp]  view plain  copy
  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.   
  7.     if(test_bit(HCI_RUNNING, &hdev->flags))  
  8.         return   
  9.     if(urb->status==0){  
  10.         hdev->stat.byte_rx+=urb->actual_length;  
  11.         if(hci_recv_fragment( hdev,HCI_ACLDATA_PKT, urb->transfer_buffer, urb->actual_length)<0)  
  12.             hdev->stat.err_rx++;  
  13.         }  
  14.     if(!test_bit(BCM_BULK_RUNNING, &data->flags));  
  15.         return;  
  16.     usb_anchor_urb(urb,& data->bulk_anchor);  
  17.     err=usb_submit_urb(urb, GFP_KERNEL);  
  18.     if(err<0){  
  19.         usb_unanchor_urb(urb);  
  20.     }  
  21. }  

此处也与中断的一样。

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

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

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

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

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

此处的回调函数是bcm_tx_complete

[cpp]  view plain  copy
  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.   
  7.     if(!test_bit(HCI_RUNNING,&hdev->flags));  
  8.         goto done ;  
  9.     if(!urb->status)  
  10.         hdev->stat.byte_tx+=urb->transfer_buffer_length;  
  11.     else  
  12.         hdev->stat.err_tx++;  
  13. done:  
  14.     kfree(urb->setup_packet);  
  15.     kfree_skb(skb);  
  16. }  

最后是close函数

[cpp]  view plain  copy
  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. }  

就是针对dataflags进行位清零设置。

最后

[cpp]  view plain  copy
  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. }  

你可能感兴趣的:(linux)