2016/4/11

Device Driver , kernel boot.

Device Driver
  Device Tree and Open Firmware Support
    Support for device tree in /proc
module_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;
}

沒有留言:

張貼留言