IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux驱动——设备树 -> 正文阅读

[系统运维]Linux驱动——设备树

在对总线设备驱动进行详细说明时可以看出,虽然总线设备驱动可以实现驱动和设备分离,但是总线设备驱动引发另外的一个问题就是在相同的芯片不同的开发板上,当外设资源不同时需要在不同的设备文件中去定义引脚,这样就导致开发板中保留大量设备文件。为了解决这一问题引入了设备树。设备树是为内核中的驱动程序定义硬件信息。上层应用层调用相关设备文件时,会去调用底层的相关设备驱动文件,而驱动所需要操作的相关引脚是由设备树对其进行制定。

在单板上电启动时,首先运行的是bootloader,bootloader的主要作用是启动时为内核传递参数,bootloader会将设备树文件和内核读入到内存中,bootloader会将设备树的地址给到内核。

查看设备树文件:
首先需要编译内核,
先设备环境变量:
在这里插入图片描述
在内核目录下编译设备树文件:
在这里插入图片描述
进入到/arch/arm/boot/dts文件夹下,找到对应的设备树文件,通过使用dtc命令反编译设备树文件,使用dtc编译后就可以将dts内容中包含的一些信息展开:
-I表示输入文件 -O表示输出文件格式
在这里插入图片描述
在编译出来的1.dts中可以查看全部的设备树节点信息:
在这里插入图片描述

在树莓派3b对应的设备树文件中添加设备树节点信息:
在这里插入图片描述
在Linux内核源码目录下使用make dtbs命令进行编译,生成bcm2710-rpi-3-b.dtb文件,将该文件赋值到树莓派boot目录中,重新启动树莓派,让bootloader给内核传递设备树信息。
未加载新的dtb信息之前查看设备树节点信息:
在这里插入图片描述
加载新的dtb信息之后查看设备树节点信息:
在这里插入图片描述
在设备树中如果对设备节点添加compatible属性就可以让该设备树节点成为platform_device,查看总线设备如下:
在这里插入图片描述
打印设备树相关信息可以看到
在这里插入图片描述
其中name是自动添加与设备lable后面的名字一样。

含有compatible属性的设备树节点如何找到对应的设备驱动,Linux内核源码如下:
首先找到platform_bus_type中的match函数中用于设备树匹配的那一项
在这里插入图片描述
在这里插入图片描述

根据函数中的参数,找到对应platform_driver结构体中的device_driver中的of_match_table这一项
在这里插入图片描述
查看对应of_device_id结构体的原型,可以看到其中有compatible
在这里插入图片描述
在整个内核源码中查找of-match_table找到相应的代码示例
在这里插入图片描述
因此就可以知道驱动代码中需要再platform_driver中的driver选项中添加of_match_table选项,并在结构体外定义该结构体,其中包含该平台驱动可以包含的设备树相应的compatible选项。

根据上述分析可以编写平台驱动代码进行测试:

#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linuxq_file.h>
#include <linuxat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linuxy.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/of_device.h>
#include <linuxatform_device.h>

#define LED_MAX_CNT 10

struct led_desc {
	int pin;
	int minor;
};

//确定主设备号 
static int major = 0;
static struct class *led_class;

static int g_ledcnt = 0;
static struct led_desc leds_desc[LED_MAX_CNT];


static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	char status;
	struct inode *inode = file_inode(file);
	int minor = iminor(inode);
	
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(&status, buf, 1);

	printk("set led pin 0x%x as %d\n", leds_desc[minor].pin, status);
	
	return 1;
}

static int led_drv_open (struct inode *node, struct file *file)
{
	int minor = iminor(node);
	
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	printk("init led pin 0x%x as output\n", leds_desc[minor].pin);
	
	return 0;
}

                                 
static struct file_operations led_drv = {
	.owner	 = THIS_MODULE,
	.open    = led_drv_open,
	.write   = led_drv_write,
};
//实现platform_driver的probe函数 
static int led_probe(struct platform_device *pdev)
{	
	int minor;
	int i = 0;

	struct resource *res;
	const char *tmp_str;

	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

	if(!pdev->dev.of_node){                     //普通的平台设备
		res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
		if (!res)
			return -EINVAL;
			minor = g_ledcnt;     
			leds_desc[minor].pin = res->start;    //获取引脚信息
	}else{                                     //设备树设备
		of_property_read_string(pdev->dev.of_node,"pin",&tmp_str);   //获取设备树相关信息到tmp_str中
		printk("pin = %s\n",tmp_str);
		minor = g_ledcnt;
		leds_desc[minor].pin = tmp_str[6] - '0';   //通过设备树中设置的pin信息获取引脚信息
	}

	
	leds_desc[minor].minor = minor;   //次设备号
	
	device_create(led_class, NULL, MKDEV(major, minor), NULL, "led_driver%d", minor); 
	platform_set_drvdata(pdev, &leds_desc[minor]);
	
	g_ledcnt++;
	
    return 0;
}

static int led_remove(struct platform_device *pdev)
{
	struct led_desc *led = platform_get_drvdata(pdev);

	device_destroy(led_class, MKDEV(major, led->minor)); 

    return 0;
}

static const struct of_device_id device_ids[] = {    //用于与设备树compatible进行匹配的信息
	{ .compatible = "CAOHAI" },      //与设备树中的compatible进行匹配
	{ /* sentinel */ }


static struct platform_driver led_driver = {
    .probe      = led_probe,
    .remove     = led_remove,
    .driver     = {
        .name   = "led_driver",
        .of_match_table = device_ids,                //添加与of_match_table作为匹配选项
    },
};


static int __init led_init(void)
{
	int err;
	
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	major = register_chrdev(0, "led_driver", &led_drv);  


	led_class = class_create(THIS_MODULE, "led_driver_class");
	err = PTR_ERR(led_class);
	if (IS_ERR(led_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "led");
		return -1;
	}

	//注册platform_driver
    err = platform_driver_register(&led_driver); 
    
    return err;
}


static void __exit led_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	
    platform_driver_unregister(&led_driver); 

	class_destroy(led_class);
	unregister_chrdev(major, "led_driver");
}


                              
module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

在probe函数中可以看到以下相关信息:
在这里插入图片描述
编译完驱动代码,将代码传送至树莓派装载,可以进入到sys虚拟文件系统中查看总线驱动相关信息如下:
在这里插入图片描述
可以看到在sys虚拟文件系统中该驱动与设备树中的led_for_test_ok相匹配。使用dmesg打印底层相关信息
在这里插入图片描述
learned from:韦东山

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-01 18:06:28  更:2021-12-01 18:06:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:12:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码