zoukankan      html  css  js  c++  java
  • android 拨动按键驱动

    云科  一如

    新板上有两个按键,是拨动按键,驱动参照了gpio_矩阵的驱动。我把这两个按键注册为2个不同的input_dev,产生不同的中断,并用同一个timer和handler来接收。其中一个按键——手电,并不报值,而是在驱动直接设置闪光灯的模式和亮度。FM按键功能是打开FM - -!(好雷),在上报值方面,使用input的EV_KEY类型来保值,当拨动为开时,上报一个键的按下,等待10ms,再上报该键的弹起;拨动为关时,上报另一个键的按下,等待10ms,再上报这个键的弹起。

    源文件:

    /**********************************************************
    * toggle-keyboard.c
    *
    * keyboard driver for toggle button
    *
    *
    ***********************************************************/

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/miscdevice.h>
    #include <linux/sched.h>
    #include <linux/delay.h>
    #include <linux/poll.h>
    #include <linux/spinlock.h>
    #include <asm/irq.h>
    #include "toggle_keys.h"
    #include <linux/gpio.h>
    #include <linux/hrtimer.h>
    #include <linux/interrupt.h>
    #include <linux/slab.h>
    #include <linux/wakelock.h>
    #include <linux/earlysuspend.h>
    #include <linux/leds.h>
    #include <linux/ktime.h>
    #include <linux/platform_device.h>
    #include <linux/mutex.h>

    #define DEVICE_NAME "toggle_kb"

    extern struct toggle_bottons botton_array[];

    struct gpio_toggle {
        struct toggle_bottons *input_devs;
        const struct gpio_toggle_platform_data *info;
    };

    static unsigned int kp_toggle_gpios[] = {
        GPIO_DEBUG_SELECT_N,
        GPIO_SIM2_MSM_SCLK
    };

    static struct mutex toggle_mutex;
    static struct wake_lock toggle_wake_lock;
    static struct hrtimer toggle_timer;

    #define IRQ_EINT0 gpio_to_irq(kp_toggle_gpios[0])//torch
    #define IRQ_EINT1 gpio_to_irq(kp_toggle_gpios[1])//FM
    #define GPIO_FLASH_MODE 19
    #define LED_FLASH 96

    static int setTorch(char brightness){  
    //    printk("dyyr-setTorch, bright=%d\n", brightness);
        gpio_set_value(GPIO_FLASH_MODE, 0);//torch mode
        mdelay(1);
        gpio_set_value(LED_FLASH, brightness);
        return 0;
    }

     
    static enum hrtimer_restart toggle_timer_func(struct hrtimer *timer){
        int gpio;
        int err;
        
        mutex_lock(&toggle_mutex);
        mdelay(200);    //Prevent jitter
        //only report FM, control torch directly here
        if (botton_array[1].irq_state == 1){
            gpio=gpio_get_value(kp_toggle_gpios[1]);
            if (gpio){
                input_report_key(botton_array[1].dev, KEY_F4, 1);
                input_sync(botton_array[1].dev);
                mdelay(10);
                input_report_key(botton_array[1].dev, KEY_F4, 0);
                input_sync(botton_array[1].dev);
                printk("dyyr-report press FM\n");
            }
            else{
                input_report_key(botton_array[1].dev, KEY_F5, 1);
                input_sync(botton_array[1].dev);
                mdelay(10);
                input_report_key(botton_array[1].dev, KEY_F5, 0);
                input_sync(botton_array[1].dev);
                printk("dyyr-report unpress FM\n");
            }
            enable_irq(IRQ_EINT1);
            botton_array[1].irq_state = 0;
        }
        else if (botton_array[0].irq_state == 1){
    //        printk("dyyr-torch\n");
            gpio=gpio_get_value(kp_toggle_gpios[0]);
            if(gpio){
                err=setTorch(1);
            }
            else {
                err=setTorch(0);
            }
            botton_array[0].irq_state = 0;
            enable_irq(IRQ_EINT0);
        }
        else
           printk("dyyr-error in handler,all irq_state=0. \n");
        wake_unlock(&toggle_wake_lock);
        mutex_unlock(&toggle_mutex);
        return HRTIMER_NORESTART;
    }


    static irqreturn_t handler(int irq, void *botton){
        struct toggle_bottons *tb;
    //    int gpio;

    //    gpio=gpio_get_value(kp_toggle_gpios[1]);
    //    printk("dyyr-in handler, irq=%d, gpio_84=%d\n", irq, gpio);
        tb = botton;
        disable_irq_nosync(irq);
        wake_lock(&toggle_wake_lock);
        tb->irq_state = 1;
        hrtimer_start(&toggle_timer, ktime_set(0, 0), HRTIMER_MODE_REL);
        return IRQ_HANDLED;
    }

    static int requestIrq(struct gpio_toggle *ip){    
        int err;

    //    printk("dyyr-requestIrq\n");
        //Torch
        err = request_irq(IRQ_EINT0, handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DEVICE_NAME, &ip->input_devs[0]);
        if(err)
            goto eint0_failed;

        if (err) {
            printk("set_irq_wake failed");
        }
        
        //FM
        err = request_irq(IRQ_EINT1, handler, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DEVICE_NAME, &ip->input_devs[1]);
        if(err)
            goto eint1_failed;

        if (err) {
            printk("set_irq_wake failed ");
        }
        
        return 0;

    eint1_failed:
        ;
    eint0_failed:

        printk(DEVICE_NAME ": IRQ Requeset Error\n");
        return err;
    }


    static int gpio_toggle_probe(struct platform_device *pdev)
    {
        int err;    
        struct gpio_toggle *ip;
        int dev_count = 2;
        int i;
        int registered = 0;
        

    //    printk("dyyr-probe\n");
        ip = kzalloc(sizeof(*ip) +
                 sizeof(pdev) * dev_count, GFP_KERNEL);
        if (ip == NULL) {
            err = -ENOMEM;
            printk("gpio_toggle_probe: Failed to allocate private data\n");
            goto err_kp_alloc_failed;
        }
        ip->input_devs = botton_array;
        for (i = 0; i < dev_count; i++) {
            struct input_dev *input_dev = input_allocate_device();
            if (input_dev == NULL) {
                err = -ENOMEM;
                printk("gpio_toggle_probe: Failed to allocate input device\n");
                goto err_input_dev_alloc_failed;
            }
            input_set_drvdata(input_dev, ip);
             input_dev->name = i ? "FM_botton" : "Torch_botton";
            ip->input_devs[i].dev = input_dev;
            ip->input_devs[i].irq_state = 0;
            err = input_register_device(ip->input_devs[i].dev);
            if (err) {
                printk("gpio_toggle_probe: Unable to register ");
                goto err_input_register_device_failed;
            }
            registered++;
            err = gpio_request(kp_toggle_gpios[i], "gpio_toggle");
                if (err) {
                    printk("gpiomatrix: gpio_request failed for output %d\n", kp_toggle_gpios[i]);
                    goto err_request_output_gpio_failed;
            }
            err = gpio_direction_input(kp_toggle_gpios[i]);
            if (err) {
                printk("dyyr-: gpio_configure failed for input %d\n", kp_toggle_gpios[i]);
                goto err_output_gpio_configure_failed;
            }        
        }
        ip->input_devs[0].timer = ip->input_devs[1].timer = &toggle_timer;
        ip->input_devs[0].wake_lock = ip->input_devs[1].wake_lock = &toggle_wake_lock;
        ip->input_devs[0].mutex = ip->input_devs[1].mutex = &toggle_mutex;
        hrtimer_init(&toggle_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        toggle_timer.function = toggle_timer_func;
        wake_lock_init(&toggle_wake_lock, WAKE_LOCK_SUSPEND, "toggle_button");            

        input_set_capability(ip->input_devs[1].dev, EV_KEY, KEY_F4);
        input_set_capability(ip->input_devs[1].dev, EV_KEY, KEY_F5);
        err=requestIrq(ip);
    //    printk("dyyr ,after requestIrq,err = %d\n", err);    
        mutex_init(&toggle_mutex);
        return 0;
        
        
        for (i = dev_count - 1; i >= 0; i--) {
    err_output_gpio_configure_failed:
            gpio_free(kp_toggle_gpios[i]);
        }
    err_request_output_gpio_failed:

    err_input_register_device_failed:
        for (i = 0; i < registered; i++)
            input_unregister_device(ip->input_devs[i].dev);
        for (i = dev_count - 1; i >= registered; i--) {
            input_free_device(ip->input_devs[i].dev);
    err_input_dev_alloc_failed:
            ;
        }
        kfree(ip);
    err_kp_alloc_failed:
        return err;

    }


    /*----------------------------------------------------
    * func: 注销设备,释放中断
    * param:
    *
    *
    * return:

    *
    ------------------------------------------------------*/
    static int gpio_toggle_remove(struct platform_device *pdev)
    {
        input_unregister_device(botton_array[0].dev);
        input_unregister_device(botton_array[1].dev);
        return 0;
    }

    static struct platform_driver gpio_toggle_driver = {
        .probe        = gpio_toggle_probe,
        .remove        = gpio_toggle_remove,
        .driver        = {
            .name    = DEVICE_NAME,
        },
    };

    static int __devinit toggle_kb_init(void)
    {
        return platform_driver_register(&gpio_toggle_driver);
    }

    static void __exit toggle_kb_exit(void)
    {
        platform_driver_unregister(&gpio_toggle_driver);
    }


    MODULE_AUTHOR("Daiyyr_mail:daiyyr@yahoo.cn");
    MODULE_LICENSE("GPL");
    module_init(toggle_kb_init);
    module_exit(toggle_kb_exit);



    源文件:

    /*
     * Copyright (C) 2007 Google, Inc.
     *
     * This software is licensed under the terms of the GNU General Public
     * License version 2, as published by the Free Software Foundation, and
     * may be copied, distributed, and modified under those terms.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     */
    #include<linux/input.h>
    #include<linux/wakelock.h>


    struct toggle_bottons {
        char irq_state;
        struct mutex *mutex;
        struct wake_lock *wake_lock;
        struct hrtimer *timer;
        struct input_dev *dev;
    };


    struct gpio_toggle_input_devs {
        int count;
        struct input_dev *dev[];
    };

    struct gpio_toggle_info {
        int (*func)(struct gpio_toggle_input_devs *input_devs,
                struct gpio_toggle_info *info,
                void **data, int func);
        int (*event)(struct gpio_toggle_input_devs *input_devs,
                 struct gpio_toggle_info *info,
                 void **data, unsigned int dev, unsigned int type,
                 unsigned int code, int value); /* out events */
        bool no_suspend;
    };


    struct gpio_toggle_platform_data {
        const char *name;
        struct gpio_toggle_info **info;
        size_t info_count;
        int (*power)(const struct gpio_toggle_platform_data *pdata, bool on);
        const char *names[]; /* If name is NULL, names contain a NULL */
                     /* terminated list of input devices to create */
    };


    源文件
    (部分)


    //daiyyr@20130315, add for toggle button

    struct toggle_bottons botton_array[2];


    static struct platform_device tg_pdev = {
        .name    = "toggle_kb",
        .id    = -1,
        .dev    = {
            .platform_data    = &botton_array,
        },
    };

    其它make、config等有关编译的文件修改请参照:将新的驱动源文件添加进android内核进行编译

  • 相关阅读:
    android之wifi开发
    android wifi讲解 wifi列表显示
    jQuery格式化时间插件formatDate
    Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)
    Android圆形图片自定义控件
    Android自定义控件
    SQL表连接查询(inner join、full join、left join、right join)
    Jquery 中each循环嵌套的使用示例教程
    JQuery遍历json数组的3种方法
    怎样从数据库层面检測两表内容的一致性
  • 原文地址:https://www.cnblogs.com/yiru/p/2971110.html
Copyright © 2011-2022 走看看