几个重要的结构体
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