自己编写驱动,应用层程序,在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动

2023-10-29

驱动文件

#include <linux/init.h>
#include <linux/module.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;
 
//解析设备树,管理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;
}
static int __init mycdev_init(void)
{
    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;
}

static void __exit mycdev_exit(void)
{
	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);
 
}

module_init(mycdev_init);
module_exit(mycdev_exit);
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(使用前将#替换为@)

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

  • /proc/PID 文件格式

    我想从中检索一些流程信息 proc目录 我的问题如下 中的文件是否有标准格式 proc PID 例如 有这个proc PID status文件与Name t ProcName在第一行 我可以在其他地方用空格代替这个文件吗 t或者类似的东西
  • 退出 bash 脚本但保持进程运行

    我正在运行服务器 需要使用参数执行以下命令 这些脚本目前工作得很好 但问题是当我运行脚本时我无法返回到控制台 它在控制台中保持运行 如果我强行停止它 那么该过程也会停止 我想继续运行该进程并返回到控制台 bin sh php home st
  • Docker DNS 设置

    我尝试使用自定义网络和 dos 设置创建 docker 容器 docker网络创建 driver bridge opt com docker network bridge enable ip masquerade true opt com
  • 是否有可能通过 mmap 匿名内存“打孔”?

    考虑一个使用大量大致页面大小的内存区域 例如 64 kB 左右 的程序 每个内存区域的寿命都相当短暂 在我的特定情况下 这些是绿色线程的替代堆栈 如何最好地分配这些区域 以便一旦该区域不再使用 它 们的页面可以返回到内核 天真的解决方案显然
  • 如何阅读shell命令的源代码?

    我想阅读编写linux命令的实际源代码 我已经获得了一些使用它们的经验 现在我认为是时候与我的机器进行更深层次的交互了 我在这里找到了一些命令http directory fsf org wiki GNU http directory fs
  • 如何从“git log”中查看 Git 中的特定版本?

    My git log显示为 enter code here git trial git log commit 4c5bc66ae50780cf8dcaf032da98422aea6e2cf7 Author king lt email pro
  • 如何在 Linux 中使用单行命令获取 Java 版本

    我想通过单个命令获取 Linux 中的 Java 版本 我是 awk 的新手 所以我正在尝试类似的事情 java version awk print 3 但这不会返回版本 我将如何获取1 6 0 21从下面的Java版本输出 java ve
  • 如何使用ffmpeg重叠和合并多个音频文件?

    我正在尝试将多个音频文件合并到一个文件中 但我可以使用以下命令来连接 而不是连接 ffmpeg v debug i file1 wav i file2 wav i file3 wav filter complex 0 0 concat n
  • 远程linux服务器到远程linux服务器大型稀疏文件复制 - 如何?

    我有两台 CentOS 5 4 服务器 每台服务器上都安装了 VMware Server 假设我始终对 vmware 虚拟机使用稀疏文件 将虚拟机文件从一台服务器复制到另一台服务器的最可靠 最快速的方法是什么 虚拟机的文件复制起来很痛苦 因
  • 如何仅将整个嵌套目录中的头文件复制到另一个目录,在复制到新文件夹后保持相同的层次结构

    我有一个目录 其中有很多头文件 h 和其他 o 和 c 文件以及其他文件 这个目录里面有很多嵌套的目录 我只想将头文件复制到一个单独的目录 并在新目录中保留相同的结构 cp rf oldDirectory newDirectory将复制所有
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • 如何在 Linux x86_64 上模拟 iret

    我正在编写一个基于 Intel VT 的调试器 由于当 NMI Exiting 1 时 iret 指令在 vmx guest 中的性能发生了变化 所以我应该自己处理vmx主机中的NMI 否则 guest会出现nmi可重入错误 我查了英特尔手
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插
  • 使用命令行将 MediaWiki 维基文本格式转换为 HTML

    我倾向于编写大量文档 因此 MediaWiki 格式对我来说很容易理解 而且比编写传统 HTML 节省了我很多时间 然而 我也写了一篇博客 发现一直从键盘切换到鼠标来输入正确的 HTML 标签会增加很多时间 我希望能够使用 Mediawik
  • 我应该使用哪个 Linux 发行版作为 Xen 主机? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我为家庭办公室订购了一台服务器 我想用 Xen 对其进行分区 我认为这将使事情保持干净并且更容易维护 我将运行 MySQL PostgreSQL
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • 是否从页面缓存中的脏页面进行文件读取?

    当字节写入文件时 内核不会立即将这些字节写入磁盘 而是将这些字节存储在页缓存中的脏页中 回写缓存 问题是 如果在脏页刷新到磁盘之前发出文件读取 则将从缓存中的脏页提供字节 还是首先将脏页刷新到磁盘 然后进行磁盘读取以提供字节 将它们存储在进
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • 操作系统什么时候清除进程的内存

    进程在某些操作系统上成功或异常终止 操作系统何时决定擦除分配给该进程的内存 数据 代码等 在退出时或当它想为新进程分配内存时 这个清除内存分配过程在所有操作系统 winXP Win7 linux Mac 上都相同吗 据我了解 页表具有该进程
  • 无法安装 WWW::Curl::Easy: SZBALINT/WWW-Curl-4.17.tar.gz : make NO

    我正在尝试在我的 Fedora 26 机器上安装 WWW Curl Easy gcc c I usr include D REENTRANT D GNU SOURCE O2 g pipe Wall Werror format securit

随机推荐

  • 使用python的tkinter模块制作一个计算器

    使用tkinter模块制作的一个简单的计算器 由于刚学这个模块 所以做的不是很好 截图 点击计算后算式区的值会改成结果 可自行在数字触发的函数中添加数字输入就进行计算回显的功能 代码如下 import tkinter as tk impor
  • Python学习笔记(十):包、模块

    一 包 模块 Python中的包相当于文件夹 模块就是 py文件 不同包下有相同名称的模块时 为了区分 可在模块里加上 包名 模块名 路径 这个路径叫做命名空间 注 如果想让一个普通的文件夹变为包 则需要在这个文件夹内添加 init py文
  • 原子操作实现无锁栈

    atomic3 cpp 使用CAS操作实现一个无锁栈 include
  • Vulkan® A Specification Core And Extension::Vulkan文档核心部分和扩展部分对照与翻译说明

    2020 7 1 更 修改和完善某些描述 Vulkan版本 1 2 137 1 2 145 Vulkan文档分成两种 核心部分 核心部分 扩展部分 核心部分是必定要翻译的 对于扩展部分 本人并不是所有扩展都见过 所以对于扩展部分尽可能的翻译
  • Kanzi Shader入门

    1 版本 kanzi默认支持Opengl ES 2 0 在qnx平台可以支持到ES 3 0 2 着色器 kanzi只支持 顶点着色器 和 片段着色器 3 kanzi studio 无法直接使用shader 需要通过画刷和材质间接使用 在 普
  • strongSwan报文交互过程

    通过上篇案例 我们已经初步掌握了如何通过strongSwan配置两台Linux主机之间的IPsec隧道 今天我们再来看一下strongSwan配置IPsec的报文交互过程和转发性能 组网图还是上次的拓扑 首先查看一下在配置完strongSw
  • 使用FFmpeg命令进行hls切片,得到的ts文件时长不准确

    一 问题描述 使用如下FFmpeg命令进行hls切片 ffmpeg i video2 mp4 hls time 1 f hls out m3u8 由于使用了参数 hls time 1 所以预计生成的ts文件时长会是1秒左右 但结果却是最终生
  • 关于把数据库放在阿里云上,实现共享

    本地的数据库只能实现在自己的机器上访问 别人的电脑无法实现访问 因此通过借助阿里云 把数据库放在阿里云上 从而多人都可以通过阿里云的ip来进行访问操作 在试验过程中 难度最大的就是对阿里云一窍不通 不知从何下手 下面进行一下总结 实现的基本
  • django<model模块和分页功能模块>

    model模块使用 import os django os environ setdefault DJANGO SETTINGS MODULE wxy django settings django setup 指定django的配置 fro
  • dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique:

    C Program Files Java jdk1 8 0 181 bin java exe Dmaven multiModuleProjectDirectory E Software xiaoye CRUD parent Dmaven h
  • Java内存区域(栈、堆、方法区)详细解说

    参考文献 深入学习java虚拟机 概览 java虚拟机在执行java程序的过程中会把它所管理的内存划分成若干个不同的数据区域 这些区域各有用途 以及创建和销毁的时间 有的区域随着虚拟机的进程的启动而存在 有的则依赖用户线程的启动和结束而建立
  • 简单JS解密爬取股票信息案例

    前言 今天给大家带来一个使用JS解密爬取股票信息的案例 本案例比较简单 主要介绍如何找出JS加密的过程 希望通过本案例可以带给大家学习JS的一些思路 本案例网站 https webapi cninfo com cn marketData 一
  • Jetty, “No multipart config for servlet” problem

    I m writing handler for file transfer The request is multipart HTTP message The message is correct tested on other serve
  • Python爬虫:解决SSL证书验证问题

    如果目标网站没有设置好HTTPS证书 又或者网站的HTTPS证书不被CA机构认可 用浏览器访问的话 就可能会出现SSL证书错误的提示 用requests库来请求这类网站的话 会直接抛出SSLError错误 requests exceptio
  • ssh命令详解

    基础命令学习目录 SSH 远程连接工具 连接原理 ssh服务是一个守护进程 demon 系统后台监听客户端的连接 ssh服务端的进程名为sshd 负责实时监听客户端的请求 IP 22端口 包括公共秘钥等交换等信息 ssh服务端由2部分组成
  • C++知识积累:explicit关键字的作用

    explicit意为 显式的 该关键字主要是用于防止类构造函数出现隐式类型转换的情况 且只适用于仅含一个参数的构造函数 我们先来看第一个问题 什么是防止构造函数出现隐式转换呢 来看下面的例子 class A public A int a c
  • React-router v5和v6的区别对比

    以下是两个版本之间的区别 一 首先是注册路由的时候v5的Switch改为了Routes v5 代码如下 import Route Switch from react router dom 引入react router div 注册路由 编写
  • spring boot默认扫描的路径

    一般来说spring boot默认的扫描路径是启动类当前的包和子包 SpringBootApplication EnableTransactionManagement proxyTargetClass true MapperScan bas
  • CSS 新特性总结

    CSS 伪类选择器 is 和 where is 将选择器列表作为参数 并选择该列表中任意一个选择器可以选择的元素 其优先级是由它的选择器列表中优先级最高的选择器决定的 列表值中不能使用伪元素 where 将会选择所有能被该选择器列表中任何一
  • 自己编写驱动,应用层程序,在应用层通过ioctl控制LED灯流水,当按键KEY1按下,让风扇转动

    驱动文件 include