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

news/2025/2/9 4:07:15 标签: linux, 运维, 服务器

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;
}


http://www.niftyadmin.cn/n/5845500.html

相关文章

GitPuk快速安装配置教程(入门级)

GitPuk是一款国产开源免费的代码管理工具&#xff0c;工具简洁易用&#xff0c;开源免费&#xff0c;本文将讲解如何快速安装和配置GitPuk&#xff0c;以快速入门上手。 1、安装 支持 Windows、Mac、Linux、docker 等操作系统。 1.1 Linux安装&#xfeff; 以下以Centos7安装…

unity学习31:Video Player 视频播放相关基础

目录 1 新增Video Player的 component 2 导入视频到Asset里 3 拖入到 video player的 video clip里去即可 4 渲染模式 4.1 多种渲染模式 4.2 如果选择 Render Texture模式 4.3 然后把Render Texture 拖到游戏里的 gameObject上面 5 在UI上显示 5.1 创建UI 5.2 在UI上…

深入解析:Jsoup 库的多功能应用场景

Jsoup 是一个强大的 Java 库&#xff0c;主要用于解析和操作 HTML 文档。它不仅广泛应用于网络爬虫和数据抓取&#xff0c;还在网页内容分析、数据清洗与处理、自动化测试等多个领域有着广泛的应用。本文将详细介绍 Jsoup 库的多种用途&#xff0c;并提供具体的代码示例。 一、…

Fiddler Classic(HTTP流量代理+半汉化)

目录 一、关于Fiddler (一) Fiddler Classic (二) Fiddler Everywhere (三) Fiddler Everywhere Reporter (四) FiddlerCore (五) 总结 二、 软件安全性 1. 软件安装包 2. 软件汉化dll 三、安装与半汉化 1. 正常打开安装包点击下一步安装即可&#xff0c;安装路径自…

【提示词工程】探索大语言模型的参数设置:优化提示词交互的技巧

在与大语言模型(Large Language Model, LLM)进行交互时,提示词的设计和参数设置直接影响生成内容的质量和效果。无论是通过 API 调用还是直接使用模型,掌握模型的参数配置方法都至关重要。本文将为您详细解析常见的参数设置及其应用场景,帮助您更高效地利用大语言模型。 …

【重新认识C语言----结构体篇】

目录 -----------------------------------------begin------------------------------------- 引言 1. 结构体的基本概念 1.1 为什么需要结构体&#xff1f; 1.2 结构体的定义 2. 结构体变量的声明与初始化 2.1 声明结构体变量 2.2 初始化结构体变量 3. 结构体成员的访…

神经网络常见激活函数 4-LeakyReLU函数

LeakyReLU LeakyReLU&#xff1a; Leaky Rectified Linear Unit 函数导函数 LeakyReLU函数 L e a k y R e L U { x x > 0 p x x < 0 p ∈ ( 0 , 1 ) \rm Leaky{ReLU} \left\{ \begin{array}{} x \quad x>0 \\ px \quad x<0 \end{array} \right. \quad p \in …

LeetCode 每日一题 2025/1/27-2025/2/2

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 1/27 45. 跳跃游戏 II1/28 119. 杨辉三角 II1/29 219. 存在重复元素 II1/30 350. 两个数组的交集 II1/31 541. 反转字符串 II2/1 81. 搜索旋转排序数组 II2/2 598. 区间加法…