您的位置:首页 > 其它

平台总线设备模型

2013-10-25 09:23 141 查看
http://blog.csdn.net/mcgrady_tracy/article/details/7210915

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

首先看平台总线的定义:

[cpp] view
plaincopy

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函数,那具体看看这个函数是怎样实现的。

[cpp] view
plaincopy

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字段是否相同,这也就是平台总线的匹配规则。再来看平台总线的注册。

[cpp] view
plaincopy

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去注册了一个设备,因为总线它也是一个设备,也要被注册进内核。那就具体来看这个设备是怎么定义的。

[cpp] view
plaincopy

28 struct device platform_bus = {

29 .init_name = "platform",

30 };

31 EXPORT_SYMBOL_GPL(platform_bus);

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

[cpp] view
plaincopy

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中

[cpp] view
plaincopy

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就是用来获取设备的资源信息,去看看这个函数

[cpp] view
plaincopy

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

[cpp] view
plaincopy

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函数

[cpp] view
plaincopy

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

[cpp] view
plaincopy

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去注册一组平台设备

[cpp] view
plaincopy

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。

[cpp] view
plaincopy

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那的函数

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

[cpp] view
plaincopy

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 };

驱动注册

[cpp] view
plaincopy

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函数,那就在去看看这个函数。

[cpp] view
plaincopy

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函数。

[cpp] view
plaincopy

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_driver的probe函数,它的参数dev是platform_device结构类型。注意这里有两个probe,一个是platform_driver的probe,它是要求我们在编写平台设备驱动时自己去定义,另一个是device_driver的probe,它供总线匹配设备和驱动成功后调用,probe为这里的platform_drv_probe,这个函数的功能就是调用platform_driver的probe。

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

驱动注销

[cpp] view
plaincopy

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: