1. class结构体介绍

内核中定义了struct class结构体,一个struct class 结构体类型变量对应一个类,内核同时提供了class_create()函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建了这个类,再调用device_create()函数在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create()函数,去/sysfs下寻找对应的类而创建设备节点。
struct class结构体(2.6.26.6内核版本)

struct class {
    const char *name;
    struct module *owner;
    struct class_attribute *class_attrs;
    struct device_attribute *dev_attrs;
    struct bin_attribute *dev_bin_attrs;
    struct kobject *dev_kobj;

    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, mode_t *mode);
    void (*class_release)(struct class *class);
    void (*dev_release)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);

    const struct kobj_ns_type_operations *ns_type;
    const void *(*namespace)(struct device *dev);

    const struct dev_pm_ops *pm;
    struct subsys_private *p;
};

继续阅读

1. 结构体

内核中每个字符设备都对应一个 cdev结构的变量,下面是它的定义:

linux-2.6.22/include/linux/cdev.h
struct cdev {
    struct kobject kobj;                // 每个 cdev都是一个 kobject
    struct module *owner;               //指向实现驱动的模块
    const struct file_operations *ops;  // 操纵这个字符设备文件的方法
    struct list_head list;              // 与 cdev对应的字符设备文件的inode->i_devices的链表头
    dev_t dev;                          // 起始设备编号
    unsigned int count;                 // 设备范围号大小
};

继续阅读

1. 字符设备结构体

内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里。该散列表中的每一个元素是一个 char_device_struct 结构,它的定义如下:

   static struct char_device_struct {
       struct char_device_struct *next;    // 指向散列冲突链表中的下一个元素的指针
       unsigned int major;                 // 主设备号
       unsigned int baseminor;             // 起始次设备号
       int minorct;                        // 设备编号的范围大小
       char name[64];                      // 处理该设备编号范围内的设备驱动的名称
       struct file_operations *fops;       // 没有使用
       struct cdev *cdev;                  // 指向字符设备驱动程序描述符的指针
   } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

继续阅读

大概步骤

一、 注册设备号

# 注册函数:
    regsiter_chrdev_region()
    alloc_chrdev_region() 或           查看#cat /proc/devices
    register_chrdev()
# 注销函数:
    unregist_chrdev_region() 或
    unregister_chrdev()

二、初始化cdev并添加到系统

# 初始化cdev
    cdev_init()   // 静态初始化
    cdev_alloc()  // 动态初始化
# 添加到系统函数
    cdev_add()
# 从系统删除函数
    cdev_del()

三、创建设备节点

# 创建类
    class_create()  // 将放于/sysfs      查看#ls /sys/class
# 删除类
    class_destroy()
        
# 创建节点
    device_create() 或 class_device_create()  // 将存放于/dev  查看#ls /dev
# 删除节点
    device_destroy() 或 class_device_destroy()

继续阅读

在字符设备驱动开发的入门教程中,最常见的就是用device_create()函数来创建设备节点了,但是在之后阅读内核源码的过程中却很少见device_create()的踪影了,取而代之的是device_register()与device_add(),将device_create()函数展开不难发现:其实device_create()只是device_register()的封装,而device_register()则是device_add()的封装。
继续阅读