首页 > 代码库 > Texas Instrument's Bluetooth Driver For Shared Transport 笔记
Texas Instrument's Bluetooth Driver For Shared Transport 笔记
Bluetooth Driver acts as interface between HCI core and TI Shared Transport Layer.
/drivers/bluetooth/Btwilink.c:
#include <linux/platform_device.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci.h> #include <linux/ti_wilink_st.h> #include <linux/module.h> #define DEBUG #define VERSION "1.0" #define MAX_BT_CHNL_IDS 3#define BT_REGISTER_TIMEOUT 6000
struct ti_st { struct hci_dev *hdev; char reg_status; long (*st_write) (struct sk_buff *); struct completion wait_reg_completion; };struct ti_st - 模块操作结构体
@hdev: HCI 设备指针绑定到了蓝牙模块
@reg_status: ST 注册返回状态
@st_write: send_frame 用到的写函数
@wait_reg_completion - ti_st_open and st_reg_completion_cb之间的结束同步
static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type) { struct hci_dev *hdev = hst->hdev; /* Update HCI stat counters */ switch (pkt_type) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; } }pocket ID (cmd,acl,sco)计数
static void st_reg_completion_cb(void *priv_data, char data) { struct ti_st *lhst = priv_data; /* Save registration status for use in ti_st_open() */ lhst->reg_status = data; /* complete the wait in ti_st_open() */ complete(&lhst->wait_reg_completion); }status.ti_st_open() 函数 会等待st_register() 返回的ST_PENDING信号
static long st_receive(void *priv_data, struct sk_buff *skb) { struct ti_st *lhst = priv_data; int err; if (!skb) return -EFAULT; if (!lhst) { kfree_skb(skb); return -EFAULT; } skb->dev = (void *) lhst->hdev; /* Forward skb to HCI core layer */ err = hci_recv_frame(skb); if (err < 0) { BT_ERR("Unable to push skb to HCI core(%d)", err); return err; } lhst->hdev->stat.byte_rx += skb->len; return 0; }接收到数据时被Shared Transport层调用
static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = { { .chnl_id = HCI_EVENT_PKT, /* HCI Events */ .hdr_len = sizeof(struct hci_event_hdr), .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen), .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */ .reserve = 8, }, { .chnl_id = HCI_ACLDATA_PKT, /* ACL */ .hdr_len = sizeof(struct hci_acl_hdr), .offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen), .len_size = 2, /* sizeof(dlen) in struct hci_acl_hdr */ .reserve = 8, }, { .chnl_id = HCI_SCODATA_PKT, /* SCO */ .hdr_len = sizeof(struct hci_sco_hdr), .offset_len_in_hdr = offsetof(struct hci_sco_hdr, dlen), .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */ .reserve = 8, }, };HCI 层的接口
struct st_proto_s的定义:/include/linux/ti_wilink_st.h:
struct st_proto_s {
enum proto_type type;
long (*recv) (void *, struct sk_buff *);
unsigned char (*match_packet) (const unsigned char *data);
void (*reg_complete_cb) (void *, char data);
long (*write) (struct sk_buff *skb);
void *priv_data;
unsigned char chnl_id;
unsigned short max_frame_size; //能接收的最大帧的大小
unsigned char hdr_len; //头结构的长度
unsigned char offset_len_in_hdr; //提供头结构中的长度偏移
unsigned char len_size; //2字节或1字节
unsigned char reserve; //ST 需要交换的字节数 };
static int ti_st_open(struct hci_dev *hdev) { unsigned long timeleft; struct ti_st *hst; int err, i; BT_DBG("%s %p", hdev->name, hdev); if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; /* provide contexts for callbacks from ST */ hst = hdev->driver_data; for (i = 0; i < MAX_BT_CHNL_IDS; i++) { ti_st_proto[i].priv_data = http://www.mamicode.com/hst;>HCI core调用,初始化设备static int ti_st_close(struct hci_dev *hdev) { int err, i; struct ti_st *hst = hdev->driver_data; if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) { err = st_unregister(&ti_st_proto[i]); if (err) BT_ERR("st_unregister(%d) failed with error %d", ti_st_proto[i].chnl_id, err); } hst->st_write = NULL; return err; }关闭设备static int ti_st_send_frame(struct sk_buff *skb) { struct hci_dev *hdev; struct ti_st *hst; long len; hdev = (struct hci_dev *)skb->dev; if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; hst = hdev->driver_data; /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); /* Insert skb to shared transport layer's transmit queue. * Freeing skb memory is taken care in shared transport layer, * so don't free skb memory here. */ len = hst->st_write(skb); if (len < 0) { kfree_skb(skb); BT_ERR("ST write failed (%ld)", len); /* Try Again, would only fail if UART has gone bad */ return -EAGAIN; } /* ST accepted our skb. So, Go ahead and do rest */ hdev->stat.byte_tx += len; ti_st_tx_complete(hst, bt_cb(skb)->pkt_type); return 0; } static void ti_st_destruct(struct hci_dev *hdev) { BT_DBG("%s", hdev->name); /* do nothing here, since platform remove * would free the hdev->driver_data */ }发送帧static int bt_ti_probe(struct platform_device *pdev) { static struct ti_st *hst; struct hci_dev *hdev; int err; hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL); if (!hst) return -ENOMEM; /* Expose "hciX" device to user space */ hdev = hci_alloc_dev(); if (!hdev) { kfree(hst); return -ENOMEM; } BT_DBG("hdev %p", hdev); hst->hdev = hdev; hdev->bus = HCI_UART; hdev->driver_data = http://www.mamicode.com/hst;>设备探测static int bt_ti_remove(struct platform_device *pdev) { struct hci_dev *hdev; struct ti_st *hst = dev_get_drvdata(&pdev->dev); if (!hst) return -EFAULT; BT_DBG("%s", hst->hdev->name); hdev = hst->hdev; ti_st_close(hdev); hci_unregister_dev(hdev); hci_free_dev(hdev); kfree(hst); dev_set_drvdata(&pdev->dev, NULL); return 0; }设备卸载static struct platform_driver btwilink_driver = { .probe = bt_ti_probe, .remove = bt_ti_remove, .driver = { .name = "btwilink", .owner = THIS_MODULE, }, };platform driverstatic int __init btwilink_init(void) { BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION); return platform_driver_register(&btwilink_driver); } static void __exit btwilink_exit(void) { platform_driver_unregister(&btwilink_driver); } module_init(btwilink_init); module_exit(btwilink_exit);设备 init 与 exitMODULE_AUTHOR("Raja Mani <raja_mani@ti.com>"); MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL");Texas Instrument's Bluetooth Driver For Shared Transport 笔记