前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Platform device and platform driver

Platform device and platform driver

作者头像
全栈程序员站长
发布2022-09-15 11:01:41
9600
发布2022-09-15 11:01:41
举报
文章被收录于专栏:全栈程序员必看

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

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.cn/163815.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档