AndroidWIFI移植分析—曹颖实用教案

上传人:壹****1 文档编号:568032546 上传时间:2024-07-23 格式:PPT 页数:52 大小:1.43MB
返回 下载 相关 举报
AndroidWIFI移植分析—曹颖实用教案_第1页
第1页 / 共52页
AndroidWIFI移植分析—曹颖实用教案_第2页
第2页 / 共52页
AndroidWIFI移植分析—曹颖实用教案_第3页
第3页 / 共52页
AndroidWIFI移植分析—曹颖实用教案_第4页
第4页 / 共52页
AndroidWIFI移植分析—曹颖实用教案_第5页
第5页 / 共52页
点击查看更多>>
资源描述

《AndroidWIFI移植分析—曹颖实用教案》由会员分享,可在线阅读,更多相关《AndroidWIFI移植分析—曹颖实用教案(52页珍藏版)》请在金锄头文库上搜索。

1、1项目(xingm)概述:Android3G平板电脑功能介绍:该系统为手持移动终端,其底层硬件采用ARM来实现,搭载谷歌的Android操作系统。支持(zhch)多点触摸屏、通过WIFI实现联网、蓝牙数据传输、摄像头、USB接口、SD卡接口、重力感应系统、实物键盘。在本次项目主要涉及3G模块、WIFI模块两个部分的开发。硬件环境WIFI模块:Marvell8686SDIOWIFI开发板:FS_S5PC100软件环境Linux2.6.29Android2.1第2页/共51页第1页/共51页第一页,共52页。2SDIOWIFI部分(bfen)项目负责人:曹颖项目目标:实现WIFI上网功能、并对WI

2、FI休眠进行改善。项目开发流程:硬件分析:对Marvell8686SDIOWIFI模块(mkui)硬件工作特性了解和分析工作原理分析:对Marvel8686SDIOWIFI工作原理进行分析AndroidWIFI框架分析:对AndroidWIFI系统框架分析进行源码分析、编写、修改及编译调试、并完善时间安排:2011-9-29至2011-10-7:硬件分析、了解驱动框架2011-10-8至2011-10-16:AndroidSDIOWIFI移植及工作原理分析2011-10-17至2011-10-23:AndroidWIFI框架分析2011-10-24至2011-10-30:进行源码分析2011-

3、10-31至2011-11-5:准备答辩就业第3页/共51页第2页/共51页第二页,共52页。30、Android中WIFI基本架构 1、WIFI在Android中如何工作2、配置内核支持(zhch)SDIO WIFI-make menuconfig3、配置wpa_supplicant的驱动-BoardConfig.mk4、使能wpa_supplicant调试信息-common.*5、修改wpa_supplicant.conf6、配置路径和权限-init.rc7、运行wpa_supplicant和dhcpcd-init.rc8、设置驱动以模块方式加载-libertas_sdio.ko9、提供固

4、件供驱动模块-sd8686.bin sd8686_helper.bin10、配置dhcpcd.confAndroid SDIO WIFI移植(yzh):第4页/共51页第3页/共51页第三页,共52页。4AndroidAndroid之WIFIWIFI模块(m kui)(m kui)第5页/共51页第4页/共51页第四页,共52页。5Android使用一个修改版wpa_supplicant作为daemon来控制(kngzh)WIFI,代码位于external/wpa_supplicant。wpa_supplicant是通过socket与hardware/libhardware_legacy/wi

5、fi/wifi.c通信。UI通过.wifipackage(frameworks/base/wifi/java/android/net/wifi/)发送命令给wifi.c。相应的JNI实现位于frameworks/base/core/jni/android_net_wifi_Wifi.cpp。更高一级的网络管理位于frameworks/base/core/java/android/net。WIFI在Android中如何(rh)工作第6页/共51页第5页/共51页第五页,共52页。6makemenuconfig*Networkingsupport-*Wireless-WirelessImprove

6、dwirelessconfigurationAPI*cfg80211regulatorydebugging*nl80211newnetlinkinterfacesupport-*-CommonroutinesforIEEE802.11driversDeviceDrivers-*Networkdevicesupport-WirelessLAN-Marvell8xxxLibertasWLANdriversupportMarvellLibertas8385and8686SDIO802.11b/gcards配置(pizh)内核支持SDIO WIF第7页/共51页第6页/共51页第六页,共52页。7配置

7、(pizh)wpa_supplicant的驱动修改vendor/farsight/fs100/BoardConfig.mk:把BOARD_WPA_SUPPLICANT_DRIVER:=true改为BOARD_WPA_SUPPLICANT_DRIVER:=WEXT目的是:把driver_wext.c作为wpa_supplicant的驱动。wpa_supplicant通过它去与内核的wifi驱动打交道。修改external/wpa_supplicant/Android.mk把WPA_BUILD_SUPPLICANT:=false改为WPA_BUILD_SUPPLICANT:=true默认使用(sh

8、yng)驱动driver_wext.c。如果使用(shyng)定制的wpa_supplicant驱动(例如madwifi),可以设置:BOARD_WPA_SUPPLICANT_DRIVER:=MADWIFI第8页/共51页第7页/共51页第七页,共52页。8使能wpa_supplicant调试信息wpa_supplicant默认信息显示的等级为SG_INFO,为了(wile)输出更多信息,可修改:修改external/wpa_supplicant/common.c把intwpa_debug_level=MSG_INFO;改为:intwpa_debug_level=MSG_DEBUG;修改ext

9、ernal/wpa_supplicant/common.h把宏定义#definewpa_printf(level,.)中的if(level)=MSG_INFO)改为if(level)=MSG_DEBUG)第9页/共51页第8页/共51页第八页,共52页。9修改(xigi)wpa_supplicant.conf修改(xigi)wpa_supplicant.conf:把external/wpa_supplicant/wpa_supplicant.conf拷贝到out/target/product/fs100/system/etc/wifi/目录下,并把:ctrl_interface=DIR=/da

10、ta/misc/wifi/wpa_supplicantGROUP=wifi改为:ctrl_interface=wlan0第10页/共51页第9页/共51页第九页,共52页。10配置路径(ljng)和权限A)配置init.rc文件修改out/target/product/fs100/root/init.rc,让wifi用户拥有相关的权限(qunxin),在#givesystemaccesstowpa_supplicant.confforbackupandrestore后面增加:#addbycaoyi2011-10-19mkdir/data/misc/wifi/sockets0777wifiwif

11、ichownwifiwifi/data/misc/wifichownwifiwifi/data/misc/wifi/wpa_supplicant.conf#fordhcpmkdir/data/misc/dhcp0777dhcpdhcpchmod0770/data/misc/dhcp#endaddB)注释原有环境变量#exportPATH改为:exportPATH/sbin:/system/sbin:/system/bin:/system/xbin#abovemodifiedbycaoyi2011-10-19修改控制台注释掉原console#modfiedbycaoyi2011-10-19#se

12、rviceconsole/system/busybox/bin/ash改为:serviceconsole/system/bin/bash第11页/共51页第10页/共51页第十页,共52页。11运行(ynxng)wpa_supplicant和dhcpcd配置init.rc文件修改(xigi)out/target/product/fs100/root/init.rc,在末尾添加:#addbycaoyi2011-10-19forwifiAndroidprivatesocketservicewpa_supplicant/system/bin/wpa_supplicant-dd-Dwext-iwlan

13、0-c/system/etc/wifi/wpa_supplicant.confsocketwpa_wlan0dgram660wifiwifigroupsystemwifiinetdisabledoneshot#fordhcpservicedhcpcd/system/bin/dhcpcdwlan0groupsystemdhcpdisabledoneshot#endadd。第12页/共51页第11页/共51页第十一页,共52页。12设置(shzh)驱动以模块方式加载第13页/共51页第12页/共51页第十二页,共52页。13提供(tgng)固件firmwareAndroid不使用标准的hotplu

14、gbinary,WIFI需要的firmware要复制到/etc/firmware。或者(huzh)复制到WIFI驱动指定的位置,然后WIFI驱动会自动加载。在此把wifi模块提供的sd8686.binsd8686_helper.bin放到out/target/product/fs100/system/etc/firmware目录下。第14页/共51页第13页/共51页第十三页,共52页。14配置(pizh)dhcpcd.conf修改源码目录下external/dhcpcd下的Android.mk文件取消注释(zhsh)26include$(CLEAR_VARS)27LOCAL_MODULE:=

15、dhcpcd.conf28LOCAL_MODULE_TAGS:=user29LOCAL_MODULE_CLASS:=ETC30LOCAL_MODULE_PATH:=$(etc_dir)31LOCAL_SRC_FILES:=android.conf32include$(BUILD_PREBUILT)然后重新编译mm,将编译产生的dhcpcd.conf放置到文件系统的目录system/etc/dhcpcd/dhcpcd.conf最后确定dhcpcd.conf内容有:interfacewlan0optionsubnet_mask,routers,domain_name_serversoptionnt

16、p_servers这几行,否则修改之。第15页/共51页第14页/共51页第十四页,共52页。15其它(qt)修改修改(xigi)WifiStateTracker.java将frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java里的mInterfaceName=SystemProperties.get(wifi.interface,eth0);改为:mInterfaceName=SystemProperties.get(wifi.interface,wlan0);编译镜像文件后烧写到开发板上就可以使用WiFi模块连接外网

17、。第16页/共51页第15页/共51页第十五页,共52页。16经验(jngyn)技巧移植过程中,我们只是针对文件系统中某几个文件修改,所以没必要重新对整个文件系统编译(biny)。而这个时候就可以针对性的编译(biny)某个目录,使生成对应的库文件*.so,然后替换之前的库文件。例如:我们经常要修改wifi.c。我们可以这样:./build/envsetup.shtapasmmmhardware/libhardware_legacy/然后将生成的libhardware_legacy.so拷贝到文件系统fs100_root中lib目录。$cpout/target/product/fs100/sy

18、stem/lib/libhardware_legacy.sofs100_root/system/lib/第17页/共51页第16页/共51页第十六页,共52页。17AndroidWIFI框架(kunji)分析:WIFI工作流程WIFI初始化WIFI启动开始扫描显示扫描的AP配置(pizh)AP连接AP获取IP地址上网第18页/共51页第17页/共51页第十七页,共52页。18AndroidAndroid之WIFIWIFI模块(m kui)(m kui)第19页/共51页第18页/共51页第十八页,共52页。19AndroidWIFI源码结构(jigu)WIFIApplicationpackag

19、es/apps/Settings/src/com/android/settings/wifiWIFIFrameworkframeworks/base/wifi/java/android/net/wififrameworks/base/services/java/com/android/serverWIFIJNIframeworks/base/core/jni/android_net_wifi_Wifi.cppWIFIHardwarehardware/libhardware_legacy/wifi/wifi.cWIFItoolexternal/wpa_supplicantWIFIKernelsy

20、stem/lib/modules/libertas_sdio.ko第20页/共51页第19页/共51页第十九页,共52页。20AndroidWIFI初始化在SystemServer启动的时候,会生成一个ConnectivityService的实例:tryLog.i(TAG,StartingConnectivityService.);ServiceManager.addService(Context.CONNECTIVITY_SERVICE,newConnectivityService(context);catch(Throwablee)Log.e(TAG,FailurestartingConn

21、ectivityService,e);ConnectivityService的构造函数会创建WifiService、WifiStateTracker:if(DBG)Log.v(TAG,StartingWifiService.);mWifiStateTracker=newWifiStateTracker(context,handler);WifiServicewifiService=newWifiService(context,mWifiStateTracker);ServiceManager.addService(Context.WIFI_SERVICE,wifiService);WifiSt

22、ateTracker 会创建WifiMonitor接收来自底层的事件。WifiService和WifiMonitor是整个模块的核心。WifiService负责启动关闭(gunb)wpa_supplican和启动关闭(gunb)WifiMonitor监视线程和把命令下发给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接收事件通知。第21页/共51页第20页/共51页第二十页,共52页。21Androidsystem初始化 第22页/共51页第21页/共51页第二十一页,共52页。22WIFI初始化第23页/共51页第22页/共51页第二十二页,共52

23、页。23Wifi模块(mkui)的启动WirelessSettings在初始化的时候配置了由WifiEnabler来处理Wifi按钮,privatevoidinitToggles()mWifiEnabler=newWifiEnabler(this,(WifiManger)getSystemService(WIFI_SERVICE),(CheckBoxPreference)findPreference(KEY_TOGGLE_WIFI);当用户按下Wifi按钮后,Android会调用WifiEnabler的onPreferenceChange,再由WifiEnabler调用WifiManager的

24、setWifiEnabled接口函数,通过AIDL,实际调用的是WifiService的setWifiEnabled函数,WifiService接着向自身发送一条(ytio)MESSAGE_ENABLE_WIFI消息,在处理该消息的代码中做真正的使能工作:首先装载WIFI内核模块(该模块的位置硬编码为/system/lib/modules/wlan.ko),然后启动wpa_supplicant(配置文件硬编码为/data/misc/wifi/wpa_supplicant.conf),再通过WifiStateTracker 来启动WifiMonitor中的监视线程。第24页/共51页第23页/共

25、51页第二十三页,共52页。24Wifi模块(mkui)的启动privatebooleansetWifiEnabledBlocking(booleanenable)finalinteventualWifiState=enable?WIFI_STATE_ENABLED:WIFI_STATE_DISABLED;setWifiEnabledState(enable?WIFI_STATE_ENABLING:WIFI_STATE_DISABLING,uid);if(enable)if(!WifiNative.loadDriver()Log.e(TAG,FailedtoloadWi-Fidriver.);

26、setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);returnfalse;if(!WifiNative.startSupplicant()WifiNative.unloadDriver();Log.e(TAG,Failedtostartsupplicantdaemon.);setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);returnfalse;registerForBroadcasts();mWifiStateTracker.startEventLoop();/Success!if(persist)persistWi

27、fiEnabled(enable);setWifiEnabledState(eventualWifiState,uid);returntrue;第25页/共51页第24页/共51页第二十四页,共52页。25Wifi模块(mkui)的启动第26页/共51页第25页/共51页第二十五页,共52页。26扫描(somio)热点(AP)当使能成功后,会广播发送(fsn)WIFI_STATE_CHANGED_ACTION这个Intent通知外界WIFI已经成功使能了。WifiLayer创建的时候就会向Android注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该Intent,从而

28、开始扫描。privatevoidhandleWifiStateChanged(intwifiState)if(wifiState=WIFI_STATE_ENABLED)loadConfiguredAccessPoints();attemptScan();最终会调用到wpa_ctrl.c中的wpa_ctrl_request()函数,其实就是执行SCAN命令。当wpa_supplicant处理完SCAN命令后,它会向控制通道发送(fsn)事件通知扫描完成,从wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行来出来这个事件:第2

29、7页/共51页第26页/共51页第二十六页,共52页。27显示(xinsh)扫描的AP当扫描成后,WifiMonitor中的MonitorThread会被执行(zhxng)来出来这个事件:WifiStateTracker.javapublicvoidhandleMessage(Messagemsg)switch(msg.what)caseEVENT_SCAN_RESULTS_AVAILABLE:if(ActivityManagerNative.isSystemReady()mContext.sendBroadcast(newIntent(WifiManager.SCAN_RESULTS_AVA

30、ILABLE_ACTION); void handleEvent(int event, String remainder) switch (event) case SCAN_RESULTS: mWifiStateTracker.notifyScanResultsAvailable();-sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE); break;第28页/共51页第27页/共51页第二十七页,共52页。28显示(xinsh)扫描的APWifiLayer注册接收SCAN_RESULTS_AVAILABLE_ACTION这个Intent:privat

31、eBroadcastReceivermReceiver=newBroadcastReceiver()OverridepublicvoidonReceive(Contextcontext,Intentintent)elseif(action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)handleScanResultsAvailable();handleScanResultsAvailable();-list=mWifiManager.getScanResults();-mCallback.onAccessPointSetChanged(ap

32、,true);handleScanResultsAvailable()中首先会去拿到SCAN的结果(最终是往wpa_supplicant中发送SCAN_RESULT命令并读取返回值来实现的),对每一个扫描返回的AP,WifiLayer会回调WifiSetting的onAccessPointSetChanged函数(hnsh),从而最终把该AP加到GUI显示列表中。第29页/共51页第28页/共51页第二十八页,共52页。29配置(pizh)AP当用户在WifiSettings界面上选择了一个AP后,会显示配置AP参数(cnsh)的一个对话框:publicbooleanonPreferenceT

33、reeClick()-showAccessPointDialog(state,AccessPointDialog.MODE_INFO);-AccessPointDialogdialog=newAccessPointDialog(this,mWifiLayer);showDialog(dialog);当用户在AccessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP第30页/共51页第29页/共51页第二十九页,共52页。30连接(linji)AP在AccessPointDialog.java中点击连接(linji)后会执行:publicv

34、oidonClick(DialogInterfacedialog,intwhich)handleConnect();-mWifiLayer.connectToNetwork(mState);-/NeedWifiConfigurationfortheAPWifiConfigurationconfig=findConfiguredNetwork(state);config=addConfiguration(state,0);managerEnableNetwork(state,false)-mWifiManager.enableNetwork()-mService.enalbeNetwork()-

35、WifiNative.enableNetworkCommand()接下去就JNIenableNetworkCommand,(IZ)Z,(void*)android_net_wifi_enableNetworkCommand,最终就是向wpa_supplicant发送连接(linji)命令第31页/共51页第30页/共51页第三十页,共52页。31获取(huq)IP地址当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行(zhxng)

36、来出来这个事件:WifiStateTracker.javapublicvoidhandleMessage(Messagemsg)switch(msg.what)caseEVENT_NETWORK_STATE_CHANGED:sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID(); void handleEvent(int event, String remainder) switch (event) case CONNECTED: handleNetworkStateChange(); - mWifiStateTracker.notifySta

37、teChange(newState, BSSID, networkId);-msg.sendToTarget(); break;第32页/共51页第31页/共51页第三十一页,共52页。32获取(huq)IP地址WifiStateTracker中注册的对Wifi相关数据库的观察者if(changed)则启动:privatevoidconfigureInterface()-mDhcpTarget.sendEmptyMessage();privateclassDhcpHandlerextendsHandlerhandleMessage()-switch(msg.what)caseEVENT_DHC

38、P_START:Target.sendEmptyMessage(event);DhcpHandler会发送EVENT_DHCP_START消息启动DHCP去获取IP地址,当DHCP拿到IP地址之后,会发送EVENT_INTERFACE_CONFIGURATION_SUCCEEDED的消息,然后WifiStateTacker中的handleMessage会处理这样的消息caseEVENT_INTERFACE_CONFIGURATION_SUCCEEDED:sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID();-Intentintent=newI

39、ntent(WifiManager.NETWORK_STATE_CHANGED_ACTION);-mContext.sendStickyBroadcast(intent);这次带上完整(wnzhng)的IP地址信息。WifiLayer中注册了此Intent的接受者,会调用handleNetworkStateChanged进行处理。最后就可以自由的上网了第33页/共51页第32页/共51页第三十二页,共52页。33SDIOWIFI驱动(qdn)分析:右上图中除右上图中除SDIOSDIO卡时卡时所用到的信号线以外所用到的信号线以外增加了增加了nCDnCD、WPWP引脚,引脚,nCDnCD用来支持卡

40、热拔用来支持卡热拔插当卡热拔插时会插当卡热拔插时会(sh hu)(sh hu)触发中断触发中断它连接到它连接到S5PC100S5PC100的的GPG2_6GPG2_6见右下图,见右下图,WPWP为硬件写保护引脚为硬件写保护引脚,1,1表示卡写保护。表示卡写保护。s5pc100 SD/WIFI接口接口(ji ku)图图 第34页/共51页第33页/共51页第三十三页,共52页。34SDIO接口WIFI驱动(qdn)概述:SDIO接口WIFI驱动分为两部分(bfen),首先是SDIO接口部分(bfen),然后才是WIFI驱动部分(bfen)。SDIO是在SD标准上定义的接口标准,其实就是一种总线,

41、而WIFI设备可以看作是使用该总线的具体设备。因为SDIO接口是在SD标准上扩展的,所以SDIO设备的驱动结构和SD卡的驱动结构类似,也是分为3层,从下而上,分别是host层,core层,具体的SDIO设备驱动层。Host层实现对SDI主机控制器的操作。Core层实现SD规范、SDIO规范。最上层实现具体的SDIO设备驱动。具体的SDIO卡驱动Core核心层Host主机驱动程序第35页/共51页第34页/共51页第三十四页,共52页。35SDIO接口WIFI驱动(qdn)概述:WiFi设备也是属于(shy)网络设备的一种,所以WiFi设备的驱动结构遵循Linux网络设备驱动的体系结构,从上到下

42、分为4层,依次为网络协议接口层、网络设备接口层、提供实际功能的设备驱动功能层以及网络设备与媒介层。在实际的驱动开发中,主要的工作就是实现具体的设备驱动功能层。网络数据包的接收由中断引发,设备驱动功能层中另一个主体部分就是中断处理函数。网络协议接口层网络设备层设备驱动功能层网络设备与媒介层struct net_device_ops ndo_openndo_stopndo_start_xmitndo_set_mac_addressndo_tx_timeout;net_device第36页/共51页第35页/共51页第三十五页,共52页。36HOST主机(zhj)驱动外设主机一般归纳为platfor

43、m设备。一般在BSP中定义好platform_device结构。对于(duy)SD卡主机驱动在Drivers/mmc/host/s3cmci.c文件中实现。其中有,static struct platform_driver s3cmci_driver = .driver= .name= s3c-sdi,.owner= THIS_MODULE,.pm= s3cmci_pm_ops,.id_table= s3cmci_driver_ids,.probe= s3cmci_probe,.remove= _devexit_p(s3cmci_remove),.shutdown = s3cmci_shutd

44、own,;在入口函数module_init(s3cmci_init);-return platform_driver_register(&s3cmci_driver);注册平台驱动(q dn)最终会调用驱动(q dn)中的probe函数。即s3cmci_probe函数。第37页/共51页第36页/共51页第三十六页,共52页。37HOST主机(zhj)驱动probe函数(hnsh)分析:staticint_devinits3cmci_probe(structplatform_device*pdev)它主要对主机控制器进行一些初始化工作,其中主要函数(hnsh)有:mmc=mmc_alloc_h

45、ost(sizeof(structs3cmci_host),&pdev-dev);/分配一个mmcrequest_irq(host-irq_cd,s3cmci_irq_cd,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,DRIVER_NAME,host)/注册卡检测中断,双边沿触发,当热拔插时执行中断处理函数(hnsh)s3cmci_ird_cd.ret=mmc_add_host(mmc);/添加mmc设备第38页/共51页第37页/共51页第三十七页,共52页。38SD卡驱动(qdn)探测前面HOST驱动中probe函数中会对SD卡进行探测。里面涉及的关键

46、函数有:mmc=mmc_alloc_host(sizeof(structs3cmci_host),&pdev-dev);-INIT_DELAYED_WORK(&host-detect,mmc_rescan);/初始化工作队列s3cmci_irq_cd(intirq,void*dev_id)-mmc_detect_change(host-mmc,msecs_to_jiffies(500);/延时执行下半部-mmc_schedule_delayed_work(&host-detect,delay);ret=mmc_add_host(mmc);-mmc_start_host(host);-mmc_d

47、etect_change(host,0);-mmc_schedule_delayed_work(&host-detect,delay);/启用(qyng)卡检测的工作队列mmc_add_host启动时初始化,而s3cmci_irq_cd为动态插入卡时检测。最终执行mmc_detect_change-mmc_rescan函数进行MMC/SD卡以及SDIO设备的初始化,并在匹配到设备后注册到系统中去。这里我们只关注SDIO设备。第39页/共51页第38页/共51页第三十八页,共52页。39SD卡驱动(qdn)探测mmc_rescan()函数分析:voidmmc_rescan(structwork_

48、struct*work)mmc_claim_host(host);/声明占用SD卡总线mmc_go_idle(host);/CMD0mmc_send_if_cond(host,host-ocr_avail);/CMD8判断(pndun)SD卡版本/*FirstwesearchforSDIO.*/err=mmc_send_io_op_cond(host,0,&ocr);/CMD5检测SDIO卡/*.thennormalSD.*/err=mmc_send_app_op_cond(host,0,&ocr);/ACM41IFSDCARD?HCSDEFAULT=0NOTCAREVER2.0/*.andf

49、inallyMMC.*/err=mmc_send_op_cond(host,0,&ocr);/CMD1IFMMCCARD?mmc_release_host(host);第40页/共51页第39页/共51页第三十九页,共52页。40SDIO设备(shbi)初始化对于SDIO设备,新定义了structsdio_bus_type代表SDIO总线类型,structsdio_func代表具体的功能设备,structsdio_driver代表具体的SDIO设备驱动。所以在SDIO设备除了structmmc_card来代表设备以外,还有structsdio_func来代表具体功能设备。所以在mmc_atta

50、ch_sdio函数中除了注册(zhc)mmc_card以外,还注册(zhc)了sdio_func。分别为mmc_add_card和sdio_add_func函数。从mmc_rescan()函数看到,通过mmc_send_io_op_cond函数发送CMD5获取电压值,得到正确的响应后,调用mmc_attach_sdio函数进行SDIO设备的初始化。第41页/共51页第40页/共51页第四十页,共52页。41SDIO设备(shbi)初始化mmc_attach_sdio()函数分析:/*StartingpointforSDIOcardinit.*/intmmc_attach_sdio(struct

51、mmc_host*host,u32ocr)host-ocr=mmc_select_voltage(host,ocr);/*Detectandinitthecard.*/err=mmc_sdio_init_card(host,host-ocr,NULL,0);-err=mmc_send_io_op_cond(host,host-ocr,&ocr);/CMD5/保存主机支持最低电压值,如主机支持最低电压不在卡操作电压范围内则此卡不支持。-card=mmc_alloc_card(host,NULL);/*Allocatecardstructure.*/err=sdio_init_func(host-

52、card,i+1);err=mmc_add_card(host-card);err=sdio_add_func(host-card-sdio_funci);/注册(zhc)具体的功能设备第42页/共51页第41页/共51页第四十一页,共52页。42SDIOWIFI设备(shbi)驱动SDIO设备驱动由sdio_driver结构体定义,sdio_driver其实是driver的封装。通过(tnggu)sdio_register_driver函数将SDIO设备驱动加载进内核,其实就是挂载到sdio_bus_type总线上去。/* * SDIO function device driver */st

53、ruct sdio_driver char *name;/驱动名称const struct sdio_device_id *id_table;/驱动设备IDint (*probe)(struct sdio_func *, const struct sdio_device_id *); /探测函数(hnsh)接口void (*remove)(struct sdio_func *);struct device_driver drv;第43页/共51页第42页/共51页第四十二页,共52页。43SDIOWIFI设备(shbi)驱动在driversnetwirelesslibertasif_sdio.

54、c中定义(dngy)了一个if_sdio_driver变量。module_init(if_sdio_init_module);-ret=sdio_register_driver(&if_sdio_driver);intsdio_register_driver(structsdio_driver*drv)drv-drv.name=drv-name;drv-drv.bus=&sdio_bus_type;/设置driver的bus为sdio_bus_typereturndriver_register(&drv-drv);static struct sdio_driver if_sdio_driver

55、 = .name = libertas_sdio,.id_table = if_sdio_ids, /用于设备(shbi)和驱动的匹配.probe = if_sdio_probe,.remove = if_sdio_remove,;第44页/共51页第43页/共51页第四十三页,共52页。44设备和驱动(qdn)的匹配returndriver_register(&drv-drv);最终会调用相应bus上的匹配函数来进行匹配合适的驱动或者设备。对于SDIO设备和驱动的匹配由mmc_bus_match和sdio_bus_match完成。查看sdio_match_device的具体函数可以知道,通过

56、(tnggu)匹配id_table和读出来的SDIO设备的模块ID(class,vendor,device)来查找合适的设备或者驱动。在匹配到合适的设备或驱动后,sdio_driver结构体中的probe函数就会被调用。static int sdio_bus_match(struct device *dev, struct device_driver *drv)struct sdio_func *func = dev_to_sdio_func(dev);struct sdio_driver *sdrv = to_sdio_driver(drv);if (sdio_match_device(fu

57、nc, sdrv)return 1;return 0;第45页/共51页第44页/共51页第四十四页,共52页。45SDIOWIFI设备(shbi)驱动if_sdio_probe函数(hnsh)static int if_sdio_probe(struct sdio_func *func,const struct sdio_device_id *id)card-workqueue = create_workqueue(libertas_sdio);INIT_WORK(&card-packet_worker, if_sdio_host_to_card_worker);/初始化工作队列sdio_c

58、laim_host(func);/请求(qngqi)一个hostret = sdio_claim_irq(func, if_sdio_interrupt);/注册中断处理函数if_sdio_interrupt用来接收数据priv = lbs_add_card(card, &func-dev);/*会分配一个net_device结构,并启动一个内核线程lbs_thread,用于发送packet、cmd以及上报event。和初始化一些工作队列,并初始化一些底层操作函数static const struct net_device_ops lbs_netdev_ops = .ndo_start_xmi

59、t = lbs_hard_start_xmit,/发送函数 */priv-hw_host_to_card = if_sdio_host_to_card;/发送数据ret = lbs_start_card(priv);/会注册网络设备第46页/共51页第45页/共51页第四十五页,共52页。46具体的WIFI设备(shbi)驱动功能在实际(shj)的驱动开发中,主要的工作就是实现具体的设备驱动功能层。WIFI设备驱动操作函数接口在lbs_netdev_ops中赋值。其中,lbs_hard_start_xmit为发送函数。网络数据包的接收由中断引发,设备驱动功能层中另一个主体部分就是中断处理函数,

60、它负责读取硬件上接收的数据包并传送给上层协议。static const struct net_device_ops lbs_netdev_ops = .ndo_open = lbs_dev_open,.ndo_stop= lbs_eth_stop,.ndo_start_xmit= lbs_hard_start_xmit,.ndo_set_mac_address= lbs_set_mac_address,.ndo_tx_timeout = lbs_tx_timeout,.ndo_set_multicast_list = lbs_set_multicast_list,.ndo_change_mtu

61、= eth_change_mtu,.ndo_validate_addr= eth_validate_addr,;第47页/共51页第46页/共51页第四十六页,共52页。47数据(shj)发送流程WIFI数据包由用户空间的应用程序通过socket接口传递下来,到达驱动这一侧,最终会调用到lbs_hard_start_xmit这个函数,这个底层传输函数在if_sdio_probe中指定。网络上层调用lbs_hard_start_xmit函数后,packet和txpa头被拷贝到priv-tx_pending_buf成员。在线程lbs_thread被调度后通过priv-hw_host_to_card

62、(priv,MVMS_DAT,priv-tx_pending_buf,priv-tx_pending_len);函数将带txpa头的packet通过sdio接口发送到WIFI芯片。函数调用关系如下:WiFi驱动层提供给网络上层的发送数据接口是lbs_hard_start_xmit。在这个函数中唤醒专门处理数据发送、命令发送和事件处理的内核线程lbs_thread。内核线程lbs_thread中调用priv-hw_host_to_card(priv,MVMS_DAT,priv-tx_pending_buf,priv-tx_pending_len);即if_sdio_card_to_host函数。

63、在if_sdio_card_to_host函数中,把card-packet_worker(即if_sdio_host_to_card_worker)加入(jir)中工作队列中,等到该工作队列被调度后,经过SDIO接口发送数据给WiFi芯片。第48页/共51页第47页/共51页第四十七页,共52页。48数据(shj)接收流程WIFI数据(shj)包的接收通过中断来完成,当有无线数据(shj)到达WIFI模块时,WIFI模块发起硬件中断通知到SDIO总线控制器,然后总线控制器再发起SD中断,先进入到SD卡的中断处理函数。SD卡的中断处理函数s3cmci_irq在linux-2.6.35driver

64、smmchosts3cmci.c中定义,其中有如下代码:if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) /检测到SDIO中断if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) /判断(pndun)SDIO中断是否使能mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;writel(mci_dclear, host-base + S3C2410_SDIDSTA); /先将状态位清零mmc_signal_sdio_irq(host-mmc); /转到SDIO的中断处理函数return IRQ_

65、HANDLED;第49页/共51页第48页/共51页第四十八页,共52页。49数据(shj)接收流程mmc_signal_sdio_irq函数唤醒host-sdio_irq_thread线程,而该线程在sdio_card_irq_get函数(linux-2.6.35driversmmccoresdio_irq.c)中创建(chungjin),线程处理函数为sdio_irq_thread。最终调用if_sdio_interrupt中断处理函数。而if_sdio_interrupt函数在if_sdio_probe函数中通过sdio_claim_irq注册。而sdio_card_irq_get函数则

66、是在sdio_claim_irq中调用的。从上可知,if_sdio_interrupt函数是用来接收WIFI数据的中断处理函数。而最终也是使用SDIO的CMD52或者CMD53来读取数据。第50页/共51页第49页/共51页第四十九页,共52页。5050第51页/共51页第50页/共51页第五十页,共52页。51感谢您的观赏(gunshng)!第51页/共51页第五十一页,共52页。内容(nirng)总结1。修改源码目录下external/dhcpcd下的Android.mk文件。网络数据包的接收由中断引发,设备驱动功能层中另一个主体部分(b fen)就是中断处理函数。它主要对主机控制器进行一些初始化工作,其中主要函数有:。return driver_register(&drv-drv)。在这个函数中唤醒专门处理数据发送、命令发送和事件处理的内核线程lbs_thread。感谢您的观赏第五十二页,共52页。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号