且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

I.MX6 shutdown by software

更新时间:2022-08-12 21:07:38

/************************************************************************
 *                    I.MX6 shutdown by software
 * 声明:
 *     有时候我们的系统可能并没有像手机那样的开关机键,所以我么这个时候
 * 需要提供软件关机功能,本文直接通过JNI操作设备节点进行控制,并没有采用
 * STUB来控制,当然目前对这块的操作也不熟练。
 *
 *                                     2015-12-20 深圳 南山平山村 曾剑锋
 ***********************************************************************/

                \\\\\\\\\\\\\\-*- 目录 -*-///////////////
                |  一、参考文档:
                |  二、修改按键驱动程序:
                |  三、板级文件注册按键设备:
                |  四、添加shutdown设备节点,便于控制:
                |  五、关闭关机时的提示框:
                |  六、关闭watchdog:
                |  七、使用JNI进行测试:
                |  八、JNI对应的Java文件:
                ----------------------------------------


一、参考文档:
    Android开发 调用系统隐藏API
        http://www.pocketdigi.com/20130519/1058.html
    定做Android关机界面
        http://233.io/article/1019041.html
    Android下实现自动关机的方法总结
        http://233.io/article/1019041.html

二、修改按键驱动程序:
    cat drivers/input/keyboard/gpio_keys.c
        ......
        //主要是为了能够指向input的设备,我们能够在自己函数里实现单独控制
        struct input_dev *this_input;
        ......
        /* 添加这个我们自己的函数,并声明为系统全局符号 */
        void this_input_report_event(int mode)
        {
            unsigned int type = EV_KEY;
        
            switch (mode) {
                case 1 :
                    // for power off
                    input_event(this_input, type, KEY_POWER, 1);
                    input_sync(this_input);
        
                    msleep(2000);
        
                    input_event(this_input, type, KEY_POWER, 0);
                    input_sync(this_input);
                    break;
                case 2 :
                    // for stand by
                    input_event(this_input, type, KEY_POWER, 1);
                    input_sync(this_input);
                    input_event(this_input, type, KEY_POWER, 0);
                    input_sync(this_input);
                    break;
                case 3 :
                    // for stand by and wake up
                    input_event(this_input, type, KEY_POWER, 1);
                    input_sync(this_input);
                    input_event(this_input, type, KEY_POWER, 0);
                    input_sync(this_input);
                    input_event(this_input, type, KEY_POWER, 1);
                    input_sync(this_input);
                    input_event(this_input, type, KEY_POWER, 0);
                    input_sync(this_input);
                    break;
                default:
                    break;
            }
        }
        EXPORT_SYMBOL(this_input_report_event);
        ......
        static int __devinit gpio_keys_probe(struct platform_device *pdev)
        {
            ......
            input = input_allocate_device();
        
            this_input = input; //添加这一行,为了能向上发送按键事件
        
            if (!ddata || !input) {
                dev_err(dev, "failed to allocate state\n");
                error = -ENOMEM;
                goto fail1;
            }
            ......
        }
        ......

三、板级文件注册按键设备:
    cat arch/arm/mach-mx6/board-mx6q_sabresd.c
        ......
        //这里随意改的,只要不和其他引脚有冲突就行
        #define SABRESD_POWER_OFF   IMX_GPIO_NR(3, 29)
        ......
        static struct gpio_keys_button new_sabresd_buttons[] = {
            //GPIO_BUTTON(SABRESD_VOLUME_UP, KEY_VOLUMEUP, 1, "volume-up", 0, 1),
            //GPIO_BUTTON(SABRESD_VOLUME_DN, KEY_VOLUMEDOWN, 1, "volume-down", 0, 1),
            GPIO_BUTTON(SABRESD_POWER_OFF, KEY_POWER, 1, "power-key", 1, 1),
        };
        ......

四、添加shutdown设备节点,便于控制:
    cat drivers/input/keyboard/shutdown.c
        #include <linux/module.h>
        #include <linux/fs.h>
        #include <linux/gpio.h>
        #include <linux/miscdevice.h>
        
        /** switch case are in gpio_key.c */
        #define THIS_INPUT_SHUTDOWN_SOFTWARE           1
        #define THIS_INPUT_STANBY_SOFTWARE             2
        #define THIS_INPUT_STANBY_AND_WAKEUP_SOFTWARE  3
        
        extern void this_input_report_event(int mode);
        
        static int shutdown_open(struct inode *inode, struct file *file)
        {
            return 0;
        }
        
        static int shutdown_close(struct inode *inode, struct file *file)
        {
            return 0;
        }
        
        static ssize_t shutdown_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
        {
            return 0;
        }
        
        long shutdown_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
        {
            this_input_report_event(cmd);
        }
        
        struct file_operations shutdown_fops = {
            .owner      = THIS_MODULE,
            .open       = shutdown_open,
            .release    = shutdown_close,
            .read       = shutdown_read,
            .unlocked_ioctl = shutdown_ioctl,
        };
        
        struct miscdevice shutdown_misc = {
            .minor  = MISC_DYNAMIC_MINOR,
            .name   = "shutdown",
            .fops   = &shutdown_fops,
        };
        
        int __init shutdown_init(void)
        {
            int ret;
        
            ret = misc_register(&shutdown_misc);
            if(ret)
                printk("register shutdown FAILED!\n");
        
            return ret;
        }
        
        void __exit shutdown_exit(void)
        {
            misc_deregister(&shutdown_misc);
        }
        
        module_init(shutdown_init);
        module_exit(shutdown_exit);
        
        MODULE_LICENSE("GPL");
    
五、关闭关机时的提示框:
    cat frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
        ......
        public class PhoneWindowManager implements WindowManagerPolicy {
            ......
            private final Runnable mPowerLongPress = new Runnable() {
                @Override
                public void run() {
                    // The context isn't read
                    if (mLongPressOnPowerBehavior < 0) {
                        mLongPressOnPowerBehavior = mContext.getResources().getInteger(
                                com.android.internal.R.integer.config_longPressOnPowerBehavior);
                    }
                    int resolvedBehavior = mLongPressOnPowerBehavior;
                    if (FactoryTest.isLongPressOnPowerOffEnabled()) {
                        resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
                    }
        
                    switch (resolvedBehavior) {
                    case LONG_PRESS_POWER_NOTHING:
                        break;
                    case LONG_PRESS_POWER_GLOBAL_ACTIONS:
                        mPowerKeyHandled = true;
                        if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
                            performAuditoryFeedbackForAccessibilityIfNeed();
                        }
                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
                        //注释这一样
                        //showGlobalActionsDialog();
                        //添加这一行
                        mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
                        break;
                    case LONG_PRESS_POWER_SHUT_OFF:
                    case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
                        mPowerKeyHandled = true;
                        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
                        mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
                        break;
                    }
                }
            };
            ......
        }
        ......

六、关闭watchdog:
    cat drivers/watchdog/imx2_wdt.c
        ......
        // 这里主要是I.MX6的watchdog是一旦打开,就不能关闭的,所以在这里想了个办法,堵住,看上去堵住了
        static void imx2_wdt_shutdown(struct platform_device *pdev)
        {
            if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
                /* we are running, we need to delete the timer but will give
                 * max timeout before reboot will take place */
                del_timer_sync(&imx2_wdt.timer);
        
                //注释这两行
                //imx2_wdt_set_timeout(IMX2_WDT_MAX_TIME);
                //imx2_wdt_ping();
        
                //添加这两行
                printk("imx2_wdt_stop();");
                imx2_wdt_stop();
        
                //再次执行上面的流程,主要为因为有时候不是仅仅一次不是很稳定
                del_timer_sync(&imx2_wdt.timer);
                imx2_wdt_stop();
        
                dev_crit(imx2_wdt_miscdev.parent,
                    "Device shutdown: Expect reboot!\n");
            }
        }
        ......

七、使用JNI进行测试:
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_android_shutdown_Shutdown */
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include "android/log.h"
    #include <sys/reboot.h>  
      
    static const char *TAG="GPIO_SHUTDOWN";
    #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
    
    #define THIS_INPUT_SHUTDOWN_SOFTWARE           1
    #define THIS_INPUT_STANBY_SOFTWARE             2
    #define THIS_INPUT_STANBY_AND_WAKEUP_SOFTWARE  3
    
    /*
     * Class:     com_android_shutdown_Shutdown
     * Method:    shutdown
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_com_android_shutdown_Shutdown_shutdown
        (JNIEnv * env, jobject thiz) {
    
        int fd = open("/dev/shutdown", O_RDWR);
        if (fd < 0) {
            perror("shutdown system faild.\n");
        }
    
        ioctl(fd, THIS_INPUT_SHUTDOWN_SOFTWARE, 0);
    
        close(fd);
      
    }

八、JNI对应的Java文件:
    cat shutdown.java 
    package com.android.shutdown;
    
    public class Shutdown {
        native static public void shutdown();
        static {
            System.loadLibrary("shutdown");
        }
    }