(55)Linux驱动开发之一驱动概述

                                                                                                  驱动概述
驱动用在哪里?非标准类设备的编写和标准类设备的驱动移植。
驱动其实是随着linux内核相伴而生的。某段代码可以控制咱们的硬件去工做,去动,这段代码就称为咱们的驱动代码。
技术只是一种手段,一种技巧,咱们应该利用技术去搞出产品。
5.1.1_2.什么是驱动1_2
5.1.1.一、理解驱动的概念
(1)驱动一词的字面意思
(2)物理上的驱动
(3)硬件中的驱动
(4)linux内核驱动。软件层面的驱动广义上就是指:这一段代码操做了硬件去动,因此这一段代码就叫硬件的驱动程序。(本质上是电力提供了动力,而驱动程序提供了操做逻辑方法)
狭义上驱动程序就是专指操做系统中用来操控硬件的逻辑方法部分代码。
5.1.1.二、linux体系架构(下层用来实现上层,上层来调用下层)
(1)分层思想
(2)驱动的上面是系统调用API(驱动对上对系统调用API负责,API又对应用程序负责)
(3)驱动的下面是硬件(驱动对下管理硬件,本质上驱动是操控硬件寄存器的)
(4)驱动本身自己也是分层的()
 
 
5.1.3.模块化设计
5.1.3.一、微内核和宏内核(操做系统设计的两种思路)
(1)宏内核(又称为单内核):将内核从总体上做为一个大过程实现(能够理解为整个内核就是一个裸机程序,整个内核是一块儿来写的),并同时运行在一个单独的地址空间。全部的内核服务都在一个地址空间运行,【相互之间直接调用函数】,简单高效,架构设计比较简单。(耦合性比较高,可是有缺陷,一个不工做其余也不能工做了)
(2)微内核:功能被划分红独立的过程,过程间经过【IPC进程间通讯】进行通讯。模块化程度高(耦合性比较低),一个服务失效不会影响另一个服务。典型如windows
(3)linux:本质上是宏内核,可是又吸取了微内核的模块化特性,体如今2个层面
5.1.3.二、静态模块化:在编译时(源代码级别)实现可裁剪,特征是想要功能裁剪改变必须从新编译整个内核,比较复杂。获得一个新的zImage来代替旧的zImage,而后再去烧录才能起效果。【相似于安卓的卡刷】
这种方式来讲这个驱动模块就属于内核。
5.1.3.三、动态模块化:zImage能够不从新编译烧录,甚至能够不关机重启就实现模块的安装和卸载。【相似于安卓的线刷】这种方式其实严格来讲这个驱动模块不属于内核,它能够在须要的时候进行使用,在不须要的时候能够卸载。
 
 
5.1.4.linux设备驱动分类                   
5.1.4.一、驱动分类
(1)分3类:字符设备驱动、块设备驱动、网络设备驱动
(2)分类原则:设备自己读写操做的特征差别(硬件来决定软件怎么写,由于硬件进行了分类,因此操控硬件的软件程序(即驱动程序)也进行了分类)
就好像鞋子和脚的关系(鞋子的制做要适应脚的形状等特性)
5.1.4.二、三类驱动程序详细对比分析
(1)字符设备,准确的说应该叫“字节设备”,也就是这个设备的读写是:软件操做设备时是以【字节】为单位进行的。典型的如LCD、串口、LED、蜂鸣器、触摸屏······
(2)块设备,块设备是相对于字符设备定义的,块设备被软件操做时是以【块(多个字节构成的一个单位)】为单位的。设备的块大小是设备自己设计时定义好的,是硬件决定好的,软件是不能去更改的,不一样设备的块大小能够不同,但总的来讲块的大小是固定的。常见的块设备都是存储类设备,如:硬盘、NandFlash、iNand、SD····    (块设备不能按照字节方式去读)块设备主要就是为存储设备而生的。
 
块设备要把整个块读到内存中,而后在内存中定位到某个字节中进行读写。
(3)网络设备,网络设备是【专为网卡设计】的驱动模型,linux中网络设备驱动主要目的是为了支持API中socket相关的那些函数工做。【由于网络通讯有一套专用的接口和体系,因此单独放在一类中。】
5.1.4.三、为何字符设备驱动最重要
(1)常见大量设备都属于字符设备
(2)举例说明【非标准类型】字符设备驱动
标准类设备是指比较广泛的设备,而非标准类型设备是为某种专有功能,特定制做的设备。
 
5.1.5.驱动程序的安全性要求(写驱动就至关于在写内核)
5.1.5.一、驱动是内核的一部分
(1)驱动已经成为内核中最庞大的组成部分
(2)内核会直接以函数调用的方式调用驱动代码(驱动若是有问题,内核就死掉了)
(3)驱动的动态安装和卸载都会“更改”内核(有点像改装车)
5.1.5.二、驱动对内核的影响
(1)驱动程序崩溃甚至会致使内核崩溃(也作了一些防御措施)
(2)驱动的效率会影响内核的总体效率
(3)驱动的漏洞会形成内核安全漏洞
5.1.5.三、常见驱动安全性问题
(1)未初始化指针(野指针)
(2)恶意用户程序
(3)缓冲区溢出(定义一个buffer来接收应用层的数据,可是应用层发给的数据大于你定义的buf,若是在驱动中作出一些检验则能够避免这种错误)
(4)竞争状态(多个进程同时争夺某一个共同的资源现象)
 
【驱动接收应用层传进来的参数。】
 
5.1.6.驱动应该这么学
5.1.6.一、先学好C语言(最重要的前提就是C语言)
5.1.6.二、掌握相关预备知识
(1)硬件操做方面
(2)应用层API
5.1.6.三、驱动学习阶段
(1)注重实践,一步一步写驱动(本身去写)
(2)框架思惟(考虑这个代码的上层被谁调用和下层调用谁),多考虑总体(整个linux体系)和上下层
(3)先经过简单设备学linux【驱动框架】
(4)学会总结、记录,这会有助于理解
 
 
 
Linux操做系统包括(linux内核+linux应用程序),其中linux内核包括进程调度、内存管理、虚拟文件系统(字符设备驱动和块设备驱动)、网络接口(网络设备驱动)和进程通讯五个子系统,应用程序好比shell等。
 

 

 
                                                                                    (1)

 

                                                                                                                                      (2)
 
内核 驱动 硬件直接的关系:
linux驱动是直接和硬件打交道的软件程序。层次结构上它处于操做系统和硬件之间。
 驱动与linux操做系统内核的关系
1.驱动程序提供的一组设备驱动接口函数DeviceDriverInterface给操做系统。在linux中这一组设备驱动接口函数通常包括open,close,read,write,ioctl等。 这一组函数是经过一个叫作fileoperations的结构体注册给linux内核的。 ■Linux内核提供特定的系统功能函数进行驱动程序的注册。注册时提供设备驱动文件名称设备号对应的fileoperations结构体fileoperations结构体中存储有一组设备驱动接口函数指针。
2.驱动程序还须要提供2个模块接口函数给操做系统。 Linux设备驱动做为一个linux内核模块存在。模块都有2个接口函数---模块初始化函数和模块退出函数。上面提到的驱动程序的注册通常是由模块初始化函数来实现的。模块退出函数则用于取消内核注册释放资源。 可见只有运行了驱动的这个模块初始化函数以后驱动程序才可以被注册内核才能找到设备驱动。 那么何时模块初始化函数才得到运行呢 ·动态加载时即运行insmode时。 ·静态加载时模块编译进内核系统初始化时会自动调用这个模块初始化函数。
3.驱动与应用程序的关系 对于应用程序来讲驱动所对应的设备文件就表明着驱动。 应用程序经过linux系统提供的API调用使用驱动,咱们写应用程序就是在写特定驱动,就是在写内核。应用程序经过linux文件操做系统调用使用驱动。也就是说设备驱动对于用户来讲同操做一个文件没有区别。表明这个驱动的是驱动所对应的设备文件。
4.驱动与硬件的关系 硬件对于驱动程序来说能够抽象为一组寄存器和须要响应的中断源。 对于统一寻址的系统好比ARM这一组寄存器就是一段地址空间。 驱动就是按照芯片手册规定的原则读取或者写入这些地址空间。 中断源是硬件产生的中断中断是由内核响应的须要给这个中断注册一个中断处理函数。这能够经过调用linux内核提供特定的系统功能函数进行。 通常注册中断处理函数能够在模块初始化函数里实现或者在设备驱动接口程序open中实现。 
----------------------------------------------------------------------------------------------------------------------------------------------------------
LINUX驱动学习:
(1)驱动程序是硬件的灵魂,也是硬件和系统之间的桥梁。
(2)驱动程序的对象通常是存储器和外部设备。linux将这些设备分为3大类:【字符设备、块设备和网络设备】
字符设备是指可以一个字节一个字节读取数据的设备,字符设备通常须要在驱动层实现open(),close(),read(),write()和ioctl()函数。
(3)在linux内核中包含不少实现具体功能的模块,包括文件系统、网络协议栈、设备驱动、内核调度、内存管理和进程管理等。
(4)用户态和内核态:
Linux操做系统分为用户态和内核态,用户态处理上层的软件工做。内核态用来管理用户态的程序,完成用户态的请求的工做。驱动程序与底层的硬件交互,因此工做在内核态。
(5)模块机制是能够在运行时加入内核的代码,使得内核很容易的具备可裁剪性。
(6)静态装载和动态装载:
模块在内核启动时装载称为静态装载(烧录成镜像的形式),模块在内核已经运行起来时的装载称为动态装载。
(7)内核程序中包含的头文件是指内核代码树中的内核头文件,不是指开发应用程序时的外部头文件,eg:在内核中
实现的库函数中的打印函数printk()是C语言库函数printf()的内核版本。
(8)linux操做系统结构由4层组成:用户层、内核层、驱动层和硬件层。
(9)当内核启动后,第一件要作的事就是到存储设备(启动设备)中寻找根文件系统(包含了使系统运行的主要程序eg:shell和数据),其余普通的文件系统未来要挂载到根文件系统上来。
(10)内核启动后运行的第一个程序就是init,其将启动根文件系统中的shell程序,给用户提供一个友好的界面。
(11)根文件系统以树形结构来组织目录和文件的结构,系统启动后,根文件系统被挂接到根目录"/"上,这时候根目录下就包含了根文件系统的各个目录和文件。
(12)咱们常使用busybox工具来构建根文件系统,能够从http://www.busybox.net/downloads下载其相应的版本。
(13)构建驱动程序模块时,必须考虑驱动程序与内核的兼容性。即便模块代码相同,标准内核模块和特定厂商的内核模块其模块格式也是不一样的。
(14) 驱动模块 的组成:
一、头文件(必选)     #include<linux/module.h>     和#include<linux/init.h>是必须的
二、模块参数(可选)    驱动模块加载时,须要传递给驱动模块的参数
三、模块功能函数(可选)
四、其余(可选)
五、模块加载函数(必须)     模块的加载函数,有点相似于main()函数
六、模块卸载函数(必须)     执行后清除了加载函数里分配的资源
七、模块许可声明(必须)     表示模块受到内核支持的程度,使用MODULE_LICENSE()表示许可权限的程度。
(15)模块的操做:
1)insmod命令加载模块
2)rmmod命令卸载模块
3)lsmod查看模块加载信息
(16)linux下的驱动主要分为字符设备驱动、块设备驱动和网路设备接口驱动。咱们学习驱动就是学习这三类设备提供给咱们的接口。     
(17)  静态编译(从新下载编译linux内核)和动态编译。开发阶段以动态编译(不从新启动内核)为主。模块的方式动态加载。
(18)主设备号区分设备驱动程序。次设备号区分同一个驱动程序建立的多个设备。常见于多个串口和硬盘分区。次设备号一般依次对应同类型的多个设备。
(19)设备驱动的框架:
一、驱动程序的开始------设备的注册
二、注册的结构体
三、注册的fop指针(函数表)
(20)内核程序员得到内存的方式是kmalloc(分配出的地址空间都是物理上连续的),使用方法相似于用户空间的malloc版本。
kmalloc传递不一样标志,致使了该函数的不一样行为:
GFP_KERNEL
GFP_ATOMIC
GFP_USER
_GFP_DMA
 
2.4内核中register——char
2.6内核中调用cdev结构体的初始化,fop指针(函数表)要嵌入到这个cdev结构体中
相关文章
相关标签/搜索