nullLinux设备驱动程序
开发基础Linux设备驱动程序
开发基础主讲人:TonyShen课程目标课程目标
Linux设备驱动程序开发简介
Linux设备驱动程序结构
Linux设备驱动程序加载方式
实验:编写一个字符设备驱动程序(LED或蜂鸣器)
分别用静态编译,模块动态加载
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
实现加入内核
设备驱动程序设备驱动程序应
用
程
序驱
动
程
序设
备writereadioctlioctl设备驱动程序特点设备驱动程序特点⑴核心代码:设备驱动程序是核心的一部分,像核心中其他的代码一样,出错将导致系统的严重损伤。一个编写不当的设备驱动程序甚至能够使系统崩溃导致文件系统的破坏和数据的丢失;
⑵标准接口:设备驱动程序必须为Linux核心或者其从属的子系统提供一个标准的接口;
⑶核心机制:设备驱动程序可以使用标准的核心服务比如内存分配、中断发送和等待对列等;
⑷动态可加载:多数的Linux设备驱动程序可以在核心模块发出加载请求时进行加载,同时在不使用设备时进行卸载,这样核心可以有效地利用系统的资源
⑸可配置:Linux设备驱动属于核心的一部分,用户可以根据自己的需要进行配置来选择适合自己的驱动用户态与内核态用户态与内核态Linux运转在两种模式下,一种是用户态,另一种是内核态。
内核态有较高的权限,可以控制处理器内存的映射和分配方式,访问外设空间和处理器状态寄存器,控制中断等。
用户态只能运行系统上的应用程序。
驱动程序作为系统内核的一部分,工作在内核态。
通过get_user put_user copy_from_user copy_to_user等函数实现应用程序和驱动程序之间传送数据(指针)。Linux设备的分类Linux设备的分类字符设备
以字节为单位逐个进行I/O操作
字符设备中的缓存是可有可无
不支持随机访问
如串口设备
块设备
块设备的存取是通过buffer、cache来进行
可以进行随机访问
例如IDE硬盘设备
可以支持可安装文件系统
网络设备
通过BSD套接口访问
设备文件设备文件
Linux抽象了对硬件的处理,所有的硬件设备都可以作为普通文件一样来看待
可以使用和操作文件相同的、标准的系统调用接口来完成打开、关闭、读写和I/O控制操作
对用户来说,设备文件与普通文件并无区别
字符设备和块设备是通过文件节点访问的。在Linux的文件系统中,可以找到(或者使用mknod创建)设备对应的文件名,称这种文件为设备文件。设备文件设备文件命令 ls –l /dev 可列出系统的设备文件
主设备号和次设备号主设备号和次设备号主设备号:标识该设备的种类,也标识了该设备所使用的驱动程序
主设备号的范围只能是1-255
Linux内核支持动态分配主设备号
次设备号:标识使用同一设备驱动程序的不同硬件设备
同一个驱动程序可以管理多个设备,它们依靠次设备号来区别。次设备号只在驱动程序内部使用,系统内核直接把次设备号传递给驱动程序,由驱动程序去管理。
设备文件系统设备文件系统Linux内核自己管理设备文件,完成设备文件节点的创建、删除。(devfs,device file system)
在linux2.4/2.6内核中,设备文件系统可在配置内核时定制。
linux2.4内核配置层次
File systems ->/dev file system support
linux2.6内核配置层次
File systems ->Pseudo file system ->/dev file system support
系统驱动程序通过CONFIG_DEVFS_FS宏定义判断系统是否有对设备文件系统的支持。
配置设备文件系统配置设备文件系统Linux设备驱动程序结构Linux设备驱动程序结构Linux设备驱动程序的代码结构大致可以分为如下几个部分:
驱动程序的注册与注销、设备的打开与释放、设备的读写操作、设备的控制操作、设备的中断和轮询处理。
一个最简单字符驱动程序,由下面5个函数和1个结构体就可组成。static int my_open(struct inode * inode, struct file * filp)
{ 设备打开时的操作 … }static int my_release(struct inode * inode, struct file * filp)
{ 设备关闭时的操作 … }static int my_write(struct file *file, const char * buffer, size_t count,
loff_t * ppos)
{ 设备写入时的操作 … }驱动程序结构驱动程序结构static struct file_operations my_fops = {
对文件操作结构体成员定义初始值…
}static int __init my_init(void)
{初始化硬件,注册设备,创建设备节点… }static void __exit my_exit(void)
{删除设备节点,注销设备… }头文件与系统定义头文件与系统定义#include
#include
#include
#include
#include
#include
#include
#include "9200.h“
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#define LED AT91C_PIO_PB11
static AT91PS_SYS AT91_SYS1 = (AT91PS_SYS) AT91C_VA_BASE_SYS;
#define DEVICE_NAME = “my_led”
static int Led_Major = 0;
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t Devfs_Led_Dir, Devfs_Led_Raw;
#endif打开和关闭操作打开和关闭操作my_open和my_release函数会在设备打开和关闭时被调用,其工作很简单,仅仅执行两个宏:”MOD_INC_USE_COUNT”,”MOD_DEC_USE_COUNT”。这两个宏负责
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
(增加或者减少)设备模块被使用的情况,防止当有应用程序使用驱动程序时,此模块被意外地卸载。static int my_open(struct inode * inode, struct file * filp){
MOD_INC_USE_COUNT;
return 0;
}static int my_release(struct inode * inode, struct file * filp
MOD_DEC_USE_COUNT
return 0;
}写入操作写入操作static int my_write(struct file *file, const char * buffer, size_t count,
loff_t * ppos){
char led_status = 0;
copy_from_user(&led_status, buffer, sizeof(led_status));
if(led_status == 0x01){ //如果应用程序传来的数据是0x01
AT91F_PIOB_SetOutput(LED); //打开LED
}else{
AT91F_PIOB_ClearOutput(LED); //关闭LED
}
return 0;
}文件操作结构体初始化文件操作结构体初始化static struct file_operations my_fops = {
open: my_open,
write: my_write,
release:my_release,
};文件操作结构体文件操作结构体struct file_operations{
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t(*read) (struct file *, char *, size_t, loff_t*);
ssize_t(*write) (struct file *, const char *, size_t, loff_t*);
int(*readdir) (struct file *, void *, filldir_t);
unsigned int(*poll) (struct file *, struct poll_table_struct *);
int(*ioctl) (struct inode*, struct file *, unsigned int, unsigned long);
int(*mmap) (struct file *, struct vm_area_struct *);
int(*open) (struct inode*, struct file *);
int(*flush) (struct file *);
int(*release) (struct inode*, struct file *);
int(*fsync) (struct file *, struct dentry*, intdatasync);
int(*fasync) (int, struct file *, int);
int(*lock) (struct file *, int, struct file_lock*);
ssize_t(*readv) (struct file *, const struct iovec*, unsigned long, loff_t*);
ssize_t(*writev) (struct file *, const struct iovec*, unsigned long, loff_t*);
ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t*, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
};
设备初始化设备初始化static int __init my_init(void){
//硬件初始化
AT91F_PIOB_Enable(LED);
AT91F_PIOB_OutputEnable(LED);
//字符设备注册
Led_Major = register_chrdev(0, DEVICE_NAME, &my_fops);
if (Led_Major < 0){
printk(DEVICE_NAME "can't get major number\n");
return Led_Major;
}
// 创建设备文件
#ifdef CONFIG_DEVFS_FS
Devfs_Led_Dir = devfs_mk_dir(NULL, "led", NULL);
Devfs_Led_Raw = devfs_register(Devfs_Led_Dir, "0",
DEVFS_FL_DEFAULT, Led_Major, 1, S_IFCHR|S_IRUSR|S_IWUSR,&my_fops, NULL);
#endif
}设备注销设备注销static void __exit my_exit(void)
{
//删除设备文件
#ifdef CONFIG_DEVFS_FS
devfs_unregister(Devfs_Led_Raw);
devfs_unregister(Devfs_Led_Dir);
#endif
//注销设备
unregister_chrdev(Led_Major, DEVICE_NAME);
}module_init(my_init); //向Linux系统记录设备初始化的函数名称
module_exit(my_exit); //向Linux系统记录设备退出的函数名称
驱动程序编译驱动程序编译Makefile文件内容OBJ=io_led.o
SOURCE=io_led.c
CC=arm-linux-gcc
COMP=-Wall -O2 -DMODULE -D_KERNEL_ -I /home/armlinux/linux-2.4.19-rmk7/include –c
$(OBJ):$(SOURCE)
$(CC) $(COMP) $(SOURCE)
clean:
rm $(OBJ)运行make 命令,编译通过后当前
目录
工贸企业有限空间作业目录特种设备作业人员作业种类与目录特种设备作业人员目录1类医疗器械目录高值医用耗材参考目录
下就生成名为io_led.o的驱动程序驱动程序加载驱动程序加载
Linux内核有2种加载驱动程序的方法:
Linux系统启动时,通过代码自身加载模块.这种方式称为静态编译入内核, 驱动程序开发完毕后一般使用这种方式.
Linux系统启动后,通过insmod等命令加载模块.这种方式称为动态加载,驱动程序开发调试过程中一般使用这种方式.模块动态加载模块动态加载驱动程序模块插入内核
查看是否载入,如果载入成功会显示你的设备名称my_led
从内核移除设备#insmod io_led.o#cat /proc/devices#rmmod io_led静态编译进内核静态编译进内核1.程序放入内核目录
\\linux-2.49-rmk7\drivers\char\
2.修改linux-2.49-rmk7\drivers\char\Makefile文件
添加 obj-$(CONFIG_9200LED) += io_led.o
3.修改linux-2.49-rmk7\drivers\char\Config.in文件
添加 tristate 'Support 9200LED device' CONFIG_9200LED
4.配置内核,编译内核.
在配置菜单的字符设备中会增加 Support 9200LED device 项目内核中配置模块内核中配置模块配置内核加载驱动程序驱动测试应用程序驱动测试应用程序int main(void)
{
int fd;
char led_on = 0x01;
fd = open("/dev/led/0", O_RDWR); //打开led设备
if(fd==-1) {
printf("can not open device\n");
exit(1);
}
write(fd, &led_on, 1); //LED开
close(fd); //关闭设备文件
return 0;
}问题回顾问题回顾设备驱动程序功能与特点?
什么是用户态,内核态.主设备号,次设备号,设备文件系统?
设备驱动程序基本结构?
设备驱动程序加载方式?null谢 谢!