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 = hst;
		ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;
		ti_st_proto[i].recv = st_receive;
		ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;

		/* Prepare wait-for-completion handler */
		init_completion(&hst->wait_reg_completion);
		/* Reset ST registration callback status flag,
		 * this value will be updated in
		 * st_reg_completion_cb()
		 * function whenever it called from ST driver.
		 */
		hst->reg_status = -EINPROGRESS;

		err = st_register(&ti_st_proto[i]);
		if (!err)
			goto done;

		if (err != -EINPROGRESS) {
			clear_bit(HCI_RUNNING, &hdev->flags);
			BT_ERR("st_register failed %d", err);
			return err;
		}

		/* ST is busy with either protocol
		 * registration or firmware download.
		 */
		BT_DBG("waiting for registration "
				"completion signal from ST");
		timeleft = wait_for_completion_timeout
			(&hst->wait_reg_completion,
			 msecs_to_jiffies(BT_REGISTER_TIMEOUT));
		if (!timeleft) {
			clear_bit(HCI_RUNNING, &hdev->flags);
			BT_ERR("Timeout(%d sec),didn't get reg "
					"completion signal from ST",
					BT_REGISTER_TIMEOUT / 1000);
			return -ETIMEDOUT;
		}

		/* Is ST registration callback
		 * called with ERROR status? */
		if (hst->reg_status != 0) {
			clear_bit(HCI_RUNNING, &hdev->flags);
			BT_ERR("ST registration completed with invalid "
					"status %d", hst->reg_status);
			return -EAGAIN;
		}

done:
		hst->st_write = ti_st_proto[i].write;
		if (!hst->st_write) {
			BT_ERR("undefined ST write function");
			clear_bit(HCI_RUNNING, &hdev->flags);
			for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
				/* Undo registration with ST */
				err = st_unregister(&ti_st_proto[i]);
				if (err)
					BT_ERR("st_unregister() failed with "
							"error %d", err);
				hst->st_write = NULL;
			}
			return -EIO;
		}
	}
	return 0;
}

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 = hst;
	hdev->open = ti_st_open;
	hdev->close = ti_st_close;
	hdev->flush = NULL;
	hdev->send = ti_st_send_frame;
	hdev->destruct = ti_st_destruct;
	hdev->owner = THIS_MODULE;

	err = hci_register_dev(hdev);
	if (err < 0) {
		BT_ERR("Can't register HCI device error %d", err);
		kfree(hst);
		hci_free_dev(hdev);
		return err;
	}

	BT_DBG("HCI device registered (hdev %p)", hdev);

	dev_set_drvdata(&pdev->dev, hst);
	return err;
}

设备探测

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 driver

static 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 与 exit

MODULE_AUTHOR("Raja Mani <[email protected]>");
MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

Texas Instrument's Bluetooth Driver For Shared Transport 笔记

时间: 2024-10-24 15:37:30

Texas Instrument's Bluetooth Driver For Shared Transport 笔记的相关文章

SpringCloud报错:com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

启动SpringCloudEureka 报错:com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server 解决方法: 先仔细检查,指定的注册中心 eureka.client.serviceUrl.defaultZone的地址是否正确,端口号有没有写错.然后,在application.yml 添加以下配置: #Eureka服务注册中心也会将自己作为客户端来

eureka server 集成security,eureka client报错com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

当前Spring Coud 版本(Greenwich.SR2)  Spring Boot版本 (2.1.6.RELEASE) 在eureka server 中集成security后,发现eureka client 去注册的时候报以下错误: ----------------------------------------------------------------------------------------------------------------------------------

Keyboard Input WDF Filter Driver (Kbfiltr)源代码学习笔记

WDF版本键盘过滤驱动——Kbfiltr The Kbdfltr sample is an example of a keyboard input filter driver. This sample is WDF version of the original WDM filter driver sample. The WDM version of this sample has been deprecated. This is an upper device filter driver sa

HDLC WINCE6驱动设计

1. WINCE的网络驱动结构 1.1  WINCE 网络结构 1)WINCE 的NDIS网络接口提供如下能力: miniport 网卡驱动接口 支持802.3(MAC),802.5(RING),IRDA 支持广域网 动态绑定网卡和Plug and Play 支持同一个协议绑定多个网卡 支持网卡的MediaSense 2)WINCE的网络结构图 从该通信结构中可以看到,所有的通信协议都使用NDIS WRAPPER 作为中介和下层的硬件绑定,实现各种不同的通信. 3)NDIS Wrapper的结构

理解Android系统(一)

理解Android系统 Android 是业界流行的开源移动平台,受到广泛关注并为多个手机制造商作为手机的操作系统平台.由于它的开放性,市面上又出现了它的很多改良定制版本.且广泛的应用在手机.汽车.电脑等领域.因此,研究其安全架构及权限控制机制具有非常的重要性. 本章从 Android 层次化安全架构入手,详细地介绍 Android 平台的安全架构及其权限控制机制,涵盖 Android 应用程序权限申请方法等,并从源代码实现层面来解析该机制. 1.1 系统的层级架构 Android架构,其实就是

windows 10 超级优化,同时解决本地磁盘100%的问题

我的系统是笔记本I7处理器,配置了web服务器IIS 和一个数据库(mysql7),同时启用了虚拟机(表中已禁用),以及安装了office2016 .qq等软件,开启了远程连接.无线网络,优化后的系统内存为1.5G,供参考,不用上述功能的可以把表中红色的也进士及禁用掉. 传说可以优化到500M的内存,试好了告诉我,也好学习一下. 在安全模式下,只需要13个进程便可启动系统,但程序及网络都无法使用,如下图 在正常模式下有很大不同,如想正常访问网络.识别硬件需要37个服务(文末也有一张表供参考) 大

ORA_ERROR大全

转自:http://blog.csdn.net/haiross/article/details/12839229 常见错误:-60 ORA00060: deadlock detected while waiting for resource 一般错误:  - 1 ORA00001: unique constraint (.) violated  -17 ORA00017: session requested to set trace event  -18 ORA00018: maximum nu

12C ORA-错误汇总5 ORA-04930 to ORA-07499

ORA-04930 to ORA-07499 6 ORA-04930: open sequence number failed or initial state is valid Cause: Either Shared Sequence Number OS component was not installed properly, or an MC hardware failure may have occurred or a previous instance was not shut do

微服务搭建中遇到的问题

前言 现在我所在的xx公司要重构用户系统.旧用户系统是一个单一应用系统.下游的各个系统通过调用用户系统实现对用户查询.登录.校验.菜单的管理.为了适应新的企业级架构模式,用微服务架构对旧用户系统进行重构. 其实,从单一应用系统到微服务架构的搭建,锻炼的是重构一个旧的单一应用项目的思路:单一应用==>微服务架构应用. 过程如下: 1.从熟悉原有的项目:需求文档.操作手册.数据库设计文档.对外接口.页面原型(对系统进行实操).对外接口的调用原理.(这里因为我对用户系统不是很熟悉,所以需要从各个方面熟