在ARM体系结构中常见的是platform_driver_register 在powerpc中是of_register_platform_driver 下面通过具体的代码来分析其区别 platform_driver_register在driver/base/platform.c中定义 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); —————————————————————————————————— 而of_register_platform_driver在of_platform.c中定义 static inline int of_register_platform_driver(struct of_platform_driver *drv) { return of_register_driver(drv, &of_platform_bus_type); } int of_register_driver()在driver/of/plateform.c中定义 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) { drv->driver.bus = bus; /* register with core */ return driver_register(&drv->driver); } 而着最终都是调用的driver_register(); _____________________________________ 这是由于二者结构获取硬件信息 的方式不同造成 的,在powerpc体系是通过dts 对比platform_driver和of_platform_driver 在include/linux/platform_device.h struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; }; 在include/linux/of_platform_device.h struct of_platform_driver { int (*probe)(struct of_device* dev, const struct of_device_id *match); int (*remove)(struct of_device* dev); int (*suspend)(struct of_device* dev, pm_message_t state); int (*resume)(struct of_device* dev); int (*shutdown)(struct of_device* dev); struct device_driver driver; }; #define to_of_platform_driver(drv) \ container_of(drv,struct of_platform_driver, driver) of_device_id 和platform_device_id 可以看出 主要所区别在 of_device 和platform_device *********************************************************** 在arch/powerpc/include/asm/of_device.h定义了 /* * The of_device is a kind of "base class" that is a superset of * struct device for use by devices attached to an OF node and * probed using OF properties. */ struct of_device { struct device dev; /* Generic device interface */ struct pdev_archdata archdata; }; /* * Struct used for matching a device */ struct of_device_id { char name[32]; char type[32]; char compatible[128]; //dts中看到这个东东了哈。通过它的匹配获取硬件资源 #ifdef __KERNEL__ void *data; #else kernel_ulong_t data; #endif }; —————————————————————————————————— 在在include/linux/of_platform_device.h定义 struct platform_device { const char * name; int id; struct device dev;//这个是通用的 u32 num_resources; struct resource * resource; //获取硬件资源 const struct platform_device_id *id_entry; /* arch specific additions */ struct pdev_archdata archdata; };从上述定义的文件也可以发现powerpc 并不是一个通用的,和自己体系相关 struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t)))); }; ********************************* 返回到我们的 int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) { drv->driver.bus = bus; /* register with core */ return driver_register(&drv->driver); } bus 是从of_register_platform_driver中传入 of_platform_bus_type,是个全局变量在 arch/powerpc/kernel/of_platform.c中定义 struct bus_type of_platform_bus_type = { .uevent = of_device_uevent, }; of_device_uevent,在同上目录of_device.c定义 int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct of_device *ofdev; const char *compat; int seen = 0, cplen, sl; if (!dev) return -ENODEV; ofdev = to_of_device(dev); if (add_uevent_var(env, "OF_NAME=%s", ofdev->dev.of_node->name)) return -ENOMEM; if (add_uevent_var(env, "OF_TYPE=%s", ofdev->dev.of_node->type)) return -ENOMEM; /* Since the compatible field can contain pretty much anything * it's not really legal to split it out with commas. We split it * up using a number of environment variables instead. */ compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen);//根据compatible获取资源 具体看dts文件,在i2c学习中提过 while (compat && *compat && cplen > 0) { if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) return -ENOMEM; sl = strlen (compat) + 1; compat += sl; cplen -= sl; seen++; } if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) return -ENOMEM; /* modalias is trickier, we add it in 2 steps */ if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], sizeof(env->buf) - env->buflen); if (sl >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; env->buflen += sl; return 0; } |
|
来自: langhuayipian > 《driver》