我新建了文件夹并在其中仅放入my_char_dev.c和Makefile文件分别如下:#include <linux/module.h> // 内核模块基础支持
#include <linux/kernel.h> // 内核打印函数printk
#include <linux/fs.h> // 文件操作结构体file_operations
#include <linux/cdev.h> // 字符设备结构体cdev
#include <linux/uaccess.h> // 用户空间内存访问函数
#include <linux/device.h> // 设备类支持
#define DEVICE_NAME "my_char_dev" // 设备名称
#define CLASS_NAME "my_class" // 设备类名称
MODULE_LICENSE("GPL"); // 模块许可证
MODULE_AUTHOR("Your Name"); // 模块作者
MODULE_DESCRIPTION("Simple Char Driver with Case Control"); // 模块描述
// 设备结构体包含所有设备相关信息
struct my_device {
struct cdev cdev; // 字符设备结构
struct class *class; // 设备类指针
struct device *device; // 设备实例
int cap_enabled; // 大写转换标志 (1=启用)
} my_dev;
// 模块参数声明
static int cap_param = 0; // 默认关闭大写转换
module_param(cap_param, int, S_IRUGO); // 定义模块参数
MODULE_PARM_DESC(cap_param, "Enable uppercase conversion (1=enable)"); // 参数描述
// 设备打开函数
static int dev_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "my_char_dev: Device opened\n");
return 0;
}
// 设备释放函数
static int dev_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "my_char_dev: Device closed\n");
return 0;
}
// 设备写入函数 (核心功能)
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) {
char kernel_buf[256]; // 内核缓冲区
int i;
// 检查写入长度是否超过缓冲区大小
if (count > sizeof(kernel_buf) - 1) {
printk(KERN_WARNING "my_char_dev: Write size too large\n");
return -EFAULT;
}
// 从用户空间复制数据到内核空间
if (copy_from_user(kernel_buf, buf, count)) {
printk(KERN_ERR "my_char_dev: Failed to copy from user\n");
return -EFAULT;
}
kernel_buf[count] = '\0'; // 确保字符串终止
// 根据cap_enabled标志进行大写转换
if (my_dev.cap_enabled) {
for (i = 0; kernel_buf[i]; i++) {
if (kernel_buf[i] >= 'a' && kernel_buf[i] <= 'z') {
kernel_buf[i] -= 32; // 小写转大写
}
}
}
// 打印处理后的内容
printk(KERN_INFO "my_char_dev: Received: %s\n", kernel_buf);
return count; // 返回实际写入的字节数
}
// 文件操作结构体定义
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = dev_open,
.release = dev_release,
.write = dev_write,
};
// 模块初始化函数
static int __init char_dev_init(void) {
dev_t devno;
int result;
printk(KERN_INFO "my_char_dev: Initializing module\n");
// 1. 分配设备号
if ((result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME)) < 0) {
printk(KERN_ERR "my_char_dev: Failed to allocate device number\n");
return result;
}
// 2. 初始化字符设备
cdev_init(&my_dev.cdev, &fops);
my_dev.cdev.owner = THIS_MODULE;
// 3. 添加字符设备到系统
if ((result = cdev_add(&my_dev.cdev, devno, 1)) < 0) {
unregister_chrdev_region(devno, 1);
printk(KERN_ERR "my_char_dev: Failed to add cdev\n");
return result;
}
// 4. 创建设备类
my_dev.class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(my_dev.class)) {
cdev_del(&my_dev.cdev);
unregister_chrdev_region(devno, 1);
printk(KERN_ERR "my_char_dev: Failed to create class\n");
return PTR_ERR(my_dev.class);
}
// 5. 创建设备节点 (/dev/my_char_dev)
my_dev.device = device_create(my_dev.class, NULL, devno, NULL, DEVICE_NAME);
if (IS_ERR(my_dev.device)) {
class_destroy(my_dev.class);
cdev_del(&my_dev.cdev);
unregister_chrdev_region(devno, 1);
printk(KERN_ERR "my_char_dev: Failed to create device\n");
return PTR_ERR(my_dev.device);
}
// 6. 应用模块参数
my_dev.cap_enabled = cap_param;
printk(KERN_INFO "my_char_dev: Module loaded. Uppercase conversion: %s\n",
my_dev.cap_enabled ? "ENABLED" : "DISABLED");
return 0;
}
// 模块退出函数
static void __exit char_dev_exit(void) {
dev_t devno = my_dev.cdev.dev;
// 1. 销毁设备节点
device_destroy(my_dev.class, devno);
// 2. 销毁设备类
class_destroy(my_dev.class);
// 3. 删除字符设备
cdev_del(&my_dev.cdev);
// 4. 释放设备号
unregister_chrdev_region(devno, 1);
printk(KERN_INFO "my_char_dev: Module unloaded\n");
}
// 注册初始化和退出函数
module_init(char_dev_init);
module_exit(char_dev_exit);
obj-m := my_char_dev.o # 使用 := 替代 += 避免污染
all:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f *.o *.ko *.mod* .*.cmd .*.d modules.order Module.symvers——运行时报错如下:linzihao@linzihao-virtual-machine:~/Code/test/coursework2/work4$ make clean
make: *** 没有规则可制作目标“clean”。 停止。——这是什么原因
最新发布