`
thecloud
  • 浏览: 871930 次
文章分类
社区版块
存档分类
最新评论

platform_device(平台设备)和platform_driver(平台驱动)及平台设备驱动工作原理

 
阅读更多
首先介绍一下注册一个驱动的步骤:
1、定义一个platform_driver结构
2、初始化这个结构,指定其probe、remove等函数,并初始化其中的driver变量
3、实现其probe、remove等函数

看platform_driver结构,定义于include/linux/platform_device.h文件中:

structplatform_driver{
int(*probe)(structplatform_device*);
int(*remove)(structplatform_device*);
void(*shutdown)(structplatform_device*);
int(*suspend)(structplatform_device*,pm_message_t state);
int(*suspend_late)(structplatform_device*,pm_message_t state);
int(*resume_early)(structplatform_device*);
int(*resume)(structplatform_device*);
structdevice_driver driver;
};

可见,它包含了设备操作的几个功能函数,同样重要的是,它还包含了一个device_driver结构。刚才提到了驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于include/linux/device.h中:

structdevice_driver{
constchar*name;
structbus_type*bus;

structkobjectkobj;
structklistklist_devices;
structklist_nodeknode_bus;

structmodule*owner;
constchar*mod_name;/* used for built-in modules */
structmodule_kobject*mkobj;

int(*probe)(structdevice*dev);
int(*remove)(structdevice*dev);
void(*shutdown)(structdevice*dev);
int(*suspend)(structdevice*dev,pm_message_t state);
int(*resume)(structdevice*dev);
};

需要注意这两个变量:name和owner。那么的作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。

下面是一个platform_driver的初始化实例:

staticstructplatform_driver s3c2410iis_driver={
.probe=s3c2410iis_probe,
.remove=s3c2410iis_remove,
.driver={
.name="s3c2410-iis",
.owner=THIS_MODULE,
},
};

上面的初始化是一个音频驱动的实例。注意其中的driver这个结构体,只初始化了其name和owner两个量。接着看一下和driver相关的另一个结构,定义如下:

structplatform_device{
constchar*name;
intid;
structdevicedev;
u32num_resources;
structresource*resource;
};

该结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。platform_device就描述了设备对象。下面是一个具体的实例:

structplatform_device s3c_device_iis={
.name="s3c2410-iis",
.id=-1,
.num_resources=ARRAY_SIZE(s3c_iis_resource),
.resource=s3c_iis_resource,
.dev={
.dma_mask=&s3c_device_iis_dmamask,
.coherent_dma_mask=0xffffffffUL
}
};

它的name变量和刚才上面的platform_driver的name变量是一致的,内核正是通过这个一致性来为驱动程序找到资源,即platform_device中的resource。这个结构的定义如下,位于include/linux/ioport.h中:

structresource{
resource_size_t start;
resource_size_t end;
constchar*name;
unsignedlongflags;
structresource*parent,*sibling,*child;
};

下面是一个具体的实例:

staticstructresource s3c_iis_resource[]={
[0]={
.start=S3C24XX_PA_IIS,
.end=S3C24XX_PA_IIS+S3C24XX_SZ_IIS-1,
.flags=IORESOURCE_MEM,
}
};

这个结构的作用就是告诉驱动程序设备的起始地址和终止地址和设备的端口类型。这里的地址指的是物理地址。

另外还需要注意platform_device中的device结构,它详细描述了设备的情况,定义如下:

structdevice{
structklistklist_children;
structklist_nodeknode_parent;/* node in sibling list */
structklist_nodeknode_driver;
structklist_nodeknode_bus;
structdevice*parent;

structkobject kobj;
charbus_id[BUS_ID_SIZE];/* position on parent bus */
structdevice_type*type;
unsignedis_registered:1;
unsigneduevent_suppress:1;

structsemaphoresem;/* semaphore to synchronize calls to
* its driver.
*/


structbus_type*bus;/* type of bus device is on */
structdevice_driver*driver;/* which driver has allocated this
device */

void*driver_data;/* data private to the driver */
void*platform_data;/* Platform specific data, device
core doesn't touch it */

structdev_pm_infopower;

#ifdefCONFIG_NUMA
intnuma_node;/* NUMA node this device is close to */
#endif
u64*dma_mask;/* dma mask (if dma'able device) */
u64coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */


structlist_headdma_pools;/* dma pools (if dma'ble) */

structdma_coherent_mem*dma_mem;/* internal for coherent mem
override */

/* arch specific additions */
structdev_archdataarchdata;

spinlock_tdevres_lock;
structlist_headdevres_head;

/* class_device migration path */
structlist_headnode;
structclass*class;
dev_tdevt;/* dev_t, creates the sysfs "dev" */
structattribute_group**groups;/* optional groups */

void(*release)(structdevice*dev);
};

上面把驱动程序中涉及到的主要结构都介绍了,下面主要说一下驱动程序中怎样对这个结构进行处理,以使驱动程序能运行。

紧接上面介绍的数据结构,介绍驱动程序的具体实现过程。

相信大家都知道module_init()这个宏。驱动模块加载的时候会调用这个宏。它接收一个函数为参数,作为它的参数的函数将会对上面提到的platform_driver进行处理。看一个实例:假如这里module_init要接收的参数为s3c2410_uda1341_init这个函数,下面是这个函数的定义:

staticint__init s3c2410_uda1341_init(void){
memzero(&input_stream,sizeof(audio_stream_t));
memzero(&output_stream,sizeof(audio_stream_t));
returnplatform_driver_register(&s3c2410iis_driver);
}

注意函数体的最后一行,它调用的是platform_driver_register这个函数。这个函数定义于driver/base/platform.c中,原型如下:

int platform_driver_register(struct platform_driver *drv)

它的功能就是为上面提到的plarform_driver中的driver这个结构中的probe、remove这些变量指定功能函数。

到目前为止,内核就已经知道了有这么一个驱动模块。内核启动的时候,就会调用与该驱动相关的probe函数。我们来看一下probe函数实现了什么功能。

probe函数的原型为

int xxx_probe(struct platform_device *pdev)

即它的返回类型为int,接收一个platform_device类型的指针作为参数。返回类型就是我们熟悉的错误代码了,而接收的这个参数呢,我们上面已经说过,驱动程序为设备服务,就需要知道设备的信息。而这个参数,就包含了与设备相关的信息。

probe函数接收到plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。

在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看在的设备文件了。举一个例子,在音频芯片的驱动中,就可以调用register_sound_dsp来注册一个dsp设备文件,lcd的驱动中就可以调用register_framebuffer来注册fb设备文件。这个工作完成以后,系统中就有我们需要的设备文件了。而和设备文件相关的操作都是通过一个file_operations 来实现的。在调用register_sound_dsp等函数的时候,就需要传递一个file_operations 类型的指针。这个指针就提供了可以供用户空间调用的write、read等函数。file_operations结构的定义位于include/linux/fs.h中,列出如下:

structfile_operations{
structmodule*owner;
loff_t(*llseek)(structfile*,loff_t,int);
ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);
ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);
ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t);
ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t);
int(*readdir)(structfile*,void*,filldir_t);
unsignedint(*poll)(structfile*,structpoll_table_struct*);
int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);
long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong);
long(*compat_ioctl)(structfile*,unsignedint,unsignedlong);
int(*mmap)(structfile*,structvm_area_struct*);
int(*open)(structinode*,structfile*);
int(*flush)(structfile*,fl_owner_t id);
int(*release)(structinode*,structfile*);
int(*fsync)(structfile*,structdentry*,intdatasync);
int(*aio_fsync)(structkiocb*,intdatasync);
int(*fasync)(int,structfile*,int);
int(*lock)(structfile*,int,structfile_lock*);
ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);
unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);
int(*check_flags)(int);
int(*dir_notify)(structfile*filp,unsignedlongarg);
int(*flock)(structfile*,int,structfile_lock*);
ssize_t(*splice_write)(structpipe_inode_info*,structfile*,loff_t*,size_t,unsignedint);
ssize_t(*splice_read)(structfile*,loff_t*,structpipe_inode_info*,size_t,unsignedint);
int(*setlease)(structfile*,long,structfile_lock**);
};

到目前为止,probe函数的功能就完成了。

当用户打开一个设备,并调用其read、write等函数的时候,就可以通过上面的file_operations来找到相关的函数。所以,用户驱动程序还需要实现这些函数,具体实现和相关的设备有密切的关系,这里就不再介绍了。


分享到:
评论

相关推荐

    mini6410_2.6.38内核_uart1_platform_device驱动

    原创的友善之臂的mini6410 linux-2.6.38内核的uart1 串口驱动,使用platform_device方式,压缩包里面有驱动源代码、编译好了的ko文件、使用说明文档、用户例程的源代码和可执行程序,但是并没有给出直接编译驱动和...

    linux下驱动模型介绍

    通常编写linux 字符设备常接触到的file_operations 以及miscdevice,然后申请...platform_device 和platform_driver 做了些摘录批注。 platform_device 与platform_driver 一直分不清关系。在网上搜了下,做个总结。

    linux 设备驱动模型platform driver与driver

    根据源码分析整理的linux platfom driver与device driver的关系,对初学者有较大的帮助

    Linux Platform Device and Driver

    Linux Platform Device and DriverLinux Platform Device and DriverLinux Platform Device and DriverLinux Platform Device and DriverLinux Platform Device and DriverLinux Platform Device and DriverLinux ...

    unix分析关于UNIX的一些浅析

    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)函数会遍历总线上所有的设备,并调用__driver_attach函数,判断驱动是否和设备匹配,若匹配则将struct device中的 struct device_driver *driver指向此驱动...

    Linux设备驱动开发?平台设备驱动

    Linux2.6的内核中引入了一种新的设备驱动模型-平台(platform)设备驱动,平台设备驱动分为平台设备(platform_device)和平台驱动(platform_driver),平台设备的引入使得Linux设备驱动更加便于移植。  一、平台设备 ...

    基于platform总线的驱动模型

    讲解了 关于驱动中platform device 和 platform driver 是怎么通过bus总线进行挂接关连的

    pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z

    pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z http://blog.csdn.net/21cnbao/article/details/7919055 在Android源码树中添加userspace I2C读写...

    i2c的注册过程

    I2c的总线方式 platform_device和platform_driver的形式,在platform_device里向内核注册设备资源,在platform_driver里通过name与platform_device进行匹配,如果match,则能够使用该资源,并进行初始化。

    嵌入式系统/ARM技术中的Linux内核中的platform机制

    Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。  Linux platform. driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一...

    Platform driver&device.pptx

    Platform driver&device.pptx

    详解Linux2.6内核中基于platform机制的驱动模型

    首先介绍了Platform总线的基本概念,接着介绍了platform device和platform driver的定义和加载过程,分析了其与基类device 和driver的派生关系及在此过程中面向对象的设计思想。最后以ARM S3C2440中I2C控制器为例...

    android kernel 开发培训

    .Android linux 设备驱动开发关键函数介绍 (1)设备驱动初始化与注册函数 从Linux 2.6起引入了一套新的驱动...大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver 进行注册。

    Device_Driver

    设备驱动001_hello_world 2021-01-25完成002_pseudo_char_driver 2021-01-27已完成003_pseudo_char_driver_multiple 2021-01-30已完成004_pcd_platform_driver平台设备,平台驱动程序,设备驱动程序,设备2021-02-08...

    便携设备中嵌入式Linux电源检测驱动开发

    针对便携设备中的电源使用...采用飞思卡尔半导体的MX27处理器,设计了嵌入式Linux2.6内核下的设备驱动程序,分析了Linux2.6内核中新的驱动管理和注册机制,讨论了platform_device及platform_driver的定义和使用方法。

    总线设备驱动模型国嵌示例代码及pdf

    总线设备驱动模型国嵌示例代码及pdf,学习总线设备驱动的比较好的例子。简单容易理解,偏入门

    linux device driver platform

    platform linux 嵌入式 ARM, S2C2440, driver

    Linux 设备模型

    因此,由于这个共性,内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的封装,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动...

    详解Linux驱动中,probe函数何时被调用

    最近看到linux的设备驱动模型,关于Kobject、Kset等还不是很清淅。看到了struct device_driver这个结构时,想到一个问题:它的初始化函数到底在哪里调用呢?以前搞PCI驱动时用pci驱动注册函数就可以调用它,搞s3c...

    论文研究-嵌入式Linux系统I2C驱动的研究与应用 .pdf

    嵌入式Linux系统I2C驱动的研究与应用,邱宏宇,余瑾,从Linux2.6内核起引入了一套全新的驱动管理和注册机制Platform_device和Platform_driver,本文将深入分析I2C总线在Linux中实现的体系结构,阐述I2

Global site tag (gtag.js) - Google Analytics