【导语】在Android系统移植中,有很重要的一个部分工作,就是为新平台上的硬件设备移植驱动程序。因为Android系统是基于Linux kernel内核构建,所以这里说的移植驱动程序,其实就是基于Android系统平台开发适应移动设备的Linux内核驱动程序。
Android系统中使用了Linux内核作为自己的操作系统,除了linux的通用代码之外,主要还包含三个方面的东西:
体系结构和处理器
体系结构处理器和标准的设备驱动程序这两个方面是和硬件相关的,但是对于同一种硬件,在Android系统和标准的Linux系统中基本上是一样的。
Android专用的驱动程序
Android的专用驱动程序,通常是和硬件无关的驱动程序,仅仅在Android系统中使用。
Android系统中Linux内核与设备驱动的结构如下图示:
Android系统通常用于移动设备和其他的嵌入式设备,因此都基于ARM体系结构,在ARM体系结构具有多种处理器。因此,对于不同对的处理器,基于相同的外围设备,驱动程序也可能不一样。
需要说明的是上图中的Goldfish:
Android模拟器通过运行一个Goldfish的虚拟CPU ,Goldfish用来运行arm926t指令集(arm926t属于armv5构架),并且仿真了输入/输出,比如键盘输入和LCD 输出。这个模拟器其实是在qemu之上开发的,输入/输出是基于libSDL的。既然Goldfish是被模拟器运行的虚拟CPU,那么当Android在真实的硬件设备上运行时,我们就需要去掉它。
具体来说是有以下:
在实际应用中,通过下面的图,感受下一个量产的平板中用到了哪些硬件,体会下其中涉及到的驱动:
看一下Google为基于Linux kernel而定制的Android系统专用驱动程序:
Android Binder是基于OpenBinder框架的一个驱动,用于Android平台的进程间通信(InterProcess
Communication,IPC)。原来的Linux系统上层应用的进程间通信主要是D-bus(Desktop bus),采用消息总线的方式来进行IPC。
源代码位于drivers/staging/android/binder.c。
Android电源管理是基于标准Linux电源管理系统的轻量级Android电源管理驱动,针对嵌入式设备做
了很多优化。利用锁和定时器来切换系统状态,控制设备在不同状态下的功耗,已达到节能的目的。
源代码位于:
- [ ] kernel/power/earlysuspend.c
- [ ] kernel/power/consoleearlysuspend.c
- [ ] kernel/power/fbearlysuspend.c
- [ ] kernel/power/wakelock.c
- [ ] kernel/power/userwakelock.c
Android5.0版本引用JobSchedule调度程序,以便增加设备续航时间。
比Linux的标准的OOM(Out Of Memory)机制更加灵活,它可以根据需要
杀死进程以释放需要的内存。源代码位于 drivers/staging/ android/lowmemorykiller.c。
为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。源代码位于
mm/ashmem.c。
PMEM用于向用户空间提供连续的物理内存区域,DSP和某些设备只能工作在连续的物
理内存上。
源代码位于drivers/misc/pmem.c。
一个轻量级的日志设备,用于抓取Android系统的各种日志,是Linux所没有的。
源代码位于drivers/staging/android/logger.c。
提供了一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会
运行的时钟基准。源代码位于drivers/rtc/alarm.c。
一个基于标准 Linux USB gadget驱动框架的设备驱动,Android的USB驱动是基于gaeget框架的。
源代码位于
- [ ] drivers/usb/gadget/android.c
- [ ] drivers/usb/gadget/f_adb.c
- [ ] drivers/usb/gadget/f_mass_storage.c
为了提供调试功能,Android允许将调试日志信息写入一个被称为RAM Console的设备
里,它是一个基于RAM的Buffer。源代码位于drivers/staging/android / ram_console.c。
提供了对设备进行定时控制的功能,目前支持vibrator和LED设备。源代码位于
drivers/staging/android /timed_output.c(timed_gpio.c)。
Android采用Yaffs2作为MTD nand flash文件系统,源代码位于fs/yaffs2/目录下。
Yaffs2是一个快速稳定的应用于NAND和NOR Flash的跨平台的嵌入式设备文件系统,同其他Flash文件系统相比,
Yaffs2能使用更小的内存来保存其运行状态,因此它占用内存小。Yaffs2的垃圾回收非常简单而且快速,因此能表
现出更好的性能。Yaffs2在大容量的NAND Flash上的性能表现尤为突出,非常适合大容量的Flash存储。
Linux系统将设备驱动分为以下三类:
(1)字符设备
指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。
(2)块设备
指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。
(3)网络设备
为支持通过文件接口处理网络连接,Linux使用了源于BSD的套接字抽象,套接字keil看作应用程序、文件接口、内核的网络之间的代理。
驱动程序是介于系统和硬件之间的桥梁,实现硬件和系统之间的交互是我们底层开发的主要任务。在Android系统中,我们一般需要编写内核级和用户级的程序来完成具体的任务。
(1).编写自己的系统调用
系统调用是用户级程序访问内核最基本的方法,Linux提供了很多标准的系统调用(参见内核代码树中的include/asm-i386/unistd.h和arch/i386/kernel/entry.S文件),并且允许我们添加自己的系统调用来实现和内核的信息交换;
(2).编写驱动程序
Linux有一个重要的理念就是“一切皆文件”(everything is a file)。
用户空间的应用程序通过系统提供的统一交互接口 open() —— read() —— write() —— ioctl() —— close()方法,访问文件系统中/dev/目录下的一个文件来访问运行于内核空间的驱动程序,并通过驱动程序中实现的功能达到对硬件的访问。
(3). 使用proc 文件系统
proc是Linux提供的一种特殊的文件系统,推出它的目的就是提供一种便捷的用户和内核间的交互方式。proc 文件系统相对是比较简单的,不过proc文件的读写并不统一,读数据的buf指针直接指向的就是用户态的地址,可以用sprintf进行写入;而写方法却是内核态的地址,需要用get_user或者 copy_from_user之类的方法。
(4).使用虚拟文件系统
有些内核开发者认为利用ioctl()系统调用往往会似的系统调用意义不明确,而且难控制。而将信息放入到proc文件系统中会使信息组织混乱,因此也不赞成过多使用。他们建议实现一种孤立的虚拟文件系统来代替ioctl()和/proc,因为文件系统接口清楚,而且便于用户空间访问,同时利用虚拟文件系统使得利用脚本执行系统管理任务更家方便、有效。
(5).使用内存映像
Linux通过内存映像机制来提供用户程序对内存直接访问的能力。内存映像的意思是把内核中特定部分的内存空间映射到用户级程序的内存空间去。也就是说,用户空间和内核空间共享一块相同的内存。
上面讲了系统与硬件交互的几种方式提到了,在具体的交互中,驱动程序驱动具体的硬件模块工作时涉及到一个内核空间和用户空间交互的概念。
现代的计算机体系结构中存储管理通常都包含保护机制。提供保护的目的,是要避免系统中的一个任务访问属于另外的或属于操作系统的存储区域。如在IntelX86体系中,就提供了特权级这种保护机制,通过特权级别的区别来限制对存储区域的访问。
基于这种构架,Linux操作系统对自身进行了划分:一部分核心软件独立于普通应用程序,运行在较高的特权级别上,(Linux使用Intel体系的特权级3来运行内核。)它们驻留在被保护的内存空间上,拥有访问硬件设备的所有权限,Linux将此称为内核空间 。
相对的,其它部分被作为应用程序在用户空间 执行。它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,不能直接访问内核空间,当然还有其他一些具体的使用限制。(Linux使用Intel体系的特权级0来运行用户程序。)
版权声明:本文为【limin13215】原创文章,欢迎转载, 转载请注明链接地址:http://blog.csdn.net/limin2928/article/details/72676518