Linux设备模型之platform_device和platform_driver

     在《Linux设备模型分析之基本数据结构》一文中我分析了kobjectksetdevicedevice_driver等构成Linux设备模型的重要数据结构。但在分析Linux内核代码时这些原始数据结构大多被platform_deviceplatform_driver所封装代替,下文采用at91sam9260开发板提供的Linux2.6.19内核,剖析platform_deviceplatform_driver的使用。

       首先来看这两个结构体的定义,都在/include/linux/platform_device.h中被定义:

struct platform_device { const char * name; u32 id; struct device dev; u32 num_resources; struct resource * resource; };  

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结构体被封装在platform_device中,而device_driver结构体被封装在platform_driver中。

      其中,resource结构体在/include/linux/ioport.h中定义,该结构体指明了设备的地址范围,名称,设备类型(flags字段:存储,IO,中断等,在/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; };

       下面以at91sam9260中的I2C总线驱动为例对platform设备注册过程进行分析。

        在/arch/arm/mach-at91rm9200/at91sam9260_devices.c中定义如下:

static struct resource twi_resources[] = { [0] = { .start = AT91SAM9260_BASE_TWI, .end = AT91SAM9260_BASE_TWI + SZ_16K - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = AT91SAM9260_ID_TWI, .end = AT91SAM9260_ID_TWI, .flags = IORESOURCE_IRQ, }, }; static struct platform_device at91sam9260_twi_device = { .name = "at91_i2c", .id = -1, .resource = twi_resources, .num_resources = ARRAY_SIZE(twi_resources), } 在/drivers/i2c/buses中 static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), .suspend = at91_i2c_suspend, .resume = at91_i2c_resume, .driver = { .name = "at91_i2c", .owner = THIS_MODULE, }, };

       twi_resource中定义了两个资源:一个是作为存储的资源(IORESOURCE_MEM),定义了I2C的地址,这里注意用的是物理地址;另一个是I2C中断,使用的是at91sam9260的peripheral identifier designator。at91sam9260_twi_device即描述了TWI这个具体设备的资源,这里没有对其中的device结构进行初始化。at91_i2c_driver则是具体的驱动封装,指向了具体的操作函数,并对platform_driver结构体中的name和owner域进行了赋值,注意name的值要要一致。

     下面再来看下内核如何对这个结构进行处理。大家都知道module_init这个宏。驱动模块加载的时候会调用这个宏。它接收一个函数为参数,作为它的参数的函数将会对上面提到的platform_driver进行处理。继续往下看:

module_init(at91_i2c_init); static int __init at91_i2c_init(void) { return platform_driver_register(&at91_i2c_driver); }

      注意函数体的最后一行的platform_driver_register函数。它的定义在driver/base/platform.c中,原型如下:int platform_driver_register(struct platform_driver *drv)功能就是为上面提到的plarform_driver中的driver这个结构中的probe、remove这些变量指定功能函数。至此,内核就已经知道了有这么一个驱动模块。内核启动的时候,就会调用与该驱动相关的probe函数。我们来看一下probe函数实现了什么功能。 probe函数接收plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。

      在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看在的设备文件了。

      本文没有深入I2C驱动,具体的I2C驱动还有许多Linux内核方面的抽象,在以后的文章中会提及,先写到这里吧。

 

你可能感兴趣的:(数据结构,linux,struct,Module,resources,linux内核)