• 蓝牙学习(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: (netluetooth*)
      • 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

    https://wiki.linuxfoundation.org/networking/sk_buff

  • 相关阅读:
    连接Excel文件时,未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序
    C# 中LinkLabel的简单使用
    体验安装金蝶K/3 Wise 13.0(图像)
    VS2008让自己掌控的定义编译项目后,自己主动添加到工具箱
    哥哥牟:由于道路的明星莫属,它救了我的女儿!
    【SSH之旅】一步学习的步Struts1相框(三):分析控制Struts1示例
    Ubuntu14.04 工作区设置
    Android定调的发展
    Spark1.0.0 学习路径
    oracle 11g 基于磁盘的备份rman duplicate
  • 原文地址:https://www.cnblogs.com/feiwatson/p/9514875.html
Copyright © 2020-2023  润新知