例程代码路径:ELF 1开发板资料包\03-例程源码\03-2 驱动例程源码\03_内核空间与用户空间的数据拷贝\copy_form_user
在copy_to_user.c源码的基础上添加device_write函数的实现,重命名为copy_form_user.c
(一)定义变量
#define DEVICE_NAME "copy_form_user" // 设备名称
static char user_buffer[BUFFER_SIZE] = "";
(二)在device_write()函数添加拷贝操作,用户空间使用write函数时,会进入此函数。
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
{
ssize_t bytes_written = 0;
// 在这里处理设备写入的操作
printk(KERN_INFO "This is device_write.\n");
if (*offset >= BUFFER_SIZE)
return -ENOSPC;
if (*offset + length > BUFFER_SIZE)
length = BUFFER_SIZE - *offset;
if (copy_from_user(user_buffer + *offset, buffer, length))
return -EFAULT;
*offset += length;
bytes_written = length;
printk(KERN_INFO "Received from user: %s", user_buffer);
return bytes_written;
}
offset参数表示当前文件位置的偏移量。它用于跟踪读取或写入操作在文件中的位置。
对于device_write()函数来说,offset参数用于指示应写入数据的起始位置。根据需要,可以在函数内部修改该偏移量,以便在下一次写操作时从适当的位置开始写入。
在上述示例中,首先执行写操作,并使用offset参数作为起始位置。然后,通过将length添加到offset上来更新偏移量,以便在下一次写操作时从正确的位置开始。
完整的copy_to_user.c示例源码
#include // 包含模块相关函数的头文件
#include // 包含文件系统相关函数的头文件
#include // 包含用户空间数据访问函数的头文件
#include //包含字符设备头文件
#include
#include
#define DEVICE_NAME "copy_form_user" // 设备名称
static dev_t dev_num; //分配的设备号
struct cdev my_cdev; //字符设备指针
int major; //主设备号
int minor; //次设备号
static struct class *my_class;
static struct device *my_device;
#define BUFFER_SIZE 1024
static char kernel_buffer[BUFFER_SIZE] = "Hello, User! This is kernel_buffer!";
static char user_buffer[BUFFER_SIZE] = "";
static int device_open(struct inode *inode, struct file *file)
{
// 在这里处理设备打开的操作
printk(KERN_INFO "This is device_open.\n");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
// 在这里处理设备关闭的操作
printk(KERN_INFO "This is device_release.\n");
return 0;
}
static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
ssize_t bytes_read = 0;
// 在这里处理设备读取的操作
printk(KERN_INFO "This is device_read.\n");
if (*offset >= BUFFER_SIZE)
return 0;
if (*offset + length > BUFFER_SIZE)
length = BUFFER_SIZE - *offset;
if (copy_to_user(buffer, kernel_buffer + *offset, length))
return -EFAULT;
*offset += length;
bytes_read = length;
return bytes_read;
}
static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
{
ssize_t bytes_written = 0;
// 在这里处理设备写入的操作
printk(KERN_INFO "This is device_write.\n");
if (*offset >= BUFFER_SIZE)
return -ENOSPC;
if (*offset + length > BUFFER_SIZE)
length = BUFFER_SIZE - *offset;
if (copy_from_user(user_buffer + *offset, buffer, length))
return -EFAULT;
*offset += length;
bytes_written = length;
printk(KERN_INFO "Received from user: %s", user_buffer);
return bytes_written;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write,
};
static int __init mydevice_init(void)
{
int ret;
// 在这里执行驱动程序的初始化操作
// 注册字符设备驱动程序
ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_NAME);
if (ret < 0) {
printk(KERN_ALERT "Failed to allocate device number: %d\n", ret);
return ret;
}
major=MAJOR(dev_num);
minor=MINOR(dev_num);
printk(KERN_INFO "major number: %d\n",major);
printk(KERN_INFO "minor number: %d\n",minor);
my_cdev.owner = THIS_MODULE;
cdev_init(&my_cdev,&fops);
cdev_add(&my_cdev,dev_num,1);
// 创建设备类
my_class = class_create(THIS_MODULE, "my_class");
if (IS_ERR(my_class)) {
pr_err("Failed to create class\n");
return PTR_ERR(my_class);
}
// 创建设备节点并关联到设备类
my_device = device_create(my_class, NULL, MKDEV(major, minor), NULL, DEVICE_NAME);
if (IS_ERR(my_device)) {
pr_err("Failed to create device\n");
class_destroy(my_class);
return PTR_ERR(my_device);
}
printk(KERN_INFO "Device registered successfully.\n");
return 0;
}
static void __exit mydevice_exit(void)
{
// 在这里执行驱动程序的清理操作
// 销毁设备节点
device_destroy(my_class, MKDEV(major, minor));
// 销毁设备类
class_destroy(my_class);
// 删除字符设备
cdev_del(&my_cdev);
// 注销字符设备驱动程序
unregister_chrdev(0, DEVICE_NAME);
printk(KERN_INFO "Device unregistered.\n");
}
module_init(mydevice_init);
module_exit(mydevice_exit);
MODULE_LICENSE("GPL"); // 指定模块的许可证信息
MODULE_AUTHOR("Your Name"); // 指定模块的作者信息
MODULE_DESCRIPTION("A simple character device driver"); // 指定模块的描述信息
编译
复制7.4.2驱动中的Makefile文件,将其中的copy_to_user.o修改为copy_form_user.o,效果如下:
. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
elf@ubuntu:~/work/test/03_内核空间与用户空间的数据拷贝/copy_form_user$ make
将驱动模块编译成.ko并传到开发板中。
编写测试应用源码copy_form_user
#include
#include
#include
#include
#include
#include
#include
#define DEV_NAME "/dev/copy_form_user"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[])
{
int reg;
int fd = 0;
char *write_buffer="Hello,kernel!This is user_buffer!";
fd = open (DEV_NAME, O_RDWR);
if (fd < 0) {
perror("Open "DEV_NAME" Failed!\n");
exit(1);
}
if (write(fd, write_buffer, strlen(write_buffer)) < 0) {
printf("Failed to write to device file: %s\n", DEV_NAME);
close(fd);
exit(1);
}
printf("Wrote to device file: %s\n", DEV_NAME);
close(fd);
return 0;
}
编译应用
. /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
elf@ubuntu:~/work/test/03_内核空间与用户空间的数据拷贝/copy_form_user_app$ $C\C copy_form_user.c -o copy_form_user
将编译好的应用程序发送到开发板中
测试
root@ELF1:~# insmod copy_form_user.ko
major number: 248
minor number: 0
Device registered successfully.
root@ELF1:~# ./copy_form_user
This is device_open.
This is device_write.
Received from user: Hello,kernel!This is user_buffer!Wrote to device file: /dev/copy_f
orm_user
This is device_release.
root@ELF1:~# rmmod copy_form_user.ko
Device unregistered.
可以看到运行测试程序后,可以看到驱动里把用户空间传进去的字符串打印了出来。
|