在之前的实验中我们在没有开发板的情况下,实现了在Ubuntu虚拟机中进行基本驱动开发。具体可以参考《没有开发板如何在Ubuntu中体验Linux驱动开发》。在此基础上,我们就可以来进行字符设备框架的验证实验。
第一步,驱动程序编写
在test文件夹下创建app子目录,用于存放测试 app,创建驱动程序文件及Makefile。编写字符设备驱动,实现字符设备的注册,设备节点的创建以及文件操作集等。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
static int chrdev_open(struct inode *inode, struct file *file)
{
printk("char device open success!!! \n");
return 0;
}
static ssize_t chrdev_read(struct file *file,char __user *buf, size_t size, loff_t *off)
{
printk("char device read success!!! \n");
return 0;
}
static ssize_t chrdev_write(struct file *file,const char __user *buf,size_t size,loff_t *off)
{
printk("char device write success!!! \n");
return 0;
}
static int chrdev_release(struct inode *inode, struct file *file)
{
printk("char device release success!!! \n");
return 0;
}
static dev_t dev_num; //定义 dev_t 类型变量 dev_num 来表示设备号
static struct cdev cdev_test; //定义名为 cdev_test 的字符设备
static struct file_operations cdev_fops_test = {
.owner = THIS_MODULE,
.open = chrdev_open,
.read = chrdev_read,
.write = chrdev_write,
.release = chrdev_release,
}; //填充file_operations
static struct class *class_test;
static int __init chrdev_fops_init(void) //驱动入口函数
{
int ret;
int major,minor;//定义主设备号和次设备号
ret = alloc_chrdev_region(&dev_num,0,1,"device_test");
if (ret < 0){
printk("alloc_chrdev_region is error \n");
}
printk("alloc_chrdev_region success!!! \n");
major = MAJOR(dev_num);
minor = MINOR(dev_num);
printk("major is %d\n minor is %d \n",major,minor);
cdev_init(&cdev_test,&cdev_fops_test); //初始化字符设备
cdev_test.owner = THIS_MODULE;
ret = cdev_add(&cdev_test,dev_num,1); //进行字符设备的添加
if (ret < 0){
printk("cdev_add is error \n");
}
printk("cdev_add success!!! \n");
class_test = class_create(THIS_MODULE,"class_test");
device_create(class_test,NULL,dev_num,NULL,"cdev_test");//进行设备的创建,设备名称为 cdev_test
return 0;
}
static void __exit chrdev_fops_exit(void) //驱动出口函数
{
device_destroy(class_test,dev_num);
class_destroy(class_test);
cdev_del(&cdev_test); //删除添加的字符设备 cdev_test
unregister_chrdev_region(dev_num,1); //释放字符设备所申请的设备号
printk("module exit \n");
}
module_init(chrdev_fops_init);//注册入口函数
module_exit(chrdev_fops_exit);//注册出口函数
MODULE_LICENSE("GPL v2");//同意 GPL 开源协议
MODULE_AUTHOR("tester");//作者信息
修改Makefile中的文件名,obj-m += cdev_test.o,其余不变。编译通过结果如下
第二步,编写测试app
Linux下一切皆文件,在app目录下创建app.c文件,此为应用层测试程序,实现对文件操作集函数功能,通过调用文件操作函数实现对字符设备的操作。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
int fd; //定义文件描述符
char buf[32];
fd=open(argv[1],O_RDWR,0666);//调用 open 函数打开文件,权限为可读可写
if(fd<0){
printf("open is error\n");
return -1;
}
printf("open is ok\n");
if(!strcmp(argv[2], "read")){
read(fd,buf,32);
}
else if(!strcmp(argv[2], "write")){
write(fd,"hello\n",6);
}
close(fd); //调用 close 函数,取消文件的映射
return 0;
}
在app目录下使用 gcc -o app app.c 命令编译生成名为app的可执行文件。
第三步,驱动加载测试
加载驱动模块,可以看出成功打印出系统分配的主设备号及次设备号。
运行测试app,并传入read及write进行测试,结果如下
总结:可以看出,在Ubuntu虚拟机上成功完成了字符设备的基本框架实验,这里在文件操作集中只是简单打印了一些提示信息,后续可以配合硬件加入不同的操作。