原文地址:
这节结合even handler来分析设备的注册和打开的过程,在设备注册之前,必须先初始化INPUT子系统,由input_init()函数来完成
相关阅读:Linux Input子系统(上)--概述
-
static int __init input_init(void)
-
{
-
int err;
-
-
input_init_abs_bypass();
-
-
err = class_register(&input_class);
-
if (err) {
-
printk(KERN_ERR "input: unable to register input_dev class\n");
-
return err;
-
}
-
-
err = input_proc_init();
-
if (err)
-
goto fail1;
-
-
-
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
-
if (err) {
-
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
-
goto fail2;
-
}
-
-
return 0;
-
-
fail2: input_proc_exit();
-
fail1: class_unregister(&input_class);
-
return err;
-
}
input_fops中只定义了open函数。
-
static const struct file_operations input_fops = {
-
.owner = THIS_MODULE,
-
.open = input_open_file,
-
};
我们需要在设备驱动层中完成输入设备的注册,通过调用input_register_device()函数来完成,该函数的一个重要任务就是完成设备与事件驱动的匹配。
-
int input_register_device(struct input_dev *dev)
-
{
-
static atomic_t input_no = ATOMIC_INIT(0);
-
struct input_handler *handler;
-
const char *path;
-
int error;
-
-
__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;
-
}
-
-
-
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);
-
-
-
list_for_each_entry(handler, &input_handler_list, node)
-
input_attach_handler(dev, handler);
-
-
input_wakeup_procfs_readers();
-
-
mutex_unlock(&input_mutex);
-
-
return 0;
-
}
-
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))
-
return -ENODEV;
-
-
id = input_match_device(handler->id_table, dev);
-
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;
-
}
匹配的具体过程:
-
static const struct input_device_id *input_match_device(const struct input_device_id *id,
-
struct input_dev *dev)
-
{
-
int i;
-
-
-
for (; 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);
-
-
return id;
-
}
-
-
return NULL;
-
}
MATCH_BIT是将device的相应字段和handler的相应字段逐位对比,都一样的话表示成功,否则continue
-
#define MATCH_BIT(bit, max) \
-
for (i = 0; i < BITS_TO_LONGS(max); i++) \
-
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
-
break; \
-
if (i != BITS_TO_LONGS(max)) \
-
continue;
以event handler为例,看connect函数做了什么:
-
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) {
-
printk(KERN_ERR "evdev: 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);
-
-
-
snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
-
evdev->exist = 1;
-
evdev->minor = minor;
-
-
-
evdev->handle.dev = input_get_device(dev);
-
evdev->handle.name = evdev->name;
-
evdev->handle.handler = handler;
-
evdev->handle.private = evdev;
-
-
-
dev_set_name(&evdev->dev, evdev->name);
-
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;
-
}
至此设备的注册完成!对应event handler,在/dev中将多出一个event(x)设备文件,对应一个evdev实例,应用程序打开它的话也就意味着通过event handler来和设备驱动层传递事件。
再来看打开设备的过程,还是以event handler为例,假如打开一个event(x),则先执行:
-
static int input_open_file(struct inode *inode, struct file *file)
-
{
-
struct input_handler *handler;
-
const struct file_operations *old_fops, *new_fops = NULL;
-
int err;
-
-
lock_kernel();
-
-
-
-
handler = input_table[iminor(inode) >> 5];
-
if (!handler || !(new_fops = fops_get(handler->fops))) {
-
err = -ENODEV;
-
goto out;
-
}
-
-
-
-
-
-
if (!new_fops->open) {
-
fops_put(new_fops);
-
err = -ENODEV;
-
goto out;
-
}
-
old_fops = file->f_op;
-
-
file->f_op = new_fops;
-
-
err = new_fops->open(inode, file);
-
-
if (err) {
-
fops_put(file->f_op);
-
file->f_op = fops_get(old_fops);
-
}
-
fops_put(old_fops);
-
out:
-
unlock_kernel();
-
return err;
-
}
通过此设备号所在的组(0~31),(32~63),(64~95)……就可以找到相应的handler,所有的handler都保存在input_table中,对于次设备号在64~95范围的设备,将定位到下标为2的handler,,也就是event handler,然后将用handler中的open函数替代之前的open函数,并执行新的open函数,这样就以handler本身定义的open来打开设备完成相应的初始化了。
event handler中的open函数:
-
static int evdev_open(struct inode *inode, struct file *file)
-
{
-
struct evdev *evdev;
-
struct evdev_client *client;
-
int i = iminor(inode) - EVDEV_MINOR_BASE;
-
int error;
-
-
if (i >= EVDEV_MINORS)
-
return -ENODEV;
-
-
error = mutex_lock_interruptible(&evdev_table_mutex);
-
if (error)
-
return error;
-
-
evdev = evdev_table[i];
-
if (evdev)
-
get_device(&evdev->dev);
-
mutex_unlock(&evdev_table_mutex);
-
-
if (!evdev)
-
return -ENODEV;
-
-
-
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
-
if (!client) {
-
error = -ENOMEM;
-
goto err_put_evdev;
-
}
-
-
spin_lock_init(&client->buffer_lock);
-
client->evdev = evdev;
-
-
evdev_attach_client(evdev, client);
-
-
error = evdev_open_device(evdev);
-
if (error)
-
goto err_free_client;
-
-
file->private_data = client;
-
return 0;
-
-
err_free_client:
-
evdev_detach_client(evdev, client);
-
kfree(client);
-
err_put_evdev:
-
put_device(&evdev->dev);
-
return error;
-
}
-
static int evdev_open_device(struct evdev *evdev)
-
{
-
int retval;
-
-
retval = mutex_lock_interruptible(&evdev->mutex);
-
if (retval)
-
return retval;
-
-
if (!evdev->exist)
-
retval = -ENODEV;
-
else if (!evdev->open++) {
-
retval = input_open_device(&evdev->handle);
-
if (retval)
-
evdev->open--;
-
}
-
-
mutex_unlock(&evdev->mutex);
-
return retval;
-
}
-
int input_open_device(struct input_handle *handle)
-
{
-
struct input_dev *dev = handle->dev;
-
int retval;
-
-
retval = mutex_lock_interruptible(&dev->mutex);
-
if (retval)
-
return retval;
-
-
if (dev->going_away) {
-
retval = -ENODEV;
-
goto out;
-
}
-
-
handle->open++;
-
-
if (!dev->users++ && dev->open)
-
retval = dev->open(dev);
-
-
if (retval) {
-
dev->users--;
-
if (!--handle->open) {
-
-
-
-
-
synchronize_rcu();
-
}
-
}
-
-
out:
-
mutex_unlock(&dev->mutex);
-
return retval;
-
}
阅读(1045) | 评论(0) | 转发(0) |