Linux输入子系统分析(四)

来源:互联网 发布:手机手写画图软件 编辑:程序博客网 时间:2024/05/07 02:15
输入子系统事件驱动
   通过前面的学习,我们知道输入子系统有三个部分:输入设备驱动、输入核心、输入事件驱动。相信对前面的学习,对输入设备驱动能够大体理解。上节中我们已经知道了输入设备如何通过输入核心把事件传递给handler了,这本节开始我们学习输入事件驱动如何处理这些事件,如何与应用程序通信。
1、重要数据结构
     首先介绍input_handle,这个结构体用来连接input_devinput_handler 
       /* include/linux/input.h */
/**
 * struct input_handle - links input device with an input handler
 * @private: handler-specific data
 * @open: counter showing whether the handle is 'open', i.e. should deliver
 * events from its device
 * @name: name given to the handle by handler that created it
 * @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;

struct input_dev *dev;
struct input_handler *handler;

struct list_headd_node;
struct list_headh_node;
};
我们知道input_devinput_handler匹配过程中用到了input_device_id,现在就来看看input_device_id
struct input_device_id {

kernel_ulong_t flags;

        //对应input_id的四个数据域
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;

        //存储支持事件的位图,与input_dev中的同名数据成员功能一致
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
        
        //指示结构体中是否含有驱动信息
kernel_ulong_t driver_info;
}

input_handler这个结构体是事件驱动的主体,每一种处理方式对应一个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
 * @filter: similar to @event; separates normal event handlers from
 * "filters".
 * @match: called after comparing device's id with handler's id_table
 * to perform fine-grained matching between device and handler
 * @connect: called when attaching a handler to an input device
 * @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
 * @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
 * @h_list: list of input handles associated with the handler
 * @node: for placing the driver onto 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.
 *
 * The very same structure is used to implement input filters. Input core
 * allows filters to run first and will not pass event to regular handlers
 * if any of the filters indicate that the event should be filtered (by
 * returning %true from their filter() method).
 *
 * 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);
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);

const struct file_operations *fops;
int minor;
const char *name;

const struct input_device_id *id_table;


struct list_headh_list;
struct list_headnode;
};

2、input_handler注册
这里介绍下存放注册的input_handler所用的数据结构--->input core全局数据。
/*drivers/input/input.c*/

#define INPUT_DEVICES256           //系统支持的输入设备
static LIST_HEAD(input_dev_list);           //设备链表头
static LIST_HEAD(input_handler_list);     //handler链表头
/*
 * input_mutex protects access to both input_dev_list and input_handler_list.
 * This also causes input_[un]register_device and input_[un]register_handler
 * be mutually exclusive which simplifies locking in drivers implementing
 * input handlers.
 */
static DEFINE_MUTEX(input_mutex);          //保护以上两个链表  
static struct input_handler *input_table[8];    //存放注册的input_handler的指针数组

        input_register_device()注册的input_dev结构体加入到上面的input_dev_list当中,下面将要介绍的注
input_handler,其实就是将input_hangler加入到input_handler_list当中。input_table中存放进行文件操作的handler,使用它们次设备号的最高三比特在input_table中寻址,因此每个handler最多支持32个设备节点。由上面的代码可以看出输入子系统最多允许8个进行文件操作的input_handler同时存在。

/**
 * input_register_handler - register a new 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;
       //初始化handler中的链表节点,为加入input_handler_list做准备
INIT_LIST_HEAD(&handler->h_list);
        //如果此handler需要进行文件操作
if (handler->fops != NULL) {
                //如果相应的次设备号段被占用
if (input_table[handler->minor >> 5]) {
retval = -EBUSY;
goto out;
}
                //handler注册进input_table
input_table[handler->minor >> 5] = handler;
}
        //handler加入input_handler_list链表
list_add_tail(&handler->node, &input_handler_list);
        //遍历input_dev_list链表中的每一个input_dev结构体
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); //handler与每一个input_dev进行匹配

input_wakeup_procfs_readers();

 out:
mutex_unlock(&input_mutex);
return retval;
}

总结一下input_handler的注册过程:把自己加入input_handler_listinput_table,然后与input_dev_list中的input_dev比较并与匹配的建立连接。

结合前面小节我们发现input_devinput_handler都是将自己加入各自的链表,然后再和对方链表中匹配的进行连接。


原创粉丝点击