Linux设备驱动模型之platform总线深入浅出.doc
《Linux设备驱动模型之platform总线深入浅出.doc》由会员分享,可在线阅读,更多相关《Linux设备驱动模型之platform总线深入浅出.doc(30页珍藏版)》请在三一办公上搜索。
1、Linux设备驱动模型之platform总线深入浅出在Linux2.6以后的设备驱动模型中,需关心总线,设备和驱动这三种实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。对于依附在USB、PCI、I2C、SPI等物理总线来 这些都不是问题。但是在嵌入式系统里面,在Soc系统中集成的独立外设控制器,挂接在Soc内存空间的外设等却不依附在此类总线。基于这一背景,Linux发明了一种总线,称为platform。相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出
2、来的总线,实际中并不存在这样的总线。platform总线相关代码:driverbaseplatform.c 文件相关结构体定义:includelinuxplatform_device.h 文件中platform总线管理下最重要的两个结构体是platform_device和platform_driver分别表示设备和驱动在Linux中的定义如下一:platform_driver/includelinuxplatform_device.h struct platform_driver int (*probe)(struct platform_device *); /探测函数,在注册平台设备时被调用
3、 int (*remove)(struct platform_device *); /删除函数,在注销平台设备时被调用 void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); /挂起函数,在关机被调用 int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*r
4、esume)(struct platform_device *);/恢复函数,在开机时被调用 struct device_driver driver;/设备驱动结构;1234567891011struct device_driver const char * name; struct bus_type * bus; struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module * owner; const char * mod_name; /* used for built
5、-in modules */ struct module_kobject * mkobj; 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);12345678910111213141516171819二:platform_devices
6、truct platform_device const char * name;/设备名称 u32 id;/取-1 struct device dev;/设备结构 u32 num_resources;/ resource结构个数 struct resource * resource;/设备资源;1234567resource结构体也是描述platform_device的一个重要结构体 该元素存入了最为重要的设备资源信息struct resource resource_size_t start; resource_size_t end; const char *name; unsigned lo
7、ng flags; struct resource *parent, *sibling, *child;1234567我们通常关心start,end,flags。它们分别标明了资源的开始值,结束值和类型,flags可以为IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA等,start,end的含义会随着flags变更,如当flags为IORESOURCE_MEM时,start,end分别表示该platform_device占据的内存的开始地址和结束地址;当flags为,IORESOURCE_IRQ时,start,end分别表示该
8、platform_device使用的中断号的开始值和结束值,如果只使用了1个中断号,开始和结束值相同。对于同种类型的资源而言,可以有多份,例如某设备占据了两个内存区域,则可以定义两个IORESOURCE_MEM资源。 对resource的定义也通常在BSP的板文件中运行,而在具体的设备驱动中通过platform_get_resource()这样的API来获取,此API的原型为:struct resource *platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int num)12例如在ar
9、charmmach-at91Board-sam9261ek.c板文件中为DM9000网卡定义了如下的resourcestatic struct resource at91sam9261_dm9000_resource = 0 = .start = AT91_CHIPSELECT_2, .end = AT91_CHIPSELECT_2 + 3, .flags = IORESOURCE_MEM , 1 = .start = AT91_CHIPSELECT_2 + 0x44, .end = AT91_CHIPSELECT_2 + 0xFF, .flags = IORESOURCE_MEM , 2 =
10、 .start = AT91_PIN_PC11, .end = AT91_PIN_PC11, .flags = IORESOURCE_IRQ ;123456789101112131415161718在DM9000网卡驱动中则是通过如下办法拿到这3份资源db-addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);db-data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);db-irq_res = platform_get_resource(pdev, IORESOURCE_
11、IRQ, 0);123对于irq而言platform_get_resource()还有一个进行了封装的变体platform_get_irq(), api原型是int platform_get_irq(struct platform_device *dev, unsigned int num) struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); return r ? r-start : -ENXIO;12345实际上这个函数也是调用platform_get_resource(dev, IORESOURCE_I
12、RQ, num)来获取资源设备除了可以在BSP中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断,内存等标准资源以外,可能还会有一些配置信息,这些配置信息也依赖于板,不适宜直接放置在设备驱动上,因此,platform也提供了platform_data的支持,例如对于dm9000staTIc struct dm9000_plat_data dm9000_platdata = .flags = DM9000_PLATF_16BITONLY,;staTIc struct platform_device at91sam9261_dm9000_device = .name = dm90
13、00, .id = 0, .num_resources = ARRAY_SIZE(at91sam9261_dm9000_resource), .resource = at91sam9261_dm9000_resource, .dev = .platform_data = 12345678910111213获取platform_data的API是dev_get_platdata()struct dm9000_plat_data *pdata = dev_get_platdata(1三:platform总线 系统为platform总线定义了一个bus_type的实例platform_bus_typ
14、e,其定义位于drivers/base/platform.c下struct bus_type platform_bus_type = .name = platform, .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, .pm = 1234567最重要的是match函数,真是此成员函数确定了platform_device和platform_driver之间如何匹配的staTIc int platform_match(struct device *dev, struct dev
15、ice_driver *drv) struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv) return 1; /* Then try to match against the id table */ if (pdrv-id_table) return platform_match_
16、id(pdrv-id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev-name, drv-name) = 0);12345678910111213141516可知有3中情况下platform_device和platform_driver匹配 1.基于设备树风格的匹配 2.匹配ID表(即platform_device设备名是否出现在platform_driver的id表内) 3.匹配platform_device设备名和驱动的名字 在4.0还有一种情况是基于ACPI风格的匹配对于设备驱动
17、的开发 其设计顺序为定义 platform_device - 注册 platform_device- 定义 platform_driver- 注册 platform_driver 。 这里选用的例子是q40kbd,在/drivers/input/serio目录里。这是一个键盘控制器驱动 这里直接分析初始化函数staTIc int _init q40kbd_init(void) int error; if (!MACH_IS_Q40) return -EIO; /* platform总线驱动的注册 */ error = platform_driver_register( if (error) r
18、eturn error; /* 分配一个platform设备 */ q40kbd_device = platform_device_alloc(q40kbd, -1); if (!q40kbd_device) goto err_unregister_driver; /* platform设备注册 */ error = platform_device_add(q40kbd_device); if (error) goto err_free_device; return 0; err_free_device: platform_device_put(q40kbd_device); err_unre
19、gister_driver: platform_driver_unregister( return error;123456789101112131415161718192021222324252627驱动注册函数是 platform_driver_register()函数int platform_driver_register(struct platform_driver *drv) /把驱动的总线设置为platform总线 drv-driver.bus = /依次设置驱动的各个函数指针 if (drv-probe) drv-driver.probe = platform_drv_probe
20、; 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; /调用driver_register注册驱动 return driver_register(123456789101112
21、131415161718/* 初始化后调用bus_add_driver函数执行注册过程 */int driver_register(struct device_driver * drv) if (drv-bus-probe %s needs updating - please use bus_type methodsn, drv-name); klist_init( return bus_add_driver(drv);123456789101112为总线增加一个驱动int bus_add_driver(struct device_driver *drv) struct bus_type *
22、bus = get_bus(drv-bus); int error = 0; if (!bus) return -EINVAL; pr_debug(bus %s: add driver %sn, bus-name, drv-name); /* 为kobject结构设置名字 */ error = kobject_set_name( if (error) goto out_put_bus; drv-kobj.kset = /* 为sysfs文件系统创建设备的相关文件 */ if (error = kobject_register( if (drv-bus-drivers_autoprobe) /*
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 设备 驱动 模型 platform 总线 深入浅出
链接地址:https://www.31ppt.com/p-4842359.html