动态指定设备号

这段代码是 Linux 内核模块中用于动态指定设备号的典型实现,适用于字符设备驱动开发。以下是逐行解释:


1. 定义静态设备号参数

static int major; // 静态主设备号(如 240)
static int minor; // 静态次设备号(如 0)
  • 作用:声明两个静态整型变量,用于存储从模块参数传递的主/次设备号。
  • 静态关键字static 表示变量仅在当前文件内可见,避免命名冲突。

2. 暴露模块参数

module_param(major, int, S_IRUGO); // 允许通过 insmod/modprobe 传递 major 参数
module_param(minor, int, S_IRUGO); // 允许通过 insmod/modprobe 传递 minor 参数
  • module_param 宏:将变量声明为模块参数,支持在加载模块时动态赋值。
    • 参数1:变量名(majorminor)。
    • 参数2:参数类型(int)。
    • 参数3:权限掩码(S_IRUGO 表示只读,对应 /sys/module/<模块名>/parameters/ 下的文件权限)。
  • 使用示例
    sudo insmod my_driver.ko major=240 minor=0

3. 定义设备号变量

static dev_t dev_num; // 用于存储组合后的设备号(32/64 位,取决于内核配置)
  • dev_t 类型:内核中表示设备号的类型,包含主设备号(Major)和次设备号(Minor)。
    • 主设备号:标识设备类型(如字符设备、块设备),由内核分配。
    • 次设备号:由驱动自行管理,用于区分同类型的不同设备实例。

4. 典型使用场景

在模块初始化函数(如 module_init)中,通常会执行以下操作:

static int __init my_driver_init(void) {
    // 组合主次设备号为 dev_t
    dev_num = MKDEV(major, minor);
    
    // 注册字符设备(静态分配方式)
    register_chrdev_region(dev_num, 1, "my_device");
    
    // 或者动态分配设备号(更推荐)
    // alloc_chrdev_region(&dev_num, minor, 1, "my_device");
    
    // 创建类、设备节点等操作...
    return 0;
}

5. 关键注意事项

  1. 静态分配 vs 动态分配
    • 静态分配:需手动指定 major,需确保未被其他驱动占用(通过 cat /proc/devices 查询)。
    • 动态分配:使用 alloc_chrdev_region 让内核自动分配空闲设备号,更安全。
  2. 设备号范围
    • 传统 8+24 位:主设备号 8 位(0-255),次设备号 24 位。
    • 64 位 dev_t:现代内核支持更大范围,但主设备号仍建议使用 <256
  3. 权限管理
    • S_IRUGO 确保参数文件在 /sys/module/ 下为只读,防止运行时误修改。

6. 完整流程示例

// 1. 定义参数和设备号变量
static int major;
static int minor;
module_param(major, int, S_IRUGO);
module_param(minor, int, S_IRUGO);
static dev_t dev_num;

// 2. 模块初始化函数
static int __init my_driver_init(void) {
    int ret;
    
    // 组合设备号
    dev_num = MKDEV(major, minor);
    
    // 静态注册设备号(需确保 major 未被占用)
    ret = register_chrdev_region(dev_num, 1, "my_device");
    if (ret < 0) {
        printk(KERN_ERR "Failed to register device number\n");
        return ret;
    }
    
    // 动态分配示例(更推荐)
    // ret = alloc_chrdev_region(&dev_num, minor, 1, "my_device");
    // major = MAJOR(dev_num);  // 从分配结果中提取主设备号
    
    // 创建类、设备节点等...
    return 0;
}

// 3. 模块退出函数
static void __exit my_driver_exit(void) {
    unregister_chrdev_region(dev_num, 1);
    // 清理资源...
}

module_init(my_driver_init);
module_exit(my_driver_exit);

7. 用户空间交互

加载模块后,用户可通过 mknod 手动创建设备节点:

sudo mknod /dev/my_device c $(major) $(minor)
  • c 表示字符设备。
  • 动态分配时,需从 /proc/devices 或 dmesg 输出中获取分配的 major

通过这种方式,驱动代码实现了设备号的灵活配置,兼顾了静态指定的直接性和动态分配的安全性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值