文章目录
- 基本概念
-
- 什么是设备驱动
- 无操作系统下的驱动
- 有操作系统下的驱动
- linux设备分类
-
- 字符设备
- 块设备
- 络设备
- 内核的组成
-
- 源码目录结构
- 内核主要组成部分
-
- 进程调度SCHED
- 内存管理MM
- 虚拟文件系统VFS
- 络接口NET
- 进程间通信IPC
- 内核代码命名风格
- GNU C对ANSI C的拓展
- 变长数组
- case
- 语句表达式
- typeof关键字
- 标 元素
- 特殊属性说明
- 内建函数
- 工具链
- 环境搭建
基本概念
什么是设备驱动
计算机的运行,需要软件和硬件的合作,没有软件的硬件,是一堆废铁,没有硬件的软件,是空中楼阁,软件运行在硬件基础之上。
软件又分为系统软件和应用软件,系统软件屏蔽了底层硬件的差异,向应用层提供统一的接口,因而应用层的程序员,不需要知道不同 卡、硬盘等硬件之间有什么差异,只需要调用相同的读写函数,即可完成对设备的读写操作。这个屏蔽具体硬件差异过程的重任,就落到了设备驱动的头上。设备驱动程序,仅仅是系统软件的一部分。
设备驱动是底层硬件和上层应用之间的纽带,设备驱动最通俗的解释是:驱使硬件设备行动。设备驱动与底层硬件直接打交道,完成寄存器的读写等、中断处理等等操作。
无操作系统下的驱动
计算机的运转不一定需要操作系统,目前stm8,stm32等主流单片机都可以直接跑裸机程序,一般认为只需要完成main函数和中断服务函数即可(当然IDE也帮我们完成了很多其它的底层工作)。这样简单的应用场景,并不需要操作系统提供的多任务调度,内存管理,文件系统等功能。
虽然没有操作系统,但是并不意味着没有驱动程序。一般情况下,每一个硬件设备,都对应了一个.c和.h文件,例如EEPROM芯片AT24C04,在程序中肯定会对该芯片多次的进行读写操作,为了方便,肯定会将这些重复使用的代码实现为函数,加入到整个工程之中,这些代码,也可以称之为驱动。只不过这些驱动程序的接口直接提供给应用层,应用层没有跨越任何层次,就直接访问到了底层硬件。
有操作系统下的驱动
驱动程序属于内核的一部分,内核是操作系统最核心的部分,它负责管理系统的进程、内存、设备驱动程序、文件和 络系统,决定着系统的性能和稳定性,因此驱动程序要按照内核的规定的格式和提供的接口来写。
在有操作系统的情况下,驱动程序其实是连接硬件和内核的一个桥梁,操作系统的存在,让驱动程序增加了很多代码,操作系统就是通过给驱动程序编写者制造麻烦,达到方便应用开发者的目的。
linux设备分类
驱动设备针对的存储器和外设,而不是针对cpu内核,linux系统将存储器和外设分为三大类:
- 字符设备
- 块设备
- 络设备
字符设备
字符设备指那些必须以串行顺序依次进行访问(字符流)的设备,如键盘、鼠标、串口等,系统虚拟出一个文件,对该文件调用读写函数(read、write)即可完成对字符设备的操作
块设备
系统可以随机访问快设备,以块为单位进行操作,如硬盘、FLASH、CD-ROM等,系统虚拟出一个文件,或者在块设备上建立文件系统,对这些文件调用读写函数(read、write)即可完成对块设备的操作
络设备
络设备通常指有线 卡、无线 卡等, 络设备面向数据包的接收和发送而设计,与字符设备和块设备不同, 络通信主要依靠套接字接口
内核的组成
源码目录结构
Linux 内核源代码包含如下目录。
- arch :包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如 i386、arm、
arm64、powerpc、mips 等。Linux 内核目前已经支持 30 种左右的体系结构。在 arch
目录下,存放的是各个平台以及各个平台的芯片对 Linux 内核进程调度、内存管理、
中断等的支持,以及每个具体的 SoC 和电路板的板级支持代码。 - block:块设备驱动程序 I/O 调度。
- crypto:常用加密和散列算法(如 AES、SHA 等),还有一些压缩和 CRC 校验算法。
- documentation:内核各部分的通用解释和注释。
- drivers :设备驱动程序,每个不同的驱动占用一个子目录,如 char、block、net、
mtd、i2c 等。 - fs:所支持的各种文件系统,如 EXT、FAT、NTFS、JFFS2 等。
- include:头文件,与系统相关的头文件放置在 include/linux 子目录下。
- init:内核初始化代码。著名的 start_kernel() 就位于 init/main.c 文件中。
- ipc:进程间通信的代码。
- kernel :内核最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码
放在 arch//kernel 目录下。 - ib:库文件代码。
- mm:内存管理代码,和平台相关的一部分代码放在 arch//mm 目录下。
- net: 络相关代码,实现各种常见的 络协议。
- security:主要是一个 SELinux 的模块。
- sound:ALSA、OSS 音频设备的驱动核心代码和常用设备驱动。
- usr:实现用于打包和压缩的 cpio 等。
- include:内核 API 级别头文件。
内核主要组成部分
络接口NET
络接口提供了对各种 络标准的存取和各种 络硬件的支持。在 Linux中 络接口可分为 络协议和 络驱动程序, 络协议部分负责实现每一种可能的 络传输协议, 络设备驱动程序负责与硬件设备通信,每一种可能的硬件设备都有相应的设备驱动程序。

进程间通信IPC
Linux支持进程间通信的多种机制,包括信 量、共享内存、消息队列、管道、套接字等。利用这些机制,可以实现进程间的同步、互斥和消息传递。
内核代码命名风格
与windows下流行的编程命名风格不同,linux 区形成了自己的一套风格
- 宏:大写
- 变量:全部小写,单词之间以下划线分隔
- 函数:同变量
- 缩进:tab键
- 括 {}:
1.if、for、switch、while、else、else if 不会另起一行
2.函数的 需要另起一行
3.只有一行代码,不要用括 - switch:switch、case、default关键字左对齐
GNU C对ANSI C的拓展
Linux使用的C编译器是GNU C编译器,对标准C进行了一系列拓展,增强C的功能
变长数组
GNU C可以使用0长度数组,也可以使用变量定义数组长度
其实也就是C99中新增加的伸缩数组和变长数组的概念
伸缩的意思是,比如定义一个结构体,可以让其成员拥有不固定的长度,因此用sizeof去求该结构体类型,会忽略掉不固定的部分,而实际定义的时候,一般需要用malloc进行内存分配
变长数组不是指数组的长度在程序运行期间可变,而是指定义时可以利用变量,对长度进行说明,一旦定义了一个数组,其长度就不能变了
case
GNU C 支持 case x…y 这样的语法,区间 [x,y] 中的数都会满足这个 case 的条件
语句表达式
GNU C 把包含在括 中的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等,
typeof关键字
typeof(x) 语句可以获得 x 的类型,可以方便一些宏的实现,例如求两数中较大的值
具体实现中,需要先判断传入数据的类型,此处可以通过typeof进行判断
标 元素
C99标准已经增加了标 元素的使用,也就是数组、结构体等初始化过程不需要按顺序来,可以随意指定,例如:
在Linux内核代码中,推荐以下格式进行初始化:
特殊属性说明
GNU C 允许声明函数、变量和类型的特殊属性,以便手动优化代码和定制代码检查的方法。要指定一个声明的属性,只需要在声明后添加 (( ATTRIBUTE ))。
其中 ATTRIBUTE 为属性说明,如果存在多个属性,则以逗 分隔。GNU C 支持 noreturn、format、section、aligned、packed 等十多个属性
- noreturn 属性作用于函数,表示该函数从不返回。这会让编译器优化代码,并消除不必要的警告信息
- format 属性也用于函数,表示该函数使用 printf、scanf 或 strftime 风格的参数,指定format 属性可以让编译器根据格式串检查参数类型
- unused 属性作用于函数和变量,表示该函数或变量可能不会用到,这个属性可以避免编译器产生警告信息
- aligned 属性用于变量、结构体或联合体,指定变量、结构体或联合体的对齐方式,以字节为单位
- packed 属性作用于变量和类型,用于变量或结构体成员时表示使用最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小的内存
内建函数
内建函数是编译器内部实现的函数,这些函数可以直接使用,无须声明或者添加头文件,不属于标准库函数的内建函数通常以开头,还有一小部分内建函数与标准库函数同名,不过编译器做了优化或者重构。
工具链
最方便的就是直接下载已经编译好的工具链,目前最常用的是Linaro提供的,可以在下面的 址进行下载
http://www.linaro.org/downloads/
Linaro 是 ARM Linux 领域中最著名最具技术成就的开源组织,其会员包括 ARM、Broadcom、Samsung、TI、Qualcomm 等,国内的海思、中兴、全志和中国台湾的 MediaTek 也是它的会员
工具链包含了很多程序,例如arm-linux-gnueabihf-gcc
下面介绍一下常用的几种
- gcc:编译C源码
- g++:编译C++源码
- gdb:调试
- strip:删除符 表和调试信息,缩减可执行文件的体积
- objdump:反汇编
- ld:链接器
- gprof:检查函数被调用的次数和时间
- nm:显示符 信息
- readelf:查看ELF格式文件信息
- addr2line:将指令的地址和可执行映像转换为文件名、函数名和源代码行数的工具
环境搭建
练习驱动程序开发,最好的方式是虚拟机+qemu,不需要额外购买开发板,具体搭建的过程可以参考我之前的博客
https://blog.csdn.net/whitefish520/article/details/103850361
文章知识点与官方知识档案匹配,可进一步学习相关知识C技能树首页概览114815 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!