共计 6549 个字符,预计需要花费 17 分钟才能阅读完成。
这篇文章主要介绍“Linux 平台总线驱动设备模型是什么”,在日常操作中,相信很多人在 Linux 平台总线驱动设备模型是什么问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux 平台总线驱动设备模型是什么”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!
platform 总线是一种虚拟的总线,相应的设备则为 platform_device,而驱动则为 platform_driver。Linux 2.6 的设备驱动模型中,把 I2C、RTC、LCD 等都归纳为 platform_device。
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动; 相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
Linux2.6 系统中定义了一个 bus_type 的实例 platform_bus_type
struct bus_type platform_bus_type = { .name = platform , .dev_attrs = platform_dev_attrs, .match = platform_match, // 设备和驱动使用 match 函数来判断是否匹配 .uevent = platform_uevent, .pm = PLATFORM_PM_OPS_PTR, };
/* platform_match 函数用于匹配总线中的驱动和设备 */ static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* match against the id table first */ if (pdrv- id_table) return platform_match_id(pdrv- id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev- name, drv- name) == 0); }
platform_match 函数首先判断是否由 id_table,如果有则使用 id_table 来进行匹配,否则,判断 platform_device 和 platform_driver 成员里的 name,如果二者的 name 字段相同则匹配,如果匹配则调用 platform_driver 的 probe 函数。
platform_device 结构体的定义
struct platform_device { const char * name; /* 名字 */ int id; struct device dev; u32 num_resources; /* 资源总数 */ struct resource * resource; /* 资源 */ struct platform_device_id *id_entry; };
其中有个重要的成员是 resource,是设备的资源信息,如 IO 地址,中断号等。
struct resource { resource_size_t start; // 资源的起始值 resource_size_t end; // 资源的结束值 const char *name; unsigned long flags; // 资源的类型,如 IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA struct resource *parent, *sibling, *child; };
有的设备可能有多个资源,通常使用 platform_get_resource 函数来获取资源
/** * platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type * @num: resource index */ struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) { int i; for (i = 0; i dev- num_resources; i++) { struct resource *r = dev- resource[i]; if (type == resource_type(r) num-- == 0) return r; } return NULL; }
平台设备的注册,使用 platform_device_register 函数
int platform_device_register(struct platform_device *pdev) { device_initialize( pdev- dev); return platform_device_add(pdev); }
platform_device_register 函数先通过 device_initialize 函数初始化 platform_device 的 device 成员,然后调用 platform_device_add 向内核添加一个平台设备。
int platform_device_add(struct platform_device *pdev) { int i, ret = 0; if (!pdev) /* 如果 pdev 为空则返回 EINVAL */ return -EINVAL; /* 如果 pdev- dev.parent 为空则将 pdev- dev.parent 设置为 platform_bus */ if (!pdev- dev.parent) pdev- dev.parent = platform_bus; pdev- dev.bus = platform_bus_type; /* 设置总线类型 */ if (pdev- id != -1) /* 如果 id = - 1 则表示自动分配 name */ dev_set_name(pdev- dev, %s.%d , pdev- name, pdev- else dev_set_name( pdev- dev, pdev- name); for (i = 0; i pdev- num_resources; i++) { struct resource *p, *r = pdev- resource[i]; /* 获取资源 */ if (r- name == NULL) r- name = dev_name(pdev- dev); p = r- parent; if (!p) { if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */ p = iomem_resource; else if (resource_type(r) == IORESOURCE_IO) p = ioport_resource; } if (p insert_resource(p, r)) { printk(KERN_ERR %s: failed to claim resource %d\n , dev_name( pdev- dev), i); ret = -EBUSY; goto failed; } } pr_debug(Registering platform device %s . Parent at %s\n , dev_name( pdev- dev), dev_name(pdev- dev.parent)); /* 向内核添加一个 device */ ret = device_add(pdev- dev); if (ret == 0) return ret; failed: while (--i = 0) { struct resource *r = pdev- resource[i]; unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r); } return ret; }
platform_device_add 最终调用 device_add 来完成平台设备的注册。
相反地,如果要注销平台设备则使用 platform_device_unregister 函数
void platform_device_unregister(struct platform_device *pdev) { platform_device_del(pdev); platform_device_put(pdev); }
platform_device_unregister 函数调用 platform_device_del 函数来注销平台设备
void platform_device_del(struct platform_device *pdev) { int i; if (pdev) { device_del( pdev- dev); for (i = 0; i pdev- num_resources; i++) { struct resource *r = pdev- resource[i]; unsigned long type = resource_type(r); if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r); } } }
platform_device_del 函数调用 device_del 函数来删除平台设备,相应地,要释放资源应调用 release_resource 函数,前提是资源的类型必须为 IORESOURCE_MEM 或者 IORESOURCE_IO
platform_driver 的定义:
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; };
device_driver 的定义:
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };
platform_driver 结构体有 device_driver 成员,该成员的各自字段如上所示,device_driver 也有 probe、remove、shutdown 等函数,在平台驱动注册的时候被初始化。
前面说过,当系统中存在有平台设备和平台驱动通过总线的 match 函数匹配后则会调用 platform_driver 的 probe 函数,参数为 platform_device,有时候也通过 id_table 来判断是否匹配。
struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t)))); };
平台驱动的注册使用 platform_driver_register 函数
int platform_driver_register(struct platform_driver *drv) { drv- driver.bus = platform_bus_type; if (drv- probe) drv- driver.probe = platform_drv_probe; if (drv- remove) drv- driver.remove = platform_drv_remove; if (drv- shutdown) drv- driver.shutdown = platform_drv_shutdown; if (drv- suspend) drv- driver.suspend = platform_drv_suspend; if (drv- resume) drv- driver.resume = platform_drv_resume; return driver_register(drv- driver); }
先初始化 platform_driver 里的 driver,该 driver 的类型为 device_driver,设置 driver 的 bus 为 platform_bus_type; 设置 driver 的 probe 为 platform_drv_probe; 设置 driver 的 remove 为 platform_drv_remove; 设置 driver 的 shutdown 为 platform_drv_shutdown; 设置 driver 的 suspend 为 platform_drv_suspend; 设置 driver 的 resume 为 platform_drv_resume,*** 调用 driver_register 函数来注册平台驱动。
相反地,要注销平台驱动的话,使用 platform_driver_unregister 函数
void platform_driver_unregister(struct platform_driver *drv) { driver_unregister( drv- driver); }
到此,关于“Linux 平台总线驱动设备模型是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!