您的位置:首页 > 移动开发 > Android开发

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

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

staticvoidhci_init_req(structhci_dev*hdev,unsignedlongopt)
{
	structhci_cp_delete_stored_link_keycp;
	structsk_buff*skb;
	__le16param;
	__u8flt_type;

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

	/*Driverinitialization*/

	/*Specialcommands*/
	//把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);

	/*Mandatoryinitialization*/

	/*Reset*/
	//因为设置了noreset位,所以这里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:
	//readlocalfeatures,readlocalversion,readbuffersize,readbdaddr,readclassofdevice,readlocalname,readvoicesetting,seteventfilter,writeconnectionaccepttimeout,deletestoredlinkkey
	//下面我们会对这些cmd进行逐个地分析
	/*ReadLocalSupportedFeatures*/
	hci_send_cmd(hdev,HCI_OP_READ_LOCAL_FEATURES,0,NULL);

	/*ReadLocalVersion*/
	hci_send_cmd(hdev,HCI_OP_READ_LOCAL_VERSION,0,NULL);

	/*ReadBufferSize(ACLmtu,maxpkt,etc.)*/
	hci_send_cmd(hdev,HCI_OP_READ_BUFFER_SIZE,0,NULL);

	/*ReadBDAddress*/
	hci_send_cmd(hdev,HCI_OP_READ_BD_ADDR,0,NULL);

	/*ReadClassofDevice*/
	hci_send_cmd(hdev,HCI_OP_READ_CLASS_OF_DEV,0,NULL);

	/*ReadLocalName*/
	hci_send_cmd(hdev,HCI_OP_READ_LOCAL_NAME,0,NULL);

	/*ReadVoiceSetting*/
	hci_send_cmd(hdev,HCI_OP_READ_VOICE_SETTING,0,NULL);

	/*ClearEventFilters*/
	flt_type=HCI_FLT_CLEAR_ALL;
	hci_send_cmd(hdev,HCI_OP_SET_EVENT_FLT,1,&flt_type);

	/*Connectionaccepttimeout~20secs*/
//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是如何处理的。

在之前我们看到,hcidev注册的时候是启动了一个rxtask的,他就是用来接收的,所以我们直接去看一下它的处理
staticvoidhci_rx_task(unsignedlongarg){
……
	//对于event的处理,就是这里了,所以后期各个event都是这边进行处理的,不再详细地说明如何找了
		switch(bt_cb(skb)->pkt_type){
		caseHCI_EVENT_PKT:
			hci_event_packet(hdev,skb);
			break;
}

2.1.1.1readlocalfeatures的event的处理

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

staticinlinevoidhci_cmd_complete_evt(structhci_dev*hdev,structsk_buff*skb){
……
	caseHCI_OP_READ_LOCAL_FEATURES:
		hci_cc_read_local_features(hdev,skb);
		break;
}
	进去分析一下:
	staticvoidhci_cc_read_local_features(structhci_dev*hdev,structsk_buff*skb)
{
	structhci_rp_read_local_features*rp=(void*)skb->data;

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

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

	/*Adjustdefaultsettingsaccordingtofeatures
	*supportedbydevice.*/
	//根据支持的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("%sfeatures0x%.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]);
}

所以,readsupportfeature的response就是用来初始化一下hdev内的feature和type类型的。
2.1.1.2readlocalversion的response分析

同样的,这个cmd也是会产生一个commandcomplete的event上来,我们去分析一下:
staticvoidhci_cc_read_local_version(structhci_dev*hdev,structsk_buff*skb)
{
	structhci_rp_read_local_version*rp=(void*)skb->data;

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

	if(rp->status)
		return;
	//根据返回值设置hdev的hci_ver,lmp_ver,lmp_subver参数,就是我们通常说的hciversion,lmpversion以及制造商信息
	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("%smanufacturer%dhciver%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);
}

staticvoidhci_setup(structhci_dev*hdev)
{
	//建立eventmask,根据features发送seteventmask的cmd
	hci_setup_event_mask(hdev);
	//lmpversion大于1,这个是肯定的,发送readlocalsupportcommand
	if(hdev->lmp_ver>1)
		hci_send_cmd(hdev,HCI_OP_READ_LOCAL_COMMANDS,0,NULL);
	//支持simplepair,发送writesspmode的cmd
	if(hdev->features[6]&LMP_SIMPLE_PAIR){
		u8mode=0x01;
		hci_send_cmd(hdev,HCI_OP_WRITE_SSP_MODE,sizeof(mode),&mode);
	}
	//设置inquiry的mode,就是writeinquirymode的cmd
	if(hdev->features[3]&LMP_RSSI_INQ)
		hci_setup_inquiry_mode(hdev);
	//readinquiryresponse的txpower
	if(hdev->features[7]&LMP_INQ_TX_PWR)
		hci_send_cmd(hdev,HCI_OP_READ_INQ_RSP_TX_POWER,0,NULL);
	//再发readlocalextfeatures
	if(hdev->features[7]&LMP_EXTFEATURES){
		structhci_cp_read_local_ext_featurescp;

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

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

他同样回的commandcomplete,我们直接来看
staticvoidhci_cc_read_buffer_size(structhci_dev*hdev,structsk_buff*skb)
{
	structhci_rp_read_buffer_size*rp=(void*)skb->data;

	BT_DBG("%sstatus0x%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("%saclmtu%d:%dscomtu%d:%d",hdev->name,
					hdev->acl_mtu,hdev->acl_pkts,
					hdev->sco_mtu,hdev->sco_pkts);
}

因此,这个cmd的response是设置acl和sco的mtu以及最大的packetnum。
2.1.1.4readbdaddr的response的分析

同样的它也是commandcomplete:
staticvoidhci_cc_read_bd_addr(structhci_dev*hdev,structsk_buff*skb)
{
	structhci_rp_read_bd_addr*rp=(void*)skb->data;

	BT_DBG("%sstatus0x%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);
}
voidhci_req_complete(structhci_dev*hdev,__u16cmd,intresult)
{
	BT_DBG("%scommand0x%04xresult0x%2.2x",hdev->name,cmd,result);

	/*Ifthisistheinitphasecheckifthecompletedcommandmatches
	*thelastinitcommand,andifnotjustreturn.
	*/
	//若是init的状态,我们目前肯定在init的状态啊,又不是最后一个cmd,就直接返回了,刚刚我们看到,其实我们有很多cmd了,这里显然不是最后一个,所以就直接返回了
	if(test_bit(HCI_INIT,&hdev->flags)&&hdev->init_last_cmd!=cmd)
		return;
	//结束了就是把req_status置为HCI_REQ_DONE的状态了,唤醒reqwait的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);
	}
}

所以,readbdaddr的response就是把初始化hdev的bdaddr的值了。
2.1.1.5readclassofdevice的reponse分析

同样是commandcomplete,内容也很简单,就是初始化hdev->dev_class的值。
staticvoidhci_cc_read_class_of_dev(structhci_dev*hdev,structsk_buff*skb)
{
	structhci_rp_read_class_of_dev*rp=(void*)skb->data;

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

	if(rp->status)
		return;

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

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

2.1.1.6readlocalname的response的分析

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

2.1.1.7readvoicesetting的response的处理

和2.1.1.6类似,初始化hdev->voice_setting的值。函数是staticvoidhci_cc_read_voice_setting(structhci_dev*hdev,structsk_buff*skb)
2.1.1.8seteventfilter的response的处理

什么都没有做,就是调用了一下reqcomplete,因为不是最后一个cmd,所以就什么都没有做了,函数是:staticvoidhci_cc_set_event_flt(structhci_dev*hdev,structsk_buff*skb)
2.1.1.9writeconnectionaccepttimeout的response的处理

和2.1.1.8是一样一样的,不多说了。
2.1.1.10deletestoredlinkkey的response的分析

和2.1.1.9也是一样的。

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

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

这个response又有事情做了,否则我们就可以结束了,哈哈,解放总是那么的难到。。。
staticvoidhci_cc_read_local_commands(structhci_dev*hdev,structsk_buff*skb)
{
structhci_rp_read_local_commands*rp=(void*)skb->data;

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

if(rp->status)
gotodone;
//这里还是老规矩,赋值hdev的commands值。不管了
memcpy(hdev->commands,rp->commands,sizeof(hdev->commands));
//这里比较关键了,若是HCI_INIT的状态,我们是的,然后hdev->commands[5]&0x10,这一位就是writedefaultlinkpolicysetting。
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);
}
staticvoidhci_setup_link_policy(structhci_dev*hdev)
{
u16link_policy=0;
//linkpolicy有roleswtich,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;
//就是发送writedefaultlinkpolicy的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.13HCI_OP_WRITE_DEF_LINK_POLICY的response的分析
staticvoidhci_cc_write_link_policy(structhci_dev*hdev,structsk_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的交互就全部分析完成了,您还有什么问题吗?

若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: