linux platform驱动模型详解
platform模型驱动和字符设备模型驱动

platform模型驱动和字符设备模型驱动字符设备驱动模型:1、申请设备号:动态申请(alloc_chrdev_region()),动态申请(register_chrdev_region())struct cdev btn_cdev;//申请设备号if(major){//静态申请设备号dev_id = MKDEV(major, 0);register_chrdev_region(dev_id, 1, "button");}else{//动态申请设备号alloc_chardev_region(&dev_id, 0, 1, "button");major = MAJOR(dev_id);}在Linux中以主设备号用来标识与设备文件相连的驱动程序。
次编号被驱动程序用来辨别操作的是哪个设备。
cdev 结构体的 dev_t 成员定义了设备号,为 32 位,其中高 12 位为主设备号,低20 位为次设备号。
设备号的获得与生成:获得:主设备号:MAJOR(dev_t dev);次设备号:MINOR(dev_t dev);生成:MKDEV(int major,int minor);2、初始化设备:void cdev_init(struct cdev *, struct file_operations *);cdev_init()函数用于初始化cdev 的成员,并建立cdev 和file_operations 之间的连接。
3、注册设备int cdev_add(struct cdev *, dev_t, unsigned);cdev_add()函数向系统添加一个 cdev,完成字符设备的注册。
4、创建设备节点手动创建设备节点:mknod 的标准形式为:mknod DEVNAME {b | c} MAJOR MINOR1,DEVNAME是要创建的设备文件名,如果想将设备文件放在一个特定的文件夹下,就需要先用mkdir在dev目录下新建一个目录;2, b和c 分别表示块设备和字符设备:b表示系统从块设备中读取数据的时候,直接从内存的buffer中读取数据,而不经过磁盘;c表示字符设备文件与设备传送数据的时候是以字符的形式传送,一次传送一个字符,比如打印机、终端都是以字符的形式传送数据;3,MAJOR和MINOR分别表示主设备号和次设备号:为了管理设备,系统为每个设备分配一个编号,一个设备号由主设备号和次设备号组成。
Linux驱动之platform总线详解

Linux驱动之platform总线详解⽬录1、platform 总线简介1.1、Linux 驱动的分离和分层思想1.1.1、Linux 驱动的分离1.2、platform 平台驱动模型2、platform 框架2.1、platform 总线2.2、platform 驱动2.2.1、platform 驱动定义2.2.2、platform 驱动注册2.3、platform 设备2.3.1、platform 设备定义2.4、platform 匹配过程3、总结1、platform 总线简介1.1、Linux 驱动的分离和分层思想1.1.1、Linux 驱动的分离先讲 Linux 驱动的分离,Linux 操作系统⽀持在各类 CPU 上运⾏,因为每⼀种 CPU 对设备的驱动不⼀样,这样就造成了Linux 内核中积累了⼤量代码,并且这些代码关于同⼀设备的描述⼤致相同,这就使得内核代码很冗余。
以 CPU 通过 I2C 控制 MPU6050 为例:从图可以看出每⼀种平台下都有⼀套主机驱动和⼀套设备驱动,因为每个平台的 I2C 控制器不同,所以这个主机驱动得每个平台配⼀个⾃⼰的,但⼤家所⽤的 MPU6050 是⼀样的,所以完全可以就共⽤⼀套设备驱动代码。
完善后框架如下:当然,这只是对于 I2C 下的 MPU6050 这个设备,实际情况下,I2C 下肯定会挂载很多设备,根据这个思路,我们可以得到框架为:⽽在实际开发中,I2C 主机驱动半导体⼚家会编写好,设备驱动也由设备⼚家编写好,我们只需要提供设备信息即可,如设备接到那个 I2C 接⼝上,I2C 速度为多少。
这样就相当于把设备信息从设备驱动中剥离出来,⽽设备驱动也会⽤标准⽅法去获取设备信息(如从设备树中获取设备信息)。
这样就相当于驱动只负责驱动,设备(信息)只负责设备,想办法将两者进⾏匹配即可,来做这个匹配⼯作的就是总线,这就构成了 Linux 中的总线-驱动-设备模型。
platform设备驱动全透析

platform设备驱动全透析1.1 platform总线、设备与驱动在Linux 2.6的设备驱动模型中,关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2 C、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设等确不依附于此类总线。
基于这一背景,Linux 发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver。
注意,所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux 系统提供的一种附加手段,例如,在S3C6410处理器中,把内部集成的I2 C、RTC、SPI、LCD、看门狗等控制器都归纳为platform_device,而它们本身就是字符设备。
platform_device 结构体的定义如代码清单1所示。
代码清单1 platform_device结构体1 struct platform_device {2 const char * name;/* 设备名*/3 u32 id;4 struct device dev;5 u32 num_resources;/* 设备所使用各类资源数量*/6 struct resource * resource;/* 资源*/7 };platform_driver这个结构体中包含probe()、remove()、shutdown()、suspend()、resume()函数,通常也需要由驱动实现,如代码清单2。
代码清单2 platform_driver结构体1 struct platform_driver {2 int (*probe)(struct platform_device *);3 int (*remove)(struct platform_device *);4 void (*shutdown)(struct platform_device *);5 int (*suspend)(struct platform_device *, pm_message_t state);6 int (*suspend_late)(struct platform_device *, pm_message_t state);7 int (*resume_early)(struct platform_device *);8 int (*resume)(struct platform_device *);9 struct pm_ext_ops *pm;10 struct device_driver driver;11};系统中为platform总线定义了一个bus_type的实例platform_bus_type,其定义如代码清单15.3。
Linux设备驱动模型与sysfs---platform总线设备驱动

Linux在2.6版本引入了设备驱动模型,设备驱动模型负责统一实现和维护一些特性,诸如:热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施1.设备驱动模型基本概念设备驱动模型主要包含:类(class)、总线(bus)、设备(device)、驱动(driver),它们的本质都是内核中的几种数据结构的“实例”∙类的本质是class结构体类型,各种不同的类其实就是class的各种实例∙总线的本质是bus_type结构体类型,各种不同的总线其实就是bus_type的各种实例∙设备的本质是device结构体类型,各种不同的设备其实就是device的各种实例∙驱动的本质是device_driver结构体类型,各种不同的驱动其实就是device_driver的各种实例2.sysfs基本概念sysfs其实就是/sys目录,其主要作用就是:展示设备驱动模型中各组件的层次关系,并将各组件的本体——内核中的数据结构以文件形式呈现,方便用户层查看及操作3./sys目录结构与设备驱动模型∙/sys目录结构很好的展示了驱动设备模型,如图:∙注意:同一个设备可能在/sys中存在多个设备文件,比如一颗led的设备文件可能在/sys/bus/platform/devices/led1,同时还有一个在/sys/class/leds/led1。
虽然他们都是同一颗led的设备文件,但是他们的来源、机制、原理都是不同的,不能混为一谈4.各组件的特性与联系∙kobject:设备驱动模型各实例的最基本单元,提供一些公用型服务如:提供该实例在sysfs中的操作方法(show和store);提供在sysfs中以文件形式存在的属性,其实就是应用接口;提供各个实例的层次架构,让sysfs中弄出目录结构。
设备驱动模型中每个实例内部都会包含一个kobject∙总线、设备、驱动,这三者有着密切的联系。
在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。
Linux设备驱动模型之platform总线深入浅出

Linux设备驱动模型之platform总线深入浅出在Linux2.6以后的设备驱动模型中,需关心总线,设备和驱动这三种实体,总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
对于依附在USB、PCI、I2C、SPI等物理总线来这些都不是问题。
但是在嵌入式系统里面,在Soc系统中集成的独立外设控制器,挂接在Soc内存空间的外设等却不依附在此类总线。
基于这一背景,Linux发明了一种总线,称为platform。
相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。
platform总线相关代码:driver\base\platform.c 文件相关结构体定义:include\linux\platform_device.h 文件中platform总线管理下最重要的两个结构体是platform_device和platform_driver 分别表示设备和驱动在Linux中的定义如下一:platform_driver//include\linux\platform_device.h 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 (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *);//恢复函数,在开机时被调用struct device_driver driver;//设备驱动结构};12345678。
详解Linux2.6内核中基于platform机制的驱动模型

详解Linux2.6内核中基于platform机制的驱动模型【摘要】本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型。
首先介绍了Platform总线的基本概念,接着介绍了platform device和platform driver的定义和加载过程,分析了其与基类device 和driver的派生关系及在此过程中面向对象的设计思想。
最后以ARM S3C2440中I2C控制器为例介绍了基于platform总线的驱动开发流程。
【关键字】platform_bus, platform_device, resource , platform_driver, file_operations目录1 何谓platform bus? 22 device和platform_device 33 device_register和platform_device_register 54 device_driver和platform driver 85 driver_register 和platform_driver_register 106 bus、device及driver三者之间的关系177 哪些适用于plarform驱动?188 基于platform总线的驱动开发流程188.1 初始化platform_bus 198.2 定义platform_device 228.3 注册platform_device 228.4 定义platform_driver 288.5 注册platform_driver 298.6 操作设备321 何谓platform bus?Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。
设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。
因此从2.6内核开始引入了设备模型。
深入解析LinuxPlatform_device及驱动

深⼊解析LinuxPlatform_device及驱动[导读] 前⽂分析了Linux设备驱动的驱动模型,本⽂来聊聊Platform_driver/Platform_device这个类。
做嵌⼊式Linux的驱动,这个也是绕不开的,所以来学习分析总结⼀下。
上⽂阅读:注:代码分析基于linux-5.4.31为什么有Platform_driver前⽂谈到的总线驱动模型(注这个图是照着bootlin的⽂档绘制的):同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解⽅便):可见驱动程序的模型分层有⼀层总线基础层,那么对于嵌⼊式开发领域⽽⾔,有很多SOC芯⽚内置了各种外设,并⽐如LCD,UART、audio、摄像头⼝等等,并没有总线。
为了统⼀驱动架构抽象,所以引⼊了platform bus这个虚拟的总线模型。
做过嵌⼊式开发的⼈应该都有体会,这类设备在嵌⼊式系统中⾮常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。
在强调⼀下这个是统⼀在总线驱动模型这个体系内的。
驱动模型的实现定义在./include/linux/platform_device.h中,来梳理⼀下这些数据结构间的关系:platform_device ⽤于抽象平台设备platform_driver ⽤于抽象匹配平台设备对应的驱动程序通过继承演化关系分析,platform_device/platform_driver 仍然统⼀于总线驱动模型,只是虚拟出来了⼀条platform bus这样⼀条虚拟总线。
platform_bus在哪⾥实现的呢?该模块的实现位于./driver/base/platform.c中struct device platform_bus = {.init_name = "platform",};platform.c导出了⼀系列内核全局操作接⼝集:EXPORT_SYMBOL_GPL(platform_bus);EXPORT_SYMBOL_GPL(__platform_driver_register);EXPORT_SYMBOL_GPL(__platform_driver_probe);EXPORT_SYMBOL_GPL(platform_get_resource_byname);EXPORT_SYMBOL_GPL(platform_get_irq_byname);....那么既然这条总线并不存在,往往并不能实现设备枚举、热插拔等功能。
platform驱动启动及注册过程分析

2、平台驱动的优点
platform架构把设备和驱动给分开了,这样做的好处就是提高了驱动的移植性。platform被分成platform设备、platform驱动和 platform总线。platform设备就是用来描述外设的一些资源,platform驱动就是用来实现驱动设备的代码,platform总线是用来管理 platform设备和platform驱动的,实现platform设备和platform驱动的匹配。platform总线是在系统启动的时候就进行了初始化。
7、平台设备与平台驱动的匹配
我们知道platform_device和platform_driver是被platform_bus管理的,所以platform_device和platform_driver的匹配工作是在 platform_bus中完成的,具体是由platform_match函数实现的,而platform_match又是存在于platform_bus_type结构体变量中的, 这个结构体变量中所存的信息又是在platform_bus初始化时注册进内核中的。下面来看platform_match函数的实现: static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); 由device的地址推出platform_device的地址 struct platform_driver *pdrv = to_platform_driver(drv); 由device_driver的地址推出platform_driver的地址 /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ 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); if条件判断为0,忽略
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ห้องสมุดไป่ตู้
(2)platform 总线结构 structbus_typeplatform_bus_type={ .name="platform", .dev_attrs=platform_dev_attrs, .match=platform_match, .uevent=platform_uevent, .pm=&platform_dev_pm_ops, }; platform_dev_attrs设备属性 platform_matchmatch 函数,这个函数在当属于 platform 的设备或者驱动注册 到内核时就会调用,完成设备与驱动的匹配工作。 platform_uevent热插拔操作函数 三。platform设备 1.platform_device结构 structplatform_device{ constchar*name; intid; structdevicedev; u32num_resources; structresource*resource; structplatform_device_id*id_entry; /*archspecificadditions*/ structpdev_archdataarchdata; }; (1)platform_device 结构体中有一个 structresource 结构,是设备占用系统的资源, 在ioport.h 中定义如下: structresource{ resource_size_tstart; resource_size_tend; constchar*name; unsignedlongflags; structresource*parent,*sibling,*child; }; (2)num_resources占用系统资源的数目,一般设备都占用两种资源,io 内存和中断信 号线。这个为两种资源的总和。 2.设备注册函数platform_device_register intplatform_device_register(structplatform_device*pdev) {
} } //上面主要是遍历设备所占用的资源,找到对应的父资源,如果没有定义,那么根据资 源的类型,分别赋予 iomem_resource 和 ioport_resource,然后调用 insert_resource 插入资源。 //这样系统的资源就形成了一个树形的数据结构,便于系统的管理 pr_debug("Registeringplatformdevice'%s'.Parentat%s\n", dev_name(&pdev->dev),dev_name(pdev->dev.parent)); ret=device_add(&pdev->dev); //注册到设备模型中 if(ret==0) returnret; failed: while(--i>=0){ structresource*r=&pdev->resource[i]; unsignedlongtype=resource_type(r); if(type==IORESOURCE_MEM||type==IORESOURCE_IO) release_resource(r); } returnret; } 3.mini2440 内核注册 platform 设备过程 因为一种 soc 确定之后,其外设模块就已经确定了,所以注册 platform 设备就由板级 初始化代码来完成,在 mini2440 中是 mach-mini2440.c 的 mini2440_machine_init 函 数中调用 platform_add_devices(mini2440_devices,ARRAY_SIZE (mini2440_devices))来完成注册。这个函数完成 mini2440 的所有 platform 设备的 注册: (1)platform_add_devices 函数是 platform_device_register 的简单封装,它向内 核注册一组 platform 设备 (2)mini2440_devices 是一个 platform_device 指针数组,定义如下: staticstructplatform_device*mini2440_devices[]__initdata={ &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth,
device_initialize(&pdev->dev); returnplatform_device_add(pdev); } 这个函数首先初始化了 platform_device 的 device 结构,然后调用 platform_device_add,这个是注册函数的关键,下面分析 platform_device_add: intplatform_device_add(structplatform_device*pdev) { inti,ret=0; if(!pdev) return-EINVAL; if(!pdev->dev.parent) pdev->dev.parent=&platform_bus; //可以看出,platform 设备的父设备一般都是 platform_bus,所以注册后的 platform 设备都出现在/sys/devices/platform_bus 下 pdev->dev.bus=&platform_bus_type; //挂到 platform 总线上 if(pdev->id!=-1) dev_set_name(&pdev->dev,"%s.%d",pdev->name,pdev->id); else dev_set_name(&pdev->dev,"%s",pdev->name); //设置设备名字,这个名字与/sys/devices/platform_bus 下的名字对应 for(i=0;i<pdev->num_resources;i++){//下面操作设备所占用的系统资源 structresource*p,*r=&pdev->resource[i]; if(r->name==NULL) r->name=dev_name(&pdev->dev); p=r->parent; if(!p){ if(resource_type(r)==IORESOURCE_MEM) p=&iomem_resource; elseif(resource_type(r)==IORESOURCE_IO) p=&ioport_resource; } if(p&&insert_resource(p,r)){ printk(KERN_ERR "%s:failedtoclaimresource%d\n", dev_name(&pdev->dev),i); ret=-EBUSY; gotofailed;