写一个简单的字符设备驱动程序,要求:
定义一个全局结构指针,初始值为NULL,该数据结构中包含一个大小为1024的buffer和一个count整形变量
在open中对该全局结构进行NULL判断,为NULL则为其分配内存,并将buffer初始化为0,将count自加
在release中如果count为0,则释放,否则进行count自减
在read里面对该buffer进行读取
在write里面对该buffer进行赋值(任意赋值即可)
写测试程序进行测试
设备驱动基础知识
https://www.cnblogs.com/microxiami/p/11254081.html
字符设备驱动reference
https://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html
https://www.cnblogs.com/chen-farsight/p/6155518.html#unit3.1.5
这两篇比较详细
自己根据题目修改和简化后的实现
demo1.c文件
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/kdev_t.h>
#include<linux/types.h>
#include<linux/uaccess.h>
#include<linux/string.h>
#include <linux/slab.h>
unsigned int major=0; //主设备号
unsigned int minor=0; //次设备号
dev_t dev_no; //设备号
int ret; //返回结果
struct cdev chrdev; //struct cdev在<linux/cdev.h>中定义,描述一个字符设备
typedef struct mydata
{
char buffer[1024];
int count;
} d, *D; //d=struct mydata D=struct mydata*
D my = NULL; //NULL
int my_open(struct inode *i,struct file *f){ //open操作
if (my==NULL) //结构体指针为空时
{
my=kmalloc( sizeof(struct mydata),GFP_KERNEL); //分配内存
my->count++; //count自增
}
printk("cdev open\n");
return 0;
}
int my_release(struct inode *i,struct file *f){//release操作
if(my->count==0)
printk("cdev release\n");
else{
my->count--;
}
return 0;
}
static ssize_t my_write(struct file *f,const char __user *u,size_t l,loff_t *o){ //write操作
copy_from_user(my->buffer,u,l); //对buffer赋值
printk(KERN_EMERG"write string:%s",my->buffer);
return l;
}
static ssize_t my_read(struct file *f,char __user *u,size_t l,loff_t *o){ //read操作
copy_to_user(u,my->buffer,strlen(my->buffer)); //复制到用户态
printk(KERN_EMERG"read string:%s",my->buffer); //读取buffer
return l;
}
struct file_operations fops={ //定义文件操作集
.owner=THIS_MODULE,
.open=my_open,
.release=my_release,
.write=my_write,
.read=my_read
};
static int my_init(void){//驱动的初始化
dev_no=MKDEV(major,minor);
if(dev_no>0){
ret=register_chrdev_region(dev_no,1,"demo1");//静态注册设备号
}else{
ret=alloc_chrdev_region(&dev_no,0,1,"demo1");//动态申请设备号
}
if(ret<0){
return ret;
}
cdev_init(&chrdev,&fops);
chrdev.owner=THIS_MODULE;
cdev_add(&chrdev,dev_no,1);
return 0;
}
static void my_exit(void){ //驱动的退出
unregister_chrdev_region(dev_no,1);
cdev_del(&chrdev);
}
module_init(my_init);//调用系统函数来设置驱动初始化函数
module_exit(my_exit);//设置驱动结束的函数
MODULE_AUTHOR("xxxxx-zhangsan"); /*作者名*/
MODULE_DESCRIPTION("this ostest demo1");
MODULE_LICENSE("GPL"); /*宏声明许可证*/
Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := demo1.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -fr .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif
编译
加载驱动模块查看设备驱动号
250为设备驱动号
lsmod查看是否加载
添加设备文件
root@ubuntu:/home/linux/Lecture/lab# mknod /dev/demo1 c 250 0
root@ubuntu:/home/linux/Lecture/lab# ll /dev/demo1
crw-r--r-- 1 root root 250, 0 4月 24 22:45 /dev/demo1
删除设备文件
rm -f /dev/demo1
测试程序 test.c
#include<stdio.h>
#include <unistd.h>
#include<fcntl.h>
int main(void)
{
int fd;
char *buf="Grace under pressure!";
char buf2[20];
fd=open("/dev/demo1",O_RDWR);
if(fd<0){
printf("fd<0\n");
}else{
printf("fd:%d\n",fd);
}
write(fd,buf,22);
read(fd,buf2,22);
printf("res:%s",buf2);
close(fd);
}