Linux平台设备和驱动

2023-05-16

一 platform总线

一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中集成的独立的外设控制器,挂接在SOC内存空间的外设等确不依附于此类总线。基于这一背景,linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver.Platform总线是linux2.6内核加的一种虚拟总线。
Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。

二 平台设备的驱动软件设计流程

这里写图片描述

三 平台设备

3.1 用于描述平台设备的数据结构是platform_device, 在”linux/platform_device.h”文件中定义,程序清单如下所示:

struct platform_device{
const char      *name;           //设备名字
int             id;             //设备ID
struct device   dev;            //设备的device数据结构
u32             num_resources;  //资源的个数
struct resource *resource;      //设备的资源
const struct platform_device_id  *id_entry;//设备ID入口
struct pdev_archdata archdata;   //体系结构相关的数据
};

3.2 分配platform_device结构
注册一个platform_device之前,必须先定义或者通过platform_device_alloc()函数为设备分配一个platform_device结构。原型如下:

struct platform_device *platform_device_alloc(const char *name,int id);

3.3添加资源
通过platform_device_alloc()申请得到的platform_device结构,必须添加相关资源和私有数据才能注册。添加资源的函数是platform_device_add_resources:

int platform_device_add_resources(struct platform_device *pdev,const struct resource *res unsigned int num);

添加私有数据的函数是platform_device_add_data:

int platform_device_add_data(struct platform_device *pdev,const void *data,size_t size)

3.4 注册和注销platform_device
申请到platform_device结构后,可以通过platform_device_register()往系统进行注册。原型如下:

int platform_device_register(struct platform_device *pdev);

上述函数只能注册一个platform_device,如果有多个platform_device,则可以用platform_add_devcies()一次性完成注册,原型如下:

int platform_add_devices(struct platform_device  *devs,int num);

通过platform_device_unregister()可以注销系统的plat_device.原型如下:

void platform_unresigner(struct platform_device *pdev);

如果已经定义了设备的资源和私有数据,可以用 platform_device_register_resndata()一次
性完成数据结构申请、资源和私有数据添加以及设备注册:

struct platform_device *__init_or_module platform_device_register_resndata(
    struct device *parent,
    const char *name, int id,
    const struct resource *res, unsigned int num,
    const void *data, size_t size);

platform_device_register_simple()函数是 platform_device_register_resndata()函数的简化版,
可以一步实现分配和注册设备操作, platform_device_register_simple()函数原型如下:

static inline struct platform_device *platform_device_register_simple(
    const char *name, int id,
    const struct resource *res, unsigned int num);

实际上就是: platform_device_register_resndata(NULL, name, id, res, num, NULL, 0)。在\Linux/platform_device.h/文件还提供了更多的 platform_device 相关的操作接口函数,
在有必要的时候可以查看并使用。
3.5向系统添加平台设备的流程
向系统添加一个平台设备,可以通过两种方式完成:
 方式 1:定义资源,然后定义 platform_device 结构并初始化;最后注册;
 方式 2:定义资源,然后动态分配一个 platform_device 结构,接着往结构添加资源
信息,最后注册。
如下图所示:
这里写图片描述

四 平台驱动

4.1platform_driver
platform_driver 是 device_driver 的封装,提供了驱动的 probe 和 remove 方法,也提供了
与电源管理相关的 shutdown 和 suspend 等方法

struct platform_driver {
int (*probe)(struct platform_device *);     /* probe 方法 */
int (*remove)(struct platform_device *);    /* remove 方法 */
void (*shutdown)(struct platform_device *); /* shutdown 方法 */
int (*suspend)(struct platform_device *, pm_message_t state); /* suspend 方法 */
int (*resume)(struct platform_device *);    /* resume 方法 */
struct device_driver driver;                 /* 设备驱动 */
const struct platform_device_id *id_table;  /* 设备的 ID 表 */
};

Platform_driver 有 5 个方法:
 probe成员指向驱动的探测代码,在 probe方法中获取设备的资源信息并进行处理,
如进行物理地址到虚拟地址的 remap,或者申请中断等操作,与模块的初始化代码
不同;
 remove 成员指向驱动的移除代码,进行一些资源释放和清理工作,如取消物理地
址与虚拟地址的映射关系,或者释放中断号等,与模块的退出代码不同;
 shutdown 成员指向设备被关闭时的实现代码;
 suspend 成员执行设备挂起时候的处理代码;
 resume 成员执行设备从挂起中恢复的处理代码
4.2注册和注销平台设备
注册和注销 platform_driver 的函数分别是 platform_driver_register()和 platform_driver
_unregister(), 函数原型分别如下:

int platform_driver_register(struct platform_driver *drv);
void platform_driver_unregister(struct platform_driver *drv);

另外, platform_driver_probe()函数也能完成设备注册, 原型如下:

int platform_driver_probe(struct platform_driver *driver, int (*probe)(struct platform_device *));

如果已经明确知道一个设备不支持热插拔,可以在__init 断代码中调用 platform_driver
_probe()函数,以减少运行时对内存的消耗。如下程序清单所示代码是

int __init init_module(void)
{
int retval;
ne_add_devices();
retval = platform_driver_probe(&ne_driver, ne_drv_probe);
if (retval) {
if (io[0] == 0)
printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\""
" value(s) for ISA cards.\n");
ne_loop_rm_unreg(1);
return retval;
}
/* Unregister unused platform_devices. */
ne_loop_rm_unreg(0);
return retval;
}

注意:在设备驱动模型中已经提到,bus 根据驱动和设备的名称寻找匹配的设备和驱动,
因此注册驱动必须保证 platform_driver 的 driver.name 字段必须和 platform_device 的 name 相
同, 否则无法将驱动和设备进行绑定而注册失败。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux平台设备和驱动 的相关文章

  • IAR的UI界面优化

    显示行数 Tools Options 点击 Editor Tab size xff1a 设置Tab键占用多少个空格Indent size xff1a 应该是设置过行时缩进多少个空格Insert tab xff1a 选了之后在删除Tab时 x
  • MYNTEYE小觅双目摄像头深度版+VINS测试

    小觅双目深度版性能分析 今年 xff08 18年 xff09 11月9号小觅智能科技的深度版双目相机上市 xff0c 于是我在12月初花了2999软妹币购买了120度视角的相机 其中我比较感兴趣的是 双目 43 惯导 43 结构光 的多传感
  • QT+ROS开发

    Qt Creator for ROS 如果想在Qt上进行ros包的开发和GUI界面开发 建议采用下面的方法 http fumacrom com 1mipW Setup Qt Creator for ROS Setup Ubuntu to a
  • PX4、APM无人机仿真连接QGC地面站记录(udp连接、更改home点等)

    文章目录 一 PX41 gazebo 仿真2 连接地面站3 更改 Home点 二 APM 仿真1 执行仿真指令2 连接地面站3 更改 Home 点 本文仅记录仿真指令 xff0c 搭建安装不在此 一 PX4 首先给飞控源码和子目录权限 sp
  • LeetCode 解题笔记(一)总

    文章目录 一 常用技巧二 常用翻译三 题目x 其他9 回文数 2021 12 0911 盛最多水的容器 2022 01 0515 三数之和 2022 01 14 17 电话号码的字母组合 2022 01 1520 有效的括号 2021 12
  • LeetCode 解题笔记(二)数组篇

    文章目录 一 基础篇26 删除排序数组中的重复 2022 01 16122 买卖股票的最佳时机 II 2022 01 17189 轮转数组 2022 01 18217 存在重复元素 2022 01 19136 只出现一次的数字 2021 1
  • LeetCode 解题笔记(四)链表

    文章目录 一 总结二 题目237 删除链表中的节点 xff08 2022 03 10 xff09 19 删除链表的倒数第 N 个结点 xff08 2022 03 11 xff09 206 反转链表 xff08 2022 03 18 xff0
  • QT Quick QML 实例之 Popup 弹出界面

    QT Quick QML 实例之 Popup 弹出界面 一 演示二 实现过程1 居中弹出2 正下方弹出 所有的热爱都要不遗余力 xff0c 真正喜欢它便给它更高的优先级 xff0c 和更多的时间吧 xff01 GIT工程文件在这里 QmlL
  • QGC(GGroundControl) 系统核心架构图

    关于QGC地面站其它文章请点击这里 QGC地面站 UML 核心类图 xff1a xff08 点击图片放大看效果更好 xff09 核心系统分析图 xff1a xff08 点击图片放大看效果更好 xff09 工程结构 xff1a 整个 QGC
  • Qt 国际化翻译,函数外部字符串、Map 翻译(QT_TRANSLATE_NOOP)

    文章目录 1 Qt 的翻译流程2 利用 QT TRANSLATE NOOP 翻译 GitHub 源码 QmlLearningPro xff0c 选择子工程 xff1a TranslationsDemo pro QML 其它文章请点击这里 Q
  • IAR新建工程

    下载库函数 本文介绍基于 IAR 43 官方标准固件库 xff0c 来新建 STM8S003F 工程 xff0c STM8S 的标准固件库可以到 ST 的官方网站中找到并下载 xff1a ST官网 1 在搜索栏上搜索 STM8S003F x
  • RTSP 推流和拉流记录(运行代码)

    文章目录 1 RTSP 推流2 RTSP 拉流 1 RTSP 推流 用C 43 43 11 实现的RTSP服务器和推流器 xff0c 链接如下 RtspServer GitHub原地址 xff1a https github com PHZ7
  • FFmpeg 中 RTSP推流桌面和Android设备延时测试

    文章目录 1 FFMPEG 推流 xff1a 1 1 FFmpeg 源码准备1 2 RTSP 推流服务器 2 执行流程2 1 启动服务器2 2 执行桌面推流2 3 播放 3 安卓测试 1 FFMPEG 推流 xff1a 1 1 FFmpeg
  • Windows 下 GitKraken 6.5.1免费版本安装

    文章目录 1 安装 6 5 1 版本2 更换快捷方式3 登录 用过 GitKraken 都说好 xff0c 不过 xff0c GitKraken 从 6 5 3 版本开始收费 xff0c 它的最后一个免费版本是 6 5 1 xff0c 当你
  • QT 中的多线程之 moveToThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 注意事项6 结语 1 概述 在 Qt 中 xff0c 多线程也被广泛用于实现后台任务 异步操作 多任务处理等功能 通过使用多线程 xff0c 可以提高程序的响应性和用户体验
  • QT 多线程之继承 QThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 结语 1 概述 在 Qt 中 xff0c 可以使用 QThread 的两种方式来创建和控制线程 xff1a 继承 QThread 类和使用 QObject moveToTh
  • Qt 多线程同步:互斥锁QMutextLocker 、读写锁 QReadWriteLock、信号量 QSemaphore、 条件变量QWaitConditio、QThread::wait()

    文章目录 1 Qt 多线程为什么需要同步机制 lt font gt 2 多线程有哪些同步机制 2 1 互斥锁 xff08 QMutex xff09 2 2 读写锁 xff08 QReadWriteLock xff09 2 3 信号量 xff
  • Windows下 ffmpeg 的 “Protocol not found“ 的解决

    文章目录 1 问题描述2 排查方法记录2 1 检查代码中编码器是否安装2 2 确定ffmpeg版本号2 3 打印编译参数2 4 查看运行中调用dll 1 问题描述 调用ffmpeg库中 xff0c 如果使用 avformat open in
  • Qt 智能指针介绍: QSharedPointer、QWeakPointer 、QScopedPointer 、QPointer(附实例)

    文章目录 1 概述2 Qt 中有几种智能指针 xff1f 2 1 QSharedPointer 实例2 2 QSharedPointer 与 QWeakPointer 实例2 3 QScopedPointer 实例2 4 QPointer
  • Qt QQueue 安全的多线程队列、阻塞队列

    文章目录 1 C 43 43 queue 队列基本用法2 Qt QQueue 队列基本用法3 Qt QQueue 多线程队列4 Qt BlockingQueue 自定义线程安全的阻塞队列 1 C 43 43 queue 队列基本用法 在C

随机推荐