先看框架图:
再看看代码中的结构:
分析 一下Input_dev结构(include/linux/input.h):
struct input_dev {
const char *name; //设备名
const char *phys; //设备系统层的物理路径
const char *uniq;
struct input_id id; //输入设备ID 总线类型;厂商编号,产品ID,产品版本
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //事件类型标志位
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //键盘事件标志位
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对位移事件标志位
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对位移事件标志位
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //杂项事件标志位
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //led指示灯标志位
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //声音事件
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //强制反馈事件
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //开关事件标志位
unsigned int hint_events_per_packet;
unsigned int keycodemax; //键盘码表大小
unsigned int keycodesize; //键盘码大小
void *keycode; //键盘码表指针
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode); //设置键盘码
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke); //获取键盘码
struct ff_device *ff; //强制反馈设备
unsigned int repeat_key; //重复按键标志位
struct timer_list timer; //定时器
int rep[REP_CNT]; //重复次数
struct input_mt *mt;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev; //设备文件
struct list_head h_list; //input_handler 处理器链表头
struct list_head node; //input_device 设备链表头
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
};
Input_handler结构:
struct input_handler {
void *private; //私有数据
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); //事件处理
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
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);
bool legacy_minors;
int minor; //次设备号
const char *name; //设备名
const struct input_device_id *id_table; //输入设备ID表
struct list_head h_list; //input_handler处理器链表头
struct list_head node; //input_device设备链表头
};
Input的初始化:
static int __init input_init(void)
{
int err;
err = class_register(&input_class); //类的注册
if (err) {
pr_err("unable to register input_dev class\n");
return err;
}
err = input_proc_init(); //在proc中初始化
if (err)
goto fail1;
err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
INPUT_MAX_CHAR_DEVICES, "input"); //设备号的注册
if (err) {
pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2;
}
return 0;
fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}
input_class:
static char *input_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
}
struct class input_class = {
.name = "input",
.devnode = input_devnode,
};
EXPORT_SYMBOL_GPL(input_class);
以下可以看到都注册到input目录下。
input_proc_init:
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
proc_bus_input_dir = proc_mkdir("bus/input", NULL);
if (!proc_bus_input_dir)
return -ENOMEM;
entry = proc_create("devices", 0, proc_bus_input_dir,
&input_devices_fileops);
if (!entry)
goto fail1;
entry = proc_create("handlers", 0, proc_bus_input_dir,
&input_handlers_fileops);
if (!entry)
goto fail2;
return 0;
fail2: remove_proc_entry("devices", proc_bus_input_dir);
fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
以下可以看出,从上面的input_proc_init中在bus下创建imput目录,并在input下创建devices与handlers两个proc的虚拟文件节点。
其中input_devices_fileops:
static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
.stop = input_seq_stop,
.show = input_devices_seq_show,
};
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_devices_seq_ops);
}
static const struct file_operations input_devices_fileops = {
.owner = THIS_MODULE,
.open = input_proc_devices_open,
.poll = input_proc_devices_poll,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
input_handlers_fileops:
static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
.stop = input_seq_stop,
.show = input_handlers_seq_show,
};
static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_handlers_seq_ops);
}
static const struct file_operations input_handlers_fileops = {
.owner = THIS_MODULE,
.open = input_proc_handlers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
剩下的就是文件相关操作与事件上报过程。下次再分析。