内核接口
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read) (struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t (*write) (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
filp:待操作的设备文件file结构体指针;
buf:待写入所读取数据的用户空间缓冲区指针;
count:待读取数据字节数;
f_pos:待读取数据文件位置,读取完成后根据实际读取自救书重新定位;
__usr:是一个空的宏,主要用来显示的告诉程序员它修饰的指针变量存放的是用户空间地址。
struct file {
// ...
struct path f_path;
struct inode *f_inode;
const struct file_operations *f_op;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
// ...
}
hello_drv.c
static char kernel_buf[1024];
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_to_user(buf, kernel_buf, MIN(1024, size));
if(err < 0)
{
err = -EFAULT;
return err;
}
return MIN(1024, size);
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(kernel_buf, buf, MIN(1024, size));
if(err < 0)
{
err = -EFAULT;
return err;
}
return MIN(1024, size);
}
test.c
char buf[1024];
fd = open("/dev/hello", O_RDWR);
len = read(fd, buf, 1024);
write(fd, argv[2], len);
1、kernel_buf是定义在内核中,buf是定义在用户空间的,两者不相通;
2、参数struct file *file是用于管理进程打开的文件,当open时会被创建;
打开的设备节点时/dev/hello这个需要和驱动里注册的设备名一致。
在用户层中:
当open设备节点时返回一个fd,是结构体files_struct中数组的下标,而数组成员的类型就是file,因此可以得到驱动程序hello_drv_read(…)中第一个参数;
3、注意,始终需要判断需要写入写出数据的大小和缓冲区大小的,防止数据大于缓冲区大小;
4、FILE,为打印相应的文件名,
LINE,为打印语句在源代码中相应的行,
FUNCTION,为打印语句在源代码中相应的函数名。
5、虽然用户层的buf和内核层的buf是同一个用户层地址,但是两者是隔离的;所以从程序里看到的都一样都是虚地址。