设备程序驱动框架
一、创建设备驱动文件
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>#define MAJOR_NUM 255 //主设备号
#define MIJOR_NUM 0 //次设备号
#define DEV_NAME "demo1" //模块名(在注册时使用,主要用于内部维护)//open、read、write、close的具体操作方法
static int open(struct inode * node, struct file * file)
{printk("demo open...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{printk("demo read...\n");return 0;
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("demo write...\n");return 0;
}static int close(struct inode * node, struct file * file)
{printk("demo close...\n");return 0;
}static dev_t dev_num; //设备号
static struct file_operations fops =
{.owner = THIS_MODULE, //用来维护自己模块的结构体,THIS_MODULE这个宏就代表自己本身这个模块.open = open,.read = read,.write = write,.release = close
};//对设备的操作方法//这个结构用来绑定这个设备号和对这个设备的操作方法
static struct cdev dev;static int __init demo_init(void)
{//register dev(注册设备)dev_num = MKDEV(MAJOR_NUM,MIJOR_NUM);//(MAJOR_NUM << 20) | MINOR_NUM//MKDEV是一个宏//初始化cdev这个结构体cdev_init(&dev,&fops);cdev_add(&dev,dev_num,1);register_chrdev_region(dev_num,1,DEV_NAME);//将整个模块注册到操作系统中 printk("demo_init ##################\n");return 0;
}static void __exit demo_exit(void)
{unregister_chrdev_region(dev_num,1);cdev_del(&dev);printk("demo_exit ##################\n");
}module_init(demo_init);
module_exit(demo_exit);
//module_init和module_exit是内核留给用户的接口本质是宏,用来修饰括号里的函数,module_init在注册时使用module_exit在注销时使用
module_init:在开机时(或者说是操作系统启动时)内核会遍历整个程序找到被module_init修饰的函数并执行一次
module_exit:在关机时(或者说是操作系统关机时)内核会遍历整个程序找到被module_exit修饰的函数并执行一次利用Ctags可以快速查询(跳转)到相应的头文件或者函数(自行详细了解Ctags的使用规则)
将这个代码编译并加载进内核
在开发板上电操作系统加载完之后,我们会发现在/dev下并没有demo1这个设备
这个时候我们就需要手动创建设备节点
mknod /dev/demo1 c 255 0
利用这个命令我们就能创建相对应的字符设备 ,这里的/dev/demo1就是设备节点名,c代表的就是字符设备文件,255和0是它的主设备号和次设备号
二、应用程序
想要验证内核代码能够正确运行,我们就可以在应用层编写测试代码来进行测试,在开发板挂载的目录下进行编写
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc, const char *argv[])
{int fd = open("/dev/demo1", O_RDWR);perror("open demo1");if (fd < 0) {perror("open demo1");return 1;}unsigned char buf[48] = {0};read(fd, buf, sizeof(buf));write(fd, buf, sizeof(buf));close(fd);return 0;
}
这个代码因为我们要在开发板上运行,所以我们要使用arm-linux-gcc这个编译器来进行交叉编译
编译好后运行程序,如果能打印出printk中的内容即为成功