zoukankan      html  css  js  c++  java
  • 从sys/power/state分析并实现S3C2416的睡眠和唤醒

    环境:
    PC: debian-7.6.0  
    ARM CPU: S3C2416  
    Linux-Kernel: 3.6.0(FriendlyARM)
    U-boot: 1.3.4

    一、问题来源                                                                                                

    依据须要,在S3C2416上加入中断睡眠和唤醒功能。于是我就查查Linux支持S3C2416的睡眠模式:
    cat /sys/power/state
    运行完,万万没想到:居然是空的,该命令没有不论什么输出!也就是说,我的内核眼下不支持不论什么方式的睡眠。
    不可能啊!之前我用S3C2440的CPU(内核版本号Linux_2_6_31)实现了中断的睡眠和唤醒,而S3C2416的Linux 3.6内核配置就是參照着Linux 2.6.31进行的配置。


    Linux 2.6.31运行:

    S3C2440-Linux 2.6.31:
    cat /sys/power/state
    返回:mem

    经过各种颠倒黑白颠三倒四的尝试都失败后,灵机一闪:既然是cat后没反应,那就沿着cat /sys/power/state调用的函数从上到下,一步一步查。
    指导思想有了,那就顺蔓摸瓜的进行调试。

    、调试流程                                                                         
    显示cat /sys/power/state运行结果的函数是state_show():
    kernel/power/main.c

    static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
    {
    char *s = buf;
    printk("<0>""[#1]kernel speaking ");
    #ifdef CONFIG_SUSPEND
    printk("<0>""[#2]kernel speaking ");
    int i;

    for (i = 0; i < PM_SUSPEND_MAX; i++) {
    if (pm_states[i] && valid_state(i))
    s += sprintf(s,"%s ", pm_states[i]);
    }
    #endif
    ......
    }

    编译、烧写内核,运行cat命令。有[#2]kernel speaking信息说明CONFIG_SUSPEND宏是有定义的。
    pm_states[]数组在同文件也有定义,那么接下来就看函数valid_state():
    kernel/power/suspend.c
    bool valid_state(suspend_state_t state)
    {
    printk("<0>""[#3]kernel speaking[suspend_ops-%d] ", suspend_ops);
    return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
    }


    这个函数測试后显示suspend_ops指针为0。哈哈,原因找到了,接着顺藤摸瓜。


    suspend_ops指向struct platform_suspend_ops结构体,每一个成员的作用參见附录博文。suspend_ops的赋值在在函数suspend_set_ops():
    kernel/power/suspend.c
    void suspend_set_ops(const struct platform_suspend_ops *ops)
    {
    lock_system_sleep();
    suspend_ops = ops;
    unlock_system_sleep();
    }

    suspend_set_ops()的调用在函数s3c_pm_init():
    arch/arm/plat-samsung/pm.c
    int __init s3c_pm_init(void)
    {
    printk("S3C Power Management, Copyright 2004 Simtec Electronics ");

    suspend_set_ops(&s3c_pm_ops);
    return 0;
    }


    s3c_pm_init()的调用在函数smdk_machine_init():
    void __init smdk_machine_init(void)
    {
    ......
    s3c_pm_init();
    }


    而smdk_machine_init()是在详细的板上调用,我用的S3C2416是友善之臂的核心板,在mini2451_machine_init():
    arch/arm/mach-s3c24xx/mach-mini2451.c
    static void __init mini2451_machine_init(void)
    {
    #if defined(CONFIG_S3C24XX_SMDK)
    printk("<0>""[#4]kernel speaking ");
    smdk_machine_init();
    #endif
    }
    注意,结果出来了:[#4]kernel speaking信息没有说明CONFIG_S3C24XX_SMDK宏未定义。
    而CONFIG_S3C24XX_SMDK宏是在配置内核是选定MINI2451后默认选定的,仅仅是被友善之臂凝视掉了,在当前文件夹下的Kconfig

    config MACH_MINI2451
    	bool "MINI2451"
    	#select S3C24XX_SMDK
    	select S3C_DEV_FB
    	select S3C_DEV_HSMMC
    	select S3C_DEV_HSMMC1
    	select S3C_DEV_NAND
    	select S3C_DEV_USB_HOST
    	select S3C2416_SETUP_SDHCI
    	select WIRELESS_EXT
    	select WEXT_SPY
    	select WEXT_PRIV
    	select AVERAGE
    	help
    	  Say Y here if you are using an FriendlyARM MINI2451
    三、加入中断方式的睡眠和唤醒功能                                                
    1、改动arch/arm/mach-s3c24xx/Kconfig。去掉S3C24XX_SMDK选项前的凝视
    2、改动arch/arm/mach-s3c24xx/common-smdk.c,去掉s3c_pm_init之外的东东。并加入唤醒中断唤醒源
    下面改动參见内核Documentation/arm/Samsung-S3C24XX/Suspend.txt

    static irqreturn_t button_irq(int irq, void *pw)
    {
    	return IRQ_HANDLED;
    }
    
    void __init smdk_machine_init(void)
    {
    
    	/* Configure the LEDs (even if we have no LED support)*/
    #if 0
    	int ret = gpio_request_array(smdk_led_gpios,
    				     ARRAY_SIZE(smdk_led_gpios));
    	if (!WARN_ON(ret < 0))
    		gpio_free_array(smdk_led_gpios, ARRAY_SIZE(smdk_led_gpios));
    
    	if (machine_is_smdk2443())
    		smdk_nand_info.twrph0 = 50;
    
    	s3c_nand_set_platdata(&smdk_nand_info);
    
    	platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
    #endif
    	request_irq(IRQ_EINT0, button_irq, IRQF_TRIGGER_FALLING, "IRQ_EINT0", NULL);
    	enable_irq_wake(IRQ_EINT0);
    	
    	s3c_pm_init();
    }
    3、在arch/arm/mach-s3c24xx文件夹下加入文件common-smdk.h

    /* arch/arm/mach-s3c24xx/common-smdk.h
    *
    * Copyright (c) 2006 Simtec Electronics
    * Ben Dooks <ben@simtec.co.uk>
    *
    * Common code for SMDK2410 and SMDK2440 boards
    *
    * http://www.fluff.org/ben/smdk2440/
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License version 2 as
    * published by the Free Software Foundation.
    */
    
    extern void smdk_machine_init(void);

    4、改动arch/arm/mach-s3c24xx/mach-mini2451.c,加入smdk_machine_init所在的头文件,即common-smdk.h
    #include "common-smdk.h"

    四、S3C2416睡眠唤醒測试                                                        
    睡眠:
    cat /sys/power/state
    返回:mem
    echo mem > /sys/power/state


    睡好后,触发IRQ_EINT0中断(按键),CPU恢复之前的状态。部分截图:


    为了更好的測试,能够再睡眠前执行一个输出递增数据的程序,这样能够直观的看到唤醒后的状态。


    五、S3C2416睡眠唤醒的底层驱动实现                                  
    S3C2416睡眠的底层实现


    六、总结                                                                                        
    1、灵感非常重要。
    PS:“天才就是百分之中的一个的灵感加百分之99的汗水”。这仅仅是前半句,后半句是:“但那百分之中的一个的灵感,往往比百分之九十九的汗水来得重要”。


    为什么从小听到的仅仅有前半句、、、不吐槽了。



    2、正确的方法就是捷径。只是,歧路也能让人增长姿势。



    3、Linux内核,尤其原理方面的东东,还知之甚少。路漫长爱漫长、、、

    4、附件:Linux下截屏命令: import pic_name
    标准linu休眠和唤醒机制分析(一)

    标准linu休眠和唤醒机制分析(二)

    标准linu休眠和唤醒机制分析(三)
    标准linu休眠和唤醒机制分析(四)

  • 相关阅读:
    转:算法的空间复杂度
    转:算法的最坏情况与平均情况 复杂度就要看最坏情况
    转:一些字符串函数的实现
    转:C语言字符串操作函数
    搜狐在线笔试 时间复杂度O(n)实现数组A[n]中所有元素循环左移k个位置
    搜狐笔试 最大连续递增子段和 关键词连续递增
    转:最小区间:k个有序的数组,找到最小区间使k个数组中每个数组至少有一个数在区间中
    转:strcpy实现的考察要点
    转:strcat与strcpy与strcmp与strlen
    转:多篇文章中的设计模式-------策略模式
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7397278.html
Copyright © 2011-2022 走看看