platform_device_add()函数分析

本文详细解析了Linux中platform_device_add函数的工作原理,包括设备验证、资源分配与释放过程等关键步骤,帮助读者理解设备如何在平台总线上注册。

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

int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;

if (!pdev)    /*验证指针的有效性 */
   return -EINVAL;

if (!pdev->dev.parent)/*都说总线有两个链表,一个是设备链表(通过device 内嵌)一个是驱动链表(通过device_driver内嵌)这里如果pdev->dev.parent为0,说明设备链表还没有设备,因此处理办法是将platform_bus作为设备链表的开始,一直感觉platform_bus和platform_bus_type很难区分,不过在这里清楚了platform_bus是一个设备,platform_bus_type才是真正的总线*/
   pdev->dev.parent = &platform_bus;/*device 的父结点*/

pdev->dev.bus = &platform_bus_type;/*device 要挂接在platform_bus_type这个总线上拉,看到了,设备和总线是这么勾搭上滴,很直接,很干脆*/

if (pdev->id != -1)
   snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
    pdev->id);/*这个如果看不懂,可以参考LINUX的格式化输出的相关资料*/
else
   strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

for (i = 0; i < pdev->num_resources; i++) {
   struct resource *p, *r = &pdev->resource[i];

   if (r->name == NULL) /*name一般为NULL*/
    r->name = pdev->dev.bus_id; /*资源的名称赋值为pdev->dev.bus_id,如果一个platform_device有多个resource 则出现同名现象*/

   p = r->parent;
   if (!p) {   /*父资源为0,说明不是从一个大的资源里面切割出来的*/
    if (r->flags & IORESOURCE_MEM)
     p = &iomem_resource;
    else if (r->flags & IORESOURCE_IO)
     p = &ioport_resource;
   }

   if (p && insert_resource(p, r)) { /*如果从父资源里面切割失败,则进行如下处理*/
    printk(KERN_ERR
          "%s: failed to claim resource %d/n",
          pdev->dev.bus_id, i);
    ret = -EBUSY;
    goto failed;
   }
}

pr_debug("Registering platform device '%s'. Parent at %s/n",
   pdev->dev.bus_id, pdev->dev.parent->bus_id);

ret = device_add(&pdev->dev);/*资源也分配好了,准备工作也做足,终于可以把设备添加到设备链表里面了*/
if (ret == 0)
   return ret;

failed: /*失败处理*/
while (--i >= 0)
   if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
    release_resource(&pdev->resource[i]);
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);

### 查看 `platform_device` 类型定义的方法 在 Linux 内核源码中,`platform_device` 是一种用于表示平台总线上的设备的数据结构。要了解其类型定义,可以通过以下方法: #### 方法一:查阅内核源码头文件 `platform_device` 的定义位于内核源码中的 `<linux/platform_device.h>` 文件中。以下是其基本定义[^1]: ```c struct platform_device { const char *name; int id; bool dev_attr_init; struct device.dev; u32 num_resources; struct resource *resource; const struct platform_device_id *id_entry; void *dev.platform_data; struct dev_pm_ops *pmops; }; ``` 此结构体包含了描述平台设备所需的关键字段,例如设备名称 (`name`)、资源列表 (`resource`) 和关联数据 (`platform_data`)。 --- #### 方法二:通过交叉引用工具查找 可以使用诸如 `ctags` 或 `cscope` 这样的工具来快速定位 `platform_device` 的定义位置。具体操作如下: 1. 使用命令生成标签数据库: ```bash ctags -R . ``` 2. 查询 `platform_device` 的定义: ```bash vi -t platform_device ``` 这会直接跳转到 `<linux/platform_device.h>` 中的定义处[^4]。 --- #### 方法三:在线文档查询 如果无法访问本地源码,也可以通过官方文档或社区网站(如 LXR)搜索 `platform_device` 的定义。这些资源通常提供完整的结构体说明以及相关函数的用法[^2]。 --- #### 关键函数与用途 除了查看定义外,还需要理解与其相关的常用函数。例如: - **注册设备**:`platform_add_devices()` 用于将一组 `platform_device` 添加到系统中。 - **注册驱动程序**:`platform_driver_register()` 将驱动程序绑定到特定类型的 `platform_device` 上[^3]。 --- ### 示例代码展示 下面是一个简单的示例,演示如何定义并注册一个 `platform_device`: ```c #include <linux/platform_device.h> #include <linux/init.h> static struct resource example_resource[] = { [0] = { .start = 0x1000, .end = 0x1FFF, .flags = IORESOURCE_MEM, }, }; static struct platform_device example_platform_device = { .name = "example-device", .id = -1, .num_resources = ARRAY_SIZE(example_resource), .resource = example_resource, }; static int __init example_init(void) { return platform_device_register(&example_platform_device); } module_init(example_init); static void __exit example_exit(void) { platform_device_unregister(&example_platform_device); } module_exit(example_exit); ``` 上述代码片段展示了如何创建和注册一个名为 `"example-device"` 的平台设备。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值