linux驱动基础知识讲解

上传人:小** 文档编号:39332727 上传时间:2018-05-14 格式:PPTX 页数:72 大小:1.07MB
返回 下载 相关 举报
linux驱动基础知识讲解_第1页
第1页 / 共72页
linux驱动基础知识讲解_第2页
第2页 / 共72页
linux驱动基础知识讲解_第3页
第3页 / 共72页
linux驱动基础知识讲解_第4页
第4页 / 共72页
linux驱动基础知识讲解_第5页
第5页 / 共72页
点击查看更多>>
资源描述

《linux驱动基础知识讲解》由会员分享,可在线阅读,更多相关《linux驱动基础知识讲解(72页珍藏版)》请在金锄头文库上搜索。

1、Linux 驱动驱动 学习总结汇报习总结汇报2016年11月12日内核模块Bootloder并发控制中断处理设备驱动的结构Linux内核重要子系统统系统调用接口进程管理内存管理虚拟文件系统网络堆栈设备驱动最简单简单 的嵌入式系统统MTK的Bootloader在嵌入式操作系统中,BootLoader是在操作系统内 核运行之前运行。可以初始化硬件设备、建立内存空间 映射图,从而将系统的软硬件环境带到一个合适状态, 以便为最终调用操作系统内核准备好正确的环境。 MTK的bootloader有两部分组成:(1) 第1部分bootloader,也就是MTK内部(in-house)的pre- loader

2、,这部分依赖平台。(2) 第2部分bootloader,也就是 Little Kernel ,这部分依赖 操作系统,负责引导linux操作系统和Android框架。源码位置: vendormediatekproprietarybootablebootloaderMTK的Bootloader正常启动的主要工作如下:(1) 设备上电后,Boot ROM开始运行。(2) BootROM初始化软件堆栈(software stack)、通信端口和可引导存储 设备(比如NAND/EMMC)。(3) BootROM从存储器中加载pre-loader到内部SRAM(ISRAM)中,因 为这时候还没有初始化外部

3、的DRAM。(4) BootROM跳转到pre-loader的入口处并执行。(5) Pre-loader初始化DRAM和加载LK到RAM中。(6) Pre-loader跳转到LK中并执行,然后LK做一些初始化,比如显示的 初始化等。(7) LK从存储器中加载引导镜像(boot image),包括linux内核和 ramdisk(Android呢?)(8) LK跳转到linux内核并执行。MTK的Bootloaderpre-loaders中涉及的硬件部分(1) PLL模块 1) PLL模块用于调整处理器和外部内存的频率。 2) 在PLL模块初始化后,处理器和外部内存的频率可由 26MHZ/26M

4、HZ增加到1GHZ/192MHZ。(2) UART模块 1) UART模块用于调试或是META(Mobile Engineering Testing Architecture)模式下的握手。 2) 默认情况下,UART4初始化波特率为9216000bps和用于调试 信息的输出,UART1初始化为115200bps和作为UART META端 口。但也可以使用UART1作为调试或是UART META端口。 (3) 计时器(timer)模块 这是个基本的模块,用来计算硬件模块所需要的延时或是超时时 间。(4) 内存模块 1) Pre-loader由boot ROM加载和在芯片组内部的SRAM中执行,

5、因 为外部的DRAM还没有初始化。 2) 为了准备软件整个可执行环境,pre-loader采用内置的内存设置来 初始化DRAM(DRAM is initialized upon pre-loader built-inmemory settigns)。这样,LK就能够被加载到DRAM中并执行。(5) GPIO模块 (6) PMIC模块 为了提供一些基本的硬件功能,比如控制外设电源,pre-loader初始化 上层模块(upper modules)。(7) RTC模块 1) 当通过power按键开机后,pre-loader拉高RTC的PWBB来保持设 备一直有电(keep the device a

6、live)和继续引导LK。 2) RTC闹钟(alarm)有可能是设备开机的启动源,对于这种情况,设 备部需要按power按键就可自动启动。(8) USB模块 当USB线插入时,它初始化来和外部工具通信,比如用于升级系 统的下载工具或是META模式触发器的META工具。(9) NAND模块 (10) MSDC模块 Pre-loader可以从NAND flash或是EMMC中加载LK,这两者只 能选择其中一种来启动。LK中涉及的硬件部分LK是第2个loader,它由pre-loader引导并执行。从根本上来说 (basically),pre-loader已经初始化了相关的硬件模块,而不需要 在L

7、K中重新配置这些模块了。但一些模块在LK中被重新复位来 配置硬件寄存器,这样可创造一个干净的环境。比如计时器模块 ,在LK中,计时器重新复位清零硬件计数来对计时进行复位。所 有在LK中需要初始化的列在下面:(1) 计时器模块 通过复位硬件寄存器来复位计时。(2) 串口模块 LK采用串口模块来配置它的输入/输出系统,在这个模块初始化 后,我们可以使用LK提供的“printf()”等函数来使用串口功 能。(3) I2C模块 (4) PWM模块 (5) PMIC模块 (6) RTC模块 和计时器模块一样,在U-Boot中,I2C/PMIC/RTC重新复位寄存器来 复位这些模块。(7) LED模块 通

8、过这power off charging个模块,设备能够通知用户当前的充电状 态。(8) 充电模块 这个模块负责关机充电(power off charging)、低电压充电(lower charging in the system)。(9) LCD模块 使用这个模块,设备能够显示logo或是任何通知的消息。(10) NAND模块 因为U-Boot也需要从flash读取镜像(比如内核或是ramdisk), 所以有必要在U-Boot中初始化NAND相关的功能。(11) MSDC模块 支持MSDC启动一些重要的数据结结构大部分驱动程序涉及三个重要的内核数据结构: 文件操作file_operation

9、s结构体 文件对象file结构体 索引节点inode结构体Linux设备驱动设备驱动Linux下设备的属性 设备的类型:字符设备、块设备、网络设备 主设备号:标识设备对应的驱动程序。一般“一个主设 备号对应一个驱动程序” 次设备号:每个驱动程序负责管理它所驱动的几个硬件 实例,这些硬件实例则由次设备号来表示。同一驱动下 的实例编号,用于确定设备文件所指的设备。 可通过ls l “设备文件名”命令查看设备的主次设备 号,以及设备的类型。18分配和释释放字符设备设备 号编写驱动程序要做的第一件事,为字符设备获取一个设备号 。事先知道所需要的设备编号(主设备号)的情况: int register_c

10、hrdev_region(dev_t first, unsigned count, const char *name) first是要分配的起始设备编号值。 first的次设备号 通常设置为0。 Count 所请求的连续设备编号的个数。 Name设备名称,指和该编号范围建立关系的设备。 分配成功返回0。19分配和释释放字符设备设备 号动态分配设备编号(主要是主设备号) int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name) dev 是一个仅用于输出的参数, 它在函数成功完成

11、时保 存已分配范围的第一个编号。 baseminor 应当是请求的第一个要用的次设备号,它常 常是 0. count 和 name 参数跟request_chrdev_region 的一样 .20分配和释释放字符设备设备 号不再使用时,释放这些设备编号。使用以下函数: void unregister_chrdev_region(dev_t from, unsigned count) 在模块的卸载函数中调用该函数。21字符设备设备 的注册内核内部使用struct cdev结构表示字符设备。编写设备驱动 的第二步就是注册该设备。 包含头文件。 获取一个独立的cdev结构: struct cdev

12、*my_cdev = cdev_alloc(); 调用cdev_init初始化cdev结构体 void cdev_init(struct cdev *cdev, struct file_operations *fops); 初始化该设备的所有者字段: dev-cdev.owner = THIS_MODULE; 初始化该设备的可用操作集: dev-cdev.ops = 22字符设备设备 的注册编写设备驱动的第二步就是注册该设备。 cdev 结构已建立和初始化, 最后通过cdev_add函数把 它告诉内核:int cdev_add(struct cdev *dev, dev_t num, unsi

13、gned int count); dev 是要添加的设备的 cdev 结构, num 是这个设备对应的第一个设备编号, count 是应当关联到设备的设备号的数目. 卸载字符设备时,调用相反的动作函数: void cdev_del(struct cdev *dev);23Linux设备驱动的并发控制24设备驱动设备驱动 的并发发控制 在驱动程序中,当多个线程同时访问相同的资源时,可能会引发“竞态”,必须对共享资源进行并发控制。并发和竞态广泛存在。并发控制的目的:使得线程访问共享资源的操作是原子操作。原子操作:在执行过程中不会被别的代码路径所中断的操作。 驱动程序中的全局变量是一种典型的共享资源

14、。25考虑一个非常简单的共享资源的例子:一个全局整型变量和 一个简单的临界区,其中的操作仅仅是将整型变量的值 增加1:i+ 该操作可以转化成下面三条机器指令序列: 得到当前变量i的值并拷贝到一个寄存器中 将寄存器中的值加1 把i的新值写回到内存中 原子操作26Linux内核的并发发控制 在内核空间的内核任务需要考虑同步 内核空间中的共享数据对内核中的所有任务可见,所以 当在内核中访问数据时,就必须考虑是否会有其他内核 任务并发访问的可能、是否会产生竞争条件、是否需要 对数据同步。27确定保护对护对 象 找出哪些数据需要保护是关键所在 内核任务的局部数据仅仅被它本身访问,显然不需要保 护。 如果

15、数据只会被特定的进程访问,也不需加锁 大多数内核数据结构都需要加锁:若有其它内核任务可 以访问这些数据,那么就给这些数据加上某种形式的锁 ;若任何其它东西能看到它,那么就要锁住它。 Linux内核的并发控制28Linux内核的并发发控制并发控制的机制 中断屏蔽,原子数操作,自旋锁和信号量都是解决 并发问题的机制。 中断屏蔽很少被单独使用,原子操作只能针对整数 来进行。因此自旋锁和信号量应用最为广泛。 29锁机制可以避免竞争状态正如门锁和门一样,门后的房间可 想象成一个临界区。在一段时间内,房间里只能有一个内核任务存在,当一个任 务进入房间后,它会锁住身后的房门;当它结束对共享数据 的操作后,就

16、会走出房间,打开门锁。如果另一个任务在房 门上锁时来了,那么它就必须等待房间内的任务出来并打开门 锁后,才能进入房间。 加锁机制 30任何要访问临界资源的代码首先都需要占住相应的锁,这样该 锁就能阻止来自其它内核任务的并发访问: 任务务 1 试图锁 定队列 成功:获得锁 访问队 列 为队 列解除锁 任务务2 试图锁 定队列失败:等待 等待 等待 成功:获得锁 访问队 列 为队 列解除锁加锁机制 31原子数操作整型原子数操作 原子变量初始化 atomic_t test = ATOMIC_INIT(i); 设置原子变量的值 void atomic_set(atomic_t *v, int i) 获得原子变量的值 atomic_read(v) 原子变量加 void atomic_add(int i, atomic_t

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

最新文档


当前位置:首页 > 商业/管理/HR > 其它文档

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