linux输入子系统之按键驱动
上一节文章链接:http://blog.csdn.net/lwj103862095/article/details/17733993
这一节,我们来以输入子系统的框架来写一个按键驱动。
问:怎么写符合输入子系统框架的驱动程序?
答:
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如在中断服务程序里上报事件
问:如何分配input_dev结构体?
答:使用input_allocate_device函数
input_dev结构体的重要成员
plain?
- struct input_dev {
- const char *name;
- const char *phys;
- const char *uniq;
- struct input_id id;
- unsigned long evbit[NBITS(EV_MAX)]; // 表示能产生哪类事件
- unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
- unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
- unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
- unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
- unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
- unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
- unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
- ...
- }
问:第二步的设置,应该怎么设置,应该设置什么?
答:举例,在此按键驱动里
plain?
- /* 2.设置 */
- /* 2.1 设置按键能产生哪类事件 */
- set_bit(EV_KEY,buttons_dev->evbit); //按键类事件
- set_bit(EV_REP,buttons_dev->evbit); //重复类事件,比如按下按键L能重复打印L;按下后,能重复帮你上报事件(重复,说明肯定用到定时器)
- /* 2.2 设置能产生这类操作的哪些事件 */
- set_bit(KEY_L,buttons_dev->keybit);
- set_bit(KEY_S,buttons_dev->keybit);
- set_bit(KEY_ENTER,buttons_dev->keybit);
- set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
问:有哪些类呢?
答:在input.h里有以下类
plain?
- #define EV_SYN 0x00 //同步类
- #define EV_KEY 0x01 //按键类
- #define EV_REL 0x02 //相对位移类
- #define EV_ABS 0x03 //绝对位移类
- #define EV_MSC 0x04
- #define EV_SW 0x05
- #define EV_LED 0x11
- #define EV_SND 0x12 //声音类
- #define EV_REP 0x14 //重复类
- #define EV_FF 0x15
- #define EV_PWR 0x16
- #define EV_FF_STATUS 0x17
- #define EV_MAX 0x1f
- #define EV_CNT (EV_MAX+1)
问:如何注册?
答:使用input_register_device(struct input_dev *dev)函数来注册
问:此按键驱动的硬件操作包括哪些操作?
答:申请定时器、申请中断操作
驱动源码:
plain?
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/irq.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <linux/module.h>
- #include <linux/device.h> //class_create
- #include <mach/regs-gpio.h> //S3C2410_GPF1
- //#include <asm/arch/regs-gpio.h>
- #include <mach/hardware.h>
- //#include <asm/hardware.h>
- #include <linux/interrupt.h> //wait_event_interruptible
- #include <linux/poll.h> //poll
- #include <linux/fcntl.h>
- #include <linux/input.h>
- static struct pin_desc{
- int irq;
- unsigned char *name;
- unsigned int pin;
- unsigned int key_val;
- };
- static struct pin_desc pins_desc[4] = {
- {IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
- {IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
- {IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
- {IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
- };
- static struct pin_desc *irq_pd;
- static struct input_dev *buttons_dev;
- static struct timer_list buttons_timer;
- /* 用户中断处理函数 */
- static irqreturn_t buttons_irq(int irq, void *dev_id)
- {
- irq_pd = (struct pin_desc *)dev_id;
- /* 修改定时器定时时间,定时10ms,即10秒后启动定时器
- * HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
- * 这里HZ/100即定时10ms
- */
- mod_timer(&buttons_timer, jiffies + (HZ /100));
- return IRQ_HANDLED;
- }
- /* 定时器处理函数 */
- static void buttons_timer_function(unsigned long data)
- {
- struct pin_desc *pindesc = irq_pd;
- unsigned int pinval;
- pinval = s3c2410_gpio_getpin(pindesc->pin);
- if(pinval)
- {
- /* 松开 最后一个参数: 0-松开, 1-按下 */
- input_event(buttons_dev,EV_KEY,pindesc->key_val,0);
- input_sync(buttons_dev);
- }
- else
- {
- /* 按下 */
- input_event(buttons_dev,EV_KEY,pindesc->key_val,1);
- input_sync(buttons_dev);
- }
- }
- /* 驱动入口函数 */
- static int buttons_input_init(void)
- {
- int i;
- /* 1.分配一个input_dev结构体 */
- buttons_dev = input_allocate_device();
- /* 2.设置 */
- /* 2.1 设置按键能产生哪类事件 */
- set_bit(EV_KEY,buttons_dev->evbit);
- set_bit(EV_REP,buttons_dev->evbit);
- /* 2.2 设置能产生这类操作的哪些事件 */
- set_bit(KEY_L,buttons_dev->keybit);
- set_bit(KEY_S,buttons_dev->keybit);
- set_bit(KEY_ENTER,buttons_dev->keybit);
- set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
- /* 3.注册 */
- input_register_device(buttons_dev);
- /* 4.硬件相关的设置 */
- /* 4.1 定时器相关的操作 */
- init_timer(&buttons_timer);
- buttons_timer.function = buttons_timer_function;
- add_timer(&buttons_timer);
- /* 4.2 申请中断 */
- for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
- {
- request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
- }
- return 0;
- }
- /* 驱动出口函数 */
- static void buttons_input_exit(void)
- {
- int i;
- for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
- {
- free_irq(pins_desc[i].irq, &pins_desc[i]);
- }
- del_timer(&buttons_timer);
- input_unregister_device(buttons_dev);
- input_free_device(buttons_dev);
- }
- module_init(buttons_input_init); //用于修饰入口函数
- module_exit(buttons_input_exit); //用于修饰出口函数
- MODULE_AUTHOR("LWJ");
- MODULE_DESCRIPTION("Just for Demon");
- MODULE_LICENSE("GPL"); //遵循GPL协议
测试步骤方法一:
plain?
- [WJ2440]# ls
- Qt first_test second_test
- TQLedtest fourth_drv.ko sixth_drv.ko
- app_test fourth_test sixth_test
- bin home sixthdrvtest
- buttons_all_drv.ko lib sys
- buttons_all_test linuxrc third_drv.ko
- buttons_input.ko mnt third_test
- dev opt tmp
- driver_test proc udisk
- etc root usr
- fifth_drv.ko sbin var
- fifth_test sddisk web
- first_drv.ko second_drv.ko
- [WJ2440]# ls /dev/event* -l
- crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
- [WJ2440]# insmod buttons_input.ko
- input: Unspecified device as /devices/virtual/input/input1
- [WJ2440]# ls /dev/event* -l
- crw-rw---- 1 root root 13, 64 Jan 2 06:04 /dev/event0
- crw-rw---- 1 root root 13, 65 Jan 2 06:06 /dev/event1
- [WJ2440]# cat /dev/tty1
- [WJ2440]# cat /dev/tty1
- ls
- ls
输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls
2. 如果没有启动QT:
cat /dev/tty1
按:s2,s3,s4
就可以得到ls
或者:
exec 0</dev/tty1 (把标准输入改为tty1)
然后可以使用按键来输入
3. 如果已经启动了QT: ( 因为启动了qt之后,串口返回的是乱码)
可以点开记事本
然后按:s2,s3,s4
测试步骤方法二、
plain?
- [WJ2440]# hexdump /dev/event1
- 0000000 b738 495d 8456 0007 0001 0026 0001 0000
- 0000010 b738 495d 846f 0007 0000 0000 0000 0000
- 0000020 b738 495d 2fb8 000a 0001 0026 0000 0000
- 0000030 b738 495d 2fc7 000a 0000 0000 0000 0000
分析:
hexdump /dev/event1 (16进制显示:这句话的意思是 先open(/dev/event1), 然后再read(), 读之后把里面的数据当做16进制显示出来)
秒 微秒 类 code value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000
plain?
- struct input_event {
- struct timeval time; //时间
- __u16 type; //类
- __u16 code; //类下事件的值
- __s32 value; //0-松开, 1-按下,2-重复
- };
- struct timeval {
- __kernel_time_t tv_sec; //秒
- __kernel_suseconds_t tv_usec; //微秒
- };
linux输入子系统之按键驱动的更多相关文章
- Linux输入子系统(一) _驱动编码
输入设备都有共性:中断驱动+字符IO,基于分层的思想,Linux内核将这些设备的公有的部分提取出来,基于cdev提供接口,设计了输入子系统,所有使用输入子系统构建的设备都使用主设备号13,同时输入子系 ...
- linux输入子系统简述【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/7678035 1,linux输入子系统简述 其实驱动这部分大多还是转载别人的,linux ...
- linux-2.6.38 input子系统(用输入子系统实现按键操作)
一.设备驱动程序 在上一篇随笔中已经分析,linux输入子系统分为设备驱动层.核心层和事件层.要利用linux内核中自带的输入子系统实现一个某个设备的操作,我们一般只需要完成驱动层的程序即可,核心层和 ...
- linux输入子系统(input subsystem)之evdev.c事件处理过程
1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...
- Linux输入子系统(转)
Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中 ...
- Linux输入子系统框架分析(1)
在Linux下的输入设备键盘.触摸屏.鼠标等都能够用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层.事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备 ...
- Linux输入子系统详解
input输入子系统框架 linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...
- linux输入子系统
linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...
- linux输入子系统概念介绍
在此文章之前,我们讲解的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥.非阻塞.定时器去抖动. 上一节文章链接:http://blo ...
随机推荐
- python学习笔记(SMTP邮件发送)
想着给框架添加邮件发送功能.所以整理下python下邮件发送功能 首先python是支持邮件的发送.内置smtp库.支持发送纯文本.HTML及添加附件的邮件 之后是邮箱.像163.qq.新浪等邮箱默认 ...
- mysql学习笔记(window下简单使用+Navict)
之前安装过mysql.最近刚好要重新翻出来看看 发现又忘记了那些命令.还是要百度.所以不如自己整理下 尽管网上有很多相关的介绍.当时想对的不如自己整理出来的舒服 首先是下载安装.网上有很多就不一一罗列 ...
- Java反射深入浅出
在JVM中对一个类实例的创建,有两种方式,一种是编译时,一种是运行时.两种方式在开发过程中都是十分重要的.在Java中无时无刻无处不在的Java对象,实例化的过程也就变得尤为引人瞩目.我们经常用new ...
- 九 web爬虫讲解2—urllib库爬虫—实战爬取搜狗微信公众号—抓包软件安装Fiddler4讲解
封装模块 #!/usr/bin/env python # -*- coding: utf-8 -*- import urllib from urllib import request import j ...
- 最大流EK算法/DINIC算法学习
之前一直觉得很难,没学过网络流,毕竟是基础知识现在重新来看. 定义一下网络流问题,就是在一幅有向图中,每条边有两个属性,一个是cap表示容量,一个是flow 表示流过的流量.我们要求解的问题就是从S点 ...
- JSON.parse()和JSON.stringify()以及stringify()字符串格式化
1. parse用于从一个字符串中解析出json对象,如var str = '{"name":"huangxiaojian","age":& ...
- 你不知道的sticky
position:sticky,Chrome新版本已经做了支持.sticky的中文翻译是“粘性的”,position:sticky表现也符合这个粘性的表现.基本上,可以看出是position:rela ...
- Go开发Struct转换成map两种方式比较
最近做Go开发的时候接触到了一个新的orm第三方框架gorose,在使用的过程中,发现没有类似beego进行直接对struct结构进行操作的方法,有部分API是通过map进行数据库相关操作,那么就需要 ...
- Python判断unicode是汉字,数字,英文,或者其他字符
功能: 判断unicode是否是汉字,数字,英文,或者是否是(汉字,数字和英文字符之外的)其他字符. 全角.半角符号相互转换. 全角.半角? 全角--指一个字符占用两个标准字符位置. 汉字字符和规定了 ...
- HTTP 方法:GET与 POST
什么是 HTTP? 超文本传输协议(HTTP)的设计目的是保证客户机与服务器之间的通信. HTTP 的工作方式是客户机与服务器之间的请求-应答协议. web 浏览器可能是客户端,而计算机上的网络应用程 ...