分别是总线类型、厂商号、产品号和版本号。

1156行,evbit,设备支持的事件类型的位图,每一位代表一种事件,比如EV_KEY、EV_REL事件等等。BITS_TO_LONGS(nr)是一个宏,假设long型变量为32位,1位可以表示一种事件,那么这个宏的意思就是nr种事件需要用多少个long型变量来表示。EV_CNT的值为0x1f+1,因此BITS_TO_LONGS(0x1f+1)的值就为1。

1157行,keybit,设备拥有的按键的位图,每一位代表一个按键。

1158行,relbit,设备拥有的相对轴的位图,每一位代表一个相对轴。

1159行,absbit,设备拥有的绝对轴的位图,每一位代表一个绝对轴。

1160行,mscbit,设备支持的杂项事件位图。

1161行,ledbit,设备拥有的LED位图。

1162行,sndbit,设备支持的音效位图。

1163行,ffbit,1164行,swbit,不说了,对于本文只需要关注evbit和keybit即可,其他那些只需要有个印象,等用到的时候自然就明白了。

1166行,hint_events_per_packet,输入事件到达事件驱动程序的时候会存放在一个缓冲区里,这里表示这个缓冲区的大小。

1168行,keycodemax,键码表的大小。

1169行,keycodesize,键码表元素的大小。

1170行,扫描码到键码的映射。

1171、1173行,设置和获取键码的函数指针。

1176至1187行,与本文没什么关系,略过吧。

1189至1192行,表示当前状态的位图。

1194至1197行,一些函数指针,用到再说。

1199行,grab,这有点意思,表示设备拥有的input handle,当输入事件准备传递给事件驱动程序时会input core会先判断设备是否拥有了input handle,如果有,则把事件投递给该handle来处理,否则,遍历所有已经注册了的handle,每遍历到一个handle,就把事件投递给它。

1204行,users,计数,每打开设备一次,计数加1,关闭设备,计数减1。

1207行,sync,当为true时表示自从上一次同步以来再也没有新的输入事件产生。

1209行,dev,嵌入到设备模型中用的。

1211行,设备拥有的handle,这些handle以链表的形式连接在一起。从这可以看出,一个设备是可以拥有多个handle的。

1212行,node,作为input_dev_list这个全局链表的节点使用,从而把系统中的所有Input设备连成一个链表。

回到input_allocate_device函数,1559行,为Input设备分配内存。

1561行,指定设备的类型为input_dev_type。

1562行,还记得Input子系统初始化时注册的那个input_class没?就是这么用的。

1563行,用设备模型的函数初始化设备。

1564至1567行,锁和链表的初始化。

1569行,啥也没做,是一个空函数。

回到gpio_keys_probe函数,456至460行,如果申请内存失败或者分配设备失败,那么就释放之前申请的内存,返回出错。

462至480行,一些赋值,不细说了。

483行,如果支持按键自动重复,则设置evbit位图中的相应位为1。

486行,循环的次数等于按键的个数。

489行,事件类型默认为按键类型(EV_KEY)。

494行,gpio_keys_setup_key函数的定义:

 static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
{
char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
unsigned long irqflags;
int irq, error; setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
INIT_WORK(&bdata->work, gpio_keys_work_func); error = gpio_request(button->gpio, desc);
if (error < ) {
dev_err(dev, "failed to request GPIO %d, error %d\n",
button->gpio, error);
goto fail2;
} error = gpio_direction_input(button->gpio);
if (error < ) {
dev_err(dev, "failed to configure"
" direction for GPIO %d, error %d\n",
button->gpio, error);
goto fail3;
} if (button->debounce_interval) {
error = gpio_set_debounce(button->gpio,
button->debounce_interval * );
/* use timer if gpiolib doesn't provide debounce */
if (error < )
bdata->timer_debounce = button->debounce_interval;
} irq = gpio_to_irq(button->gpio);
if (irq < ) {
error = irq;
dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
button->gpio, error);
goto fail3;
} irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
/*
00000407 * If platform has specified that the button can be disabled,
00000408 * we don't want it to share the interrupt line.
00000409 */
if (!button->can_disable)
irqflags |= IRQF_SHARED; error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
if (error) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
irq, error);
goto fail3;
} return ; fail3:
gpio_free(button->gpio);
fail2:
return error;
}

371行,初始化按键定时器,定时器超时处理函数为gpio_keys_timer,函数的参数为bdata。之前说了,该定时器是用到延时消抖的。所谓延时消抖就是说当按键按下时,由于按键的机械特性会存在抖动,造成多次按下和抬起,因此当延时适当的时间后,如果按键仍然处于按下状态,那么就认为按键真的按下了,这是一种软件消抖的方法,当然,还有硬件消抖的方法。

372行,初始化按键的工作节点,使用系统默认的工作队列。

374至379行,申请IO口,如果IO口被占用,那么该IO口就不能用作按键的输入。

381至387行,设置IO口为输入功能。

389行,如果按键有设置延时的话那么就执行390行通过gpiolib的gpio_set_debounce函数来设置延时,如果有些平台不支持gpiolib,那么执行394行,通过定时器来实现延时。

397至403行,获取IO口对应的中断号。

405行,设置上升沿和下降沿都将触发中断的标志。

410、411行,如果IO口(按键)可以被失能的话,那么就不要设置共享中断标志,即此IO口独占一条中断线。

413至418行,申请中断,中断处理函数为gpio_keys_isr,函数的其中一个参数为bdata。

至此,gpio_keys_setup_key函数说完了,回到gpio_keys_probe函数,498、491行,如果按键可以作为唤醒源,那么设置wakeup变量为1,马上就会用到。

501行,调用drivers/input/input.c中的input_set_capability函数,定义如下:

 void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
switch (type) {
case EV_KEY:
__set_bit(code, dev->keybit);
break; case EV_REL:
__set_bit(code, dev->relbit);
break; case EV_ABS:
__set_bit(code, dev->absbit);
break; case EV_MSC:
__set_bit(code, dev->mscbit);
break; case EV_SW:
__set_bit(code, dev->swbit);
break; case EV_LED:
__set_bit(code, dev->ledbit);
break; case EV_SND:
__set_bit(code, dev->sndbit);
break; case EV_FF:
__set_bit(code, dev->ffbit);
break; case EV_PWR:
/* do nothing */
break; default:
printk(KERN_ERR
"input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
} __set_bit(type, dev->evbit);
}

很明显的排比句,根据按键支持的事件设置按键表示的键值,最后再设置按键支持的事件。通俗地说,按键产生的是按键事件(EV_KEY),一个按键只能代表一个键值,比如键盘上的F1、F2等等。

回到gpio_keys_probe函数,504至509行,sysfs文件系统相关的,简单地说,sysfs_create_group函数就是在/sys相应的目录下创建一些文件,这样就可以在用户空间通过echo或cat来设置或者读取驱动中的一些参数。

511至516行,调用input_register_device函数注册Input设备,定义如下:

 int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT();
struct input_handler *handler;
const char *path;
int error; /* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit); /* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit); /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev); /*
00001751 * If delay and period are pre-set by the driver, then autorepeating
00001752 * is handled by the driver itself and we don't do it in input.c.
00001753 */
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] = ;
dev->rep[REP_PERIOD] = ;
} 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) - ); 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 ;
}

1736行,注意,这是一个static型变量,就是说当函数返回时它所占用的内存不会释放,它的值会维持不变,并且只会被初始化一次,第一次进该函数时input_no=0,第二次进时input_no=1,以此类推。

1737行,遇到了一个新的结构体struct input_handler,它定义了输入设备的接口,主要用在事件驱动程序中,它的定义在include/linux/input.h中:

 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_head h_list;
struct list_head node;
};

1306行,private,驱动的私有数据指针。

1308至1313行,一些函数指针,其中,event是Input core向事件驱动程序传递消息时调用的函数。

1315行,fops,事件驱动实现的文件操作集。

1316行,minor,次设备号的起始值。

1317行,name,handler的名字,会出现在/proc/bus/input/handlers。

1319行,id_table,事件驱动支持的id table。

1321行,h_list,将所有handle连接起来。

1322行,node,作为全局链表input_handler_list的节点,input_handler_list将所有handler节点连成一个双向循环链表。

容易被这里的链表弄晕,索性一次把它讲清楚,下面看struct input_handle的定义,注意,是handle,不是handler。

 struct input_handle {

     void *private;

     int open;
const char *name; struct input_dev *dev;
struct input_handler *handler; struct list_head d_node;
struct list_head h_node;
};

1339行,private,handler的私有数据指针。

1341行,open,handle的打开计数。

1342行,name,handle的名字。

1344行,dev,此handle依附的Input设备。

1345行,handler,通过此handle与设备进行交互的handler。

1347,d_node,1348,h_node,细心的话可以发现在说struct input_dev时也有两个关于链表的成员,而struct input_handler和struct input_handle也有两个关于链表的成员,它们三者形成的关系如下图所示:

应该很清楚了吧,这里只以其中的一个input_dev和handler为例画出来的图,其他的以此类推。其中input_dev_list和input_handler_list是两条全局的链表,每当调用input_register_device函数时会将Input设备加入到input_dev_list链表的尾部;每当调用input_register_handler函数时会将handler加入到input_handler_list链表的尾部;每当调用input_register_handle函数时会将handle加入到其对应的Input设备的h_list链表的尾部,并且还会该handle加入到其对应的handler的h_list链表的尾部。

回到input_register_device函数,1742行,设置事件位图的同步事件位为1,表示设备支持同步事件。

1745行,清0保留的键值,该键值不会被发送到用户空间。

1748行,清0事件位图中没有设置的位。

1754行,初始化设备的定时器。

1755至1760行,如果dev->rep[REP_DELAY]和dev->rep[REP_PERIOD]的值都为0,那么就给他们和定时器设置一些默认值,具体的函数和变量等用到的时候再说。

1762至1766行,如果dev->getkeycode和dev->setkeycode这两个函数指针没有设置,就为它们赋默认值。

1771行,将设备加入到设备模型中,关于设备模型的就略过了,下文也如此。

1786行,看到了吧,将Input设备加入到input_dev_list链表的尾部。

1788、1789行,遍历input_handler_list链表,每找到一个节点就调用input_attach_handler函数,它的定义如下:

 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error; id = input_match_device(handler, 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;
}

842行,struct input_device_id,关于这个结构体这里就不说了,不过可以看下它的定义,在include/input/mod_devicetable.h中:

 struct input_device_id {

     kernel_ulong_t flags;

     __u16 bustype;
__u16 vendor;
__u16 product;
__u16 version; kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + ];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + ];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + ];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + ];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + ];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + ];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + ];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + ];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + ]; kernel_ulong_t driver_info;
};

845行,调用input_match_device函数,定义如下:

 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; for (id = handler->id_table; 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); if (!handler->match || handler->match(handler, dev))
return id;
} return NULL;
}

805行,循环handler的id_table数组的每一项。

807至821行,都是检查handler的flags标志的,意思也很明显,不多说了。

823至831行,只要弄懂第一个就行了,其他的都是一样的,下面看MATCH_BIT这个宏的定义:

 #define MATCH_BIT(bit, max) \
for (i = ; 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(evbit,  EV_MAX);为例,把宏展开后是这样的:

         for (i = ; i < BITS_TO_LONGS(EV_MAX); i++)
if ((id->evbit [i] & dev->evbit [i]) != id->evbit [i])
break;
if (i != BITS_TO_LONGS(EV_MAX))
continue;

以id->evbit[i]的值为准,如果id-evbit[i]不等于dev-evbit[i],那么跳出793行的for循环,接着判断796行,如果条件不成立,那么后面的就不用比较了,直接进行id_table数组的下一个元素的比较。

824至831行,和上面相同。

833行,至少要满足其中一个条件,否则Input设备就不能与handler匹配。

回到input_attach_handler函数,849行,调用handler的connect函数,等讲事件驱动程序evdev.c的时候再讲。

回到input_register_device函数,1791行,proc文件系统相关的,略过。至此,input_register_device函数讲完了,回到gpio_keys_probe函数,这里把剩下的代码贴出来,省得再回去看。

最新文章

  1. 温故知新--计算机网络 iso/osi七层模型 tcp/ip四层模型
  2. py-faster-rcnn +cudnn V5
  3. php案列分享
  4. ansible解密
  5. node.js整理 04网络操作
  6. Delphi调用REST
  7. NServiceBus教程-持久化配置
  8. linux下挂载移动硬盘ntfs格式
  9. 如何评估oracle AWR 的在oracle 中的存储情况
  10. 玩转html5(一)-----盘点html5新增的那些酷酷的input类型和属性
  11. PHP7 ?:和??的区别
  12. Docker Compose 常用命令
  13. linux 新建用户、用户组 以及为新用户分配权限的基本操作
  14. Always On 集群监听创建失败问题
  15. reveal破解
  16. mysql创建定时器(event),查看定时器,打开定时器,设置定时器时间
  17. PHP报错Deprecated: Function ereg_replace() is deprecated in
  18. BZOJ5125: [Lydsy1712月赛]小Q的书架(DP决策单调性)
  19. 转载:Spring使用p名称空间配置属性
  20. 安装一个apk文件源代码

热门文章

  1. Android导入第三方静态库.a编译成动态库.so
  2. Asp.Net JsonResult重写
  3. 学习率设置&amp;&amp;训练模型之loss曲线滑动平均
  4. 《A.I.爱》王力宏与人工智能谈恋爱 邀李开复来客串
  5. JAVA通过oshi获取系统和硬件信息
  6. 单反毁三代,kindle富一生
  7. 【tp5】tp5实现空模块、空控制器、空操作的页面404跳转
  8. sysbench做测试
  9. mechanize (1)
  10. 11G新特性 -- Expression Statistics