linux input设备驱动

linux input设备驱动_第1张图片

一. 输入设备结构体

     1. input_dev 输入设备

struct input_dev {
	const char *name;		//设备名
	const char *phys;		//设备系统层的物理路径
	const char *uniq;		//
	struct input_id 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 hint_events_per_packet;
	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);	//获取键盘码
	int (*setkeycode_new)(struct input_dev *dev,const struct input_keymap_entry *ke,unsigned int *old_keycode);	
	int (*getkeycode_new)(struct input_dev *dev,struct input_keymap_entry *ke);

	struct ff_device *ff;	//强制反馈设备
	unsigned int repeat_key;	//重复按键标志位
	struct timer_list timer;	//定时器
	int rep[REP_CNT];		//重复次数
	struct input_mt_slot *mt;
	int mtsize;
	int slot;
	struct input_absinfo *absinfo;
	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 (*open)(struct input_dev *dev);		//open方法
	void (*close)(struct input_dev *dev);	//close方法
	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 __rcu *grab;
	spinlock_t event_lock;
	struct mutex mutex;
	unsigned int users;
	bool going_away;
	bool sync;
	struct device dev;		//设备文件
	struct list_head	h_list;	//input_handler处理器链表头
	struct list_head	node;	//input_device设备链表头
};

      2. input_handler 输入处理器

struct input_handler {
	void *private;	//私有数据
	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);	//事件处理
	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);	//过滤器
	bool (*match)(struct input_handler *handler, struct input_dev *dev);	//设备匹配
	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);	//设备连接
	void (*disconnect)(struct input_handle *handle);	//设备断开连接
	void (*start)(struct input_handle *handle);
	const struct file_operations *fops;	//输入操作函数集
	int minor;	//次设备号
	const char *name;	//设备名
	const struct input_device_id *id_table;	//输入设备 id表
	struct list_head	h_list;	//input_handler处理器链表头
	struct list_head	node;	//input_device设备链表头
};

 

二. 输入系统初始化

     1 input_init

static int __init input_init(void)
{
	int err;

	err = class_register(&input_class);	//注册类 创建"/sys/input" 
	if (err) {
		printk(KERN_ERR "input: unable to register input_dev class\n");
		return err;
	}

	err = input_proc_init();	//初始化"/proc/bus/input"接口
	if (err)
		goto fail1;

	err = register_chrdev(INPUT_MAJOR, "input", &input_fops);	//注册所有输入字符设备,并捆绑input_fops
	if (err) {
		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
		goto fail2;
	}

	return 0;

 fail2:	input_proc_exit();
 fail1:	class_unregister(&input_class);
	return err;
}

     2. /proc 接口

     2.1 创建/proc/bus/input下的文件

static int __init input_proc_init(void)
{
	struct proc_dir_entry *entry;

	proc_bus_input_dir = proc_mkdir("bus/input", NULL);	//创建"/proc/bus/input"
	if (!proc_bus_input_dir)
		return -ENOMEM;

	entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);	//创建"/proc/bus/input/devices"
	if (!entry)
		goto fail1;

	entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops);	//创建"/proc/bus/input/handlers"
	if (!entry)
		goto fail2;

	return 0;

 fail2:	remove_proc_entry("devices", proc_bus_input_dir);
 fail1: remove_proc_entry("bus/input", NULL);
	return -ENOMEM;
}

     2.2 devices文件 

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

    2.2.1 限于篇幅及省略啰嗦

这里当我们去cat /proc/bus/input/devices时候,会调用input_proc_devices_open函数,接着调用seq_open(file, &input_devices_seq_ops),捆绑了input_devices_seq_ops操作函数集,

其seq_operations函数集中声明了.show方法为input_devices_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,

接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

     2.2.2 input_devices_seq_show

static int input_devices_seq_show(struct seq_file *seq, void *v)
{
	struct input_dev *dev = container_of(v, struct input_dev, node);	//获取到输入设备结构体
	const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);	//获取在/sys下的路径
	struct input_handle *handle;

	seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
	//打印I:总线类型,厂商id,产品id,版本号 
	seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");	//打印N:输入设备名
	seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");	//打印P:phys
	seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");	//打印S:sysfs文件系统下的路径
	seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");	//打印U:uniq
	seq_printf(seq, "H: Handlers=");	//打印H:input_handler处理器名

	list_for_each_entry(handle, &dev->h_list, d_node)	//遍历处理器链表
		seq_printf(seq, "%s ", handle->name);
	seq_putc(seq, '\n');

	input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);	//打印EV:事件类型位图
	if (test_bit(EV_KEY, dev->evbit))					//打印各种具体事件的事件位图
		input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);	
	if (test_bit(EV_REL, dev->evbit))
		input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
	if (test_bit(EV_ABS, dev->evbit))
		input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
	if (test_bit(EV_MSC, dev->evbit))
		input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
	if (test_bit(EV_LED, dev->evbit))
		input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
	if (test_bit(EV_SND, dev->evbit))
		input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
	if (test_bit(EV_FF, dev->evbit))
		input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
	if (test_bit(EV_SW, dev->evbit))
		input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);

	seq_putc(seq, '\n');

	kfree(path);
	return 0;
}

打印效果大致如下:因设备不同而异

cat devices 
I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"		
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: EV=3
B: KEY=100000 0 0 0

I: Bus=0017 Vendor=0001 Product=0001 Version=0100
N: Name="Macintosh mouse button emulation"
P: Phys=
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=mouse0 event1 
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=3

这里可以根据Bus值得知该输入设备是基于什么总线的

#define BUS_PCI		0x01
#define BUS_ISAPNP		0x02
#define BUS_USB		0x03
#define BUS_HIL		0x04
#define BUS_BLUETOOTH	0x05
#define BUS_VIRTUAL	0x06
#define BUS_ISA		0x10
#define BUS_I8042		0x11
#define BUS_XTKBD		0x12
#define BUS_RS232		0x13
#define BUS_GAMEPORT	0x14
#define BUS_PARPORT	0x15
#define BUS_AMIGA		0x16
#define BUS_ADB		0x17
#define BUS_I2C		0x18
#define BUS_HOST		0x19
#define BUS_GSC		0x1A
#define BUS_ATARI		0x1B
#define BUS_SPI		0x1C

 

     2.3 handlers文件

static const struct file_operations input_handlers_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_handlers_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

     2.3.1 
这里当我们去cat /proc/bus/input/handlers时候,会调用input_proc_handlers_open函数,接着调用seq_open(file, &input_handlers_seq_ops),捆绑了input_handlers_seq_ops操作函数集,
其seq_operations函数集中声明了.show方法为input_handlers_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,
接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
	struct input_handler *handler = container_of(v, struct input_handler, node);	//获得输入处理器
	union input_seq_state *state = (union input_seq_state *)&seq->private;

	seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);	//打印N:Number=序号 name=设备名
	if (handler->filter)
		seq_puts(seq, " (filter)");
	if (handler->fops)
		seq_printf(seq, " Minor=%d", handler->minor);		//打印Minor=次设备号
	seq_putc(seq, '\n');

	return 0;
}

我的打印是

cat handlers 
N: Number=0 Name=rfkill
N: Number=1 Name=kbd
N: Number=2 Name=mousedev Minor=32
N: Number=3 Name=evdev Minor=64

     3. 字符设备接口

     3.1 主设备号

#define INPUT_MAJOR		13

     3.2 input_fops

static const struct file_operations input_fops = {
	.owner = THIS_MODULE,
	.open = input_open_file,	//打开方法
	.llseek = noop_llseek,	
};

    3.2.1 input_open_file

static int input_open_file(struct inode *inode, struct file *file)
{
	struct input_handler *handler;
	const struct file_operations *old_fops, *new_fops = NULL;
	int err;

	err = mutex_lock_interruptible(&input_mutex);
	if (err)
		return err;

	/* No load-on-demand here? */
	handler = input_table[iminor(inode) >> 5];	//根据节点算出次设备号,并在全局input_table找到输入处理器
	if (handler)
		new_fops = fops_get(handler->fops);	//获取输入操作函数集指针

	mutex_unlock(&input_mutex);

	/*
	 * That's _really_ odd. Usually NULL ->open means "nothing special",
	 * not "no device". Oh, well...
	 */
	if (!new_fops || !new_fops->open) {	//判断输入操作函数集的存在且存在open方法
		fops_put(new_fops);	
		err = -ENODEV;
		goto out;
	}

	old_fops = file->f_op;	//获取文件的操作函数集指针
	file->f_op = new_fops;	//替换为输入操作函数集指针

	err = new_fops->open(inode, file);	//调用输入操作函数集的open方法
	if (err) {
		fops_put(file->f_op);
		file->f_op = fops_get(old_fops);
	}
	fops_put(old_fops);
out:
	return err;
}


三. 分配input_dev

struct input_dev *input_allocate_device(void)
{
	struct input_dev *dev;

	dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);	//分配内存
	if (dev) {
		dev->dev.type = &input_dev_type;	//设置设备文件
		dev->dev.class = &input_class;	//设置类
		device_initialize(&dev->dev);	//初始化设备文件
		mutex_init(&dev->mutex);
		spin_lock_init(&dev->event_lock);
		INIT_LIST_HEAD(&dev->h_list);	//初始化input_handler链表头
		INIT_LIST_HEAD(&dev->node);
		__module_get(THIS_MODULE);
	}

	return dev;
}

四. 设置输入设备类型

      1.设置标志位的辅助宏

#define	setbit(a, i)	(((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))	//设置标志位(eg:setbit(EV_KEY,my_input_dev.evbit))
#define	clrbit(a, i)	(((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))	//清除标志位(eg:setbit(REL_Z,my_input_dev.relbit))
#define	isset(a, i)	(((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))		//检测某标志位是否设置
#define	isclr(a, i)	((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)	//检测某标志位是否清除

      2.设置事件类型标志位ev_bit

#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	//led指示灯事件
#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

      3.设置对应事件的标志位

标志位的值在include/linux/Input.h中有详细定义

五. 注册注销输入设备

     1.1 注册输入设备

int input_register_device(struct input_dev *dev)
{
	static atomic_t input_no = ATOMIC_INIT(0);	//原子变量,标记注册的个数
	struct input_handler *handler;
	const char *path;
	int error;

	__set_bit(EV_SYN, dev->evbit);	//添加同步事件
	__clear_bit(KEY_RESERVED, dev->keybit);	//清除保留键
	input_cleanse_bitmasks(dev);	//清除位掩码
	init_timer(&dev->timer);	//初始化定时器
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {	//若没设置重复延时和重复周期
		dev->timer.data = (long) dev;		//设置定时器数据
		dev->timer.function = input_repeat_key;	//设置定时器中断响应函数
		dev->rep[REP_DELAY] = 250;	//设置延时时间
		dev->rep[REP_PERIOD] = 33;	//设置重复周期
	}
	if (!dev->getkeycode && !dev->getkeycode_new)	//若没定义获取键盘码的函数
		dev->getkeycode_new = input_default_getkeycode;	//则设置为系统默认的获取键盘码函数
	if (!dev->setkeycode && !dev->setkeycode_new)	//若没定义设置键盘码的函数
		dev->setkeycode_new = input_default_setkeycode;	//则设置为系统默认的设置键盘码函数
	dev_set_name(&dev->dev, "input%ld",(unsigned long) atomic_inc_return(&input_no) - 1);	//设置输入设备名字-->"/sys/class/input/input%d"
	error = device_add(&dev->dev);	//添加设备
	if (error)
		return error;
	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
	printk(KERN_INFO "input: %s as %s\n",dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
	kfree(path);
	error = mutex_lock_interruptible(&input_mutex);
	if (error) {
		device_del(&dev->dev);
		return error;
	}
	list_add_tail(&dev->node, &input_dev_list);	//将其设备添加到全局输入设备链表
	list_for_each_entry(handler, &input_handler_list, node)	//遍历全局输入处理器链表
		input_attach_handler(dev, handler);	//匹配input_dev和input_handler
	input_wakeup_procfs_readers();
	mutex_unlock(&input_mutex);
	return 0;
}

     1.2 注销输入设备

void input_unregister_device(struct input_dev *dev)
{
	struct input_handle *handle, *next;
	input_disconnect_device(dev);	//断开设备连接
	mutex_lock(&input_mutex);
	list_for_each_entry_safe(handle, next, &dev->h_list, d_node)	//遍历输入处理器链表
		handle->handler->disconnect(handle);	//查找到对应项并调用其断开连接函数
	WARN_ON(!list_empty(&dev->h_list));
	del_timer_sync(&dev->timer);	//移除定时器
	list_del_init(&dev->node);		//逆初始化设备
	input_wakeup_procfs_readers();	
	mutex_unlock(&input_mutex);
	device_unregister(&dev->dev);	//注销设备
}

六. 输入处理器

     1.输入处理器的驱动,内核已经帮我们设计好了 eg:evdev.c,tsdev.c,joydev.c,keyboard.c,mousedev.c

     2. 以mousedev.c为蓝本分析下处理器驱动的设计

     2.1 mousedev_handler的定义

static struct input_handler mousedev_handler = {
	.event =	mousedev_event,	//事件处理函数(设备上报输入事件给到处理器,处理器调用此函数解析)
	.connect =	mousedev_connect,	//连接(处理器和设备匹配后调用)
	.disconnect =	mousedev_disconnect,	//断开
	.fops =		&mousedev_fops,	//操作函数集
	.minor =		MOUSEDEV_MINOR_BASE,	//次设备号
	.name =		"mousedev",	//设备名
	.id_table =	mousedev_ids,
};

    2.1.1  mousedev_ids

input_device_id的结构体在处理器与设备匹配的时候会用上,mousedev_ids罗列了鼠标的大致分类,flags标记了需要匹配的事件类型

static const struct input_device_id mousedev_ids[] = {
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
		.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
		.relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
	},	/* A mouse like device, at least one button,two relative axes */
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
		.relbit = { BIT_MASK(REL_WHEEL) },
	},	/* A separate scrollwheel */
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
		.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
	},	/* A tablet like device, at least touch detection,two absolute axes */
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
		.keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =BIT_MASK(BTN_TOOL_FINGER) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |BIT_MASK(ABS_PRESSURE) |BIT_MASK(ABS_TOOL_WIDTH) },
	},	/* A touchpad */
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT |INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
		.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
	},	/* Mouse-like device with absolute X and Y but ordinaryclicks, like hp ILO2 High Performance mouse */

	{ },	/* Terminating entry */
};

     2.2 处理器的注册

int input_register_handler(struct input_handler *handler)
{
	struct input_dev *dev;
	int retval;
	retval = mutex_lock_interruptible(&input_mutex);
	if (retval)
		return retval;
	INIT_LIST_HEAD(&handler->h_list);	//初始化处理器链表头
	if (handler->fops != NULL) {
		if (input_table[handler->minor >> 5]) {	//判断是否已经注册
			retval = -EBUSY;
			goto out;
		}
		input_table[handler->minor >> 5] = handler;	//填充全局input_table表
	}
	list_add_tail(&handler->node, &input_handler_list);	//添加输入处理器到全局输入处理器链表
	list_for_each_entry(dev, &input_dev_list, node)	//遍历全局输入设链表
		input_attach_handler(dev, handler);		//匹配input_device和input_handler
	input_wakeup_procfs_readers();
 out:
	mutex_unlock(&input_mutex);
	return retval;
}

     2.3 处理器的注销

void input_unregister_handler(struct input_handler *handler)
{
	struct input_handle *handle, *next;
	mutex_lock(&input_mutex);
	list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
		handler->disconnect(handle);	//调用断开连接函数
	WARN_ON(!list_empty(&handler->h_list));
	list_del_init(&handler->node);	//删除输入设备链表
	if (handler->fops != NULL)
		input_table[handler->minor >> 5] = NULL;	//清空全局输入处理器表
	input_wakeup_procfs_readers();
	mutex_unlock(&input_mutex);
}


七. 设备的匹配

linux input设备驱动_第2张图片

     1.在输入设备或者输入处理器注册的时候都会遍历全局链表input_handler_list或input_dev_list并调用input_attach_handler寻找匹配项

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
	const struct input_device_id *id;
	int error;

	id = input_match_device(handler, dev);	//匹配input_handler和input_dev获取input_device_id
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);	//匹配到则调用其input_handler的连接方法
	if (error && error != -ENODEV)
		printk(KERN_ERR"input: failed to attach handler %s to device %s,error: %d\n",handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

     2.input_match_device

static const struct input_device_id *input_match_device(struct input_handler *handler,struct input_dev *dev)
{
	const struct input_device_id *id;
	int i;

	for (id = handler->id_table; id->flags || id->driver_info; id++) {

		if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
			if (id->bustype != dev->id.bustype)	//判断总线类型
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
			if (id->vendor != dev->id.vendor)	//判断厂商id
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
			if (id->product != dev->id.product)	//判断产品id
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
			if (id->version != dev->id.version)	//判断版本
				continue;

		MATCH_BIT(evbit,  EV_MAX);	//匹配各个标志位
		MATCH_BIT(keybit, KEY_MAX);
		MATCH_BIT(relbit, REL_MAX);
		MATCH_BIT(absbit, ABS_MAX);
		MATCH_BIT(mscbit, MSC_MAX);
		MATCH_BIT(ledbit, LED_MAX);
		MATCH_BIT(sndbit, SND_MAX);
		MATCH_BIT(ffbit,  FF_MAX);
		MATCH_BIT(swbit,  SW_MAX);

		if (!handler->match || handler->match(handler, dev))	//若input_handler存在match方法则调用其方法
			return id;
	}

	return NULL;
}

八. 事件的处理

     1.设备需要上报事件(一般在中断处理函数中上报)

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)	//上报键盘事件
{
	input_event(dev, EV_KEY, code, !!value);
}

static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)	//上报相对位移事件
{
	input_event(dev, EV_REL, code, value);
}

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)	//上报绝对位移事件
{
	input_event(dev, EV_ABS, code, value);
}

static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)	//上报强制反馈事件
{
	input_event(dev, EV_FF_STATUS, code, value);
}

static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value)		//上报开关事件
{
	input_event(dev, EV_SW, code, !!value);
}

static inline void input_sync(struct input_dev *dev)	//上报同步事件----在上报完其他事件后必须上报同步事件通知对应的输入处理器
{
	input_event(dev, EV_SYN, SYN_REPORT, 0);
}

     2.所有上报事件都会调用到input_event函数

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
	unsigned long flags;
	if (is_event_supported(type, dev->evbit, EV_MAX)) {	//判断对应的input_dev是否支持该事件
		spin_lock_irqsave(&dev->event_lock, flags);
		add_input_randomness(type, code, value);
		input_handle_event(dev, NULL, type, code, value);	//输入事件处理句柄
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}

     3.input_handle_event函数

static void input_handle_event(struct input_dev *dev,struct input_handler *src_handler,unsigned int type, unsigned int code, int value)
{
	int disposition = INPUT_IGNORE_EVENT;
	switch (type) {	//判断事件类型
	case EV_SYN:	//同步事件
		switch (code) {
		case SYN_CONFIG:
			disposition = INPUT_PASS_TO_ALL;	//这里有个宏#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
			break;

		case SYN_REPORT:
			if (!dev->sync) {
				dev->sync = true;
				disposition = INPUT_PASS_TO_HANDLERS;
			}
			break;
		case SYN_MT_REPORT:
			dev->sync = false;
			disposition = INPUT_PASS_TO_HANDLERS;
			break;
		}
		break;

	case EV_KEY:	//键盘事件
		if (is_event_supported(code, dev->keybit, KEY_MAX) && !!test_bit(code, dev->key) != value) {

			if (value != 2) {
				__change_bit(code, dev->key);
				if (value)
					input_start_autorepeat(dev, code);
				else
					input_stop_autorepeat(dev);
			}

			disposition = INPUT_PASS_TO_HANDLERS;
		}
		break;

	case EV_SW:	//开关事件
		if (is_event_supported(code, dev->swbit, SW_MAX) &&!!test_bit(code, dev->sw) != value) {
			__change_bit(code, dev->sw);
			disposition = INPUT_PASS_TO_HANDLERS;
		}
		break;

	case EV_ABS:	//绝对位移事件
		if (is_event_supported(code, dev->absbit, ABS_MAX))
			disposition = input_handle_abs_event(dev, src_handler,code, &value);

		break;

	case EV_REL:	//相对位移事件
		if (is_event_supported(code, dev->relbit, REL_MAX) && value)
			disposition = INPUT_PASS_TO_HANDLERS;

		break;

	case EV_MSC:	//杂项事件
		if (is_event_supported(code, dev->mscbit, MSC_MAX))
			disposition = INPUT_PASS_TO_ALL;

		break;

	case EV_LED:	//led事件
		if (is_event_supported(code, dev->ledbit, LED_MAX) &&
		    !!test_bit(code, dev->led) != value) {

			__change_bit(code, dev->led);
			disposition = INPUT_PASS_TO_ALL;
		}
		break;

	case EV_SND:	//声音事件
		if (is_event_supported(code, dev->sndbit, SND_MAX)) {

			if (!!test_bit(code, dev->snd) != !!value)
				__change_bit(code, dev->snd);
			disposition = INPUT_PASS_TO_ALL;
		}
		break;

	case EV_REP:	//重复事件
		if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
			dev->rep[code] = value;
			disposition = INPUT_PASS_TO_ALL;
		}
		break;

	case EV_FF:	//强制反馈事件
		if (value >= 0)
			disposition = INPUT_PASS_TO_ALL;
		break;

	case EV_PWR:	//电源事件
		disposition = INPUT_PASS_TO_ALL;
		break;
	}

	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
		dev->sync = false;

	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
		dev->event(dev, type, code, value);	//根据事件类型不同,部分事件会先调用到input_dev的事件处理函数

	if (disposition & INPUT_PASS_TO_HANDLERS)
		input_pass_event(dev, src_handler, type, code, value);	//直接传递事件给对应事件的输入处理器处理
}

    4.input_pass_event

static void input_pass_event(struct input_dev *dev,struct input_handler *src_handler,unsigned int type, unsigned int code, int value)
{
	struct input_handler *handler;
	struct input_handle *handle;
	rcu_read_lock();
	handle = rcu_dereference(dev->grab);
	if (handle)
		handle->handler->event(handle, type, code, value);	//调用处理器的event方法
	else {
		bool filtered = false;

		list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
			if (!handle->open)
				continue;

		handler = handle->handler;

		if (handler == src_handler)
			continue;

		if (!handler->filter) {
			if (filtered)
				break;
			handler->event(handle, type, code, value);

		} else if (handler->filter(handle, type, code, value))
				filtered = true;
		}
	}

	rcu_read_unlock();
}




 

 

你可能感兴趣的:(linux input设备驱动)