linux platform

linux platform_第1张图片

从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_deviceplatform_driver。Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。

   Linuxplatform_driver机制和传统的device_driver机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。通过platform机制开发底层设备驱动的大致流程如图所示。 

                               linux platform_第2张图片 
                               图 platform机制开发驱动流程

platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在include/linux/platform_device.h中,定义原型如下:

 

structplatform_device 
{

  const char *name;     

   intid;                

  struct devicedev;      

  u32num_resources;     

  struct resource *resource;      

   struct platform_device_id       *id_entry;   

     

   structpdev_archdata      archdata;

};

structdevice {
struct klist      klist_children;
struct klist_node knode_parent;     
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device      *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE];
struct device_type *type;
unsigned      is_registered:1;
unsigned      uevent_suppress:1;
struct semaphore sem;
struct bus_type * bus;      
struct device_driver *driver;
void      *driver_data;
void      *platform_data;
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int      numa_node;
#endif
u64      *dma_mask;
u64      coherent_dma_mask;
struct list_head dma_pools;
struct dma_coherent_mem *dma_mem;

struct dev_archdata archdata;
spinlock_t      devres_lock;
struct list_head devres_head;

struct list_head node;
struct class      *class;
dev_t        devt;     
struct attribute_group **groups;
void (*release)(struct device * dev);
};

 

    Platform_device通常在BSP的板文件中实现,在板文件中,将platform_device归纳为一个数组,最终调用platform_add_device()函数统一注册。

  下面来看一下platform_device结构体中最重要的一个成员structresource * resource。structresource被定义在include/linux/ioport.h中,定义原型如下:  

struct resource 

{  

         resource_size_tstart;  //定义资源的起始地址

         resource_size_tend;    //定义资源的结束地址

        constchar *name;       //定义资源的名称

         unsignedlong flags;    //定义资源的类型,比如MEM,IO,IRQ,DMA类型

        structresource *parent, *sibling, *child;  //资源链表指针

};  

   通过调用函数platform_add_devices()向系统中添加该设备了,该函数内部调用platform_device_register()进行设备注册。要注意的是,这里的platform_device设备的注册过程必须在相应设备驱动加载之前被调用,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。
   
接下来来看platform_driver结构体的原型定义,在include/linux/platform_device.h中,代码如下:

structplatform_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)(structplatform_device *, pm_message_t state);

  int (*resume_early)(structplatform_device *);

  int (*resume)(struct platform_device*);

  struct device_driver driver;

};

  内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在driver/base/platform.c文件中,具体实现代码如下:

int platform_driver_register(structplatform_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;

  if(drv->suspend)  drv->driver.suspend =platform_drv_suspend;

  if(drv->resume)   drv->driver.resume =platform_drv_resume;

  returndriver_register(&drv->driver);

}

  总结,通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独自的资源(地址总线和IRQs),都可以用platform_driver实现。如:LCD,网卡、USB、UART等,都可以用platfrom_driver写,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。

 

 

 

do_basic_setup()->driver_init()->platform_bus_init()->...初始化platform bus(虚拟总线)
设备向内核注册的时候platform_device_register()->platform_device_add()->...内核把设备挂在虚拟的platform bus下
驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev()对每个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()->比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动.

你可能感兴趣的:(open-wrt,linux,嵌入式-mips)