前言
基于韦东山视频的简单总结
内核基于 Linux2.6.22
框架
左边是基于各种接口的输入设备,比如 USB 鼠标,蓝牙鼠标,2.4G 鼠标等
右边呢则是封装了统一设备层,这些乱七八槽的接口键盘,统一都由鼠标类处理。
左边注册流程:
1. input_allocate_device(): 分配 input_dev
2. 设置 input_dev
3. input_register_device(): 注册 input_dev
右边注册流程:
1. 创建一个 input_handler
2. 注册 input_handler
两边连接: connect() 创建如下结构体管理
左右就通过如下结构管理的:
handle{
input device: 左边
input handler: 右边
}
左边:通过一个全局链表 input_dev_list 管理
右边:通过一个全局链表 input_handler_list 管理
流程汇总
右边通用驱动注册流程
参考代码: Evdev.c (linux-2.6.22.6\drivers\input)
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
module_init(evdev_init);
左边具体驱动注册流程
1. input_allocate_device(): 分配 input_dev
2. 设置 input_dev
3. input_register_device(): 注册 input_dev
参考代码: Gpio_keys.c (drivers\input\keyboard)
///////////////////////////////////////////////////////////////////////////////
// 以一个普通的按键驱动为例
module_init(gpio_keys_init);
static int __init gpio_keys_init//(void)
{
return platform_driver_register(&gpio_keys_device_driver);
struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.driver = {
.name = "gpio-keys",
}
};
}
// 平台设备匹配后调用 probe 函数
static int __devinit gpio_keys_probe//(struct platform_device *pdev)
{
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
int i, error;
////////////////////////////////////////////////////////
// 1. 分配 input_dev
// 为新的输入设备分配内存
input = input_allocate_device();
struct input_dev *input_allocate_device//(void)
{
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev->cdev.class = &input_class;
dev->cdev.groups = input_dev_attr_groups;
class_device_initialize(&dev->cdev);
mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
}
return dev;
}
if (!input)
return -ENOMEM;
platform_set_drvdata(pdev, input);
////////////////////////////////////////////////////////
// 2. 设置 input_dev
// 能产生哪类事件
input->evbit[0] = BIT(EV_KEY);
input->name = pdev->name;
input->phys = "gpio-keys/input0";
input->dev.parent = &pdev->dev;
// 匹配用的 id
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
int irq = gpio_to_irq(button->gpio);
unsigned int type = button->type ?: EV_KEY;
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
// 注册按键中断,当有按键发生时调用
error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, button->desc ? button->desc : "gpio_keys", pdev);
if (error) {
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
irq, error);
goto fail;
}
input_set_capability(input, type, button->code);
}
////////////////////////////////////////////////////////
// 3. 注册 input_dev
error = input_register_device(input);
int input_register_device//(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);// static 这样就会自增了,在 bss 段应该
struct input_handler *handler;
const char *path;
int error;
set_bit(EV_SYN, dev->evbit);
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
// 初始化定时器
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;
// 将 input_dev 放入全局链表 input_dev_list 中管理
list_add_tail(&dev->node, &input_dev_list);
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
if (!dev->cdev.dev)
dev->cdev.dev = dev->dev.parent;
error = class_device_add(&dev->cdev);
if (error)
return error;
path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
// 遍历系统中的 handler,查找是否有对应的 handle,即设备驱动可以处理这个设备
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
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;
/* 注册 input_dev 或 input_handler 时,会两两比较左边的 input_dev 和右边的 input_handler,
根据 input_handler 的【id_table】判断这个 input_handler 能否支持这个 input_dev,
如果能支持,则调用 input_handler 的 connect 函数建立"连接"*/
// 比较 handler->id_table 与 dev,
id = input_match_device(handler->id_table, dev);
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;
}
if (!id)
return -ENODEV;
// 调用 handler 的 connect() 函数,将其挂入 handle.input_dev 链表中
error = handler->connect(handler, dev, id);
/*
connect 怎么建立连接?
1. 分配一个 input_handle 结构体
2.
input_handle.dev = input_dev; // 指向左边的 input_dev
input_handle.handler = input_handler; // 指向右边的 input_handler
3. 注册:
input_handler->h_list = &input_handle;
inpu_dev->h_list = &input_handle;
*/
// 以 event 驱动为例:
static int evdev_connect//(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
dev_t devt;
int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
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);
init_waitqueue_head(&evdev->wait);
// 设置,在驱动层保存驱动程序与设备的对应关系 handle: handler / input dev
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
sprintf(evdev->name, "event%d", minor);
evdev_table[minor] = evdev;
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
cdev = class_device_create(&input_class, &dev->cdev, devt,
dev->cdev.dev, evdev->name);
if (IS_ERR(cdev)) {
error = PTR_ERR(cdev);
goto err_free_evdev;
}
/* temporary symlink to keep userspace happy */
error = sysfs_create_link(&input_class.subsys.kobj,
&cdev->kobj, evdev->name);
if (error)
goto err_cdev_destroy;
// 只是将其添加到 handle 双链表中,如果有 handler->star ,则会调用。
error = input_register_handle(&evdev->handle);
int input_register_handle//(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
list_add_tail(&handle->d_node, &handle->dev->h_list);
list_add_tail(&handle->h_node, &handler->h_list);
if (handler->start)
handler->start(handle);
return 0;
}
if (error)
goto err_remove_link;
return 0;
err_remove_link:
sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
err_cdev_destroy:
class_device_destroy(&input_class, devt);
err_free_evdev:
kfree(evdev);
evdev_table[minor] = NULL;
return error;
}
input_wakeup_procfs_readers();
return 0;
}
if (error) {
printk(KERN_ERR "Unable to register gpio-keys input device\n");
goto fail;
}
return 0;
fail:
for (i = i - 1; i >= 0; i--)
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
input_free_device(input);
return error;
}
用户空间系统调用路由
仔细看 input.c 核心,里面注册了一个字符设备,然后只声明了一个 open() 函数
static int __init input_init(void)
/////////////////////////////////////////////////////////////////////////////////////////
// static const struct file_operations input_fops = {
// .owner = THIS_MODULE,
// .open = input_open_file,
// };
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
在 open() 函数里面,将路径到各通用程序中注册的 file_operations 结构体
// 打来按键,调用的是这里的打开函数
static int input_open_file(struct inode *inode, struct file *file)
{
// 通过子设备号获得相应的设备操作函数
struct input_handler *handler = input_table[iminor(inode) >> 5];
/**
* struct input_handler - implements one of interfaces for input devices
* @private: driver-specific data
* @event: event 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
* @blacklist: prointer 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
*/
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_head h_list;
struct list_head node;
};
const struct file_operations *old_fops, *new_fops = NULL;
int err;
/* No load-on-demand here? */
if (!handler || !(new_fops = fops_get(handler->fops)))
return -ENODEV;
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
return -ENODEV;
}
// 替换 file 结构体的 f_op,并保存,这样在以后操作就是直接操作驱动的 file_operations 结构了
old_fops = file->f_op;
file->f_op = new_fops;
// 调用驱动程序的 open() 函数
err = new_fops->open(inode, file);
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
对应按键驱动,相关操作是在 input_register_handler() 中注册的
// 而这个 open() 是在哪里设置的呢,根据匹配 id, 知道按键设备最终匹配的是 evdev.c 里的驱动
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
// static struct input_handler evdev_handler = {
// .event = evdev_event,
// .connect = evdev_connect,
// .disconnect = evdev_disconnect,
// .fops = &evdev_fops,
// static const struct file_operations evdev_fops = {
// .owner = THIS_MODULE,
// .read = evdev_read,
// .write = evdev_write,
// .poll = evdev_poll,
// .open = evdev_open,
// .release = evdev_release,
// .unlocked_ioctl = evdev_ioctl,
// #ifdef CONFIG_COMPAT
// .compat_ioctl = evdev_ioctl_compat,
// #endif
// .fasync = evdev_fasync,
// .flush = evdev_flush
// };
// .minor = EVDEV_MINOR_BASE,
// .name = "evdev",
// .id_table = evdev_ids,
// static const struct input_device_id evdev_ids[] = {
// { .driver_info = 1 }, /* Matches all devices */
// { }, /* Terminating zero entry */
// };
// };
int input_register_handler//(struct input_handler *handler)
{
struct input_dev *dev;
// 初始化链表
INIT_LIST_HEAD(&handler->h_list);
// 根据次设备号,将操作函数结构体放入数组
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5])
return -EBUSY;
input_table[handler->minor >> 5] = handler;
}
// 添加到全局数组中方便管理
list_add_tail(&handler->node, &input_handler_list);
// 遍历 input_dev 输入设备链表,并匹配
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
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;
/* 注册 input_dev 或 input_handler 时,会两两比较左边的 input_dev 和右边的 input_handler,
根据 input_handler 的【id_table】判断这个 input_handler 能否支持这个 input_dev,
如果能支持,则调用 input_handler 的 connect 函数建立"连接"*/
// 比较 handler->id_table 与 dev,
id = input_match_device(handler->id_table, dev);
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;
}
if (!id)
return -ENODEV;
// 调用 handler 的 connect() 函数, 将 handler 与对应的 input_dev 连接起来,这里是链接在 event_handler 上面
error = handler->connect(handler, dev, id);
/*
connect 怎么建立连接?
1. 分配一个 input_handle 结构体
2.
input_handle.dev = input_dev; // 指向左边的input_dev
input_handle.handler = input_handler; // 指向右边的input_handler
3. 注册:
input_handler->h_list = &input_handle;
inpu_dev->h_list = &input_handle;
*/
// 对应按键驱动,应该链接在 event_handler 下面的链表中
static int evdev_connect//(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
dev_t devt;
int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
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);
init_waitqueue_head(&evdev->wait);
// 设置,在驱动层保存驱动程序与设备的对应关系 handle: handler / input dev
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
sprintf(evdev->name, "event%d", minor);
evdev_table[minor] = evdev;
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
cdev = class_device_create(&input_class, &dev->cdev, devt,
dev->cdev.dev, evdev->name);
if (IS_ERR(cdev)) {
error = PTR_ERR(cdev);
goto err_free_evdev;
}
/* temporary symlink to keep userspace happy */
error = sysfs_create_link(&input_class.subsys.kobj,
&cdev->kobj, evdev->name);
if (error)
goto err_cdev_destroy;
// 只是将其添加到 handle 双链表中,如果有 handler->star ,则会调用。
error = input_register_handle(&evdev->handle);
int input_register_handle//(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
list_add_tail(&handle->d_node, &handle->dev->h_list);
list_add_tail(&handle->h_node, &handler->h_list);
if (handler->start)
handler->start(handle);
return 0;
}
if (error)
goto err_remove_link;
return 0;
err_remove_link:
sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
err_cdev_destroy:
class_device_destroy(&input_class, devt);
err_free_evdev:
kfree(evdev);
evdev_table[minor] = NULL;
return error;
}
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->cdev.kobj), error);
return error;
}
input_wakeup_procfs_readers();
return 0;
}
}
所以对于按键,最终调用的 open() 函数为:
// 最终调用的 open() 函数为
static int evdev_open//(struct inode *inode, struct file *file)
{
struct evdev_client *client;
struct evdev *evdev;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
evdev = evdev_table[i];
if (!evdev || !evdev->exist)
return -ENODEV;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
if (!client)
return -ENOMEM;
client->evdev = evdev;
// evdev.c 用来管理下辖设备驱动的链表
list_add_tail(&client->node, &evdev->client_list);
if (!evdev->open++ && evdev->exist) {
error = input_open_device(&evdev->handle);
if (error) {
list_del(&client->node);
kfree(client);
return error;
}
}
file->private_data = client;
return 0;
}
经过上面的折腾,读按键时则会调用, 真正的读按键了,open() 之后就调用 read()
static ssize_t evdev_read//(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
int retval;
if (count < evdev_event_size())
return -EINVAL;
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
// 等待 event 中断,如果没有数据就挂起等待
retval = wait_event_interruptible(evdev->wait, client->head != client->tail || !evdev->exist);
if (retval)
return retval;
if (!evdev->exist)
return -ENODEV;
// 这里将获得的 event 复制到用户空间去
while (client->head != client->tail && retval + evdev_event_size() <= count) {
struct input_event *event = (struct input_event *) client->buffer + client->tail;
if (evdev_event_to_user(buffer + retval, event))
return -EFAULT;
client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += evdev_event_size();
}
return retval;
}
异步唤醒上报键值
用户例子
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#include<poll.h>
#include<signal.h>
int Oflags;
int buttons_fd;
int key_value,i=0,count;
struct input_event ev_key;
void my_signal_fun(int signum)
{
printf("my_signal_fun: start!\n");
for (;;) {
printf("for()\n");
count = read(buttons_fd,&ev_key,sizeof(struct input_event));
for(i=0; i<(int)count/sizeof(struct input_event); i++)
if(EV_KEY==ev_key.type)
printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code,ev_key.value);
if(EV_SYN==ev_key.type)
{
printf("syn event\n\n");
break;
}
}
}
int main(void)
{
signal(SIGIO,my_signal_fun);
buttons_fd = open("/dev/input/event0", O_RDWR);
if (buttons_fd < 0) {
perror("open device buttons");
exit(1);
}
fcntl(buttons_fd, F_SETOWN, getpid());
Oflags = fcntl(buttons_fd, F_GETFL);
fcntl(buttons_fd, F_SETFL, Oflags | FASYNC);
while(1)
{
sleep(1000);
}
close(buttons_fd);
return 0;
}
驱动上报流程
/* 驱动程序上报按键事件
// 在设备的中断服务程序里,确定事件是什么,然后调用相应的 input_handler 的 event 处理函数
gpio_keys_isr//(int irq, void * dev_id)
// 上报事件
input_event(input, type, button->code, !!state);
input_sync(input);
*/
// 上报按键事件的函数
// 为了好看,打乱的顺序
//////////////////////////////////////////////////////////
// 第一步
input_event//(input, type, button->code, !!state);
///////////////////////////////////////////////////////////////////////////////////////
// 第二步
static inline void input_sync//(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
/**
* 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)
{
struct input_handle *handle;
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
add_input_randomness(type, code, value);
// 根据 event 事件类似,做相关处理
switch (type) {
case EV_SYN:
switch (code) {
case SYN_CONFIG:
if (dev->event)
dev->event(dev, type, code, value);
break;
case SYN_REPORT:
if (dev->sync)
return;
dev->sync = 1;
break;
}
break;
case EV_KEY:
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
return;
if (value == 2)
break;
// 置位 input_dev.key[] 表示有按键发生?
change_bit(code, dev->key);
if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
dev->repeat_key = code;
// 这里的时钟是 input_register_device() 中设置,对应处理函数为 input_repeat_key()
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
static void input_repeat_key//(unsigned long data)
{
struct input_dev *dev = (void *) data;
if (!test_bit(dev->repeat_key, dev->key))
return;
input_event(dev, EV_KEY, dev->repeat_key, 2);
input_sync(dev);
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
}
break;
case EV_SW:
if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
return;
change_bit(code, dev->sw);
break;
case EV_ABS:
if (code > ABS_MAX || !test_bit(code, dev->absbit))
return;
if (dev->absfuzz[code]) {
if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
return;
if ((value > dev->abs[code] - dev->absfuzz[code]) &&
(value < dev->abs[code] + dev->absfuzz[code]))
value = (dev->abs[code] * 3 + value) >> 2;
if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
(value < dev->abs[code] + (dev->absfuzz[code] << 1)))
value = (dev->abs[code] + value) >> 1;
}
if (dev->abs[code] == value)
return;
dev->abs[code] = value;
break;
case EV_REL:
if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
return;
break;
case EV_MSC:
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
if (dev->event)
dev->event(dev, type, code, value);
break;
case EV_LED:
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
return;
change_bit(code, dev->led);
if (dev->event)
dev->event(dev, type, code, value);
break;
case EV_SND:
if (code > SND_MAX || !test_bit(code, dev->sndbit))
return;
if (!!test_bit(code, dev->snd) != !!value)
change_bit(code, dev->snd);
if (dev->event)
dev->event(dev, type, code, value);
break;
case EV_REP:
if (code > REP_MAX || value < 0 || dev->rep[code] == value)
return;
dev->rep[code] = value;
if (dev->event)
dev->event(dev, type, code, value);
break;
case EV_FF:
if (value < 0)
return;
if (dev->event)
dev->event(dev, type, code, value);
break;
}
if (type != EV_SYN)
dev->sync = 0;
if (dev->grab)
dev->grab->handler->event(dev->grab, type, code, value);
else
// 遍历所有的 handle,如果是打开的,则调用其 event 函数,这个 handle 是在 connect 中注册的。
// 所有的 event0,event1...eventn 他用使用的都是相同的 【evdev_handler】
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
// 有数据时的唤醒位置, 这个函数在 input_event() 那层被调用,即 input.c 函数中
static void evdev_event//(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
if (evdev->grab) {
client = evdev->grab;
//////////////////////////////////////////////////////////////////////
// 在这里构造要上报给应用层的数据
/* struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
*/
do_gettimeofday(&client->buffer[client->head].time);
client->buffer[client->head].type = type;
client->buffer[client->head].code = code;
client->buffer[client->head].value = value;
client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
// 异步通知用户程序,如果有等待的话,其实就是发送信号给那个进程处理,关于信号处理,看我其他博文了
kill_fasync(&client->fasync, SIGIO, POLL_IN);
} else
list_for_each_entry(client, &evdev->client_list, node) {
do_gettimeofday(&client->buffer[client->head].time);
client->buffer[client->head].type = type;
client->buffer[client->head].code = code;
client->buffer[client->head].value = value;
client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
// 这里进行唤醒在读/写上睡眠的进程
wake_up_interruptible(&evdev->wait);
}
}
}