天天看點

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

/**
*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擡起

繼續閱讀