device_create ()详解

本文介绍了在驱动程序初始化入口函数中,向内核注册设备后注册类的操作。还提及从Linux内核2.6某版本后,udev替代devfs,加入udev支持的方法。同时详细讲解了class_create和class_device_create函数的用法,以及相关内核源码中设备文件添加目录的处理逻辑。

在驱动程序中初始化入口函数中,向内核注册一个设备后,往往要注册一个类
例如
static int __init mydriver_init(void) //驱动程序的初始化
{  
   ……
    MYDRIVER_Major = register_chrdev(0, DEVICE_NAME, &mydriver_fops); //向内核注册一个设备,返回值为注册的主设备号
    if (MYDRIVER_Major < 0)
    {
        printk(DEVICE_NAME " can't register major number\n");
        return MYDRIVER_Major;
    }
    ……
    mydriver_class = class_create(THIS_MODULE, DEVICE_NAME); 
//注册一个类,使mdev可以在"/dev/"目录下 面建立设备节点
    ……
    //创建一个设备节点,节点名为DEVICE_NAME
    device_create(mydriver_class, NULL, MKDEV(MYDRIVER_Major, 0), NULL, DEVICE_NAME);
    ……
}

从linux内核2.6的某个版本之后,devfs不复存在,udev成为devfs的 替代。相比devfs,udev有很多优势,在此就不罗嗦了,提醒一点,udev是应用层的东东,不要试图在内核的配置选项里找到它;加入对udev的支 持很简单,以作者所写的一个字符设备驱动为例,在驱动初始化的代码里调用class_create为该设备创建一个class,再为每个设备调用 class_device_create创建对应的设备。大致用法如下:
struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);
这样的module被加载时,udev daemon就会自动在/dev下创建my_device设备文件


class_create()
-------------------------------------------------
linux-2.6.22/include/linux/device.h
struct class *class_create(struct module *owner, const char *name)
    class_create - create a struct class structure
    @owner: pointer to the module that is to "own" this struct class
    @name: pointer to a string for the name of this class.
在/sys/class/下创建类目录

class_device_create()
-------------------------------------------------
linux-2.6.22/include/linux/device.h
struct class_device *class_device_create(struct class        *cls,
                                         struct class_device *parent,
                                         dev_t               devt,
                                         struct device       *device,
                                         const char          *fmt, ...)

    class_device_create - creates a class device and registers it with sysfs
    @cls: pointer to the struct class that this device should be registered to.
    @parent: pointer to the parent struct class_device of this new device, if any.
    @devt: the dev_t for the char device to be added.
    @device: a pointer to a struct device that is assiociated with this class device.
    @fmt: string for the class device's name

 

对于没有指定dev->parent的dev都将被添加到/sys/devices/virtual/tty/ 目录下,如果指定了dev->parent,那么同时该dev->class存在,同时parent->class存在,那么该dev->name目录将被添加到parent->class所在目录下

****@*****:~$ ls -a /sys/class/tty/console
lrwxrwxrwx 1 root root 0 2009-06-30 09:40 /sys/class/tty/console->../../devices/virtual/tty/console
****@*****:~$ ls -a/sys/devices/virtual/tty/console/
total 0
-rw-r--r-- 1 root root 4.0K 2009-06-30 10:51 uevent
drwxr-xr-x 2 root root 0 2009-06-30 10:51 power
lrwxrwxrwx 1 root root 0 2009-06-30 10:57 subsystem-> ../../../../class/tty
-r--r--r-- 1 root root 4.0K 2009-06-30 10:57 dev

来看看linux2.6.25内核源码,是怎么做得.

device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1),"console");
==>device_register
==>device_add
==>setup_parent
==>get_device_parent
==>dev->kobj.parent= kobj("/sys/devices/virtual/tty");
//所以所有的文件添加都将指向该目录

#ifdef CONFIG_SYSFS_DEPRECATED
static struct kobject *get_device_parent(struct device*dev,
                    struct device *parent)
{
    
    if (dev->class&& (!parent || parent->class!= dev->class))
        return &dev->class->subsys.kobj;
    
    else if (parent)
        return &parent->kobj;

    return NULL;
}
#else
static struct kobject*get_device_parent(struct device *dev,
                    struct device *parent)
{
    int retval;

    if (dev->class){
        struct kobject *kobj = NULL;
        struct kobject *parent_kobj;
        struct kobject *k;

        

        if (parent== NULL)
            parent_kobj= virtual_device_parent(dev);
// 获取/sys/devices/virtual目录对应的kobj
        else if(parent->class)
            return&parent->kobj;
        else
            parent_kobj= &parent->kobj;

        
        spin_lock(&dev->class->class_dirs.list_lock); // class->class_dirs本身就是一个kset
       

        
// 如果该kset的list链表上没有挂接到/sys/devices/virtual目录上的son,那么说明该class_dirs还没有在
        
// /sys/devices/virtual目录下创建,所以就需要创建该class名对应的目录
        list_for_each_entry(k,&dev->class->class_dirs.list, entry)
            if(k->parent == parent_kobj){
                kobj= kobject_get(k);
                break;
            }
        spin_unlock(&dev->class->class_dirs.list_lock);
        if (kobj)
            return kobj;
        
// 创建/sys/devices/virtual/tty这个tty_class对应的目录
        
        k = kobject_create();
        if (!k)
            returnNULL;
        k->kset= &dev->class->class_dirs;

// 名在/sys/devices/virtual/目录下创建以tty_class的name为目录名的目录[luther.gliethttp]

        retval = kobject_add(k, parent_kobj,"%s", dev->class->name);
// 将kobj添加到parent_kobj对应目录下
        if (retval< 0) {
            kobject_put(k);
            returnNULL;
        }
        
        return k;
    }
    if (parent)
        return &parent->kobj;
    return NULL;
}
#endif

<think>首先,用户的问题是:"我想获取Android 11系统中device_create函数的解析"。用户指定了Android 11系统。 根据系统级指令,我需要: - 使用$...$格式的行内数学表达式,但这个主题是关于Linux内核函数的,可能不涉及数学表达式。所以,如果没有必要,我可以省略数学部分。 - 独立公式使用$$...$$,但同样,可能不需要。 - LaTeX语法正确:在代码块中,我应该确保代码格式正确。 - 使用中文回答。 - 生成相关问题:在回答末尾,添加相关的问题。 - 引用的段落末尾添加引用标识:[^1], [^2], 等。 用户提供了三个引用: - 引用[1]: 关于device_create()的函数原型和功能。 - 引用[2]: 关于DEVICE_ATTR宏的详解。 - 引用[3]: 关于dtb解析和platform_device创建过程。 用户说:"上述引用仅供参考,并不是用户真正的需求",所以我不能直接复制这些引用。我需要基于这些引用和Android 11系统来解析device_create函数。 用户上一次的问题可能是我回答的快速排序示例,但那是示例,不是实际对话历史。用户消息开头说:"参考站内引用",意思是参考这些引用。 所以,对于device_create函数解析: - device_create是一个Linux内核函数,用于在sysfs中创建设备节点。 - Android 11基于Linux内核,通常是4.x或5.x版本。我需要确认Android 11的内核版本。 - 回想一下:Android 11大约在2020年发布,内核版本可能是4.14或5.x。我应该基于通用Linux内核来解释,因为Android内核是定制的。 关键点: - device_create函数原型:struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...); - 参数: - class: 设备所属的类别。 - parent: 父设备,可选。 - devt: 设备号。 - drvdata: 驱动程序特定的数据。 - fmt: 格式字符串,用于设备名称(可变参数)。 - 功能:创建一个设备实例并将其添加到sysfs文件系统中。 在Android中,device_create用于设备驱动程序创建设备节点,以便用户空间通过sysfs或dev节点访问。 用户提到Android 11,所以我应该强调在Android环境下的使用。但device_create是内核函数,所以解析本质上是内核级别的。 引用[2]提到DEVICE_ATTR,这与sysfs属性相关,device_create会创建sysfs条目。 引用[3]关于dtb解析,可能与设备树相关,但device_create不是直接用于dtb解析;它是用于驱动程序创建设备。 结构化回答: 1. **介绍device_create函数**:解释其作用和背景。 2. **函数原型和参数**:详细解析每个参数。 3. **在Android 11中的使用**:讨论Android内核版本和具体应用。 4. **示例或代码片段**:提供简单的代码示例。 5. **注意事项**:如错误处理、权限等。 6. **相关问题**:生成相关问题。 使用中文回答。 确认Android 11内核版本:Android 11通常使用Linux内核4.14或5.4。我可以假设为4.x或5.x,通用解释。 生成相关问题: - 例如:如何在Android驱动中使用device_create? - device_create与class_create的关系? - sysfs在Android中的作用? 引用标识:在引用内容后加[^1], [^2]。用户提供的引用有编号,所以我应该使用它们。 用户说:"上述引用仅供参考",所以我需要基于它们构建回答,但不是直接复制。 回答结构: - 开头解释device_create。 - 然后解析原型参数。 - 讨论在Android中的使用。 - 可能添加代码片段。 - 结尾相关问题。 </think>### Android 11系统中 device_create() 函数解析 在Android 11系统中,`device_create()` 是一个关键的Linux内核函数,用于在sysfs文件系统中动态创建设备节点。Android 11基于Linux内核(通常为4.14或5.x版本),该函数在设备驱动程序开发中扮演核心角色,允许用户空间通过 `/sys/class/` 目录访问和控制硬件设备。以下是针对Android 11环境的详细解析: #### 1. **device_create() 的功能与作用** - **核心功能**:`device_create()` 创建一个设备实例(`struct device`),并将其注册到sysfs中,自动生成对应的设备节点(如 `/sys/class/class_name/device_name`)。这便于用户空间应用通过sysfs属性文件(如读写设备状态)进行交互。 - **在Android中的重要性**:在Android 11中,许多硬件驱动(如传感器、GPIO、显示驱动)使用此函数动态创建设备节点,支持HAL(Hardware Abstraction Layer)层的实现。例如,传感器驱动调用 `device_create()` 后,应用可以通过 `/sys/class/sensors/` 路径访问数据。 - **背景依赖**:该函数通常与 `class_create()` 配合使用。首先用 `class_create()` 创建一个设备类别(class),然后调用 `device_create()` 在此类别下添加具体设备[^1]。 #### 2. **函数原型与参数解析** 在Linux内核头文件 `include/linux/device.h` 中定义的原型如下(适用于Android 11内核版本如4.14): ```c struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...); ``` - **参数详解**: - `class *class`:设备所属的类别指针,必须通过 `class_create()` 预先创建。例如,Android传感器驱动可能使用 `class_create(THIS_MODULE, "sensors")` 创建的类别。 - `parent *parent`:父设备的指针,用于设备树层次结构。在Android中,常为NULL(表示无父设备)或指向platform_device对象(如SoC总线设备)[^3]。 - `dev_t devt`:设备号,标识设备的major和minor号(使用 `MKDEV(ma, mi)` 宏生成)。在Android驱动中,通常通过 `alloc_chrdev_region()` 分配。 - `void *drvdata`:驱动程序私有数据指针,可存储设备特定信息(如寄存器地址)。Android驱动中常用于传递HAL相关上下文。 - `const char *fmt, ...`:可变参数格式字符串,用于定义设备名称(如 `"sensor_accel"`)。支持类似 `printf` 的格式化(如 `%s` 用于动态命名)。 - **返回值**:成功时返回指向 `struct device` 的指针;失败时返回 `ERR_PTR()` 错误码(如 `-ENOMEM` 内存不足)。 在Android 11中,内核配置可能影响参数行为,例如设备树(DTB)解析产生的 `parent` 参数常用于嵌入式设备总线初始化[^3]。 #### 3. **在Android 11中的使用流程** Android驱动中调用 `device_create()` 的典型步骤如下(以伪代码形式展示): 1. **创建设备类别**:使用 `class_create()` 建立sysfs类别。 2. **创建设备节点**:调用 `device_create()` 在类别下添加设备。 3. **添加属性文件**:可选步骤,使用 `DEVICE_ATTR` 宏定义sysfs属性文件(如读写权限),并通过 `device_create_file()` 绑定到设备[^2]。 ```c /* 示例:Android传感器驱动代码片段 */ #include <linux/device.h> #include <linux/fs.h> static struct class *sensor_class; static dev_t sensor_dev; static int __init sensor_driver_init(void) { // 分配设备号 alloc_chrdev_region(&sensor_dev, 0, 1, "sensor"); // 创建设备类别 sensor_class = class_create(THIS_MODULE, "android_sensor"); if (IS_ERR(sensor_class)) return PTR_ERR(sensor_class); // 创建设备节点 (名称格式为"sensor_accel0") struct device *dev = device_create(sensor_class, NULL, sensor_dev, NULL, "sensor_accel%d", 0); if (IS_ERR(dev)) { class_destroy(sensor_class); return PTR_ERR(dev); } // 可选:添加属性文件 (例如,读写校准数据) DEVICE_ATTR(calibration, 0644, show_calibration, store_calibration); device_create_file(dev, &dev_attr_calibration); return 0; } static void __exit sensor_driver_exit(void) { device_destroy(sensor_class, sensor_dev); class_destroy(sensor_class); unregister_chrdev_region(sensor_dev, 1); } module_init(sensor_driver_init); module_exit(sensor_driver_exit); ``` - **Android特定点**: - **内核版本兼容**:Android 11内核(如4.14)可能包含安全补丁,确保 `device_create()` 的权限检查更严格(例如,sysfs文件权限需遵循SELinux策略)。 - **性能优化**:在启动过程中,`device_create()` 常用于解析设备树(DTB)生成的platform_device对象,减少静态设备注册开销[^3]。 - **错误处理**:失败时应返回错误码,Android驱动必须处理资源泄漏风险(如使用 `IS_ERR()` 检查)。 #### 4. **注意事项与常见问题** - **权限和安全**:在Android中,sysfs属性文件的权限(如 `mode` 参数)需符合SELinux策略。例如,用户空间应用访问设备节点时,权限不足可能导致访问拒绝。 - **内存管理**:`device_create()` 返回的设备指针必须通过 `device_destroy()` 释放,否则在驱动卸载时会导致内核内存泄漏[^1]。 - **调试技巧**:Android内核日志(使用 `pr_debug()` 或 `printk()`)可追踪设备创建过程。例如,日志输出 `create child: /soc/bus@xxx` 帮助调试设备树层级[^3]。 - **替代函数**:在较新内核中,`device_create()` 可能被推荐使用 `device_create_with_groups()` 以支持属性组。 总之,在Android 11中,`device_create()` 是驱动开发的核心API,确保sysfs设备节点的动态管理。开发者应参考Android内核源码(如 `kernel/drivers/base/core.c`)和文档以适配具体硬件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值