linux输入子系统分析

 

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;

/*首先列举busvendorproductversion是否匹配*/

         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_handlerid_table判断这个input_handler是否支持这个input_dev,如果能支持,则调用input_handlerconnectconnect函数建立“连接

线面来看一下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)à中断子程序产生bdatareport

{   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,进行相应的动作

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值