linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(2)
2012-05-27 22:23
591 查看
linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)的地址链接
1、上一篇说到了input_match_device函数,这篇接着来分析它的源码,如下所示:
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++) { 循环,用来匹配id和dev->id中的信息
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) id->flags中定义了要匹配的项
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) 匹配产品ID
if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) 匹配版本号
if (id->version != dev->id.version)
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;
从MATCH_BIT宏的定义可以看出。只有当iput device和input handler的id成员在evbit、keybit、… swbit项相同才会匹配成功。而且匹配的顺序是从evbit、keybit到swbit。只要有一项不同,就会循环到id中的下一项进行比较。
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;
}
注册input device的过程就是为input device设置默认值,并将其挂以input_dev_list。与挂载在input_handler_list中的handler相匹配。如果匹配成功,就会调用handler的connect函数。
2、还记得在上一篇“linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)”中的这个函数吗?按键的中断处理函数
static irqreturn_t button_interrupt(int
irq, void *dummy) 中断处理函数
{
input_report_key(button_dev,
BTN_0, inb(BUTTON_PORT) & 1);向输入子系统报告产生按键事件,该函数第1个参数是产生事件的输入设备,第2个参数是产生的事件,第3个参数是事件的值。当第2个参数为按键时,第
3个参数表示按键的状态,value值为0表示按键释放,非0表示按键按下。
源码如下:
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);input_event函数源码如下:
/**
* input_event() - report new input event 向输入子系统报告输入设备产生的事件
* @dev: device that generated the event 产生事件的输入设备
* @type: type of the event 事件的类型
* @code: event code 产生的事件
* @value: value of the event 事件的值和上面一样
*
* This function should be used by drivers implementing various input
* devices. See also input_inject_event().
*/
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX))
该函数检查输入设备是否支持事件,源码如下所示:
static inline int is_event_supported(unsigned int code,
unsigned long *bm, unsigned int max)
{
return code <= max && test_bit(code, bm);
}该函数检查input_dev.evbit中的相应位是否设置,如果设置返回1,否则返回0。每一种类型的事件都在input_dev.evbit 中用一个位来表示,构成一个位图,如果某位为1,表示该输入设备支持这类事件,如果为0,表示输入设备不支持这类事件。
还记得上一篇中的这个吗:button_dev->evbit[0]
= BIT_MASK(EV_KEY); 这就是用来设置输入设备button_dev所支持的事件类型,其中有定义:
#define BIT_MASK(nr)
(1UL << ((nr) % BITS_PER_LONG))
#define BITS_PER_LONG 32
input_dev.evdit支持的事件表示方法:
{
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);有随机数有关
input_handle_event(dev, type, code, value);向输入子系统传送事件信息,第1个参数是输入设备input_dev,第2个参数是事件的类型,第3个参数是键码,第4个参数是键值。函数源码如下:
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT; 该变量表示使用什么样的方式处理事件
switch (type) { 对不同的事件类型,分别处理
case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
}
break;
case EV_KEY: 对EV_KEY事件进行处理。
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
is_event_supported()函数判断是否支持该按键。 test_bit()函数来测试按键状态是否改变
在上一篇中还有这样的定义:button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
if (value != 2) {
__change_bit(code, dev->key);改变键的状态
if (value)
input_start_autorepeat(dev, code);处理重复按键的情况
}
disposition = INPUT_PASS_TO_HANDLERS;设置该变量,表示事件需要handler来处理,其中disposition变量的值可以去一下几种:
#define INPUT_IGNORE_EVENT
0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
INPUT_IGNORE_EVENT表示忽略事件,不对其进行处理。INPUT_PASS_ TO_HANDLERS表示将事件交给handler处理。INPUT_PASS_TO_DEVICE表示将事件
交给input_dev处理。INPUT_PASS_TO_ALL表示将事件交给handler和input_dev共同处理。
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
判断disposition等于INPUT_PASS_TO_DEVICE,然后判断dev->event是否对其指定了一个处理函数,如果这些条件都满足,则调用自定义的dev->event()函数处理事件。
if (disposition & INPUT_PASS_TO_HANDLERS) 如果事件需要handler处理,则调用input_pass_event()函数
input_pass_event(dev, type, code, value);此函数将事件传递到合适的函数,然后对齐进行处理,源码如下:
/*
* Pass event through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);得到dev->grab的指针
if (handle)
handle->handler->event(handle, type, code, value); 调用handler的event函数
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
如果没有为input device强制指定handler,即为grab赋值,就会遍历input device->h_list上的handle成员。看下图:
rcu_read_unlock();
}
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
}
input_sync(button_dev); 通知接受者,一个事件完毕
return IRQ_HANDLED;
}
1、上一篇说到了input_match_device函数,这篇接着来分析它的源码,如下所示:
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++) { 循环,用来匹配id和dev->id中的信息
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) id->flags中定义了要匹配的项
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) 匹配产品ID
if (id->product != dev->id.product)
continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) 匹配版本号
if (id->version != dev->id.version)
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;
从MATCH_BIT宏的定义可以看出。只有当iput device和input handler的id成员在evbit、keybit、… swbit项相同才会匹配成功。而且匹配的顺序是从evbit、keybit到swbit。只要有一项不同,就会循环到id中的下一项进行比较。
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;
}
注册input device的过程就是为input device设置默认值,并将其挂以input_dev_list。与挂载在input_handler_list中的handler相匹配。如果匹配成功,就会调用handler的connect函数。
2、还记得在上一篇“linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)”中的这个函数吗?按键的中断处理函数
static irqreturn_t button_interrupt(int
irq, void *dummy) 中断处理函数
{
input_report_key(button_dev,
BTN_0, inb(BUTTON_PORT) & 1);向输入子系统报告产生按键事件,该函数第1个参数是产生事件的输入设备,第2个参数是产生的事件,第3个参数是事件的值。当第2个参数为按键时,第
3个参数表示按键的状态,value值为0表示按键释放,非0表示按键按下。
源码如下:
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);input_event函数源码如下:
/**
* input_event() - report new input event 向输入子系统报告输入设备产生的事件
* @dev: device that generated the event 产生事件的输入设备
* @type: type of the event 事件的类型
* @code: event code 产生的事件
* @value: value of the event 事件的值和上面一样
*
* This function should be used by drivers implementing various input
* devices. See also input_inject_event().
*/
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX))
该函数检查输入设备是否支持事件,源码如下所示:
static inline int is_event_supported(unsigned int code,
unsigned long *bm, unsigned int max)
{
return code <= max && test_bit(code, bm);
}该函数检查input_dev.evbit中的相应位是否设置,如果设置返回1,否则返回0。每一种类型的事件都在input_dev.evbit 中用一个位来表示,构成一个位图,如果某位为1,表示该输入设备支持这类事件,如果为0,表示输入设备不支持这类事件。
还记得上一篇中的这个吗:button_dev->evbit[0]
= BIT_MASK(EV_KEY); 这就是用来设置输入设备button_dev所支持的事件类型,其中有定义:
#define BIT_MASK(nr)
(1UL << ((nr) % BITS_PER_LONG))
#define BITS_PER_LONG 32
input_dev.evdit支持的事件表示方法:
{
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);有随机数有关
input_handle_event(dev, type, code, value);向输入子系统传送事件信息,第1个参数是输入设备input_dev,第2个参数是事件的类型,第3个参数是键码,第4个参数是键值。函数源码如下:
static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition = INPUT_IGNORE_EVENT; 该变量表示使用什么样的方式处理事件
switch (type) { 对不同的事件类型,分别处理
case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
}
break;
case EV_KEY: 对EV_KEY事件进行处理。
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
is_event_supported()函数判断是否支持该按键。 test_bit()函数来测试按键状态是否改变
在上一篇中还有这样的定义:button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
if (value != 2) {
__change_bit(code, dev->key);改变键的状态
if (value)
input_start_autorepeat(dev, code);处理重复按键的情况
}
disposition = INPUT_PASS_TO_HANDLERS;设置该变量,表示事件需要handler来处理,其中disposition变量的值可以去一下几种:
#define INPUT_IGNORE_EVENT
0
#define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2
#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
INPUT_IGNORE_EVENT表示忽略事件,不对其进行处理。INPUT_PASS_ TO_HANDLERS表示将事件交给handler处理。INPUT_PASS_TO_DEVICE表示将事件
交给input_dev处理。INPUT_PASS_TO_ALL表示将事件交给handler和input_dev共同处理。
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
判断disposition等于INPUT_PASS_TO_DEVICE,然后判断dev->event是否对其指定了一个处理函数,如果这些条件都满足,则调用自定义的dev->event()函数处理事件。
if (disposition & INPUT_PASS_TO_HANDLERS) 如果事件需要handler处理,则调用input_pass_event()函数
input_pass_event(dev, type, code, value);此函数将事件传递到合适的函数,然后对齐进行处理,源码如下:
/*
* Pass event through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);得到dev->grab的指针
if (handle)
handle->handler->event(handle, type, code, value); 调用handler的event函数
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle,
type, code, value);
如果没有为input device强制指定handler,即为grab赋值,就会遍历input device->h_list上的handle成员。看下图:
rcu_read_unlock();
}
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
}
input_sync(button_dev); 通知接受者,一个事件完毕
return IRQ_HANDLED;
}
相关文章推荐
- linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux 输入子系统(2)----简单实例分析系统结构(input_dev层)
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- [转]linux 输入子系统驱动实例分析--gpio keys
- linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- linux驱动---Input 输入子系统
- Linux输入子系统——按键驱动实例
- linux驱动——input输入子系统(1)—输入子系统核心层(Input Core)
- Linux输入子系统(5):设备驱动层实例之触摸屏驱动