Linux input输入子系统

输入设备(按键、键盘、触摸屏、鼠标)是典型的字符设备,工作机理是底层
在按键、触摸等动作发生时产生一个中断(或驱动timer定时查询),然后CPU
通过SPI、I2C或外部存储器总线读取键值,坐标等数据。
输入核心层提供了底层输入设备驱动程序所需的API,如分配/释放一个输入设备
struct input_dev *input_allocate_device(void);
void input_free_device(struct input_dev *dev);
input_allocate_device()返回的是1个input_dev的结构体,此结构体用于表征1个输入设备
注册/注销输入设备用的接口
input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
报告输入事件的接口,指定type, code, value
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);


input通用数据结构
1. input_dev是input设备基本的设备结构,每个input驱动程序必须分配初始化这样一个结构
include/linux/input.h
struct input_dev {
const char *name; //设备名称
const char *phys;//设备在系统的物理路径
const char *uniq;//统一的ID
struct input_id id;//设备ID


unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//事件
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//按键
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//相对设备
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//绝对设备
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];//杂项设备
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];//LED
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];//声音设备
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];//强制反馈设备
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];//开关设备


unsigned int keycodemax;//按键码的最大值
unsigned int keycodesize;//按键码的大小
void *keycode;//按键码
int (*setkeycode)(struct input_dev *dev,
 unsigned int scancode, unsigned int keycode);
int (*getkeycode)(struct input_dev *dev,
 unsigned int scancode, unsigned int *keycode);


struct ff_device *ff;


unsigned int repeat_key;
struct timer_list timer;


int sync;


int abs[ABS_CNT];
int rep[REP_MAX + 1];


unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];


int absmax[ABS_CNT];
int absmin[ABS_CNT];
int absfuzz[ABS_CNT];
int absflat[ABS_CNT];
int absres[ABS_CNT];


int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);


struct input_handle *grab;


spinlock_t event_lock;
struct mutex mutex;


unsigned int users;
bool going_away;


struct device dev;


struct list_headh_list;
struct list_headnode;
};


2. input_event 驱动层向input子系统核心报告事件的函数。
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value);
 
不同设备内容的报告均是通过input_event函数来完成的,选择使用了不同参数而已
@type:类型(EV_KEY键盘,EV_REL相对,EV_ABS绝对)
@code:编码(事件代码,如键盘代码)
@value:值(EV_KEY当按键按下时值为1,松开时值为0,如果事件为EV_REL,value的正
数值和负数值分别代表两个不同的方向)


键盘keyboard属于按键设备EV_KEY
轨迹属于相对设备EV_REL
触模屏属于绝对设备EV_ABS


3. 分配并初始化input_dev
input_allocate_device()


4. 向内核注册一个input设备
input_register_device()


5. input驱动流程
1)定义input设备结构
struct input_dev *input;
2)分配并初始化input_dev接构
input = input_allocate_device();
input->name = "gpio-keys";
input->phys = "gpio-keys/input0";
input->id.bustype = BUS_HOST;
input->id.vendor  = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
3) 记录本设备对于哪些事件感兴趣(对其进行处理)input_set_capability();
定义/drivers/input/input.c
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
input_set_capability(input, EV_KEY, 101);


4)向内核注册一个input设备
input_register_device(input);


5)记录按键状态
int state = (gpio_get_value((S3C64XX_GPN(0)) ? 1 : 0) ^ 1 ;


6)汇报输入事件
input_event(input, EV_KEY, 101, !!state);


7)等待输入事件处理完成
input_sync(input);


8)注销一个input设备
input_unregister_device(input);


/************************input gpio_keys 例子********************/

/**
*interrupt key kernel 2.6.35.7
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/timer.h>
#define KEY_MAJOR 233
#define DEVICE_NAME "gpio_key"

struct gpio_button_data {
	struct input_dev *input;
	struct timer_list timer;
	struct work_struct work;
	
} *data;


static void gpio_keys_report_event(void)
{
	
	struct input_dev *input = data->input;
	//记录按键状态
	int state = (gpio_get_value(S3C64XX_GPN(0)) ? 1 : 0) ^ 1 ;
	//汇报输入事件
	unsigned int type = EV_KEY;
	int code = 139;
	printk("type=%d, code=%d, state=%d\n", type, code, state);
	/**5. 汇报事件*/
	input_event(input, type, code, !!state);
	//等待输入事件完成
	input_sync(input);
	
}
static void gpio_key_work_func(struct work_struct *work)
{
	//struct gpio_button_data *data =
			//	container_of(work, struct gpio_button_data, work);
	
	gpio_keys_report_event();
	
}
static void gpio_keys_timer(unsigned long _data)
{
	schedule_work(&data->work);
}

static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	 
	mod_timer(&data->timer, jiffies+msecs_to_jiffies(0));
	schedule_work(&data->work);
	return IRQ_HANDLED;
}

static int keys_init(void)
{
	int ret = 0;
	int irq;//中断号
	unsigned long irqflags;
	setup_timer(&data->timer, gpio_keys_timer, (unsigned long)data);
	add_timer(&data->timer);
	//申请管脚
	gpio_request(S3C64XX_GPN(0), "HOME");
	//设置为输入
	gpio_direction_input(S3C64XX_GPN(0));
	
	irq = gpio_to_irq(S3C64XX_GPN(0));
	printk("the gpio_key irq is [%d]\n ", irq);
	
	irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
	
	ret = request_irq(irq, gpio_key_isr, irqflags, "HOME", NULL);
	if (ret) {
		printk("can't get gpio irq\n");
		return -1;
	}
	
	return 0;
}


static int gpio_keys_probe(void)
{
	int ret = 0;
	
	//struct gpio_button_data *data;
	/**1. 定义input_dev 结构*/
	struct input_dev *input;
	/**2. 分配并初始化结构*/
	input = input_allocate_device();
	
	input->name = "gpio-key";
	input->phys = "gpio-key/input0";
	input->id.bustype = BUS_HOST;
	input->id.vendor  = 0x0001;
	input->id.product = 0x0001;
	input->id.version = 0x0100;
	
	data = kzalloc(sizeof(struct gpio_button_data), GFP_KERNEL);
	data->input = input;
	
	keys_init();
	/**3. 记录感兴趣的事件*/
	input_set_capability(input, EV_KEY, 139);
	
	/**4. 向内核注册一个input设备*/
	ret = input_register_device(input);
	if(ret) {
		printk("unable to register input device\n");
		return -1;
	}
	
	return 0;
}



int key_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{

	
	return 0;
}

static const struct file_operations key_ops = {
	.owner = THIS_MODULE,
	.ioctl = key_ioctl,
};

static int __init gpio_keys_init(void)
{
	int ret = 0;
	ret = register_chrdev(KEY_MAJOR, DEVICE_NAME, &key_ops);
	
	if (ret < 0) {
		printk("can't register gpio_keys_number\n");
		return -1;
	}

	gpio_keys_probe();
	INIT_WORK(&data->work, gpio_key_work_func);
	
	
	
	printk("gpio_keys init\n");
	return 0;
}

static void __exit gpio_keys_exit(void)
{
	unregister_chrdev(KEY_MAJOR, DEVICE_NAME);
}

module_init(gpio_keys_init);
module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");



在串口测试

/ # getevent

add device 2: /dev/input/event0
  name:     "gpio-key"
could not get driver version for /dev/input/mice, Not a typewriter
type=1, code=139, state=1
type=1, code=139, state=1
/dev/input/event0: 0001 008b 00000001
/dev/input/event0: 0000 0000 00000000

0001表示EV_KEY,008b是按键扫描码,1按下,0抬起















 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值