android驱动_android驱动开发 - CSDN
精华内容
参与话题
  • Android驱动深度开发视频教程

    万人学习 2018-11-30 10:35:12
    也许是中国第一个讲解android驱动的课程,涵盖: bootloader,内核移植,INIT进程,框架(BINDER IPC,SERVICE FRAMEWORK Activity Manager Serive,JNI,HAL等),binder驱动,logger,Ashmen,电源管理,常用驱动(如灯光...
  • Android系统移植:驱动

    万次阅读 多人点赞 2017-05-24 15:13:16
    【导语】在Android系统移植中,有很重要的一个部分工作,就是为新平台上的硬件设备移植驱动程序。因为Android系统是基于Linux kernel内核构建,所以这里说的移植驱动程序,其实就是基于Android系统平台开发适应移动...

    【导语】在Android系统移植中,有很重要的一个部分工作,就是为新平台上的硬件设备移植驱动程序。因为Android系统是基于Linux kernel内核构建,所以这里说的移植驱动程序,其实就是基于Android系统平台开发适应移动设备的Linux内核驱动程序。

    一. Android系统中Linux内核与设备驱动

    Android系统中使用了Linux内核作为自己的操作系统,除了linux的通用代码之外,主要还包含三个方面的东西:

    • 体系结构和处理器
      体系结构处理器和标准的设备驱动程序这两个方面是和硬件相关的,但是对于同一种硬件,在Android系统和标准的Linux系统中基本上是一样的。

    • Android专用的驱动程序
      Android的专用驱动程序,通常是和硬件无关的驱动程序,仅仅在Android系统中使用。

    • 标准的linux设备驱动程序

    Android系统中Linux内核与设备驱动的结构如下图示:

    这里写图片描述

    Android系统通常用于移动设备和其他的嵌入式设备,因此都基于ARM体系结构,在ARM体系结构具有多种处理器。因此,对于不同对的处理器,基于相同的外围设备,驱动程序也可能不一样。

    需要说明的是上图中的Goldfish:

    Android模拟器通过运行一个Goldfish的虚拟CPU ,Goldfish用来运行arm926t指令集(arm926t属于armv5构架),并且仿真了输入/输出,比如键盘输入和LCD 输出。这个模拟器其实是在qemu之上开发的,输入/输出是基于libSDL的。既然Goldfish是被模拟器运行的虚拟CPU,那么当Android在真实的硬件设备上运行时,我们就需要去掉它。

    二. Android系统上的设备驱动

    • 基本图形用户界面(GUI)部分:包括显示部分、用户输入部分和硬件相关的加速部分,还包括媒体编解码和OpenGL等。
    • 音视频输入输出部分:包括音频、视频输出和摄像头等。
    • 连接部分:包括无线局域网、蓝牙、GPS等。
    • 电话部分:包括通话、GSM等。
    • 附属部件:包括传感器、背光、振动器等。

    具体来说是有以下:

    • [x] Display显示部分:包括FrameBuffer驱动和Gralloc模块。
    • [x] Input用户输入部分:包括Event驱动和EventHub。
    • [x] Codec多媒体编解码:包括硬件Codec驱动和Codec插件,例如OpenMax。
    • [x] 3DAccelerator(3D加速器)部分:包括硬件OpenGL驱动和OpenGL插件。
    • [x] Audio音频部分:包括Audio驱动和Audio硬件抽象层。
    • [x] VideoOut视频输出部分:包括视频显示驱动和Overlay硬件抽象层。
    • [x] Camera摄像头部分:包括Camera驱动(通常是v4l2)和Camera硬件抽象层。
    • [x] Phone电话部分:包括Modem驱动程序和RIL库。
    • [x] GPS全球定位系统部分:包括GPS驱动(例如串口)和GPS硬件抽象层。
    • [x] Wi-Fi无线局域网部分:包括Wlan驱动和协议和Wi-Fi的适配层。
    • [x] BlueTooth蓝牙部分:包括BT驱动和协议及BT的适配层。
    • [x] Sensor传感器部分:包括Sensor驱动和Sensor硬件抽象层。
    • [x] Vibrator振动器部分:包括Vibrator驱动和Vibrator硬件抽象层。
    • [x] Light背光部分:包括Light驱动和Light硬件抽象层。
    • [x] Alarm警告器部分:包括Alarm驱动和RTC系统和用户空间调用。
    • [x] Battery电池部分:包括电池部分驱动和电池的硬件抽象层。

    在实际应用中,通过下面的图,感受下一个量产的平板中用到了哪些硬件,体会下其中涉及到的驱动:
    全志A33平板PCBA,如有侵权,请及时告知

    三.Android系统专用驱动

    看一下Google为基于Linux kernel而定制的Android系统专用驱动程序:

    (1)Android Binder

    Android Binder是基于OpenBinder框架的一个驱动,用于Android平台的进程间通信(InterProcess
    Communication,IPC)。原来的Linux系统上层应用的进程间通信主要是D-bus(Desktop bus),采用消息总线的方式来进行IPC。
    源代码位于drivers/staging/android/binder.c。

    (2)Android电源管理

    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调度程序,以便增加设备续航时间。

    (3)低内存管理器(Low Memory Killer)

    比Linux的标准的OOM(Out Of Memory)机制更加灵活,它可以根据需要
    杀死进程以释放需要的内存。源代码位于 drivers/staging/ android/lowmemorykiller.c。

    (4)匿名共享内存(Ashmem)

    为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。源代码位于
    mm/ashmem.c。

    (5)Android PMEM(Physical)

    PMEM用于向用户空间提供连续的物理内存区域,DSP和某些设备只能工作在连续的物
    理内存上。
    源代码位于drivers/misc/pmem.c。

    (6)Android Logger

    一个轻量级的日志设备,用于抓取Android系统的各种日志,是Linux所没有的。
    源代码位于drivers/staging/android/logger.c。

    (7)Android Alarm

    提供了一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会
    运行的时钟基准。源代码位于drivers/rtc/alarm.c。

    (8)USB Gadget驱动

    一个基于标准 Linux USB gadget驱动框架的设备驱动,Android的USB驱动是基于gaeget框架的。
    源代码位于
    - [ ] drivers/usb/gadget/android.c
    - [ ] drivers/usb/gadget/f_adb.c
    - [ ] drivers/usb/gadget/f_mass_storage.c

    (9)Android Ram Console

    为了提供调试功能,Android允许将调试日志信息写入一个被称为RAM Console的设备
    里,它是一个基于RAM的Buffer。源代码位于drivers/staging/android / ram_console.c。

    (10)Android timed device

    提供了对设备进行定时控制的功能,目前支持vibrator和LED设备。源代码位于
    drivers/staging/android /timed_output.c(timed_gpio.c)。

    (11)Yaffs2 文件系统

    Android采用Yaffs2作为MTD nand flash文件系统,源代码位于fs/yaffs2/目录下。
    Yaffs2是一个快速稳定的应用于NAND和NOR Flash的跨平台的嵌入式设备文件系统,同其他Flash文件系统相比,
    Yaffs2能使用更小的内存来保存其运行状态,因此它占用内存小。Yaffs2的垃圾回收非常简单而且快速,因此能表
    现出更好的性能。Yaffs2在大容量的NAND Flash上的性能表现尤为突出,非常适合大容量的Flash存储。

    四.Android驱动开发主要工作

    Linux系统将设备驱动分为以下三类:

    • (1)字符设备

      指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。

    • (2)块设备

      指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。

    • (3)网络设备

      为支持通过文件接口处理网络连接,Linux使用了源于BSD的套接字抽象,套接字keil看作应用程序、文件接口、内核的网络之间的代理。

    驱动程序是介于系统和硬件之间的桥梁,实现硬件和系统之间的交互是我们底层开发的主要任务。在Android系统中,我们一般需要编写内核级和用户级的程序来完成具体的任务。

    4.1 实现系统和硬件之间交互的几种方式

    • (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通过内存映像机制来提供用户程序对内存直接访问的能力。内存映像的意思是把内核中特定部分的内存空间映射到用户级程序的内存空间去。也就是说,用户空间和内核空间共享一块相同的内存。

    4.2 内核空间和用户空间的交互

    上面讲了系统与硬件交互的几种方式提到了,在具体的交互中,驱动程序驱动具体的硬件模块工作时涉及到一个内核空间和用户空间交互的概念。

    现代的计算机体系结构中存储管理通常都包含保护机制。提供保护的目的,是要避免系统中的一个任务访问属于另外的或属于操作系统的存储区域。如在IntelX86体系中,就提供了特权级这种保护机制,通过特权级别的区别来限制对存储区域的访问。

    基于这种构架,Linux操作系统对自身进行了划分:一部分核心软件独立于普通应用程序,运行在较高的特权级别上,(Linux使用Intel体系的特权级3来运行内核。)它们驻留在被保护的内存空间上,拥有访问硬件设备的所有权限,Linux将此称为内核空间

    相对的,其它部分被作为应用程序在用户空间 执行。它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,不能直接访问内核空间,当然还有其他一些具体的使用限制。(Linux使用Intel体系的特权级0来运行用户程序。)

    通过下面的图,看一下内核空间与用户空间的交互关系:
    这里写图片描述

    版权声明:本文为【limin13215】原创文章,欢迎转载, 转载请注明链接地址:http://blog.csdn.net/limin2928/article/details/72676518

    展开全文
  • Android驱动入门系列(一)

    万次阅读 多人点赞 2013-03-08 17:07:41
    Android驱动入门系列(一) —— Android驱动简介及编写第一个Android驱动   以下文章参考网上搜到的《Android驱动开发全过程(有图有真相)》一文,其中根据自己的实际编写情况作了部分修改,不用作商业用途 ...

    Android驱动入门系列(一)   —— Android驱动简介及编写第一个Android驱动

     

    以下文章参考网上搜到的《Android驱动开发全过程(有图有真相)》一文,其中根据自己的实际编写情况作了部分修改,不用作商业用途

    前言

    意外在网上发现了这扁文章,看后感觉很有必要分享,所以整理并上传,希望大家喜欢。

    Android 硬件抽象层(HAL)概要介绍和学习计划

    Android 的硬件抽象层,简单来说,就是对Linux 内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把

    对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在

    用户空间,而Linux 内核驱动程序运行在内核空间。为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间

    不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害

    厂家的利益。我们知道,Linux 内核源代码版权遵循GNU License,而Android 源代码版权遵循Apache License,前者在发布产

    品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在Linux 驱动层,那就意味着发布时要公

    开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了,在手机市场竞争激烈的今天,这对厂家来

    说,损害是非常大的。因此,Android 才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问

    硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中

    去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android 被踢出了Linux 内核主线代码树中。大家想

    想,Android 放在内核空间的驱动程序对硬件的支持是不完整的,把Linux 内核移植到别的机器上去时,由于缺乏硬件抽象层

    的支持,硬件就完全不能用了,这也是为什么说Android 是开放系统而不是开源系统的原因。撇开这些争论,学习Android

    件抽象层,对理解整个Android 整个系统,都是极其有用的,因为它从下到上涉及到了Android 系统的硬件驱动层、硬件抽象

    层、运行时库和应用程序框架层等等,下面这个图阐述了硬件抽象层在Android 系统中的位置,以及它和其它层的关系:

    在学习Android 硬件抽象层的过程中,我们将会学习如何在内核空间编写硬件

    驱动程序、如何在硬件抽象层中添加接口支持访问硬件、如何在系统启动时

    提供硬件访问服务以及 如何编写JNI 使得可以通过Java 接口来访问硬件,而

    作为中间的一个小插曲,我们还将学习一下如何在Android 系统中添加一个C

    可执行程序来访问硬件驱动程序。由于这是一个系统的学习过程,笔者将分

    成六篇文章来描述每一个学习过程,包括:

    . Android 内核源代码工程中编写硬件驱动程序。

    . Android 系统中增加C 可执行程序来访问硬件驱动程序。

    . Android 硬件抽象层增加接口模块访问硬件驱动程序。

    . Android 系统中编写JNI 方法在应用程序框架层提供Java 接口访问硬件。

    . Android 系统的应用程序框架层增加硬件服务接口。

    . Android 系统中编写APP 通过应用程序框架层访问硬件服务。

    学习完这六篇文章,相信大家对Android 系统就会有一个更深刻的认识了,敬请关注。

     

     

    在Ubuntu 上为Android 系统编写Linux 内核驱动程序

    这里,我们不会为真实的硬件设备编写内核驱动程序。为了方便描述为Android 系统编写内核驱动程序的过程,我们使用一

    个虚拟的硬件设备,这个设备只有一个4 字节的寄存器,它可读可写。想起我们第一次学习程序语言时,都喜欢用“Hello, World

    作为例子,这里,我们就把这个虚拟的设备命名为“hello”,而这个内核驱动程序也命名为hello 驱动程序。其实,Android

    核驱动程序和一般Linux 内核驱动程序的编写方法是一样的,都是以Linux 模块的形式实现的,具体可参考前面Android 学习

    启动篇一文中提到的Linux Device Drivers 一书。不过,这里我们还是从Android 系统的角度来描述Android 内核驱动程序的编

    写和编译过程。

    一. 参照这两篇文章在Ubuntu 上下载、编译和安装Android 最新源代码和在Ubuntu 上下载、编译和安装Android 最新内核源

    代码(Linux Kernel)准备好Android 内核驱动程序开发环境。(我这里使用的Android 4.0.4版本)

    二. 进入到samsung_android_kernel_3.0/drivers目录,新建hello 目录:

    root@brantyou-ubuntu:~/workspace/samsung_android_kernel_3.0# cd drivers/
    root@brantyou-ubuntu:~/workspace/samsung_android_kernel_3.0/drivers# mkdir hello

     

    三. 在hello 目录中增加hello.h 文件:

    #ifndef _HELLO_ANDROID_H_
    #define _HELLO_ANDROID_H_
    
    #include <linux/cdev.h>
    #include <linux/semaphore.h>
    
    #define	HELLO_DEVICE_NODE_NAME		"hello"
    #define	HELLO_DEVICE_FILE_NAME		"hello"
    #define	HELLO_DEVICE_PROC_NAME		"hello"
    #define	HELLO_DEVICE_CLASS_NAME		"hello"
    
    struct hello_android_dev{
    	int val;
    	struct semaphore sem;
    	struct cdev dev;
    };
    
    #endif
    
    

    这个头文件定义了一些字符串常量宏,在后面我们要用到。此外,还定义了一个字符设备结构体hello_Android_dev,这个就

    是我们虚拟的硬件设备了,val 成员变量就代表设备里面的寄存器,它的类型为intsem 成员变量是一个信号量,是用同步

    访问寄存器val 的,dev 成员变量是一个内嵌的字符设备,这个Linux 驱动程序自定义字符设备结构体的标准方法。

    四.在hello 目录中增加hello.c 文件,这是驱动程序的实现部分。驱动程序的功能主要是向上层提供访问设备的寄存器的值,

    包括读和写。这里,提供了三种访问设备寄存器的方法,一是通过proc 文件系统来访问,二是通过传统的设备文件的方法来

    访问,三是通过devfs 文件系统来访问。下面分段描述该驱动程序的实现。

    首先是包含必要的头文件和定义三种访问设备的方法:hello.c

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/proc_fs.h>
    #include <linux/device.h>
    #include <asm/uaccess.h>
    
    #include "hello.h"
    
    // * Master and slave devices number variables
    static int hello_major = 0;
    static int hello_minor = 0;
    
    // * device types and device variables
    static struct class* hello_class = NULL;
    static struct hello_android_dev* hello_dev = NULL;
    
    // * traditional method of operation of the device file
    static int hello_open(struct inode* inode, struct file* flip);
    static int hello_release(struct inode* inode, struct file* flip);
    static ssize_t hello_read(struct file* flip, char __user* buf, size_t count, loff_t* f_pos);
    static ssize_t hello_write(struct file* flip, const char __user* buf, size_t count, loff_t* f_pos);
    
    // * the method of operation of the device file table
    static struct file_operations hello_fops = {
    	.owner = THIS_MODULE,
    	.open = hello_open,
    	.release = hello_release,
    	.read = hello_read,
    	.write = hello_write,
    };
    
    
    // * access to set property methods
    static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
    static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
    
    // * define the device properties
    static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);
    
    
    // * open the device methods
    static int hello_open(struct inode* inode, struct file* flip)
    {
    	struct hello_android_dev* dev;
    
    	// save the device struct to the private area
    	dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
    	flip->private_data = dev;
    
    	return 0;
    }
    
    // * release
    static int hello_release(struct inode* inode, struct file* filp)
    {
    	return 0;
    }
    
    // * read
    static ssize_t hello_read(struct file* filp, char __user* buf, size_t count, loff_t* f_pos)
    {
    	ssize_t err = 0;
    	struct hello_android_dev* dev = filp->private_data;
    
    	// async access
    	if(down_interruptible( &(dev->sem) )){
    		return -ERESTARTSYS;
    	}
    
    	if(count < sizeof(dev->val) ){
    		goto out;
    	}
    
    	// 
    	if(copy_to_user(buf, &(dev->val), sizeof(dev->val) )){
    		err = -EFAULT;
    		goto out;
    	}
    
    	err = sizeof(dev->val);
    
    out:
    	up(&(dev->sem));
    
    	return err;
    }
    
    // * write
    static ssize_t hello_write(struct file* filp, const char __user* buf, size_t count, loff_t* f_pos)
    {
    	struct hello_android_dev* dev = filp->private_data;
    	ssize_t err = 0;
    	
    	// async access
    	if(down_interruptible( &(dev->sem) )){
    		return -ERESTARTSYS;
    	}
    	
    	if(count != sizeof(dev->val) ){
    		goto out;
    	}
    	
    	// save the buffer value to device registers
    	if( copy_from_user( &(dev->val), buf, count) ){
    		err = -EFAULT;
    		goto out;
    	}
    	
    	err = sizeof(dev->val);
    
    out:
    	up(&(dev->sem));
    	return err;
    }
    
    // * read the registers value val to the buffer buf, inner
    static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf)
    {
    	int val = 0;
    	
    	// async access
    	if(down_interruptible( &(dev->sem) )){
    		return -ERESTARTSYS;
    	}
    	
    	val = dev->val;
    	up( &(dev->sem) );
    	
    	return snprintf(buf, PAGE_SIZE, "%d\n", val);
    }
    
    // * write the buffer value buf to the device registers val, inner
    static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count)
    {
    	int val = 0;
    	
    	// translate the string to number
    	val = simple_strtol(buf, NULL, 10);
    	
    	// async access
    	if(down_interruptible( &(dev->sem) )){
    		return -ERESTARTSYS;
    	}
    	
    	dev->val = val;
    	up( &(dev->sem));
    	
    	return count;
    }
    
    // * read the device properties val
    static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf)
    {
    	struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
    	
    	return __hello_get_val(hdev, buf);
    }
    
    // * write the device properties val
    static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
    {
    	struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
    	
    	return __hello_set_val(hdev, buf, count);
    }
    
    // * read the device registers val, and save to the page buffer
    static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data)
    {
    	if(off > 0){
    		*eof = 1;
    		return 0;
    	}
    	
    	return __hello_get_val(hello_dev, page);
    }
    
    // * save the buffer value buff to the device registers val
    static ssize_t hello_proc_write(struct file* filp, const char __user* buff, unsigned long len, void* data)
    {
    	int err = 0;
    	char* page = NULL;
    	
    	if(len > PAGE_SIZE){
    		printk(KERN_ALERT"The buff is too large:%lu.\n", len);
    		return -EFAULT;
    	}
    	
    	page = (char*)__get_free_page(GFP_KERNEL);
    	if(!page){
    		printk(KERN_ALERT"Failed to alloc page.\n");
    		return -ENOMEM;
    	}
    	
    	// copy the user buffer value to kernel buffer
    	if(copy_from_user(page, buff, len) ){
    		printk(KERN_ALERT"Failed to copy buff from user.\n");
    		err = -EFAULT;
    		goto out;
    	}
    	
    	err = __hello_set_val(hello_dev, page, len);
    	
    out:
    	free_page( (unsigned long)page);
    	return err;
    }
    
    // * create /proc/hello file
    static void hello_create_proc(void)
    {
    	struct proc_dir_entry* entry;
    	entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
    	if(entry){
    		entry->owner = THIS_MODULE;
    		entry->read_proc = hello_proc_read;
    		entry->write_proc = hello_proc_write;
    	}
    }
    
    // * delete /proc/hello file
    static void hello_remove_proc(void)
    {
    	remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
    }
    
    // * init device
    static int __hello_setup_dev(struct hello_android_dev* dev)
    {
    	int err;
    	dev_t devno = MKDEV(hello_major, hello_minor);
    	
    	memset(dev, 0, sizeof(struct hello_android_dev) );
    	
    	cdev_init( &(dev->dev), &hello_fops);
    	dev->dev.owner = THIS_MODULE;
    	dev->dev.ops = &hello_fops;
    	
    	// registe charater device
    	err = cdev_add( &(dev->dev), devno, 1);
    	if(err){
    		return err;
    	}
    	
    	// init single and registers value val
    	init_MUTEX(&(dev->sem));
    	dev->val = 0;
    	
    	return 0;
    }
    
    // * load module
    static int __init hello_init(void)
    {
    	int err = -1;
    	dev_t dev = 0;
    	struct device* temp = NULL;
    	
    	printk(KERN_ALERT"Initializing hello device.\n");
    	
    	// malloc master and slave device number
    	err = alloc_chrdev_region( &dev, 0, 1, HELLO_DEVICE_NODE_NAME);
    	if(err < 0){
    		printk(KERN_ALERT"Failed to alloc char dev region.\n");
    		goto fail;
    	}
    	
    	hello_major = MAJOR(dev);
    	hello_minor = MINOR(dev);
    	
    	// alloc hello device struct valiriable
    	hello_dev = kmalloc( sizeof(struct hello_android_dev), GFP_KERNEL);
    	if(!hello_dev){
    		err = -ENOMEM;
    		printk(KERN_ALERT"Failed to alloc hello_dev.\n");
    		goto unregister;
    	}
    	
    	// init device
    	err = __hello_setup_dev(hello_dev);
    	if(err){
    		printk(KERN_ALERT"Failed to setup dev:%d.\n", err);
    		goto cleanup;
    	}
    	
    	// create device type directory hello on /sys/class/
    	hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
    	if(IS_ERR(hello_class)){
    		err = PTR_ERR(hello_class);
    		printk(KERN_ALERT"Failed to create hello class.\n");
    		goto destroy_cdev;
    	}
    	
    	// create device file hello on /dev/ and /sys/class/hello
    	temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
    	if(IS_ERR(temp)){
    		err = PTR_ERR(temp);
    		printk(KERN_ALERT"Failed to create hello device.\n");
    		goto destroy_class;
    	}
    	
    	// create property file val on /sys/class/hello/hello
    	err = device_create_file(temp, &dev_attr_val);
    	if(err < 0){
    		printk(KERN_ALERT"Failed to create attribute val.\n");
    		goto destroy_device;
    	}
    	
    	dev_set_drvdata(temp, hello_dev);
    	
    	// create /proc/hello file
    	hello_create_proc();
    	
    	printk(KERN_ALERT"Successed to initialize hello device.\n");
    	return 0;
    	
    destroy_device:
    	device_destroy(hello_class, dev);
    
    destroy_class:
    	class_destroy(hello_class);
    
    destroy_cdev:
    	cdev_del(&hello_dev->dev);
    
    cleanup:
    	kfree(hello_dev);
    
    unregister:
    	unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);
    
    fail:
    	return err;
    }
    
    // * unload module
    static void __exit hello_exit(void)
    {
    	dev_t devno = MKDEV(hello_major, hello_minor);
    	
    	printk(KERN_ALERT"Destroy hello device.\n");
    	
    	// delete /proc/hello file
    	hello_remove_proc();
    	
    	// destroy device type and device
    	if(hello_class){
    		device_destroy(hello_class, MKDEV(hello_major, hello_minor) );
    		class_destroy(hello_class);
    	}
    	
    	// delete character device and release device memory
    	if(hello_dev){
    		cdev_del(&(hello_dev->dev) );
    		kfree(hello_dev);
    	}
    	
    	// destroy device number
    	unregister_chrdev_region(devno, 1);
    }
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("First Android Device");
    
    module_init(hello_init);
    module_exit(hello_exit);


     

    五.在hello 目录中新增Kconfig 和Makefile 两个文件,其中Kconfig 是在编译前执行配置命令make menuconfig 时用到的,而

    Makefile 是执行编译命令make 是用到的:

    Kconfig 文件的内容:

    config HELLO
    tristate "First Android Driver"
    default n
    help
    This is brantyou first Android driver.


    Makefile 文件的内容:

    obj-$(CONFIG_HELLO) += hello.o

     

    Kconfig 文件中,tristate 表示编译选项HELLO 支持在编译内核时,hello 模块支持以模块、内建和不编译三种编译方

    法,默认是不编译,因此,在编译内核前,我们还需要执行make menuconfig 命令来配置编译选项,使得hello 可以以模块或

    者内建的方法进行编译。

    Makefile 文件中,根据选项HELLO 的值,执行不同的编译方法。

    六. 修改arch/arm/Kconfig 和drivers/Kconfig 两个文件,在menu "Device Drivers"和endmenu 之间添加一行:

    source "drivers/hello/Kconfig"
    
    

     

    这样,执行make menuconfig 时,就可以配置hello 模块的编译选项了。.

    (PS:在我的操作中发现,arch/arm/Kconfig里面不需要修改,因为其中有个菜单选项关于Device的已经指向了drivers/Kconfig这里,所以只需要修改这里就OK)

    七. 修改drivers/Makefile 文件,添加一行:

    obj-$(CONFIG_HELLO) += hello/
    
    

     

    八. 配置编译选项:

    root@brantyou-ubuntu:~/workspace/samsung_android_kernel_3.0# make menuconfig

     

    找到"Device Drivers" => "First Android Drivers"选项,设置为y

    注意,如果内核不支持动态加载模块,这里不能选择m,虽然我们在Kconfig 文件中配置了HELLO 选项为tristate

    要支持动态加载模块选项,必须要在配置菜单中选择Enable loadable module support 选项;在支持动态卸载模块选项,必须

    要在Enable loadable module support 菜单项中,选择Module unloading 选项。

     

    九. 编译:

    root@brantyou-ubuntu:~/workspace/samsung_android_kernel_3.0# make


    编译成功后,就可以在hello 目录下看到hello.o 文件了,这时候编译出来的zImage 已经包含了hello 驱动。

     

    十. 运行新编译的内核文件,验证hello 驱动程序是否已经正常安装:

    PS: 我这里是重新烧写zImage到板子上测试的,下面两句是直接在模拟器上测试的。

    linuxidc@www.linuxdc.com:~/Android$ emulator -kernel ./kernel/common/arch/arm/boot/zImage &

    linuxidc@www.linuxdc.com:~/Android$ adb shell

    进入到dev 目录,可以看到hello 设备文件:

    root@Android:/ # cd dev

    root@Android:/dev # ls

    进入到proc 目录,可以看到hello 文件:

    root@Android:/ # cd proc

    root@Android:/proc # ls

    访问hello 文件的值:

    root@Android:/proc # cat hello

    0

    root@Android:/proc # echo '5' > hello

    root@Android:/proc # cat hello

    5

    进入到sys/class 目录,可以看到hello 目录:

    root@Android:/ # cd sys/class

    root@Android:/sys/class # ls

    进入到hello 目录,可以看到hello 目录:

    root@Android:/sys/class # cd hello

    root@Android:/sys/class/hello # ls

    进入到下一层hello 目录,可以看到val 文件:

    root@Android:/sys/class/hello # cd hello

    root@Android:/sys/class/hello/hello # ls

    访问属性文件val 的值:

    root@Android:/sys/class/hello/hello # cat val

    5

    root@Android:/sys/class/hello/hello # echo '0' > val

    root@Android:/sys/class/hello/hello # cat val

    0

    至此,我们的hello 内核驱动程序就完成了,并且验证一切正常。这里我们采用的是系统提供的方法和驱动程序进行

    交互,也就是通过proc 文件系统和devfs 文件系统的方法,下一篇文章中,我们将通过自己编译的C 语言程序来访问/dev/hello

    文件来和hello 驱动程序交互,敬请期待。

     

    如过程中碰到问题,可参考我的其他blog。

     

    展开全文
  • RK3288 android驱动入门

    千人学习 2019-08-26 10:20:58
    本次课程包含 前面 RK3399 的内容,使用 RK3288 和 RK3399 多块开发板,带领大家把开发板上面的硬件模块功能都实现了,两个课程,大家看需求选其一即可,个人认为,RK平台功能快速实现有这些课程即可!
  • 于此,将框架(Framework)和设计模式(Design Pattern)应用于Linux驱动开发,...其直接的益处就是:让我们能基于一致的设计理念来结合Android HAL与Linux两层的驱动开发,规划出整体和谐Android-based软硬整合产品架构。
  • QQ:971586331 软件环境: 操作系统:windows 10 IDE版本:Android Studio 3.4.2 JAVA版本:jdk-8u221-windows-x64 NDK版本:android-ndk-...开发板android版本:android 4.0.3 硬件环境: 开发板:itop-44...

    QQ:971586331

    软件环境:

    操作系统:windows 10

    IDE版本:Android Studio 3.4.2

    JAVA版本:jdk-8u221-windows-x64

    NDK版本:android-ndk-r20-windows-x86_64

    Kernel版本:linux 3.0

    开发板android版本:android 4.0.3

    硬件环境:

    开发板:itop-4412 精英版

    本文内容:本文描述了如何使用android应用程序调用linux驱动控制LED灯的亮灭。要实现android应用程序控制LED,需要三个程序,LED的linux驱动,JNI库和android应用程序。android应用程序通过JNI库调用LED驱动程序,从而实现android应用程序控制LED。

    1.开发板环境搭建

    开发环境搭建请参考《iTOP-4412开发板之精英版使用手册_V3.1.pdf》,本文使用的配置是

    uboot:iTop4412_uboot_20180320.tar

    kernel:iTop4412_Kernel_3.0_20180604.tar

    android:iTop4412_ICS_git_20151120.tar

    编译完成后将ramdisk-uboot.img,system.img,zImage,u-boot-iTOP-4412.bin文件通过OTG或SD烧写到开发板的EMMC中,如果在uboot下使用OTG,发现windows 10装不上光盘中的android_drv_90000_64.exe驱动,可以谷歌搜索安装android_11000010001_x64_718.exe。

    2.LED的驱动程序

    LED驱动在kernel的drivers/char/itop4412-leds.c中,从itop4412-leds.c中我们可以得知LED驱动的设备文件名叫“leds”。驱动程序实现了ioctl函数。

    long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
    {
    	printk("debug: leds_ioctl cmd is %d\n" , cmd);
    
    	switch(cmd)
    	{
    		case 0:
    		case 1:
    			if (arg > LED_NUM) {
    				return -EINVAL;
    			}
    
    			gpio_set_value(led_gpios[arg], cmd);
    			break;
    
    		default:
    			return -EINVAL;
    	}
    
    	return 0;
    }

    leds_ioctl的cmd参数表示灯的亮灯,arg参数表示灯的编号,根据文件中的定义可以知,0表示GPL2_0,也就是LED2,1表示GPK1_1,也就是LED3。

    static int led_gpios[] = {
    	EXYNOS4_GPL2(0),
    	EXYNOS4_GPK1(1),
    };

    接下来我们查看drivers/char/Makefile文件,宏CONFIG_LEDS_CTL控制LED驱动是否编译

    obj-$(CONFIG_LEDS_CTL)		+= itop4412_leds.o

    再查看drivers/char/Kconfig文件,默认就是y

    config LEDS_CTL
            bool "Enable LEDS config"
            default y
            help
              Enable LEDS config

    再查看.config,已经将LED驱动编入了内核

    CONFIG_LEDS_CTL=y

    看来板子的驱动已经做好了,完全不用我们动手,接下我们看怎么编写JNI接口调用linux驱动

    3.JNI和NDK

    因为android是使用java语言进行开发的,但linux驱动是用C语言进行开发的,所以面临java如果调用C语言接口的问题,JNI提供的API就是解决java和其他语言通信的问题。NDK 是一套工具集合,允许你使用C语言来实现应用程序的部分功能。我们写好JNI接口后使用NDK打包成库文件,就可以提供给android应用程序调用了。接下来我们新建工程编写JNI。

    新建一个空activity

    填写工程名,选择工程路径,开发语言选择java,API选择15

    创建工程后得待编译完成,然后在包名下创建一个名叫jni_led的类

    文件内容如下:

    package com.example.led_test;
    
    public class jni_led {
    
        public native static String Leds_Operation(int ledNum, boolean status); //操作接口
    }

    打开 Android Studio 的 Terminal,使用javac命令将java文件编译成.class文件

    F:\OneDrive\Linux\android_project\led_test>javac .\app\src\main\java\com\example\led_test\jni_led.java

    使用javah命令创建头文件。-encoding UTF-8表示指定编码格式,防止出现“错误: 编码GBK的不可映射字符”,-d jni表示在当前目录下创建jni目录,将生成的文件放在jni目录中,-classpath表示指定类文件的路径。这里有一个地方要注意,类文件在写的时候是包名+类名,所有路径只用写到java目录,后面的com,example和led_test虽然都是文件夹,但这里表示包名(第一次写在这里纠结了好久,我想我路径明明写对了啊,为什么找不到\app\src\main\java\com\example\led_test文件夹下的类)

    F:\OneDrive\Linux\android_project\led_test>javah -encoding UTF-8 -d jni -classpath ./app/src/main/java com.example.led_test.jni_led
    

    指令执行完成后可以发现在jni目录下生成了包名加类名的头文件

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_led_test_jni_led */
    
    #ifndef _Included_com_example_led_test_jni_led
    #define _Included_com_example_led_test_jni_led
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_led_test_jni_led
     * Method:    Leds_Operation
     * Signature: (IZ)Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_example_led_1test_jni_1led_Leds_1Operation
      (JNIEnv *, jclass, jint, jboolean);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    可以发现,头文件中根据jni_led.java中定义的java类接口生成了JNI接口函数,我们要实现这个接口函数。

    然后在JNI下创建com_example_led_test_jni_led.c文件

    在com_example_led_test_jni_led.c中,我们将头文件中的接口函数据复制过来,然后使用linux API操作linux设备文件

    //
    // Created by shiyu on 2019/8/17.
    //
    
    #include<jni.h>
    #include<stdio.h>
    #include <fcntl.h>
    #include <linux/ioctl.h>
    //导入我们创建的头文件
    #include "com_example_led_test_jni_led.h"
    
    #define DEVICE_NAME		"/dev/leds"
    
    JNIEXPORT jstring JNICALL Java_com_example_led_JNITest_Leds_1Operation
      (JNIEnv *env, jclass obj, jint ledsNum, jboolean status){
    
    int leds_fd = 0;
    
    	leds_fd = open(DEVICE_NAME, O_RDWR);  //打开设备节点
    	if (leds_fd == -1) {
    		return 1;
    	}
    
    	switch (ledsNum) {
    	case 0:
    		if (status)
    			ioctl(leds_fd, 0, 0);
    		else
    			ioctl(leds_fd, 1, 0);
    		break;
    	case 1:
    		if (status)
    			ioctl(leds_fd, 0, 1);
    		else
    			ioctl(leds_fd, 1, 1);
    		break;
    	defautl :
    		break;
    	}
    
    	close(leds_fd);
    
    	return 0;  //操作成功返回0
    }

    在jni下创建一个Android.mk文件

    
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := jni_led
    LOCAL_SRC_FILES := com_example_led_test_jni_led.c
    include $(BUILD_SHARED_LIBRARY)

    这时指定了生成库的名字和源文件,再新建一个Application.mk文件

    APP_ABI := all

    安装NDK工具集后,进入jni目录使用ndk-build命令将JNI接口程序编译成库文件

    在libs目录下生成了各种平台的库文件

    为了让项目能够找到我们的生成的库,在 build.gradle 文件夹的 android 下添加:

    sourceSets {
            main() {
                jniLibs.srcDirs = ['../libs']
                jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
            }
        }

    然后在jni_led.java中加载生成的库文件

    package com.example.led_test;
    
    public class jni_led {
        static {
            System.loadLibrary("jni_led");  //加载生成的.so文件
        }
        public native static String Leds_Operation(int ledNum, boolean status); //操作接口
    }

    接下来我们编写android应用程序利用Leds_Operation接口控制LED灯

    4.编写android应用程序

    打开工程目录下的activity_main.xml文件,添加4个button,并指写button的onClick回调函数

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TableLayout
            android:id="@+id/TableLayout2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:collapseColumns="4" >
    
            <TableRow>
    
                <Button
                    android:id="@+id/button_led3off"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led3_off_click"
                    android:text="led3_off"
                    tools:layout_editor_absoluteX="228dp"
                    tools:layout_editor_absoluteY="186dp" />
    
                <Button
                    android:id="@+id/button_led3on"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led3_on_click"
                    android:text="led3_on"
                    tools:layout_editor_absoluteX="98dp"
                    tools:layout_editor_absoluteY="186dp" />
    
                <Button
                    android:id="@+id/button_led2off"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led2_on_click"
                    android:text="led2_off"
                    tools:layout_editor_absoluteX="228dp"
                    tools:layout_editor_absoluteY="100dp" />
    
                <Button
                    android:id="@+id/button_led2on"
                    android:layout_width="200dp"
                    android:layout_height="200dp"
                    android:onClick="led2_off_click"
                    android:text="led2_on"
                    tools:layout_editor_absoluteX="98dp"
                    tools:layout_editor_absoluteY="100dp" />
            </TableRow>
        </TableLayout>
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    我们为4个按键指定了4个回调函数据,接下来我们在MainActivity.java中实现这4个回调函数

    package com.example.led_test;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void led2_on_click( View view )
        {
            jni_led.Leds_Operation(0, false);
        }
    
        public void led2_off_click( View view )
        {
            jni_led.Leds_Operation(0, true);
        }
    
        public void led3_on_click( View view )
        {
            jni_led.Leds_Operation(1, false);
        }
    
        public void led3_off_click( View view )
        {
            jni_led.Leds_Operation(1, true);
        }
    }
    

    如上,我们实现了这4个回调函数,调用jni_led库中的Leds_Operation函数,Leds_Operation会调用Java_com_example_led_JNITest_Leds_1Operation函数,这样就实现了android应用程序调用linux驱动接口。

    连接开发板,编译运行。

     

     

    展开全文
  • sky我所做的事情都是源于自己对梦想的追求--分享技术、共同创造新世界---欢迎交流:zhangbinghua2012@163.com博客园首页新随笔联系订阅管理Android 开发之 ---- 底层驱动开发(一) 【转】转自:...驱动概述 ...

    sky

    我所做的事情都是源于自己对梦想的追求--分享技术、共同创造新世界---欢迎交流:zhangbinghua2012@163.com

    Android 开发之 ---- 底层驱动开发(一) 【转】

    转自:http://blog.csdn.net/jmq_0000/article/details/7372783

    驱动概述

            说到 Android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正,还增加了不少内容。android 驱动 主要分两种类型:Android 专用驱动 和 Android 使用的设备驱动(linux)。

          Android 专有驱动程序:

          1)Android Ashmem 匿名共享内存; 为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。

          2)Android Logger    轻量级的LOG(日志) 驱动;

          3)Android Binder     基于 OpenBinder 框架的一个驱动;

          4)Android Power Management  电源管理模块;

          5)Low Memory Killer  低内存管理器;

          6)Android PMEM        物理内存驱动;

          7)USB Gadget             USB 驱动(基于 gaeget 框架);

          8)Ram Console           用于调试写入日志信息的设备;

          9)Time Device             定时控制设备;  

         10)Android Alarm         硬件时钟;


         Android 上的设备驱动:

          1)Framebuff 显示驱动;

          2)Event 输入设备驱动;

          3)ALSA 音频驱动;

          4)OSS 音频驱动;

          5)v412摄像头:视频驱动;

          6)MTD 驱动;

          7)蓝牙驱动;

          8)WLAN 设备驱动;


     Android 专有驱动程序

          1.Android Ashmem 

                   为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。

                   设备节点:/dev/ashmen .主设备号 10.

                   源码位置: include/linux/ashmen.h    Kernel /mm/ashmen.c

                         相比于 malloc 和 anonymous/named mmap 等传统的内存分配机制,其优势是通过内核驱动提供了辅助内核的内存回收算法机制(pin/unoin)

          2.Android Logger  

                        无论是底层的源代码还上层的应用,我们都可以使用 logger 这个日志设备看、来进行调试。

                         设备节点:  /dev/log/main      /dev/log/event   /dev/log/radio

                         源码位置:include/linux/logger.h         include/linux/logger.c

          3.Android Binder     

                    IPC Binder 一种进程间通信机制。他的进程能够为其它进程提供服务 ----- 通过标准的 Linux 系统调用 API。

                    设备节点 :/dev/binder

                    源码位置:Kernel/include/linux/binder.h    Kernel/drivers/misc/binder.c

          4.Android Power Management  

                   一个基于标准 linux 电源管理的轻量级 Android 电源管理系统,在 drivers/android/power.c      kernel/power/

          5.Low Memory Killer 

                    它在用户空间中指定了一组内存临界值,当其中某个值与进程描述中的 oom_adj 值在同一范围时,该进程将被Kill掉(在parameters/adj中指定oome_adj 的最小值)。它与标准的Linux OOM机制类似,只是实现方法不同

                    源码位置:drivers/misc/lowmemorykiller.c       

          6.Android PMEM       

                    PMEM 主要作用就是向用户空间提供连续的物理内存区域。

                          1.让 GPU 或 VPU 缓冲区共享 CPU 核心。

                          2.用于 Android service 堆。

                   源码位置:include/linux/android_pmem.h drivers/android/pmem.c                        

          7.USB Gadget            

                    基于标准 Linux USB gaeget 驱动框架的设备驱动。

                    源码位置:drivers/usb/gadet/ 

          8.Ram Console         

                    为了提供调试功能,android 允许将调试日志信息写入这个设备,它是基于 RAM 的 buffer.

                    源码位置: drivers/staging/android/ram_console.c

          9.Time Device            

                   定时控制,提供了对设备进行定时控制的功能。

                   源码位置:drivers/staging/android/timed_output.c(timed_gpio.c)

        10.Android Alarm       

                    提供一个定时器,用于把设备从睡眠状态唤醒,同时它还提供了一个即使在设备睡眠时也会运行的时钟基准。

                     设备节点:/dev/alarm

                     源码位置:drivers/trc/alarm.c


    Android 设备驱动

        1. Framebuffer 帧缓存设备

             Framebuffer 驱动在 Linux 中是标准的显示设备的驱动。对于 PC 系统,它是显卡的驱动 ; 对于嵌入式 SOC 处理器系统,它是 LCD 控制器或者其他显示控制器的驱动。它是一个字符设备,在文件系统中设备节点通常是 /dev/fbx 。 每个系统可以有多个显示设备 , 依次用 /dev/fbO 、 /dev/fb l
    等来表示。在 Android 系统中主设备号为 29 ,次设备号递增生成。

             Android 对 Framebuffer 驱动的使用方式是标准的 , 在 / dev / graphie / 中的 Framebuffer 设备节点由 init 进程自动创建 , 被 libui 库调用 。 Android 的 GUI 系统中 , 通过调用 Framebuffer 驱动的标准接口,实现显示设备的抽象。

             

         Framebuff的结构框架和实现 : 

              linux LCD驱动(二)--FrameBuffer  

                  Linux LCD驱动(四)--驱动的实现                                    

     

        2.Event输入设备驱动

             Input 驱动程序是 Linux 输入设备的驱动程序 , 分为游戏杆 (joystick) 、 鼠标 (mouse 和 mice)和事件设备 (Event queue)3 种驱动程序。其中事件驱动程序是目前通用的程序,可支持键盘 、 鼠标、触摸屏等多种输入设备。 Input 驱动程序的主设备号是 l3 ,每一种 Input 设备从设备号占 用5 位 , 3 种从设备号分配是 : 游戏杆 0 ~ 61 ; Mouse 鼠标 33 ~ 62 ; Mice 鼠标 63 ; 事件设备 64 ~ 95 ,各个具体的设备在 misc 、 touchscreen 、 keyboard 等目录中。
            Event 设备在用户空问使用 read 、 ioctl 、 poll 等文件系统的接口操作, read 用于读取输入信息, ioctl 用于获取和设置信息, poll 用于用户空间的阻塞,当内核有按键等中断时,通过在中断中唤醒内核的 poll 实现。 

            Event 输入驱动的架构和实现:

                              Linux设备驱动之——input子系统

     

         3.ALSA音频驱动

             高级 Linux 声音体系 ALSA(Advanced Linux Sound Architecture ) 是为音频系统提供驱动 的Linux 内核组件,以替代原先的开发声音系统 OSS 。它是一个完全开放源代码的音频驱动程序集 ,除了像 OSS 那样提供一组内核驱动程序模块之外 , ALSA 还专门为简化应用程序的编写提供相应的函数库,与 OSS 提供的基于 ioctl 等原始编程接口相比, ALSA 函数库使用起来要更加方便一些 

            利用该函数库,开发人员可以方便、快捷地开发出自己的应用程序,细节则留给函数库进行内部处理 。 所以虽然 ALSA 也提供了类似于 OSS 的系统接口 , 但建议应用程序开发者使用音频函数库,而不是直接调用驱动函数。

                         ALSA 驱动的主设备号为 116 ,次设备号由各个设备单独定义,主要的设备节点如下:
                                 / dev / snd / contmlCX —— 主控制 ;
                                 / dev / snd / pcmXXXc —— PCM 数据通道 ;
                                 / dev / snd / seq —— 顺序器;
                                 / dev / snd / timer —— 定义器。
            在用户空问中 , ALSA 驱动通常配合 ALsA 库使用 , 库通过 ioctl 等接口调用 ALSA 驱动程序的设备节点。对于 AIJSA 驱动的调用,调用的是用户空间的 ALsA 库的接口,而不是直接调用  ALSA 驱动程序。 ALSA 音频驱动的架构如下图所示:

                                         

            ALSA 驱动程序的主要头文件是 include / sound ./ sound . h ,驱动核心数据结构和具体驱动的注册函数是 include / sound / core . h ,驱动程序 的核心实现是 Sound / core / sound . c 文件。                     

           ALSA 驱动程序使用下面的函数注册控制和设备:

                    int snd _ pcm _ new (struct snd _ card * card , char * id , int device , int playback _ count , int capture _ count , struct snd _ pcm ** rpcm) ;

                     int snd ctl _ add(struct snd _ card * card , struct snd _ kcontrol * kcontro1) ;

             ALSA 音频驱动在内核进行 menuconfig 配置时 , 配置选项为 “ Device Drivers ” > “ Sound c ard support ” 一 > “ Advanced Linux Sound Architecture ” 。子选项包含了 Generic sound devices( 通用声音设备 ) 、 ARM 体系结构支持,以及兼容 OSS 的几个选项。 ALsA 音频驱动配置对应的文件是sound / core / Kconfig 。

          Android 没有直接使用 ALSA 驱动,可以基于 A-LSA 驱动和 ALSA 库实现 Android Audio 的硬件抽象层; ALSA 库调用内核的 ALSA 驱动, Audio 的硬件抽象层调用 ALSA 库。      


          4.OSS音频驱动

             OSS(Open Sound System开放声音系统)是 linux 上最早出现的声卡驱动。OSS 由一套完整的内核驱动程序模块组成,可以为绝大多数声卡提供统一的编程接口。

             OSS 是字符设备,主设备号14,主要包括下面几种设备文件:

              1) /dev/sndstat

                     它是声卡驱动程序提供的简单接口,它通常是一个只读文件,作用也只限于汇报声卡的当前状态。(用于检测声卡)

              2)/dev/dsp

                     用于数字采样和数字录音的设备文件。对于音频编程很重要。实现模拟信号和数字信号的转换。

              3)/dev/audio

                     类似于/dev/dsp,使用的是 mu-law 编码方式。

              4)/dev/mixer

                     用于多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。

              5)/dev/sequencer

                       这个设备用来对声卡内建的波表合成器进行操作,或者对 MIDI 总线上的乐器进行控制。

               OSS 驱动所涉及的文件主要包括:

                    kernel/include/linux/soundcard.h

                    kernel/include/linux/sound.h   定义 OSS 驱动的次设备号和注册函数

                    kernel/sound_core.c    OSS核心实现部分

               OSS驱动架构图:

           

         5.V4l2视频驱动

       V4L2是V4L的升级版本,为linux下视频设备程序提供了一套接口规范。包括一套数据结构和底层V4L2驱动接口。V4L2提供了很多访问接口,你可以根据具体需要选择操作方法。需要注意的是,很少有驱动完全实现了所有的接口功能。所以在使用时需要参考驱动源码,或仔细阅读驱动提供者的使用说明。

          V4L2的主设备号是81,次设备号:0~255,这些次设备号里也有好几种设备(视频设备、Radio设备、Teletext、VBI)。

            V4L2的设备节点: /dev/videoX, /dev/vbiX and /dev/radioX

          V4L2框架图:

            

    【作者】张昺华
    【新浪微博】 张昺华--sky
    【twitter】 @sky2030_
    【facebook】 张昺华 zhangbinghua
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
    posted @ 2016-11-18 15:17 张昺华-sky 阅读(3711) 评论(0) 编辑 收藏
    张昺华-sky的头像
    昵称:张昺华-sky
    园龄:3年5个月
    粉丝:107
    关注:10
    <2018年5月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789
     
    Copyright ©2018 张昺华-sky




    展开全文
  • android驱动框架介绍

    千次阅读 2019-06-28 14:05:11
    android驱动框架介绍 了解android驱动框架: 1.方法1——jni调用底层驱动 在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序: 优点:简单易行; 缺点:主要在于驱动程序,由于...
  • Android驱动开发全过程

    千次阅读 2019-07-01 21:35:10
    Android驱动开发全过程(有图有真相) 前言 意外在网上发现了这扁文章,看后感觉很有必要分享,所以整理并上传,希望大家喜欢。 Android硬件抽象层(HAL)概要介绍和学习计划 Android 的硬件抽象层,简单来说,...
  • android 设备驱动

    2019-06-25 16:59:39
    说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正,还增加了...
  • 电脑无法安装Android设备驱动

    万次阅读 2017-12-16 18:51:36
    但是最近将电脑系统重做成了win7 32位,导致接上设备后总是提示Windows找不到驱动程式,使用驱动精灵扫描后根据推荐的驱动安装也不行,安装到最后总是提示安装失败,后来发现在AndroidSDK中带了一个android_winusb.inf
  • Android底层技术:HAL驱动开发

    万人学习 2019-06-26 11:58:07
    本课程提供开发者学习Android底层的HAL(硬件抽象层)的开发方法和技术。HAL所在的位置是介于Android系统服务与Linux内核之间,HAL Driver是以library形式出现,给HAL Stub调用,供Android System架构者调用。而HAL ...
  • Android ADB USB 驱动 万能配置方式

    万次阅读 2019-12-11 13:47:04
    Android ADB USB 驱动 万能配置方式latest_usb_driver_windows.zip 下载:新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建...
  • 如何学习Android驱动开发

    千次阅读 2017-04-05 14:53:20
    如何成为一名优秀的Android驱动程序员?参数如下要求: 一、Android驱动的基础知识 1.Android驱动是基于Linux驱动,强烈推荐阅读Linux Device Driver 3rd版,这本书讲了Linux下设备驱动的基础知识,要求反复细读。 2...
  • android adb interface驱动安装

    千次阅读 2017-06-12 10:56:48
    起安卓工控机需要adb连接才能下载调试程序。 起先使用adb connect通过网络来链接的。...方式就是下载adb interface驱动后,指定驱动位置更新就可以了。 至于windows平台怎么更新驱动的就不多赘述了。 更
  • Android调试adb devices找不到设备

    万次阅读 2017-05-25 14:43:53
    adb驱动已经安装成功,但是adb devices却无法找到设备,USB大容量存储也是正常; 以前如果出现此种情况,我能想到的原因如下: 1.杀毒软件问题(关闭MacAfee) 2.驱动安装有误,重新安装驱动,手动选择驱动路径,...
  • 本文以使用USB转串口芯片PL2303为例,经测试Android设备与外设通信ok。 1、USB转串口驱动 drivers/usb/serial/pl2303.c drivers/usb/serial/pl2303.h 驱动加载成功则当插入外设时会生成/dev/ttyUSB*设备节点,若...
  • 浅谈Android与Linux系统的差异

    万次阅读 2019-11-18 22:32:19
    Android和Linux作为现行主流的操作系统,无论在消费类产品还是在工控领域,都有广泛的应用。都说Android系统是脱胎于Linux系统,那么是不是Android是不是属于Linux的一种。现在就来谈谈Android和Linux系统的异同点。
  • android 手机usb 驱动安装

    千次阅读 2018-09-21 15:03:41
    连上手机 1.查看你的设备(有!号的)的ID号:  1)右键单击[我的电脑] -&gt; 属性 -&gt; 设备管理器  2)右键单击[有问号的设备] -&gt; 属性 -&gt; 详细信息 -&...google sdk\...
  • Android 开发之 ---- 底层驱动开发(一)

    万次阅读 多人点赞 2012-05-07 10:48:48
    驱动概述  说到 android 驱动是离不开 Linux 驱动的。Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码)。...android 驱动 主要分两种类型:Android 专用驱动Android 使用
1 2 3 4 5 ... 20
收藏数 111,043
精华内容 44,417
关键字:

android驱动