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,忽略
驱动框架
linux platform 驱动模型分析一。
概述platform设备和驱动与linux设备模型密切相关。
platform在linux设备模型中,其实就是一种虚拟总线没有对应的硬件结构。
它的主要作用就是管理系统的外设资源,比如io内存,中断信号线。
现在大多数处理器芯片都是soc,如s3c2440,它包括处理器内核(arm920t)和系统的外设(lcd接口,nandflash接口等)。
linux在引入了platform机制之后,内核假设所有的这些外设都挂载在platform虚拟总线上,以便进行统一管理。
二。
platform 总线1. 在系统中platform对应的文件drivers/base/platform.c,它不是作为一个模块注册到内核的,关键的注册总线的函数由系统初始化部分,对应/init/main.c中的do_basic_setup函数间接调用。
这里可以看出platform非常重要,要在系统其他驱动加载之前注册。
下面分析platform总线注册函数[cpp] view plaincopyprint?int __init platform_bus_init(void){int error;early_platform_cleanup();error = device_register(&platform_bus);//总线也是设备,所以也要进行设备的注册if (error)return error;error = bus_register(&platform_bus_type);//注册platform_bus_type总线到内核if (error)device_unregister(&platform_bus);return error;}int __init platform_bus_init(void){ int error; early_platform_cleanup();error = device_register(&platform_bus);//总线也是设备,所以也要进行设备的注册if (error)return error;error = bus_register(&platform_bus_type);//注册platform_bus_type总线到内核if (error)device_unregister(&platform_bus);return error; } 这个函数向内核注册了一种总线。
Linux的Platform驱动模型
2.1 定义Platform总线
(1) bus_type总线的定义 // include\linux\device.h struct bus_type { //每个bus_type对象都对应/sys/bus目录下的一个子目录 const char *name; //总线名称 const char *dev_name; struct device *dev_root; struct bus_attribute *bus_attrs; //总线自身的属性,show,store struct device_attribute *dev_attrs; // 总线下设备共有的属性 struct driver_attribute *drv_attrs; // 总线下驱动共有的属性 int (*match)(struct device *dev, struct device_driver *drv); //匹配函数 int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //事件 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 dev_pm_ops *pm; //管理电源的函数 struct iommu_ops *iommu_ops; struct subsys_private *p; //管理设备与驱动的数据结构,私有变量指针 struct lock_class_key lock_key; };
Linux platform驱动架构的解析与应用
Linux platform驱动架构的解析与应用赵波;高真香子;项伯阳;于忠得【摘要】采用Linux 2.6.31内核,详细介绍、分析了platform驱动架构的组成与实现的方法,并以FS2410为硬件实验平台、8寸夏普TFT LCD屏为实验对象,实现了基于platform驱动架构的LCD驱动.实验证明,在采用该方法移植的LCD上,可以清晰、稳定地运行QT/E应用程序,此种架构具有较好的移植性和安全性.%To meet the management of equipments, Linux 2. 6 provides Linux device model a general abstraction describing the structure of the system, which is now used within the kernel to support a wide variety of tasks. This article recommends in detail and analyses Linux platform driver framework based on Linux 2. 6. 31. Moreover, porting the 8 inch TFT LCD driver to FS2410 using this method results successfully, which can run QT/E applications clearly and stably. The Linux platform framework is good at porting and security.【期刊名称】《大连工业大学学报》【年(卷),期】2013(032)001【总页数】4页(P71-74)【关键词】Linux platform;Linux driver;Linux设备驱动模型;LCD驱动【作者】赵波;高真香子;项伯阳;于忠得【作者单位】大连工业大学信息科学与工程学院,辽宁大连116034;大连工业大学信息科学与工程学院,辽宁大连116034;大连交通大学电气信息学院,辽宁大连116028;大连工业大学信息科学与工程学院,辽宁大连116034【正文语种】中文【中图分类】TP368.10 引言为统一管理Linux中的所有设备,Linux开发了设备模型。
Linux驱动中的platform
Linux驱动中的platform从Linux2.6 内核起,引入一套新的驱动管理和注册机制:platform_device和platform_driver 。
Linux 中大部分的设备驱动,都可以使用这套机制,设备用platform_device 表示;驱动用platform_driver 进行注册。
Linux platform driver 机制和传统的device driver 机制(即:通过driver_register 函数进行注册)相比,一个十分明显的优势在于platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中用使用这些资源时,通过platform device 提供的标准接口进行申请并使用。
platform 是一个虚拟的地址总线,相比PCI、USB,它主要用于描述SOC 上的片上资源。
platform 所描述的资源有一个共同点:在CPU 的总线上直接取址。
平台设备会分到一个名称(用在驱动绑定中)以及一系列诸如地址和中断请求号(IRQ)之类的资源。
platform 总线下驱动的开发步骤是:1、设备需要实现的结构体是:platform_device 。
1)初始化resource 结构变量2)初始化platform_device 结构变量3)向系统注册设备:platform_device_register。
以上三步,必须在设备驱动加载前完成,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。
platform_driver_register()中添加device 到内核最终还是调用的device_add 函数。
Platform_device_add 和device_add 最主要的区别是多了一步insert_resource(p, r),即将platform 资源(resource)添加进内核,由内核统一管理。
LinuxPlatform驱动模型(二)_驱动方法
LinuxPlatform驱动模型(⼆)_驱动⽅法在和中我们讨论了设备信息的写法,本⽂主要讨论平台总线中另外⼀部分-驱动⽅法,将试图回答下⾯⼏个问题:1. 如何填充platform_driver对象?2. 如何将驱动⽅法对象注册到平台总线中?正⽂前的⼀点罗嗦写驱动也有⼀段时间了,可以发现,其实驱动本质上只做了两件事:向上提供接⼝,向下控制硬件,当然,这⾥的向上并不是直接提供接⼝到应⽤层,⽽是提供接⼝给内核再由内核间接的将我们的接⼝提供给应⽤层。
⽽写驱动也是有⼀些套路可寻的,拿到⼀个硬件,我们⼤体可以按照下⾯的流程写⼀个驱动:1. 确定驱动架构:根据硬件连接⽅式结合分层/分离思想设计驱动的基本结构2. 确定驱动对象:内核中的⼀个驱动/设备就是⼀个对象,1.定义,2.初始化,3.注册,4.注销3. 向上提供接⼝:根据业务需要确定提供cdev/proc/sysfs哪种接⼝4. 向下控制硬件:1.查看原理图确定引脚和控制逻辑,2.查看芯⽚⼿册确定寄存器配置⽅式,3.进⾏内存映射,4.实现控制逻辑认识驱动⽅法对象内核⽤platform_driver结构来表⽰⼀个驱动⽅法对象//include/linux/device.h173 struct platform_driver {174 int (*probe)(struct platform_device *);175 int (*remove)(struct platform_device *);176 void (*shutdown)(struct platform_device *);177 int (*suspend)(struct platform_device *, pm_message_t state);178 int (*resume)(struct platform_device *);179 struct device_driver driver;180 const struct platform_device_id *id_table;181 bool prevent_deferred_probe;182 };在这个结构中,我们主要关⼼以下⼏个成员struct platform_driver--174-->探测函数,如果驱动匹配到了⽬标设备,总线会⾃动回调probe函数,必须实现,下⾯详细讨论。
platform设备驱动模型(基于globalfifo)
Platform设备驱动模型linux设备驱动模型中,三个重要的实体,总线、设备、驱动。
其中的概念和意义不再强调,网上还有书上都有很多。
这里只强调两点:1)引入platform使得设备被挂在在总线上,符合了linux2.6内核的设备模型。
2)隔离BSP和驱动。
在BSP中定义的platform设备和设备使用的资源、设备的具体配置信息,而在驱动中,只需要通过通用API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。
几个重要的结构体:platform_bus_type是platform总线定义了一个bus_type的实例。
这部分有系统内部为我们完成,我们不需要去做特殊的定义或者初始化。
点击(此处)折叠或打开1struct bus_type platform_bus_type ={ ="platform", //总线名称3.dev_attrs = platform_dev_attrs,4.match =platform_match,//匹配函数,该函数确定了platform_device和platform_driver之间如何匹配5.uevent = platform_uevent, //用于添加环境变量6.pm = PLATFORM_PM_OPS_PTR,7};8EXPORT_SYMBOL_GPL(platform_bus_type);910int __init platform_bus_init(void) //总线的初始化11{12int error;1314 early_platform_cleanup();1516error= device_register(&platform_bus);17if(error)18 return error;19error= bus_register(&platform_bus_type);20if(error)21 device_unregister(&platform_bus);22 return error;23}24总线也是一种设备,要先注册总线设备,在使用总线设备完成总线注册。
linux ALSA 声卡驱动之Asoc架构中的Platform
1.Platform驱动在ASoC中的作用前面说过,ASoC被分为Machine、Platform和Codec三大部分,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DAI)把音频数据传送给codec进行处理,最终由codec输出驱动耳机或者喇叭的音频信号。
在具体的实现上。
ASoC把platform驱动分为两个部分:snd_soc_platform_driver和snd_soc_dai_driver。
其中。
Paltform_driver负责管理音频数据,把音频数据通过dma或者其他操作传送到cpu dai中,dai_driver主要完成cpu的dai的参数配置,同时会通过一定的途径把必要的dma 等参数与snd_soc_platform_driver进行交互2.snd_soc_platform_driver的注册通常,ASoC把snd_soc_platform_driver注册为一个系统的platform_driver,不要被这两个术语锁迷惑,前者是针对ASoC子系统,后者是来自linux的设备驱动模型,我们要做的就是. 定义一个snd_soc_platform_driver结构的实例. 在platform_driver的probe回调中利用ASoC的API:snd_soc_register_platform()注册上面定义的实例;. 实现snd_soc_pllatform_driver中的各个回调函数以kernel2.6.37中的/sound/soc/davinci/davinici-pcm.c为例Snd_soc_register_platform()该函数用于注册一个snd_soc_platform,只有注册以后,它才可以被Machine驱动使用,它的代码已经清晰的表达了它的实现过程. 为snd_soc_platform实例申请内存. 从platform_device中获取他的名字,用于Machine驱动的匹配工作;. 初始化snd_soc_platform的字段. 把snd_soc_platform实例链接到全局链表platform_list中. 调用snd_soc_instantiate_cards,触发声卡的machine、platform、codec、dai等的匹配工作3.cpu的snd_soc_dai driver驱动的注册dai驱动通常对应cpu的一个或者几个I2S/PCM接口,与snd_soc_platform一样,dai 驱动也就实现为一个platform driver,实现一个dai驱动大致可以分为以下几个步骤:. 定义一个snd_soc_dai_driver结构的实例;. 在对应的platform_driver中的probe回调中通过API:snd_soc_register_dai或者snd_soc_register_dais,注册snd_soc_dai实例;. 实现snd_soc_dai_driver结构中的probe、suspend等回调;. 实现snd_soc_dai_driver结构中的snd_soc_dai_ops字段中的回调函数;Snd_soc_register_dai这个函数在上一篇codec驱动总有介绍Snd_soc_dai该结构在snd_soc_register_dai函数中通过动态内存申请获得,有如下几个重要字段:. driver 指向关联的snd_soc_dai_sriver结构,由注册时通过参数传入;. Playback_dma_data用于保存该dai播放stream的dma信息,例如dma的目标地址,dma传送单元大小和通道号. Capture_dma_data同上,用于录音stream;. Platform 指向关联的snd_soc_platform结构;Snd_soc_dai_driver该结构需要自己根据不同的soc芯片进行定义,关键字段如下. probe、remove回调函数,分别在声卡加载和预卸时被调用;. suspend、resume 电源管理回调函数. Ops 指向snd_soc_dai_ops结构,用于配置和控制该dai;. Playback snd_soc_pcm_stream结构,用于指出该dai支持的声道数,码率,数据格式等. Capture snd_soc_pcm_stream结构,用于指出该dai支持的声道数,码率,数据格式4.Snd_soc_dai_driver中的ops字段Ops字段指向一个snd_soc_dai_ops结构,该结构实际上是一组回调函数的集合,dai的配置和控制几乎都是通过这些回调函数来实现的,这些回调函数基本可以分为3大类,驱动程序可以根据实际情况实现其中的一个部分工作始终配置函数通常由machine驱动调用:. set_sysclk 设置dai的主时钟. set_pll 设置PLL参数. set_clkdiv 设置分频系数. dai的格式配置函数通常由machine驱动调用:. set_fmt 设置dai的格式. set_tdm_slot 如果dai支持时分复用,用于设置时分复用的slot;. set_channel_map 声道的时分复用映射设置;. set_tristate 设置dai引脚的状态,当与其他dai并联使用同一个引脚时需要使用该回调标准的snd_soc_ops回调通常由soc-core在进行PCM操作时调用:. startup. Shutdown. Hw_params. Hw_free. Prepare. Trygger抗pop,pop声由soc-core调用;.digital_mute以下这些api通常被machine驱动使用,machine驱动在他的snd_pcm_ops字段中的hw_paarams回调中使用这些api:. Snd_soc_daiPset_fmt() 实际上会调用snd_soc_dai_ops或者codec driver中的set_fmt回调. Snd_soc_dai_set_pll() 实际上会调用snd_soc_dai_ops或者codec driver中的set_pll回调. Snd_soc_dai_set_sysclk() 实际上会调用snd_soc_dai_ops或者codec driver中的set_sysclk回调. Snd_soc_dai_set_clkdiv() 实际上会调用snd_soc_dai_ops或者codec driver中的set_clkdiv回调Snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)的第二个参数fmt在这里特别说一下,ASoC目前只是用了它的低16位,并且为它专门定义了一些宏来方便我们使用:Bit 0-3用于设置接口的格式:Bit 4-7用于设置接口时钟的开关特性:Bit 8-11用于设置接口时钟的相位Bit 12-15用于设置接口的主从格式5.snd_soc_platform_driver中的ops字段该字段是一个snd_pcm_ops结构,实现该结构中的各个回调函数式soc platform驱动的主要工作,他们基本都涉及dma操作以及dma buffer的管理等工作。
【Linux笔记】总线设备驱动模型
【Linux笔记】总线设备驱动模型Linux内核中更是存在着更多的分离、分层思想的代码,platform平台设备驱动就是用了这样的思想。
本篇笔记我们一起来学习一下platform驱动框架。
对于 Linux 这样一个成熟、庞大、复杂的操作系统,代码的重用性非常重要,否则的话就会在Linux 内核中存在大量无意义的重复代码。
为了能提高驱动代码的重用性,因此引入了platform。
下面以一个例子来说明传统的设动转变至Linux 总线、驱动和设备模式(来源:《正点原子Linux驱动开发指南》):最后一张图就是Linux下的总线(bus)、驱动(driver)和设备(device)模型。
但是在SOC 中有些外设是没有总线这个概念的,但是又要使用总线、驱动和设备模型该怎么办呢?为了解决此问题, Linux 提出了 platform_bus 这个虚拟总线,相应的就有 platform_driver 和 platform_device。
总线设备驱动模型1、platform_busplatform总线实例(在文件drivers/base/platform.c 中):这里我们重点关注匹配函数platform_match:我们暂且先知道其有几种匹配方法。
2、platform_driverplatform驱动结构体(在文件include/linux/platform_device.h 中):platform_driver 结构体中的driver成员所属的结构体类型为(在文件include/linux/device.h 中):这里体现出了C语言的面向对象的思想,其中driver相当于基类,platform_driver继承了这个基类。
struct device_driver 结构体中(在文件include/linux/device.h中)的name成员在上面提到的匹配函数platform_match里用到,即:platform_driver 结构体中的id_table成员所属的结构体类型为(在文件include/linux/mod_devicetable.h 中):注册/卸载函数:platform 驱动注册函数:int platform_driver_register(struct platform_driver *driver);platform 驱动卸载函数:void platform_driver_unregister(struct platform_driver *drv);3、platform_device描述设备有两种方法:一种是用用设备树来指定,另一种是直接用platform_device结构体来指定。
LINUX设备驱动之platfo...
LINUX设备驱动之platfo...阅读本⽂之前,如果你对设备驱动模型还不了解,请先阅读本站设备驱动模型相关⽂章。
Platform总线是kernel中的⼀种虚拟总线,2.6版本很多驱动都⽤它来实现。
⼀.Platform初始化系统启动时初始化时创建了platform_bus设备和platform_bus_type总线:内核初始化函数kernel_init()中调⽤了do_basic_setup() ,该函数中调⽤driver_init(),该函数中调⽤platform_bus_init(),我们看看platform_bus_init()函数:int __init platform_bus_init(void){int error;early_platform_cleanup();error = device_register(&platform_bus);if (error)return error;error = bus_register(&platform_bus_type);if (error)device_unregister(&platform_bus);return error;}device_register(&platform_bus)中的platform_bus如下:struct device platform_bus = {.init_name = "platform",};改函数把设备名为platform 的设备platform_bus注册到系统中,其他的platform的设备都会以它为parent。
它在sysfs中⽬录下.即 /sys/devices/platform。
接着bus_register(&platform_bus_type)注册了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,};默认platform_bus_type中没有定义probe函数。
了解Linux平台总线的驱动设备模型一定不会错
了解Linux平台总线的驱动设备模型一定不会错platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。
Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
Linux2.6系统中定义了一个bus_type的实例platform_bus_type[cpp] view plain copyprint?struct bus_type platform_bus_type = {.name = "platform",.dev_attrs = platform_dev_attrs,.match = platform_match, //设备和驱动使用match函数来判断是否匹配.uevent = platform_uevent,.pm = PLATFORM_PM_OPS_PTR,};[cpp] view plain copyprint?/* platform_match函数用于匹配总线中的驱动和设备 */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_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,。
- 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;