Platform device and platform driver

Platform device and platform driverPlatformdevice是专门给嵌入式系统设计的设备类型,一般在移植内核到自己的开发板时,基本上注册的所有的设备的类型全是platformdevice。实际上,platform在Linux内核中是以一条总线的身份登场的,要想让这样的总线和设备一起完美的工作,必须首先在系统

大家好,又见面了,我是你们的朋友全栈君。 

Platform device是专门给嵌入式系统设计的设备类型,一般在移植内核到自己的开发板时,基本上注册的所有的设备的类型全是platform device。实际上,platform在Linux内核中是以一条总线的身份登场的,要想让这样的总线和设备一起完美的工作,必须首先在系统初始化的比较早的阶段声明并注册平台设备,注册时的设备名作为设备的唯一标识,在随后的驱动加载阶段,和驱动的驱动名进行匹配,如果这两个字符串相同,那么即宣告设备找到驱动,或是驱动找到设备,接着才会进一步调用platform driver的probe成员函数进行设备的初始化并注册对应的字符、块或是网络设备。这也就是我们阅读驱动代码时,通常在代码中都有一个名为XXX_probe的函数,而且特别长的原因。

定义平台设备,只需声明一个静态的类型为struct platform_device的全局变量就行了,struct platform_device定义如下:

struct platform_device {

       const char       * name;

       int          id;

       struct device   dev;

       u32         num_resources;

       struct resource * resource;

};

成员介绍

name:平台设备名,是这个设备与设备驱动可以相认的关键保证,所以在这个嵌入式平台上它一定要唯一(除非大家都适用同一驱动),而且要和它的驱动名同名。

id:   一般初始化为-1,此时设备名沿用初值,如果是其他值,那设备名会被格式化为name.id的形式。相关代码见函数platform_device_add()。

dev: 内嵌struct device结构体,在内核驱动模型里面代表一个设备,基本上接下来很多关系都靠这个结构体来打通。这个结构体还有些成员可以稍作初始化,来向驱动传递更多有关设备的信息。

num_resources与resource:这个设备所占用的系统资源,这种资源一般有IO、内存、中断、DMA等,有多少资源,就定义多少个struct resource类型的数组成员,同时把资源个数放在num_resources就行了。

 

下面以mini2440开发板的LCD设备为例介绍platform_device的前世今生。

在mini2440开发板上,他的LCD设备定义变量初始化如下

struct platform_device s3c_device_lcd = {

       .name               = “s3c2410-lcd”,

       .id            = -1,

       .num_resources        = ARRAY_SIZE(s3c_lcd_resource),

       .resource   = s3c_lcd_resource,

       .dev              = {

              .dma_mask            = &s3c_device_lcd_dmamask,

              .coherent_dma_mask     = 0xffffffffUL

       }

};

 

 

由于2440的LCD控制器与2410的在同一地址上且诸控制寄存器也相同,故沿用的是2410的设置。s3c_lcd_resource代码如下:

static struct resource s3c_lcd_resource[] = {

       [0] = {

              .start = S3C24XX_PA_LCD,

              .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD – 1,

              .flags = IORESOURCE_MEM,

       },

       [1] = {

              .start = IRQ_LCD,

              .end   = IRQ_LCD,

              .flags = IORESOURCE_IRQ,

       }

 

};

在init_machine里面还调用了函数s3c24xx_fb_set_platdata()来设置平台设备内嵌dev成员的platform_data 成员,代码如下:

void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)

{

       struct s3c2410fb_mach_info *npd;

 

       npd = kmalloc(sizeof(*npd), GFP_KERNEL);

       if (npd) {

              memcpy(npd, pd, sizeof(*npd));

              s3c_device_lcd.dev.platform_data = npd;

       } else {

              printk(KERN_ERR “no memory for LCD platform data\n”);

       }

}

 

同时在函数init_machine()比较末尾的地方注册系统中的设备,当这个函数返回时,系统这就存在注册的平台设备了,但是现在还不能用,因为设备只是形式上声明了自己的存在,并没有可用的驱动和它关联,所以内核的移植工作到这里还没有完成!

要让设备工作,必须要加载设备的驱动,平台设备的驱动一般都存在于$kernel dir$/drivers下面,驱动的起点基本上都是以module_init()开始的。在这个函数中放入一个init函数,init函数里面使用已经初始化好的平台驱动结构体并调用platform_driver_register()注册平台驱动,此函数代码如下所示:

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;

       if (drv->suspend)

              drv->driver.suspend = platform_drv_suspend;

       if (drv->resume)

              drv->driver.resume = platform_drv_resume;

       return driver_register(&drv->driver);

}

具体实例:

int __init s3c2410fb_init(void)

{

       int ret = platform_driver_register(&s3c2410fb_driver);

 

       if (ret == 0)

              ret = platform_driver_register(&s3c2412fb_driver);;

 

       return ret;

}

module_init(s3c2410fb_init);

调用流程为:

platform_driver_register()àdrv->driver.probe = platform_drv_probe;à driver_register()àbus_add_driver()àdriver_attach()à__driver_attach()àdrv->bus->match()àdriver_probe_device()àreally_probe()àdrv->probe(dev)(即platform_drv_probe())àdrv->probe(dev);此时调用的才是自己实现的probe函数,够波折吧。

以上调用流程中比较重要环节是drv->bus->match(),如果这里调用失败,那么说明设备和驱动不匹配,此驱动不适用这个设备,所以给一个设备注册驱动时,关键是要让这个函数的调用返回非零!要如何才能使这个函数调用成功呢?先来看看它的代码再说:

static int platform_match(struct device *dev, struct device_driver *drv)

{

       struct platform_device *pdev;

 

       pdev = container_of(dev, struct platform_device, dev);

       return (strcmp(pdev->name, drv->name) == 0);

}

注意到上面以红色展示的代码语句了吗,这是在比较驱动名与设备名啊,这个就是上面我提到的,平台设备的名字是他和驱动相认的关键!如果这两个名字一样了,那么注册的平台设备驱动的probe被调用就成了既定的事实了,最后这个驱动是否确实适合这个设备,或是相关额外的考虑,就要看此probe函数的返回值了,如果返回0,那么万事大吉,驱动和设备门当户对,如果非零,那可能在probe阶段驱动和设备出现了点小矛盾,谈不拢,最后还是分开了。

至此,该说的也说得差不多了,就此打住吧~~~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/163815.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • No Suitable Driver Found For Jdbc解决方法

    No Suitable Driver Found For Jdbc解决方法在学习java数据库连接池使用的时候遇到问题,无法连接到数据库,之前练习别的时候都没事,莫名的到这里有连接不上了,查看日志是”NoSuitableDriverFoundForJdbc”,但查看数据库连接配置没问题啊,后来发现原来是少导入了一个包mysql-connector-java-3.1.14-bin.jar,导入该包,问题解决.总结一下NoSuitableDriver…

    2022年6月23日
    38
  • Java判断对象是否为空的方法:isEmpty,null,” “

    Java判断对象是否为空的方法:isEmpty,null,” “今天修改辞职同事遗留的代码才发现这个问题,不能用isEmpty来判断一个对象是否为null,之前没在意这个问题,在报了空指针之后才发现这个问题。查了一下关于判断为空的几个方法的区别,这里做一个简单的总结:null一个对象如果有可能是null的话,首先要做的就是判断是否为null:object==null,否则就有可能会出现空指针异常,这个通常是我们在进行数据库的查询操作时,查询结果首…

    2022年6月13日
    21
  • 【夏虫语冰】visio2013安装出错,您输入的产品密钥无法在此计算机上使用,错误25004[通俗易懂]

    【夏虫语冰】visio2013安装出错,您输入的产品密钥无法在此计算机上使用,错误25004[通俗易懂]问题的原因并不是您所下载的Office程序无法安装上去,而是所使用的密钥不能再授权安装和使用Office产品。如果在此电脑上之前已经安装并使用过了试用版本的Office的话,是不能重复不断地继续使用试用版本的Office和申请的授权密钥的。Office卸载工具有很多,下面介绍几个常见的工具:1、微软新版工具(未测试,微软官网无法下载)“SetupProd_OffScrub.exe”是微软新推出来Office卸载工具。下载链接&官方教程见下:从PC…

    2022年9月5日
    5
  • 抗渗等级p6是什么意思_混凝土p6是什么意思「建议收藏」

    抗渗等级p6是什么意思_混凝土p6是什么意思「建议收藏」展开全部40是混凝土的强度等62616964757a686964616fe58685e5aeb931333431356664级,P6是抗渗混凝土按抗渗压力。抗渗混凝土按抗渗压力不同分为P6、P8、P10、P12和大于P12共5个等级。抗渗混凝土通过提高混凝土的密实度,改善孔隙结构,从而减少渗透通道,提高抗渗性。混凝土按标准抗压强度(以边长为150mm的立方体为标准试件,在标准养护条件下养护28天,…

    2022年8月10日
    4
  • oracle sequence order_oracle session

    oracle sequence order_oracle session在oracle中sequence就是所谓的序列号,每次取的时候它会自动增加,一般用在需要按序列号排序的地方。  1、Create Sequence  你首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限,  CREATE SEQUEN

    2022年10月10日
    0
  • Emmet最全提示说明

    Emmet最全提示说明

    2021年11月24日
    50

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号