Chinaunix首页 | 论坛 | 博客
  • 博客访问: 206053
  • 博文数量: 33
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1277
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-03 10:03
个人简介

现于杭州电子科技大学攻读硕士学位

文章分类

全部博文(33)

文章存档

2013年(33)

我的朋友

分类: LINUX

2013-09-07 17:05:21

**********************************************设备驱动架构的分层与分离思想**********************************************************/
/*
 *设备驱动的分层思想:在设备驱动方便,往往为同类的设备设计一个框架,而在框架中的核心层则实现了该设备驱动通用的一些功能,同样的,如果在具体的
 *设备驱动中不想使用或者由于硬件设计的关系不使用核心层的函数,它可以重载之,例子如下:
 */
return_type core_func(xxx_device *xxx_dev,param1,param2)
{
 if(xxx_dev->funca)   //判断底层设备是否重载了funca(底层是否定义了该函数),如果重载了(底层定义了该函数),就调用底层提供的funca函数,否则直接使用通用层的代码
    return xxx_dev->funca(.......);
  /* 核心层通用的funca代码 */
  .......
}
/*
 *主机驱动与外设驱动分离思想:
 *    该思想是将主机控制器驱动和外设驱动进行分离,外设的驱动与主机控制器的驱动不相关,主机控制器的驱动不关心外设,而外设驱动不关心主机控制器。
 *这样做了以后,那么要将它们联系起来就需要设计一个核心层,外设只是通过核心层的通用API进行数据传输(核心层通常需要定义主机和设备使用的数据结构、
 *将主机控制器和设备联系起来的代码,用于在两者之间传输数据的代码等等)。linux的SPI、I2C、USB、ASoC等子系统都典型地利用了这种分离的设计思想
 */
/**********************************************************end***********************************************************************/


/****************************************************platform设备驱动****************************************************************/
/*
 *    在2.6内核的设备驱动模型中,总是关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动,在系统每注册一个驱动的时候,
 *会寻找与之相匹配的设备,而匹配由总线完成。
 *
 *    linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动称为platform_driver,所谓的platform_device并不是与字符设备、块设备和
 *网络设备并列的概念,而是linux系统提供的一种附加手段
 *
 *
 *相关结构和接口函数在platform_device.h、ioport.h、platform.c
 */
/*=====================================================平台设备相关的数据结构=============================================================*/
#include
-----------------------------------struct platform_device--------------------------------------
platform_device结构体定义如下:
struct platform_device {  //表示挂在platform总线的设备
 const char * name;     //设备名,一定要与struct platform_driver->struct device_driver->name相同
 int  id;               //支持的设备,通常取-1支持所有匹配的设备
 struct device dev;
 u32  num_resources;    //设备所使用的各类资源数量
 struct resource * resource; //资源

 struct platform_device_id *id_entry;
};
-----------------------------------------------------------------------------------------------

/*---------------------------------------struct device-------------------------------------------*/
//device结构:
struct device {
 struct device  *parent;

 struct device_private *p;

 struct kobject kobj;
 const char  *init_name; /* initial name of the device */
 struct device_type *type;

 struct semaphore sem; /* semaphore to synchronize calls to
      * its driver.
      */

 struct bus_type *bus;  /* type of bus device is on */
 struct device_driver *driver; /* which driver has allocated this
        device */
 void  *driver_data; /* data private to the driver */ 
 void  *platform_data; /* Platform specific data, device    //可用于存放自己定义的与开发板相关的设备资源数据platform_data
        core doesn't touch it */
 struct dev_pm_info power;

#ifdef CONFIG_NUMA
 int  numa_node; /* NUMA node this device is close to */
#endif
 u64  *dma_mask; /* dma mask (if dma'able device) */
 u64  coherent_dma_mask;/* Like dma_mask, but for
          alloc_coherent mappings as
          not all hardware supports
          64 bit addresses for consistent
          allocations such descriptors. */

 struct device_dma_parameters *dma_parms;

 struct list_head dma_pools; /* dma pools (if dma'ble) */

 struct dma_coherent_mem *dma_mem; /* internal for coherent mem
          override */
 /* arch specific additions */
 struct dev_archdata archdata;

 dev_t   devt; /* dev_t, creates the sysfs "dev" */

 spinlock_t  devres_lock;
 struct list_head devres_head;

 struct klist_node knode_class;
 struct class  *class;
 struct attribute_group **groups; /* optional groups */

 void (*release)(struct device *dev); 
};
-----------------------------------------------------------------------------------------------

/*---------------------------------------struct resource-----------------------------------------*/
//resource(资源)结构:
struct resource {  //表示设备使用的资源
 resource_size_t start;  //资源的开始值
 resource_size_t end;    //资源的结束值
 const char *name;       //
 unsigned long flags;    //资源类型,在linux目录下ioport.h中定义,以IORESOURCE_开头,start、end会随着flags变化而变更
 struct resource *parent, *sibling, *child;
};
//对resource的定义通常在BSP的板文件中实现,而在具体的设备中通过下面这个函数来获取资源:
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num); //type=flags,num为资源引索(从0开始,其最大值为同类资源的个数-1)
int platform_get_irq(struct platform_device *dev, unsigned int num);   //获取中断号资源
---------------------------------------------------------------------------------------------- 
/*
 *设备的硬件描述除了中断、内存等以外,可能还会有一些配置信息,这些配置信息也依赖于板所以不适合直接放置在设备驱动本身,因此,platform也提供了platform_data的支持, platform_data
 *的形式是自己定义的,如DM9000的platform_data为一个dm9000_plat_data结构体,我们就可以将MAC地址,总线宽度等放到自己定义的platform_data_xxx中,然后保存到struct platform_device-> struct device dev.platform_data中
 *,使用的时候可以这样: struct platform_device *pdev=函数传进来的struct platform_device指针; struct platform_data_xxx *pdatax=pdev->dev.platform_data                                                                                                                    
 *
 *对platform_device的定义通常在BSP的板文件中实现,在板文件中,将platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册,platform_add_devices()函数可以
 *将平台设备添加到系统中,这个函数的原型为:
 */
int platform_add_devices(struct platform_device **devs, int num); //devs为平台设备数组指针,num为平台设备数目,它的内部调用platform_device_register()函数注册单个的平台设备
int platform_device_register(struct platform_device *dev);  //注册platform_device
void platform_device_unregister(struct platform_device *dev);  //卸载platform_device
=================================================================================================================================================

/*=========================================================平台驱动相关数据结构=================================================================*/
----------------------------------struct platform_driver--------------------------------------
//platform_driver结构体包含probe()、remove()、shutdown()、suspend()、resume()函数,通常需要由驱动实现:
struct platform_driver { //挂在platform总线上的设备的对应的驱动
 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); //也是挂起函数,不过它与suspend的区别是工作于中断都被禁止的情况下,而且仅有一个CPU是活跃的,绝大部分驱动不实现该函数
 int (*resume_early)(struct platform_device *); //该函数也是恢复函数,它与resume区别是工作于中断都被禁止的情况下,绝大部分驱动不实现该函数
 int (*resume)(struct platform_device *); //恢复函数,用于电源管理
 struct device_driver driver;    //driver->name一定要与与platform_device结构中设备名platform_device->name相同
 struct platform_device_id *id_table;
};
---------------------------------------------------------------------------------------------
/*----------------------------------struct device_driver-------------------------------------*/
struct device_driver {
 const char  *name;   //设备名,一定要与platform_device结构中设备名platform_device->name匹配
 struct bus_type  *bus;

 struct module  *owner;  //THIS_MODULE
 const char   *mod_name; /* used for built-in modules */

 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);
 struct attribute_group **groups;

 struct dev_pm_ops *pm;

 struct driver_private *p;
};
--------------------------------------------------------------------------------------------
//通常在suspend函数里会停止设备,并关闭给它提供的时钟,所以在suspend函数里经常看到下面的语句:
clk_disable(xxx->clk);
//而在resume函数中进行相反的操作:
clk_enable();

struct clk *clk_get(struct device *dev, const char *id); //获取时钟
void clk_put(struct clk *clk); //释放时钟
int clk_enable(struct clk *clk); //使能时钟
int clk_disable(struct clk *clk); //禁止时钟
unsigned long clk_get_rate(struct clk *clk); //获取时钟频率
long clk_round_rate(struct clk *clk,unsigned long rate); //试探时钟频率
int clk_set_rate(struct clk *clk,unsigned long rate);  //设置时钟频率

//device_driver结构体:
#include


//系统中为platform总线定义了一个bus_type的实例platform_bus_type:
struct bus_type platform_bus_type = {
 .name  = "platform",
 .dev_attrs = platform_dev_attrs,
 .match  = platform_match,           //该成员函数确定了platform_device和platform_driver之间如何匹配,通过比较name字段是否相同,如果相同则驱动的probe函数来进一步进行设备的具体的初始化和注册
 .uevent  = platform_uevent,
 .pm  = PLATFORM_PM_OPS_PTR,
};

int platform_driver_register(struct platform_driver *drv);   //注册platform_driver
void platform_driver_unregister(struct platform_driver *drv); //卸载platform_driver


//一般的模板:
static struct resource xxx_resource[] = {
    [0] = {
        .start = xxxx,        
        .end   = xxxx,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = xxx,                  
        .end   = xxx,
        .flags = IORESOURCE_IRQ,
    },
    ............
    ............

};

static struct platform_device xxx_device={
    .name         = "xxx",
    .id       = -1,
    .num_resources    = ARRAY_SIZE(xxx_resource),
    .resource     = xxx_resource,
    .dev = {
     .release = xxx_release,
 },
}; 


static int xxx_init(void)
{
 platform_device_register(&xxx_device);
 return 0;
}

static void xxx_exit(void)
{
 platform_device_unregister(&xxx_device);
}

module_init(xxx_init);
module_exit(xxx_exit);
以上是device:
//下面是具体的设备驱动程序实现:

static struct platform_driver xxx_device_driver={
                                               .probe=xxx_probe,
                                               .remove=__devexit_p(xxx_remove),
                                               .....
                                               .driver={
                                                         .name="xxx",
                                                         .owner=THIS_MODULE,
                                                         .......
                                                        }
                                               };

static int __devinit xxx_probe(struct platform_device *pdev)
  {
     申请设备号;
     为设备设备描述结构体分配内存;
     注册设备;
     。。。。。 
 }

static int __devexit xxx_remove(struct platform_device *pdev)
  {
     卸载设备号;
     为设备设备描述结构体释放内存;
     卸载设备;
     。。。。。 
 }

static int xxx_init(void)
{
 platform_driver_registe(&xxx_device_driver);
 return 0;
}

static void xxx_exit(void)
{
 platform_driver_unregister(&xxx_device_driver); 
}

module_init(xxx_init);
module_exit(xxx_exit);

//备注:
1:在devs.c中定义了各种平台的platform_device和资源,可在该文件下添加相应的设备和资源
2:在arch/arm/mach-2410/mach-smdk2410.c中的 static struct platform_device *smdk2410_devices[] __initdata = {
                                                                                                           &xxx_device,
                                                                                                          };
//以完成设备的注册。这样的platform_device_register(&xxx_device)和platform_device_unregister(&xxx_device)就可以省略不用自己做了

/****************************************************end**********************************************************************/

阅读(1258) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~