/**
input系统中,分为:
设备驱动层
核心层
事件处理层
将 input_dev结构体(表示一个输入设备) 注册到 核心层.
注意:
1: 这个input_dev必需由input_allocate_device()函数来分配
2: input_register_device()如果注册失败,必需调用input_free_device()来释放分配的空间
3: 如果注册成功,在卸载函数中应该调用input_unregister_device()来注销input_dev
input_dev = input_allocate_device();
if (!input_dev)
{
ret = -ENOMEM;
return ret;
}
.....
.....
ret = input_register_device(input_dev);
if (ret) {
printk("ts-if: Could not register input device(touchscreen)!\n");
input_free_device(input_dev);
return ret;
}
成功 : 返回 0
失败 : 返回非0值
*/
int input_register_device(struct input_dev * dev)
{
/**
为生成设备节点序号做准备。
下面的代码会调用dev_set_name()来设置设备节点的名字
会在sysfs系统中以input0、input1、input2.....出现
*/
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler * handler;
const char *path;
/**
struct input_dev
{
...
设备支持的事件类型
每一个事件的类型都用一个位来表示
如果某一位被置 1 ,表示该设备支持这类事件
被值 0 ,表示该设备不支持这类事件
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
}
*/
/*
将evbit的第0位置1 表示支持所有的事件
*/
__set_bit(EV_SYN,dev->evbit);
/**
如果驱动预先设置了延时,自动重复被驱动处理,
核心层就不做这件事了
*/
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;
}
/**
检查getkeycode函数有没有被定义。
如果没有定义,则使用默认的input_default_getkeycode.
*/
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;//得到指定的键值
/**
检查setkeycode函数有没有被定义。
如果没有定义,则使用默认的input_default_setkeycode.
*/
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;//设置键值
//设置input_dev中的device的名字
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
/**
任何一个设备的注册都会经过这个函数,设备驱动模型中的核心函数
*/
error = device_add(&dev->dev);
if (error)
{
return error;
}
/**
生成并返回设备的路径,调用者必需使用kfree()来释放结果
因为它的代码中有path = kzalloc(len, gfp_mask);
*/
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);
/**
获取锁---访问临界区---释放锁
获取互斥锁且可以被信号打断,当正在等待锁的时信号到来了会返回EINTR
*/
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
/**
input_dev维护了两条链表
1 : input_dev_list链表,该链表包含了系统中所有的input_dev。
2 : input_handle_list链表
将input_dev添加到input_dev_list链表
*/
list_add_tail(&dev->node, &input_dev_list);
/**
遍历input_handler链表上,对链表中的每一个input_handler执行
input_attach_handler函数
*/
list_for_each_entry(handler, &input_handler_list, node)
{
/**
匹配input_dev和input_handler。下面讲解。
*/
input_attach_handler(dev, handler);
}
/**
当用户层调用poll()系统调用的时候, input_proc_devices_poll函数会被调用
static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &input_devices_poll_wait, wait);
...
return 0;
}
唤醒读等待队列input_devices_poll_wait
*/
input_wakeup_procfs_readers();
//释放互斥锁
mutex_unlock(&input_mutex);
return 0;
}
/**
用于匹配input_dev和input_handler
匹配成功的关键是 :
handler中的blacklist、id_table
如果匹配成功,会调用handler的connect函数
*/
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
/**
//设备的标识,存储了设备的信息
struct input_device_id
{
kernel_ulong_t flags;//要匹配的项
设备中的这些信息将要和input_handler中的id_table中定义的进行匹配
__u16 bustype; //总线类型
__u16 vendor; //制造商ID
__u16 product; //产品ID
__u16 version; //版本号
....
...
}
*/
const struct input_device_id * id;
int error;
id = input_match_device(handler,dev);
if(!id)
{
return -ENODEV;
}
/**
一下是匹配成功后要执行的。
调用handler的connect函数
*/
err = handler->connect(handler,dev,id);
if(error && error != -ENODEV)
{
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
}
return error;
}
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;
/**
id_table 表示驱动支持的设备列表
id_table的出现,让一个handler支持多个input_dev变成了可能。
evdev支持所有的设备
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, //匹配所有的设备
{ },
};
keyboard支持的设备
static const struct input_device_id kbd_ids[] = {
{ //比较evbit
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_KEY) },//只要能产生按键类事件,就支持
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_SND) },//主要能产生声音就支持
},
{ },
};
*/
for (id = handler->id_table; id->flags || id->driver_info; id++) {
//匹配总线类型
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
//如果id_table[i]中支持的总线类型 与设备的标识中的总线类型不相符
//就比较id_table[i+1]项
if (id->bustype != dev->id.bustype)
continue;
//匹配制造商id
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
continue;
//匹配产品id
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;
}
static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
{
/**
evbit:设备支持哪些事件
EV_KEY : 0x01
evbit 是long类型
第0位被置1,表示支持所有事件。
某一位置1表示支持该事件
某一位为0标识不支持该事件
test_bit(EV_KEY, dev->evbit) : 测试是否支持按键类事件
test_bit(BTN_TOUCH, dev->keybit)测试是否支持按键类事件中是否支持触摸
*/
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
return false;
.....
return true;
}
input_register_device()浅析
最新推荐文章于 2024-05-30 20:53:58 发布