看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 (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
};可见,它包含了设备操作的几个功能函数,同样重要的是,它还包含了一个device_driver结构。刚才提到了驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于include/linux/device.h中:
struct 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-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);
};需要注意这两个变量:name和owner。那么的作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。
两者的工作顺序是先定义platform_device -> 注册 platform_device->,再定义 platform_driver-> 注册 platform_driver。
下面是一个platform_driver的初始化实例:
static struct platform_driver s3c2410iis_driver = {
.probe = s3c2410iis_probe,
.remove = s3c2410iis_remove,
.driver = {
.name = "s3c2410-iis",
.owner = THIS_MODULE,
},
}; 上面的初始化是一个音频驱动的实例。注意其中的driver这个结构体,只初始化了其name和owner两个量。接着看一下和driver相关的另一个结构,定义如下:
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};该结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。platform_device就描述了设备对象。下面是一个具体的实例:
struct platform_device s3c_device_iis = {
.name = "s3c2410-iis",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_iis_resource),
.resource = s3c_iis_resource,
.dev = {
.dma_mask = &s3c_device_iis_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};它的name变量和刚才上面的platform_driver的name变量是一致的,内核正是通过这个一致性来为驱动程序找到资源,即platform_device中的resource。这个结构的定义如下,位于include/linux/ioport.h中:
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};下面是一个具体的实例:
static struct resource s3c_iis_resource[] = {
[0] = {
.start = S3C24XX_PA_IIS,
.end = S3C24XX_PA_IIS + S3C24XX_SZ_IIS -1,
.flags = IORESOURCE_MEM,
}
};有了platform_device就可以调用函数platform_add_devices向系统中添加该设备了。系统中的设备资源都可以采用这种方式列举在一起,然后成一个指针数组,如:
static struct platform_device *smdk6410_devices[] __initdata = {
......
&s3c_device_usbgadget,
&s3c_device_usb, //jeff add.
&s3c_device_iis,
......
}然后在6410的初始化函数smdk6410_machine_init()中执行:
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));将所有的device添加进系统。platform_add_devices的好处在于它是一次性的执行多个platform_device_register。
在驱动初始化函数中调用函数platform_driver_register()注册该platform_driver,
需要注意的是s3c_device_iis结构中name元素和s3c2410iis_driver结构中driver.name必须是相同的,
这样在platform_driver_register()注册时会对所有已注册的platform_device中元素的name和当前注册的platform_driver的driver.name进行比较,
只有找到具备相同名称的platform_device存在后,platform_driver才能注册成功。当注册成功时会调用platform_driver结构元素probe函数指针,
这里就是s3c2410iis_probe开始探测加载。platform driver中的函数都是以platform device作为参数进入。
platform_driver_register(&s3c2410iis_driver);
本文介绍Linux平台设备模型中platform_device和platform_driver的概念及其注册过程。包括如何定义和初始化这些结构体,以及它们之间的关联方式。并通过一个具体实例展示了音频驱动的注册流程。

2852

被折叠的 条评论
为什么被折叠?



