概述:
一、
ssize_t (*read) (struct file *filp, char __user *buff, size_t count, loff_t *offp);
ssize_t (*write) (struct file *filp, const char __user *buff, size_t count, loff_t *offp);
read:拷贝数据到应用程序空间
write:从应用程序空间拷贝数据
read和write方法的buff参数为用户空间的指针
二、
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);
定义在#include <linux/uaccess.h>
copy_to_user:拷贝数据到应用程序空间
copy_from_user:从应用程序空间拷贝数据
这两个函数的作用并不限于在内核空间和用户空间之间拷贝数据,还检查用户空间的指针是否有效。如果指针无效,就不会进行拷贝;如果在拷贝过程中遇到无效地址,则仅仅复制部分数据,返回值为还需要拷贝的内存数量值。出错通常返回-EFAULT。
如果并不需要检查用户空间指针,可以调用:__copy_to_user、__copy_from_user
三、
图1 read使用参数
read和write出错返回负值,错误码定义在<linux/errno.h>中定义,如:-EINTR(系统调用被中断)、-EFAULT(无效地址)等等。
例程:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define MAX_BUF_LEN 256
static int major = 277;
static int minor = 0;
static dev_t devnum1;
static struct cdev cdev1;
static char helloBuf[MAX_BUF_LEN];
int hello_open(struct inode *pinode, struct file *pfile)
{
printk("hello_open, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
return 0;
}
int hello_release(struct inode *pinode, struct file *pfile)
{
printk("hello_release, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
return 0;
}
ssize_t hello_read(struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
int copySize;
if (size > MAX_BUF_LEN)
{
copySize = MAX_BUF_LEN;
}
else
{
copySize = size;
}
memcpy(helloBuf, "hello", 5);
if(copy_to_user(buf, helloBuf, copySize))
{
return -EFAULT;
}
return copySize;
}
ssize_t hello_write(struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
int copySize;
if(size > MAX_BUF_LEN)
{
copySize = MAX_BUF_LEN;
}
else
{
copySize = size;
}
memset(helloBuf, 0, MAX_BUF_LEN);
if(copy_from_user(helloBuf, buf, copySize))
{
return -EFAULT;
}
printk("%s\n",helloBuf);
return copySize;
}
static struct file_operations hello_ops = {
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
};
static int hello_init(void)
{
printk("hello_init\n");
devnum1 = MKDEV(major,minor);
printk("major:%d, minor:%d\n", MAJOR(devnum1), MINOR(devnum1));
if (register_chrdev_region(devnum1, 1, "hello1"))//分配设备号
{
printk("register_chrdev_region failed\n");
return -1;
}
cdev_init(&cdev1, &hello_ops);//初始化cdev,绑定fops
if (cdev_add(&cdev1, devnum1, 1) < 0)//添加设备到内核
{
printk("cdev_add failed\n");
unregister_chrdev_region(devnum1, 1);
return -1;
}
return 0;
}
static void hello_exit(void)
{
printk("hello_exit\n");
cdev_del(&cdev1);
unregister_chrdev_region(devnum1, 1);
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);
mknod /dev/hello0 c 277 0
#include <stdio.h>
#include <stdlib.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 = open("/dev/hello0", O_RDWR, 666);
if (fd < 0)
{
perror("open faied");
return -1;
}
printf("open successed: %d\n", fd);
char readBuf[256] = {0};
read(fd, readBuf, sizeof(readBuf));
printf("buf:%s\n", readBuf);
char writeBuf[] = "halo";
write(fd, writeBuf, strlen(writeBuf));
sleep(2);
close(fd);
return 0;
}