运用应用程序调用自己编写的字符设备驱动
-
将字符设备驱动程序make,编译一下
-
导入模块并查看模块
sudo insmod memdev.ko
sudo lsmod
-
创建设备文件memdev0并查看,在/dev目录下
-
cd /dev
-
sudo mknod 设备文件名 c(字符设备驱动程序) 主设备号 次设备号
-
查看主设备号
cat /proc/devices
-
创建设备文件
sudo mknod memdev0 c 241 0
-
编译mem_app.c文件,生成可执行文件a.out
gcc mem_app.c
-
用超级用户权限运行可执行文件
sudo ./a.out
运行成功!!!!下面是源码资源!!!!!!
===================================================================================
字符设备驱动程序源码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define BASEMINOR 0
#define COUNT 3
#define NAME "memdev"
#define MEMDEV_SIZE 4096
dev_t devno;
struct memdev{
char *data;
unsigned long size;
};
struct cdev *cdevp = NULL;
struct memdev *memdevp = NULL;
int mem_open (struct inode *inode,struct file *filp){
//printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
struct memdev *mdev = NULL;
int num = MINOR(inode->i_rdev);
if(num >= COUNT){
return -ENODEV;
}
mdev = &memdevp[num];
filp->private_data = mdev;
return 0;
}
int mem_release (struct inode *inode,struct file *filp){
printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
return 0;
}
static ssize_t mem_read (struct file *filp,char __user *buf,size_t size,loff_t *ppos){
//printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
unsigned long p = *ppos;
unsigned int count = size;
int ret =0;
struct memdev *mdev = filp->private_data;
if(p >= MEMDEV_SIZE){
return 0;
}
if(count > MEMDEV_SIZE - p){
count = MEMDEV_SIZE - p;
}
if(copy_to_user(buf,(void*)(mdev->data+p),count)){
return -EFAULT;
}else{
*ppos += count; /
ret = count;
}
return ret;
}
static ssize_t mem_write (struct file *filp,const char __user *buf,size_t size,loff_t *ppos){
//printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
unsigned long p = *ppos;
unsigned int count = size;
int ret =0;
struct memdev *mdev = filp->private_data;
if(p >= MEMDEV_SIZE){
return 0;
}
if(count > MEMDEV_SIZE - p){
count = MEMDEV_SIZE - p;
}
if(copy_from_user(mdev->data + p,buf,count)){
return -EFAULT;
}else{
*ppos += count; /
ret = count;
}
return ret;
}
loff_t mem_llseek (struct file *filp,loff_t offset,int whence){
//printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
loff_t newpos;
switch(whence){
case 0:
newpos = offset;
break;
case 1:
newpos = filp->f_pos + offset;
break;
case 2:
newpos = MEMDEV_SIZE - 1 + offset;
break;
default:
return -EINVAL;
}
if((newpos < 0) || (newpos > MEMDEV_SIZE)){
return -EINVAL;
}
filp->f_pos = newpos;
return newpos;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.open = mem_open,
.release = mem_release,
.llseek = mem_llseek,
.write = mem_write,
.read = mem_read
};
static int __init mem_init(void)
{
int ret;
int i;
/***********************************************************************/
ret = alloc_chrdev_region(&devno,BASEMINOR,COUNT,NAME);
if(ret < 0){
printk(KERN_ERR "alloc_chrdev_region failed...\n");
goto err1;
}
//设备号申请成功打印出来
printk(KERN_INFO "major = %d \n",MAJOR(devno));
/***********************************************************************/
cdevp = cdev_alloc();
if(NULL == cdevp){
printk(KERN_ERR "cdev_alloc failed...\n");
ret = -ENOMEM;
goto err2;
//cdev结构体申请失败需要将上一步申请到的设备号资源释放。
}
/***********************************************************************/
cdev_init(cdevp,&fops);
/***********************************************************************/
ret = cdev_add(cdevp,devno,COUNT);
if(ret < 0){
printk(KERN_ERR "cdev_add failed...\n");
goto err2;
}
/***********************************************************************/
//为memdev设备结构体分配内存
memdevp = kmalloc(COUNT * sizeof(struct memdev),GFP_KERNEL);
if(NULL == memdevp){
printk(KERN_ERR "memdevp kmalloc failed...\n");
ret = -ENOMEM;
goto err2;
}
memset(memdevp,0,sizeof(struct memdev));
//上一步申请的是一片空间,这一片空间里是COUNT个设备的总空间,需要为每一个设备分配空间
for(i = 0;i<COUNT;i++){
memdevp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
memdevp[i].size = MEMDEV_SIZE;
memset(memdevp[i].data,0,MEMDEV_SIZE);
}
/***********************************************************************/
printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
return 0;
err2:
unregister_chrdev_region(devno,COUNT); //释放申请到的设备号资源
err1:
return ret;
}
static void __exit mem_exit(void)
{
cdev_del(cdevp);
unregister_chrdev_region(devno,COUNT); //释放申请到的设备号资源
printk(KERN_INFO "---%s---%s---%d---\n",__FILE__,__func__,__LINE__);
}
module_init(mem_init);
module_exit(mem_exit);
MODULE_LICENSE("GPL");
Makefile文件源码
KERNDIR = /lib/modules/4.15.0-107-generic/build
PWD = $(shell pwd)
obj-m:=memdev.o
all:
make -C $(KERNDIR) M=$(PWD) modules
clean:
make -C $(KERNDIR) M=$(PWD) clean
应用程序源码
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp0 = NULL;
char buf[4096];
strcpy(buf,"mem is a chrdev!!!!");
printf("buf1: %s",buf);
/****************************************************************
*将buf字符串写入memdev0设备文件中,然后将buf字符串更新,
*最后从设备文件中读取,写入和读取的内容一致表示成功写入!!!
****************************************************************/
fp0 = fopen("/dev/memdev0","r+");
if(fp0 < 0){
printf("open memdev0 failed!!!\n");
return -1;
}
fwrite(buf,sizeof(buf),1,fp0);
fseek(fp0,0,SEEK_SET);
strcpy(buf,"buf is NULL!!!!");
printf("buf2: %s",buf);
fread(buf,sizeof(buf),1,fp0);
printf("buf3: %s",buf);
return 0;
}