当前位置:
文档之家› 第四章 Linux驱动程序设计.ppt
第四章 Linux驱动程序设计.ppt
printk(KERN_ALERT " Hello world exit\n"); } module_init(hello_init); module_exit(hello_exit);
模块初始化 宏
模块卸载宏
2019年12月24日
21
打印调试printk
指示日志级别的宏 KERN_EMERG 用于紧急事件消息,一般是系统崩溃前提示<0>
块设备通过位于 /dev 目录的文件系统结点来存取
块设备和字符设备的区别仅仅在于内核内部管理数据的 方式
块设备有专门的接口,块设备的接口必须支持挂装 (mount)文件系统。
应用程序一般通过文件系统来访问块设备上的内容
2019年12月24日
17
4-2设备的分类和特点
网络设备特点
简单的内核模块编译(内核2.6)
如果是多个源文件编译出一个模块,假设模块名是test.ko, 那么源文件名不能有test.c
obj-m := test.o
test-objs := file1.o file2.o file3.o
KDIR := /home/at9200/kernel/linux-2.6.38/
(4)应用程序得到文件描述符后,使用库提供的write 或ioclt函数发出控制命令 (5)库根据write或ioclt函数传入的参数执行“swi”指令, 这条指令会引起CPU异常,再次进入内核 (6)内核的异常处理函数根据参数调用驱动程序的相关 函数,控制硬件
4-2设备的分类和特点
块设备特点
static int __init hello_init(void) {
printk(KERN_ALERT "Hello world\n");
用法类似于printf, 但它有优先级(比如
KERN_ALERT)
return 0; }
宏,告诉内核这两个函数只会 在加载和卸载模块时使用
static void __exit hello_exit(void) {
教学内容
第一章 嵌入式系统概述 第二章 学习板硬件及开发环境的建立 第三章 构建嵌入式Linux系统 第四章 嵌入式Linux设备驱动 第五章 嵌入式Linux串口和网络编程 第六章 嵌入式Linux图形编程
2019年12月24日
1
第四章 嵌入式Linux驱动程序
4.1 嵌入式Linux设备驱动简介 4.2 设备的分类及特点 4.3 构造和运行驱动程序模块
2019年12月24日
8
内核态和用户态
大多数OS(包括Linux)把内核和运行在其上的应用程 序分为两个层次管理,即用户态和内核态
内核态有较高的权限,可以控制处理器内存的映射和分 配方式等等————对应于ARM的svc模式
用户态:只能运行系统上的应用程序————对应于 ARM的usr模式
内核态与用户态切换:可通过软件中断实 现
2019年12月24日
3
本章目标
了解Linux设备驱动程序的基础知识 掌握Linux驱动模块的构造和装载方法
2019年12月24日
4
本章结构
Linux驱动程序概述
2019年12月24日
设备驱动程序简介
设备的分类和特点 构造和运行模块
字符设备 块设备
网络设备 设备驱动的Hello World模块 内核驱动模块和应用程序对比
module_exit()---模块卸载函数(必须) 当通过rmmod命令卸载某模块时,模块的卸载函数会 自动被内核执行,完成与模块装载函数相反的功能
2019年12月24日
28
4-3-1 设备驱动的Hello World模块
MODULE_LICENSE()---模块许可证声明(必须) 模块许可证(LICENSE)声明描述内核模块的许可权 限 如果不声明LICENSE,模块被加载时,将收到内核被 污染(kernel tainted)的警告 包括:“GPL”、 “GPL v2”、 “GPL and additional rights”、 “Dual BSD/GPL”、“Dual MPI/GPL”、 “Proprietary”
通过单独的网络接口来访问
任何一个网络事务都通过一个网络接口访问,即一个能 够和其他主机交换数据的设备。
网卡 软件设备:环回接口(loopback)
内核调用一套和数据包传输相关的函数
2019年12月24日
18
4-3 构造和运行模块
驱动程序加入内核的方法
把所有需要的功能都编译到内核中 生成的内核镜像(Image)文件会很大
insmod 将模块动态加载到正在运行内核 rmmod 程序移除模块
2019年12月24日
20
4.3.1 设备驱动的Hello World模块
#include <linux/init.h> #include <linux/module.h>
自由许可证
MODULE_LICENSE("Dual BSD/GPL");
make -C $(KDIR) M=$(PWD) clean
简单的内核模块编译(内核2.6)
obj-m := led_drv.o表示编译后生成 led_drv.ko模块
$(KDIR) 指定了target内核源码的路径, “M=”表示这是个外部模块,M=$(PWD) 指定了该模块文件所在的路径。
2019年12月24日
29
4-3-1 设备驱动的Hello World模块
模块加载函数
static int __init initialization_function(void)
{ /* 初始化代码 */
}
应当声明成静态的 (static), 因为它们不 会在特定文件之外可见
module_init(initialization_function);
如果我们要在现有的内核中新增或删除功 能,将不得不重新编译和装载内核。
2019年12月24日
19
4-3 驱动程序加入内核的方法
Linux提供了机制被称为模块(Module)的 机制
提供了对许多模块支持, 包括但不限于, 设备驱动
每个模块由目标代码组成( 没有连接成一个完整可执行程 序)
2019年12月24日
30
4-3-1 设备驱动的Hello World模块
模块卸载函数
static void __exit cleanup_function(void在释)模放块所被 有移所除占前用注的销系接统口资并源 {
/* 释放资源 */ } module_exit(cleanup_function);
KERN_ALERT 用于需要立即采取动作<1>
KERN_CRIT 临界状态,通常涉及到严重的硬件或软件操作失败<2>
KERN_ERR 用于报告错误状态,设备驱动程序会经常使用其来报告来自硬 件的问题<3>
KERN_WARNING 用于对可能出现的问题进行警告<4>
KERN_NOTICE 用于有必要进行提示的正常情况<5>
内核态和用户态
驱动程序作为系统内核的一部分,其工作在内核态,而 应用程序工作在用户态,即不能直接通过指针,把用户空 间的数据地址传递给内核(MMU映射地址不一样)。
需要经过转换,把用户态“看到的空间”转换成内核态 可访问的地址。Linux系统提供了一系列方便的函数实现 这种转换,如:__get_user、__put_user、 •__copy_from_user、__copy_to_user
高回报
2019年12月24日
7
4-1设备驱动程序简介
驱动程序的特点
操控硬件,是应用程序和硬件设备之间的一 个接口
隐藏硬件细节,提高应用软件的可移植性 提供安全性 开发模式
内核态驱动 用户态驱动
提供机制,而不是提供策略
机制:驱动程序能实现什么功能 策略:用户如何使用这些功能
表明该函数只是在初始化时使用。模块加载器在模块加 载后会丢掉这个初始化函数, 这样可将该函数占用的内存 释放出来,以作他用。
原型:#define __init __attribute__ ((__定se义cti会on在__(模“.i块nit目.te标xt”代)))码中增加一个特殊的 段, 用于说明内核模块初始化函数所在的位 置。没有这个定义, 初始化函数不会被调用。
库
称为系统调用,执行
其他库函数的实现
swi指令进入内核
内核
系统调用的异常处理
其他功能
驱动程序 open read write ioctl ቤተ መጻሕፍቲ ባይዱ…
物理设备控制器 物理设备
4层软件关系说明
(1)应用程序使用库函数提供的open函数打开设备文 件
(2)库根据open函数传入的参数执行“swi”指令,引起 CPU异常,进入内核 (3)内核的异常处理函数根据这些参数找到相应的驱动 程序,返回一个文件描述符给库,进而返回给应用程序
2019年12月24日
2
课程目标
掌握嵌入式Linux设备驱动程序的基本原 理、架构和设计方法
字符设备驱动 块设备驱动 网络设备驱动
掌握Linux设备驱动开发中常用的机制和 内核资源
中断顶/底半部处理 内核定时器和延时操作 并发控制在内核中的应用 内存管理和分配 阻塞型I/O和非阻塞型I/O
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean: