Linux驱动开发——(九)platform设备驱动

news2024/11/24 13:39:30

目录

一、Linux驱动的分离

二、Linux驱动的分层

三、platform平台驱动模型简介

3.1 platform_driver结构体

3.2 device_driver结构体

3.3 platform驱动API函数

四、驱动代码


一、Linux驱动的分离

对于Linux这种庞大而复杂的系统,需要非常注重代码的重用性,否则Linux内核中将会存在大量无意义的重复代码。假设现在有三个平台A、B和C,该三个平台都有MPU6050这个I2C接口的六轴传感器,如果按照写裸机I2C驱动的思路,每个平台都有一个MPU6050的驱动,因此编写出来的最简单的驱动框架如图:

如果再来几个I2C设备,比如AT24C02、FT5206(电容触摸屏)等,按照上图的写法,那么设备端的驱动将再重复编写好几次。显然在Linux驱动程序中这种写法是不推荐的,最好的做法就是每个平台的I2C控制器都提供一个统一的接口(主机驱动)每个设备也只提供一个驱动程序(设备驱动),每个设备通过统一的I2C接口驱动来访问,这样就可以大大简化驱动文件: 

此时如果再来几个I2C设备,比如AT24C02、FT5206(电容触摸屏)等,那么就是:

 这便是驱动的分隔,即将主机驱动和设备驱动分隔开来,比如I2C、SPI等等都会采用驱动分隔的方式来简化驱动的开发。

在实际的驱动开发中,主机控制器驱动一般由半导体厂家编写好,而设备驱动一般也由设备器件的厂家编写好,我们只需要提供设备信息即可。

驱动只负责驱动,设备只负责设备,将两者进行匹配即可(相当于将设备信息从设备驱动中剥离开来,驱动使用标准方法去获取到设备信息,比如从设备树中获取到设备信息,然后根据获取到的设备信息来初始化设备)——即Linux中的总线(bus)、驱动(driver)和设备(device)模型:

当向系统注册一个驱动的时候,总线就会在右侧的设备中查找,看看有没有与之匹配的设备,如果有的话就将两者联系起来;同样的,当向系统中注册一个设备的时候,总线也会在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来。Linux内核中大量的驱动程序都采用总线、驱动和设备模式,platform驱动就是这一思想下的产物。


二、Linux驱动的分层

网络有7层模型,不同的层负责不同的内容。同样的, Linux下的驱动往往也是分层的,分层的目的也是为了在不同的层处理不同的内容。

比如input子系统(经常所使用到)负责管理所有跟输入有关的驱动,包括键盘、鼠标、触摸等,最底层的就是设备原始驱动,负责获取输入设备的原始值,获取到的输入事件上报给input核心层。 input核心层会处理各种IO模型,并且提供file_operations操作集合。在编写输入设备驱动的时候只需要处理好输入事件的上报即可,至于如何处理这些上报的输入事件那是上层去考虑的。


三、platform平台驱动模型简介

platform驱动框架分为总线、设备和驱动,其中总线是Linux内核提供的,编写驱动时只需要关注设备(platform_device)和驱动(platform_driver)的具体实现即可。在无设备树的Linux内核下,需要分别编写并注册platform_device和platform_driver;在使用设备树时,设备的描述被放到了设备树中,因此platform_device不用编写,只需要实现platform_driver即可。

3.1 platform_driver结构体

platform_driver结构体表示platform驱动,此结构体定义在文件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 (*resume)(struct platform_device *); 
    struct device_driver driver; 
    const struct platform_device_id *id_table; 
    bool prevent_deferred_probe; 
};

probe函数:当驱动与设备匹配成功以后probe函数就会执行。

driver成员:device_driver结构体变量,Linux内核里大量使用面向对象的思维,device_driver相当于基类,提供了最基础的驱动框架。plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。

id_table:platform总线匹配驱动和设备的时候采用的一种方法, id_table是个表 (数组),每个元素的类型为platform_device_id

struct platform_device_id { 
    char name[PLATFORM_NAME_SIZE]; 
    kernel_ulong_t driver_data; 
};

3.2 device_driver结构体

device_driver结构体定义在include/linux/device.h:

struct device_driver { 
    const char *name; 
    struct bus_type *bus; 

    struct module *owner; 
    const char *mod_name; /* used for built-in modules */ 

    bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 

    const struct of_device_id *of_match_table; 
    const struct acpi_device_id *acpi_match_table; 

    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); 
    const struct attribute_group **groups; 

    const struct dev_pm_ops *pm; 

    struct driver_private *p; 
};

of_match_table:采用设备树时驱动所使用的匹配表(数组),每个匹配项都为of_device_id结构体类型,此结构体定义在文件include/linux/mod_devicetable.h中,内容如下:

struct of_device_id { 
    char name[32]; 
    char type[32]; 
    char compatible[128]; 
    const void *data; 
};

compatible:对于设备树而言,通过设备节点的compatible属性值和of_match_table中每个项目的compatible成员变量进行比较,如果有相等的就表示设备和此驱动匹配成功。

注意,of_device_id表最后一个匹配项必须是空的

3.3 platform驱动API函数

在编写platform驱动时,首先定义一个platform_driver结构体变量,然后实现结构体中的各个成员变量(重点是实现匹配方法以及probe函数)。当驱动和设备匹配成功以后probe函数就会执行,具体的驱动程序在probe函数里面编写,比如字符设备驱动等等。

当我们定义并初始化好platform_driver结构体变量以后,需要在驱动入口函数里面调用platform_driver_register函数向Linux内核注册一个platform驱动

int platform_driver_register (struct platform_driver *driver) 

driver:要注册的platform驱动。
返回值:负数即失败;0即成功。

驱动卸载函数中通过platform_driver_unregister函数卸载platform驱动

void platform_driver_unregister(struct platform_driver *drv)

drv:要卸载的platform驱动。
返回值:无。


四、驱动代码

platform驱动框架:

struct xxx_dev{ 
    struct cdev cdev; 
    /* 设备结构体其他具体内容 */ 
}; 

struct xxx_dev xxxdev; /* 定义个设备结构体变量 */ 

static int xxx_open(struct inode *inode, struct file *filp) 
{ 
    /* 函数具体内容 */ 
    return 0; 
} 

static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) 
{ 
    /* 函数具体内容 */ 
    return 0; 
} 
 
/*
* 字符设备驱动操作集 
*/ 
static struct file_operations xxx_fops = { 
    .owner = THIS_MODULE, 
    .open = xxx_open, 
    .write = xxx_write, 
}; 

/* 
* platform驱动的probe函数 
* 驱动与设备匹配成功以后此函数就会执行 
*/ 
static int xxx_probe(struct platform_device *dev) 
{ 
    ...... 
    cdev_init(&xxxdev.cdev, &xxx_fops); /* 注册字符设备驱动 */ 
    /* 函数具体内容 */ 
    return 0; 
} 

static int xxx_remove(struct platform_device *dev) 
{ 
    ...... 
    cdev_del(&xxxdev.cdev);/* 删除cdev */ 
    /* 函数具体内容 */ 
    return 0; 
} 

/* 匹配列表 */ 
static const struct of_device_id xxx_of_match[] = { 
    { .compatible = "xxx-gpio" }, 
    { /* Sentinel */ } 
}; 

/* 
* platform平台驱动结构体 
*/ 
static struct platform_driver xxx_driver = { 
    .driver = { 
        .name = "xxx", 
        .of_match_table = xxx_of_match, 
    }, 
    .probe = xxx_probe,
    .remove = xxx_remove, 
}; 

/* 驱动模块加载 */ 
static int __init xxxdriver_init(void) 
{ 
    return platform_driver_register(&xxx_driver); 
} 
 
/* 驱动模块卸载 */ 
static void __exit xxxdriver_exit(void) 
{ 
    platform_driver_unregister(&xxx_driver); 
} 

module_init(xxxdriver_init); 
module_exit(xxxdriver_exit); 
MODULE_LICENSE("GPL");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632901.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker-容器的前世今生

文章目录 Docker为什么产生?硬件虚拟化硬件虚拟化解决的问题硬件虚拟化定义硬件虚拟化技术虚拟机的优点虚拟机的缺点 操作系统虚拟化即容器容器化解决的问题容器化定义容器化技术历史 容器和虚拟机对比 Docker的发展历史Docker架构客户端服务端仓库Registry Docker重…

JavaEE 初阶篇-深入了解特殊文件(Properties 属性文件、XML)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 Properties 属性文件概述 1.1 Properties 属性文件特性与作用 1.2 使用 Properties 把键值对数据写出到属性文件中 1.3 使用 Properties 读取属性文件里的键值对数…

JMeter 请求头信息配置详解

在进行 Web 测试和 API 测试时,正确配置 HTTP 请求头是关键步骤之一,尤其当使用诸如 JMeter 这样的强大工具时。在本文中,我将详细介绍如何在 JMeter 中有效地配置和管理HTTP请求头。 在 JMeter 中添加和配置 HTTP 请求头 步骤 1: 打开 HTT…

【Redis 开发】多级缓存,本地进程缓存Caffeine

多级缓存 多级缓存本地进程缓存CaffeineCaffeine三种缓存驱逐策略 多级缓存 Redis处理并发的能力是非常强大的,但是tomcat的支持并发的能力跟不上Redis的性能,导致整体性能的下降 Redis缓存失效时,会对数据库产生冲击,之间再无屏…

0425DormAJAX项目

0425DormAJAX项目包-CSDN博客 数据库字段 添加界面: 初始状态: 点击性别,宿舍号使用ajax动态添加: 学生主界面: 实现分页查询: 点击修改学生宿舍,查看换寝记录,ajax动态显示列表&…

如何在WordPress中设置网站的SEO标题和描述

在WordPress中,想要让你的网站在搜索引擎结果中脱颖而出,设置优秀的SEO标题和描述至关重要。这不仅可以帮助搜索引擎更好地理解你的网站内容,还可以吸引更多的点击率和流量。而选择一款合适的SEO插件是实现这一目标的关键之一。让我们来看看两…

速成AWD并获奖的学习方法和思考记录

前言 这是一个市赛。之前没有怎么打过AWD,所以进入决赛后只有三天的准备时间,期间我不停的请教大佬,阅读各类文章,受益颇深,做此纪录,奉献给掌控的各位同学学习。 在AWD中本是三人一队,可惜我…

Babel 原理浅析

Babel 原理浅析 Babel 是什么Babel 的作用及常用场景Babel 执行过程原理Babel的基本原理解析过程插件系统 Babel 是什么 官方解释:Babel 是一个 JavaScript 编译器,也是一个工具链,主要用于将 ECMAScript 2015 代码转换为当前和旧版浏览器或环…

一篇文章 学会Qt 样式表(qss)

QML 中风格和主题的设计可以通过配置文件选择现有几种中的一种,或者直接在控件定义时,指定其属性,如背景颜色或者字体大小。在QWidget框架中,则通过了一种叫做qss样式表的东西来进行描述,跟CSS逻辑上类似。 这个qss抽…

ThreeJs模拟工厂生产过程八

这节算是给这个车间场景收个尾,等了几天并没有人发设备模型给我,只能自己找了一个凑合用了。加载模型之前,首先要把货架上的料箱合并,以防加载模型之后因模型数量多出现卡顿,方法和之前介绍的合并传送带方法相同&#…

【C++初阶】string

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿&#x1…

echarts tooltip 内容太多,超出范围显示不全问题,亲测有效

参考文章:echarts tooltip显示不全问题 在项目里面的tooltip数据特别多,显示不全问题(有下面几种方法,选择最适合自己的): 1、如果盒子还够大,只是tooltip飘到上面或者下面被覆盖住了&#xff…

一文解读 SQL 生成工具

SQL 生成工具可用于测试 Parser 与其他数据库产品的兼容性,通过解析 YACC 语法文件中的产生式,生成对应的 SQL 语句,再使用数据库执行该 SQL,根据结果判断语句是否与其他数据库语法兼容。 01工具使用 语法文件预处理 预处理目的…

13 Linux实操篇-网络配置

第十三章 Linux实操篇-网路配置 13.1 Linux 网络配置原理图 13.2 查看网络IP 和网关 子网ip 与网关 13.3 查看Windows 中 VMnet8 和 Linux 的网络配置 查看Windows 中 VMnet8:ipconfig Linux 的网络配置: ifconfig 13.4 ping 测试主机之间网络连通性 基本语法&a…

教育装备展火热开幕,锐捷网络用科技力量点亮教育未来之光

了解教育装备行业发展新趋势、感受教育装备领域创新脉动。4月19日,一场汇聚智慧与创新的教育行业盛会——第 83 届中国教育装备展示会在山城重庆隆重启幕。位于N4013号的锐捷网络展位不仅汇聚了极简以太全光3.X、三擎云桌面2.X、极简教育城域网等前沿科技方案,更通过样机展示、…

ssl证书是怎么实现数据加密传输的?原理是什么?

SSL证书实现数据加密传输的过程大致可以分为以下几个步骤: 1. 握手阶段: - 客户端请求连接:当用户尝试访问一个HTTPS网站时,浏览器(客户端)会向服务器发起一个HTTPS请求,请求建立一个安全连接。…

通过iMock学习Jvmsandbox

Jvm-sandbox Jvm-sandbox基于Jvm-sandbox的Mock平台iMockiMock的工程学习iMock怎么写的(sandbox的module应该怎么写) Jvm-sandbox Jvm-sandbox是阿里开源的一款java的沙箱,看网上的介绍在沙箱里你可以做你能想到的奇妙的事情。 基于Jvm-san…

图题目:可以到达所有点的最少点数目

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:可以到达所有点的最少点数目 出处:1557. 可以到达所有点的最少点数目 难度 4 级 题目描述 要求 给定一个有向无环图,包含编…

Web3与智能合约:科技革新下的新金融时代

在当今数字化时代,Web3和智能合约正在共同塑造着金融领域的未来。Web3作为下一代互联网的重要组成部分,以其去中心化、安全性和透明性为核心特点,正推动着金融行业向着数字化和去中心化的方向发展。而智能合约作为Web3技术的关键应用之一&…

如何将本地项目上传到Github(SSH方式)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…