前言
现在调试的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);