Device Driver Device Tree and Open Firmware Support Support for device tree in /procmodule_platform_driver(imx_wm8962_driver);
include/linux/platform_device.h
/* module_platform_driver() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of * boilerplate. Each module may only use this macro once, and * calling it replaces module_init() and module_exit() */ #define module_platform_driver(__platform_driver) \ module_driver(__platform_driver, platform_driver_register, \ platform_driver_unregister) /* module_platform_driver_probe() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of * boilerplate. Each module may only use this macro once, and * calling it replaces module_init() and module_exit() */
include/linux/device.h
/** * module_driver() - Helper macro for drivers that don't do anything * special in module init/exit. This eliminates a lot of boilerplate. * Each module may only use this macro once, and calling it replaces * module_init() and module_exit(). * * @__driver: driver name * @__register: register function for this driver type * @__unregister: unregister function for this driver type * @...: Additional arguments to be passed to __register and __unregister. * * Use this macro to construct bus specific macros for registering * drivers, and do not use it on its own. */ #define module_driver(__driver, __register, __unregister, ...) \ static int __init __driver##_init(void) \ { \ return __register(&(__driver) , ##__VA_ARGS__); \ } \ module_init(__driver##_init); \ static void __exit __driver##_exit(void) \ { \ __unregister(&(__driver) , ##__VA_ARGS__); \ } \ module_exit(__driver##_exit);
所以是 call platform_driver_register(imx_wm8962_driver)
./drivers/base/platform.c:541:EXPORT_SYMBOL_GPL(platform_driver_register);
/** * platform_driver_register - register a driver for platform-level devices * @drv: platform driver structure */ 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; return driver_register(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_register);
至於要call 到 XXX_probe( ), 有一堆要檢查,主要是確認 platform driver 跟 platform data 有 match
match 的方式有很多種,有 bus, 有 name, 還有用 of_device (也就是 dtd) 內的 compatible 字串比較,
新版 driver 好像把所有 driver 都賦予一個 bus, 非 bus 的就給 platform 這個 'bus'
code 都在 driver/base/bus.c, dd.c, platform.c 和 driver/of/base.c
base.c:
static const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { if (!matches) return NULL; while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; if (matches->name[0]) match &= node->name && !strcmp(matches->name, node->name); if (matches->type[0]) match &= node->type && !strcmp(matches->type, node->type); if (matches->compatible[0]) match &= __of_device_is_compatible(node, matches->compatible); if (match) return matches; matches++; } return NULL; }
compatible 的比較:
/** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ static int __of_device_is_compatible(const struct device_node *device, const char *compat) { const char* cp; int cplen, l; cp = __of_get_property(device, "compatible", &cplen); if (cp == NULL) return 0; while (cplen > 0) { if (of_compat_cmp(cp, compat, strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; cplen -= l; } return 0; }
沒有留言:
張貼留言