精华内容
下载资源
问答
  • Android蓝牙驱动开发总结,详细解析蓝牙驱动的流程,非常好的资料!
  • Android之蓝牙驱动开发总结
  • Android 蓝牙驱动开发Android 之蓝牙驱动开发总结Android 蓝牙驱动开发一 Bluetooth 基本概念 1二 Android Bluetooth 架构 12.1 Bluetooth 架构图 12.2 Bluetooth 代码层次结构 3三 Bluetooth 协议栈分析 43.1 蓝牙...

    Android 蓝牙驱动开发

    Android 之蓝牙驱动开

    发总结

    Android 蓝牙驱动开发

    一 Bluetooth 基本概念 1

    二 Android Bluetooth 架构 1

    2.1 Bluetooth 架构图 1

    2.2 Bluetooth 代码层次结构 3

    三 Bluetooth 协议栈分析 4

    3.1 蓝牙协议栈 4

    3.2 Android 与蓝牙协议栈的关 5

    四 Bluetooth 之 HCI 层分析 5

    4.1 HCI 层与基带的通信方式 6

    4.2 包的分析及研究 7

    4.3 通信过程的研究与分析 8

    五 Bluetooth 之编程实现 8

    5.1 HCI 层编程 8

    5.2 L2CAP 层编程 10

    5.3 SDP 层编程 12

    六 Bluetooth 之启动过程实现 13

    6.1 Bluetooth 启动步骤 14

    6.2 Bluetooth 启动流程 14

    6.3 Bluetooth 数据流向 14

    6.4 Bluez 控制流程 14

    6.5 Bluetooth 启动过程分析 15

    七 Bluetooth 之驱动移植 15

    7.1 android 系统配置 15

    7.2 启动项修改 16

    7.3 电源管理rfkill 驱动 16

    7.4 Rebuild Android image and reboot 16

    7.5 实现 BT 睡眠唤醒机制 16

    7.6 系统集成 17

    八 Bluetooth 之调试与编译 17

    8.1 Bluetooth 驱动调试 17

    Android 蓝牙驱动开发

    8.2 Bluetooth 调试工具 18

    九 Bluetooth 之应用程序开发 18

    9.1 Bluetooth 的AP

    展开全文
  • Android蓝牙开发必备,是初学者,初级工程师学习Android 蓝牙的必备手册。 主要分为三部分 1.打开蓝牙; 2.查找附近已配对或可用的设备; 3.连接设备; 4.设备间数据 交换。
  • 蓝牙USB驱动开发.pdf

    2010-08-23 13:27:24
    :论述了在Linux操作系统环境下,蓝牙无线收发模块的USB驱动程序的开发过程,对在Lin. ux系统环境下开发一般USB设备类驱动程序进行了归纳与总结.根据该开发模块,可相对容易地 开发其它USB设备类驱动程序,因此,...
  • 在开发蓝牙HCI层驱动的时候,代码中会有BCCMD协议层和BCSP层,这两层对驱动开发相当重要,这个文档主要介绍了BCMMD的一些知识,对驱动开发相当有用。
  • 在开发蓝牙HCI层驱动的时候,代码中会有BCCMD协议层和BCSP层,这两层对驱动开发相当重要,这个文档主要介绍了BCSP和bccmd的一些知识,对驱动开发相当有用。
  • BlueSoleil蓝牙驱动

    2011-10-01 21:31:43
    BlueSoleil系列是由IVT公司开发的蓝牙软件管理器产品,通俗讲就是蓝牙驱动程序,是目前行业内最流行的蓝牙PC软件。基于多种平台的BlueSoleil,能实现台式机或笔记本等各种计算机平台间的无线连接,并且还能用户无线...
  • bluez是蓝牙协议栈的另外一种实现,Linux内核的默认实现。

    在这里插入图片描述

    =>返回专栏总目录<=

    一、蓝牙硬件接口有哪些?

    蓝牙芯片通过UARTUSBSDIOI2CPcCard和主控芯片通信

    二、协议栈如何与蓝牙驱动交互?

    三、协议栈介绍

    什么是bluedroid?

    bluedroid:蓝牙协议栈的实现,包括 基础通讯协议、Profile协议

    展开全文
  • linux下蓝牙驱动代码

    2010-05-27 17:47:15
    linux下自学开发蓝牙驱动,该蓝牙基于USB接口
  • CP210x_Windows_Drivers_蓝讯蓝牙开发串口下载官方驱动. 蓝讯开发下载时, 建议使用CP2102芯片的串口模块, 经过大量测试和使用, 此串口芯片在1.5M工作稳定性最好的. 该驱动已测试在WIN10/WIN7/XP, 64bit/32bit中均...
  • 基于Linux的蓝牙无线模块USB驱动程序的开发.pdf
  • Linux 下蓝牙驱动移植

    千次阅读 2014-11-06 11:12:27
    蓝牙驱动移植 转自:http://blog.sina.com.cn/s/blog_7834f3e90100r57c.html 我的蓝牙设备是:USB蓝牙,芯片制造商: CSR, 芯片型号: 41B14。芯片上贴的是AS6320QA。可见是水货。但在windows下测试可以使用。 ...

    蓝牙驱动移植
    转自:http://blog.sina.com.cn/s/blog_7834f3e90100r57c.html

    作者蓝牙设备是:USB蓝牙,芯片制造商: CSR,  芯片型号: 41B14。芯片上贴的是AS6320QA。可见是水货。但在windows下测试可以使用。


    [A]   内核配置  

    Linux 2.6版本之后的内核一般都有蓝牙模块的配置,所以不用再打补丁了。一般在配置内核的时候选择如下选项:

    [*] Networking support  --->                

    <*>   Bluetooth subsystem support  --->  //蓝牙子系统必须选择

    <*>   L2CAP protocol suppor       //逻辑链路控制和适配协议。

    <*>   SCO links support            //蓝牙语音和耳机支持

    <*>   RFCOMM protocol suppor       //面向流的传输协议,支持拨号网络等

    [*]   RFCOMM TTY support          

    <*>   BNEP protocol support        //蓝牙网络封装协议,自组网支持

    [*]   Multicast filter support     //蓝牙多播,支持支持BNEP

    [*]   Protocol filter support //蓝牙多播,支持支持支持BNEP

    <*>   HIDP protocol support        //基本支持协议

    Bluetooth device drivers  --->

    <*> HCI USB driver               //USB蓝牙模块支持

    <M>HCI UART driver               //基于串口,CF卡或PCMCIA的蓝牙

    <*> HCI BlueFRITZ! USB driver

    <*> HCI VHCI (Virtual HCI device) driver

    其余的选项,根据自己的蓝牙设备进行调整。


    [B]     蓝牙协议栈移植

    a)       需要的软件包

    可以在http://sourcearchive.com/下载多用到的所有软件包

     (1) D-Bus library 提供简单的应用程序互相通讯

    下载地址:http://www.freedesktop.org/wiki/Software/dbus#Download

     (2) GLib library    GLib是GTK+和GNOME工程的基础底层核心程序库,是一个综合用途的实用的轻量级的C程序库,它提供C语言的常用的数据结构的定义、相关的处理函数,有趣而实用的宏,可移植的封装和一些运行时机能,如事件循环、线程、动态调用、对象系统等的API。它能够在类UNIX的操作系统平台(如LINUX, HP-UNIX等),WINDOWS,OS2和BeOS等操作系统台上运行。

    下载地址:http://ftp.gnome.org/pub/gnome/sources/glib/2.26/

    (3) USB library (optional) 是一个用C语言开发的跨平台的USB设备访问接口库。

    下载地址:http://www.libusb.org/

    (4) Lexical Analyzer (flex或 lex)          词法分析器

    下载地址:http://linux.softpedia.com/get/Programming/Interpreters/Flex-23296.shtml

    (5)YACC (yacc, bison, byacc)           Unix/Linux上一个用来生成编译器的编译器(编译器代码生成器)

    下载地址:http://invisible-island.net/byacc/byacc.html

    (6) alsa-libALSA 应用

    下载地址:http://www.alsa-project.org/

    b)        解压编译

    在编译之前,首先将下载的所有包都放在 bluetooth 文件夹下。并在该文件夹下建立 bluetooth-build 文件夹,并将其输出到环境变量。

    #cd  Bluetooth

    #mkdir  bluetooth-build

    #blue=$PWD/bluetooth-build

    #export blue

    #export          //检查是否包含blue环境变量

    (1)     编译 alsa-lib 库

    #tar  -jxvf alsa-lib-1.0.24.1.tar.bz2

    #cd alsa-lib-1.0.24.1

    #./configure --prefix=$blue CC=arm-linux-gcc --host=arm-linux --disable-python

    #make

    #make install

    (2)     编译 expat

    #tar –zxvf expat-2.0.1.tar.gz

    #cd expat-2.0.1

    #./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux

    #make

    #make install

    (3)     D-Bus

    #tar  dbus-1.4.1.tar.gz

    #cd  dbus-1.4.1

    配置configure:

    #echo ac_cv_have_abstract_sockets=yes>arm-linux.cache

    #./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux--cache-file=arm-linux.cache --with-x=no

    (4)     编译 glib 库

    #vi arm-linux.cache

    在其中输入如下内容:

    glib_cv_long_long_format=ll

    glib_cv_stack_grows=no

    glib_cv_working_bcopy=no

    glib_cv_sane_realloc=yes

    glib_cv_have_strlcpy=no

    glib_cv_va_val_copy=yes

    glib_cv_rtldglobal_broken=no

    glib_cv_uscore=no

    ac_cv_func_posix_getpwuid_r=yes

    ac_cv_func_nonposix_getpwuid_r=no

    ac_cv_func_posix_getgrgid_r=no

    glib_cv_use_pid_surrogate=no

    ac_cv_func_printf_unix98=no

    ac_cv_func_vsnprintf_c99=no

    ac_cv_path_GLIB_COMPILE_SCHEMAS=yes

    或者不建立arm-linux.chach文件,直接输入如下命令也可以:

    echo glib_cv_long_long_format=ll>arm-linux.cache

    echo glib_cv_stack_grows=no>>arm-linux.cache

    echo glib_cv_working_bcopy=no>>arm-linux.cache

    echo glib_cv_sane_realloc=yes>>arm-linux.cache

    echo glib_cv_have_strlcpy=no>>arm-linux.cache

    echo glib_cv_va_val_copy=yes>>arm-linux.cache

    echo glib_cv_rtldglobal_broken=no>>arm-linux.cache

    echo glib_cv_uscore=no>>arm-linux.cache

    echo ac_cv_func_posix_getpwuid_r=yes>>arm-linux.cache

    echo ac_cv_func_nonposix_getpwuid_r=no>>arm-linux.cache

    echo ac_cv_func_posix_getgrgid_r=no>>arm-linux.cache

    echo glib_cv_use_pid_surrogate=no>>arm-linux.cache

    echo ac_cv_func_printf_unix98=no>>arm-linux.cache

    echo ac_cv_func_vsnprintf_c99=no>>arm-linux.cache

    echo ac_cv_path_GLIB_COMPILE_SCHEMAS=yes>>arm-linux.cache

     

    然后保存退出。如果不创建该文件,编译总出现…can’t run test program …错误

    #./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux --cache-file=arm-linux.cache

    如果继续出错,记录下提示error错误行的上一行,如:

    checking abstract socket namespace...

    configure: error: cannot run test program while cross compiling

    注意到abstract socket namespace在configure中查找abstract socket可以看到类似这样的结构

    echo "$as_me:$LINENO: checking abstract socket namespace" >&5

    echo $ECHO_N "checking abstract socket namespace... $ECHO_C" >&6

    if test "${ac_cv_have_abstract_sockets+set}" = set; then

    echo $ECHO_N "(cached) $ECHO_C" >&6

    其中ac_cv_have_abstract_sockets是我们要查找的变量。然后在当前目录下的arm-linux.cache中加入:echo ac_cv_have_abstract_sockets=yes

     

    #make

    出现如下错误:

    (process:18811): GLib-Genmarshal-WARNING **: unknown type: VARIANT

    make[2]: *** [stamp-gmarshal.h] 错误 1

    make[2]: Leaving directory `/root/mywork/mini2440/bluetooth/glib-2.26.0/gobject'

    make[1]: *** [all-recursive] 错误 1

    make[1]: Leaving directory `/root/mywork/mini2440/bluetooth/glib-2.26.0'

    make: *** [all] 错误 2

    出现如上错误好像是文件格式错误引起的。解决办法如下:

    第一次出错:将其中唯一的一行注释掉!

    #vi gobject/stamp-gmarshal.h

    第二次出错:将如下文件的开头空行删除。

    #vi gobject/gmarshal.c

    这时候,继续编译就通过了。!

    #vi tests/gobject/stamp-testmarshal.h

    什么也不输入,保存退出即可。

    (5)     编译 bluez

    #tar  -zxvf  bluez-4.87.tar.gz

    #cd  bluez-4.87

    # ./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux

    #make

    #make  install

    编译顺利,没初现错误。

    (6)     编译YACC

    #tar  -zxvf  byacc.tar.gz

    #cd  byacc-20101127

    # ./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux

    #make

    #make  install

    (7)     编译USB library

    #tar  -zxvf  libusb-1.0.8.tar.bz2

    #cd  libusb-1.0.8

    # ./configure --prefix=$blue CC="arm-linux-gcc -I$blue/include -L$blue/lib " --host=arm-linux

    #make

    #make  install

    至此,所有的软件包都编译完成!

    (8)     复制生成的软件到开发板

    1)      将bluetooth-build/sbin下的文件复制到开发板的/sbin下

    #cp  bluetooth-build/sbin/*    ROOTFS/sbin               //ROOTFS自己指定

    #cp  bluetooth-build/bin/hcitool         ROOTFS/bin/

    #cp  bluetooth-build/bin/rfcomm              ROOTFS/bin/

    #cp  bluetooth-build/bin/sdptool              ROOTFS/bin/

     

    2)      复制相关的库到开发板的/lib下

    #cp  Bluetooth-build/lib/libbluetooth*    ROOTFS/lib         //ROOTFS自己指定

    3)      复制配置文件到开发板的/etc目录下

    #cp  -arf bluetooth-build/etc/bluetooth/    ROOTFS/etc/          //ROOTFS自己指定

     

    [C]     蓝牙测试

    1.检查是否有蓝牙设备

    在插入蓝牙到到USB口前后,用 lsusb 命令可以发现输出内容不一样。即插入蓝牙设备后 lsusb 输出多了一行。然后,运行 hciconfig 可以看到:

    #hciconfig

    hci0:       Type: BR/EDR  Bus: USB

           BD Address: 00:00:00:00:00:00  ACL MTU: 0:0  SCO MTU: 0:0

           DOWN

           RX bytes:0 acl:0 sco:0 events:0 errors:0

           TX bytes:0 acl:0 sco:0 commands:0 errors:0

    上面的信息说明检测到了蓝牙设备hci0。

    2.激活蓝牙设备

    #hciconfig hci0 up

    可以激活借口(这一步不做,hcitool scan无法运行) 。这时候如果再次执行hciconfg命令,可以发现蓝牙以及激活(UP RUNNING):

    hci0:       Type: BR/EDR  Bus: USB

           BD Address: 00:1F:81:00:02:DD  ACL MTU: 1021:4  SCO MTU: 180:1

           UP RUNNING

           RX bytes:342 acl:0 sco:0 events:10 errors:0

           TX bytes:33 acl:0 sco:0 commands:11 errors:1

    3.扫描设备

    #hcitool scan

    可以得到:

    Scanning ...

           00:23:7A:F3:66:8D     BlackBerry 9000                这就是搜索到的设备(提前打开哦)

    4.修改配置文件:

    修改/etc/bluetooth/rfcomm.conf

    将里面的:device 11:22:33:44:55:66;

    修改成hcitool scan的结果,也就是:

    device 00:23:7A:F3:66:8D

    保存退出。

    rfcomm_create_dev。

    5.创建蓝牙设备

    运行:

    #rfcomm_create_dev。

     


    展开全文
  • rtl8822驱动资料,包含bs,bu蓝牙驱动,移植文档,芯片手册。
  • linux下的蓝牙驱动程序详解

    万次阅读 2015-06-29 21:51:07
    2、该驱动是USB蓝牙设备驱动,分析根据蓝牙驱动的写的顺序进行。因为只是要做数据的传输,所以讲用于语音的等时传输部分去掉了。 首先,定义一个结构体 struct bcm_data ={ struct usb_endpoint_descriptor

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

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

    首先,定义一个结构体

    struct bcm_data ={
    	struct usb_endpoint_descriptor *intr_ep;
    	struct usb_endpoint_descriptor *bulk_tx_ep;     //批量传输的收端点
    	struct usb_endpoint_descriptor *bulk_rx_ep;    //批量传输的收端点
    
    	struct usb_anchor tx_anchor;             //用于阻塞操作
    	struct usb_anchor intr_anchor;
    	struct usb_anchor bulk_anchor;
    
    	struct usb_device *udev;
    	struct usb_interface *intf;
    
    	unsigned long flags;
    
    	__u8 cmdreq_type;
    }

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

    static int __init bcm_driver_init(void)
    {
    	usb_register(&bcm_driver);
    	return 0;
    }
    
    static void __exit bcm_driver_exit(void)
    {
    	usb_deregister(&bcm_driver);
    }
    module_init(bcm_driver_init);
    module_exit(bcm_driver_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("WillwWu")

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

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

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

    支持的USB设备表

    static usb_device_id bcm_table[]={
    	{	USB_DEVICE(0x0a5c, 0x2148)},
    		{},
    }
    MODULE_DEVICE_TABLE(usb, bcm_table);

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

    下面来看看探测函数

    static int bcm_probe (struct usb_interface *intf ,const struct usb_device_id * id)
    {
    	struct usb_endpoint_descriptor *ep_desc;
    	struct hci_dev  *hdev;
    	struct bcm_data *data;
    	int  i,err;
    
    	if(intf->cur_altsetting->desc.bInterfaceNumber !=0)   //该接口的编号,端点0保留
    		return -ENODEV;
    	data=kzalloc( sizeof(*data) ,  GFP_KERNEL)
    		if(!data)
    			return -ENOMEM;
    	for(i=0;i<intf->cur_altsetting->desc.bNumEndpoints;i++){   //对端点描述符进行分配
    			ep_desc = &intf->cur_altsetting->endpoint[i].desc;
    			if(!data->intr_ep && usb_endpoint_is_int_in(ep_desc)){
    				data->intr_ep=ep_desc;
    				}
    			if(!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)){
    
    				data->bulk_tx_ep=ep_desc;
    				}
    			if(!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)){
    				data->bulk_rx_ep=ep_desc;
    				}
    			if(!data->intr_ep||!data->bulk_tx_ep||!data->bulk_rx_ep){
    				kfree(data);
    				return -ENODEV;
    		}	
    		}
    	data->cmdreq_type=USB_TYPE_CLASS;
    	data->udev=interface_to_usbdev(intf); //从接口描述符获取usb_device结构体信息并赋值
    	data->intf=intf;
    
    	init_usb_anchor(&data->tx_anchor);    //初始化阻塞
    	init_usb_anchor(&data->intr_anchor);
    	init_usb_anchor(&data->bulk_anchor);
    
    	hdev=hci_alloc_dev();        //申请一个hci_dev
    	if(!hdev){
    		kfree(data);
    		return -ENOMEM;
    		}
    	hdev->bus = HCI_USB;
    	hci_set_drvdata(hdev, data);    //将data中的数据保存到hdev中
    	data->hdev=hdev;
    	SET_HCIDEV_DEV(hdev, intf->dev);
    	/*设置hdev的各成员的函数指针*/
    	hdev->open = bcm_open;  
    	hdev->close = bcm_close;
    	hdev->flush  = bcm_flush
    	hdev->send  =bcm_send;
    	
    	if (!reset)
    		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); 
    	err=hci_register_dev(hdev) //注册hci_dev
    	if (err < 0) {
    		hci_free_dev(hdev);
    		kfree(data);
    		return err;
    			}
    	usb_set_intfdata(intf, data);  //将data中的数据保存到intf中
    	
    	return 0;
    }

    要区分一下的是:

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

    bInterfaceNumber: 该接口的编号.

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

    static void bcm_disconnect(struct usb_interface *intf)
    {
    	struct bcm_data *data;
    	struct hci_dev *hdev;
    
    	if(!data)
    		return ;
    	hdev = data->hdev;
    	intf = data->intf;
    	usb_set_intfdata(intf, NULL);
    	hci_unregister_dev( hdev);
    	hci_free_dev( hdev);
    	kfree(data);
    }

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

    static int bcm_open(struct hci_dev *hdev)
    {
    	……
    	if(test_and_set_bit(HCI_RUNNING, &hdev->flags))
    		return 0;
    	if(test_and_set_bit(BCM_INTR_RUNNING,&data->flags))//BCM_INTR_RUNNING=0
    		return 0;
    	err=bcm_submit_intr_urb(hdev,GFP_KERNEL);
    	if(err<0)
    		goto error;
    	set_bit(BCM_BULK_RUNNING,&data->flags);    //BCM_BULK_RUNNING=1                
    	err=bcm_submit_bulk_urb(hdev,GFP_KERNEL);
    ……
    error:
    	clear_bit(HCI_RUNNING, &hdev->flags);
    	clear_bit(BCM_INTR_RUNNING,&data->flags);
    	clear_bit(BCM_BULK_RUNNING,&data->flags);
    	return err;
    }

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

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

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

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

    static void bcm_intr_complete(struct urb *)
    {
    	struct hci_dev *hdev = urb->context;
    	struct bcm_data *data = hci_get_drvdata(hdev);
    	int err;
    
    	if(test_bit(HCI_RUNNING, &hdev->flags))
    		return 
    /*判断urb是否发送成功,若status为0,则表示数据被发送或者接受成功*/
    	if(urb->status==0){
    		hdev->stat.byte_rx+=urb->actual_length;
    		if(hci_recv_fragment( hdev,HCI_EVENT_PKT, urb->transfer_buffer, urb->actual_length)<0)
    			hdev->stat.err_rx++;
    		}
    	if(!test_bit(BCM_INTR_RUNNING, &data->flags));
    		return;
    	usb_anchor_urb(urb, &data->intr_anchor);
    	err=usb_submit_urb(urb, GFP_KERNEL);
    	if(err<0){
    		usb_unanchor_urb(urb);
    	}
    }

    帧的类型:

    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链表尾部

    int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
    {
    	int rem = 0;
    
    	if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
    		return -EILSEQ;
    
    	while (count) {
    		rem = hci_reassembly(hdev, type, data, count, type - 1);
    		if (rem < 0)
    			return rem;
    
    		data += (count - rem);
    		count = rem;
    	}
    
    	return rem;
    }

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

    static int bcm_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
    {
    	struct bcm_data *data=hci_get_drvdata(hdev);
    	struct urb *urb;
    	unsigned *buf;
    	unsigned int pipe;
    	int err,size = HCI_MAX_FRAME_SIZE;
    
    	if(!data->bulk_rx_ep)
    		return -ENODEV;
    	urb=usb_alloc_urb(0, mem_flags);
    	if(!urb)
    		return -ENOMEM;
    	buf=kzalloc(size, mem_flags);
    	pipe=usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
    	usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, bcm_bulk_complete, hdev);
    	usb_anchor_urb(urb, &data->bulk_anchor);
    	err=usb_submit_urb(urb, mem_flags);
    	if(err<0)
    		usb_unanchor_urb( urb)
    	usb_free_urb(urb);
    	return err;
    
    }

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

    static void bcm_bulk_complete(struct urb *)
    {
    	struct hci_dev *hdev = urb->context;
    	struct bcm_data *data = hci_get_drvdata(hdev);
    	int err;
    
    	if(test_bit(HCI_RUNNING, &hdev->flags))
    		return 
    	if(urb->status==0){
    		hdev->stat.byte_rx+=urb->actual_length;
    		if(hci_recv_fragment( hdev,HCI_ACLDATA_PKT, urb->transfer_buffer, urb->actual_length)<0)
    			hdev->stat.err_rx++;
    		}
    	if(!test_bit(BCM_BULK_RUNNING, &data->flags));
    		return;
    	usb_anchor_urb(urb,& data->bulk_anchor);
    	err=usb_submit_urb(urb, GFP_KERNEL);
    	if(err<0){
    		usb_unanchor_urb(urb);
    	}
    }
    

    此处也与中断的一样。

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

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

    static int bcm_send (struct sk_buff *skb)
    {
    	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
    	struct bcm_data *data=hci_get_drvdata( hdev);
    	struct urb *urb;
    	struct usb_ctrlrequest *cr;
    	unsigned int pipe;
    
    	if(!test_bit(HCI_RUNNING,&hdev->flags))     //每一步都要首先检测是否正在运行
    		return -EBUSY;
    	switch(bt_cb(skb)->pkt_type){           //从skb中的控制buffer中取出包的类型
    		case HCI_COMMAND_PKT:
    			urb=usb_alloc_urb(0, GFP_ATOMIC);
    			if(!urb)
    				return -ENOMEM;
    			cr=kmalloc(sizeof(*cr), GFP_ATOMIC);
    			if(!cr){
    				usb_free_urb(urb);
    				return -ENOMEM;
    				}
    			cr->bRequestType = data->cmdreq_type;
    			cr->bRequest     = 0;
    			cr->wIndex       = 0;
    			cr->wValue       = 0;
    			cr->wLength      = __cpu_to_le16(skb->len);
    
    			pipe = usb_sndctrlpipe(data->udev, 0x00);
     /*填充控制URB,这里我们需要注意的是,此处的数据缓冲区和数据的长度,都是由skb中的结构体成员进行设置的*/
    			usb_fill_control_urb(urb, data->udev, pipe, (void *) cr,skb->data, skb->len, bcm_tx_complete, skb); 
    			hdev->stat.cmd_tx++;
    			break;
    		case HCI_ACLDATA_PKT
    			urb=usb_alloc_urb(0, GFP_ATOMIC);
    			if(!urb)
    				return -ENOMEM;
    			pipe=usb_sndbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
    			usb_fill_bulk_urb( urb, data->udev, pipe, skb->data, skb->len, bcm_tx_complete, skb);   //填充批量URB
    			hdev->stat.acl_tx++;
    					break;
    		default:
    			return -EILSEQ;
    		}
    		usb_anchor_urb(urb, &data->tx_anchor);
    		err=usb_submit_urb(urb,GFP_ATOMIC);
    		if(err<0){
    			kfree(urb->setup_packet);
    			usb_unanchor_urb(urb);
    			}
    		return err;
    }

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

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

    此处的回调函数是bcm_tx_complete

    static void bcm_tx_complete(struct urb *)
    {	
    	struct sk_buff *skb=urb->context;
    	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
    	struct bcm_data *data= hci_get_drvdata(hdev);
    
    	if(!test_bit(HCI_RUNNING,&hdev->flags));
    		goto done ;
    	if(!urb->status)
    		hdev->stat.byte_tx+=urb->transfer_buffer_length;
    	else
    		hdev->stat.err_tx++;
    done:
    	kfree(urb->setup_packet);
    	kfree_skb(skb);
    }

    最后是close函数

    static int bcm_close(struct hci_dev *hdev)
    {
    	struct bcm_data *data = hci_get_drvdata(hdev);
    	if(!test_and_clear_bit(HCI_RUNNING,&hdev->flags))
    		return 0;
    	clear_bit(BCM_INTR_RUNNING, &data->flags);
    	clear_bit(BCM_BULK_RUNNING, &data->flags);
    	data->intf->needs_remote_wakeup=0;
    	return 0;
    }

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

    最后

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




    展开全文
  • 蓝牙串口USB驱动

    热门讨论 2012-08-15 09:39:31
    蓝牙串口USB驱动
  • linux 蓝牙驱动移植

    千次阅读 2013-08-09 00:36:10
    蓝牙驱动移植 转自:http://blog.sina.com.cn/s/blog_7834f3e90100r57c.html 我的蓝牙设备是:USB蓝牙,芯片制造商: CSR, 芯片型号: 41B14。芯片上贴的是AS6320QA。可见是水货。但在windows下测试可以使用。 ...
  • iOS蓝牙开发

    2018-10-29 16:20:23
    iOS蓝牙开发,手机APP与硬件设备通过蓝牙进行通信,传输数据
  • WinCE蓝牙驱动

    千次阅读 2009-11-24 10:24:00
    之前没有摸过蓝牙,这回的项目里面有蓝牙模块.而我目前对蓝牙只知道的有:1.我们的设计里蓝牙模块是连接在串口上的.2.蓝牙不是蓝色的牙齿.呵呵, ,我不得不提前开始接触一下蓝牙协议栈.粗看起来还挺复杂庞大的.单蓝牙...
  • mini2440 蓝牙驱动移植

    千次阅读 2013-05-06 16:10:13
    原文地址:蓝牙驱动移植">mini2440 蓝牙驱动移植 我的蓝牙设备是:USB蓝牙,芯片制造商: CSR, 芯片型号:41B14。芯片上贴的是AS6320QA。可见是水货。但在windows下测试可以使用。 Linux2.6版本之后的内核...
  • CSR蓝牙开发,包括环境的搭建以及相关的CSR蓝牙联系 网站等。 希望供给给有需要的人,加油,fight!
  • 2、重启后插入并启动你的蓝牙适配器(可能会自动安装相应驱动程序),会弹出蓝牙设备未激活的提示窗(可不理它)(这里请注意:要在系统托盘右键单击蓝牙图标,再左键点击“启动蓝牙”!否则下步可能出现“please ...
  • 本节我们主要是从下面2个方面进行讲解:1.准备工作、2. 蓝牙nRF51822开发板驱动
  • 蓝牙模组驱动开发为例介绍状态机在物联网模组嵌入式AT指令开发中的应用,通过状态跳变,完成每个状态的事情,配合多次指令下发以及延时,稳定可靠的驱动模组。
  • 迷你4WD Arduino机器人,由蓝牙控制。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,988
精华内容 5,995
关键字:

蓝牙驱动开发