您的位置:首页 > 运维架构 > Linux

Linux input输入子系统

2015-09-02 13:42 736 查看
输入设备(按键、键盘、触摸屏、鼠标)是典型的字符设备,工作机理是底层

在按键、触摸等动作发生时产生一个中断(或驱动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 例子********************/

[csharp] view
plaincopy

/**

*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抬起
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: