define class

class Person
   def initialize(name,age=18)
       @name = name
       @age = age
       @motherland = "China"
end
def talk
      puts"my name is "+@name+",age is "+@age.to_s
      if @motherland=="China"
          puts "I am a Chinese"
      else
          puts "I am a foreigner"
      end
end
      attr_writer :motherland
end
p1 =Person.new("snow",20)
p1.talk
p2=Person.new("ben")
p2.motherland="english"
p2.talk
#---------------------Define another class
class Student   def talk
     puts "I'am a student.my name is "+@name+",age is "+@age.to_s
   end
 end
 p3 = Student.new("luccc",25);p3.talk
 #--------------------------
 a = 5;
 puts "a=#{a}";
 def p3.ownMtd
   puts "This method is p3s,Other Student have not it!";
 end
 p3.ownMtd;
逐行解释代码:#include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/ctype.h> #define DEVICE_NAME "mydev" #define CLASS_NAME "myclass" MODULE_LICENSE("GPL"); MODULE_AUTHOR("YourName"); MODULE_DESCRIPTION("Character device driver with uppercase conversion"); static int cap = 0; module_param(cap, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(cap, "Enable uppercase conversion (1=enabled)"); static int major_num; static struct class* dev_class = NULL; static struct cdev my_cdev; static int device_open(struct inode *inode, struct file *file) { return 0; } static int device_release(struct inode *inode, struct file *file) { return 0; } static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { char kernel_buffer[1024]; size_t bytes_to_copy = min(count, sizeof(kernel_buffer) - 1); // Copy data from userspace if (copy_from_user(kernel_buffer, buf, bytes_to_copy)) { return -EFAULT; } kernel_buffer[bytes_to_copy] = '\0'; // Uppercase conversion if enabled if (cap) { for (int i = 0; kernel_buffer[i]; i++) { kernel_buffer[i] = toupper(kernel_buffer[i]); } } // Print to kernel log printk(KERN_INFO "mydev: %s\n", kernel_buffer); return bytes_to_copy; } static struct file_operations fops = { .owner = THIS_MODULE, .open = device_open, .release = device_release, .write = device_write, }; static int __init mydev_init(void) { // Allocate device numbers if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { return -1; } // Create character device cdev_init(&my_cdev, &fops); if (cdev_add(&my_cdev, major_num, 1) < 0) { unregister_chrdev_region(major_num, 1); return -1; } // Create device class dev_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(dev_class)) { cdev_del(&my_cdev); unregister_chrdev_region(major_num, 1); return PTR_ERR(dev_class); } // Create device node device_create(dev_class, NULL, major_num, NULL, DEVICE_NAME); printk(KERN_INFO "mydev: Loaded with cap=%d\n", cap); return 0; } static void __exit mydev_exit(void) { device_destroy(dev_class, major_num); class_destroy(dev_class); cdev_del(&my_cdev); unregister_chrdev_region(major_num, 1); printk(KERN_INFO "mydev: Unloaded\n"); } module_init(mydev_init); module_exit(mydev_exit);
最新发布
08-06
<think>我们逐行解释提供的Linux内核模块代码,该模块实现了一个字符设备驱动,支持大写转换参数。 注意:代码中已经包含了必要的头文件和函数定义。我们将按照代码顺序进行解释。 首先,包含必要的头文件: ```c #include <linux/module.h> // 包含加载模块需要的符号和函数 #include <linux/fs.h> // 文件系统相关,用于文件操作结构体 #include <linux/cdev.h> // 字符设备相关 #include <linux/device.h> // 设备类相关 #include <linux/uaccess.h> // 用户空间和内核空间数据拷贝 #include <linux/ctype.h> // 字符处理函数(如toupper) ``` 定义设备名称和类名称: ```c #define DEVICE_NAME "mydev" // 设备名称,出现在/dev/下 #define CLASS_NAME "myclass" // 设备类名称 ``` 模块的元信息: ```c MODULE_LICENSE("GPL"); // 模块许可证,必须 MODULE_AUTHOR("YourName"); // 作者 MODULE_DESCRIPTION("Character device driver with uppercase conversion"); // 描述 ``` 模块参数: ```c static int cap = 0; // 默认关闭大写转换 module_param(cap, int, S_IRUGO | S_IWUSR); // 定义模块参数,名称是cap,类型是int,权限是用户可读、用户可写 MODULE_PARM_DESC(cap, "Enable uppercase conversion (1=enabled)"); // 参数描述 ``` 全局变量: ```c static int major_num; // 存储动态分配的主设备号 static struct class* dev_class = NULL; // 设备类指针 static struct cdev my_cdev; // 字符设备结构 ``` 设备打开函数: ```c static int device_open(struct inode *inode, struct file *file) { return 0; // 打开设备,这里直接返回0表示成功 } ``` 设备释放函数: ```c static int device_release(struct inode *inode, struct file *file) { return 0; // 关闭设备,这里直接返回0 } ``` 设备写函数: ```c static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { char kernel_buffer[1024]; // 内核缓冲区,用于存储用户空间传来的数据 size_t bytes_to_copy = min(count, sizeof(kernel_buffer) - 1); // 计算要拷贝的字节数,不超过缓冲区大小减1(留一个给'\0') // 从用户空间拷贝数据到内核空间 if (copy_from_user(kernel_buffer, buf, bytes_to_copy)) { return -EFAULT; // 拷贝失败,返回错误码 } kernel_buffer[bytes_to_copy] = '\0'; // 确保字符串以'\0'结尾 // 如果cap参数为1(启用大写转换),则转换缓冲区中的字符 if (cap) { for (int i = 0; kernel_buffer[i]; i++) { kernel_buffer[i] = toupper(kernel_buffer[i]); // 逐个字符转换为大写 } } // 打印信息到内核日志 printk(KERN_INFO "mydev: %s\n", kernel_buffer); return bytes_to_copy; // 返回实际写入的字节数 } ``` 定义文件操作结构体: ```c static struct file_operations fops = { .owner = THIS_MODULE, // 指向拥有该结构体的模块 .open = device_open, // 打开设备函数 .release = device_release, // 关闭设备函数 .write = device_write, // 写设备函数 }; ``` 模块初始化函数(加载模块时调用): ```c static int __init mydev_init(void) { // 动态申请设备号(主设备号由内核分配) if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { return -1; // 申请失败 } // 初始化字符设备结构,将文件操作函数集关联到该设备 cdev_init(&my_cdev, &fops); // 添加字符设备到系统 if (cdev_add(&my_cdev, major_num, 1) < 0) { unregister_chrdev_region(major_num, 1); // 添加失败,释放设备号 return -1; } // 创建设备类(在/sys/class/下可见) dev_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(dev_class)) { // 检查错误 cdev_del(&my_cdev); // 删除字符设备 unregister_chrdev_region(major_num, 1); // 释放设备号 return PTR_ERR(dev_class); // 返回错误码 } // 创建设备节点(/dev/mydev),这样用户空间就可以访问了 device_create(dev_class, NULL, major_num, NULL, DEVICE_NAME); // 打印加载信息,包括cap参数的值 printk(KERN_INFO "mydev: Loaded with cap=%d\n", cap); return 0; // 初始化成功 } ``` 模块退出函数(卸载模块时调用): ```c static void __exit mydev_exit(void) { // 销毁设备节点 device_destroy(dev_class, major_num); // 销毁设备类 class_destroy(dev_class); // 删除字符设备 cdev_del(&my_cdev); // 释放设备号 unregister_chrdev_region(major_num, 1); // 打印卸载信息 printk(KERN_INFO "mydev: Unloaded\n"); } ``` 指定模块的初始化和退出函数: ```c module_init(mydev_init); // 指定模块初始化函数 module_exit(mydev_exit); // 指定模块退出函数 ``` ### 总结: 该内核模块实现了一个简单的字符设备驱动。当用户向/dev/mydev写入数据时,内核会将这些数据打印到内核日志中。如果加载模块时指定了参数`cap=1`,则会将所有写入的字符转换为大写后再打印。模块支持动态分配主设备号,并自动创建设备节点。 ### 注意事项: 1. 内核模块编程需要特别注意内存安全和错误处理。 2. 用户空间和内核空间之间的数据拷贝必须使用copy_from_user/copy_to_user等安全函数。 3. 在卸载模块时必须释放所有申请的资源(设备号、设备节点、设备类等)。 §§相关问题§§: 1. 在字符设备驱动中,如何实现读操作(read)? 2. 为什么在内核模块中不能使用标准C库函数(如printf)? 3. 如何在内核模块中处理多个并发写操作? 4. 解释copy_from_user函数的作用和返回值的含义。</think>### 逐行代码解释: ```c #include <linux/module.h> // 内核模块基础支持(加载/卸载/初始化) #include <linux/fs.h> // 文件系统相关(file_operations结构) #include <linux/cdev.h> // 字符设备操作(cdev结构) #include <linux/device.h> // 设备模型支持(class_create/device_create) #include <linux/uaccess.h> // 用户空间内存访问(copy_from_user) #include <linux/ctype.h> // 字符处理函数(toupper) #define DEVICE_NAME "mydev" // 设备名称(/dev/mydev) #define CLASS_NAME "myclass" // 设备类名称(sysfs中使用) MODULE_LICENSE("GPL"); // 声明模块许可证(GPL是必须的) MODULE_AUTHOR("YourName"); // 模块作者信息 MODULE_DESCRIPTION("Character device driver with uppercase conversion"); // 模块描述 // 模块参数:cap(大写转换开关) static int cap = 0; // 默认关闭大写转换 module_param(cap, int, S_IRUGO | S_IWUSR); // 定义模块参数(名称,类型,权限) MODULE_PARM_DESC(cap, "Enable uppercase conversion (1=enabled)"); // 参数描述 // 全局变量声明 static int major_num; // 存储主设备号 static struct class* dev_class = NULL; // 设备类指针 static struct cdev my_cdev; // 字符设备结构体 // 设备打开回调函数 static int device_open(struct inode *inode, struct file *file) { return 0; // 简单返回成功(无特殊操作) } // 设备关闭回调函数 static int device_release(struct inode *inode, struct file *file) { return 0; // 简单返回成功(无特殊操作) } // 设备写操作回调函数(核心功能) static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { char kernel_buffer[1024]; // 内核缓冲区(存储用户数据) // 计算安全拷贝大小(防止缓冲区溢出) size_t bytes_to_copy = min(count, sizeof(kernel_buffer) - 1); // 从用户空间复制数据到内核空间 if (copy_from_user(kernel_buffer, buf, bytes_to_copy)) { return -EFAULT; // 复制失败返回错误码 } kernel_buffer[bytes_to_copy] = '\0'; // 添加字符串终止符 // 大写转换(当cap=1时启用) if (cap) { for (int i = 0; kernel_buffer[i]; i++) { kernel_buffer[i] = toupper(kernel_buffer[i]); // 字符转大写 } } // 打印到内核日志(dmesg可查看) printk(KERN_INFO "mydev: %s\n", kernel_buffer); return bytes_to_copy; // 返回实际写入的字节数 } // 定义文件操作结构体(驱动功能映射) static struct file_operations fops = { .owner = THIS_MODULE, // 指向当前模块的指针 .open = device_open, // 打开设备回调 .release = device_release, // 关闭设备回调 .write = device_write, // 写设备回调 }; // 模块初始化函数(insmod时调用) static int __init mydev_init(void) { // 1. 动态分配设备号(主+次设备号) if (alloc_chrdev_region(&major_num, 0, 1, DEVICE_NAME) < 0) { return -1; // 分配失败返回错误 } // 2. 初始化并添加字符设备 cdev_init(&my_cdev, &fops); // 关联文件操作 if (cdev_add(&my_cdev, major_num, 1) < 0) { unregister_chrdev_region(major_num, 1); // 失败时释放设备号 return -1; } // 3. 创建设备类(sysfs中使用) dev_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(dev_class)) { // 错误检查 cdev_del(&my_cdev); unregister_chrdev_region(major_num, 1); return PTR_ERR(dev_class); // 返回错误代码 } // 4. 创建设备节点(/dev/mydev) device_create(dev_class, NULL, major_num, NULL, DEVICE_NAME); // 打印加载成功信息(包含cap参数值) printk(KERN_INFO "mydev: Loaded with cap=%d\n", cap); return 0; // 初始化成功 } // 模块退出函数(rmmod时调用) static void __exit mydev_exit(void) { // 1. 销毁设备节点 device_destroy(dev_class, major_num); // 2. 销毁设备类 class_destroy(dev_class); // 3. 删除字符设备 cdev_del(&my_cdev); // 4. 释放设备号 unregister_chrdev_region(major_num, 1); // 打印卸载信息 printk(KERN_INFO "mydev: Unloaded\n"); } // 指定模块初始化和退出函数 module_init(mydev_init); // 注册初始化函数 module_exit(mydev_exit); // 注册退出函数 ``` ### 关键点详解: 1. **内存安全**: - `copy_from_user()`:安全地从用户空间复制数据(防止非法内存访问) - 缓冲区大小限制:`min(count, sizeof(buffer)-1)` 防止溢出 - 字符串终止:`kernel_buffer[bytes_to_copy] = '\0'` 确保有效字符串 2. **设备注册流程**: ```mermaid graph TD A[alloc_chrdev_region] --> B[cdev_init] B --> C[cdev_add] C --> D[class_create] D --> E[device_create] ``` 3. **资源清理顺序**: ```mermaid graph LR F[device_destroy] --> G[class_destroy] G --> H[cdev_del] H --> I[unregister_chrdev_region] ``` (逆初始化顺序释放资源,避免内存泄漏) 4. **大写转换逻辑**: ```c if (cap) { for (int i = 0; kernel_buffer[i]; i++) { kernel_buffer[i] = toupper(kernel_buffer[i]); } } ``` - 仅当`cap=1`时执行转换 - 使用内核提供的`toupper()`函数(来自<linux/ctype.h>) - 就地修改缓冲区内容 5. **内核日志输出**: - `printk(KERN_INFO ...)`:输出到内核环形缓冲区 - 日志级别`KERN_INFO`表示普通信息 - 可通过`dmesg`命令查看输出内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值