linux platform设备与驱动
Posted chencesc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux platform设备与驱动相关的知识,希望对你有一定的参考价值。
174 struct platform_driver { 175 int (*probe)(struct platform_device *); 176 int (*remove)(struct platform_device *); 177 void (*shutdown)(struct platform_device *); 178 int (*suspend)(struct platform_device *, pm_message_t state); 179 int (*resume)(struct platform_device *); 180 struct device_driver driver; 181 const struct platform_device_id *id_table; 182 bool prevent_deferred_probe; 183 };
259 struct device_driver { 260 const char *name; 261 struct bus_type *bus; 262 263 struct module *owner; 264 const char *mod_name; /* used for built-in modules */ 265 266 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 267 enum probe_type probe_type; 268 269 const struct of_device_id *of_match_table; //device tree通过这个去匹配 270 const struct acpi_device_id *acpi_match_table; 271 272 int (*probe) (struct device *dev); 273 int (*remove) (struct device *dev); 274 void (*shutdown) (struct device *dev); 275 int (*suspend) (struct device *dev, pm_message_t state); 276 int (*resume) (struct device *dev); 277 const struct attribute_group **groups; 278 279 const struct dev_pm_ops *pm; 280 281 struct driver_private *p; 282 };
22 struct platform_device { 23 const char *name; 24 int id; 25 bool id_auto; 26 struct device dev; 27 u32 num_resources; 28 struct resource *resource; 29 30 const struct platform_device_id *id_entry; 31 char *driver_override; /* Driver name to force a match */ 32 33 /* MFD cell pointer */ 34 struct mfd_cell *mfd_cell; 35 36 /* arch specific additions */ 37 struct pdev_archdata archdata; 38 };
以上是头文件的结构体定义
129 static const struct of_device_id dw_spi_mmio_of_match[] = { 130 { .compatible = "snps,dw-apb-ssi", }, 131 { /* end of table */} 132 }; 133 MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); 134 135 static struct platform_driver dw_spi_mmio_driver = { 136 .probe = dw_spi_mmio_probe, 137 .remove = dw_spi_mmio_remove, 138 .driver = { 139 .name = DRIVER_NAME, 140 .of_match_table = dw_spi_mmio_of_match, 141 }, 142 }; 143 module_platform_driver(dw_spi_mmio_driver); 144 145 MODULE_AUTHOR("Jean-Hugues Deschenes <[email protected]>"); 146 MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); 147 MODULE_LICENSE("GPL v2");
以前的写法 :
struct platform_device s3c_device_usb = { .name = "s3c2410-ohci", //s3c6410-usb .id = -1, .num_resources = ARRAY_SIZE(s3c_usb_resource), .resource = s3c_usb_resource, .dev = { .dma_mask = &s3c_device_usb_dmamask, .coherent_dma_mask = 0xffffffffUL } };
有了platform_device就可以调用函数platform_add_devices向系统中添加该设备了。系统中的设备资源都可以采用这种方式列举在一起,然后成一个指针数组,如: static struct platform_device *smdk6410_devices[] __initdata = { ...... &s3c_device_usbgadget, &s3c_device_usb, //jeff add. ...... } static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = ohci_hcd_s3c2410_drv_remove, .shutdown = usb_hcd_platform_shutdown, /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { .owner = THIS_MODULE, .name = "s3c2410-ohci", }, };
(1)在内核初始化时kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()初始化platform_bus(虚拟总线);
(2)设备注册的时候platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把设备挂在虚拟的platform bus下;
(3)驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev(),对每个挂在虚拟的
platform bus的设备作__driver_attach()->driver_probe_device(),判断drv->bus->match()是否存在并且是否执行成功,此时通过指针执行platform_match,
比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就调用really_probe(实际就是执行的相应设备的platform_driver->probe(platform_device),
注意platform_drv_probe的_dev参数是由bus_for_each_dev的next_device获得)开始真正的探测加载,如果probe成功则绑定该设备到该驱动。 当进入probe函数后,需要获取设备的资源信息,根据参数type所指定类型,例如IORESOURCE_MEM,来分别获取指定的资源。 struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);当然,也可以固定资源类型,
如获取资源中的中断号:struct int platform_get_irq(struct platform_device *dev, unsigned int num); probe函数一般完成硬件设备使能,struct resource的获取以及虚拟地址的动态映射和具体类型设备的注册(因为平台设备只是一种虚拟的设备类型);
remove函数完成硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和具体类型设备的注销。只要和内核本身运行依赖性不大的外围设备
( 换句话说只要不在内核运行所需的一个最小系统之内的设备 ), 相对独立的拥有各自独自的资源 (addresses and IRQs) ,都可以用platform_driver 实现。
如:lcd,usb,uart 等,都可以用platfrom_driver 写,而timer,irq等最小系统之内的设备则最好不用platfrom_driver 机制,实际上内核实现也是这样的。
http://blog.csdn.net/zhandoushi1982/article/details/5130207
http://blog.csdn.net/lichengtongxiazai/article/details/38941997 DT书写规范
http://www.right.com.cn/forum/thread-146260-1-1.html DT(2)
以上是关于linux platform设备与驱动的主要内容,如果未能解决你的问题,请参考以下文章