一、对应框图
二、用户空间--》内核空间(写)
#include <linux/uaccess.h>
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
函数功能:将用户空间的数据,拷贝到内核空间
参数:
to:内核空间首地址
from:用户空间首地址
n:拷贝大小
返回值: 成功返回0,失败返回未拷贝的字节数
三、内核空间--》用户空间(读)
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
函数功能:将内核空间的数据,拷贝到用户空间
参数:
to:用户空间首地址
from:内核空间首地址
n:拷贝大小
返回值: 成功返回0,失败返回未拷贝的字节数
四、练习代码
驱动代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #define CNAME "myled" unsigned int major = 0; char kbuf[128] = {}; int myled_open(struct inode *inode, struct file *file) { printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); return 0; } ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff) { int ret; printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); //如果用户空间想读的大小256个字节,大于内核空间的大小128个字节,需要更正用户空间读的大小 if(size > sizeof(kbuf)) size = sizeof(kbuf); ret = copy_to_user(ubuf,kbuf,size); //将内核空间的数据,写入到用户空间 if(ret){ printk("copy to user is error\n"); return -EIO; } return size; } ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff) { int ret; printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); //如果用户空间想写的大小256个字节,大于内核空间的大小128个字节,需要更正用户空间写的大小 if(size > sizeof(kbuf)) size = sizeof(kbuf); ret = copy_from_user(kbuf,ubuf,size); //将用户空间的数据,写入到内核空间 if(ret){ printk("copy from user is error\n"); return -EIO; } printk("kernel kbuf=%s\n",kbuf); return size; } int myled_close(struct inode *inode, struct file *file) { printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); return 0; } //操作方法结构体 const struct file_operations fops = { .open = myled_open, .read = myled_read, .write = myled_write, .release = myled_close, }; //入口函数 static int __init demo_init(void) { //注册字符设备驱动 major = register_chrdev(0,CNAME,&fops); if(major < 0){ printk("register chrdev is error\n"); return -EIO; } printk("major = %d\n",major); return 0; //函数的返回值 } //出口函数 static void __exit demo_exit(void) { //注销字符设备驱动 unregister_chrdev(major,CNAME); } module_init(demo_init); //指定入口地址 module_exit(demo_exit); //指定出口地址 MODULE_LICENSE("GPL"); //许可证,遵循GPL协议
应用代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int main(int argc,const char * argv[]) { int fd = -1; char buf[128] = "hello DC24031"; fd = open("/dev/myled",O_RDWR); //打开 if(fd == -1){ perror("open is error\n"); exit(1); } write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间 memset(buf,0,sizeof(buf)); //buf清零 read(fd,buf,sizeof(buf)); //将内核空间的数据,读到用户空间 printf("user buf = %s\n",buf); close(fd); return 0; }