Johannes 《Linux内核模块与设备驱动开发:编写Linux驱动程序》 (11)kmalloc 动态内存分配和struct file中的私有数据

复制代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>

static dev_t dev_nr;
static struct cdev my_cdev;
static struct class *my_class;

#define MEMSIZE 64

static int my_open(struct inode *inode, struct file *filp)
{
	filp->private_data = kmalloc(MEMSIZE, GFP_KERNEL);

	if (!filp->private_data) {
		pr_err("hello_cdev - Out of memory\n");
		return -ENOMEM;
	}

	return 0;
}

static int my_release(struct inode *inode, struct file *filp)
{
	kfree(filp->private_data);
	return 0;
}

static ssize_t my_read(struct file *filp, char __user *user_buf, size_t len, loff_t *off)
{
	char *text = filp->private_data;
	int not_copied, delta, to_copy = (len + *off) < MEMSIZE ? len : (MEMSIZE - *off);

	pr_info("hello_cdev - Read is called, we want to read %ld bytes, but actually only copying %d bytes. The offset is %lld\n", len, to_copy, *off);

	if (*off >= MEMSIZE)
		return 0;

	not_copied = copy_to_user(user_buf, &text[*off], to_copy);
	delta = to_copy - not_copied;
	if (not_copied) 
		pr_warn("hello_cdev - Could only copy %d bytes\n", delta);

	*off += delta;

	return delta;
}

static ssize_t my_write(struct file *filp, const char __user *user_buf, size_t len, loff_t *off)
{
	char *text = filp->private_data;
	int not_copied, delta, to_copy = (len + *off) < MEMSIZE ? len : (MEMSIZE - *off);

	pr_info("hello_cdev - Write is called, we want to write %ld bytes, but actually only copying %d bytes. The offset is %lld\n", len, to_copy, *off);

	if (*off >= MEMSIZE)
		return 0;

	not_copied = copy_from_user(&text[*off], user_buf, to_copy);
	delta = to_copy - not_copied;
	if (not_copied) 
		pr_warn("hello_cdev - Could only copy %d bytes\n", delta);

	*off += delta;
	return delta;
}

static struct file_operations fops = {
	.read = my_read,
	.write = my_write,
	.open = my_open,
	.release = my_release,
	.llseek = default_llseek,
};

static int __init my_init(void)
{
	int status;
#ifdef STATIC_DEVNR
	dev_nr = STATIC_DEVNR;
	status = register_chrdev_region(dev_nr, MINORMASK + 1, "hello_cdev");
#else
	status = alloc_chrdev_region(&dev_nr, 0, MINORMASK + 1, "hello_cdev");
#endif
	if (status) {
		pr_err("hello_cdev - Error reserving the region of device numbers\n");
		return status;
	}

	cdev_init(&my_cdev, &fops);
	my_cdev.owner = THIS_MODULE;

	status = cdev_add(&my_cdev, dev_nr, MINORMASK + 1);
	if (status) {
		pr_err("hello_cdev - Error adding cdev\n");
		goto free_devnr;
	}

	pr_info("hello_cdev - Registered a character device for Major %d starting with Minor %d\n", MAJOR(dev_nr), MINOR(dev_nr));

	my_class = class_create("my_class");
	if (!my_class) {
		pr_err("hello_cdev - Could not create class my_class\n");
		status = ENOMEM;
		goto delete_cdev;
	}

	if (!device_create(my_class, NULL, dev_nr, NULL, "hello%d", 0)) {
		pr_err("hello_cdev - Could not create device hello0\n");
		status = ENOMEM;
		goto delete_class;
	}

	pr_info("hello_cdev - Created device under /sys/class/my_class/hello0\n");

	return 0;

delete_class:
	class_unregister(my_class);
	class_destroy(my_class);
delete_cdev:
	cdev_del(&my_cdev);
free_devnr:
	unregister_chrdev_region(dev_nr, MINORMASK + 1);
	return status;
}

static void __exit my_exit(void)
{
	device_destroy(my_class, dev_nr);
	class_unregister(my_class);
	class_destroy(my_class);
	cdev_del(&my_cdev);
	unregister_chrdev_region(dev_nr, MINORMASK + 1);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johannes 4Linux");
MODULE_DESCRIPTION("A sample driver for manually registering a character device");

和lesson10 auto_devfile 相对应的是其添加修改了open/release/read/write 。

malloc/free 在c 里面很常见的成对出现,用于申请内存空间和释放内存空间,这里的kmalloc/free 成对出现在open/release 里面。要实现这对就要在头文件添加<linux/slab.h>.参数

GFP_KERNEL:常规

GFP_ATOMIC:中断上下文调用,原子操作

GFP_DMA: DMA 申请一段连续空间。

程序只是学习使用,JOHANNES 就直接给GFP_KENREL。

然后read/write 函数里面就是copy_to_user()/user_to_copy()。

不看视频,直接看这个程序,能理解这个程序是注册了一个字符设备文件,打开字符设备文件就会申请下一段64字节(MEMSIZE)内存空间,从外部用户层给内存空间读写数据,就会对这段内存空间进行读写。

视频:https://www.bilibili.com/video/BV18SE26cEjn?spm_id_from=333.788.videopod.sections&vd_source=92b7efa4daa5bb4fdcdc9f2db97c307b&p=11

觉得没太多可说的。就是lesson8/lesson10 综合加上了一段内存空间申请读写。

相关推荐
hansang_IR1 小时前
【题解】[COCI 2024/2025 #2] 流明 / Blistavost
c++·算法·动态规划·dp
程序喵大人1 小时前
【C++进阶】STL算法与函数对象 - 01 让算法去处理一段迭代器范围
开发语言·c++·算法·函数对象
Keven_111 小时前
算法札记:二叉树前序、中序、后序遍历及对应序列重要性质
数据结构·算法·深度优先
Delite8021 小时前
微库仑氧化法硫氯检测:油品分析中测量误差的控制要点
算法
宵时待雨1 小时前
优选算法专题12:队列
算法·leetcode·职场和发展
tianyu2341 小时前
双指针循环匹配金额——打款记录与账单的自动对账算法
java·算法·双指针循环·匹配金额
无足鸟ICT1 小时前
【RHCA+】if判断
linux
大魔王爱学习2 小时前
终端bash&zsh中实现基于前缀的历史命令搜索
linux·bash
2401_858286112 小时前
OS81.【Linux】基于环形队列的多生产者-多消费者模型
linux·运维·服务器·环形队列