linux输入子系统(input subsystem)之按键输入和LED控制
实验现象:在控制台打印按键值,并且通过按键控制相应的LED亮灭。
1.代码
input_subsys_drv.c
#include <linux/module.h>
#include <linux/version.h> #include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h> #include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h> struct pin_desc{
int irq;
char *name;
unsigned int pin;
unsigned int key_val;
}; struct pin_desc pins_desc[] = {
{IRQ_EINT0, "S2", S3C2410_GPF0, KEY_L},
{IRQ_EINT2, "S3", S3C2410_GPF2, KEY_S},
{IRQ_EINT11, "S4", S3C2410_GPG3, KEY_ENTER},
{IRQ_EINT19, "S5", S3C2410_GPG11, KEY_LEFTSHIFT},
}; static struct input_dev *input_subsys_dev;
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer; static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* [cgw]: 按键IO发生边沿中断时重新设置定时间隔
* 用于按键消抖
*/
irq_pd = (struct pin_desc *)dev_id;
buttons_timer.data = irq_pd->pin;
mod_timer(&buttons_timer, jiffies+HZ/);
return IRQ_RETVAL(IRQ_HANDLED);
} static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval; if (!pindesc)
return; /* [cgw]: 获取按键IO状态 */
pinval = s3c2410_gpio_getpin((unsigned int)data); /* [cgw]: 根据按键IO状态上报按键事件 */
if (pinval)
{
/* [cgw]: 上报按键弹起 */
input_report_key(input_subsys_dev, pindesc->key_val, );
//input_sync(input_subsys_dev);
}
else
{
/* [cgw]: 上报按键按下 */
input_report_key(input_subsys_dev, pindesc->key_val, );
//input_sync(input_subsys_dev);
} //printk("timer occur!\n");
} static int led_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
printk("led event!\n");
printk("value: 0x%x\n", value); /* [cgw]: 根据应用程序下发的LED控制事件
* 亮灭LED
*/
//if (code == SND_BELL) {
if (code == LED_MUTE) {
if (value == 0xAA) {
/* [cgw]: 点亮 */
s3c2410_gpio_setpin(S3C2410_GPF4, );
} else if (value == 0xEE) {
/* [cgw]: 熄灭 */
s3c2410_gpio_setpin(S3C2410_GPF4, );
} return ;
} return -;
} int input_subsys_open(struct input_dev *dev)
{
int i, retval; /* [cgw]: 设置按键IO为中断输入 */
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0);
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_EINT11);
s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19); /* [cgw]: 设置LED IO为输出,初始为熄灭LED */
s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF4, ); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, ); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, ); /* [cgw]: 为按键IO分配中断线 */
for (i = ; i < ; i++)
{
retval = request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
} printk("input subsys open!\n"); return ;
} static int input_subsys_init(void)
{
/* [cgw]: 分配一个输入设备 */
input_subsys_dev = input_allocate_device();
input_subsys_dev->name = "input_subsys_dev"; /* [cgw]: 设置支持的事件类型 */
set_bit(EV_KEY, input_subsys_dev->evbit);
//set_bit(EV_REP, input_subsys_dev->evbit); set_bit(EV_LED, input_subsys_dev->evbit);
//set_bit(EV_SND, input_subsys_dev->evbit); /* [cgw]: 设置支持的事件码 */
set_bit(KEY_L, input_subsys_dev->keybit);
set_bit(KEY_S, input_subsys_dev->keybit);
set_bit(KEY_ENTER, input_subsys_dev->keybit);
set_bit(KEY_LEFTSHIFT, input_subsys_dev->keybit); set_bit(LED_MUTE, input_subsys_dev->ledbit);
//set_bit(SND_BELL, input_subsys_dev->sndbit); /* [cgw]: 分配输入设备的open方法,用户操作open(/dev/xxx, ...)时调用 */
input_subsys_dev->open = input_subsys_open;
/* [cgw]: 分配输入设备的event方法,用户在应用程序write()时 */
input_subsys_dev->event = led_event; /* [cgw]: 注册输入设备 */
input_register_device(input_subsys_dev); /* [cgw]: 初始化定时器,用于按键消抖 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer); printk("input subsys init!\n"); return ;
} static void input_subsys_exit(void)
{
int i; /* [cgw]: 释放按键IO中断 */
for (i = ; i < ; i++)
{
free_irq(pins_desc[i].irq, &pins_desc[i]);
} /* [cgw]: 删除定时器 */
del_timer(&buttons_timer);
/* [cgw]: 注销输入设备 */
input_unregister_device(input_subsys_dev);
/* [cgw]: 释放输入设备内存空间 */
input_free_device(input_subsys_dev);
} module_init(input_subsys_init); module_exit(input_subsys_exit); MODULE_LICENSE("GPL");
input_subsys_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h> #include <linux/input.h> int fd; void my_signal_fun(int signum)
{
struct input_event buttons_event, leds_event; /* [cgw]: 异步通知产生时返回的数据 */
read(fd, &buttons_event, sizeof(struct input_event)); /* [cgw]: 打印事件类型,事件码,事件值 */
printf("type: 0x%x code: 0x%x value: 0x%x\n",
buttons_event.type,
buttons_event.code,
buttons_event.value); /* [cgw]: 返回的是KEY_L或KEY_S值 */
if (buttons_event.code == KEY_L || buttons_event.code == KEY_S) {
/* [cgw]: 按键弹起 */
if (buttons_event.value == ) { /* [cgw]: 构造一个EV_LED事件 */ //leds_event.type = EV_SND;
leds_event.type = EV_LED;
//leds_event.code = SND_BELL;
leds_event.code = LED_MUTE; /* [cgw]: KEY_L和KEY_S控制LED的亮灭 */
if (buttons_event.code == KEY_L) {
leds_event.value = 0xAA;
} else if (buttons_event.code == KEY_S) {
leds_event.value = 0xEE;
} /* [cgw]: 发送LED控制事件 */
write(fd, &leds_event, sizeof(struct input_event)); printf("led write!\n");
}
}
} int main(int argc, char **argv)
{
int Oflags; /* [cgw]: 设置需要处理的信号SIGIO,即输入文件会请求一个SIGIO
* 信号,当有新数据到来这个信号会发给filp->f_owner进程
*/
signal(SIGIO, my_signal_fun); fd = open("/dev/event1", O_RDWR | O_NONBLOCK); //printf("fd = 0x%x\n", fd); if (fd < )
{
printf("can't open!\n");
} /* [cgw]: 根据文件标识符fd,设置能够获得这个文件的进程(owner)
* getpid()获得当前进程ID
*/
fcntl(fd, F_SETOWN, getpid()); /* [cgw]: 获得file->f_flags标志 */
Oflags = fcntl(fd, F_GETFL); /* [cgw]: 置位FASYNC使能异步通知 */
fcntl(fd, F_SETFL, Oflags | FASYNC); while ()
{
/* [cgw]: 休眠 */
sleep();
} return ;
}
makefile
KERN_DIR = /work/system/linux-2.6.22.6 all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += input_subsys_drv.o
2. 实验
2.1
安装驱动程序:
insmod input_subsys_drv.ko
# insmod input_subsys_drv.ko
input: input_subsys_dev as /class/input/input1
input subsys open!
input subsys init!
运行应用程序
./input_subsys_test
# ./input_subsys_test
type: 0x1 code: 0x26 value: 0x1
type: 0x1 code: 0x26 value: 0x0
led event!
value: 0xaa
led write!
type: 0x11 code: 0x7 value: 0xaa
type: 0x1 code: 0x1f value: 0x1
type: 0x1 code: 0x1f value: 0x0
led event!
value: 0xee
led write!
type: 0x11 code: 0x7 value: 0xee
3. 现象分析
按一下按键KEY_L,终端输出:
type: 0x1 code: 0x26 value: 0x1 //按键按下
type: 0x1 code: 0x26 value: 0x0 //按键弹起
led event! //应用程序操作write, 发送LED控制事件,调用led_event()
value: 0xaa //读到的LED亮的命令
led write! //返回应用程序继执行
type: 0x11 code: 0x7 value: 0xaa //因为应用程序发送了事件给驱动程序,驱动把这个事件作为一个输入事件(相当于按键输入事件),同样通过异步通知反馈到应用程序
The end!
linux输入子系统(input subsystem)之按键输入和LED控制的更多相关文章
- Linux输入子系统(Input Subsystem)
Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析 http://b ...
- 10. linux输入子系统/input 设备【转】
转自:https://www.cnblogs.com/crmn/articles/6696819.html 按键事件信息之上报绝对事件信息之上报相对事件信息之上报功能键驱动编写多点触控事件的上报 只产 ...
- Linux 输入子系统 input
一.输入子系统 针对输入设备设计:触摸屏.键盘.按键.传感器.鼠标...... 二.每种设备都属于字符设备驱动,程序的写法步骤也相同 1.实现入口函数 xxx_init() 和卸载函数 xxx_exi ...
- Linux输入子系统(转)
Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中 ...
- linux输入子系统(6)-input子系统介绍及结构图
注:本系列转自: http://www.ourunix.org/post/290.html input子系统介绍 输入设备(如按键,键盘,触摸屏,鼠标,蜂鸣器等)是典型的字符设备,其一 ...
- linux输入子系统
linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...
- Linux 混杂设备、外部中断和输入子系统
混杂设备也是一种字符设备,主设备号固定为10.相对于普通字符设备驱动,它不需要自己去生成设备文件. 1.声明使用的头文件 #include <linux/miscdevice.h> 2.定 ...
- Linux 输入子系统
Technorati 标签: Kernel 输入子系统 Input 在Linux中,输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理,是底层在按键.触摸时,触发一个 ...
- 12.Linux之输入子系统分析(详解)
版权声明:本文为博主原创文章,转载请标注出处: 在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时 ...
随机推荐
- js基本类型和引用类型
先来两个例题 //1. var person; person.age=10; console.log(person.age) //undefined person是字符串而不是对象,没有属性 //2. ...
- HTML5权威指南--标签新变化,文件API,拖放API(简要学习笔记一)
1.标签元素更加语义化 2.内容类型仍然为“text/html” 扩展符仍然为html或者htm. <1>DOCTYPE 声明<!DOCTYPE html>就可 ...
- CRL快速开发框架升级到3.1
CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性) 无需第三方工具生成代理类 ...
- C#字符串的倒序输出
介绍 在本文中,我将演示如何将字符串的单词倒序输出.在这里我不是要将“John” 这样的字符串倒序为成“nhoJ”,.这是不一样的,因为它完全倒序了整个字符串.而以下代码将教你如何将“你 好 我是 缇 ...
- Effective前端4:尽可能地使用伪元素
伪元素是一个好东西,但是很多人都没怎么用,因为他们觉得伪元素太诡异了.其实使用伪元素有很多好处,最大的好处是它可以简化页面的html标签,同时用起来也很方便,善于使用伪元素可以让你的页面更加地简洁优雅 ...
- 产品前端重构(TypeScript、MVC框架设计)
最近两周完成了对公司某一产品的前端重构,本文记录重构的主要思路及相关的设计内容. 公司期望把某一管理类信息系统从项目代码中抽取.重构为一个可复用的产品.该系统的前端是基于 ExtJs 5 进行构造的, ...
- 利用javascript跨域访问cookie之广告推广
在上一篇<说一说javascript跨域和jsonp>中,利用JSONP进行了跨域的数据访问,利用JS本身的跨域能力在远端生成HTML结构的方式完成了一个小广告. 在实际应用中, 跨域使用 ...
- C++ tinyXML使用
tinyXML下载: http://sourceforge.net/projects/tinyxml/ 加载到项目: 这六个文件添加到你的c++工程中,分别是tinystr.h.tinystr.cpp ...
- asp.net获取数据库连接字符串
1.添加引用 using System.Configuration; 2.代码 string strConnectionString=ConfigurationManager.AppSettings[ ...
- 记录一次bug解决过程:规范变量名称和mybatis的使用以及代码优化
一.总结 Mybatis中当parameterType为基本数据类型的时候,统一采用_parameter来代替基本数据类型变量. Mybatis中resultMap返回一个对象,resultType返 ...