美文网首页
字符设备

字符设备

作者: wjundong | 来源:发表于2022-11-23 17:15 被阅读0次

字符设备

设备号 32 位, 次设备号 20 位, 主设备号 12 位, 最大 4096

#define MINORBITS 20
#define MINORMASK       ((1U << MINORBITS) - 1)
#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

dev_t dev = MKDEV(245, 15);
printk("devnum: %d, major %d minor %d\n", dev, MAJOR(dev), MINOR(dev));
// devnum: 256901135, major 245 minor 15
  • register_chrdev_region

    /**
     * @brief 分配一个或多个设备号
     * 
     * @param first 要分配的起始设备编号, 包括次设备号, 比如 MKDEV(5, 3) 作为起始, MKDEV(5, 0) 就不算在内
     * @param count 请求的连续设备编号的总数, 注意, 如果 count 太大, 你要求的范围可能溢出到下一个主设备号
     *              但是只要你要求的编号范围可用, 一切都仍然会正确工作.
     * @param name  应当连接到这个编号范围的设备的名字, 它会出现在 /proc/devices 和 sysfs 中
     * @return 如果分配成功进行, register_chrdev_region 的返回值是 0, 出错的情况下, 返回一个负的错误码
     */
    int register_chrdev_region(dev_t first, unsigned int count, char *name);
    

    分配设备号时不能有交集, 同一个主设备号可以有不同的名字, 只需注册两次, 两次主设备号相同, 此设备号不同和名称不同即可, 比如

    register_chrdev_region(MKDEV(257, 15), 3, "hello");
    register_chrdev_region(MKDEV(257, 18), 5, "fuck");
    

    设备号 257:15 ~ 257:17 被分配, 名称为 hello, 设备号 257:18 ~ 257:22 被分配, 名称为 fuck, 如果第二次分配时, 和第一次分配的有交集, 比如 register_chrdev_region(MKDEV(257, 17), 5, "fuck"); 则第二次分配将出错, 返回非0值.

    一个设备可以有多个设备号(包括不同的主设备号), 一个主设备号(包含多个次设备号)也可以分配到不同的设备中(只要次设备号不同), 比如

    分配到设备号 257:15 ~ 257:17, 设备号 666:0 ~ 666:12  可以对同一个设备同时添加这两组设备号.
    分配到设备号 257:15 ~ 257:17 共 3 个, 可以分别添加到不同的设备
    

    也就是说分配到的每一个设备号(主+次组合)都可以独立地被标识并添加到设备中. 设备号的分配和实际设备如何添加设备号没有关系, 实际设备可以添加多个设备号作为自己的标识索引, 而且每个主设备号分配时名称不一致也没有关系.

    设备添加设备号时如果设备号已经被添加到其它设备, 将会发生覆盖, 即设备号将和旧的设备断联, 而和新加的设备关联.

  • alloc_chrdev_region

    /**
     * @brief 分配一系列字符设备编号。主编号将被动态选择,并在dev中返回(与第一个次要编号一起)
     * 
     * @param dev 输出第一个分配的设备号
     * @param baseminor 请求的次设备号范围的第一个
     * @param count 所需的设备号数量
     * @param name 关联设备或驱动程序的名称
     * @return 返回零错误代码或负错误代码
     */
    int alloc_chrdev_region (dev_t * dev, unsigned baseminor, unsigned count, const char * name);
    该函数总是分配一个新的主设备号, 即使老的设备号还有很多区域没有注册。因此不像 `register_chrdev_region` 那样灵活, 能够一个主设备号注册不同设备。比如
    ```c
    alloc_chrdev_region(&dev, 0, 15, "hello");
    alloc_chrdev_region(&dev, 18, 15, "hello");
    

    虽然两次分配, 次设备号没有交集, 但函数返回两个不同的主设备号

  • unregister_chrdev_region

    /**
     * @brief 销毁分配的设备号
     * 
     * @param from 取消登记的数字范围中的第一个
     * @param count 要注销的设备编号的数量
     */
    void unregister_chrdev_region ( dev_t from, unsigned count);
    

    若 count 数量不对, 还有次设备号没没被释放, 则主设备号还会存在, 直到所有次设备号被释放

  • cdev_init

    /**
     * @brief 初始化一个 cdev 结构,并绑定 fops,使其准备好使用 cdev_add 添加到系统
     * 
     * @param cdev 要初始化的结构
     * @param fops 常量结构 fops
     */
    void cdev_init (struct cdev * cdev, const struct file_operations * fops);
    
  • cdev_add

    /**
     * @brief cdev_add 将由 p 表示的设备添加到系统中,使其立即处于活动状态。
     * 
     * @param p 设备的 cdev 结构
     * @param dev 此设备负责的设备号的第一个
     * @param count 与此设备对应的连续次要号码的数量
     * @return 如果失败,则返回负错误代码 
     */
    int cdev_add (struct cdev * p, dev_t dev, unsigned count);
    
  • cdev_del

    /**
     * @brief 从系统中删除设备 p,可能释放结构本身
     * 
     * @param p 要删除的 cdev 结构
     */
    void cdev_del (struct cdev * p);
    

相关文章

网友评论

      本文标题:字符设备

      本文链接:https://www.haomeiwen.com/subject/sfwzxdtx.html