input子系统
谨以此文纪念过往的岁月。
一.前言
linux的input子系统在网上的资料很多,讲应用的很多,但是input子系统如何去工作的较少,想通过源码去理解input子系统如何工作的。
二.input子系统应用
一般input子系统应用流程如下
input_allocate_device -> input_register_device->input_event->input_unregister_device
关于其具体的使用会在讲述函数时说明。
2.1 input_dev 结构体
struct input_dev {
const char *name;
const char *phys; --物理路径
const char *uniq; --设备的唯一识别码
struct input_id id; --设备id
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; --BITS_TO_LONGS其实将多个bit组合成多个long类型的数据,evbit用于表明设备对事件类型的支持
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 keycodemax; --键盘码表项的个数
unsigned int keycodesize; --键盘码表项的大小
void *keycode; --键盘码表的首地址
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int sync;
int abs[ABS_MAX + 1];
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_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
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;
int going_away;
struct device dev;
struct list_head h_list;
struct list_head node;
};
2.2申请设备
申请设备比较简单。
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);
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
}
return dev;
}
2.3设备初始化
2.3.1设定设备所支持的事件
有两种手段可以去设定,1.__set_bit(EV_KEY,xx->evbit),设定evbit支持EV_KEY 2.xx_dev->evbit[0] = BIT(EV_KEY);
2.3.2设定设备事件使能位
其设置方法同上。
__set_bit(xx_keycodes[i], xx_dev->keybit);
对于上面两个性质的设置还可以通过调用input_set_capability函数来实现。
其源码如下:
下面的源码很简单易懂,不说了。
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
switch (type) {
case EV_KEY:
__set_bit(code, dev->keybit);
break;
case EV_REL:
__set_bit(code, dev->relbit);
break;
case EV_ABS:
__set_bit(code, dev->absbit);
break;
case EV_MSC:
__set_bit(code, dev->mscbit);
break;
case EV_SW:
__set_bit(code, dev->swbit);
break;
case EV_LED:
__set_bit(code, dev->ledbit);
break;
case EV_SND:
__set_bit(code, dev->sndbit);
break;
case EV_FF:
__set_bit(code, dev->ffbit);
break;
case EV_PWR:
/* do nothing */
break;
default:
printk(KERN_ERR
"input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
}
__set_bit(type, dev->evbit);
}
2.3.3设置设备的信息
设置设备的name,bus,以及open,close等等成员。关于open和close还有点事可以说的。open必须要返回0,否则出错,close无返回值。
2.4 input设备注册
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0); --这个记住每调用一次该函数input_no增加一次
struct input_handler *handler; --设置handler初始
const char *path;
int error;
__set_bit(EV_SYN, dev->evbit); --每个设备都要支持该事件
init_timer(&dev->timer); --初始化定时器,在linux中采用定时器定时去查询设备事件
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { --如果rep没有设定
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 = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",(unsigned long) atomic_inc_return(&input_no) - 1); --设置设备名称
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); --将设备节点添加到input设备链表中。
list_for_each_entry(handler, &input_handler_list, node) --从input处理链表中查询匹配
input_attach_handler(dev, handler); --匹配处理函数
input_wakeup_procfs_readers(); --这个不管
mutex_unlock(&input_mutex);
return 0;
}
根据上面的函数,来一一分析其调用的函数。
No.1 input_repeat_key该函数在没有设定repeat参数情况下调用。下面的函数在看event层的时候在回过头来看。
static void input_repeat_key(unsigned long data)
{
struct input_dev *dev = (void *) data;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags); --自旋锁锁定,记住临界区的代码不能够阻塞。
if (test_bit(dev->repeat_key, dev->key) &&is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
if (dev->sync) {
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
No.2 input_default_getkeycode
这个函数是默认的获取keycode,下面的函数又是很好理解的,偷懒一下。
static int input_default_getkeycode(struct input_dev *dev, int scancode, int *keycode)
{
if (!dev->keycodesize)
return -EINVAL;
if (scancode >= dev->keycodemax)
return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode);
return 0;
}
static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
switch (dev->keycodesize) {
case 1:
return ((u8 *)dev->keycode)[scancode];
case 2:
return ((u16 *)dev->keycode)[scancode];
default:
return ((u32 *)dev->keycode)[scancode];
}
}
No.3 input_default_setkeycode
默认的设置keycode函数,来好好看一下。
static int input_default_setkeycode(struct input_dev *dev,int scancode, int keycode)
{
int old_keycode;
int i;
if (scancode >= dev->keycodemax) --scancode是设置的"位",检查设置位是否溢出
return -EINVAL;
if (!dev->keycodesize)
return -EINVAL;
if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) --检测大小是否匹配。
return -EINVAL;
switch (dev->keycodesize) { --下面是查询替换事件查询表
case 1: {
u8 *k = (u8 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
case 2: {
u16 *k = (u16 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
default: {
u32 *k = (u32 *)dev->keycode;
old_keycode = k[scancode];
k[scancode] = keycode;
break;
}
}
clear_bit(old_keycode, dev->keybit); --更改位
set_bit(keycode, dev->keybit);
for (i = 0; i < dev->keycodemax; i++) { --防止出错
if (input_fetch_keycode(dev, i) == old_keycode) {
set_bit(old_keycode, dev->keybit);
break; /* Setting the bit twice is useless, so break */
}
}
return 0;
}
No.4 input_attach_handler
这个函数很重要,这个其实类似于platform中probe函数,将设备与设备事件处理相连接。
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev)) --先检测dev是否在黑名单中,强人!!!下面会看这handler在哪儿设置了。
return -ENODEV;
id = input_match_device(handler->id_table, dev); --查询到设备id表
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); --将两者连接起来。
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;
}
这儿先转走,那handler的input_handler_list在哪儿添加成员的呢?