Linux Platform devices 平台设备驱动

发布者:MysticalSoul最新更新时间:2024-07-16 来源: elecfans关键字:Linux  Platform  devices 手机看文章 扫描二维码
随时随地手机看文章

platform平台设备驱动是基于设备总线驱动模型的,它只不过是将 device 进一步封装成为 platform_device,将 device_driver 进一步封装成为 platform_device_driver,前面已经分析过设备总线驱动模型,关于device 与 device_driver 的注册过程以及它们在sysfs文件系统中的层次关系就不在分析,本文重点分析platform平台设备驱动与设备总线驱动模型相比较新增添的那些东西。


在Linux设备模型的抽象中,存在着一类称作“Platform Device”的设备,内核是这样描述它们的(Documentation/driver-model/platform.txt):

Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms.  What they usually have in common is direct addressing from a CPU bus.  Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.

   

概括来说,Platform设备包括:基于端口的设备(已不推荐使用,保留下来只为兼容旧设备,legacy);连接物理总线的桥设备;集成在SOC平台上面的控制器;连接在其它bus上的设备(很少见)。等等。


这些设备有一个基本的特征:可以通过CPU bus直接寻址(例如在嵌入式系统常见的“寄存器”)。因此,由于这个共性,内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的封装,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动。


可以说,paltform设备对Linux驱动工程师是非常重要的,因为我们编写的大多数设备驱动,都是为了驱动plaftom设备。



platform_bus_type

我们知道,在设备总线驱动模型的中,BUS像一个月老一样,通过它的match函数,将注册到bus中的device与driver进行配对,那么每一个不同的bus 都有自己的match函数,我们来看看platform_bus_type.

struct bus_type platform_bus_type = {  

    .name       = 'platform',  

    .dev_attrs  = platform_dev_attrs,  

    .match      = platform_match,  

    .uevent     = platform_uevent,  

    .pm     = &platform_dev_pm_ops,  

};  

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

{  

    struct platform_device *pdev = to_platform_device(dev);  

    struct platform_driver *pdrv = to_platform_driver(drv);  

  

    /* match against the id table first */  

    if (pdrv->id_table)  

        return platform_match_id(pdrv->id_table, pdev) != NULL;  

  

    /* fall-back to driver name match */  

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

}  

    如果platform_device_driver中定义了id_table,则调用 platform_match_id 进行匹配


    举个例子:


static struct platform_device_id s3c24xx_driver_ids[] = {  

    {  

        .name       = 's3c2410-i2c',  

        .driver_data    = TYPE_S3C2410,  

    }, {  

        .name       = 's3c2440-i2c',  

        .driver_data    = TYPE_S3C2440,  

    }, { },  

};  

struct platform_device s3c_device_i2c0 = {  

    .name         = 's3c2410-i2c',  

#ifdef CONFIG_S3C_DEV_I2C1  

    .id       = 0,  

#else  

    .id       = -1,  

#endif  

    .num_resources    = ARRAY_SIZE(s3c_i2c_resource),  

    .resource     = s3c_i2c_resource,  

};  

static const struct platform_device_id *platform_match_id(struct platform_device_id *id, struct platform_device *pdev)  

{  

    while (id->name[0]) {  

        if (strcmp(pdev->name, id->name) == 0) {  

            pdev->id_entry = id;  

            return id;  

        }  

        id++;  

    }  

    return NULL;  

}  

    显然,platform_match_id 的作用就是遍历整个 Id_table 数组,寻找是否有与 platform_device->name 同名的,如果有,则返回这个 Platform_device_id ,使用Id_table 打破了原本设备总线驱动模型,一个 device 只能用与一个 device_driver 配对的局限性。现在一个platform_device_driver 可以与多个platform_device配对。


    如果没有,则只是根据 platform_device_driver->name 与 platform_device->name 进行比较,这也就是老师为啥在写平台设备驱动程序的时候经常说,“将驱动注册到内核中去,如果有同名设备,则调用driver->probe函数....”。




pletform_device 中的 id 的作用:


    if (pdev->id != -1)      /* 如果不是-1 对name编号 */  

        dev_set_name(&pdev->dev, '%s.%d', pdev->name,  pdev->id);  

    else                             /* -1时直接是名字 */

        dev_set_name(&pdev->dev, pdev->name); 



从device封装而来的platform_device

struct platform_device {  

    const char  * name;  

    int     id;  

    struct device   dev;  

    u32     num_resources;  

    struct resource * resource;  

  

    struct platform_device_id   *id_entry;  

  

    /* arch specific additions */  

    struct pdev_archdata    archdata;  

};    

    name,设备的名称,该名称在设备注册时,会拷贝到dev.init_name中。

    dev,真正的设备,通过 container_of ,就能找到整个platform_device ,访问其它成员,如后面要提到的 resource 

    num_resources、resource,该设备的资源描述,由struct resource(include/linux/ioport.h)结构抽象。 

    在Linux中,系统资源包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型。这些资源大多具有独占性,不允许多个设备同时使用,因此Linux内核提供了一些API,用于分配、管理这些资源。 

    当某个设备需要使用某些资源时,只需利用struct resource组织这些资源(如名称、类型、起始、结束地址等),并保存在该设备的resource指针中即可。然后在设备probe时,设备需求会调用资源管理接口,分配、使用这些资源。而内核的资源管理逻辑,可以判断这些资源是否已被使用、是否可被使用等等。

struct resource {  

    resource_size_t start;  

    resource_size_t end;  

    const char *name;  

    unsigned long flags;  

    struct resource *parent, *sibling, *child;  

};  

static struct resource led_resource[] = {   //jz2440的参数,驱动未测试   

    [0] = {  

        .start = 0x56000010,  

        .end   = 0x56000010 + 8 - 1,  

        .flags = IORESOURCE_MEM,  

    },  

    [1] = {  

        .start = 5,  

        .end   = 5,  

        .flags = IORESOURCE_IRQ,  

    },  

};  

static struct platform_device led_dev = {  

    .name = 'myled',    //设备名字 与 驱动相匹配  

    .id   = -1,  

    .num_resources = ARRAY_SIZE(led_resource),  

    .resource = led_resource,  

      

    .dev = {  

        .release = led_release,  

        //.devt = MKDEV(252, 1),  

    },  

};  


从 device_driver 封装而来的platform_device_dirver

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 (*resume)(struct platform_device *);  

    struct device_driver driver;  

    struct platform_device_id *id_table;  

};  

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;  

  

    return driver_register(&drv->driver);  

}  

    struct platform_driver结构和struct device_driver非常类似,上边的platform_drv_probe、platform_drv_remove、platform_drv_shutdown,只不过稍作转换调用platform_driver中的probe、remove、shutdown函数,举个例子稍微看一下

static int platform_drv_probe(struct device *_dev)  

{  

    struct platform_driver *drv = to_platform_driver(_dev->driver);  

    struct platform_device *dev = to_platform_device(_dev);  

  

    return drv->probe(dev);  

}  


Platform Device提供的API

/* include/linux/platform_device.h */  

extern int platform_device_register(struct platform_device *);  

extern void platform_device_unregister(struct platform_device *);  

   

extern void arch_setup_pdev_archdata(struct platform_device *);  

extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);  

extern int platform_get_irq(struct platform_device *, unsigned int);  

extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);  

extern int platform_get_irq_byname(struct platform_device *, const char *);  

extern int platform_add_devices(struct platform_device **, int);  

   

extern struct platform_device *platform_device_register_full(const struct platform_device_info *pdevinfo);  

[1] [2] [3]
关键字:Linux  Platform  devices 引用地址:Linux Platform devices 平台设备驱动

上一篇:spi驱动框架全面分析,从master驱动到设备驱动
下一篇:ALSA声卡07_分析调用过程_学习笔记

推荐阅读最新更新时间:2026-03-23 10:50

linux中LCD设备驱动(2)——基于s3c6410平台
上一篇说了framebuffer帧缓冲的有关知识,这一篇具体的说下LCD驱动的实现。 1、LCD设备驱动在linux内核中是作为平台设备存在,所以又要说那些已经说过很多遍的东西。 int __devinit s3cfb_init(void) { return platform_driver_register(&s3cfb_driver); } static void __exit s3cfb_cleanup(void) { platform_driver_unregister(&s3cfb_driver); } module_init(s3cfb_init); module_exit(s3cfb_cleanup); 对
[单片机]
linux中LCD设备驱动(3)——基于s3c6410平台
上一篇在说LCD设备驱动对应的probe函数时,没有说完,这一篇接着继续说probe函数。 s3cfb_pre_init();上一次说到了这个函数,而且还讲到了一个结构体s3cfb_fimd_info_t,并说了它的大致作用。 s3cfb_set_backlight_power(1);看名字就只到它的大致作用,与背光灯有关,源码如下: static void s3cfb_set_backlight_power(int to) { s3cfb_fimd.backlight_power = to; if (s3cfb_fimd.set_backlight_power) (s3cfb_fimd.set_backlight_
[单片机]
迅为i.MX6ULL终结者设备树下的Platform驱动实验程序编写
1 修改设备树文件 设备树文件可以直接使用第三十五章中添加的gpioled子节点即可,不用重复添加。 2 platform驱动程序 本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/15_gpioled_dts 创建led_driver.c文件,具体内容如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 6
[单片机]
【IMX6ULL学习笔记】十七、总线驱动框架-Platform、IIC、SPI等
一、总线 Linux 总线驱动模型主要可以分为三个部分:总线、设备、驱动。Linux 中的总线(bus)、驱动(driver)和设备(device)模型,也就是常说的驱动分离。Linux内核在启动时会向系统注册总线,比如 IIC总线、SPI总线、SDIO总线、Platform总线等。总线是与硬件平台无关的,由Linux系统提供并进行注册,无需用户关心。总线的职责就是将驱动与设备进行匹配,Linux系统内核使用 bus_type 结构体表示总线,此结构体定义在文件include/linux/device.h,bus_type 结构体内容如下: struct bus_type { const char *name; /* 总线
[单片机]
【IMX6ULL学习笔记】十七、总线驱动框架-<font color='red'>Platform</font>、IIC、SPI等
新思科技Polaris Software Integrity Platform®应用安全平台将提供全新功能
完全集成的 SaaS 产品可简化任何规模的 DevSecOps 应用安全测试 更快地交付安全、可信的应用产品是多个团队的共同责任。企业需要一个平台将开发、DevOps 和安全团队聚集在一起,满足DevSecOps发展需求,将安全融入整个软件开发生命周期(SDLC)中。 新思科技近日宣布将推出新一代Polaris Software Integrity Platform®软件质量与安全平台。该平台提供全新功能——快速应用安全测试(Fast Application Security Testing, fAST),并将于2023年4月24日至27日在美国旧金山RSA信息安全大会上进行首秀。凭借新思科技fAST Stati
[物联网]
Astera Labs面向CXL附加内存扩展和池化应用的Leo Memory Connectivity Platform进入预量产阶段
Astera Labs面向CXL附加内存扩展和池化应用的Leo Memory Connectivity Platform进入预量产阶段 解决加速和智能基础架构中的内存瓶颈及可组合性,为云规模部署打下基础 中国,北京 - 2022年9月1日- 智能系统专用连接解决方案企业Astera Labs今日宣布已开始向客户和战略合作伙伴提供Leo Memory Connectivity Platform预量产样品,平台可支持Compute Express Link™ (CXL™) 1.1和2.0,实现云服务器的安全性、可靠性以及高性能内存扩展和池化。 在对Leo智能内存控制器 (Smart Memory Controllers)与业界
[嵌入式]
2416开发记录十一:按键驱动(platform/中断)
在前面几章的基础上编写了一个按键中断的驱动,并验证成功。 这里用到了字符设备驱动,platform驱动,并有资源的获取,算是比较全面的platform驱动了。 首先是设备模块代码 //my2416PlatformKeyDev.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include
[单片机]
ADI为RapID Platform网络接口添加POWERLINK协议以提高设计灵活性和
中国,北京 — Analog Devices, Inc. (ADI),今日宣布为RapID™ Platform网络接口添加POWERLINK实时工业以太网协议,该接口由ADI公司的确定性以太网技术部门(以前的Innovasic, Inc.)开发。借助这个经过预先测试和认证的完整解决方案,系统设计人员能够以最快的速度和最低的成本,为现有产品或新产品添加工业以太网。通过RapID Platform网络接口,系统设计人员能够灵活地将RapID Platform作为一个模块嵌入现场设备应用中,或者完全将模块的组件嵌入现场设备的电路板中。无论通过哪种方式使用,RapID Platform都能够灵活可靠地管理主处理器的工业协议和网络流量,同时
[网络通信]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved