Linux驱动下的platform总线架构(转)
Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用 platform_driver 进行注册。
Linux platform driver 机制和传统的 device driver 机制(即:通过 driver_register 函数进行注册)相比,一个十分明显的优势在于 platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中用使用这些资源时,通过 platform device 提供的标准接口进行申请并使用。
struct platform_device { // include/linux/platform_device.h
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
***************************************************************************
/*
* 主要用于定义具体设备占用的硬件资源(如:地址空间、中断号等)。
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
***************************************************************************
platform 总线下驱动的开发步骤是:
1、设备
设备注册中,需要实现的机构体是:platform_device 。
1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。(以上三步,必须在 设备驱动加载前完成,所以,AT91RM9200 的内核下,该三步是放在 arch/arm/mach-at91/board-dk.c 中)
2、驱动
驱动注册中,需要实现的结构体是:platform_driver 。
struct platform_driver { // include/linux/platform_device.h
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 pm_ext_ops *pm;
struct device_driver driver;
};
在驱动程序的初始化函数中,调用了 platform_driver_register() 注册 platform_driver 。
需要注意的是:platform_driver 和 platform_device 中的 name 变量的值必须是相同的 。这样在
platform_driver_register() 注册时,会将当前注册的 platform_driver 中的 name 变量的值和已注册的所有 platform_device 中的 name 变量的值进行比较,只有找到具有相同名称的 platform_device 才能注册成功。当注册成功时,会调用 platform_driver 结构元素 probe 函数指针。
********************************************************************
static int __init ds1302_rtc_init(void)
{
return platform_driver_register(&ds1302_platform_driver);
}
********************************************************************
然后,进入:drivers/base/platform.c:platform_driver_register()
********************************************************************
/**
* platform_driver_register
* @drv: platform driver structure
*/
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;
if (drv->pm)
drv->driver.pm = &drv->pm->base;
return driver_register(&drv->driver);
}
此处,对drv->driver 结构体中的几个函数指针进行初始化设置。最后,调用 driver_register 注册 driver 成员。
drv->driver 的类型是:
struct platform_driver { // include/linux/platform_device.h
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 pm_ext_ops *pm;
struct device_driver driver; // drv->driver
};
const char *name;
struct bus_type *bus;
const char *mod_name; /* used for built-in modules */
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 attribute_group **groups;
};
********************************************************************
然后,进入:drivers/base/driver.c:driver_register
********************************************************************
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*/
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n
", drv->name);
return -EEXIST;
}
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
********************************************************************
然后,进入:drivers/base/bus.c:bus_add_driver
********************************************************************
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
if (!bus)
return -EINVAL;
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
return error;
out_unregister:
kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
return error;
Linux驱动下的platform总线架构(转)相关推荐
- linux驱动编写(platform总线和网卡驱动)
[ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 对于linux驱动来说,一般的架构还是按照bus-host-device的形式来进行的.比如就拿 ...
- linux platform匹配机制,Linux驱动中的platform总线详解
platform总线是学习linux驱动必须要掌握的一个知识点. 一.概念 嵌入式系统中有很多的物理总线:I2c.SPI.USB.uart.PCIE.APB.AHB linux从2.6起就加入了一套新 ...
- Linux驱动开发:platform总线驱动
目录 1.为什么需要platform总线 2.设备端:platform_device 2.1 platform_device结构体 2.2 注册 2.3 注销 3.驱动端:platform_drive ...
- linux设备模型(8)_platform设备,Linux设备模型之platform总线
Linux设备模型之platform总线- 一:前言 Platform总线是kernel中最近加入的一种虚拟总线.在近版的2.6kernel中,很多驱动都用platform改写了.只有在分析完plat ...
- 设备树下的platform总线-21
设备树下的platform总线 of _iomap 函数 作用:of iomap函数用于直接内存映射,以前我们会通过ioremap函数来完成物理地址到虚拟地址的映射. 函数原型: #include & ...
- Linux设备驱动模型之platform总线
1 平台设备和驱动初识 platform是一个虚拟的地址总线,相比pci,usb,它主要用于描述SOC上的片上资源,比如s3c2410上集成的控制器(lcd,watchdog,rtc等),platfo ...
- Linux驱动开发8 platform驱动分隔、分离与分层
我们在前面几章编写的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 等这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因 ...
- linux 驱动开发之platform设备驱动一(4)
前言 Linux 设备和驱动通常都需要挂接在一种总线上,例如PCI.USB.I2C.SPI 等的设备存在真实的总线,这自然不是问题,但是SOC上的外设控制器.挂接在SoC内存空间的外设等却不依附于此类 ...
- Linux驱动开发之platform设备驱动实验【完整教程】
为了方便驱动的编写,提高软件的重用性和跨平台性能,于是就提出了Linux驱动的分离和分层 驱动的分层,分层的目的时为了在不同的层处理不同的内容,最简单的驱动分层是input子系统负责管理所有跟输入 ...
最新文章
- 编译器的普遍翻译步骤
- [ACM] hdu 1228 A+B (字符串处理)
- Python 技术篇-利用pyqt5库读取剪切板已复制数据的格式类型实例演示,python判断复制文件的文件类型
- MySQL删除数据表
- 1035. 插入与归并(25)
- //输入学生人数,挨个输入姓名,身高,年龄,求平均年龄,然后按身高降序排列输出...
- MyBatis-Plus之通过插件将数据库表生成Entiry,Mapper.xml,Mapper.class的方式。
- ajax成功之后在执行,ajax传入成功后执行后台方法
- 安装版win7安装时分区
- 意尔康体育:帆软助力其提速增效,让数据帮助业务效率提升400%
- 在Linux中使用matplotlib进行科学画图
- 多学一点(十三)——解决Linux kdump服务启动失败
- oracle 命令行执行sql文件
- MATLAB中能对三角函数降幂嘛,三角函数降幂公式是什么
- 导弹跟踪问题 计算机模拟,计算机模拟版本3[整理版.ppt
- 重新获取新的IP地址的方法
- 信息学奥赛一本通C++语言-----1142:单词的长度
- 数字电路设计: FPGA实现倍频
- UEditor定制工具栏图标
- python标准库calendar判断年份是闰年和平年
热门文章
- 需求获取安排计划书_若想成功融资,商业计划书必须秀色可餐:餐饮业商业计划书模板...
- oracle+基本内置函数,oracle 内置函数
- 9 Node 中的 TensorFlow.js
- Linux export 命令设置环境目录
- nginx php 扩展,源码安装Nginx+PHP-FPM及扩展
- python2.7读取excel_对Python2.7pandas中的read_excel详解
- IAR编译器中函数智能提示
- 网络编程---tcp/udp协议
- Hadoop(八)Java程序访问HDFS集群中数据块与查看文件系统
- C语言结构体内存布局问题