文章目录

  • 基本概念
    • 什么是设备驱动
    • 无操作系统下的驱动
    • 有操作系统下的驱动
    • 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:网络相关代码,实现各种常见的网络协议。
  • scripts:用于配置内核的脚本文件。
  • security:主要是一个 SELinux 的模块。
  • sound:ALSA、OSS 音频设备的驱动核心代码和常用设备驱动。
  • usr:实现用于打包和压缩的 cpio 等。
  • include:内核 API 级别头文件。

内核主要组成部分

进程调度SCHED

进程调度控制系统使得多个进程在CPU的中微观上分时执行,宏观上并发执行
进程整体上可以分为五种状态:

  • 就绪态:资源准备就绪,等待系统调用该进程
  • 执行态:当前CPU正在执行该进程
  • 睡眠态:等待其它进程释放资源
  • 暂停态:停止执行,等待某种信号
  • 僵尸态:进程已死,资源未释放

内存管理MM

内存管理的主要作用是控制多个进程安全地共享主内存区域。当CPU提供内存管理单元(MMU)时,Linux内存管理对每个进程提供虚拟地址到物理地址的转换

每个进程拥有虚拟的4G内存空间,其中3G是用户空间,是属于进程私有的,1G是内核空间,是所有进程共享的

虚拟文件系统VFS

用户通过虚拟文件系统,对文件进行操作,即可达到访问硬件的目的,虚拟文件系统隐藏了硬件差异,向上为用户提供统一的接口,向下调用驱动程序实现的file_operations结构体中的成员函数

网络接口NET

网络接口提供了对各种网络标准的存取和各种网络硬件的支持。在 Linux中网络接口可分为网络协议和网络驱动程序,网络协议部分负责实现每一种可能的网络传输协议,网络设备驱动程序负责与硬件设备通信,每一种可能的硬件设备都有相应的设备驱动程序。

进程间通信IPC

Linux支持进程间通信的多种机制,包括信号量、共享内存、消息队列、管道、套接字等。利用这些机制,可以实现进程间的同步、互斥和消息传递。

内核代码命名风格

与windows下流行的编程命名风格不同,linux社区形成了自己的一套风格

#define PI 3.1415926
int min_value, max_value;
void send_data(void);
  • 宏:大写
  • 变量:全部小写,单词之间以下划线分隔
  • 函数:同变量
  • 缩进: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长度数组,也可以使用变量定义数组长度

struct var_data {int len;
char data[0];
};int n=10;
int array[n];

其实也就是C99中新增加的伸缩数组和变长数组的概念

伸缩的意思是,比如定义一个结构体,可以让其成员拥有不固定的长度,因此用sizeof去求该结构体类型,会忽略掉不固定的部分,而实际定义的时候,一般需要用malloc进行内存分配

变长数组不是指数组的长度在程序运行期间可变,而是指定义时可以利用变量,对长度进行说明,一旦定义了一个数组,其长度就不能变了

case

GNU C 支持 case x…y 这样的语法,区间 [x,y] 中的数都会满足这个 case 的条件

switch (ch) {case '0'... '9': c -= '0';
break;
case 'a'... 'f': c -= 'a' - 10;
break;
case 'A'... 'F': c -= 'A' - 10;
break;
}

语句表达式

GNU C 把包含在括号中的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等,

typeof关键字

typeof(x) 语句可以获得 x 的类型,可以方便一些宏的实现,例如求两数中较大的值
# define max(a,b) ...
具体实现中,需要先判断传入数据的类型,此处可以通过typeof进行判断

标号元素

C99标准已经增加了标号元素的使用,也就是数组、结构体等初始化过程不需要按顺序来,可以随意指定,例如:

int a[10] = {[1] = 2,[3] = 5,0,
}

在Linux内核代码中,推荐以下格式进行初始化:

struct file_operations ext2_file_operations = {.llseek       = generic_file_llseek,.read        = generic_file_read,...
};

特殊属性说明

GNU C 允许声明函数、变量和类型的特殊属性,以便手动优化代码和定制代码检查的方法。要指定一个声明的属性,只需要在声明后添加_ _attribute_ _ (( ATTRIBUTE ))

其中 ATTRIBUTE 为属性说明,如果存在多个属性,则以逗号分隔。GNU C 支持 noreturn、format、section、aligned、packed 等十多个属性

  • noreturn 属性作用于函数,表示该函数从不返回。这会让编译器优化代码,并消除不必要的警告信息
  • format 属性也用于函数,表示该函数使用 printf、scanf 或 strftime 风格的参数,指定format 属性可以让编译器根据格式串检查参数类型
  • unused 属性作用于函数和变量,表示该函数或变量可能不会用到,这个属性可以避免编译器产生警告信息
  • aligned 属性用于变量、结构体或联合体,指定变量、结构体或联合体的对齐方式,以字节为单位
  • packed 属性作用于变量和类型,用于变量或结构体成员时表示使用最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小的内存

内建函数

内建函数是编译器内部实现的函数,这些函数可以直接使用,无须声明或者添加头文件,不属于标准库函数的内建函数通常以_ _builtin开头,还有一小部分内建函数与标准库函数同名,不过编译器做了优化或者重构。

工具链

最方便的就是直接下载已经编译好的工具链,目前最常用的是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

linux设备驱动(一)相关推荐

  1. linux设备驱动第五篇:驱动中的并发与竟态

    目录[-] 综述 信号量与互斥锁 Completions 机制 自旋锁 其他的一些选择 不加锁算法 原子变量与位操作 seqlock(顺序锁) 读取-拷贝-更新(RCU) 小结 综述 在上一篇介绍了l ...

  2. 《Android深度探索(卷1):HAL与驱动开发》——1.6节 Linux设备驱动

    本节书摘来自异步社区<Android深度探索(卷1):HAL与驱动开发>一书中的第1章,第1.6节 Linux设备驱动,作者李宁,更多章节内容可以访问云栖社区"异步社区" ...

  3. linux设备驱动归纳总结

    前言: (总结已经基本写完,这段时间我会从新排版和修正.错误总会有的,望能指正!) 前段时间学习了嵌入式驱动,趁着没开始找工作,这段时间我会每天抽出时间来复习. 我的总结是根据学习时的笔记(李杨老师授 ...

  4. 【翻译】【linux设备驱动】linux地址类型

    [翻译][linux设备驱动]linux地址类型 Linux中使用的地址类型列表: 用户虚拟地址(User virtual addresses) 用户空间程序可见的普通地址.用户虚拟地址的长度为32位 ...

  5. linux 统一设备模型 pci,Linux设备驱动模型摘抄

    Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄Linux设备驱动模型摘抄 Linux设备驱动模型摘抄(1) Linux统一设备模型 简介 Li ...

  6. linux设备驱动——总线、设备、驱动

    http://blog.csdn.net/wh_19910525/article/details/7398051 2.6 版本内核是如何管理总线,驱动,设备之间的关系的,关于bus_type.devi ...

  7. LINUX设备驱动之设备模型一--kobject

    http://blog.csdn.net/yangzhu1982/article/details/6186016 Linux设备驱动之设备模型一kobject Eric Fang  2010-01-1 ...

  8. linux设备驱动之总线、设备、驱动

    文章转载至多个地方,网上拼凑的一篇文章,说的好听一些的话那就叫自己总结的文章,只 是多次引用啊,哈哈,哎,不管了,反正这个有利用学习进步就好,这是重要的,文章转载过来要经过一篇大脑才能成为自己的,以后 ...

  9. 《Linux设备驱动开发详解 A》一一2.3 接口与总线

    本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...

  10. 【Linux开发】linux设备驱动归纳总结(七):2.内核定时器

    linux设备驱动归纳总结(七):2.内核定时器 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

最新文章

  1. 商业实战第三场 电视直销好记星
  2. 巧用httpModules实现网站域名更换
  3. 简单分析synchronized不会锁泄漏的原因
  4. php连mssql 中文乱码,PHP连接MSSQL显示中文时为乱码_PHP教程
  5. Android动态权限申请
  6. PHP 7.2 新功能介绍
  7. 三角形描边css,[CSS] tips带有描边的小箭头
  8. linux输出文字的颜色特效
  9. javascript复制到黏贴板之完美兼容
  10. 统一视角理解实例分割算法:最新进展分析与总结
  11. STM32读写DS1302,HAL库方式
  12. PRINCE2产品认证报考常见一些问答
  13. 如何使用阿里云搭建个人网站 1
  14. win7计算机序列号在哪里,win7系统如何查看主板序列号?win7系统查看主板序列号的详细步骤图文教程...
  15. 计算机减法函数word,Word中减法公式怎么用
  16. Oracle数据库占用磁盘,导致磁盘活动时间为100%的解决方法
  17. qq邮箱html源码,qq邮箱源码
  18. 用开源力量抗击新冠疫情!腾讯作为创始成员加入Linux基金会公共卫生计划
  19. Robot Framework robot命令
  20. EDA和CAD合并建立电子模块热仿真模型 step by step

热门文章

  1. 《锋利的JQuery》读书笔记
  2. 【Matlab代码】基于小波分析的音频信号的特征识别
  3. Mac版 QQ防撤回插件
  4. LFW人脸数据集测试协议及编程实现
  5. JDK16和JDK8共存与切换
  6. 常用手机屏幕显示级别与分辨率对照
  7. 为什么CAD导出PDF没有颜色
  8. 线性代数第3章思维导图
  9. ArcGIS实验操作二:平移矢量要素(附实验数据下载)
  10. 虎牙tv是用php写的吗,huya虎牙php_麦麦同学