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

驱动概述

驱动用在哪里?非标准类设备的编写和标准类设备的驱动移植。

驱动实际上是随着linux内核相伴而生的。某段代码能够控制我们的硬件去工作,去动,这段代码就称为我们的驱动代码。

技术只是一种手段,一种技巧,我们应该利用技术去搞出产品。

5.1.1_2.什么是驱动1_2

5.1.1.1、理解驱动的概念

(1)驱动一词的字面意思

(2)物理上的驱动

(3)硬件中的驱动

(4)linux内核驱动。软件层面的驱动广义上就是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序。(本质上是电力提供了动力,而驱动程序提供了操作逻辑方法)

狭义上驱动程序就是专指操作系统中用来操控硬件的逻辑方法部分代码。

5.1.1.2、linux体系架构(下层用来实现上层,上层来调用下层)

(1)分层思想

(2)驱动的上面是系统调用API(驱动对上对系统调用API负责,API又对应用程序负责)

(3)驱动的下面是硬件(驱动对下管理硬件,本质上驱动是操控硬件寄存器的)

(4)驱动自己本身也是分层的()

5.1.3.模块化设计

5.1.3.1、微内核和宏内核(操作系统设计的两种思路)

(1)宏内核(又称为单内核):将内核从整体上作为一个大过程实现(可以理解为整个内核就是一个裸机程序,整个内核是一起来写的),并同时运行在一个单独的地址空间。所有的内核服务都在一个地址空间运行,【相互之间直接调用函数】,简单高效,架构设计比较简单。(耦合性比较高,但是有缺陷,一个不工作其他也不能工作了)

(2)微内核:功能被划分成独立的过程,过程间通过【IPC进程间通信】进行通信。模块化程度高(耦合性比较低),一个服务失效不会影响另外一个服务。典型如windows

(3)linux:本质上是宏内核,但是又吸收了微内核的模块化特性,体现在2个层面

5.1.3.2、静态模块化:在编译时(源代码级别)实现可裁剪,特征是想要功能裁剪改变必须重新编译整个内核,比较复杂。得到一个新的zImage来代替旧的zImage,然后再去烧录才能起效果。【类似于安卓的卡刷】

这种方式来说这个驱动模块就属于内核。

5.1.3.3、动态模块化:zImage可以不重新编译烧录,甚至可以不关机重启就实现模块的安装和卸载。【类似于安卓的线刷】这种方式其实严格来说这个驱动模块不属于内核,它可以在需要的时候进行使用,在不需要的时候可以卸载。

5.1.4.linux设备驱动分类

5.1.4.1、驱动分类

(1)分3类:字符设备驱动、块设备驱动、网络设备驱动

(2)分类原则:设备本身读写操作的特征差异(硬件来决定软件怎么写,因为硬件进行了分类,所以操控硬件的软件程序(即驱动程序)也进行了分类)

就好像鞋子和脚的关系(鞋子的制作要适应脚的形状等特性)

5.1.4.2、三类驱动程序详细对比分析

(1)字符设备,准确的说应该叫“字节设备”,也就是这个设备的读写是:软件操作设备时是以【字节】为单位进行的。典型的如LCD、串口、LED、蜂鸣器、触摸屏······

(2)块设备,块设备是相对于字符设备定义的,块设备被软件操作时是以【块(多个字节构成的一个单位)】为单位的。设备的块大小是设备本身设计时定义好的,是硬件决定好的,软件是不能去更改的,不同设备的块大小可以不一样,但总的来说块的大小是固定的。常见的块设备都是存储类设备,如:硬盘、NandFlash、iNand、SD····    (块设备不能按照字节方式去读)块设备主要就是为存储设备而生的。

块设备要把整个块读到内存中,然后在内存中定位到某个字节中进行读写。

(3)网络设备,网络设备是【专为网卡设计】的驱动模型,linux中网络设备驱动主要目的是为了支持API中socket相关的那些函数工作。【因为网络通信有一套专用的接口和体系,所以单独放在一类中。】

5.1.4.3、为什么字符设备驱动最重要

(1)常见大量设备都属于字符设备

(2)举例说明【非标准类型】字符设备驱动

标准类设备是指比较普遍的设备,而非标准类型设备是为某种专有功能,特定制作的设备。

5.1.5.驱动程序的安全性要求(写驱动就相当于在写内核)

5.1.5.1、驱动是内核的一部分

(1)驱动已经成为内核中最庞大的组成部分

(2)内核会直接以函数调用的方式调用驱动代码(驱动如果有问题,内核就死掉了)

(3)驱动的动态安装和卸载都会“更改”内核(有点像改装车)

5.1.5.2、驱动对内核的影响

(1)驱动程序崩溃甚至会导致内核崩溃(也做了一些防护措施)

(2)驱动的效率会影响内核的整体效率

(3)驱动的漏洞会造成内核安全漏洞

5.1.5.3、常见驱动安全性问题

(1)未初始化指针(野指针)

(2)恶意用户程序

(3)缓冲区溢出(定义一个buffer来接收应用层的数据,但是应用层发给的数据大于你定义的buf,如果在驱动中做出一些检验则可以避免这种错误)

(4)竞争状态(多个进程同时争夺某一个共同的资源现象)

【驱动接收应用层传进来的参数。】

5.1.6.驱动应该这么学

5.1.6.1、先学好C语言(最重要的前提就是C语言)

5.1.6.2、掌握相关预备知识

(1)硬件操作方面

(2)应用层API

5.1.6.3、驱动学习阶段

(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) 驱动模块 的组成:

1、头文件(必选)     #include<linux/module.h>     和#include<linux/init.h>是必须的

2、模块参数(可选)    驱动模块加载时,需要传递给驱动模块的参数

3、模块功能函数(可选)

4、其他(可选)

5、模块加载函数(必须)     模块的加载函数,有点类似于main()函数

6、模块卸载函数(必须)     执行后清除了加载函数里分配的资源

7、模块许可声明(必须)     表示模块受到内核支持的程度,使用MODULE_LICENSE()表示许可权限的程度。

(15)模块的操作:

1)insmod命令加载模块

2)rmmod命令卸载模块

3)lsmod查看模块加载信息

(16)linux下的驱动主要分为字符设备驱动、块设备驱动和网路设备接口驱动。我们学习驱动就是学习这三类设备提供给我们的接口。

(17)  静态编译(重新下载编译linux内核)和动态编译。开发阶段以动态编译(不重新启动内核)为主。模块的方式动态加载。

(18)主设备号区分设备驱动程序。次设备号区分同一个驱动程序创建的多个设备。常见于多个串口和硬盘分区。次设备号通常依次对应同类型的多个设备。

(19)设备驱动的框架:

1、驱动程序的开始------设备的注册

2、注册的结构体

3、注册的fop指针(函数表)

(20)内核程序员获得内存的方式是kmalloc(分配出的地址空间都是物理上连续的),使用方法类似于用户空间的malloc版本。

kmalloc传递不同标志,导致了该函数的不同行为:

GFP_KERNEL

GFP_ATOMIC

GFP_USER

_GFP_DMA

2.4内核中register——char

2.6内核中调用cdev结构体的初始化,fop指针(函数表)要嵌入到这个cdev结构体中

时间: 2024-10-08 06:22:37

(55)Linux驱动开发之一驱动概述的相关文章

linux驱动开发-模块驱动

linux内核是可以高度定制的,通过配置编译选项达到定制的目的. 在配置kernel编译选项时驱动程序的编译选项一般有三种,不编译.编译为内核驱动.编译为模块驱动.所以linux驱动一般分为两类,内核驱动和模块驱动,当然这两者之间并无绝对区别:当编译为内核驱动时,驱动程序将会随内核一起运行,就相当于内核的固有部分一样:当编译为模块驱动时,每个驱动程序都是独立的个体,在需要的时候安装,用完了再卸载,可以节约硬件资源.以下内容描述的是模块驱动的开发过程. 1.获取内核源码,按照目标器件(PC机或者开

驱动开发 —— 高级驱动学习方法

回顾一下之前的字符设备驱动编程: 1,实现入口函数 xxx_init()和卸载函数 xxx_exit() 2,申请设备号 register_chrdev_region (与内核相关) 3,注册字符设备驱动 cdev_alloc.cdev_init. cdev_add (与内核相关) 4,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关) 5,硬件部分初始化 io资源映射 ioremap,内核提供gpio库函数 (与硬件相关) 注

BDD(行为驱动开发)

BDD的重点是通过与利益相关者的讨论取得对预期的软件行为的清醒认识.它通过用自然语言书写非程序员可读的测试用例扩展了测试驱动开发方法.行为驱动开发人员使用混合了领域中统一的语言的母语语言来描述他们的代码的目的.这让开发者得以把精力集中在代码应该怎么写,而不是技术细节上,而且也最大程度的减少了将代码编写者的技术语言与商业客户.用户.利益相关者.项目管理者等的领域语言之间来回翻译的代价. 关于如何处理需求说明与测试,不同的组织使用不同的名称,或者说是不同的定义,但他们都有一套共同的核心原则与思想,而

Linux驱动开发概述

原文出处:http://www.cnblogs.com/jacklu/p/4722563.html Linux设备分类 设备的驱动程序也要像裸机程序那样进行一些硬件操作,不同的是驱动程序需要"融合进内核里",因此需要在驱动程序中加入操作系统规定的接口,这些接口都是独立于设备的.虽然操作系统为驱动程序设计者带来了"麻烦",却为应用程序设计者带来了"便利". Linux下设备分为三类:字符设备.块设备.网络设备. 字符设备是指必须以串行顺序访问的设备

Android系统移植与驱动开发概述读书心得

第一章是Android系统移植与驱动开发概述,包含了Android系统架构.Android系统移植的主要工作.查看Linux内核版本.Linux内核版本号的定义规则.如何学习Linux驱动开发以及Linux设备驱动等六方面内容 Android系统架构分为四层,分别是Linux内核.C/C++代码库.Android SDK API和应用程序.Linux内核这一层主要包括Linux的驱动程序以及内存管理.进程管理.电源管理等程序. Android移植可分为两部分:应用移植和系统移植.应用移植是指将应

Linux下spi驱动开发

转载至:http://www.embedu.org/Column/Column367.htm 作者:刘洪涛,华清远见嵌入式学院讲师. 一.概述 基于子系统去开发驱动程序已经是linux内核中普遍的做法了.前面写过基于I2C子系 统的驱动开发.本文介绍另外一种常用总线SPI的开发方法.SPI子系统的开发和I2C有很多的相似性,大家可以对比学习.本主题分为两个部分叙述,第一 部分介绍基于SPI子系统开发的理论框架:第二部分以华清远见教学平台FS_S5PC100上的M25P10芯片为例(内核版本2.6

《Android深度探索卷一》第一章Android系统移植与驱动开发概述。

<Android深度探索>第一章讲的是Android系统移植与驱动开发概述.这一章节将对Android以及Linux驱动做一个总体的介绍. Android是一个非常优秀的的嵌入式操作系统.经过几年的发展和演进,Android已经形成了非常完善的系统架构.Android的系统架构分为四层,如下图 Android移植可分为两部分:应用移植和系统移植. Android系统移植是指让Android操作系统在某一个特定硬件平台上运行.使一个操作系统在特定硬件平台上运行的一个首要条件就是该操作系统支持硬件

《Linux设备驱动开发详解(第3版)》海量更新总结

本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux设备驱动概述及开发环境构建>[D]删除关于LDD6410开发板的介绍[F]更新新的Ubuntu虚拟机[N]添加关于QEMU模拟vexpress板的描述 第2章 <驱动设计的硬件基础> [N]增加关于SoC的介绍:[N]增加关于eFuse的内容:[D]删除ISA总线的内容了:[N]增加关于SP

Android系统移植与驱动开发概述 第一章

Android系统移植与驱动开发概述 1. Android的系统架构分为Linux内核.C/C++代码库.Android SDK API.应用程序四层. 2. Android移植可分为应用移植和系统移植.应用移植是指将应用程序移植到特定的硬件平台.系统移植指的是让Android操作系统在某一特定硬件平台上运行(首要条件是该操作系统支持硬件平台的CPU架构).系统移植的主要任务是移植Linux驱动和HAL(Hardware Abstraction Layer:硬件抽象层,位于应用程序与驱动之间).