用paltform框架的驱动形式,编写驱动,应用层程序,在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动

2023-11-07

驱动文件

#include <linux/init.h>
#include <linux/module.h>
#include<linux/platform_device.h>
#include<linux/mod_devicetable.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

 
//创建设备节点,便于应用层对设备文件进行读写
struct cdev *cdev;
dev_t devno;
struct class *cls;
struct device *device;
unsigned int minor = 0;
unsigned int major = 0;
struct resource *res;
int irqno;
struct gpio_desc *gpiono_d;

//解析设备树,管理gpio子系统
struct device_node *denode;
int irq;
struct gpio_desc *gpiono[4];
 
//ioctl灯的状态宏
enum{
	LED1,
	LED2,
	LED3,
};
#define LED_ON _IOW('a',1,int)
#define LED_OFF _IOW('a',0,int)
 
irqreturn_t irq_handler(int irq,void *arg)
{
	gpiod_set_value(gpiono[3],!gpiod_get_value(gpiono[3]));
	return IRQ_HANDLED;	
} 
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
int mycdev_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long args)
{
	int which;
    int ret;
 
    switch(cmd)
    {
    case LED_ON:
        ret = copy_from_user(&which,(void*)args,sizeof(int));
        if(ret)
        {
            printk("copy from user is error\n");
            return -EIO;
        }
        switch (which)
        {
            case LED1:
                gpiod_set_value(gpiono[0],1);   
                break;
            case LED2:
                gpiod_set_value(gpiono[1],1);   
                break;
            case LED3:
                gpiod_set_value(gpiono[2],1);   
                break;
        }
    break;
    case LED_OFF:
        ret = copy_from_user(&which,(void*)args,sizeof(int));
        if(ret)
        {
            printk("copy from user is error\n");
            return -EIO;
        }
        switch (which)
        {
            case LED1:
                gpiod_set_value(gpiono[0],0);   
				break;
            case LED2:
                gpiod_set_value(gpiono[1],0);   
                break;
            case LED3:
                gpiod_set_value(gpiono[2],0);   
                break;
        }
        break; 
	}
	return 0;
}
const struct file_operations fops = {
    .open = mycdev_open,
	.unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};

int fun_dev(void)
{
    int ret;
	int i;
	//1.分配对象
	cdev = cdev_alloc();
	if(NULL == cdev)
	{
		printk("分配对象失败\n");
		ret= -ENOMEM;
		goto ERR1;
	}
	printk("分配对象成功\n");
	//2.对象初始化
	cdev_init(cdev,&fops);
	//3.设备资源的申请
	ret = alloc_chrdev_region(&devno,minor,3,"mycdev");
	if(ret)
	{
		printk("动态申请设备好失败\n");
		goto ERR2;
	}
	major = MAJOR(devno);
	minor = MINOR(devno);
 
	//4.注册
	ret = cdev_add(cdev,devno,3);
    if(ret)
	{
		printk("驱动独享注册内核失败\n");
		goto ERR3;
	}
	//5.提交目录
	cls = class_create(THIS_MODULE,"mycdev");
	if(IS_ERR(cls))
	{
		printk("向上提交目录失败\n");
		goto ERR4;
	}
	//6.提交设备节点信息,需要提交3次节点信息
	for(i = 0;i < 3;i++)
	{
		device = device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
		if(IS_ERR(device))
		{
			printk("向上提交节点信息失败\n");
			goto ERR5;
		}
	}
    return 0;
ERR5://
	for(--i;i>=0;i--)
	{
		device_destroy(cls,MKDEV(major,i));
	}
	class_destroy(cls);
 
ERR4://
	cdev_del(cdev);
 
ERR3://
    unregister_chrdev_region(MKDEV(major,minor),3);
ERR2://
    kfree(cdev);
ERR1://对象空间申请失败
	return ret;
}

//分配对象并且初始化
//probe函数
int pdrv_probe(struct platform_device *pdev)
{
   char *p[4] = {"led1","led2","led3","fan"};
	int ret;
	int i;
    fun_dev();
	//由设备名解析对应的设备树节点
	denode = of_find_node_by_name(NULL,"keyirq");
	if(denode == NULL)
	{
		printk("解析设备树失败\n");
		return -EIO;
	}
	//获取中断号
	irq = irq_of_parse_and_map(denode,0);
	if(!irq)
	{
		printk("获取软中断号失败\n");
		return -ENXIO;
	}
	
	//注册中断号
	ret = request_irq(irq,irq_handler,IRQF_TRIGGER_FALLING,"myirq1",NULL);
	if(ret)
	{
		printk("注册中断号失败\n");	
		return -EIO;
 	}
	
	denode = of_find_node_by_name(NULL,"extend-leds");
	if(denode == NULL)
	{
		printk("解析设备树失败\n");
		return -EIO;
	}
	//根据得到的设备树节点解析对应的gpio编号
	for(i = 0;i < 4;i++)
	{
		gpiono[i] = gpiod_get_from_of_node(denode,p[i],0,GPIOD_OUT_LOW,NULL);
		if(IS_ERR(gpiono[i]))
		{
			printk("编号led%d解析失败\n",i);
			return PTR_ERR(gpiono[i]);
		}
	}
	return 0;
}
//remove函数
int pdrv_remove(struct platform_device *pdev)
{
   int i;
	for(i = 0;i < 4;i++)
	{
		gpiod_set_value(gpiono[i],0);
		gpiod_put(gpiono[i]);
	}
	free_irq(irq,NULL);
	//1.销毁节点信息
	for(i=0;i<3;i++)
	{
		device_destroy(cls,MKDEV(major,i));
	}
	//2.销毁目录
	class_destroy(cls);
	//3.注销
	cdev_del(cdev);
	//4.回收设备资源
    unregister_chrdev_region(MKDEV(major,minor),3);
	//5.回收对象空间
    kfree(cdev);
}
//构建设备树匹配标配
struct of_device_id oftable[]=
{
    {.compatible="hqyj,platform"},
     {.compatible="hqyj,platform1"},
    {},
};
//分配对象并且初始化
struct platform_driver pdrv={
    .probe=pdrv_probe,
    .remove=pdrv_remove,
    .driver={
        .name="aaaaa",
        .of_match_table=oftable,//设置设备树匹配    
    },
};
//一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

应用文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
enum{
	LED1,
	LED2,
	LED3,
};
#define LED_ON _IOW('a',1,int)
#define LED_OFF _IOW('a',0,int)
int main(int argc,const char * argv[])
{
    int which;
    int fd = -1;
    fd = open("/dev/mycdev0",O_RDWR);
    if(fd == -1)
    {
        perror("open is error\n");
        return -1;
    }
 
    while(1)
    {
        which = LED1;
        ioctl(fd,LED_ON,&which);
        sleep(1);
        ioctl(fd,LED_OFF,&which);
 
        which = LED2;
        ioctl(fd,LED_ON,&which);
        sleep(1);
        ioctl(fd,LED_OFF,&which);
 
        which = LED3;
        ioctl(fd,LED_ON,&which);
        sleep(1);
        ioctl(fd,LED_OFF,&which);
    }
    close(fd);
    return 0;
}

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

用paltform框架的驱动形式,编写驱动,应用层程序,在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动 的相关文章

  • 归档文件系统或格式

    我正在寻找一种文件类型来存储已退役系统的档案 目前 我们主要使用 tar gz 但从 200GB tar gz 存档中查找并提取几个文件是很麻烦的 因为 tar gz 不支持任何类型的随机访问读取规定 在你明白之前 使用 FUSE 安装 t
  • 在 /dev/input/eventX 中写入事件需要哪些命令?

    我正在开发一个android需要将触摸事件发送到 dev input eventX 的应用程序 我知道C执行此类操作的代码结构如下 struct input event struct timeval time unsigned short
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • 在 Linux 中禁用历史记录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 要在 Linux 环境中禁用历史记录 我执行了以下命令 export HISTFILESIZE 0 export HISTSIZE 0 u
  • 拆分字符串以仅获取前 5 个字符

    我想去那个地点 var log src ap kernelmodule 10 001 100 但看起来我的代码必须处理 ap kernelmodule 10 002 100 ap kernelmodule 10 003 101 等 我想使用
  • Bash 解析和 shell 扩展

    我对 bash 解析输入和执行扩展的方式感到困惑 对于输入来说 hello world 作为 bash 中的参数传递给显示其输入内容的脚本 我不太确定 Bash 如何解析它 Example var hello world displaywh
  • 抑制 makefile 中命令调用的回显?

    我为一个作业编写了一个程序 该程序应该将其输出打印到标准输出 分配规范需要创建一个 Makefile 当调用它时make run gt outputFile应该运行该程序并将输出写入一个文件 该文件的 SHA1 指纹与规范中给出的指纹相同
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • nginx 上的多个网站和可用网站

    通过 nginx 的基本安装 您的sites available文件夹只有一个文件 default 怎么样sites available文件夹的工作原理以及如何使用它来托管多个 单独的 网站 只是为了添加另一种方法 您可以为您托管的每个虚拟
  • 如何根据 HTTP 请求使用 Python 和 Flask 执行 shell 命令并流输出?

    下列的这个帖子 https stackoverflow com questions 15092961 how to continuously display python output in a webpage 我能够tail f网页的日志
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数
  • 为什么内核需要虚拟寻址?

    在Linux中 每个进程都有其虚拟地址空间 例如 32位系统为4GB 其中3GB为进程保留 1GB为内核保留 这种虚拟寻址机制有助于隔离每个进程的地址空间 对于流程来说这是可以理解的 因为有很多流程 但既然我们只有 1 个内核 那么为什么我
  • 无法从 jenkins 作为后台进程运行 nohup 命令

    更新 根据下面的讨论 我编辑了我的答案以获得更准确的描述 我正在尝试从詹金斯运行 nohup 命令 完整的命令是 nohup java jar home jar server process 0 35 jar prod gt gt var
  • 从 Python 调用 PARI/GP

    我想打电话PARI GP http pari math u bordeaux fr dochtml gpman html仅从Python计算函数nextprime n 对于不同的n是我定义的 不幸的是我无法得到帕里蟒蛇 http code
  • 加载数据infile,Windows和Linux的区别

    我有一个需要导入到 MySQL 表的文件 这是我的命令 LOAD DATA LOCAL INFILE C test csv INTO TABLE logs fields terminated by LINES terminated BY n
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t

随机推荐

  • STM32传感器外设集--语音识别模块(LD3320)

    目录 本节主要贴上以前写的语音识别外设LD3320 希望对大家有用 本人已经测试过有用 如何使用 将下面这段函数添加到功能函数中 LD3320 h LD3320 c 本节主要贴上以前写的语音识别外设LD3320 希望对大家有用 本人已经测试
  • 机器学习之 决策树(Decision Tree)

    机器学习算法系列 机器学习 之线性回归 机器学习 之逻辑回归及python实现 机器学习项目实战 交易数据异常检测 机器学习之 决策树 Decision Tree 机器学习之 决策树 Decision Tree python实现 机器学习之
  • 保险业的变革,软件机器人车险录入自动化

    在现代社会 技术的迅猛发展正在改变各行各业的运作方式 包括保险业 随着数字化转型的推进 保险公司采用创新技术来提高效率和准确性 博为小帮软件机器人结合自动化的功能和OCR技术的识别能力 实现了车险单处理流程的全自动化 本文将深入探讨这一技术
  • 漏洞扫描工具 -- awvs13

    我羡慕那些又帅又有钱的男生 他们拥有过很多女孩的青春 而我 只能拼命赚钱 才能拥有一个爱过别人的姑娘 awvs是一款知名的Web网络漏洞扫描工具 它通过网络爬虫测试你的网站安全 检测流行安全漏洞 一 安装主程序 一路下一步 二 绿化程序 1
  • 9、cglib demo分析以及methodProxy与Fastclass源码

    前言 上一节讲了say方法最终会转发 在demo中 cglib CglibProxy intercept这个里面用了 Object result methodProxy invokeSuper o objects 这个invokeSuper
  • Django 出现:Could not parse the remainder: 'date::'Y /m /d''

    在项目中练习中使用动态Url的时候在日期format的时候出现 Could not parse the remainder date Y m d from post date time date Y m d 这里主要是自己跟着练习的时候出现
  • Lodop、C-Lodop页面找不到报404错误解决

    在使用 Lodop C Lodop打印控件时 使用火狐浏览器不报错 换成IE浏览器时报404错误 找不到控件的下载位置 以前的配置如下 1 spring servlet xml中配置 找到打印控件的位置
  • 微信小程序开发1.简易教程

    微信小程序 简易教程 一 基础 第一章 起步 开发小程序的第一步 你需要拥有一个小程序帐号 通过这个帐号你就可以管理你的小程序 跟随这个教程 开始你的小程序之旅吧 申请账号 点击 https mp weixin qq com wxopen
  • C++ 面向对象之引用

    前言 引用是c 区别于c的一个特别好用的特性 它和指针的作用很相似 或者说类似于指针中的常量指针 本文将会从其语法 注意事项 做函数等方面浅谈引用 同时 本文参考了B站视频 链接如下 https www bilibili com video
  • 小白的福音—秒懂UDP协议&TCP协议

    ForeWord 本文介绍了UDP TCP协议的基础知识 主要内容有 UDP TCP协议在TCP IP协议栈中的位置和作用 UDP TCP协议数据段格式 TCP协议如何保证数据传输的可靠性 tips 全文阅读需5min 小伙伴们燥起来 TC
  • 在Linux中配置Samba服务器实现网盘

    在Linux中配置Samba服务器实现网盘 文章目录 在Linux中配置Samba服务器实现网盘 1 安装与基本配置 2 在Windows中使用共享文件夹 3 高级配置 3 1 smb cfg 文件详解 3 2 多用户 多用户组 3 3 典
  • Python网络爬虫实战:爬取携程网酒店评价信息

    这个爬虫是在一个小老弟的委托之下写的 他需要爬取携程网上的酒店的评价数据 来做一些分词和统计方面的分析 然后来找我帮忙 爬这个网站的时候也遇到了一些有意思的小麻烦 正好整理一下拿出来跟大家分享一下 这次爬取过程稍微曲折 各种碰壁 最终成功的
  • Java时间格式化

    Java中的时间格式化是将时间对象转换为指定格式的字符串 或将字符串解析为时间对象 Java提供了丰富的时间格式化API 可以帮助我们方便地处理时间格式化 本篇技术博客将详细介绍Java时间格式化的定义 使用和示例代码 时间格式化 Java
  • 【JavaEE初阶】第八节.多线程(基础篇)阻塞队列(案例二)

    作者简介 大家好 我是未央 博客首页 未央 303 系列专栏 JavaEE初阶 每日一句 人的一生 可以有所作为的时机只有一次 那就是现在 文章目录 一 阻塞队列概论 1 1 阻塞队列的概念与作用 1 2 阻塞队列的应用场景 生产者消费者模
  • Mac 不是私密连接,拒绝访问

    备忘 1 鼠标停在该页面 直接键盘输入 输入时没有任何显示 thisisunsafe 2 刷新页面 参考 Mac chrome 提示您的连接不是私密连接 没有继续访问 20201116更新 同样适用于在打开git图片时 thisisunsa
  • 最简单的大屏适配解决方案---autofit.js

    在工作开发当中 我们避免不了要去做大屏 那么做大屏其实最难的点和最核心的问题就是适配 下面为大家介绍最好用的大屏解决方案 autofit js 一行代码搞定 开袋即食 效果图展示 可根据窗口大小进行自动适配 使用方法 1 npm下载 npm
  • 元代理模型可迁移对抗攻击

    1 引言 该论文是关于黑盒攻击可迁移性的文章 在当前大量的研究中 许多方法直接攻击代理模型并获得的可迁移性的对抗样本来欺骗目标模型 但由于代理模型和目标模型之间的不匹配 使得它们的攻击效果受到局限 在该论文中 作者从一个新颖的角度解决了这个
  • centos 8 配置LVS+ keepalived 高可用

    作者 小刘在C站 个人主页 小刘主页 每天分享云计算网络运维课堂笔记 努力不一定有回报 但一定会有收获加油 一起努力 共赴美好人生 夕阳下 是最美的绽放 树高千尺 落叶归根人生不易 人间真情 前言 现在的努力的程度就是以后生活的好坏 目录
  • 【GPU】显卡算力对比表

    参考链接 英伟达GPU算力表 https developer nvidia com cuda gpus 显卡算力对比表
  • 用paltform框架的驱动形式,编写驱动,应用层程序,在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动

    驱动文件 include