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

文章目录

    • 前情提要
    • 第五章 嵌入式 Linux 驱动开发
      • 1) 设备驱动的概念、抽象层次、分类、特点、安装方法
        • 什么是驱动程序:
        • 设备驱动分类
      • 2) 设备驱动开发过程
        • 直接编译进内核
        • 编译成模块
      • 3) 字符设备驱动结构,file_operations 里常用的接口函数、驱动的结构
        • 驱动程序举例:
      • 4) 所有的函数不需要背

前情提要

本人是一名大三学生,由于期末复习需要,所以按照老师的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 */

  1. 块设备驱动

设备上的数据以块的方式存放(如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 函数中实现的。

      //老注册接口
      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. 文件操作数据结构的指针
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) 所有的函数不需要背

上一篇:18_Scala面向对象编程trait


下一篇:学习《现代密码学——基于安全多方计算协议的研究》 第一章