蓝牙学习(2)USB Adapter
主要分析一下蓝牙USB Adapter使用USB接口传输HCI包的实现及过程。
参照上面的Bluetooth core system architecture图, 蓝牙USB Adapter作为Bluetooth controller以USB的物理形式连接到Linux host processor上,通过HCI protocol和Host通信。
bluetooth in Linux kernel
Linux kernel side主要包括:
- Bluetooth Core: (net\bluetooth\*)
- HCI (Host Controller Interface) device and connection manager, schedule
- SCO (Synchronous Connection Oriented) audio links
- L2CAP (Logical Link Control and Adaptation Protocol)
- SMP (Security Manager Protocol) on LE (Low Energy) links
- HCI Device drivers (Interface to the hardware)
- USB (btusb)
- UART (hciuart)
- SDIO
- RFCOMM (RFCOMM Protocol for serial communication) Module (creates /dev/rfcomm serial devices)
- BNEP (Bluetooth Network Encapsulation Protocol) Module (creates /sys/class/net/bnep network interfaces)
- CMTP (CAPI Message Transport Protocol) Module
- HIDP (Human Interface Device Protocol) Module (creates /sys/class/input devices)
HCI device driver
HCI:Host Controller Interface
HCI提供了访问Controller的统一接口
Controller主要包含下面几种类型
- BR/EDR Controller
- BD/EDR/LE Controller
- LE Controller
- AMP Controller (Alternate MAC/PHY)
include/net/bluetooth/hci.h 中定义的HCI bus 接口类型包括:
/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
#define HCI_SDIO 6
#define HCI_SPI 7
#define HCI_I2C 8
#define HCI_SMD 9
btusb
bluetooth USB adapter是作为usb device挂载到USB总线上的。因此是通过usb_driver
提供的机制去probe,而不是直接通过platform_driver.
这点和i2c, SPI 等设备驱动都是类似的。
static struct usb_driver btusb_driver = {
.name = "btusb",
.probe = btusb_probe,
.disconnect = btusb_disconnect,
#ifdef CONFIG_PM
.suspend = btusb_suspend,
.resume = btusb_resume,
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
probe
在probe函数中, hci device的operators函数指针被赋值
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
//...
hdev->open = btusb_open;
hdev->close = btusb_close;
hdev->flush = btusb_flush;
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
//...
}
其中HCI Device数据结构定义, include/net/bluetooth/hci_core.h
struct hci_dev {
struct list_head list;
struct mutex lock;
char name[8];
unsigned long flags;
__u16 id;
__u8 bus;
__u8 dev_type;
//...
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
int (*setup)(struct hci_dev *hdev);
int (*shutdown)(struct hci_dev *hdev);
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
//...
}
接收发送数据
Bluetooth USB设备定义了不同的pipe用于不同类型的数据传输
- Control pipes are used to transport HCI commands.
- Interrupt pipes are responsible for carrying HCI events.
- Bulk pipes transfer asynchronous connectionless (ACL) Bluetooth data.
- Isochronous pipes carry SCO audio data.
static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct urb *urb;
BT_DBG("%s", hdev->name);
switch (hci_skb_pkt_type(skb)) {
case HCI_COMMAND_PKT:
urb = alloc_ctrl_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.cmd_tx++;
return submit_or_queue_tx_urb(hdev, urb);
case HCI_ACLDATA_PKT:
urb = alloc_bulk_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.acl_tx++;
return submit_or_queue_tx_urb(hdev, urb);
case HCI_SCODATA_PKT:
if (hci_conn_num(hdev, SCO_LINK) < 1)
return -ENODEV;
urb = alloc_isoc_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.sco_tx++;
return submit_tx_urb(hdev, urb);
}
return -EILSEQ;
}
接收中断处理:
注册
btusb_open -->
btusb_submit_intr_urb-->
//initialize a interrupt urb
usb_fill_int_urb(urb, data->udev, pipe, buf, size,
btusb_intr_complete, hdev, data->intr_ep->bInterval);
usb_complete_t 回调函数btusb_intr_complete
被注册
if (btusb_recv_intr(data, urb->transfer_buffer,
urb->actual_length) < 0) {
bt_dev_err(hdev, "corrupted event packet");
hdev->stat.err_rx++;
}
在btusb_recv_intr
函数中,数据被copy到skb. 内核中所有network相关的queue, buffer都用这个通用的结构体。
Reference
https://iotbreaks.com/base-knowledge-about-bluetooth/
http://www.embeddedlinux.org.cn/essentiallinuxdevicedrivers/final/ch16lev1sec1.html#ch16lev1sec1