zl程序教程

您现在的位置是:首页 >  系统

当前栏目

linux驱动开发--copy_to_user 、copy_from_user函数实现内核空间数据与用户空间数据的相互访问

Linux驱动内核开发 实现 函数 -- 用户
2023-09-14 08:57:16 时间
设备读操作

如果该操作为空,将使得read系统调用返回负EINVAL失败,正常返回实际读取的字节数

ssize_t (*read)(struct file *filp, char __user *buf, size_t  count, lofft *f_pos);
filp:待操作的设备文件file结构体指针
buf:待写入所读取数据的用户空间缓冲区指针
count:待读取数据字节数
f_pos:待读取数据文件位置,读取完成后根据实际读取字节数重新定位
返回:成功实际读取的字节数,失败返回负值


设备写操作
如果该操作为空,将使得write系统调用返回负EINVAL失败,正常返回实际写入的字节数
ssize_t (*write)(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

filp:待操作的设备文件file结构体指针
buf:待写入所读取数据的用户空间缓冲区指针
count:待读取数据字节数
f_pos:待读取数据文件位置,写入完成后根据实际写入字节数重新定位
返回:成功实际写入的字节数,失败返回负值


内核为驱动程序提供在内核空间和用户空间传递数据的方法
定义在arch/arm/include/asm/uaccess.h中
用户空间-- 内核空间
copy_from_user函数
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
to:目标地址(内核空间)
from:源地址(用户空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
get_user宏
int get_user(data, ptr);
data:可以是字节、半字、字、双字类型的内核变量
ptr:用户空间内存指针
返回:成功返回0,失败返回非0

-----------------------------------------------------------------------------------------------

内核空间-- 用户空间
copy_to_user函数
unsigned long copy_to_user(void *to, const void *from, unsigned long n)
to:目标地址(用户空间)
from:源地址(内核空间)
n:将要拷贝数据的字节数
返回:成功返回0,失败返回没有拷贝成功的数据字节数
put_user宏:
int put_user(data, prt)
data:可以是字节、半字、字、双字类型的内核变量
ptr:用户空间内存指针
返回:成功返回0, 失败返回非0

/**

*Copyright (c) 2013.TianYuan

*All rights reserved.

*文件名称: char_device_driver08.c

*文件标识: copy_to_user 、copy_from_user函数的使用

*当前版本:1.0

*作者:wuyq 

*取代版本:xxx

*原作者:xxx

*完成日期:2013-11-28

#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 


pcdevp = container_of(inode- i_cdev, struct cdd_cdev, cdev); printk("led = %d\n", pcdevp- led); filp- private_data = pcdevp; return 0; int cdd_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) int ret = 0; struct cdd_cdev *cdevp = filp- private_data; printk("enter cdd_read!\n"); ret = copy_to_user(buf, cdevp- kbuf, count); printk("kernel kbuf content:%s\n", cdevp- kbuf); return ret; int cdd_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) int ret = 0; struct cdd_cdev *cdevp = filp- private_data; printk("enter cdd_write!\n"); ret = copy_from_user(cdevp- kbuf, buf, count); return ret; int cdd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) printk("enter cdd_ioctl!\n"); return 0; int cdd_release(struct inode *inode, struct file *filp) printk("enter cdd_release!\n"); return 0; struct file_operations cdd_fops = { .owner = THIS_MODULE, .open = cdd_open, .read = cdd_read, .write = cdd_write, .ioctl = cdd_ioctl, .release = cdd_release, int __init cdd_init(void) int ret = 0; int i = 0; if(cdd_major){ dev = MKDEV(CDD_MAJOR, CDD_MINOR);//生成设备号 //注册设备号;1、要注册的起始设备号2、连续注册的设备号个数3、名字 ret = register_chrdev_region(dev, CDD_COUNT, "cdd_demo"); }else{ // 动态分配设备号 ret = alloc_chrdev_region( dev, cdd_minor, CDD_COUNT, "cdd_demo02"); if(ret 0){ printk("register_chrdev_region failed!\n"); goto failure_register_chrdev; //获取主设备号 cdd_major = MAJOR(dev); printk("cdd_major = %d\n", cdd_major); cdd_cdevp = kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT, GFP_KERNEL); if(IS_ERR(cdd_cdevp)){ printk("kzalloc failed!\n"); goto failure_kzalloc; /*创建设备类*/ dev_class = class_create(THIS_MODULE, "cdd_class"); if(IS_ERR(dev_class)){ printk("class_create failed!\n"); goto failure_dev_class; for(i=0; i CDD_COUNT; i++){ /*初始化cdev*/ cdev_init( (cdd_cdevp[i].cdev), cdd_fops); /*添加cdev到内核*/ cdev_add( (cdd_cdevp[i].cdev), dev+i, 1); /* “/dev/xxx” */ device_create(dev_class, NULL, dev+i, NULL, "cdd%d", i); cdd_cdevp[i].led = i; return 0; failure_dev_class: kfree(cdd_cdevp); failure_kzalloc: unregister_chrdev_region(dev, CDD_COUNT); failure_register_chrdev: return ret; void __exit cdd_exit(void) /*逆序消除*/ int i = 0; for(; i CDD_COUNT; i++){ device_destroy(dev_class, dev+i); cdev_del( (cdd_cdevp[i].cdev)); //cdev_del( ((cdd_cdevp+i)- cdev)); class_destroy(dev_class); kfree(cdd_cdevp); unregister_chrdev_region(dev, CDD_COUNT); module_init(cdd_init); module_exit(cdd_exit);

/**

*Copyright (c) 2013.TianYuan

*All rights reserved.

*文件名称: char_device_driver08_test.c

*文件标识: 测试程序:测试内核空间的copy_to_user、copy_frome_user

* 执行:先./char_device_driver08_test 再cat /dev/cdd0 cat /dev/cdd5观察两者的区别

*当前版本:1.0

*作者:wuyq 

*取代版本:xxx

*原作者:xxx

*完成日期:2013-11-28

#include stdio.h 

#include fcntl.h 

#include stdlib.h 

/*手工创建设备节点文件

mknod /dev/cdd c 248 0

int fd = 0;

char rbuf[100];

char wbuf[100] = "nihao!\n";


Linux下访问DNS服务 要访问DNS服务,就必须先知道DNS服务器的IP地址。Linux 使用/etc/resolv.conf文件来存放DNS服务器的IP地址。机器ernest-laptop上,该文件的内容如下:
练习将maven项目打成war包放在linux服务器中,进行访问 第一次使用云服务器,练习将maven项目打成war包放在linux服务器中,进行访问。 这是阿里云的投稿活动,经过自己的尝试对阿里云服务器使用更加熟悉,阿里云使用方便,对学生也十分良心~让我学到了一些服务器的知识,祝阿里云团队蒸蒸日上~