读写方法集的实现
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); /* 用户调用read函数的回调函数 */
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); /* 用户调用write函数的回调函数 */
读写函数
/*
功能:将用户空间from数据写入到内核空间to;
参数:
参数1:to指针,指向的是内核缓存空间的起始地址;
参数2:from指针,指向的是用户缓存空间的起始地址;
参数3:n表示拷贝数据的字节数;
返回值:
成功返回拷贝的字节数;失败返回-EFAULT
*/
extern int copy_from_user(void *to, const void __user *from, int n);
/*
功能:将内核空间from数据写入到用户空间to中;
参数:
参数1:to指针,指向的用户缓存控件的起始地址;
参数2:from指针,指向的是内核缓存空间的起始地址;
参数3:n表示拷贝数据的字节数;
返回值:
成功返回拷贝的字节数;失败返回-EFAULT
*/
extern int copy_to_user(void __user *to, const void *from, int n);
实例
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#define KBUFSIZE 64
static dev_t dev_num;/* dev_num存储申请成功的设备号 */
static unsigned int count = 4;/* 次设备的数量 */
static struct cdev *cdev_p;/* 字符设备注册结构体指针 */
static struct class *class_p;
static struct device *device_p;
static unsigned char kernel_buf[KBUFSIZE];
int my_char_driver_open(struct inode *inode_p, struct file *file_p)
{
dev_t my_dev;
my_dev = inode_p->i_rdev;
printk(KERN_INFO "my char driver open <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
return 0;
}
int my_char_driver_release(struct inode *inode_p, struct file *file_p)
{
dev_t my_dev;
my_dev = inode_p->i_rdev;
printk(KERN_INFO "my char driver release <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));
return 0;
}
/* 提供给用户的read函数调用时,内核中的驱动调用read */
ssize_t my_char_driver_read(struct file *file_p, char __user *buf, size_t size, loff_t *loff_p)
{
int ret;
if (size < 0)
size = 0;
if (size > KBUFSIZE)
size = KBUFSIZE;
ret = copy_to_user(buf, kernel_buf, size);
if (ret == -EFAULT)
return ret;
return size;
}
ssize_t my_char_driver_write(struct file *file_p, const char __user *buf, size_t size, loff_t *loff_p)
{
int ret;
if (size < 0)
size = 0;
if (size > KBUFSIZE)
size = KBUFSIZE;
ret = copy_from_user(kernel_buf, buf, size);
if (ret == -EFAULT)
return ret;
printk(KERN_INFO "kernel_buf : %s\n", kernel_buf);
return size;
}
const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = my_char_driver_open,
.release = my_char_driver_release,
.read = my_char_driver_read,
.write = my_char_driver_write
};
/* 定义模块加载入口函数 */
static int __init my_char_driver_init(void)
{
int ret = 0;
/* 1. 申请设备号:手动申请(给定主设备号和起始次设备号)/动态申请(返回设备号) */
ret = alloc_chrdev_region(&dev_num, 0, count, "chrdev");/* 动态申请设备号 */
if (ret != 0)
{
goto err0;
}
/* 2. 注册设备到系统中,有系统统一调度管理 */
/* 2.1 申请字符设备注册结构体空间*/
cdev_p = cdev_alloc();
if (cdev_p == NULL)
{
ret = - ENOMEM;
goto err1;
}
/* 2.2 初始化字符数设备结构体空间中的操作方法集 */
cdev_init(cdev_p, &fops);
/* 2.3 添加字符设备结构体到系统中,由系统统一调度管理 */
ret = cdev_add(cdev_p, dev_num, count);
if (ret != 0)
{
goto err2;
}
/* 3. 创建设备节点(可选:一般都会加上) */
/* 3.1 创建节点对象 */
class_p = class_create(THIS_MODULE, "mychar");
if (IS_ERR(class_p))
{
ret = - ENOMEM;
goto err3;
}
int i;
for (i = 0; i < count; i++) /* 由于驱动可以管理多个设备文件,需要循环创建设备文件 */
{
char drv_name[20] = {0};
sprintf(drv_name, "mychar%d", i);
/* 3.2 创建设备节点 */
device_p = device_create(class_p, NULL, MKDEV(MAJOR(dev_num), i), NULL, drv_name);
if (IS_ERR(device_p))
{
ret = - ENOMEM;
goto err4;
}
}
printk(KERN_INFO "my char driver : <major: %d, minor: %d> init success\n", MAJOR(dev_num), MINOR(dev_num));
return 0;
err4:
/* 释放创建成功的设备节点 */
for (i--; i >= 0; i--)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
err3:
err2:
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
err1:
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
err0:
return ret;
}
/* 定义模块卸载入口函数 */
static void __exit my_char_driver_exit(void)
{
/* 释放设备节点 */
int i;
for (i = 0; i < count; i++)
device_destroy(class_p, MKDEV(MAJOR(dev_num), i));
/* 释放设备节点对象 */
class_destroy(class_p);
/* 释放字符设备结构体空间 */
cdev_del(cdev_p);
/* 释放设备号 */
unregister_chrdev_region(dev_num, count);
printk(KERN_INFO "my char driver exit success\n");
}
module_init(my_char_driver_init);/* 声明模块加载入口函数 */
module_exit(my_char_driver_exit);/* 声明模块卸载入口函数 */
MODULE_LICENSE("GPL");
网友评论