linux驱动学习笔记---输入子系统框架(十一)

1.input core层中初始化input_dev_list链表与input_handler_list链表 

 2.初始化input_handler对象,并注册到内核链表中

注册之后会匹配一次

通过结构体中的node成员连接起来构成input_handler链表

 注册时,会将handler对象加入到input_table数组中

 3.初始化input_dev对象,并注册到input_device_list链表中

注册时匹配一次

struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

	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)];
	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,
			  const struct input_keymap_entry *ke,
			  unsigned int *old_keycode);
	int (*getkeycode)(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;
	int trkid;

	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);
	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 __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;
	struct list_head	node;
};

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

		if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
			if (id->product != dev->id.product)
				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))
			return id;
	}

	return NULL;
}

4.匹配成功后会调用input_handler对象中的evdev_connect方法创建evdev对象

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

	for (minor = 0; minor < EVDEV_MINORS; minor++)
		if (!evdev_table[minor])
			break;

	if (minor == EVDEV_MINORS) {
		pr_err("no more free evdev devices\n");
		return -ENFILE;
	}

	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
	if (!evdev)
		return -ENOMEM;

	INIT_LIST_HEAD(&evdev->client_list);
	spin_lock_init(&evdev->client_lock);
	mutex_init(&evdev->mutex);
	init_waitqueue_head(&evdev->wait);

	dev_set_name(&evdev->dev, "event%d", minor);
	evdev->exist = true;
	evdev->minor = minor;

	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;

	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);

	error = input_register_handle(&evdev->handle);
	if (error)
		goto err_free_evdev;

	error = evdev_install_chrdev(evdev);
	if (error)
		goto err_unregister_handle;

	error = device_add(&evdev->dev);
	if (error)
		goto err_cleanup_evdev;

	return 0;

 err_cleanup_evdev:
	evdev_cleanup(evdev);
 err_unregister_handle:
	input_unregister_handle(&evdev->handle);
 err_free_evdev:
	put_device(&evdev->dev);
	return error;
}

 5.evdev对象会产生一个evdev_client对象,这个对象会产生一个缓冲队列(刚产生时队列为空)

里面的evdev成员中有wait_queue_head成员

  6.evdev对象会产生一个input_handle对象,这个对象会产生一个input_handler的指针和一个input_dev的指针

这两个指针会分别指向input_handler对象与input_dev对象

7.evdev对象产生后会生成设备节点

8.应用层app通过设备节点访问其中的read函数

因为此时缓冲队列中无资源,所以会进入阻塞状态休眠

 9.中断上传资源,通过input_report_key函数,同时用过input_sync唤醒进程

上传数据到到input_handler对象中的evdev_event方法中,数据进入缓冲队列中,此时外部read就可以读写到资源

 

 完整驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

//设计一个描述按键的对象: 名字, irqno, gpio, 按键值,触发方式
struct key_desc{
	char *name;
	int irqno;
	int gpio;
	int code;
	int flags;// 触发方式
};

struct key_desc all_keys[] = {
		[0] = {
			.name = "key1_up_eint0", 
			.irqno = IRQ_EINT(0),
			.gpio = S5PV210_GPH0(0),
			.code = KEY_UP,
			.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,

		},
		[1] = {
			.name = "key2_down_eint1", 
			.irqno = IRQ_EINT(1),
			.gpio = S5PV210_GPH0(1),
			.code = KEY_DOWN,
			.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,

		},
		[2] = {
			.name = "key3_left_eint2", 
			.irqno = IRQ_EINT(2),
			.gpio = S5PV210_GPH0(2),
			.code = KEY_LEFT,
			.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,

		},
		[3] = {
			.name = "key4_right_eint3", 
			.irqno = IRQ_EINT(3),
			.gpio = S5PV210_GPH0(3),
			.code = KEY_RIGHT,
			.flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,

		},
		
};

static struct input_dev *key_inputdev;

irqreturn_t input_key_irq (int irqno, void *dev_id)
{
	struct key_desc *pdesc = (struct key_desc *)dev_id;

	int value = gpio_get_value(pdesc->gpio);

	if(value)
	{
		//上报数据
		//参数1--哪个设备上报
		//参数2--哪个按键
		//参数3--按下还是抬起
		input_report_key(key_inputdev,pdesc->code,0);
		//最后一定要同步--表示上报完毕
		input_sync(key_inputdev);
		
	}else
	{
		input_report_key(key_inputdev,pdesc->code,1);
		input_sync(key_inputdev);
	}
	
	
	return IRQ_HANDLED;
}

static int __init input_key_drv_init(void)
{
	int ret;

// 1, 分配一个input device对象 
   	key_inputdev= input_allocate_device();
	if(key_inputdev == NULL)
	{
		printk("input_allocate_device error\n");
		return -ENOMEM;
	}

// 2, 初始化 input device对象
	key_inputdev->evbit[0] |= BIT_MASK(EV_KEY);

	key_inputdev->keybit[BIT_WORD(KEY_DOWN)] |= BIT_MASK(KEY_DOWN);
	key_inputdev->keybit[BIT_WORD(KEY_UP)] |= BIT_MASK(KEY_UP);
	key_inputdev->keybit[BIT_WORD(KEY_LEFT)] |= BIT_MASK(KEY_LEFT);
	key_inputdev->keybit[BIT_WORD(KEY_RIGHT)] |= BIT_MASK(KEY_RIGHT);
// 3, 注册input device对象
	ret = input_register_device(key_inputdev);
	if(ret != 0)
	{
		printk("input_register_device error\n");
		goto err_free_dev;
	}
	
// 4, 初始化硬件,并获取到数据之后上报数据
	int i;
	int irqno;
	int flags;
	char *name;
	for(i=0; i<ARRAY_SIZE(all_keys); i++)
	{
		name =  all_keys[i].name;
		irqno = all_keys[i].irqno;
		flags = all_keys[i].flags;
		ret = request_irq(irqno, input_key_irq, flags, name, &all_keys[i]);
		if(ret != 0)
		{
			printk("request_irq error\n");
			return ret;
		}
	}

	return 0;

err_unregister_dev:
	input_unregister_device(key_inputdev);
err_free_dev:
	input_free_device(key_inputdev);
	return ret;
}

static void __exit input_key_drv_exit(void)
{
	int i;
	int irqno;
	for(i=0; i<ARRAY_SIZE(all_keys); i++)
	{
		irqno = all_keys[i].irqno;
		free_irq(irqno, &all_keys[i]);
	}
	input_unregister_device(key_inputdev);
	input_free_device(key_inputdev);
}

module_init(input_key_drv_init);
module_exit(input_key_drv_exit);
MODULE_LICENSE("GPL");

完整app代码 

#include <stdio.h>
#include<sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/input.h>

int main(int argc, char *argv[])
{	
	int on;	int ret;
	int fd;
	struct input_event data;

	//打开设备	
	fd = open("/dev/event0", O_RDWR);	
	if(fd < 0)	
	{		
		perror("open");		
		exit(1);	
	}	
	while(1)	
	{		
		ret = read(fd, &data, sizeof(struct input_event));
		if(ret < 0)		
		{			
			perror("open");
			exit(1);		
		}			
		//拆包		
		if(data.type == EV_KEY)		
		{				
			if(data.code == KEY_DOWN)
			{				
				if(data.value)				
				{					
					printf("<app>---KEY_DOWN pressed\n");
				}else				
				{					
					printf("<app>---KEY_DOWN released\n");
				}			
			}else if(data.code == KEY_UP)
			{
				if(data.value)				
				{					
					printf("<app>---KEY_UP pressed\n");
				}else				
				{					
					printf("<app>---KEY_UP released\n");
				}	
			}else if(data.code == KEY_LEFT)
			{
				if(data.value)				
				{					
					printf("<app>---KEY_LEFT pressed\n");
				}else				
				{					
					printf("<app>---KEY_LEFT released\n");
				}
			}else if(data.code == KEY_RIGHT)
			{
				if(data.value)				
				{					
					printf("<app>---KEY_RIGHT pressed\n");
				}else				
				{					
					printf("<app>---KEY_RIGHT released\n");
				}
			}
		}			
	}		
	close(fd);
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值