`
836811384
  • 浏览: 542286 次
文章分类
社区版块
存档分类
最新评论

[android源码分析]hci_init_req中的各种command和event的交互

 
阅读更多

在蓝牙中,host和controller之间的command和event的交互是底层各种工作开展的基础,在初始化的过程中必然也存在着类似的操作。本章会详细分析在hci_init_req过程中所涉及到的所有command和event的交互。至于command和event的格式意义,请参见bluetooth的core spec,这里不做详细介绍,若想详细了解,spec的研读是必不可少的。

static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
{
	struct hci_cp_delete_stored_link_key cp;
	struct sk_buff *skb;
	__le16 param;
	__u8 flt_type;

	BT_DBG("%s %ld", hdev->name, opt);

	/* Driver initialization */

	/* Special commands */
	//把hdev->driver_init中的cmd发送完成掉,然后清空hdev->driver_init这个queue
	while ((skb = skb_dequeue(&hdev->driver_init))) {
		bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
		skb->dev = (void *) hdev;

		skb_queue_tail(&hdev->cmd_q, skb);
		tasklet_schedule(&hdev->cmd_task);
	}
	skb_queue_purge(&hdev->driver_init);

	/* Mandatory initialization */

	/* Reset */
	//因为设置了no reset位,所以这里reset命令是不发送的
	if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
			set_bit(HCI_RESET, &hdev->flags);
			hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
	}
	//这里会连续发送几个cmd:
	//read local features, read local version, read buffer size, read bd addr, read class of device, read local name, read voice setting, set event filter, write connection accept timeout, delete stored link key
	//下面我们会对这些cmd进行逐个地分析
	/* Read Local Supported Features */
	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);

	/* Read Local Version */
	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);

	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);

	/* Read BD Address */
	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);

	/* Read Class of Device */
	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);

	/* Read Local Name */
	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);

	/* Read Voice Setting */
	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);

	/* Clear Event Filters */
	flt_type = HCI_FLT_CLEAR_ALL;
	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);

	/* Connection accept timeout ~20 secs */
//7d00*0.625ms=20s
	param = cpu_to_le16(0x7d00);
	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);

	bacpy(&cp.bdaddr, BDADDR_ANY);
	cp.delete_all = 1;
	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
}

这里各种cmd就已经发送出去了,下面就是对接收到的response要做一些处理了,首先我们来看一下对event是如何处理的。

在之前我们看到,hci dev注册的时候是启动了一个rxtask的,他就是用来接收的,所以我们直接去看一下它的处理

static void hci_rx_task(unsigned long arg){
……
	//对于event的处理,就是这里了,所以后期各个event都是这边进行处理的,不再详细地说明如何找了
		switch (bt_cb(skb)->pkt_type) {
		case HCI_EVENT_PKT:
			hci_event_packet(hdev, skb);
			break;
}

2.1.1.1 read local featuresevent的处理

spec中,我们知道,这个cmd的回应是一个commandcompleteevent。所以,直接去看command complete event的处理:

static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb){
……
	case HCI_OP_READ_LOCAL_FEATURES:
		hci_cc_read_local_features(hdev, skb);
		break;
}
	进去分析一下:
	static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_local_features *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		return;
	//把response的feature拷贝到hdev的features中,也就是说我们支持的feature其实是通过和controller交互得到的
	memcpy(hdev->features, rp->features, 8);

	/* Adjust default settings according to features
	 * supported by device. */
	//根据支持的feature来设置packet的type
	if (hdev->features[0] & LMP_3SLOT)
		hdev->pkt_type |= (HCI_DM3 | HCI_DH3);

	if (hdev->features[0] & LMP_5SLOT)
		hdev->pkt_type |= (HCI_DM5 | HCI_DH5);

	if (hdev->features[1] & LMP_HV2) {
		hdev->pkt_type  |= (HCI_HV2);
		hdev->esco_type |= (ESCO_HV2);
	}

	if (hdev->features[1] & LMP_HV3) {
		hdev->pkt_type  |= (HCI_HV3);
		hdev->esco_type |= (ESCO_HV3);
	}

	if (hdev->features[3] & LMP_ESCO)
		hdev->esco_type |= (ESCO_EV3);

	if (hdev->features[4] & LMP_EV4)
		hdev->esco_type |= (ESCO_EV4);

	if (hdev->features[4] & LMP_EV5)
		hdev->esco_type |= (ESCO_EV5);

	if (hdev->features[5] & LMP_EDR_ESCO_2M)
		hdev->esco_type |= (ESCO_2EV3);

	if (hdev->features[5] & LMP_EDR_ESCO_3M)
		hdev->esco_type |= (ESCO_3EV3);

	if (hdev->features[5] & LMP_EDR_3S_ESCO)
		hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
//最后一个打印
	BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
					hdev->features[0], hdev->features[1],
					hdev->features[2], hdev->features[3],
					hdev->features[4], hdev->features[5],
					hdev->features[6], hdev->features[7]);
}

所以,read supportfeatureresponse就是用来初始化一下hdev内的featuretype类型的。

2.1.1.2 read local versionresponse分析

同样的,这个cmd也是会产生一个commandcompleteevent上来,我们去分析一下:

static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_local_version *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		return;
	//根据返回值设置hdev的hci_ver,lmp_ver,lmp_subver参数,就是我们通常说的hci version, lmp version以及制造商信息
	hdev->hci_ver = rp->hci_ver;
	hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
	hdev->lmp_ver = rp->lmp_ver;
	hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
	hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);

	BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
					hdev->manufacturer,
					hdev->hci_ver, hdev->hci_rev);
	//我们这里是处于HCI_INIT的状态的,所以这里会有个hci_setup的操作
	if (test_bit(HCI_INIT, &hdev->flags))
		//这里就是根据上面的features以及version作进一步的操作,仍然是发送各种cmd
		hci_setup(hdev);
}

static void hci_setup(struct hci_dev *hdev)
{
	//建立event mask,根据features发送set event mask的cmd
	hci_setup_event_mask(hdev);
	//lmp version大于1,这个是肯定的,发送read local support command
	if (hdev->lmp_ver > 1)
		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
	//支持simple pair,发送write ssp mode的cmd
	if (hdev->features[6] & LMP_SIMPLE_PAIR) {
		u8 mode = 0x01;
		hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
	}
	//设置inquiry的mode,就是write inquiry mode的cmd
	if (hdev->features[3] & LMP_RSSI_INQ)
		hci_setup_inquiry_mode(hdev);
	//read inquiry response的tx power
	if (hdev->features[7] & LMP_INQ_TX_PWR)
		hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
	//再发read local ext features
	if (hdev->features[7] & LMP_EXTFEATURES) {
		struct hci_cp_read_local_ext_features cp;

		cp.page = 0x01;
		hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
							sizeof(cp), &cp);
	}
	//支持le,则再发le support的命令
	if (hdev->features[4] & LMP_LE)
		hci_set_le_support(hdev);
}

这个函数会根据不同的属性又发送了一堆cmd,那么实际上在第一次中会发送如何几个cmd,我们会接在上面的cmd后面继续分析:set event maskread local support command。就是先回发这两个cmd

2.1.1.3 readbuff sizeresponse分析

他同样回的command complete,我们直接来看

static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_buffer_size *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);
	//若是status非0,就是有问题,则直接返回
	if (rp->status)
		return;
	//根据返回值设置hdev的acl, sco的mtu以及能发送的acl和sco的packet的最大个数
	hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
	hdev->sco_mtu  = rp->sco_mtu;
	hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
	hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
	//这个应该是没有的
	if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
		hdev->sco_mtu  = 64;
		hdev->sco_pkts = 8;
	}
	//因为还没有发送,所以他们都设置为最大值。
	hdev->acl_cnt = hdev->acl_pkts;
	hdev->sco_cnt = hdev->sco_pkts;

	BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
					hdev->acl_mtu, hdev->acl_pkts,
					hdev->sco_mtu, hdev->sco_pkts);
}

因此,这个cmdresponse是设置aclscomtu以及最大的packetnum

2.1.1.4 readbd addrresponse的分析

同样的它也是commandcomplete

static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_bd_addr *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);
	//返回值ok,就把bdaddr拷贝到hdev->bdaddr中去
	if (!rp->status)
		bacpy(&hdev->bdaddr, &rp->bdaddr);
	//这里是看request是否已经结束了,这里分析一下吧,后面应该还有很多
	hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
}
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
{
	BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result);

	/* If this is the init phase check if the completed command matches
	 * the last init command, and if not just return.
	 */
	//若是init的状态,我们目前肯定在init的状态啊,又不是最后一个cmd,就直接返回了,刚刚我们看到,其实我们有很多cmd了,这里显然不是最后一个,所以就直接返回了
	if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd)
		return;
	//结束了就是把req_status置为HCI_REQ_DONE的状态了,唤醒req wait的q
	if (hdev->req_status == HCI_REQ_PEND) {
		hdev->req_result = result;
		hdev->req_status = HCI_REQ_DONE;
		wake_up_interruptible(&hdev->req_wait_q);
	}
}

所以,read bd addrresponse就是把初始化hdevbdaddr的值了。

2.1.1.5 readclass of devicereponse分析

同样是command complete,内容也很简单,就是初始化hdev->dev_class的值。

static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_class_of_dev *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		return;

	memcpy(hdev->dev_class, rp->dev_class, 3);

	BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
		hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
}

2.1.1.6 readlocal nameresponse的分析

和上面类似,只是这次初始化的是hdev->dev_name的值。代码就不贴了,函数是

staticvoid hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)

2.1.1.7 readvoice settingresponse的处理

2.1.1.6类似,初始化hdev->voice_setting的值。函数是staticvoid hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)

2.1.1.8 setevent filterresponse的处理

什么都没有做,就是调用了一下reqcomplete,因为不是最后一个cmd,所以就什么都没有做了,函数是:static void hci_cc_set_event_flt(struct hci_dev *hdev, structsk_buff *skb)

2.1.1.9 writeconnection accept timeoutresponse的处理

2.1.1.8是一样一样的,不多说了。

2.1.1.10delete stored link keyresponse的分析

2.1.1.9也是一样的。

至此,上面10cmd都是开始一次性发送下去的,我们全部分析完成了,基本都是对hdev的初始化。只有read local versionresponse会产生新的cmd发送下去,其它都还是没有什么额外的操作。下面我们接着分析read local version产生的cmd发送下去之后的response。共有两个:set event maskread local support command

2.1.1.11 set event maskresponse

和上面的2.1.1.10是相同的,没有什么好说的。

2.1.1.12 read local support commandresponse

这个response又有事情做了,否则我们就可以结束了,哈哈,解放总是那么的难到。。。

static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_rp_read_local_commands *rp = (void *) skb->data;

	BT_DBG("%s status 0x%x", hdev->name, rp->status);

	if (rp->status)
		goto done;
	//这里还是老规矩,赋值hdev的commands值。不管了
	memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
	//这里比较关键了,若是HCI_INIT的状态,我们是的,然后hdev->commands[5] & 0x10,这一位就是write default link policy setting。
	if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
		hci_setup_link_policy(hdev);

done:
	hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
}
	static void hci_setup_link_policy(struct hci_dev *hdev)
{
	u16 link_policy = 0;
	//link policy有role swtich,hold,sniff,park的支援
	if (hdev->features[0] & LMP_RSWITCH)
		link_policy |= HCI_LP_RSWITCH;
	if (hdev->features[0] & LMP_HOLD)
		link_policy |= HCI_LP_HOLD;
	if (hdev->features[0] & LMP_SNIFF)
		link_policy |= HCI_LP_SNIFF;
	if (hdev->features[1] & LMP_PARK)
		link_policy |= HCI_LP_PARK;
	//就是发送write default link policy的cmd,这个cmd又会产生一个新的event,我们来看一下
	link_policy = cpu_to_le16(link_policy);
	hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
					sizeof(link_policy), &link_policy);
}
	2.1.13 HCI_OP_WRITE_DEF_LINK_POLICY的response的分析
	static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
{
……

	if (rp->status)
		return;
	//这里就是检查返回的值和我随着cmd传下去的设置的值是否相同的,相同的话就直接返回。很显然,这里是相同的
	sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
	if (!sent)
		return;

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
	//若是不相同,就重新设置。
	if (conn)
		conn->link_policy = get_unaligned_le16(sent + 2);

	hci_dev_unlock(hdev);
}


至此,在hci_init_req中的所有command和event的交互就全部分析完成了,您还有什么问题吗?

若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics