[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的研读是必不可少的。
这里各种cmd就已经发送出去了,下面就是对接收到的response要做一些处理了,首先我们来看一下对event是如何处理的。
在之前我们看到,hcidev注册的时候是启动了一个rxtask的,他就是用来接收的,所以我们直接去看一下它的处理
2.1.1.1readlocalfeatures的event的处理
从spec中,我们知道,这个cmd的回应是一个commandcomplete的event。所以,直接去看command
completeevent的处理:
所以,readsupportfeature的response就是用来初始化一下hdev内的feature和type类型的。
2.1.1.2readlocalversion的response分析
同样的,这个cmd也是会产生一个commandcomplete的event上来,我们去分析一下:
这个函数会根据不同的属性又发送了一堆cmd,那么实际上在第一次中会发送如何几个cmd,我们会接在上面的cmd后面继续分析:set
eventmask,readlocalsupportcommand。就是先回发这两个cmd。
2.1.1.3readbuffsize的response分析
他同样回的commandcomplete,我们直接来看
因此,这个cmd的response是设置acl和sco的mtu以及最大的packetnum。
2.1.1.4readbdaddr的response的分析
同样的它也是commandcomplete:
所以,readbdaddr的response就是把初始化hdev的bdaddr的值了。
2.1.1.5readclassofdevice的reponse分析
同样是commandcomplete,内容也很简单,就是初始化hdev->dev_class的值。
2.1.1.6readlocalname的response的分析
和上面类似,只是这次初始化的是hdev->dev_name的值。代码就不贴了,函数是
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又有事情做了,否则我们就可以结束了,哈哈,解放总是那么的难到。。。
至此,在hci_init_req中的所有command和event的交互就全部分析完成了,您还有什么问题吗?
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·
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的交互就全部分析完成了,您还有什么问题吗?
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·
相关文章推荐
- Android View系统源码分析(四)—— 各种消息监测的基本实现方法&View.dispatchTouchEvent()
- 深入Android内核——Android init.c源码深入分析
- 【Android7.1.2源码解析系列】android init目录下的Android.mk编译文件分析
- 一道面试题引发的对android中context的研究(三)-各种Context在ActivityThread中实例化过程源码分析
- EventBus for Android 源码分析
- Android-4.0.3-init.c启动源码分析
- android 源码分析流程(一) init.c
- Android中TouchEvent来源的源码分析及内部类扮演的角色
- 【Android7.1.2源码解析系列】实战分析init.rc文件
- Android M 启动源码分析笔记之 - Init 进程
- Android init进程——源码分析
- Android-vold源码分析之handleBlockEvent(5)
- Android-vold源码分析之runCommand(7)
- [android源码分析]bluez启动过程中的各种plugin的初始化(一)--__bluetooth_builtin数组所耍的花样
- Android触摸屏事件派发机制详解与源码分析一(View篇)onTouch,onClick,ontouchevent
- android 4.04的应用程序启动过程及与Zygote的交互(基于静态源码分析)
- Android-vold源码分析之handleBlockEvent(5)
- Android3.1 init进程启动源码分析