#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "my_char_device"
#define BUFFER_SIZE 256
static int major = 0;
static struct cdev my_cdev;
static char buffer[BUFFER_SIZE];
static int cap = 0;
static ssize_t my_char_device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
if (copy_from_user(buffer, buf, count)) {
return -EFAULT;
}
buffer[count] = '\0';
if (cap) {
int i;
for (i = 0; i < count; i++) {
if (buffer[i] >= 'a' && buffer[i] <= 'z') {
buffer[i] -= 32;
}
}
}
printk(KERN_INFO "Written: %s\n", buffer);
return count;
}
static const struct file_operations my_fops = {
.write = my_char_device_write,
};
static int __init my_char_device_init(void) {
int err;
err = alloc_chrdev_region(&major, 0, 1, DEVICE_NAME);
if (err < 0) {
printk(KERN_ERR "Failed to allocate major number\n");
return err;
}
cdev_init(&my_cdev, &my_fops);
my_cdev.owner = THIS_MODULE;
err = cdev_add(&my_cdev, major, 1);
if (err) {
printk(KERN_ERR "Failed to add character device\n");
unregister_chrdev_region(major, 1);
return err;
}
printk(KERN_INFO "Character device registered successfully\n");
return 0;
}
static void __exit my_char_device_exit(void) {
cdev_del(&my_cdev);
unregister_chrdev_region(major, 1);
printk(KERN_INFO "Character device unregistered\n");
}
module_param(cap, int, S_IRUGO);
module_init(my_char_device_init);
module_exit(my_char_device_exit);
MODULE_LICENSE("GPL");
以下是对上述代码的逐步解释:
1. 首先,定义了一些必要的头文件和宏。
2. 定义了一些全局变量,包括主要设备号、字符设备结构、缓冲区和转换标志。
3. my_char_device_write 函数处理对字符设备的写操作。它将用户空间的数据复制到内核缓冲区,并根据 cap 标志进行大小写转换,然后使用 printk 打印出来。
4. my_char_device_init 函数在模块加载时执行,进行设备号分配、字符设备初始化和添加等操作。
5. my_char_device_exit 函数在模块卸载时执行,进行设备删除和设备号释放等操作。
6. module_param 用于定义模块可以接收的参数。
7. module_init 和 module_exit 分别指定模块加载和卸载时调用的函数。
8. MODULE_LICENSE 声明模块的许可证。
要编译和使用这个内核模块,您需要适当的内核开发环境和工具。