Ubuntu系统(bluez)蓝牙调试

前言
现在调试的Ubuntu、debian系统,蓝牙上层的协议使用bluez,蓝牙的移植与bluedroid略有不同。本文主要介绍Ubuntu(蓝牙移植上debian与Ubuntu是一样的)系统下蓝牙移植的相关知识,并给出移植指导。涉及的知识点有bluez下蓝牙的驱动、hciattach的作用、蓝牙电源的控制、蓝牙移植修改点。

1 Bluez下内核蓝牙框架简介
使用Bluez时,需要内核提供一系列的socket接口来操作蓝牙,内核中蓝牙的框架如图1所示。蓝牙框架分成两部分:蓝牙socket部分及蓝牙驱动部分。蓝牙socket部分负责管理提供给bluez的socket,并包含L2cap层的功能;蓝牙驱动包含hci层协议及蓝牙硬件接口的管理。蓝牙socket部分与蓝牙驱动通过hci_core来连接。从Bluez下移植蓝牙方面看,只关心两个地方,一个是蓝牙驱动的移植,另一个是bluez的工具集中的hciattach工具(使用uart接口的蓝牙才需要这部分),

这里写图片描述

图1 内核中蓝牙框图
对比bluedroid与bluez在蓝牙移植方面的差异,最大的不同就是hci和L2cap层所处的位置,在bluedroid中,hci和L2cap层放在bluedroid中,是在内核之上。而bluez中,hci和L2cap层不属于bluez中的代码,而是放到内核里。

2 内核中的蓝牙
在Ubuntu系统下,Bluez的蓝牙驱动负责hci协议的处理、与蓝牙硬件交互数据、注册hci接口供蓝牙socket部分使用。

2.1 注册hci_core接口
不管是uart接口还是usb接口的蓝牙,都是通过hci_register_dev函数向hci_core层注册接口,下面为uart接口及usb接口蓝牙向hci_core层注册例子:

kernel\drivers\bluetooth\hci_ldisc.c
    hdev->bus = HCI_UART;
    hci_set_drvdata(hdev, hu);

hdev->open  = hci_uart_open;
    hdev->close = hci_uart_close;
    hdev->flush = hci_uart_flush;
    hdev->send  = hci_uart_send_frame;
    SET_HCIDEV_DEV(hdev, hu->tty->dev);

if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
        set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);

if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
        set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);

if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
        hdev->dev_type = HCI_AMP;
    else
        hdev->dev_type = HCI_BREDR;

if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
        return 0;

if (hci_register_dev(hdev) < 0)      //uart接口蓝牙注册

kernel\drivers\bluetooth\rtk_btusb_8723bu.c
    HDEV_BUS = HCI_USB;

data->hdev = hdev;

SET_HCIDEV_DEV(hdev, &intf->dev);

hdev->open    = btusb_open;
    hdev->close    = btusb_close;
    hdev->flush    = btusb_flush;
    hdev->send    = btusb_send_frame;
    hdev->notify  = btusb_notify;

#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)
    hci_set_drvdata(hdev, data);
#else
    hdev->driver_data = data;
    hdev->destruct = btusb_destruct;
    hdev->owner = THIS_MODULE;
#endif

……

err = hci_register_dev(hdev);        // usb接口蓝牙注册

Hci_core向蓝牙驱动传递数据通过hdev->send接口,而蓝牙驱动接收到数据后直接调用hci_core Export的hci_recv_frame、hci_recv_fragment接口提交数据。
在使用hci_register_dev注册接口的时候,hci_core会在rfkill下注册一个RFKILL_TYPE_BLUETOOTH类型的设备,名称为hciX。在Ubuntu系统中,只要发现rfkill下有注册RFKILL_TYPE_BLUETOOTH类型设备,就认为存在蓝牙设备,桌面上就会显示蓝牙图标,后面对蓝牙的开关操作就是通过rfkill下的接口。

2.2 蓝牙驱动的移植
现在调试过的蓝牙有uart接口和usb接口的,这两种接口的驱动是完全不同的,下面分别介绍。

2.2.1 USB接口蓝牙
对于usb接口的蓝牙,只要给蓝牙上电,usb枚举到蓝牙设备后,就会调用蓝牙驱动的probe函数,在该函数中就会向hci_core注册接口。

kernel\drivers\bluetooth\rtk_btusb_8723bu.c
    static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{

……

hdev = hci_alloc_dev();
    if (!hdev) {
        rtk_free(data);
        data = NULL;
        return -ENOMEM;
    }

HDEV_BUS = HCI_USB;

data->hdev = hdev;

SET_HCIDEV_DEV(hdev, &intf->dev);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/58c9968651d15f170d876cac89ac483f.html