struct device的成员变量bus_id到哪里去了?

本文探讨了在Linux内核编程中遇到的device结构体bus_id成员变量问题,通过对比init_name和bus_id的区别,解释了如何正确地进行设备名称初始化及匹配,最终解决了设备注册过程中的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


struct device的成员变量bus_id到哪里去了?


http://zhuzhenzhong123.blog.163.com/blog/static/198862752011101825626662/


    在做bus驱动实验的时候,出现了一个问题:
提示bus_id找不到。于是到内核源代码找了一番,果然没有看见。直接到device结构体中看,找到的最像的也就
const char *init_name; /* initial name of the device */
想到这个也可以作为标识,并且BUS_ID_SIZE也找不到,于是将strncpy(my_dev.init_name, "my_dev", BUS_ID_SIZE);注释掉,直接在mydev中添

加.init_name="my_dev"。
    但是在注册驱动时又出现了段错误,根据console打印,知道在strncmp时,也就是总线在比较驱动和设备的名字的时候出问题了。
于是在比较函数里加入
printk("dev->init_name:%s\tdriver->name:%s\n", dev->init_name, driver->name);
想看看到底是怎么比较的。结果console上打印出来的是
dev->init_name:<NULL>   driver->name:my_dev (与下面亮点关联)
Unable to handle kernel NULL pointer dereference at virtual address 00000000
dev->init_name不存在?
    于是baidu了一下,发现了了下面网友的那段,我用对了init_name,却没直接在内核里搜到dev_name(dev),于是又在内核搜索一番。可以找到下面一段总线上的比较函数:
static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
{
    struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
    int len = strlen(sub->wanted);

    if (0 == strncmp(dev_name(dev), sub->wanted, len))
    return 1;
    return 0;
}
它用的是dev_name(dev)而不是dev->init_name。还是在match函数里加入输出语句,打印如下:
dev_name(dev):my_dev       driver->name:my_dev
成功了!

    那我们深究下,dev_name()是什么东东呢?
static inline const char *dev_name(const struct device *dev)
{
    return kobject_name(&dev->kobj);
}
├───static inline const char *kobject_name(const struct kobject *kobj)
    {
        return kobj->name;
    }
其实就是kobj->name;
dev_name(dev)怎么和dev->kobj-name联系上的呢?找遍“可见”代码找不到,猜测很可能是在device_register里面。
从源码里顺蔓摸瓜:

└─device_register
    └─device_add
        └─if (dev->init_name)
            {
                dev_set_name(dev, "%s", dev->init_name);
                dev->init_name = NULL; (亮点!)
            }
                dev_set_name
                └─kobject_set_name_vargs (看到希望了!)
                    └─kobj->name= kvasprintf(GFP_KERNEL, fmt, vargs);(找到了,这个就是的了!) 
找到了!就是在注册设备的时候将init_name成员赋给了kobj->name,发现那个"亮点"没,不是说说写得有多漂亮(也不是说写得不漂亮,纠结了。。),“亮

点”的意思是发现了新大陆那种感觉,越说越远。。看到前面我为了查错误从控制台打出来的信息,dev->init_name:<NULL>   driver->name:my_dev中,dev-

>init_name等于NULL就是在这个dev->init_name = NULL;“亮点”的地方被置空了。这也是为什么用strncmp比较会出错的原因。

要感谢下面这个网友,才想到要到内核去搜一下dev_name。内核版本号不同,必然有一些改动,当我们发现不同后,要善于从中去找到不同,找到解决问题的方

法。

以下是转载自
网友ying_seven的博客(看到其也是转载的,但是并没有注明来处)

--------------------------------------------------------------------------------------------------------------------------
按照国嵌的代码(LDD那本书上的代码也一样):
struct device my_bus = {
    .bus_id = "my_bus0",
    .release = my_bus_release,
};

static int my_match(struct device *dev, struct device_driver *driver)
{
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

编译时,提示 struct device 中没有bus_id 这样的错误。打开/lib/modules/2.6.35-28-generic/build/include/linux/device.h
找到struct device  的定义,里面没有bus_id,但有:
const char *init_name; /* initial name of the device */                      这句。

可见,要把上面结构中的.bus_id = "my_bus0",         改为       .init_name = "my_bus0",
同时上网搜到,return !strncmp(dev->bus_id, driver->name, strlen(driver->name));这句也要改成:
return !strncmp(dev_name(dev), driver->name, strlen(driver->name));

这样编译即可成功!

另注:
如果要设置设备的名字,也不再使用strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);     而改用:
dev_set_name(&dev, "name");












C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c: In function 'lvgl_init': C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c:285:62: error: 'bus_rtc_handle' undeclared (first use in this function); did you mean 'dev_rtc_handle'? 285 | ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_rtc_config, &bus_rtc_handle)); | ^~~~~~~~~~~~~~ C:/Espressif/frameworks/esp-idf-v5.4/components/esp_common/include/esp_err.h:116:30: note: in definition of macro 'ESP_ERROR_CHECK' 116 | esp_err_t err_rc_ = (x); \ | ^ C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c:285:62: note: each undeclared identifier is reported only once for each function it appears in 285 | ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_rtc_config, &bus_rtc_handle)); | ^~~~~~~~~~~~~~ C:/Espressif/frameworks/esp-idf-v5.4/components/esp_common/include/esp_err.h:116:30: note: in definition of macro 'ESP_ERROR_CHECK' 116 | esp_err_t err_rc_ = (x); \ | ^ C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c:296:77: error: passing argument 3 of 'i2c_master_bus_add_device' from incompatible pointer type [-Wincompatible-pointer-types] 296 | ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_rtc_handle, &dev_rtc_cfg, &dev_rtc_handle)); | ^~~~~~~~~~~~~~~ | | | struct i2c_master_bus_t ** C:/Espressif/frameworks/esp-idf-v5.4/components/esp_common/include/esp_err.h:116:30: note: in definition of macro 'ESP_ERROR_CHECK' 116 | esp_err_t err_rc_ = (x); \ | ^ In file included from C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c:13: C:/Espressif/frameworks/esp-idf-v5.4/components/esp_driver_i2c/include/driver/i2c_master.h:97:137: note: expected 'struct i2c_master_dev_t **' but argument is of type 'struct i2c_master_bus_t **' 97 | esp_err_t i2c_master_bus_add_device(i2c_master_bus_handle_t bus_handle, const i2c_device_config_t *dev_config, i2c_master_dev_handle_t *ret_handle); | ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~ C:/TPC/IOT/LVGL_test/LVGLtest_inv_iic/ESP32_Project/main/lvgl_init.c:299:24: error: passing argument 1 of 'i2c_master_receive' from incompatible pointer type [-Wincompatible-pointer-types] 299 | i2c_master_receive(dev_rtc_handle, data_rd, 1, -1); | ^~~~~~~~~~~~~~ | | | i2c_master_bus_handle_t {aka struct i2c_master_bus_t *} C:/Espressif/frameworks/esp-idf-v5.4/components/esp_driver_i2c/include/driver/i2c_master.h:193:54: note: expected 'i2c_master_dev_handle_t' {aka 'struct i2c_master_dev_t *'} but argument is of type 'i2c_master_bus_handle_t' {aka 'struct i2c_master_bus_t *'} 193 | esp_err_t i2c_master_receive(i2c_master_dev_handle_t i2c_dev, uint8_t *read_buffer, size_t read_size, int xfer_timeout_ms); | ~~~~~~~~~~~~~~~~~~~~~~~~^
最新发布
06-06
### 关于 `struct device_driver` 的使用说明 #### 结构定义与作用 `struct device_driver` 是 Linux 设备模型的核心组成部分之一,主要用于表示设备驱动程序的信息。该结构体包含了多个字段来描述驱动的行为以及它所支持的特定操作[^4]。 ```c struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); // ...其他成员... }; ``` - **name**: 驱动名称,在系统中唯一标识此驱动。 - **bus**: 所属总线类型指针,表明该驱动属于哪个硬件通信协议下的设备类别。 - **owner**: 加载模块的所有者信息。 - **mod_name**: 模块名字符串常量。 - **probe/remove/shutdown**: 对应不同生命周期阶段的操作回调函数原型声明。 #### 注册过程 当创建并初始化好一个具体的 `platform_driver` 或者其他的某种类型的驱动实例之后(比如 PCI、I2C),就需要将其注册到内核当中以便能够被发现和匹配相应的物理设备。这通常通过调用诸如 `platform_driver_register()` 来完成,而这些高层API最终会调用通用接口 `_driver_register()` 完成实际工作[^5]。 对于自定义实现来说,则可以直接利用如下方式: ```c static struct platform_driver my_platform_driver = { .probe = my_probe, .remove = my_remove, .driver = { .name = "my-device", .of_match_table = of_match_ptr(my_of_match), }, }; module_platform_driver(my_platform_driver); ``` 上述代码片段展示了如何构建一个基于平台总线(`platform`)上的简单驱动框架,并且关联了一个 Open Firmware (OF) 节点表用于自动识别兼容性的设备节点[^1]。 #### 实际应用案例分析 考虑 I2C 总线下传感器类设备的情况,这里展示了一部分关于设置其对应 `device` 属性的例子: ```c client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; ``` 这段代码来自某处具体场景下对 I2C 客户端对象 (`struct i2c_client`) 中嵌入式的 `struct device dev` 成员变量进行了必要的配置,使其可以正确参与到整个系统的资源管理和事件处理机制之中[^3]。 #### 初始化顺序概述 从内核启动直至所有基础服务准备就绪期间,存在一系列精心设计好的初始化步骤确保各个组件按需加载和服务可用性。其中涉及到的关键环节包括但不限于执行 `start_kernel()` 函数链路直到最后一步显式调用了全局范围内的 `driver_init()` 方法,从而正式开启了各类驱动器向核心层登记的过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值