Linux platform子系统和设备树

news2024/10/17 0:23:19

1 Linux platform子系统

在Linux 2.6内核中,提出了总线、设备、驱动的架构,目的是让我们写出来的驱动通用性更强。

arm核内部总线结构:
在这里插入图片描述

1.1 核心思想

  • 将设备的信息从驱动中分离出来,我们需要在操作系统中,添加设备和驱动两部分。

  • 设备中包含是设备的信息(资源),驱动中包含的是操作设备函数接口。

  • 为了能让驱动最终能操作我们的硬件设备,我们在驱动中必须获取设备的信息(资源)。驱动是如何获取具体设备信息呢?

  • 设备和驱动都会注册到总线上,当注册设备的时候,会去寻找同名的驱动,当注册驱动的时候,也会去找同名的设备。相互查找。一旦匹配成功,操作系统就会自动调用驱动提供的probe函数。我们只需要在probe函数中,使用操作系统提供的通用API获取硬件的资源即可

在这里插入图片描述

1.2 Linux总线的理解

  • 总线在操作系统中本质就是两个链表: 挂载设备的链表和挂载驱动的链表。
  • 在操作系统中总线种类可以分成两大类:
  • 平台总线:平台总线挂载都是控制器设备,用于CPU核与硬件控制器之间的通信。在Linux系统中用"platform bus"表示。
  • 边缘设备之间通信的总线:边缘设备之间通信的总线挂载是符合总线时序的外围设备如:i2c , spi ,usb , uart 等。不同的边缘设备之间通信的总线,总线时序是不一样的,
  • 对于这些总线,Linux 内核是单独实现的

1.3 基于总线写驱动的思路

  • 根据自己的设备,确定总线的类型
  • 根据总线的类型, 确定设备在总线上如何描述
  • 根据总线的类型, 确定驱动在总线上如何描述
  • 根据总线的类型,确定在总线上如何注册设备
  • 根据总线的类型,确定在总线上如何注册驱动
  • 根据总线的类型, 确定设备和驱动匹配原则

设备和驱动匹配后,操作系统就会调用驱动提供的probe函数。在这个函数中,一般需要做两件事情:

  • (1)获取匹配的硬件资源
  • (2)向上层提供硬件设备的操作函数接口(如:注册字符设备)

案例代码

  • 驱动程序:
#include "linux/export.h"
#include "linux/platform_device.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>

#define PLATFORM_LED_NAME "imx_led"



static int imx_led_probe(struct platform_device *pdev)
{
    int err = 0;
    struct resource	*led_ccm_reg;
    struct resource	*led_mux_reg;
    struct resource	*led_gpio_reg;

    printk("imx led probe\n");
    /* probe函数
     * 1、获取平台设备资源
       2、注册设备驱动,向上层提供接口
    */

    /* 1、获取平台设备资源 */
    led_ccm_reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!led_ccm_reg) {
        err = -ENODEV;
        printk("platform_get_resource ccm\n");
        goto err_platform_get_resource;
    }
    printk("ccm addr: %#x\n", (unsigned int)led_ccm_reg->start);

    led_mux_reg = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    if (!led_mux_reg) {
        err = -ENODEV;
        printk("platform_get_resource mux\n");
        goto err_platform_get_resource;
    }
    printk("mux addr: %#x\n", (unsigned int)led_mux_reg->start);

    led_gpio_reg = platform_get_resource(pdev, IORESOURCE_MEM, 2);
    if (!led_gpio_reg) {
        err = -ENODEV;
        printk("platform_get_resource gpio\n");
        goto err_platform_get_resource;
    }
    printk("gpio addr: %#x\n", (unsigned int)led_gpio_reg->start);

    /* 2、注册字符设备驱动:向应用层提供接口 todo */

    return 0;

err_platform_get_resource:
    return err;
}

static int imx_led_remove(struct platform_device *pdev)
{
    printk("imx led remove\n");
    return 0;
}

/* 3、关联平台设备 */
static const struct of_device_id imx_lex_dt_ids[] = {
	{ .compatible = PLATFORM_LED_NAME },
	{ }
};
MODULE_DEVICE_TABLE(of, imx_lex_dt_ids);

/* 1、描述平台驱动 */
static struct platform_driver drv = {
    .probe = imx_led_probe,
    .remove = imx_led_remove,
    .driver = {
        .name = PLATFORM_LED_NAME,
        .owner = THIS_MODULE,
        .of_match_table = imx_lex_dt_ids,
    }
};

static int __init led_init(void)
{
    int err = 0;
    /* 2、注册平台驱动 */
    err = platform_driver_register(&drv);
    if (err < 0) {
        printk("platform_driver_register failed\n");
        goto err_platform_driver_register;
    }

    printk("driver init success\n");
    return 0;

err_platform_driver_register:
    return err;
}

static void __exit led_exit(void)
{
    platform_driver_unregister(&drv);
    printk("driver exit\n");
}

MODULE_AUTHOR("jk luo");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("This is platform driver");

module_init(led_init);
module_exit(led_exit);

  • 设备程序:
#include "linux/kernel.h"
#include "linux/platform_device.h"
#include <linux/init.h>
#include <linux/module.h>

#define PLATFORM_LED_NAME "imx_led"
#define LED_CCM_REG 0x20C406C  // 26、27管脚高电平
#define LED_CCM_REG_SIZE 0x4
#define LED_MUXCTL_REG 0x20E00B0  // 低四位设置为0101
#define LED_MUXCTL_REG_SIZE 0x4
#define LED_GPIO_BASE_REG 0x209C000
#define LED_GPIO_REG_SIZE 0x8
#define LED_GPIO_DAT_REG_OFFSET 0x0  // gpio1的27号管脚
#define LED_GPIO_DIR_REG_OFFSET 0x4  // 高电平输出,低电平输入

void led_device_release(struct device *dev)
{
    printk("led_device_release\n");
}

static struct resource led_device_resource[] = {
    [0] = {
        .start = LED_CCM_REG,
        .end = LED_CCM_REG + LED_CCM_REG_SIZE - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = LED_MUXCTL_REG,
        .end = LED_MUXCTL_REG + LED_MUXCTL_REG_SIZE - 1,
        .flags = IORESOURCE_MEM,
    },
    [2] = {
        .start = LED_GPIO_BASE_REG,
        .end = LED_GPIO_BASE_REG + LED_GPIO_REG_SIZE - 1,
        .flags = IORESOURCE_MEM,
    }
};

static struct platform_device pdev = {
    .name = PLATFORM_LED_NAME,
    .resource = led_device_resource,
    .num_resources = ARRAY_SIZE(led_device_resource),
    .dev = {
        .release = led_device_release,
    }
};

static int __init led_init(void)
{
    int err = 0;
    err = platform_device_register(&pdev);
    if (err < 0) {
        printk("platform_device_register failed\n");
        goto err_platform_device_register;
    }

    printk("device init success\n");
    return 0;

err_platform_device_register:
    return err;
}

static void __exit led_exit(void)
{
    platform_device_unregister(&pdev);
    printk("unregister device\n");
}

MODULE_AUTHOR("jk luo");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("This is platform device");

module_init(led_init);
module_exit(led_exit);


2 Linux设备树

  • Linux内核在启动的时候,要求把设备树文件传递给它。它拿到设备树之后,会解析设备树文件,从而识别设备信息

  • 因为设备的信息是针对于特定平台的,如果我们在Linux内核中包含太多设备信息,则Linux内核移植性就会变差。引入设备树之后,设备的信息的描述不再在是以代码的形式存在于Linux内核源代码中

  • dtc,device tree compiler,是将.dts 编译为.dtb需要用到的**编译工具,**是编译设备树的小工具

  • dts,device tree source,是设备树**源码文件,**是描述硬件信息的asiII文本文件

  • dtsi,device tree source include,是设备树源码文件要用到的头文件,类似头文件,描述平台共性

  • dtb,device tree binary,是将DTS 编译以后得到的二进制文件是编译后的二进制文件,可被bootloader/kernel识别并解析

一般开发的时候,把这些设备树文件拷贝出来,方便查找:

  • imx6ull-14x14-smartcar.dts:外围设备相关设备树文件
  • imx6ull.dtsi:芯片相关设备树文件

将dtb文件反编译成dts文件C.将test.dtb文件反编译成test.dts文件:dtc -O dts -I dtb -o test.dts test.dtb

2.1 设备树语法规则

一个节点就是用来描述一个设备的信息,每个节点必须有一个<名称>[@<设备地址>]形式的名字。

  • 1、名称就是一个ascii字符串,节点的命名应该根据设备的功能来命名。例如一个3com以太网适配器的节点就应该命名为ethernet,而不应该是3com509
  • 2、如果存在reg属性:则设备地址是reg属性的第一个数字。
  • 3、每个设备的节点都应该有一个compatible属性

2.2 节点属性

属性有两种格式:

  • 格式1(没有值) : property-name
  • 格式2(键值对) : property-name = value

2.3 添加设备树节点

在设备树文件的首节点的最后一个大括号之前添加新节点: 每个设备树节点必须要有compatible属性。compatible用于与驱动匹配,reg表示寄存器地址和大小。

	};
	// 在首节点的最后一个大括号之前添加新节点。节点名称格式为:名称@reg中第一个数字
	smartcar-led@20c406c {
		compatible = "imx-led"; // 这个名称与驱动匹配
		reg = <0x20c406c 0x4>,<0x20e00b0 0x4>,<0x209c000 0x8>; // 设备的寄存器地址,多个寄存器,用逗号隔开
	};
};

在开发板的/sys/firemware/devicetree/base目录下可以查看设备树是否添加成功。

2.4 在驱动中匹配设备树节点

通过struct device_driver结构体中的of_match_table成员,来匹配设备树节点。

static struct platform_driver imx_led_driver = {
	.driver = {
           .of_match_table = led_dt_ids, // 匹配设备树节点
		  },
};

3 pinctrl和GPIO子系统

所谓的子系统,实质上就是设备树中,对SOC芯片不同寄存器进行了定义和配置。驱动开发时,仅需了解了SOC芯片厂商是如何在设备树中定义这些寄存器的,然后将这些子系统配置,以节点属性的方式添加到我们新增的设备树节点中;最后编译设备树,并在驱动程序中调用各子系统的系统API,操作寄存器。

比如:使用IMX6ULL,通过GPIO管脚控制LED流水灯亮、灭。

  • 控制流水灯,需要根据硬件电路图,找到对应的控制管脚,设置管脚IO复用模式IOMUX为GPIO的工作模式(IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA)
  • 配置好IOMUX后,还需要配置管脚PAD属性,这些属性配置比较复杂,需要根据SOC厂商的芯片说明(IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA),进行配置,通常参考设备树中其他pinctrl的配置值即可。
  • 最后要配置管脚的输入输出工作模式。如果为输出工作模式,还需要配置高低电平。

基于以上流程:

  • SOC芯片厂商,在设备树中,对IOMUX和输入工作模式配置,通过一个宏定义直接做好了,我们只需找到对应的宏即可
  • 管脚PAD属性:参考设备树中,同一IOMUX工作模式下,厂商的配置。
  • 最后,将这些配置,在pinctrl子系统中,新增子节点。
		pinctrl_rgb_led: rgb_led {
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO04__GPIO1_IO04  0x1b0b1
				MX6UL_PAD_CSI_VSYNC__GPIO4_IO19  0x1b0b1
				MX6UL_PAD_CSI_HSYNC__GPIO4_IO20  0x1b0b1
			>;
		};

GPIO子系统:

  • 在设备树文件imx6ull.dtsi中,定义了各gpioX组的设备信息,只需在我们新增的设备树节点中,以属性的方式引用对应的gpioX组;最后在驱动程序中,调用系统提供的API操作GPIO管脚。
	};
	// 在首节点的最后一个大括号之前添加新节点
	smartcar-led@20c406c {
		compatible = "imx-led"; // 这个名称与驱动匹配
		reg = <0x20c406c 0x4>,<0x20e00b0 0x4>,<0x209c000 0x8>; // 设备的寄存器地址
		status = okay;
		pinctrl-0 = <&pinctrl_rgb_led>;
		rgb_led_red = <gpio1 4 GPIO_ACTIVE_LOW>;
		rgb_led_green = <gpio4 20 GPIO_ACTIVE_LOW>;
		rgb_led_red = <gpio4 19 GPIO_ACTIVE_LOW>;
	};
};

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

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

相关文章

【H2O2|全栈】JS入门知识(二)

目录 JS 前言 准备工作 运算符 算数运算符 比较运算符 自增、自减运算符 逻辑运算符 运算符的优先级 分支语句 if-else语句 switch语句 三元表达式 结束语 JS 前言 本系列博客主要分享JavaScript的基础语法知识&#xff0c;本期为第二期&#xff0c;包含一些简…

平时使用Xshell能连接虚拟机,现在突然连接不上

问题&#xff1a;平时使用Xshell能连接虚拟机&#xff0c;现在突然连接不上&#xff0c;使用ip addr 命令查看ip地址 ens33 接口状态为 DOWN&#xff0c;没有分配IP地址&#xff0c;这通常意味着该网络接口未激活或存在配置问题。&#xff08;因为平时能连接&#xff0c;就说明…

mysql 09 独立表空间结构

表空间中的页实在是太多了&#xff0c;为了更好的管理这些页面&#xff0c;设计 InnoDB 的大叔们提出了 区 &#xff08;英文名&#xff1a; extent &#xff09;的概念。对于16KB的页来说&#xff0c;连续的64个页就是一个 区 &#xff0c;也就是说一个区默认占用1MB空间大小。…

农作物苹果叶片病虫害识别数据集

农作物苹果叶片病虫害识别数据集 一、引言 农作物病虫害是影响农业生产的重要因素之一&#xff0c;其中苹果作为广泛种植的水果品种&#xff0c;其叶片病虫害问题尤为突出。为了有效应对苹果叶片病虫害&#xff0c;提高苹果产量和品质&#xff0c;农业科研机构和学者不断开展…

2024软考网络工程师笔记 - 第4章.局域网和城域网

文章目录 局域网基础1️⃣局域网和城域网体系架构 IEEE&#xff08;负责链路层&#xff09;2️⃣局域网拓扑结构 &#x1f551;CSMA/CD1️⃣CSMA/CD2️⃣CSMA/CD三种监听算法3️⃣冲突检测原理 &#x1f552;二进制指数退避算法1️⃣ 二进制指数退避算法 &#x1f553;最小帧长…

你的抠图最快速度是多久?

前言 在图像处理的过程中&#xff0c;抠图速度和质量往往是大家非常关注的问题。那么&#xff0c;你的抠图最快速度是多久呢&#xff1f;今天我要给大家分享一个我用过的极为方便的抠图工具 —— 千鹿 AI。 只需要简单地上传图片&#xff0c;几秒钟后&#xff0c;就能得到一张…

【超详细】TCP协议

TCP(Transmission Control Protocol 传输控制协议) 传输层协议有连接可靠传输面向字节流 为什么TCP是传输控制协议呢&#xff1f; 我们以前所看到的write接口&#xff0c;都是把用户级缓冲区的数据拷贝到发送缓冲区中&#xff0c;然后数据就由TCP自主决定了&#xff0c;所以…

29.第二阶段x86游戏实战2-遍历周围-花指令与二叉树数据结构(有如何阅读vm代码混淆代码)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

到底是微服务,还是SOA?

引言&#xff1a;大概正式工作有5年了&#xff0c;换了三个大厂【也是真特么世道艰难&#xff0c;中国互联网人才饱和了】。基本上每个公司有的架构都不太相同&#xff0c;干过TOC和TOB的业务&#xff0c;但是大家用的架构都不太相同。有坚持ALL in one的SB&#xff0c;最后服务…

windows下安装、配置neo4j并服务化启动

第一步&#xff1a;下载Neo4j压缩包 官网下载地址&#xff1a;https://neo4j.com/download-center/ &#xff08;官网下载真的非常慢&#xff0c;而且会自己中断&#xff0c;建议从以下链接下载&#xff09; 百度网盘下载地址&#xff1a;链接&#xff1a;https://pan.baid…

李生——2024年特别推荐中国品牌艺术家

李生北京人&#xff0c;字玄鹤、云鹤&#xff0c;号墨湖斋&#xff0c;玄鹤楼&#xff0c;中国共产党党员。主要成就:中国著名书法家、国家高级书法师、中国当代正能量文艺工作者:时代标杆等荣誉称号&#xff0c;现为中国东方文化研究会科教文化艺术专业委员会副研究员。自幼喜…

基于Python的博客系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

JavaSE——泛型

目录 一、泛型的引入 二、泛型的好处 三、泛型介绍 四、泛型的语法 (一)泛型的声明 (二)泛型的实例化 五、泛型使用的注意事项和细节 六、泛型练习题1 七、自定义泛型 (一)自定义泛型类 (二)自定义泛型接口 (三)自定义泛型方法 八、泛型练习题2 九、泛型的继承和…

【Linux-进程间通信】vscode使用通信引入匿名管道引入

一、新系统&#xff0c;新软件 1.新系统 哈喽宝子们&#xff0c;从今以后我们不再使用风靡一时的CentOS系统了&#xff0c;因为CentOS已经不在维护了&#xff0c;各大公司几乎也都从CentOS转入其他操作系统了&#xff1b;我们现在由原来的CentOS系统切换到最新的Ubuntu系统&a…

向日葵下载教程以及三款远程控制工具推荐!!!

向日葵远程控制下载教程&#xff01;&#xff01; 亲爱的朋友们&#xff0c;如果你对远程控制软件有所需求&#xff0c;那么向日葵绝对是一个不错的选择。现在我将带你走一遍向日葵的下载流程。 1. 打开你的浏览器&#xff0c;输入“向日葵官方网站”&#xff0c;进入官方网站…

力扣之1398.购买了产品A和产品B却没有购买产品C顾客

题目&#xff1a; Sql 建表语句&#xff1a; Create table If Not Exists Customers (customer_id int, customer_name varchar(30)) Create table If Not Exists Orders (order_id int, customer_id int, product_name varchar(30)) Truncate table Customers insert in…

前端求职简历-待补充

当然可以&#xff0c;针对大厂的前端岗位&#xff0c;一个吸引人的简历应该突出你的技术能力、项目经验、教育背景以及任何能体现你学习能力和团队协作能力的证明。以下是一个简历大纲示例&#xff0c;你可以根据自己的实际情况进行调整&#xff1a; 个人信息 姓名联系方式&a…

如何在算家云搭建SadTalker(数字人)

一、SadTalker简介 SadTalker 是一个基于深度学习的AI 数字人制作工具&#xff0c;可以通过对照片中的人物进行动态化处理,生成具有头部运动和面部表情的数字人。该模型通过接收一张图片和一段音频文件&#xff0c;能够自动生成包含人脸动作&#xff08;如张嘴、眨眼、移动头部…

comfyui工作流保姆级教程来啦(附整合包)!从入门到精通一文解决

一、SD主流 UI Stable Diffusion&#xff08;SD&#xff09;因为其开源特性&#xff0c;有着较高的受欢迎程度&#xff0c;并且基于SD的开源社区及教程、插件等&#xff0c;都是所有工具里最多的。基于SD&#xff0c;有不同的操作界面&#xff0c;可以理解为一个工具的不同客户…

网络编程(21)——通过beast库快速实现http服务器

目录 二十一、day21 1. 头文件和作用域重命名 2. reponse时调用的一些函数 3. http_connection a. 构造函数 b. start() c. process_request() d. create_response() e. create_post_response() f. write_response() 4. Server 5. 主函数 6. 测试 1&#xff09;测…