平台设备驱动之gpio子系统(写驱动实现在/sys/...目录下用echo命令点灯)

news2025/2/27 5:40:17
1、 关键函数(include/linux 及 driver目录下)
module_platform_driver(leds_drv);   //平台设备驱动入口
	//获取匹配成功后设备树节点中的 propertyof_get_named_gpio_flags(node, "led_gpio", 0, &flags);  
	//在/sys/目录下创建文件供操作,第一个参数相当于设备地址,第二个是待创建的与设备对应的文件名sysfs_create_file(&dev->kobj, &gpio_attr[i].attr);   	
	// 用于向文件写数据											gpio_direction_output(gpio_dev_pointer->led_gpio, gpio_dev_pointer->led_gpio_output); 
 	//用于读取文件数据gpio_get_value(gpio_dev_pointer->smoke_sensor_gpio); 
2、驱动完整代码
#include <linux/init.h>                        
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>

#include <linux/of_gpio.h>
#include <linux/gpio.h>

#include <linux/platform_device.h>
#include <asm/io.h>

#include <dt-bindings/gpio/gpio.h>

#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#endif

struct gpio_dev{
	struct platform_device *pdev;
	int led_gpio;
	int led_gpio_output;
	int smoke_sensor_gpio;
};

struct gpio_dev * gpio_dev_pointer = NULL;

static ssize_t led_store(struct device *dev, struct device_attribute *attr,
              const char *buf, size_t count) {
              
    //写文件,控制 gpio 输出 ( echo 1 >   led_gpio)                
    if (buf[0] == '0') {
		gpio_dev_pointer->led_gpio_output = 0;
        gpio_direction_output(gpio_dev_pointer->led_gpio, gpio_dev_pointer->led_gpio_output);
    }else if (buf[0] == '1') {
		gpio_dev_pointer->led_gpio_output = 1;
        gpio_direction_output(gpio_dev_pointer->led_gpio, gpio_dev_pointer->led_gpio_output);
    }    

    printk(KERN_ERR "led_gpio_store %c \n",gpio_dev_pointer->led_gpio_output);   
    return count;
}

static ssize_t smoke_sensor_show(struct device *dev, struct device_attribute *attr,char *buf){  
	int sensor_value = 0;
	sensor_value = gpio_get_value(gpio_dev_pointer->smoke_sensor_gpio);//cat smoke_sensor_gpio时会触发
	return snprintf(buf, PAGE_SIZE, "%d\n",sensor_value);
}

static struct device_attribute gpio_attr[] = {  
    __ATTR(led_gpio, 0664, NULL, led_store), //写:关联属性文件的写回调函数(*store)  echo时触发
    __ATTR(smoke_sensor_gpio, 0664, smoke_sensor_show,NULL), //读:关联属性文件的读回调函数(*show)  cat 时触发
};

static int gpio_init_sysfs(struct device *dev)
{
	int i, ret;
	for(i = 0; i < ARRAY_SIZE(gpio_attr); i++){
		ret = sysfs_create_file(&dev->kobj, &gpio_attr[i].attr);
		if(ret){
			dev_err(dev, "create charger node(%s) error\n",gpio_attr[i].attr.name);
       		return -1;
			}			
		}
	return 0;
}

static int gpio_remove_sysfs(struct device *dev)
{
	int i;
	for(i = 0; i < ARRAY_SIZE(gpio_attr); i++){
		 sysfs_remove_file(&dev->kobj, &gpio_attr[i].attr);
		}
	return 0;
}


static int get_OF_node_property(struct gpio_dev *pdata){
	int gpio;
	int ret;
	enum of_gpio_flags flags;
	struct device *dev = &pdata->pdev->dev;
	struct device_node *node = dev->of_node;


	gpio = of_get_named_gpio_flags(node, "led_gpio", 0, &flags);
	if(gpio_is_valid(gpio))
		{
			pdata->led_gpio = gpio;
			pdata->led_gpio_output = (flags == GPIO_ACTIVE_HIGH)?1:0;
			printk(KERN_ERR"led_gpio: %d\n", pdata->led_gpio);
			ret = devm_gpio_request(dev,gpio,"led_gpio");
			if(ret){
					printk("Failed to get led_gpio gpio.\n");
					return -1;
				}
		}
	
	gpio = of_get_named_gpio_flags(node, "smoke_sensor_gpio", 0, &flags);
    if (gpio_is_valid(gpio))
    {
	pdata->smoke_sensor_gpio        = gpio;
	printk(KERN_ERR"smoke_sensor_gpio: %d\n", pdata->smoke_sensor_gpio);

	ret = devm_gpio_request(dev,gpio, "smoke_sensor_gpio");
	if (ret) {
	   printk("Failed to get smoke_sensor_gpio gpio.\n");
	   return -1;
	}

	ret = gpio_direction_input(gpio);
	if (ret) {
	   printk("Failed to set flame_sensor_gpio gpio.\n");
	   return -1;
	}
    }
	return 0;
	
}

static void gpio_set_default(struct gpio_dev *pdata) {
    if (pdata->led_gpio) {
        gpio_direction_output(pdata->led_gpio, pdata->led_gpio_output);
    }
}


int leds_probe(struct platform_device *pdev)
{
   int  ret = 0;
   printk(KERN_ALERT "%s \n",__func__);      
   gpio_dev_pointer = kmalloc(sizeof(struct gpio_dev), GFP_KERNEL);//为结构体指针申请空间
   if (gpio_dev_pointer == NULL) {
      printk(KERN_ERR"kmalloc struct gpio_dev err \n");
      return -ENOMEM;
   }
   memset(gpio_dev_pointer, 0, sizeof(struct gpio_dev)); //初始化结构体
   
   gpio_dev_pointer->pdev = pdev;
   ret = get_OF_node_property(gpio_dev_pointer);
   if(ret<0){
	  printk(KERN_ERR"gpio_dt err \n");	
	  return -1;
     }
   gpio_set_default(gpio_dev_pointer);
   ret = gpio_init_sysfs(&gpio_dev_pointer->pdev->dev);
   if(ret<0){
	printk(KERN_ERR"gpio_init_sysfs  err \n");	
	return -1;
   }
   printk(KERN_ALERT "%s  ok !!\n",__func__);
   return 0;

}

int leds_remove(struct platform_device *pdev)
{   
    gpio_remove_sysfs(&gpio_dev_pointer->pdev->dev);
    kfree(gpio_dev_pointer);
	printk("leds_remove ok\n");   
    return 0;
}

static const struct of_device_id of_led_match[] = {
    { .compatible = "sys_rw_led_sensor", },
    {},
};

MODULE_DEVICE_TABLE(of, of_led_match);

struct platform_driver leds_drv = {
   .driver = {
      .owner = THIS_MODULE,
      .name = "sys_rw_led driver" ,
      .of_match_table = of_led_match,
   },
   .probe = leds_probe,
   .remove = leds_remove,    
};
module_platform_driver(leds_drv);
MODULE_LICENSE("GPL");
3、测试代码
$ insmod gpio.ko
$ cd /sys/devices/sys_rw_gpio
$ echo 0 > led_gpio  //关灯
$ echo 1 > led_gpio  //亮灯	
$ cat smoke_sensor_gpio  //读管脚输入电平,默认读到0,用杜邦线,把它接到前面亮灯的管脚时,能成功读到1
4、验证结果

在这里插入图片描述

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

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

相关文章

JavaScript将:;隔开的字符串转换为json格式。使用正则表达式匹配键值对,并构建对象。多用于解析cssText为style Object对象

// 使用正则表达式匹配键值对&#xff0c;并构建对象 let string2Json(s)>{const r {};s.replace(/&#xff1b;/g, ;).replace(/\;/g, \n).replace(/&#xff1a;/g, :).replace(/\n/g, \n)//合并多个换行符.split(\n).forEach(item > {const [k, v] item.split(:);(k…

2025年追觅科技社招校招入职测评北森题库商业推理测试内容与技巧

在追觅科技的招聘流程中&#xff0c;无论是校园招聘还是社会招聘&#xff0c;应聘者都需要通过北森测评题库的商业推理部分。这部分的测评旨在评估应聘者的商业推理能力&#xff0c;是评估考生综合能力的重要工具。考试时间为40分钟&#xff0c;需要完成28题&#xff0c;题型以…

【工具变量】公司企业数字领导力(2004-2023年)

数据简介&#xff1a;企业数字化领导力是指在数字经济时代&#xff0c;领导者通过战略性地使用数字资产、引领组织变革&#xff0c;使企业在数字化环境中获得持续成功的能力。对于上市公司而言&#xff0c;这种领导力尤为重要&#xff0c;因为它直接关系到企业的战略方向、市场…

【Vue工作原理】VueCli4 模板文件template不存在会生产一个默认文件原理

Vue CLI 4 的 HtmlWebpackPlugin 在模板文件缺失时&#xff0c;‌不会中断构建流程‌&#xff0c;而是自动生成一个‌极简 HTML 结构‌&#xff08;DeepSeek回答&#xff09; ‌&#x1f4d8; 官方资料来源解析&#xff08;基于 2025 年存档数据&#xff09;‌ 当前时间&#…

数据开发的简历及面试

简历 个人信息: 邮箱别写QQ邮箱, 写126邮箱/189邮箱等 学历>>本科及以上写,大专及以下不写 专业>>非计算机专业不写 政治面貌>>党员写, 群众不用写 掌握的技能: 精通 > 熟悉 > 了解 专业工具: 大数据相关的 公司: 如果没有可以写的>>金融服…

如何在docker上部署前端nginx服务(VUE)

目录结构 clean.sh docker stop rszWeb; docker rm rszWeb; start.sh docker run -d \ --name rszWeb \ -p 7084:80 \ -m 500m \ --privileged=true \ --restart=always \ -v /home/rsz/ui/conf/nginx.conf:/etc/nginx/nginx.conf \ -v /home/rsz/ui/logs:/meta/logs \ -v /…

模型和数据集的平台之在Hugging Face上进行模型下载、上传以及创建专属Space

模型下载 步骤&#xff1a; 注册Hugging Face平台 https://huggingface.co/ 新建一个hf_download_josn.py 文件 touch hf_download_josn.py 编写hf_download_josn.py文件 import os from huggingface_hub import hf_hub_download# 指定模型标识符 repo_id "inter…

[Web 信息收集] Web 信息收集 — 手动收集 IP 信息

关注这个专栏的其他相关笔记&#xff1a;[Web 安全] Web 安全攻防 - 学习手册-CSDN博客 0x01&#xff1a;通过 DNS 服务获取域名对应 IP DNS 即域名系统&#xff0c;用于将域名与 IP 地址相互映射&#xff0c;方便用户访问互联网。对于域名到 IP 的转换过程则可以参考下面这篇…

排序算法(3):

这是我们的最后一篇排序算法了&#xff0c;也是我们的初阶数据结构的最后一篇了。 我们来看&#xff0c;我们之前已经讲完了插入排序&#xff0c;选择排序&#xff0c;交换排序&#xff0c;我们还剩下最后一个归并排序&#xff0c;我们今天就讲解归并排序&#xff0c;另外我们还…

TypeScript - 泛型

泛型允许在定义函数、类或接口时&#xff0c;使用类型参数来表示未指定的类型&#xff0c;这些参数在具体使用时&#xff0c;才被指定具体的类型&#xff0c;泛型能让同一段代码适用于多种类型&#xff0c;同时仍然保持类型的安全性。 举例&#xff1a;如下代码中 <T> 就…

Python基于Django和Vue的校园互助平台(附源码、文档说明)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

Redis 高可用性:如何让你的缓存一直在线,稳定运行?

&#x1f3af; 引言&#xff1a;Redis的高可用性为啥这么重要&#xff1f; 在现代高可用系统中&#xff0c;Redis 是一款不可或缺的分布式缓存与数据库系统。无论是提升访问速度&#xff0c;还是实现数据的高效持久化&#xff0c;Redis 都能轻松搞定。可是&#xff0c;当你把 …

【Linux】调试工具GDB的使用及案例讲解

Linux系列 文章目录 Linux系列前言一、gdb的使用背景二、gdb的使用总结 本篇主要针对小白讲解&#xff0c;可以很多地方比较咯嗦 前言 GDB是Linux下一款强大的调试工具。GDB可以调试C、C、Java等语言&#xff0c;对于在Linux下工作的程序员来说&#xff0c;GDB是必不可少的调试…

DeepSeek回答:AI时代Go语言学习路线

最近有小伙伴经常会问&#xff1a;**该如何学习入门Go语言&#xff1f;怎样提升Go语言Coding水平&#xff1f;**这篇文章我们就使用DeepSeek来梳理下Go语言在AI时代的学习路线。 向DeepSeek提问的问题原文&#xff1a; 你现在是一名资深的Go语言工程师&#xff0c;精通Go语言并…

1分钟用DeepSeek编写一个PDF转Word软件

一、引言 如今&#xff0c;在线工具的普及让PDF转Word成为了一个常见需求&#xff0c;常见的pdf转word工具有收费的wps&#xff0c;免费的有pdfgear&#xff0c;见下文&#xff1a; PDFgear:一款免费的PDF编辑、格式转化软件-CSDN博客 还有网上在线的免费pdf转word工具smallp…

【Linux】初探信号的奥秘

目录 一、引入信号&#xff1a; 1、什么是信号&#xff1a; 二、前后台进程&#xff1a; 三、信号的处理方式&#xff1a; 四、键盘数据与信号&#xff1a; 前言&#xff1a; 在Linux系统编程中&#xff0c;信号&#xff08;Signal&#xff09;是一种至关重要的进程间通信…

Ubuntu搭建esp32环境 配置打开AT指令集 websocket功能

1&#xff0c;搭建前提 环境搭建参考乐鑫官网给的本地编译 ESP-AT 工程方法 因为公司电脑和网络的特殊性&#xff0c;不能正确解析域名&#xff08;仅在浏览器上可以访问&#xff09; &#xff0c;所以这边访问的时候改成了ssh 未了避免使用外网困难的问题&#xff0c;这里用…

express(node ORM) 使用 Winston 记录日志 及数据库保存日志

一、安装 npm i winston npm i winston-mysql二、 配置 winston 2.1、封装 const config require(__dirname ‘/…/config/config.json’)[env]; 先判断当前是什么环境&#xff0c;如果.env中没有配置&#xff0c;就是开发环境。接着去config/config.json中读取对应的配置。…

是德科技keysight N5173B信号发生器,是一款经济高效的仪器

是德科技keysight N5173B信号发生器安捷伦N5173B信号源 是德N5173B微波模拟信号发生器&#xff0c;拥有 9 kHz 至 40 GHz 的频率覆盖范围&#xff0c;N5173B为宽带滤波器、放大器、接收机等器件的参数测试提供了必要的信号&#xff0c;是一款经济高效的仪器。 N5173B特点&…

从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)?

本文首发&#xff1a;从零到一&#xff1a;如何用阿里云百炼和火山引擎搭建专属 AI 助手&#xff08;DeepSeek&#xff09;&#xff1f; 阿里云百炼和火山引擎都推出了免费的 DeepSeek 模型体验额度&#xff0c;今天我和大家一起搭建一个本地的专属 AI 助手。  阿里云百炼为 …