输入子系统(一)

本次所涉及到的文件:
include/linux/input.h
drivers/input/input.c
arch/arm/mach-rk30/board-rk30-sdk.c
drivers/input/keyboard/rk29_keys.c

Boot Log:
[ 1.853285] input: rk29-keypad as /devices/platform/rk29-keypad/input/input0

match name → “rk29-keypad”

1、相关配置:

Device Drivers  --->
    Input device support  --->
        [*]   Keyboards  --->
            <*>   rk29 keyboard

按键驱动对应的源码位置为:   drivers/input/keyboard/rk29_keys.c
按键相关的参数从board文件中传递给驱动程序:

2、相关按键属性定义:
arch/arm/mach-rk30/board-rk30-sdk.c

static struct rk29_keys_button key_button[] = {
    /***{
                .desc   = "vol-",
                .code   = KEY_VOLUMEDOWN,
                .gpio   = RK30_PIN4_PC5,
                .active_low = PRESS_LEV_LOW,
        },
        {
                .desc   = "play",
                .code   = KEY_POWER,
                .gpio   = RK30_PIN6_PA2,
                .active_low = PRESS_LEV_LOW,
                //.code_long_press = EV_ENCALL,
                .wakeup = 1,
        },
        {
                .desc   = "vol+",
                .code   = KEY_VOLUMEUP,
                .adc_value      = 1,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },*/
#if defined(CONFIG_PROJECT_D200)
        {
                .desc   = "play",
                .code   =   KEY_POWER,
                .gpio   =  RK30_PIN6_PA0,///RK30_PIN2_PA1,///
                .active_low = PRESS_LEV_LOW,
                //.code_long_press = EV_ENCALL,
                .wakeup = 1,
        },
#endif
#ifndef RK3000_SDK
/***    {
                .desc   = "menu",
                .code   = EV_MENU,
                .adc_value      = 135,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },
        {
                .desc   = "home",
                .code   = KEY_HOME,
                .adc_value      = 550,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },*/
        {
                .desc   = "esc",
                .code   =  KEY_HOME,///KEY_BACK,
                .adc_value      =  630,///334,
                .gpio = RK30_PIN2_PC7,///INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },
/***    {
                .desc   = "camera",
                .code   = KEY_CAMERA,
                .adc_value      = 743,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },*/
#else
/***    {
                .desc   = "menu",
                .code   = EV_MENU,
                .adc_value      = 155,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },
        {
                .desc   = "home",
                .code   = KEY_HOME,
                .adc_value      = 630,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },*/
        {
                .desc   = "home",
                .code   = KEY_BACK,
                .adc_value      = 386,
                .gpio =  RK30_PIN2_PC7,///INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },
/***    {
                .desc   = "camera",
                .code   = KEY_CAMERA,
                .adc_value      = 827,
                .gpio = INVALID_GPIO,
                .active_low = PRESS_LEV_LOW,
        },*/
#endif
};

3、相关按键操作:
drivers/input/keyboard/rk29_keys.c

input = input_allocate_device();
分配input_dev结构体,并调用input_register_device(input)对其进行注册,

3.1、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->dev.type = &input_dev_type;    /* 初始化设备结构类型 */
        dev->dev.class = &input_class;      /* 初始化为输入设备类 */
        device_initialize(&dev->dev);       /* 初始化device结构体 */
        mutex_init(&dev->mutex);            /* 初始化互斥锁 */
        spin_lock_init(&dev->event_lock);   /* 初始化事件自旋锁 */
        INIT_LIST_HEAD(&dev->h_list);       /* 初始化链表 */
        INIT_LIST_HEAD(&dev->node);

        __module_get(THIS_MODULE);          /* 模块引用 */
    }

    return dev;
}

注:input_dev类型的指针,该结构体属于输入设备结构体,包含输入设备的一些信息,如设备支持的按键码、设备名称、设备支持的事件等。
关于input_dev结构体更详尽的解释参见:http://bbs.21ic.com/icview-309385-1-1.html

3.2、注册函数input_register_device( )

int input_register_device(struct input_dev *dev)
{
    static atomic_t input_no = ATOMIC_INIT(0);
    struct input_handler *handler;
    const char *path;
    int error;

    /* Every input device generates EV_SYN/SYN_REPORT events. */
    __set_bit(EV_SYN, dev->evbit);
    /*
        #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    /* LED灯设备 */
        #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)
        详细输入子系统的事件编码信息参见http://blog.csdn.net/droidphone/article/details/8432055
     */

    /* 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);

    if (!dev->hint_events_per_packet)
        dev->hint_events_per_packet =
                input_estimate_events_per_packet(dev);

    /* 初始化timer定时器,为处理重复击键而定义 */
    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;

    dev_set_name(&dev->dev, "input%ld",
             (unsigned long) atomic_inc_return(&input_no) - 1);
    /* 将input_dev包含的device注册到设备模型中 */
    error = device_add(&dev->dev);
    if (error)
        return error;
    /* 打印设备路径,输出调试信息 */
    path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    pr_info("%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;
    }
    /* 将input_dev加入到input_dev_list链表中 */
    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 0;
}

3.3、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)
        pr_err("failed to attach handler %s to device %s, error: %d\n",
               handler->name, kobject_name(&dev->dev.kobj), error);

    return error;
}

3.4、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匹配项 */
        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;
}

注:注册input_dev的过程就是为input_device设置默认值,并将其挂到input_dev_list。与挂载在input_handler_list中的handler相匹配。如匹配成功,则调用handler的connect函数。

关于此输入子系统部分,发现网上有更为详尽的解释和说明,故贴出地址以备参考:
http://blog.csdn.net/tianxiawuzhei/article/details/7607068
http://blog.csdn.net/weiqing1981127/article/details/8138389

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值