简单字符设备驱动程序的操作步骤
2017-09-21 08:51
211 查看
一、Linux驱动程序开发步骤
1.查看原理图,数据手册等
2.找相近的驱动程序作为模板
3.实现驱动程序的初始化
4.设计所要实现的操作:open,read,write,close
5.实现中断(可以不需要)
6.用insmod命令加载驱动
二、驱动框架
驱动是无法直接识别应用程序上的应用层API:read,open,write等,需要对应驱动程序上的led_read,led_open,led_write,这些都是驱动函数。
每个系统调用,驱动程序怎样和它对应起来?
使用file_operations结构,和应用层API对接。
Linux怎么知道去调用哪个驱动程序的file_operations?
根据设备类型和主设备号,需要将注册函数将主设备号和file_operations一起注册到内核
将驱动程序加载到内核,调用驱动初始化函数,像内核注册
module_init(memdev_init);
三、驱动程序的加载和卸载
module_init(memdev_init);
module_exit(memdev_exit);
四、几种重要的数据结构
struct file
file结构代表一个打开的文件,它由内核在open时创建,并传递给该文件上进行操作的所有函数,直到最后的close函数。
file结构private_data是跨系统调用时保存状态信息非常有用的资源。
file结构的f_ops 保存了文件的当前读写位置。
struct inode
内核用inode代表一个磁盘上的文件,它和file结构不同,后者表示打开的文件描述符。对于单个文件,可能会有许多个表示打开文件的文件描述符file结构,但他们都指单个inode结构。inode的dev_t i_rdev成员包含了真正的设备编号,struct cdev *i_cdev包含了指向struct cdev结构的指针。
struct file_operations
file_operations结构保存了字符设备驱动程序的方法。它是一个在 <linux/fs.h> 中定义的 struct file_operations 结构,这是一个内核结构,不会出现在用户空间的程序中,它定义了常见文件 I/O 函数的入口。系统调用函数通过内核,最终调用对应的 struct file_operations 结构的接口函数(例如,open() 文件操作是通过调用对应文件的file_operations 结构的 open 函数接口而被实现)。当然,每个设备的驱动程序不一定要实现其中所有的函数操作,若不需要定义实现时,则只需将其设为
NULL 即可。
驱动程序的简单模板:
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");//模块开源许可声明
/* 模块加载时的初始化函数 */
// __init的意思是将代码放入特定的初始化内存区域,初始化后空间可以回收
static int __init myinit(void)
{
printk(KERN_CRIT"hello mymodule!\n");
printk(KERN_CRIT"module name :%s\n",THIS_MODULE->name);
return 0;//内核编程,有返回值的一定不要遗漏
}
module_init(myinit);//告知系统哪个是初始化函数
/* 模块清理函数 */
//__exit的意思是如果以后不卸载则不要放入系统
static void __exit myexit(void)
{
printk(KERN_CRIT"goodbye cruel world\n");
}
module_exit(myexit);//告知系统哪个是清理函数设备号和设备类的创建和销毁:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h> //设备号注册相关
#include <linux/device.h> //class和device相关
MODULE_LICENSE("GPL");
dev_t devno;//设备号
struct class *cls; //设备类
static int __init myinit(void)
{//在模块初始化时,动态申请前设备号
alloc_chrdev_region(&devno,10,1,"mydev");
cls=class_create(THIS_MODULE,"myclass");//创建类
device_create(cls,NULL,devno,NULL,"mynewdev");//在类下面创建设备
printk("major is %d, minor is %d\n",MAJOR(devno),MINOR(devno));
return 0;
}
module_init(myinit);
static void __exit myexit(void)
{//模块清理的时候,反注册设备号
device_destroy(cls,devno);//销毁设备
class_destroy(cls);//销毁类
unregister_chrdev_region(devno,1);//反注册设备号
}
module_exit(myexit);
1.查看原理图,数据手册等
2.找相近的驱动程序作为模板
3.实现驱动程序的初始化
4.设计所要实现的操作:open,read,write,close
5.实现中断(可以不需要)
6.用insmod命令加载驱动
二、驱动框架
驱动是无法直接识别应用程序上的应用层API:read,open,write等,需要对应驱动程序上的led_read,led_open,led_write,这些都是驱动函数。
每个系统调用,驱动程序怎样和它对应起来?
使用file_operations结构,和应用层API对接。
Linux怎么知道去调用哪个驱动程序的file_operations?
根据设备类型和主设备号,需要将注册函数将主设备号和file_operations一起注册到内核
将驱动程序加载到内核,调用驱动初始化函数,像内核注册
module_init(memdev_init);
三、驱动程序的加载和卸载
module_init(memdev_init);
module_exit(memdev_exit);
四、几种重要的数据结构
struct file
file结构代表一个打开的文件,它由内核在open时创建,并传递给该文件上进行操作的所有函数,直到最后的close函数。
file结构private_data是跨系统调用时保存状态信息非常有用的资源。
file结构的f_ops 保存了文件的当前读写位置。
struct inode
内核用inode代表一个磁盘上的文件,它和file结构不同,后者表示打开的文件描述符。对于单个文件,可能会有许多个表示打开文件的文件描述符file结构,但他们都指单个inode结构。inode的dev_t i_rdev成员包含了真正的设备编号,struct cdev *i_cdev包含了指向struct cdev结构的指针。
struct file_operations
file_operations结构保存了字符设备驱动程序的方法。它是一个在 <linux/fs.h> 中定义的 struct file_operations 结构,这是一个内核结构,不会出现在用户空间的程序中,它定义了常见文件 I/O 函数的入口。系统调用函数通过内核,最终调用对应的 struct file_operations 结构的接口函数(例如,open() 文件操作是通过调用对应文件的file_operations 结构的 open 函数接口而被实现)。当然,每个设备的驱动程序不一定要实现其中所有的函数操作,若不需要定义实现时,则只需将其设为
NULL 即可。
驱动程序的简单模板:
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");//模块开源许可声明
/* 模块加载时的初始化函数 */
// __init的意思是将代码放入特定的初始化内存区域,初始化后空间可以回收
static int __init myinit(void)
{
printk(KERN_CRIT"hello mymodule!\n");
printk(KERN_CRIT"module name :%s\n",THIS_MODULE->name);
return 0;//内核编程,有返回值的一定不要遗漏
}
module_init(myinit);//告知系统哪个是初始化函数
/* 模块清理函数 */
//__exit的意思是如果以后不卸载则不要放入系统
static void __exit myexit(void)
{
printk(KERN_CRIT"goodbye cruel world\n");
}
module_exit(myexit);//告知系统哪个是清理函数设备号和设备类的创建和销毁:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h> //设备号注册相关
#include <linux/device.h> //class和device相关
MODULE_LICENSE("GPL");
dev_t devno;//设备号
struct class *cls; //设备类
static int __init myinit(void)
{//在模块初始化时,动态申请前设备号
alloc_chrdev_region(&devno,10,1,"mydev");
cls=class_create(THIS_MODULE,"myclass");//创建类
device_create(cls,NULL,devno,NULL,"mynewdev");//在类下面创建设备
printk("major is %d, minor is %d\n",MAJOR(devno),MINOR(devno));
return 0;
}
module_init(myinit);
static void __exit myexit(void)
{//模块清理的时候,反注册设备号
device_destroy(cls,devno);//销毁设备
class_destroy(cls);//销毁类
unregister_chrdev_region(devno,1);//反注册设备号
}
module_exit(myexit);
相关文章推荐
- Linux设备驱动程序第三版学习(6)- 高级字符驱动程序操作(续1)- 进程休眠 .
- 实验5.1.1简单字符设备驱动程序设计与验证
- 【转】linux设备驱动程序之简单字符设备驱动
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]
- 简单字符设备驱动程序(二)
- Linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek]
- Linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek]
- Linux字符设备驱动程序的一个简单示例
- Linux设备驱动程序——简单字符设备驱动程序
- Linux设备驱动程序学习(4) -高级字符驱动程序操作[(1)ioctl and llseek]
- 字符设备驱动0:一个简单但完整的字符设备驱动程序
- Linux设备驱动程序学习(5) -高级字符驱动程序操作[(2)阻塞型I/O和休眠]
- ldd3学习之十二(4):高级字符驱动程序操作--llseek、设备文件的访问控制
- linux字符设备驱动程序相关的数据结构及操作
- Linux设备驱动程序第三版学习(7)- 高级字符驱动程序操作(续2)- poll/select
- 简单字符设备驱动程序分析
- linux设备驱动程序之简单字符设备驱动
- linux设备驱动程序之简单字符设备驱动
- Linux设备驱动程序学习(6) -高级字符驱动程序操作[(3)设备文件的访问控制]
- linux设备驱动程序之简单字符设备驱动