zoukankan      html  css  js  c++  java
  • I.MX6 gpio-keys driver hacking

    /****************************************************************************
     *                   I.MX6 gpio-keys driver hacking
     * 说明:
     *     1. 本文解读gpio-keys驱动是如何注册,最终处理函数在哪里。
     *     2. 从最后生成的设备节点来看,我们直接可以通过操作该设备节点来来让系统
     *         进行相关操作,譬如关机、挂起等操作。
     *
     *                                          2016-3-17 深圳 南山平山村 曾剑锋
     ***************************************************************************/
    
    static struct platform_driver gpio_keys_device_driver = {     <----+
        .probe      = gpio_keys_probe,                        ---------*-------+
        .remove     = __devexit_p(gpio_keys_remove),                   |       |
        .driver     = {                                                |       |
            .name   = "gpio-keys",                                     |       |
            .owner  = THIS_MODULE,                                     |       |
    #ifdef CONFIG_PM                                                   |       |
            .pm = &gpio_keys_pm_ops,                                   |       |
    #endif                                                             |       |
        }                                                              |       |
    };                                                                 |       |
                                                                       |       |
    static int __init gpio_keys_init(void)            <------------+   |       |
    {                                                              |   |       |
        return platform_driver_register(&gpio_keys_device_driver); | --+       |
    }                                                              |           |
                                                                   |           |
    static void __exit gpio_keys_exit(void)                        |           |
    {                                                              |           |
        platform_driver_unregister(&gpio_keys_device_driver);      |           |
    }                                                              |           |
                                                                   |           |
    module_init(gpio_keys_init);                      -------------+           |
    module_exit(gpio_keys_exit);                                               |
                                                                               |
    MODULE_LICENSE("GPL");                                                     |
    MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");                         |
    MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");                       |
    MODULE_ALIAS("platform:gpio-keys");                                        |
                                                                               |
    static int __devinit gpio_keys_probe(struct platform_device *pdev)   <-----+
    {
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_keys_drvdata *ddata;
        struct device *dev = &pdev->dev;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
    
        ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
                pdata->nbuttons * sizeof(struct gpio_button_data),
                GFP_KERNEL);
        input = input_allocate_device();
        if (!ddata || !input) {
            dev_err(dev, "failed to allocate state
    ");
            error = -ENOMEM;
            goto fail1;
        }
    
        ddata->input = input;
        ddata->n_buttons = pdata->nbuttons;
        ddata->enable = pdata->enable;
        ddata->disable = pdata->disable;
        mutex_init(&ddata->disable_lock);
    
        platform_set_drvdata(pdev, ddata);
        input_set_drvdata(input, ddata);
    
        input->name = pdata->name ? : pdev->name;
        input->phys = "gpio-keys/input0";
        input->dev.parent = &pdev->dev;
        input->open = gpio_keys_open;
        input->close = gpio_keys_close;
    
        input->id.bustype = BUS_HOST;
        input->id.vendor = 0x0001;
        input->id.product = 0x0001;
        input->id.version = 0x0100;
    
        /* Enable auto repeat feature of Linux input subsystem */
        if (pdata->rep)
            __set_bit(EV_REP, input->evbit);
    
        for (i = 0; i < pdata->nbuttons; i++) {
            struct gpio_keys_button *button = &pdata->buttons[i];
            struct gpio_button_data *bdata = &ddata->data[i];
            unsigned int type = button->type ?: EV_KEY;
    
            bdata->input = input;
            bdata->button = button;
    
            error = gpio_keys_setup_key(pdev, bdata, button);         -------+
            if (error)                                                       |
                goto fail2;                                                  |
                                                                             |
            if (button->wakeup)                                              |
                wakeup = 1;                                                  |
                                                                             |
            input_set_capability(input, type, button->code);                 |
        }                                                                    |
                                                                             |
        error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);  |
        if (error) {                                                         |
            dev_err(dev, "Unable to export keys/switches, error: %d
    ",      |
                error);                                                      |
            goto fail2;                                                      |
        }                                                                    |
                                                                             |
        error = input_register_device(input);                                |
        if (error) {                                                         |
            dev_err(dev, "Unable to register input device, error: %d
    ",     |
                error);                                                      |
            goto fail3;                                                      |
        }                                                                    |
                                                                             |
        /* get current state of buttons */                                   |
        for (i = 0; i < pdata->nbuttons; i++)                                |
            gpio_keys_report_event(&ddata->data[i]);                         |
        input_sync(input);                                                   |
                                                                             |
        device_init_wakeup(&pdev->dev, wakeup);                              |
                                                                             |
        return 0;                                                            |
                                                                             |
     fail3:                                                                  |
        sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);          |
     fail2:                                                                  |
        while (--i >= 0) {                                                   |
            free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);  |
            if (ddata->data[i].timer_debounce)                               |
                del_timer_sync(&ddata->data[i].timer);                       |
            cancel_work_sync(&ddata->data[i].work);                          |
            gpio_free(pdata->buttons[i].gpio);                               |
        }                                                                    |
                                                                             |
        platform_set_drvdata(pdev, NULL);                                    |
     fail1:                                                                  |
        input_free_device(input);                                            |
        kfree(ddata);                                                        |
                                     +---------------------------------------+
        return error;                |
    }                                |
                                     V
    static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                         struct gpio_button_data *bdata,
                         struct gpio_keys_button *button)
    {
        const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
        unsigned long irqflags;
        int irq, error;
    
        setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
        INIT_WORK(&bdata->work, gpio_keys_work_func);           --------------------+
                                                                                    |
        error = gpio_request(button->gpio, desc);                                   |
        if (error < 0) {                                                            |
            dev_err(dev, "failed to request GPIO %d, error %d
    ",                   |
                button->gpio, error);                                               |
            goto fail2;                                                             |
        }                                                                           |
                                                                                    |
        error = gpio_direction_input(button->gpio);                                 |
        if (error < 0) {                                                            |
            dev_err(dev, "failed to configure"                                      |
                " direction for GPIO %d, error %d
    ",                               |
                button->gpio, error);                                               |
            goto fail3;                                                             |
        }                                                                           |
                                                                                    |
        if (button->debounce_interval) {                                            |
            error = gpio_set_debounce(button->gpio,                                 |
                          button->debounce_interval * 1000);                        |
            /* use timer if gpiolib doesn't provide debounce */                     |
            if (error < 0)                                                          |
                bdata->timer_debounce = button->debounce_interval;                  |
        }                                                                           |
                                                                                    |
        irq = gpio_to_irq(button->gpio);                                            |
        if (irq < 0) {                                                              |
            error = irq;                                                            |
            dev_err(dev, "Unable to get irq number for GPIO %d, error %d
    ",        |
                button->gpio, error);                                               |
            goto fail3;                                                             |
        }                                                                           |
                                                                                    |
        irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;                      |
        /*                                                                          |
         * If platform has specified that the button can be disabled,               |
         * we don't want it to share the interrupt line.                            |
         */                                                                         |
        if (!button->can_disable)                                                   |
            irqflags |= IRQF_SHARED;                                                |
        /*                                                                          |
         * Resume power key early during syscore instead of at device               |
         * resume time.                                                             |
         * Some platform like Android need to konw the power key is pressed         |
         * then to reume the other devcies                                          |
         */                                                                         |
        if (button->wakeup)                                                         |
            irqflags |= IRQF_NO_SUSPEND | IRQF_EARLY_RESUME;                        |
                                                                                    |
        error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); |
        if (error < 0) {                                                            |
            dev_err(dev, "Unable to claim irq %d; error %d
    ",                      |
                irq, error);                                                        |
            goto fail3;                                                             |
        }                                                                           |
                                                                                    |
        return 0;                                                                   |
                                                                                    |
    fail3:                                                                          |
        gpio_free(button->gpio);                                                    |
    fail2:                                                                          |
        return error;                                                               |
    }                                                                               |
                                                                                    |
    static void gpio_keys_work_func(struct work_struct *work)         <-------------+
    {
        struct gpio_button_data *bdata =
            container_of(work, struct gpio_button_data, work);
    
        gpio_keys_report_event(bdata);                                -----------+
    }                                                                            |
                                                                                 |
    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_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
        printk("zengjf check gpio-keys positon: %s in line %d.
    ", __func__, _LINE__);
    
        if (type == EV_ABS) {
            if (state)
                input_event(input, type, button->code, button->value);
        } else {
            input_event(input, type, button->code, !!state);
        }
        input_sync(input);
    }
    
    
    
    /**
     * root@android:/ # cat /proc/bus/input/devices                                   
     *    I: Bus=0019 Vendor=0001 Product=0001 Version=0100
     *    N: Name="gpio-keys"
     *    P: Phys=gpio-keys/input0
     *    S: Sysfs=/devices/platform/gpio-keys/input/input0
     *    U: Uniq=
     *    H: Handlers=event0 
     *    B: PROP=0
     *    B: EV=3
     *    B: KEY=100000 0 0 0
     *    ......
     */
  • 相关阅读:
    SQLServer多表联查,多表分页查询
    GOF23种设计模式概括
    常用的正则表达式
    面向对象七大原则
    Jquery简单学习
    MVC图片上传详解
    面向对象OOP概念描述
    C++ 基础命名空间 using namespace std;
    找不到WJSWDLL.dll
    AspectJ中的类型间声明(成员注入)
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/5287784.html
Copyright © 2011-2022 走看看