Linux实现内核空间和用户空间数据的传递

清空文件内容:sudo echo " "  >/var/log/kern.log

read和write的主角是内核,也就是说从内核的角度来决定是读还是写。

1,read 从内核空间传数据到用户空间,从内核里面读,读到用户空间
copy_to_user //字符串
copy_to_user(user_dst,kernel_source,count);
put_user  //整形数据
put_user(data_source,data_dst)

2,write //写到内核,从用户空间传数据到内核空间,从用户里面传数据到内核空间
copy_from_user (kernel_dst,user_source,count)  //字符串
get_user(data_dst,data_source);//整形数据

内核代码实现:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/slab.h>
#include<asm/uaccess.h>

MODULE_LICENSE("Dual BSD/GPL");

#define CHARDEVICIVEDRIVER_MAJOR 0
#define CHARDEVICIVEDRIVER_MINOR 1

#define CHARDEVICIVEDRIVER_COUNT 2
#define CHARDEVICIVEDRIVER_NAME "chardevicedriver"

#define CHARDEVICIVEDRIVER_CLASS_NAME "chardevicedriver_class"

static u32 chardevicedriver_major = CHARDEVICIVEDRIVER_MAJOR;
static u32 chardevicedriver_minor = CHARDEVICIVEDRIVER_MINOR;

struct chardevicedriver_cdev
{
	struct device* dev_device;//设备号
	struct cdev cdev;
	
	u8 led;
	u32 var;
};

static struct chardevicedriver_cdev* chardevicedriver_cdevp = NULL;
static struct class* dev_class = NULL;//设备文件
static struct device* dev_device = NULL;//设备文件

static int chardevicedriver_open(struct inode* inode,struct file* filp)
{
	struct chardevicedriver_cdev* pcdev = NULL;
	
	pcdev = container_of(inode->i_cdev,struct chardevicedriver_cdev,cdev);
	pcdev->led = MINOR(inode->i_rdev) + 1;
	filp->private_data = pcdev; //可供其他函数使用
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	printk("__FUNCTION__ = %s,:led = %d\n",__FUNCTION__ ,pcdev->led);
	
	return 0;
}

ssize_t chardevicedriver_read(struct file* filp,char __user* buf,size_t count,loff_t* f_pos)
{
	char s_buf[100] = "kernel_space data is reading for coying to user_space\n";
	struct chardevicedriver_cdev* pcdev = filp->private_data;
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	printk("__FUNCTION__ = %s,:led = %d\n",__FUNCTION__ ,pcdev->led);
	
	//定义内核空间数据
	if(count == 4)
	{
		if(put_user(pcdev->var,(unsigned long __user*)buf))
		{
			printk("put data to user space failure\n");
			goto failure_put_user;
		}
	}
	
	if(copy_to_user(buf,s_buf,count))
	{
		printk("copy_to_user failure\n");
		goto failure_copy_to_user;
	}
	
	printk("kernel space copy data to user space success:sbuf = %s\n",s_buf);
	return count;
	
	failure_put_user:
	failure_copy_to_user:
		return -1;
}

//写到内核空间,从用户空间考到内核空间:copy_from_user()
ssize_t chardevicedriver_write(struct file* filp,const char __user* buf,size_t count,loff_t* f_pos)
{
	char sbuf[100] = {0};
	struct chardevicedriver_cdev* pcdev = filp->private_data;
	printk("__FUNCTION__ = %s,:led = %d\n",__FUNCTION__ ,pcdev->led);
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	
	//拷贝到内核空间
	if(count == 4)
	{
		if(get_user(pcdev->var,(unsigned long __user*)buf))
		{
			printk("get_user return failure\n");
			goto get_user_failure;
		}
		printk("write to kernel space data is =%d\n",pcdev->var);
	}
	
	if(!copy_from_user(sbuf,buf,count))
	{
		printk("copy from user return failure\n");
		goto copy_from_user_failure;
	}
	printk("copy from user :kernel space read data from user space is = %s\n",sbuf);
	
	return count;
	
	get_user_failure:
	copy_from_user_failure:
		return -1;
}

long unlocked_chardevicedriver_ioctl(struct file* filp,unsigned int cmd,unsigned long argc)
{

	struct chardevicedriver_cdev* pcdev = filp->private_data;
	printk("__FUNCTION__ = %s,:led = %d\n",__FUNCTION__ ,pcdev->led);
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}

static int chardevicedriver_release(struct inode* inode,struct file* filp)
{

	struct chardevicedriver_cdev* pcdev = filp->private_data;
	printk("FILE = %s,FUNCTION = %s,LINE = %d\n",__FILE__,__FUNCTION__,__LINE__);
	printk("__FUNCTION__ = %s,:led = %d\n",__FUNCTION__ ,pcdev->led);
	return 0;
}


static struct file_operations chardevicedriver_fops = {
		.owner = THIS_MODULE,
		.open = chardevicedriver_open,
		.write = chardevicedriver_write,
		.read = chardevicedriver_read,
		//.ioctl = chardevicedriver_ioctl,
	.unlocked_ioctl = unlocked_chardevicedriver_ioctl,
		.release = chardevicedriver_release,
};

//添加cdev并且创建一个设备文件
static int chardevicedriver_cdev_add(struct chardevicedriver_cdev* pcdev,int index)
{
	int ret = -1;
	dev_t dev = 0;
	printk("chardevicedriver+cdev_add enter success\n");
	
	dev = MKDEV(chardevicedriver_major,chardevicedriver_minor+index);
	cdev_init(&(pcdev->cdev),&chardevicedriver_fops);
	ret = cdev_add(&(pcdev->cdev),dev,CHARDEVICIVEDRIVER_COUNT);
	if(ret <0)
	{
		printk("cdev_add add dev to cdev failure\n");
		return ret;
	}
	printk("__FUNCTION = %s,dev add to c_dev success\n ",__FUNCTION__);
	
	//create device
	pcdev->dev_device = device_create(dev_class,NULL,dev,NULL,"chardevicedriver%d",MINOR(dev));
	if(IS_ERR(pcdev->dev_device))
	{
		printk("chardevicedriver:device_create failure\n");
		ret = PTR_ERR(pcdev->dev_device);
		return ret;
	}
	printk("chardevicedriver:class_device_craete success:/dev/chardevicedriver%d\n",MINOR(dev));
	
	return 0;
}

//static struct cdev chardevicedriver_cdev;

static int __init chardevicedriver_init(void)
{
	int ret = -1;
	dev_t dev = 0; //设备号
	int i = 0;
	int j =0;
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	if(chardevicedriver_major)
	{
		dev = MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR);
		ret = register_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT,CHARDEVICIVEDRIVER_NAME);
		if(ret >0)
		{
			printk("register_chrdev_regin can't getr char device : major = %d,name = %s\n",\
			CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
			goto failure_register_chrdev;
		}
	}
	else
	{
		alloc_chrdev_region(&dev,chardevicedriver_minor,CHARDEVICIVEDRIVER_COUNT,CHARDEVICIVEDRIVER_NAME);
		chardevicedriver_major = MAJOR(dev);
		printk("chardevicedriver:chardevicedriver_major = %d,chardevicedriver_minor = %d\n",chardevicedriver_major,chardevicedriver_minor);
	}
	printk("register_chrdev_regin  : major = %d,name = %s\n",\
		CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_NAME);
		
	//注册cdev
	chardevicedriver_cdevp = kmalloc(sizeof(struct chardevicedriver_cdev)*CHARDEVICIVEDRIVER_COUNT,GFP_KERNEL);
	if(IS_ERR(chardevicedriver_cdevp))
	{
		printk("chardevicedriver_cdevp:kmalloc space failure\n");
		ret = PTR_ERR(chardevicedriver_cdevp);
		goto failure_alloc_cdev;
	}
	memset(chardevicedriver_cdevp,0,sizeof(struct chardevicedriver_cdev)*(CHARDEVICIVEDRIVER_COUNT));
	
	//create device for create device file
	dev_class = class_create(THIS_MODULE,CHARDEVICIVEDRIVER_CLASS_NAME);
	if(IS_ERR(dev_class))
	{
		printk("__FUNCTION__:%s,device create failure\n",__FUNCTION__);
		ret = PTR_ERR(dev_device);
		goto failure_device_create;
	}
	printk("__FUNCTION__: device_create success:deice_name = %s\n",CHARDEVICIVEDRIVER_CLASS_NAME);
	
	for(i = 0; i<2; i++)
	{
		ret = chardevicedriver_cdev_add(&(chardevicedriver_cdevp[i]),i);
		if(ret<0)
		{
		printk("chardevicedriver_cdev_add return failure\n");
			goto failure_add_cdev;
		}
		printk("chardevicedriver_cdev_add call success:\n");
	}
	
	return ret;
	
	failure_add_cdev:
		for(j = i;j>0;j--)
		{
			device_destroy(dev_class,MKDEV(chardevicedriver_major,chardevicedriver_minor+j));
			cdev_del(&(chardevicedriver_cdevp[j].cdev));
		}
		class_destroy(dev_class);
	failure_device_create:
		kfree(chardevicedriver_cdevp);
	failure_alloc_cdev:
		unregister_chrdev_region(dev,CHARDEVICIVEDRIVER_COUNT);
	failure_register_chrdev:
		return ret;
}

static void __exit chardevicedriver_exit(void)
{

	
	int i ;
	//delete cdev
	for(i = 0;i < CHARDEVICIVEDRIVER_COUNT;i++)
	{
		device_destroy(dev_class,MKDEV(chardevicedriver_major,chardevicedriver_minor+i));
		cdev_del(&(chardevicedriver_cdevp[i].cdev));
	}
	printk("function = %s,line = %d\n",__FUNCTION__,__LINE__);
	
	//destroy device class
	class_destroy(dev_class);
	kfree(chardevicedriver_cdevp);
	chardevicedriver_cdevp = NULL;
	unregister_chrdev_region(MKDEV(CHARDEVICIVEDRIVER_MAJOR,CHARDEVICIVEDRIVER_MINOR),CHARDEVICIVEDRIVER_COUNT);
}

module_init(chardevicedriver_init);
module_exit(chardevicedriver_exit);

MODULE_AUTHOR("tangtang");
MODULE_VERSION("0.0.1");

 清空打印日志:sudo echo > /var/log/kern.log,下面我们来看看我们安装和调用驱动的打印吧:

 

我们来看看应用程序怎么写的:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/ioctl.h>

int fd;
char ch;
char rbuf[100] = {0};
char wbuf[100] = "this string in user space for writing to kernel!";
unsigned long var;

int main(int argc,char* argv[])
{
	fd = open("/dev/chardevicedriver1",O_RDWR);
	if(fd < 0)
	{		 
		printf(" open char device driver failure\n");
		fd = open("/dev/chardevicedriver",O_RDWR);
		if(fd < 0)
		{
			printf(" open char device driver failure\n");
		}
	}
	printf("open char device driver /dev/chardevicedriver1 success\n");
	
	while(1)
	{
		printf("char device driver/dev/chardevicedriver1 starting\n");
		printf("1,press '1' to read string device\n");
		printf("2,press '2' to read int device\n");
		printf("3,press '3' to write string device\n");
		printf("4,press '4' to write int device\n");
		printf("5,press '5' to octl device\n");
		printf("q,press 'q' to oprate device\n");
		
		ch = getchar();
		getchar();
		if(ch == 'q')
		{
			break;
		}
		switch(ch)
		{
			case '1':
				read(fd,rbuf,100);
				printf("read data from kernel rbuf = %s\n",rbuf);
				break;
			case '2':
				read(fd,&var,4);
				printf("read int dat from kernel var = %ld\n",var);
				break;
			case '3':
				write(fd,wbuf,100);
				printf("write buf to kernel space wbuf = %s\n");
				break;
			case '4':
				 var = 0x77177;
				write(fd,&var,4);
				printf("write integer to kernel space var = %ld\n",var);
				break;
			case '5':
				ioctl(fd,0,0);
				break;
		
			default:
				break;
		}
		sleep(1);
	}
	close(fd);
	return 0;
}

看到驱动里面的打印我们知道驱动函数已经被调到了,这里用的最简单的打印调式方法。也是应用程序和驱动程序的一种交互,

 

 

 

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌上花开缓缓归以

你的鼓励将是我创作的最大动力,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值