linux驱动程序开发-第五节:用户空间与内核空间数据交换

资料链接:



============================================================================================
1.  驱动设计


#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

static struct cdev gec6818_led_cdev;		//字符设备结构体

static dev_t	led_num=0;					//设备号



static int  gec6818_led_open (struct inode * inode, struct file *file)
{
	printk("gec6818_led_open \n");
	return 0;
}

static int  gec6818_led_release (struct inode * inode, struct file *file)
{
	printk("gec6818_led_release \n");
	return 0;
}

static ssize_t gec6818_led_write (struct file * file, const char __user * buf, size_t len, loff_t * off)
{
	int rt;
	
	char kbuf[64]={0};
	
	//判断当前len是否合法
	if(len > sizeof kbuf)
		return -EINVAL;		//返回参数无效错误码
		
	//从用户空间拷贝数据
	
	rt = copy_from_user(kbuf,buf,len);
	
	//获取成功复制的字节数
	
	len = len - rt;
	
	
	printk("gec6818_led_write,kbuf[%s],len[%d]\n",kbuf,len);
	
	return len;
}

static ssize_t gec6818_led_read (struct file *file, char __user *buf, size_t len, loff_t * offs)
{
	
	int rt;
	
	char kbuf[5]={'1','2','3','4','\0'};
	
	//判断当前len是否合法
	if(len > sizeof kbuf)
		return -EINVAL;		//返回参数无效错误码
		
	//从内核空间拷贝到用户空间
	
	rt = copy_to_user(buf,kbuf,len);
	
	//获取成功复制的字节数
	
	len = len - rt;
	
	
	printk("gec6818_led_read,__user buf[%s],len[%d]\n",buf,len);
	
	return len;
	
	
}

static const struct file_operations gec6818_led_fops = {
 	.owner 		= THIS_MODULE,
	.write 		= gec6818_led_write,
	.open 		= gec6818_led_open,
	.release 	= gec6818_led_release,
	.read 		= gec6818_led_read,
};

//入口函数
static int __init gec6818_led_init(void)
{
	
	int rt=0;

	//动态申请设备号
	rt=alloc_chrdev_region(&led_num,0,1,"gec6818_leds");
	
	if(rt < 0)
	{
		printk("alloc_chrdev_region fail\n");
		
		return rt;
		
	}
	
	printk("led_major = %d\n",MAJOR(led_num));
	printk("led_minor = %d\n",MINOR(led_num));	
	
	
	//字符设备初始化
	cdev_init(&gec6818_led_cdev,&gec6818_led_fops);
	
	//字符设备添加到内核
	rt = cdev_add(&gec6818_led_cdev,led_num,1);
	
	if(rt < 0)
	{
		printk("cdev_add fail\n");
		goto fail_cdev_add;
		
	}
	
	printk("gec6818 led init\n");
	return 0;
	
	
fail_cdev_add:
	unregister_chrdev_region(led_num,1);
	
	return rt;

}


//出口函数
static void __exit gec6818_led_exit(void)
{
	cdev_del(&gec6818_led_cdev);
	
	unregister_chrdev_region(led_num,1);
	
	printk("gec6818 led exit\n");
}

//驱动程序的入口:insmod led_drv.ko调用module_init,module_init又会去调用gec6818_led_init。
module_init(gec6818_led_init);

//驱动程序的出口:rmsmod led_drv调用module_exit,module_exit又会去调用gec6818_led_exit。
module_exit(gec6818_led_exit)


//模块描述
MODULE_AUTHOR("[email protected]");			//作者信息
MODULE_DESCRIPTION("gec6818 led driver");		//模块功能说明
MODULE_LICENSE("GPL");							//许可证:驱动遵循GPL协议

========================================================================================================
2. 用户程序设计


#include <stdio.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=-1;
	
	int len;
	
	char buf[64]="hello teacher.wen";
	
	//打开gec6818_leds设备
	fd = open("/dev/gec6818_leds",O_RDWR);
	
	if(fd < 0)
	{
		perror("open /dev/gec6818_leds:");
		
		return fd;
		
	}
	
	sleep(2);
	
	write(fd,buf,strlen(buf));
	
	sleep(2);	
	
	len = read(fd,buf,5);
	
	if(len > 0)
		printf("read buf:%s\n len=%d\n",buf,len);
	
	
	sleep(2);		
	
	close(fd);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wghkemo123/article/details/86175506