【嵌入式系统复习总结】第五章 嵌入式 Linux 驱动开发

文章目录

前情提要

本人是一名大三学生,由于期末复习需要,所以按照老师的ppt总结整理此笔记,希望对你有所帮助

第五章 嵌入式 Linux 驱动开发

  1. 设备驱动的概念、抽象层次、分类、特点、安装方法
  2. 设备驱动开发过程
  3. 字符设备驱动结构,file_operations 里常用的接口函数、驱动的结构
  4. 所有的函数不需要背

1) 设备驱动的概念、抽象层次、分类、特点、安装方法

设备驱动程序介于操作系统和硬件之间,屏蔽了硬件设备的物理细节,并提供了访问各种硬件设备的统一接口。Linux内核源程序中占有60%以上。

应用程序 库 内核 驱动程序之间的关系

什么是驱动程序:
  1. 作为操作系统的一部分(OS = Kernel + Device Driver)
    • 向上为Linux系统提供访问硬件统一调用接口
    • 向下用于控制硬件:与Arm裸机程序一样,通过读写硬件寄存器达到控制硬件的目的
  2. 驱动程序的运行是被动的
    • 驱动只是告诉内核"我在这里,我能做这些工作":向内核注册
    • 这些工作何时开始,取决于应用程序:应用触发驱动
设备驱动分类
  1. 字符设备驱动
    设备以字节流 方式访问(以字节为单位读写)
    字符设备驱动实现了open、close 、read、write 等系统调用
    应用程序通过设备文件 (如/dev/ttySAC0)访问设备
    字符设备文件的第一个标志是前面的"c"标志。

    $ ls --l /dev
    crw-rw---- 1 root uucp 4, 64 08-30 22:58 ttyS0 /串口设备, c表示字符设备/
    crw-rw---- 1 root uucp 3, 4 08-30 22:58 ttyS0 /* 主设备号3,此设备号4 */

  2. 块设备驱动

设备上的数据以块的方式存放 (如NAND Flash上的数据以页为单位)

块设备驱动程序也向用户层提供open、close

应用通过设备文件 (如/dev/sda1)来访问设备

块设备驱动特别之处:

(1)操作硬件的实现方式不一样:先将数据组织成块,再操作设备

(2)数据块上的数据按照一定的格式组织:存放文件系统,实现mount

例如,在系统中的块设备IDE硬盘的主设备号是3,而多个IDE硬盘及其各个分区分别赋予次设备号1、2、3......

复制代码
$ ls --l /dev
brw-r-----  1 root  floppy 2,   0 08-30 22:58 fd0/*软盘设备,b表示块设备*/
  1. 网络设备驱动
    设备上的数据以不固定大小的帧 输入与输出
    没有/dev上对应的设备文件,不通过open、read、write操作
    系统为网络设备访问分配唯一接口(如eth0)
    为应用层提供一套数据包传输函数访问接口(SOCKET)

2) 设备驱动开发过程

  1. 查看原理图、数据手册,了解设备的操作方法
  2. 在内核中找到相近的驱动程序,以它为模板开发
  3. 实现驱动程序的初始化,并向内核注册
  4. 按照内核规定的驱动框架,实现相关操作函数(如open、read、write)
  5. 编译 驱动程序到内核中 ,或者编译成模块并挂载(insmod)到内核
直接编译进内核
  1. 将驱动模块源码合入内核源码

    • 设备驱动程序应包含在drivers子目录
    • 首先确认是否存在于设备驱动程序特性相似的目录名
    • 存在则插入相应目录,否则字符类型插入char目录,块类型插入block目录,网络类型插入net目录
  2. 修改内核编译选项文件

    • Linux内核支持使用内核编译选项包含到内核中的功能
    • make menuconfig读入这些内核编译选项文件来配置内核
    • 2.6内核编译选项文件为KConfig
    • 进入加入了驱动模块的目录,修改目录下的KConfig,使得加入的驱动能在配置项中显示
  3. 修改内核源码中的Makefile

    • Makefile指定了驱动程序的编译规则,使得驱动程序能包含到内核image中
    • Makefile根据make menuconfig配置设定的编译条件变量,决定是要把特定源代码编译成模块还是包含到内核中,或者是清除。
    • 进入合入了驱动模块的目录,修改改目录下的Makefile,使得合入的驱动源码能编译进内核
  4. 确认合入内核的驱动在内核启动时自动运行

    • 重新编译并启动新内核,dmesg=>确认"hello world"已打印出来
    • 带**__int标志**的函数被放入初始化代码段,内核会依次调用初始化代码段的
    • 函数,并在初始化完成后释放 init 区段.
编译成模块
  1. 模块加载函数(必需)

    安装模块时被系统自动调用的函数,通过module_init宏来指定

  2. 模块卸载函数(必需)

    卸载模块时被系统自动调用的函数,通过module_exit宏来指定

加载 insmod (insmod hello.ko)

卸载 rmmod (rmmod hello)

查看 lsmod

加载 modprobe (modprobe hello)

modprobe 如同 insmod, 也是加载一个模块到内核。它的不同

之处在于它会根据/lib/modules/<$version>/modules.dep

来查看要加载的模块, 看它是否还依赖于其他模块,如果是,

modprobe 会首先找到这些模块, 把它们先加载到内核。

3) 字符设备驱动结构,file_operations 里常用的接口函数、驱动的结构

总体结构:

3、调用关系

(1)当应用程序使用open打开某个设备(/dev的设备文件)

设备驱动程序file_operations结构中open成员函数被调用

(2)当应用程序使用使用read、write、ioctl等函数读写、控制设备

设备驱动程序file_operations结构中read、write、ioctl等成员函数被调用

4、字符设备驱动程序目的

为具体硬件设备file_operations 结构实现操作设备所需的成员函数

5、设备文件与驱动程序file_operations结构的对应关系

主设备号用来标识 与设备文件相连 的驱动程序,次编号 背驱动程序来辨别操作的是那个设备
主设备号 用来反映设备类型
次设备号 用来区分同类型的设备

6、设备驱动注册

在驱动中init 函数中实现的。

c 复制代码
      //老注册接口
      register_chrdev(DEV_MAJOR, DEV_NAME, &dev_ops); 

     //2.6内核使用cdev来描述一个字符设备
     cdev_init(&s_cdev, &dev_ops); //初始化cdev		
     ret = cdev_add(&s_cdev, s_dev, DEV_COUNT); //注册cdev

注册完成后,应用程序操作设备文件时,系统就会根据

主设备号找到内核中注册file_operations结构

驱动程序举例:

字符驱动程序框架

  1. 包含头文件
    编写字符驱动程序时需要的内核头文件
  2. 定义常量
    定义模块的主设备号和名称,它们将在字符设备的初始化的注册函数中使用。
  3. 函数声明
    声明需要使用的函数,将被注册到文件操作数据结构struct file_operations中。
  4. 文件操作数据结构的指针
c 复制代码
static struct file_operations virtual_char_fops={
	owner:         THIS_MODULE,
	llseek:          virtual_char_llseek,
	read:            virtual_char_read,
	write:           virtual_char_write,
	ioctl:            virtual_char_ioctl,
	open:           virtual_char_open,
	release:        virtual_char_close,
}

这是驱动程序的核心部分,定义了一个静态文件操作数据结构,将数据结构中几个成员赋值为驱动程序中函数的指针

复制代码
5. 函数中的各种操作
   - module_init()注册的函数执行设备文件的注册
   - module_exit()注册的函数执行设备文件的卸载。
   - open中增加引用计数;close中减少引用计数。
   - write/read中执行定义的读写操作,内容传递主要通过缓冲区的指针buf。
   - ioctl中执行驱动程序自定义的命令,根据cmd选择要执行的命令
  1. 应用程序
    linux的应用程序与驱动程序调用关系

应用程序使用驱动程序主要有以下几个步骤:

  1. 使用open打开设备文件
  2. 在使用驱动程序的时候,根据需要调用write/read/ioctl等操作
  3. 使用close关闭设备文件

4) 所有的函数不需要背

相关推荐
DKPT44 分钟前
JVM栈溢出和堆溢出哪个先满?
java·开发语言·jvm·笔记·学习
CiLerLinux5 小时前
第四十九章 ESP32S3 WiFi 路由实验
网络·人工智能·单片机·嵌入式硬件
时光の尘5 小时前
【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
单片机·嵌入式硬件·pcb·二极管·电感·三极管·场效应管
Lu Zelin5 小时前
单片机为什么不能跑Linux
linux·单片机·嵌入式硬件
驱动开发0076 小时前
虚拟麦克风驱动下载,支持将手机话筒映射成PC端麦克风
驱动开发·安全
CS Beginner6 小时前
【Linux】 Ubuntu 开发环境极速搭建
linux·运维·ubuntu
ajassi20006 小时前
开源 C++ QT QML 开发(二)工程结构
linux·qt·qml
宁静致远20216 小时前
stm32 freertos下基于hal库的模拟I2C驱动实现
stm32·嵌入式硬件·freertos
bnsarocket7 小时前
Verilog和FPGA的自学笔记1——FPGA
笔记·fpga开发·verilog·自学
今天只学一颗糖7 小时前
Linux学习笔记--insmod 命令
linux·笔记·学习