linux_driver自动创建节点的解析

本文详细解释了如何在驱动程序中加入udev支持,通过在内核中定义类和设备,自动创建设备节点。重点介绍了structclass、class_create()、device_create()等关键函数的使用,并以字符设备驱动为例进行演示。

                                                                        自动创建节点的解析

       在驱动用加入对udev的支持主要做的就是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...)( 在2.6较早的内核中用class_device_create)创建对应的设备。

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

struct class定义在头文件include/linux/device.h中class_create(…)在/drivers/base/class.c中实现device_create(…)函数在/drivers/base/core.c中实现class_destroy(...),device_destroy(...)也在/drivers/base/core.c中实现调用过程类似如下:

static struct class *spidev_class;
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
        ....
        dev = device_create(spidev_class, &spi->dev, spidev->devt,
                spidev, "spidev%d.%d",
                spi->master->bus_num, spi->chip_select);
        ...
}
 
static int spidev_remove(struct spi_device *spi)
{
    ......
    device_destroy(spidev_class, spidev->devt);
    .....
 
    return 0;
}
 
static struct spi_driver spidev_spi = {
    .driver = {
        .name =        "spidev",
        .owner =    THIS_MODULE,
    },
    .probe =    spidev_probe,
    .remove =    __devexit_p(spidev_remove),
 
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
    ....
    spidev_class = class_create(THIS_MODULE, "spidev");
    if (IS_ERR(spidev_class)) {
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
        return PTR_ERR(spidev_class);
    }
    ....
}
module_init(spidev_init);
 
static void __exit spidev_exit(void)
{
    ......
    class_destroy(spidev_class);
    ......
}
module_exit(spidev_exit);
 
MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");
 
下面www.linuxidc.com 以一个简单字符设备驱动来展示如何使用这几个函数 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
 
int HELLO_MAJOR = 0;
int HELLO_MINOR = 0;
int NUMBER_OF_DEVICES = 2;
 
struct class *my_class;
struct cdev cdev;
dev_t devno;
 
struct file_operations hello_fops = {
 .owner = THIS_MODULE
};
 
static int __init hello_init (void)
{
    int result;
    devno = MKDEV(HELLO_MAJOR, HELLO_MINOR);
    if (HELLO_MAJOR)
        result = register_chrdev_region(devno, 2, "memdev");
    else
    {
        result = alloc_chrdev_region(&devno, 0, 2, "memdev");
        HELLO_MAJOR = MAJOR(devno);
    }  
    printk("MAJOR IS %d\n",HELLO_MAJOR);
    my_class = class_create(THIS_MODULE,"hello_char_class");  //类名为hello_char_class
    if(IS_ERR(my_class)) 
    {
        printk("Err: failed in creating class.\n");
        return -1; 
    }
    device_create(my_class,NULL,devno,NULL,"memdev");      //设备名为memdev
    if (result<0) 
    {
        printk (KERN_WARNING "hello: can't get major number %d\n", HELLO_MAJOR);
        return result;
    }
 
    cdev_init(&cdev, &hello_fops);
    cdev.owner = THIS_MODULE;
    cdev_add(&cdev, devno, NUMBER_OF_DEVICES);
    printk (KERN_INFO "Character driver Registered\n");
    return 0;
}
 
static void __exit hello_exit (void)
{
    cdev_del (&cdev);
    device_destroy(my_class, devno);         //delete device node under /dev//必须先删除设备,再删除class类
    class_destroy(my_class);                 //delete class created by us
    unregister_chrdev_region (devno,NUMBER_OF_DEVICES);
    printk (KERN_INFO "char driver cleaned up\n");
}
 
module_init (hello_init);
module_exit (hello_exit);
 
MODULE_LICENSE ("GPL");
这样,模块加载后,就能在/dev目录下找到memdev这个设备节点了。

<think>我们正在分析一个Linux内核驱动中的平台驱动结构体定义:`static struct platform_driver gimgsensor_platform_driver`。这个结构体在摄像头传感器驱动中扮演核心角色。 ### 结构体定义解析Linux内核中,`platform_driver`是用于平台设备驱动的关键数据结构。其典型定义如下(参考引用[2][3]): ```c struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe; }; ``` ### 驱动注册流程 摄像头驱动通常通过`module_platform_driver`宏注册(参考引用[4][5]): ```c static struct platform_driver gimgsensor_platform_driver = { .probe = imgsensor_probe, .remove = imgsensor_remove, .driver = { .name = "image_sensor", .owner = THIS_MODULE, .of_match_table = gimgsensor_dt_match, // 设备树匹配表 } }; module_platform_driver(gimgsensor_platform_driver); ``` ### 核心作用说明 1. **设备探测入口** 当内核检测到与`.driver.of_match_table`匹配的设备节点时,自动触发`imgsensor_probe`函数[^1][^3]: ```c static struct of_device_id gimgsensor_dt_match[] = { {.compatible = "mediatek,imgsensor"}, // 匹配设备树中的compatible属性 {} }; ``` 2. **资源初始化中心** `probe`函数负责: - 初始化传感器硬件(电源/时钟/MIPI配置)[^1] - 注册字符设备或V4L2子设备(暴露给上层框架)[^5] - 构建传感器控制结构体(如设置分辨率/帧率控制函数) 3. **生命周期管理** - `remove`: 卸载驱动时释放资源(如中断/内存映射)[^3] - `suspend/resume`: 实现电源管理(休眠时关供电,唤醒时重新初始化)[^2] ### 设备树匹配机制 驱动通过`.compatible`属性与硬件绑定(参考引用[1][4]): ```dts // 设备节点示例 camera_sensor: imgsensor@1a { compatible = "mediatek,imgsensor"; // 匹配驱动中的gimgsensor_dt_match reg = <0x1a>; pinctrl-names = "default"; reset-gpios = <&gpio 120 0>; }; ``` ### 设计优势 1. **硬件抽象** 将传感器操作(初始化/配置)封装在`probe`中,使驱动与具体SoC解耦[^5]。 2. **延迟加载** 仅当实际检测到硬件时才加载驱动,节省系统资源[^3]。 3. **多设备支持** 通过`id_table`支持多个兼容设备(如不同型号传感器共用驱动)[^2]。 ### 执行流程 ```mermaid graph LR A[insmod驱动模块] --> B[platform_driver_register] B --> C[扫描设备树匹配节点] C --匹配成功--> D[调用imgsensor_probe] D --> E[初始化MIPI/GPIO] D --> F[注册V4L2子设备] D --> G[创建sysfs控制接口] ``` ### 典型问题分析 若`probe`函数未执行,需检查: 1. 设备树`compatible`属性是否与驱动完全一致 2. 传感器供电/时钟是否在驱动加载前已使能 3. 是否因`prevent_deferred_probe`导致延迟初始化失败 §§相关问题§§ 1. 如何调试Linux驱动中probe函数未被调用的问题? 2. platform_driverdevice_driver有何区别? 3. 在probe函数中应该避免哪些操作? 4. 如何通过sysfs控制摄像头传感器参数? 5. 多摄像头系统中如何避免资源冲突?</think>### `static struct platform_driver gimgsensor_platform_driver` 的作用解析 #### 1. **核心定义与作用** ```c static struct platform_driver gimgsensor_platform_driver = { .probe = imgsensor_probe, // 设备匹配时调用 .remove = imgsensor_remove, // 设备移除时调用 .driver = { .name = "image_sensor", // 驱动标识名 .owner = THIS_MODULE, // 所属内核模块 .of_match_table = gimgsensor_dt_match, // 设备树匹配表 } }; ``` - **平台驱动注册**:该结构体用于向 Linux 内核注册一个**平台设备驱动**(Platform Driver),属于 Linux 设备驱动模型的核心组件[^4][^5]。 - **硬件抽象层**:通过平台总线(Platform Bus)实现驱动与硬件的解耦,使摄像头传感器驱动不直接依赖具体 SoC 硬件[^1]。 --- #### 2. **关键功能实现** ##### (1) **设备探测(Probe)** - **触发条件**:当设备树(Device Tree)中的节点与`.of_match_table`匹配时(如 `compatible = "mediatek,imgsensor"`),自动调用 `.probe` 函数[^1][^4]。 - **核心操作**: ```c int imgsensor_probe(struct platform_device *pdev) { // 1. 解析设备树资源(GPIO/时钟等) // 2. 初始化传感器硬件(MIPI配置、电源管理) // 3. 注册字符设备/V4L2子设备 // 4. 填充传感器操作函数集 } ``` 此函数是驱动初始化的核心入口[^3][^5]。 ##### (2) **设备移除(Remove)** - **触发条件**:驱动卸载或设备热拔插时调用 `.remove`。 - **资源释放**:注销设备、释放内存、关闭硬件资源[^3]。 ##### (3) **设备树匹配** ```c static const struct of_device_id gimgsensor_dt_match[] = { { .compatible = "mediatek,imgsensor" }, // 匹配设备节点 {} }; ``` 通过 `.compatible` 属性将驱动设备节点绑定,实现硬件描述与驱动分离[^1][^4]。 --- #### 3. **驱动注册方式** 通常通过宏简化注册: ```c module_platform_driver(gimgsensor_platform_driver); ``` 展开后等效于: ```c static int __init imgsensor_drv_init(void) { platform_driver_register(&gimgsensor_platform_driver); } static void __exit imgsensor_drv_exit(void) { platform_driver_unregister(&gimgsensor_platform_driver); } ``` 此方法自动处理模块加载/卸载的注册逻辑[^4][^5]。 --- #### 4. **设计优势** 1. **硬件无关性** 同一驱动可适配不同硬件平台(如高通/MTK),只需修改设备节点[^1]。 2. **延迟初始化** 仅当设备实际存在时才会调用 `probe`,节省系统资源[^3]。 3. **标准化电源管理** 可直接集成 `.suspend`/`.resume` 等电源管理函数[^2]。 --- #### 5. 执行流程示例 ```mermaid graph TB A[加载驱动模块] --> B[platform_driver_register] B --> C{匹配设备节点?} C -- 匹配成功 --> D[调用imgsensor_probe] D --> E[初始化传感器硬件] D --> F[注册V4L2子设备] C -- 无匹配 --> G[等待设备出现] ``` --- ### 常见应用场景 - **摄像头传感器驱动**:如 `imgsensor_probe` 中初始化 MIPI 接口、I²C 通信、图像格式配置[^5]。 - **复杂外设管理**:在 `probe` 中进一步注册子设备(如 miscdevice、V4L2 设备)[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值