290 likes | 777 Views
Android 嵌入式系统软件开发. Android Embedded System Software Development 周 庆 国 ( zhouqg@lzu.edu.cn ) 兰 州 大 学. 5.1 framebuffer 驱动. 第五章 Android 设备驱动. 5.2 键盘驱动. 5.3 音频驱动. 5.4 蓝牙驱动. 5.5 wlan 驱动. 5.1 Framebuffer 驱动. Framebuffer 驱动是标准的显示设备的驱动
E N D
Android嵌入式系统软件开发 Android Embedded System Software Development 周 庆 国 (zhouqg@lzu.edu.cn) 兰 州 大 学
5.1 framebuffer驱动 第五章 Android 设备驱动 5.2键盘驱动 5.3音频驱动 5.4蓝牙驱动 5.5 wlan驱动
5.1 Framebuffer驱动 Framebuffer驱动是标准的显示设备的驱动 Framebuffer驱动是一个字符设备,这个驱动在文件系统中的设备节点通常是:/dev/fbX 每个系统可以有多个显示设备,使用/dev/fb0、/dev/fb1等来表示主设备号为29,次设备号递增增长(由每个Framebuffer程序的注册顺序决定) Framebuffer驱动在用户空间大多使用ioctl、mmap等文件系统的接口进行操作,ioctl用于获得和设置信息,mmap可以将Framebuffer的内存映射到用户空间。 Framebuffer驱动也可以直接支持write操作,直接用写的方式输出显示内容。 Framebuffer驱动的主要头文件:include/linux/fb.hFramebuffer驱动核心实现:drivers/video/fbmem.cFramebuffer驱动中核心的数据接口是fb_info 3
Framebuffer驱动 Framebuffer驱动需要定义一个实现fb_info结构、实现fb_ops中的各个函数指针。 在配置Linux系统时,Framebuffer驱动的配置选项是:"Device Drivers">"Graphics support"其配置文件为:drivers/video/Kconfig,其中也包含了文本模式和控制台、启动图标(bootup Logo)等子选项支持,具体的Framebuffer驱动由每一个平台支持 Framebuffer驱动是android中的标准设备,但是路径稍有不同/dev/graphic/fb0,android对Framebuffer驱动的使用方式是标准的,在android的GUI系统中,通过调用Framebuffer驱动的标准接口,实现显示设备的抽象。Framebuffer设备节点由init进程自动创建,被libui库调用。 4
FrameBuffer SurfaceFlinger是一个服务,主要是负责合成各窗口的Surface,通过OpenGLES显示到FrameBuffer上。 DisplayHardware是对显示设备的抽象,包括FrameBuffer和Overlay。它加载FrameBuffer和Overlay插件,并初始化OpenGLES。 5
FrameBuffer • FramebufferNativeWindow 是framebuffer 的抽象,它负责加载libgralloc,并打开framebuffer设备。FramebufferNativeWindow并不直接使用 framebuffer,而是自己创建了两个Buffer: queueBuffer负责显示一个Buffer到屏幕上,它调用fb->post去显示。 dequeueBuffer获取一个空闲的Buffer,用来在后台绘制。 • 这两个函数由eglSwapBuffers调过来,调到 6
FrameBuffer egl_window_surface_v2_t::swapBuffers: nativeWindow->queueBuffer(nativeWindow, buffer); nativeWindow->dequeueBuffer(nativeWindow, &buffer); msm7k/liboverlay是Overlay的实现,与其它平台不同的是,高通平台上的Overlay并不是提供一个framebuffer设备,而通过fb0的ioctl来实现的,ioctl分为两类操作: OverlayControlChannel用于设置参数,比如设置Overlay的位置,宽度和高度。 7
FrameBuffer • OverlayDataChannel用于显示Overlay,其中最重要的函数就是queueBuffer • msm7k/libgralloc 是显示缓存的抽象,包括framebuffer和普通Surface的Buffer。 • framebuffer只是/dev/graphic/fb0的包装,Surface的Buffer则是对/dev/pmem、ashmem和GPU内存(msm_hw3dm)的包装,它的目标主要是方便硬件加速,因为 DMA传输使用物理地址,要求内存在物理地址上连续。 • msm7k/libcopybit这是2D加速库,主要负责Surface的拉伸、旋转和合成等操作。它有两种实现方式: copybit.cpp: 基于fb0的ioctl(MSMFB_BLIT)的实现。 copybit_c2d.cpp: 基于kgsl的实现。 • pmem misc/pmem.c: 对物理内存的管理,算法和用户空间的接口。 board-msm7x27.c定义了物理内存的缺省大小。 8
FrameBuffer msm_msm7x2x_allocate_memory_regions分配几大块内存用于给pmem做二次分配。 KGSL 3D图形加速驱动程序,源代码drivers/gpu/msm目录下,是对GPU的包装,给OpenGLES 2.0提供抽象的接口。 msm_fb msm_fb.c: framebuffer, overlay和blit的用户接口。 mdp_dma.c: 对具体显示设备的包装,提供两种framebuffer更新的方式: mdp_refresh_screen: 定时更新。 mdp_dma_pan_update: 通过pan display主动更新。 mdp_dma_lcdc.c:针对LCD实现的显示设备,mdp_lcdc_update用更新framebuffer。 9
5.2 键盘驱动 Android基本键盘驱动采用了Linux的input和event机制,内核中通过platform机制将按键信息注册进系统 键盘驱动通过input_register_device()调用,注册成标准输入设备/dev/input/event0 驱动上报按键值要和Android里面的/system/usr/keylayout/*.kl文件里面键值表的一致 按键信息:事件类型+事件码+事件值(键值) 事件类型:表示键盘或touch或其他输入设备; 事件码 :表明是键盘上什么键被操作; 事件值 :表明这项操作是按下还是松开; 10
键盘 按键结构体中特别重要的是code变量中的数据,android通过event机制可以获取这个数据。 在android系统中,获取到键盘的键值后,会搜索/system/usr/keylayout/gpio-keys.kl这个文件key 158 BACK WAKE_DROPPEDkey 139 MENU WAKE_DROPPEDkey 102 HOME WAKEkey 116 ENDCALL WAKE_DROPPEDkey 99 ROTATOR 如果code与其中的键值相对应,android就会响应对应的按键信息。 至于android如何建立gpio-key.kl这个文件,以及获取到键值后的处理,感兴趣的可以自行研究。 11
5.3 音频驱动 12
音频 (1)Audio的Java部分 代码路径:frameworks/base/media/java/android/media 与audio相关的java package是android.media,主要包含audio manager和audio系统的几个类,这部分主要给上层的AP部分提供audio相关的接口 (2)Audio的JNI部分 代码路径:frameworks/base/core/jni Android系统会生成一个libandroid_runtime.so,audio的JNI是其中的一个部分。 13
音频 (3)audio frameworks 头文件路径:frameworks/base/include/media/ 代码路径:frameworks/base/media/libmedia/ Audio本地框架是media库的一部分,本部分的内容被编译成库libmedia.so,提供audio部分的接口(其中包括基于binder的IPC机制)。 14
音频 (4)Audio Flinger 代码路径:frameworks/base/libs/audioflinger 这部分内容被编译成库libaudioflinger.so,它是audio系统的本地服务部分 (5)HAL 头文件路径:hardware/libhardware_legacy/include/hardware Audio硬件抽象层的实现在各个系统中可能不同,需要使用代码继承相应的类并实现他们,作为android系统本地框架和驱动程序的接口 15
音频 (6)ALAS lib 代码路径:external/alsa-lib 在HAL中通过继承android提供的基本类,并实现类中函数,但是并不是直接操作linux kernel driver,而是通过alsa lib提供的API,而alsa lib中接口会使用系统调用的接口(open, ioctl, write, read etc.)实现与driver的对接。 16
音频 (7)audio driver 系统相关代码:sound/soc/s3c24xx/smdks5p_rt5625.c 声卡驱动核心:sound/soc/soc-core.c Codec驱动代码:sound/soc/codecs/rt5625.c 系统相关代码是和s5pc100平台相关的codec一些配置和资源的定义,声卡驱动核心主要是根据linux kernel已经成熟的driver体系架构来注册驱动统一管理声卡相关组件的驱动,codec驱动代码是和具体使用audio codec芯片的驱动部分代码。 17
音频 18
5.4 蓝牙驱动 19
蓝牙 在linux中,蓝牙设备驱动是网络设备,使用网络接口。 蓝牙设备的网络协议,所定义的协议族为: AF_BLUETOOTH (31) 蓝牙协议部分头文件: include/net/bluetooth/hci_core.h include/net/bluetooth/bluetooth.h 蓝牙协议源代码文件: net/bluetooth/* 蓝牙系统的协议和驱动程序在内核进行menuconfig配置时,配置选项为:networking support >bluetooth subsystem support >bluetooth device drivers 20
蓝牙 蓝牙协议对应的配置文件为:net/bluetooth/Kconfig;蓝牙系统驱动程序对应的配置文件为:drivers/bluetooth/Kconfig 在蓝牙协议部分,包含了主控制接口(HCI),SCO(SCO audio links)模块,L2CAP(Logical Link Control and Adaptation Protocol)模块,BNEP模块(蓝牙网络封装协议)等,BNEP等模块内容包含在其中的几个子目录中。 蓝牙驱动中的不同接口文件: hci_vhci.c 蓝牙虚拟主控制器驱动程序; hci_uart.c 蓝牙串口驱动程序; btusb.c 蓝牙usb驱动程序; btsdio.c 蓝牙sdio驱动程序; 21
5.5 wlan驱动 wifi 在linux中,Wlan设备属于网络设备,采用网络接口。 Wlan在用户空间采用标准的socket接口进行控制。 WiFi协议部分头文件:include/net/wireless.h WiFi协议部分源文件:net/wireless/* WiFi驱动程序部分:drivers/net/wireless/* 目前的实现不支持 Ad-hoc 方式 22
wifi 在 SystemServer 启动的时候,会生成一个 ConnectivityService 的实例 ConnectivityService 的构造函数会创建WifiService if (DBG) Log.v(TAG, "Starting Wifi Service."); mWifiStateTracker = new WifiStateTracker(context, handler); WifiService wifiService = new WifiService(context,mWifiStateTracker); ServiceManager.addService(Context.WIFI_SERVICE, wifiService); 23
wifi WifiStateTracker 会创建 WifiMonitor 接收来自底层的事件,WifiService 和WifiMonitor 是整个模块的核心。 WifiService 负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor监视线程和把命令下发给 wpa_supplicant,而 WifiMonitor 则负责从 wpa_supplicant接收事件通知。 24
WIFI模块初始化 25
WIFI模块启动 26
WIFI 当用户按下Wifi 按钮后,Android 会调用WifiEnabler 的onPreferenceChange,再由WifiEnabler调用WifiManager 的setWifiEnabled 接口函数,通过AIDL,实际调用的是WifiService 的setWifiEnabled 函数,WifiService 接着向自身发送一条MESSAGE_ENABLE_WIFI 消息,在处理该消息的代码中做真正的使能工作: 首先装载WIFI 内核模块(该模块的位置硬编码为”/system/lib/modules/libertas_sdio.ko” ), 然后启动wpa_supplicant ( 配置文件硬编码为”/data/misc/wifi/wpa_supplicant.conf”),再通过WifiStateTracker 来启动WifiMonitor 中的监视线程。 27
谢谢 28 28 28