Linux输入子系统

几个重要的结构体

struct input_dev {
	const char *name;
	unsigned long evbit[BITS_TO_LONGS(EV_CNT)]
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//设置这里来支持具体的按键
	unsigned long key[BITS_TO_LONGS(KEY_CNT)];//保存按键的值
	struct input_value *vals;
	struct list_head h_list;
}


//最大的一个承包商evdev
struct evdev {
	int open;
	struct input_handle handle;  //负责人,客户通过负责人找到自己的方案
	wait_queue_head_t wait;
	struct evdev_client __rcu *grab;  //环形缓冲区,负责保存客户的数据
	struct list_head client_list;      //用来记录环形缓冲区
	spinlock_t client_lock; /* protects client_list */
	struct mutex mutex;
	struct device dev;
	struct cdev cdev;     //提供设备节点,给上层调用
	bool exist;
};


struct input_handle {

	void *private;//指向struct evdev

	int open;
	const char *name;

	struct input_dev *dev;
	struct input_handler *handler;  


	struct list_head	d_node;//让客户保存自己的联系方式,通过d_node找到input_handle
	struct list_head	h_node;
};

struct input_handler {

	void *private;
	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
	void (*events)(struct input_handle *handle,const struct input_value *vals, unsigned int count);
	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);

	bool legacy_minors;
	int minor;
	const char *name;

	const struct input_device_id *id_table;

	struct list_head	h_list;
	struct list_head	node;
};


struct evdev_client {
	unsigned int head;
	unsigned int tail;
	unsigned int packet_head; /* [future] position of the first element of next packet */
	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
	struct wake_lock wake_lock;
	bool use_wake_lock;
	char name[28];
	struct fasync_struct *fasync;
	struct evdev *evdev;
	struct list_head node;
	int clkid;
	unsigned int bufsize;
	struct input_event buffer[];
};

整个input子系统可以按如下模型来理解(kernel层)

1.承包商有很多,但能力最强的是evdev,承包商到中间商那里注册

kernel/drivers/input/evdev.c
static struct input_handler evdev_handler = {  
	.event		= evdev_event,
	.events		= evdev_events,        
	.connect	= evdev_connect,	
	.disconnect	= evdev_disconnect,
	.legacy_minors	= true,
	.minor		= EVDEV_MINOR_BASE,
	.name		= "evdev",
	.id_table	= evdev_ids,
};
static int __init evdev_init(void)
{
	return input_register_handler(&evdev_handler); 
}


int input_register_handler(struct input_handler *handler)
{
	list_add_tail(&handler->node, &input_handler_list);//跟中间商那里登记下
}

2.客户提需求  高通电源键汇报为例kernel/drivers/platform/msm/qpnp-power-on.c

static int qpnp_pon_config_init(struct qpnp_pon *pon)
{
	qpnp_pon_config_input();
	input_register_device();
}

static int qpnp_pon_config_input(struct qpnp_pon *pon,  struct qpnp_pon_config *cfg)
{
	pon->pon_input = input_allocate_device();
	pon->pon_input->name = "qpnp_pon";
	pon->pon_input->phys = "qpnp_pon/input0";
	input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
}
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
	case EV_KEY:
		__set_bit(code, dev->keybit);//这里设置支持的按键 keybit是一个数组,通过一个位代表一个按键码,__set_bit的作用是将某位置1
		break;
	__set_bit(type, dev->evbit);//这里设置支持按键事件
}

int input_register_device(struct input_dev *dev)
{
	struct input_handler *handler;
	list_for_each_entry(handler, &input_handler_list, node)//找到所有已注册的承包商
		input_attach_handler(dev, handler);//看承包商的能力匹配能否满足客户的要求	
}

3.中间商找到合适的承包商,并让承包商定制方案

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
	 input_match_device(handler, dev);//看能力可否满足
	 if (!id)
		return -ENODEV;
	 handler->connect(handler, dev, id);//满足了,让承包商定制方案
}
static const struct input_device_id *input_match_device(struct input_handler *handler,struct input_dev *dev)
{
	const struct input_device_id *id;

	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;

		if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
			continue;

		if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX))
			continue;

		if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
			continue;

		if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
			continue;

		if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
			continue;

		if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX))
			continue;

		if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX))
			continue;

		if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX))
			continue;

		if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX))
			continue;
		
		if (!handler->match || handler->match(handler, dev)){
			return id;
			}
	}
	//bitmap_subset(A,B)判断A是否B的子集合,比如A支持EV_KEY和EV_REL,但B只支持EV_KEY,B是A的子集,但A不是B的子集
	return NULL;
}


4.承包商定制方案

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
{	
	struct evdev *evdev;
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;
	error = input_register_handle(&evdev->handle);
	cdev_init(&evdev->cdev, &evdev_fops);
	cdev_add(&evdev->cdev, evdev->dev.devt, 1);
}

int input_register_handle(struct input_handle *handle)
{
	list_add_tail_rcu(&handle->d_node, &dev->h_list);//将这项工作的接口人告诉客户,客户查找h_list,
	//就能找出stuct input_handle,input_handle又指向了struct evdev;
	
}

5.客户把工作交出去

static qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
{
按下
	input_report_key(pon->pon_input, KEY_POWER, 1);
	input_sync(pon->pon_input);
弹开
	input_report_key(pon->pon_input, KEY_POWER, 0);
	input_sync(pon->pon_input);

}
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
	input_event(dev, EV_KEY, code, !!value);//两次取反可以将非0值转换成1
}

static inline void input_sync(struct input_dev *dev)
{
	input_event(dev, EV_SYN, SYN_REPORT, 0);
}

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_handle_event(dev, type, code, value);
	}
}


static inline int is_event_supported(unsigned int code,unsigned long *bm, unsigned int max)
{
	return code <= max && test_bit(code, bm);
}
//判断第n位是否为1,是1返回1,是0返回0
static inline int test_bit(int nr, const volatile unsigned long *addr)
{
	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}


//事件类型共有如下几种
#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
#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


static void input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
	int disposition;

	disposition = input_get_disposition(dev, type, code, value);


	if (disposition & INPUT_PASS_TO_HANDLERS) {
		struct input_value *v;
		v = &dev->vals[dev->num_vals++];//input_register_device,分配了空间,用来保存input_value
		v->type = type;
		v->code = code;
		v->value = value;
	}

	if (disposition & INPUT_FLUSH) {
		if (dev->num_vals >= 2)//一次按下(没有弹开)刚好是2  input_report_key input_sync
			input_pass_values(dev, dev->vals, dev->num_vals);
		dev->num_vals = 0;
	} else if (dev->num_vals >= dev->max_vals - 2) {
		dev->vals[dev->num_vals++] = input_value_sync;
		input_pass_values(dev, dev->vals, dev->num_vals);
		dev->num_vals = 0;
	}
}

static int input_get_disposition(struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
	int disposition = INPUT_IGNORE_EVENT;
	switch (type) {
	case EV_SYN:
		switch (code) {
		case SYN_REPORT:
			disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
			break;
		}
		break;

	case EV_KEY:
		if (is_event_supported(code, dev->keybit, KEY_MAX)) { //判断是否支持该按键码code,前面已设置(input_set_capability)

			if (!!test_bit(code, dev->key) != !!value) {  //现在汇报的按键值跟之前的对比,如果不一样,则汇报上去

				__change_bit(code, dev->key);//更新按键值 __change_bit的作用某一位取反
				disposition = INPUT_PASS_TO_HANDLERS;
			}
		}
		break;

	return disposition;
}

struct input_dev *input_allocate_device(void)//分配输入设备的时候,dev->key已清零,上面的value为1
{
	dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
}


static void input_pass_values(struct input_dev *dev, struct input_value *vals, unsigned int count)
{
	struct input_handle *handle;
	       list_for_each_entry_rcu(handle, &dev->h_list, d_node) //从dev->h_list找出handle
			if (handle->open)
	     		count = input_to_handler(handle, vals, count);
}

static unsigned int input_to_handler(struct input_handle *handle,
			struct input_value *vals, unsigned int count)
{
	struct input_handler *handler = handle->handler;
	if (handler->events)
		handler->events(handle, vals, count);
	else if (handler->event)
		for (v = vals; v != end; v++)
			handler->event(handle, v->type, v->code, v->value);
	return count;
}



static void evdev_events(struct input_handle *handle,const struct input_value *vals, unsigned int count)
{
	struct evdev *evdev = handle->private; 
	list_for_each_entry_rcu(client, &evdev->client_list, node)//找出client
		evdev_pass_values(client, vals, count,time_mono, time_real);
}
//这里client赋值
static int evdev_open(struct inode *inode, struct file *file)
{
	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
	struct evdev_client *client= kzalloc(size, GFP_KERNEL | __GFP_NOWARN);;
	evdev_attach_client(evdev, client);
	return 0;
}
static void evdev_attach_client(struct evdev *evdev,struct evdev_client *client)
{
	list_add_tail_rcu(&client->node, &evdev->client_list);
}


static void evdev_pass_values(struct evdev_client *client,const struct input_value *vals, unsigned int count,ktime_t mono, ktime_t real)
{
	struct input_event event;
	for (v = vals; v != vals + count; v++) {
		event.type = v->type;
		event.code = v->code;
		event.value = v->value;
		__pass_event(client, &event);
		if (v->type == EV_SYN && v->code == SYN_REPORT)
			wakeup = true;
	}

	if (wakeup)
		wake_up_interruptible(&evdev->wait);
}


static void __pass_event(struct evdev_client *client,const struct input_event *event)//将数据放到环形缓冲区,接下来通过read来读走数据
{
	client->buffer[client->head++] = *event;
	client->head &= client->bufsize - 1;

	if (unlikely(client->head == client->tail)) {
		/*
		 * This effectively "drops" all unconsumed events, leaving
		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
		 */
		client->tail = (client->head - 2) & (client->bufsize - 1);

		client->buffer[client->tail].time = event->time;
		client->buffer[client->tail].type = EV_SYN;
		client->buffer[client->tail].code = SYN_DROPPED;
		client->buffer[client->tail].value = 0;

		client->packet_head = client->tail;
		
	}

	if (event->type == EV_SYN && event->code == SYN_REPORT) {
		client->packet_head = client->head;
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}
}
//关于环形缓冲区,可参考https://blog.csdn.net/zifehng/article/details/70169512

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值