第五十八章 Linux INPUT 子系统实验

imx6ull-alientek-emmc.dts

(使用第四十九章的设备树文件即可)

keyinput.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : keyinput.c
作者 : 左忠凯
版本 : V1.0
描述 : Linux 按键 input 子系统实验
其他 : 无
论坛 : www.openedv.com
日志 : 初版 V1.0 2019/8/21 左忠凯创建
***************************************************************/
#define KEYINPUT_CNT 1 /* 设备号个数 */
#define KEYINPUT_NAME "keyinput" /* 名字 */
#define KEY0VALUE 0X01 /* KEY0 按键值 */
#define INVAKEY 0XFF /* 无效的按键值 */
#define KEY_NUM 1 /* 按键数量 */

/* 中断 IO 描述结构体 */
struct irq_keydesc 
{
	int gpio; /* gpio */
	int irqnum; /* 中断号 */
	unsigned char value; /* 按键对应的键值 */
	char name[10]; /* 名字 */
	irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
};

/* keyinput 设备结构体 */
struct keyinput_dev
{
	dev_t devid; /* 设备号 */
	struct cdev cdev; /* cdev */
	struct class *class; /* 类 */
	struct device *device; /* 设备 */
	struct device_node *nd; /* 设备节点 */
	struct timer_list timer; /* 定义一个定时器 */
	struct irq_keydesc irqkeydesc[KEY_NUM]; /* 按键描述数组 */
	unsigned char curkeynum; /* 当前的按键号 */
	struct input_dev *inputdev; /* input 结构体 */
};

struct keyinput_dev keyinputdev; /* key input 设备 */

/* @description : 中断服务函数,开启定时器,延时 10ms,
* 定时器用于按键消抖。
* @param - irq : 中断号
* @param - dev_id : 设备结构。
* @return : 中断执行结果
*/
static irqreturn_t key0_handler(int irq, void *dev_id)
{
	struct keyinput_dev *dev = (struct keyinput_dev *)dev_id;

	dev->curkeynum = 0;
	dev->timer.data = (volatile long)dev_id;
	mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10));
	return IRQ_RETVAL(IRQ_HANDLED);
}

/* @description : 定时器服务函数,用于按键消抖,定时器到了以后
* 再次读取按键值,如果按键还是处于按下状态就表示按键有效。
* @param - arg : 设备结构变量
* @return : 无
*/
void timer_function(unsigned long arg)
{
	unsigned char value;
	unsigned char num;
	struct irq_keydesc *keydesc;
	struct keyinput_dev *dev = (struct keyinput_dev *)arg;

	num = dev->curkeynum;
	keydesc = &dev->irqkeydesc[num];
	value = gpio_get_value(keydesc->gpio); /* 读取 IO 值 */
	if(value == 0)
	{ 
		/* 按下按键 */
		/* 上报按键值 */
		//input_event(dev->inputdev, EV_KEY, keydesc->value, 1);
		input_report_key(dev->inputdev, keydesc->value, 1);/*1,按下*/
		input_sync(dev->inputdev);
	} 
	else 
	{ 
		/* 按键松开 */
		//input_event(dev->inputdev, EV_KEY, keydesc->value, 0);
		input_report_key(dev->inputdev, keydesc->value, 0);
		input_sync(dev->inputdev);
	} 
}

/*
* @description : 按键 IO 初始化
* @param : 无
* @return : 无
*/
static int keyio_init(void)
{
	unsigned char i = 0;
	char name[10];
	int ret = 0;

	keyinputdev.nd = of_find_node_by_path("/key");
	if (keyinputdev.nd== NULL)
	{
		printk("key node not find!\r\n");
		return -EINVAL;
	}

	/* 提取 GPIO */
	for (i = 0; i < KEY_NUM; i++) 
	{
		keyinputdev.irqkeydesc[i].gpio = 
			of_get_named_gpio(keyinputdev.nd,"key-gpio", i);
		if (keyinputdev.irqkeydesc[i].gpio < 0) 
		{
			printk("can't get key%d\r\n", i);
		}
	}

	/* 初始化 key 所使用的 IO,并且设置成中断模式 */
	for (i = 0; i < KEY_NUM; i++) 
	{
		memset(keyinputdev.irqkeydesc[i].name, 0, sizeof(name)); 
		sprintf(keyinputdev.irqkeydesc[i].name, "KEY%d", i); 
		gpio_request(keyinputdev.irqkeydesc[i].gpio, name);
		gpio_direction_input(keyinputdev.irqkeydesc[i].gpio); 
		keyinputdev.irqkeydesc[i].irqnum =
			irq_of_parse_and_map(keyinputdev.nd, i);
	}
	/* 申请中断 */
	keyinputdev.irqkeydesc[0].handler = key0_handler;
	keyinputdev.irqkeydesc[0].value = KEY_0;

	for (i = 0; i < KEY_NUM; i++) 
	{
		ret = request_irq(keyinputdev.irqkeydesc[i].irqnum,
			keyinputdev.irqkeydesc[i].handler,
			IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
			keyinputdev.irqkeydesc[i].name, &keyinputdev);
		if(ret < 0)
		{
			printk("irq %d request failed!\r\n",
			keyinputdev.irqkeydesc[i].irqnum);
			return -EFAULT;
		}
	}

	/* 创建定时器 */
	init_timer(&keyinputdev.timer);
	keyinputdev.timer.function = timer_function;

	/* 申请 input_dev */
	keyinputdev.inputdev = input_allocate_device();
	keyinputdev.inputdev->name = KEYINPUT_NAME;
	#if 0
	/* 初始化 input_dev,设置产生哪些事件 */
	__set_bit(EV_KEY, keyinputdev.inputdev->evbit); /*按键事件 */
	__set_bit(EV_REP, keyinputdev.inputdev->evbit); /* 重复事件 */

	/* 初始化 input_dev,设置产生哪些按键 */
	__set_bit(KEY_0, keyinputdev.inputdev->keybit);
	#endif

	#if 0
	keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) |
		BIT_MASK(EV_REP);
	keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |=
		BIT_MASK(KEY_0);
	#endif
	keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) |
		BIT_MASK(EV_REP);
	input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0);

	/* 注册输入设备 */
	ret = input_register_device(keyinputdev.inputdev);
	if (ret) 
	{
		printk("register input device failed!\r\n");
		return ret;
	}
	return 0;
}

/*
* @description : 驱动入口函数
* @param : 无
* @return : 无
*/
static int __init keyinput_init(void)
{
	keyio_init();
	return 0;
}

/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit keyinput_exit(void)
{
	unsigned int i = 0;
	/* 删除定时器 */
	del_timer_sync(&keyinputdev.timer);

	/* 释放中断 */
	for (i = 0; i < KEY_NUM; i++) 
	{
		free_irq(keyinputdev.irqkeydesc[i].irqnum, &keyinputdev);
	}
	/* 释放 input_dev */
	input_unregister_device(keyinputdev.inputdev);
	input_free_device(keyinputdev.inputdev);
}

module_init(keyinput_init);
module_exit(keyinput_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

keyinputApp.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : keyinputApp.c
作者 : 左忠凯
版本 : V1.0
描述 : input 子系统测试 APP。
其他 : 无
使用方法 :./keyinputApp /dev/input/event1
论坛 : www.openedv.com
日志 : 初版 V1.0 2019/8/26 左忠凯创建
***************************************************************/

/* 定义一个 input_event 变量,存放输入事件信息 */
static struct input_event inputevent;

/*
* @description : main 主程序
* @param - argc : argv 数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
	int fd;
	int err = 0;
	char *filename;

	filename = argv[1];

	if(argc != 2) 
	{
		printf("Error Usage!\r\n");
		return -1;
	}

	fd = open(filename, O_RDWR);
	if (fd < 0) 
	{
		printf("Can't open file %s\r\n", filename);
		return -1;
	}

	while (1) 
	{
		err = read(fd, &inputevent, sizeof(inputevent));
		if (err > 0)	/* 读取数据成功 */
		{ 
			switch (inputevent.type) 
			{
				case EV_KEY:
					if (inputevent.code < BTN_MISC)	/* 键盘键值 */
					{ 
						printf("key %d %s\r\n", inputevent.code,
							inputevent.value ? "press" : "release");
					} 
					else 
					{
						printf("button %d %s\r\n", inputevent.code,
						    inputevent.value ? "press" : "release");
					}
					break;

				/* 其他类型的事件,自行处理 */
				case EV_REL:
					break;

				case EV_ABS:
					break;

				case EV_MSC:
					break;

				case EV_SW:
					break;
					
				default:
					break;
			}
		} 
		else 
		{
			printf("读取数据失败\r\n");
		}
	}
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

yolov8 opencv模型部署(C++版)

TensorRT系列之 Windows10下yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov7 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov6 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov5 tensorrt模型加速…

Android 常用命令和工具解析之Battery Historian

Batterystats是包含在 Android 框架中的一种工具&#xff0c;用于收集设备上的电池数据。您可以使用adb bugreport命令抓取日志&#xff0c;将收集的电池数据转储到开发机器&#xff0c;并生成可使用 Battery Historian 分析的报告。Battery Historian 会将报告从 Batterystats…

leetcode刷题日记 1

https://leetcode.cn/problems/decode-ways/description/ 题目分析 分析了一下题目&#xff0c;我的第一想法&#xff1a;和之前的上楼梯问题很像 为什么这么说呢&#xff0c;感觉他们的值和他们之前元素都有千丝万缕的联系 就像上楼梯问题 就是我们的dp问题 怎么解释呢&a…

初阶数据结构:树---堆

目录 一、树的概念 二、树的构成 &#xff08;一&#xff09;、树的基本组成成分 &#xff08;二&#xff09;、树的实现方法 三、树的特殊结构------二叉树 &#xff08;一&#xff09;、二叉树的概念 &#xff08;二&#xff09;、二叉树的性质 &#xff08;三&#…

学习笔记:机器学习中的数学原理(一)

1. 集合 集合分为有限集和无限集&#xff1b; 对于有限集&#xff0c;两集合元素数相等即为等势&#xff1b; 对于无限集&#xff0c;两集合元素存在一一映射关系即为等势&#xff1b; 无限集根据是否与正整数集等势分为可数集和不可数集。 2. sigmoid函数&#xff08;也叫…

音频进阶学习十一——离散傅里叶级数DFS

文章目录 前言一、傅里叶级数1.定义2.周期信号序列3.表达式DFSIDFS参数含义 4.DFS公式解析1&#xff09;右边解析 T T T、 f f f、 ω \omega ω的关系求和公式N的释义求和公式K的释义 e j ( − 2 π k n N ) e^{j(\frac{-2\pi kn}{N})} ej(N−2πkn​)的释义 ∑ n 0 N − 1 e…

互联网分布式ID解决方案

业界实现方案 1. 基于UUID 2. 基于DB数据库多种模式(自增主键、segment) 3. 基于Redis 4. 基于ZK、ETCD 5. 基于SnowFlake 6. 美团Leaf(DB-Segment、zkSnowFlake) 7. 百度uid-generator() 基于UUID生成唯一ID UUID生成策略 推荐阅读 DDD领域驱动与微服务架构设计设计模…

BUU28 [GXYCTF2019]BabySQli1

常规万能密码&#xff0c;发现登不上去 过滤掉了or&#xff0c;&#xff0c;当尝试了n种方法以后&#xff0c;最关键的是发现()居然也被过滤了 哈哈&#xff0c;那玩个淡&#xff0c; 再搜wp&#xff01;&#xff01; 当输入admin的时候&#xff0c;提示密码错误&#xff0…

数据分析:企业数字化转型的金钥匙

引言&#xff1a;数字化浪潮下的数据金矿 在数字化浪潮席卷全球的背景下&#xff0c;有研究表明&#xff0c;只有不到30%的企业能够充分利用手中掌握的数据&#xff0c;这是否让人深思&#xff1f;数据已然成为企业最为宝贵的资产之一。然而&#xff0c;企业是否真正准备好从数…

git SourceTree 使用

Source Tree 使用原理 文件的状态 创建仓库和提交 验证 再克隆的时候发发现一个问题&#xff0c;就是有一个 这个验证&#xff0c;起始很简单 就是 gitee 的账号和密码&#xff0c;但是要搞清楚的是账号不是名称&#xff0c;我之前一直再使用名称登录老是出问题 这个很简单的…

485网关数据收发测试

目录 1.UDP SERVER数据收发测试 使用产品&#xff1a; || ZQWL-GW1600NM 产品||【智嵌物联】智能网关型串口服务器 1.UDP SERVER数据收发测试 A&#xff08;TX&#xff09;连接RX B&#xff08;RX&#xff09;连接TX 打开1个网络调试助手&#xff0c;模拟用户的UDP客户端设…

xinference 安装(http导致错误解决)

为什么要使用xinference 安装xinference 环境 1&#xff09;conda create -n Xinference python3.11 注意&#xff1a;3.9 3.10均可能出现xinference 安装时候出现numpy兼容性&#xff0c;以及无法安装all版本 错误&#xff1a; error while attempting to bind on address&am…

路由器如何进行数据包转发?

路由器进行数据包转发的过程是网络通信的核心之一&#xff0c;主要涉及以下几个步骤&#xff1a; 接收数据包&#xff1a;当一个数据包到达路由器的一个接口时&#xff0c;它首先被暂时存储在该接口的缓冲区中。 解析目标地址&#xff1a;路由器会检查数据包中的目标IP地址。…

集合类不安全问题

ArrayList不是线程安全类&#xff0c;在多线程同时写的情况下&#xff0c;会抛出java.util.ConcurrentModificationException异常 解决办法&#xff1a; 1.使用Vector&#xff08;ArrayList所有方法加synchronized&#xff0c;太重&#xff09; 2.使用Collections.synchronized…

Windows Docker笔记-安装docker

安装环境 操作系统&#xff1a;Windows 11 家庭中文版 docker版本&#xff1a;Docker Desktop version: 4.36.0 (175267) 注意&#xff1a; Docker Desktop 支持以下Windows操作系统&#xff1a; 支持的版本&#xff1a;Windows 10&#xff08;家庭版、专业版、企业版、教育…

docker /var/lib/docker/overlay2目录把磁盘空间占满问题

1、查看服务器磁盘空间 df -h果然100%了,docker系统文件把磁盘空间占满了。 2、进入overlay2目录&#xff0c;查找那个容器工作目录占用最高 cd /var/lib/docker/overlay2du -h --max-depth1详见下图 好家伙占用110G&#xff01;复制目录名称2c3c48ccac533c5d4a366d45a19bb9…

【python】简单的flask做页面。一组字母组成的所有单词。这里的输入是一组字母,而输出是所有可能得字母组成的单词列表

目录结构如下&#xff1a; . ├── static │ ├── css │ │ └── styles.css │ └── js │ └── scripts.js ├── templates │ ├── base.html │ ├── case_converter.html │ ├── index.html │ └── word_finder.html ├── app.py ├── tree.py…

吴恩达深度学习——卷积神经网络实例分析

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 LeNet-5AlexNetVGG-16ResNets残差块 1*1卷积 LeNet-5 输入层&#xff1a;输入为一张尺寸是 32 32 1 32321 32321的图像&#xff0c;其中 32 32 3232 3232是图像的长和宽&…

利用 IMU 估计人体关节轴向和位置 —— 论文推导

Title: 利用 IMU 估计人体关节轴向和位置 —— “Joint axis and position estimation from inertial measurement data by exploiting kinematic constraints” —— 论文推导 文章目录 I. 论文回顾II. 铰接关节的约束1. 铰接关节约束的原理2. 铰接关节约束的梯度3. 铰接关节约…

oracle ORA-27054报错处理

现象 在oracle执行expdp&#xff0c;rman备份&#xff0c;xtts的时候,由于没有足够的本地空间&#xff0c;只能使用到NFS的文件系统但有时候会出现如下报错 ORA-27054: NFS file system where the file is created or resides is not mounted with correct options根据提示信…