struct input_dev { const char *name; const char *phys; const char *uniq; struct input_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)];//表示能产生哪些相对位移事件,x,y,滚轮 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//表示能产生哪些绝对位移事件,x,y unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; |
/*
*Event types
*/
#define EV_SYN 0x00//同步事件 #define EV_KEY 0x01 #define EV_REL 0x02//相对位移 #define EV_ABS 0x03//绝对位移 #define EV_MSC 0x04 #define EV_SW 0x05 #define EV_LED 0x11 #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 #define EV_PWR 0x16 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f #define EV_CNT (EV_MAX+1)
|
下面进行输入子系统的分析:
input_initàerr = register_chrdev(INPUT_MAJOR, "input", &input_fops);à fops只含有下面 static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file,//à只含有一个open结构 .llseek = noop_llseek, }; |
问题:怎样读取按键的值:
input_open_file struct input_handler *handler = input_table[iminor(inode) >> 5]; if (handler) new_fops = fops_get(handler->fops); //à.fops = &evdev_fops, old_fops = file->f_op; file->f_op = new_fops; err = new_fops->open(inode, file); |
App读取:
Readà ………à最终会调用到下层的file->f_op—>read函数 |
Input_table数组构成:
input_register_handler(&evdev_handler); static struct input_handler evdev_handler = { .event = evdev_event, //à各种事件动作与回报 .id_table = evdev_ids, //à看看支持不支持所用硬件设备 .connect = evdev_connect, //->支持硬件设备就 .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, .name = "evdev", }; |
如果handler支持这个设备,就将device和传软件层匹配在一起。
硬件操作:
input_register_device: error = device_add(&dev->dev); //à增加设备 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); //à在内核中加入设备路径 list_add_tail(&dev->node, &input_dev_list); //à加入链表中 list_for_each_entry(handler, &input_handler_list, node) //à对应每一个handler调用下面的函数 input_attach_handler(dev, handler); //à根据input_handler的id_table判断是否能支持该设备 |
软件操作:
input_register_device: error = device_add(&dev->dev); path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); |
input_attach_handler(dev,handler):
id = input_match_device(handler, dev); error = handler->connect(handler, dev, id); | //àid_table中两边是否匹配 //à匹配则进行连接 |
下面列举input_match_device:
const struct input_device_id *id; int i; /*首先列举bus,vendor,product,version是否匹配*/ 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; } |
注册input_dev或者input_handler时,会两两比较左边的input_dve和右边的input_handler,根据input_handler的id_table判断这个input_handler是否支持这个input_dev,如果能支持,则调用input_handler的connect的connect函数建立“连接”。
线面来看一下connect函数:
此处,将左右两边连接起来,相当于一个节点连接了两部分内容
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);à分配一个input_handle空间
evdev->handle.dev = input_get_device(dev); //à指向左边的input_dev evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler; //à指向右边的input_handler evdev->handle.private = evdev; error = input_register_handle(&evdev->handle); //à注册这个handle list_add_tail_rcu(&handle->d_node, &dev->h_list); list_add_tail_rcu(&handle->h_node, &handler->h_list); |
读取:
App:read……. Evdev_read /*无数据并且是非阻塞方式打开,则立刻返回*/ if (client->packet_head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; /*否则休眠*/ retval = wait_event_interruptible(evdev->wait, client->packet_head != client->tail || !evdev->exist); evdev_event if (type == EV_SYN && code == SYN_REPORT)à为同步事件并且code同步返回时唤醒 wake_up_interruptible(&evdev->wait); |
Gpio_keys.c例子:
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)à中断子程序产生bdata给report { struct gpio_button_data *bdata = dev_id; struct gpio_keys_button *button = bdata->button; BUG_ON(irq != gpio_to_irq(button->gpio)); if (bdata->timer_debounce) mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(bdata->timer_debounce)); else schedule_work(&bdata->work); return IRQ_HANDLED; } static void gpio_keys_report_event(struct gpio_button_data *bdata) { struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; input_event(input, type, button->code, !!state);à核心程序 input_sync(input);à上报信息 } |
à下转input_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)) { spin_lock_irqsave(&dev->event_lock, flags); add_input_randomness(type, code, value); input_handle_event(dev, type, code, value);-->执行event函数 spin_unlock_irqrestore(&dev->event_lock, flags); } } |
input_handle_event(dev, type,code, value)
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value);à调用handle,进行相应的动作 |