linux驱动——input输入子系统(1)—输入子系统核心层(Input Core)的链接地址
input_handler一般称为handler处理器,表示对输入事件的具体处理。 input_handler为输入设备的功能实现了一个接口,输入事件最终传递到handler处理器,handler处理器根据一定的规则,然后对事件进行处理。
input_handler是输入设备的事件处理接口,为处理事件提供一个统一的函数模板,程序员应该根据具体的需要实现其中的一些函数,并将其注册到输入子系统中。
1、struct input_handler结构体
/**
* struct input_handler - implements one of interfaces for input devices
* @private: driver-specific data 驱动的数据
* @event: event handler. This method is being called by input core with
* interrupts disabled and dev->event_lock spinlock held and so
* it may not sleep 被输入子系统调用去处理发送给设备的事件,不可睡眠
* @connect: called when attaching a handler to an input device用来连接handle和input device(用input_dev表示)
* @disconnect: disconnects a handler from input device 断开连接
* @start: starts handler for given handle. This function is called by
* input core right after connect() method and also when a process
* that "grabbed" a device releases it
* @fops: file operations this driver implements handler实现的文件操作集
* @minor: beginning of range of 32 minors for devices this driver
* can provide 次设备号
* @name: name of the handler, to be shown in /proc/bus/input/handlers
* @id_table: pointer to a table of input_device_ids this driver can
* handle 表示驱动能处理的表
* @blacklist: pointer to a table of input_device_ids this driver should
* ignore even if they match @id_table这个表包含了驱动应该忽略的设备
* @h_list: list of input handles associated with the handler
* @node: for placing the driver onto input_handler_list 连接到全局的 input_handler_list 链表中。
*
* Input handlers attach to input devices and create input handles. There
* are likely several handlers attached to any given input device at the
* same time. All of them will get their copy of input event generated by
* the device.
*
* Note that input core serializes calls to connect() and disconnect()
* methods.
*/
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
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);
const struct file_operations *fops;
int minor;
const char *name;
const struct input_device_id *id_table;
const struct input_device_id *blacklist;
struct list_headh_list;
struct list_headnode;
};
2、注册input_handler
input_register_handler()函数注册一个新的input handler处理器。这个handler将为输入设备使用,一个handler可以添加到多个支持它的设备中,也就是一个handler可以处理多个输入设备的事件。
函数源码在Input.c (linux2.6.28\drivers\input)文件中,如下:
/**
* input_register_handler - register a new input handler 注册一个新的input handler
* @handler: handler to be registered
*
* This function registers a new input handler (interface) for input
* devices in the system and attaches it to all input devices that
* are compatible with the handler.
*/
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
int retval;
retval = mutex_lock_interruptible(&input_mutex);加锁
if (retval)
return retval;
INIT_LIST_HEAD(&handler->h_list);初始化h_list链表
if (handler->fops != NULL) { 看到这,是否想起上一篇中说到的内容了呢?
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler; 以handler->minor右移5位作为索引值插入到input_table[ ]中
}
list_add_tail(&handler->node, &input_handler_list); 将handler加入全局的input_handler_list链表中
其中有:static LIST_HEAD(input_handler_list);
list_for_each_entry(dev, &input_dev_list, node) 其中有:static LIST_HEAD(input_dev_list);
input_attach_handler(dev, handler); input_attach_handler()这个函数的作用是匹配 input_dev_list链表中的input_dev与handler。如果成功会将input_dev与handler联系起来。
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex); 解锁
return retval;
}
3、下面来介绍struct input_handle结构体,注意与上面的区别。
/**
* struct input_handle - links input device with an input handler用来连接input_dev和input_handler
* @private: handler-specific data handler的数据
* @open: counter showing whether the handle is 'open', i.e. should deliver
* events from its device 一个变量,表示handle是否正在被使用,当使用时,会将事件分发给设备
* @name: name given to the handle by handler that created it 表示handle的名字
* @dev: input device the handle is attached to
* @handler: handler that works with the device through this handle
* @d_node: used to put the handle on device's list of attached handles
* @h_node: used to put the handle on handler's list of handles from which
* it gets events
*/
struct input_handle {
void *private;
int open;
const char *name; 表示handle的名字
struct input_dev *dev; 表示该handle依附的input_dev设备
struct input_handler *handler; 该handler处理器就是与设备相关的处理器
struct list_headd_node; 将handle放到设备相关的链表中,也就是放到input_dev->h_list表示的链表中。
struct list_headh_node; 将handle放到input_handler相关的链表中,也就是放到handler->h_list表示的链表中。
};
4、注册函数input_register_handle()
/**
* input_register_handle - register a new input handle
* @handle: handle to register
*
* This function puts a new input handle onto device's
* and handler's lists so that events can flow through
* it once it is opened using input_open_device().
*
* This function is supposed to be called from handler's
* connect() method.
*/
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex); 加锁
if (error)
return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list); 此函数将handle加入到输入设备的dev->h_list链表中。
mutex_unlock(&dev->mutex);
synchronize_rcu();
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail(&handle->h_node, &handler->h_list);此函数将handle加入input_handler的handler->h_list链表中。
if (handler->start) 如果定义了start函数,则调用它。
handler->start(handle);
return 0;
}
这样通过input_handle结构体把input_dev和input_handler连接起来了。看下图:
linux驱动——input输入子系统(3)——evdev的地址链接