平台总线设备模型

平台总线是内核实现的一条虚拟总线,Linux设备模型包含三个重要的元素,总线、设备和驱动,那看看平台总线又是怎样去实现的。

首先看平台总线的定义:

946 struct bus_type platform_bus_type = { 947 .name = "platform", 948 .dev_attrs = platform_dev_attrs, 949 .match = platform_match, 950 .uevent = platform_uevent, 951 .pm = &platform_dev_pm_ops, 952 };

我们知道总线匹配设备和驱动是通过它的match函数,那具体看看这个函数是怎样实现的。

606 static int platform_match(struct device *dev, struct device_driver *drv) 607 { 608 struct platform_device *pdev = to_platform_device(dev); 609 struct platform_driver *pdrv = to_platform_driver(drv); 610 611 /* match against the id table first */ 612 if (pdrv->id_table) 613 return platform_match_id(pdrv->id_table, pdev) != NULL; 614 615 /* fall-back to driver name match */ 616 return (strcmp(pdev->name, drv->name) == 0); 617 }

我们看,如果平台驱动有一个id_table,那就通过函数platform_match_id去匹配,如果没有就比较平台设备的name字段和平台驱动的name字段是否相同,这也就是平台总线的匹配规则。再来看平台总线的注册。

955 int __init platform_bus_init(void) 956 { 957 int error; 958 959 early_platform_cleanup(); 960 961 error = device_register(&platform_bus); 962 if (error) 963 return error; 964 error = bus_register(&platform_bus_type); 965 if (error) 966 device_unregister(&platform_bus); 967 return error; 968 }

我们看平台总线注册就是采用的bus_register函数,再看在注册平台总线之前,还调用了

device_register去注册了一个设备,因为总线它也是一个设备,也要被注册进内核。那就具体来看这个设备是怎么定义的。

28 struct device platform_bus = { 29 .init_name = "platform", 30 }; 31 EXPORT_SYMBOL_GPL(platform_bus);

我们看就给了一个名字。看完了总线,又来看看平台设备又是怎样定义怎样去注册。

 17 struct platform_device { 18 const char * name; 19 int id; 20 struct device dev; 21 u32 num_resources; 22 struct resource * resource; 23 24 struct platform_device_id *id_entry; 25 26 /* arch specific additions */ 27 struct pdev_archdata archdata; 28 };

其中有个重要的元素resource,该元素存入的最重要的设备资源信息,比如I/O基地址,中断号等等。structresource结构定义在include/linux/ioport.h

18 struct resource { 19 resource_size_t start; 20 resource_size_t end; 21 const char *name; 22 unsigned long flags; 23 struct resource *parent, *sibling, *child; 24 };

有可能设备的资源不只一个,定义资源时定义成一个数组的形式,那就使用函数去获取,

platform_get_resource就是用来获取设备的资源信息,去看看这个函数

33 /** 34 * platform_get_resource - get a resource for a device 35 * @dev: platform device 36 * @type: resource type 37 * @num: resource index 38 */ 39 struct resource *platform_get_resource(struct platform_device *dev, 40 unsigned int type, unsigned int num) 41 { 42 int i; 43 44 for (i = 0; i < dev->num_resources; i++) { 45 struct resource *r = &dev->resource[i]; 46 47 if (type == resource_type(r) && num-- == 0) 48 return r; 49 } 50 return NULL; 51 } 52 EXPORT_SYMBOL_GPL(platform_get_resource);

这个函数的第一个参数为要获取资源的平台设备,第二个参数为资源类型,比如IORESOURCE_MEM,第三个参数为资源在数组中的一个号。如果是获取中断号,还可以使用函数platform_get_irq

54 /** 55 * platform_get_irq - get an IRQ for a device 56 * @dev: platform device 57 * @num: IRQ number index 58 */ 59 int platform_get_irq(struct platform_device *dev, unsigned int num) 60 { 61 struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 62 63 return r ? r->start : -ENXIO; 64 } 65 EXPORT_SYMBOL_GPL(platform_get_irq);

我们看这个函数也是调用platform_get_resource去获取资源,只是它获取资源的类型为IORESOURCE_IRQ,最后返回中断号。

再来看平台设备的注册,平台设备注册采用platform_device_register函数

54 /** 55 * platform_get_irq - get an IRQ for a device 56 * @dev: platform device 57 * @num: IRQ number index 58 */ 59 int platform_get_irq(struct platform_device *dev, unsigned int num) 60 { 61 struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 62 63 return r ? r->start : -ENXIO; 64 } 65 EXPORT_SYMBOL_GPL(platform_get_irq);

device_initialize就是device_register那的函数,那就看platform_device_add

227 /** 228 * platform_device_add - add a platform device to device hierarchy 229 * @pdev: platform device we're adding 230 * 231 * This is part 2 of platform_device_register(), though may be called 232 * separately _iff_ pdev was allocated by platform_device_alloc(). 233 */ 234 int platform_device_add(struct platform_device *pdev) 235 { 236 int i, ret = 0; 237 238 if (!pdev) 239 return -EINVAL; 240 241 if (!pdev->dev.parent) 242 pdev->dev.parent = &platform_bus; 243 244 pdev->dev.bus = &platform_bus_type; 245 246 if (pdev->id != -1) 247 dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 248 else 249 dev_set_name(&pdev->dev, "%s", pdev->name); 250 251 for (i = 0; i < pdev->num_resources; i++) { 252 struct resource *p, *r = &pdev->resource[i]; 253 254 if (r->name == NULL) 255 r->name = dev_name(&pdev->dev); 256 257 p = r->parent; 258 if (!p) { 259 if (resource_type(r) == IORESOURCE_MEM) 260 p = &iomem_resource; 261 else if (resource_type(r) == IORESOURCE_IO) 262 p = &ioport_resource; 263 } 264 265 if (p && insert_resource(p, r)) { 266 printk(KERN_ERR 267 "%s: failed to claim resource %d\n", 268 dev_name(&pdev->dev), i); 269 ret = -EBUSY; 270 goto failed; 271 } 272 } 273 274 pr_debug("Registering platform device '%s'. Parent at %s\n", 275 dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 276 277 ret = device_add(&pdev->dev); 278 if (ret == 0) 279 return ret; 280 281 failed: 282 while (--i >= 0) { 283 struct resource *r = &pdev->resource[i]; 284 unsigned long type = resource_type(r); 285 286 if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 287 release_resource(r); 288 } 289 290 return ret; 291 } 292 EXPORT_SYMBOL_GPL(platform_device_add);

最终调用device_register那的device_add完成平台设备的注册。

我们也可以使用platform_add_devices去注册一组平台设备

103 /** 104 * platform_add_devices - add a numbers of platform devices 105 * @devs: array of platform devices to add 106 * @num: number of platform devices in array 107 */ 108 int platform_add_devices(struct platform_device **devs, int num) 109 { 110 int i, ret = 0; 111 112 for (i = 0; i < num; i++) { 113 ret = platform_device_register(devs[i]); 114 if (ret) { 115 while (--i >= 0) 116 platform_device_unregister(devs[i]); 117 break; 118 } 119 } 120 121 return ret; 122 } 123 EXPORT_SYMBOL_GPL(platform_add_devices);

看完了注册来看注销函数,注销函数就是platform_device_unregister

331 /** 332 * platform_device_unregister - unregister a platform-level device 333 * @pdev: platform device we're unregistering 334 * 335 * Unregistration is done in 2 steps. First we release all resources 336 * and remove it from the subsystem, then we drop reference count by 337 * calling platform_device_put(). 338 */ 339 void platform_device_unregister(struct platform_device *pdev) 340 { 341 platform_device_del(pdev); 342 platform_device_put(pdev); 343 } 344 EXPORT_SYMBOL_GPL(platform_device_unregister); 294 /** 295 * platform_device_del - remove a platform-level device 296 * @pdev: platform device we're removing 297 * 298 * Note that this function will also release all memory- and port-based 299 * resources owned by the device (@dev->resource). This function must 300 * _only_ be externally called in error cases. All other usage is a bug. 301 */ 302 void platform_device_del(struct platform_device *pdev) 303 { 304 int i; 305 306 if (pdev) { 307 device_del(&pdev->dev); 308 309 for (i = 0; i < pdev->num_resources; i++) { 310 struct resource *r = &pdev->resource[i]; 311 unsigned long type = resource_type(r); 312 313 if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 314 release_resource(r); 315 } 316 } 317 } 318 EXPORT_SYMBOL_GPL(platform_device_del);

device_del就是device_unregister那的函数

再来看驱动,平台设备驱动结构定义

58 struct platform_driver { 59 int (*probe)(struct platform_device *); 60 int (*remove)(struct platform_device *); 61 void (*shutdown)(struct platform_device *); 62 int (*suspend)(struct platform_device *, pm_message_t state); 63 int (*resume)(struct platform_device *); 64 struct device_driver driver; 65 struct platform_device_id *id_table; 66 };

驱动注册

474 /** 475 * platform_driver_register 476 * @drv: platform driver structure 477 */ 478 int platform_driver_register(struct platform_driver *drv) 479 { 480 drv->driver.bus = &platform_bus_type; 481 if (drv->probe) 482 drv->driver.probe = platform_drv_probe; 483 if (drv->remove) 484 drv->driver.remove = platform_drv_remove; 485 if (drv->shutdown) 486 drv->driver.shutdown = platform_drv_shutdown; 487 488 return driver_register(&drv->driver); 489 } 490 EXPORT_SYMBOL_GPL(platform_driver_register);

平台驱动结构里面有个成员driver,它是device_driver结构类型,它的probe函数指针赋值了这里的platform_drv_probe,也就是平台总线匹配设备和驱动成功后,将调用这里的

platform_drv_probe函数,那就在去看看这个函数。

445 static int platform_drv_probe(struct device *_dev) 446 { 447 struct platform_driver *drv = to_platform_driver(_dev->driver); 448 struct platform_device *dev = to_platform_device(_dev); 449 450 return drv->probe(dev); 451 }

还有一点的是它的remove函数为这里的platform_drv_remove,不管是设备注销还是驱动注销都是先调用这个函数,然后才调用平台驱动的remove函数。

458 static int platform_drv_remove(struct device *_dev) 459 { 460 struct platform_driver *drv = to_platform_driver(_dev->driver); 461 struct platform_device *dev = to_platform_device(_dev); 462 463 return drv->remove(dev); 464 }

也就是最后调用platform_driverprobe函数,它的参数devplatform_device结构类型。注意这里有两个probe,一个是platform_driverprobe,它是要求我们在编写平台设备驱动时自己去定义,另一个是device_driverprobe,它供总线匹配设备和驱动成功后调用,probe为这里的platform_drv_probe,这个函数的功能就是调用platform_driverprobe

平台设备驱动注册最后调用的就是driver_register,只不过这里的总线是平台总线。

驱动注销

492 /** 493 * platform_driver_unregister 494 * @drv: platform driver structure 495 */ 496 void platform_driver_unregister(struct platform_driver *drv) 497 { 498 driver_unregister(&drv->driver); 499 } 500 EXPORT_SYMBOL_GPL(platform_driver_unregister);

转载于:https://www.cnblogs.com/phonegap/archive/2012/01/19/2536123.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值