1. 程式人生 > >android 休眠喚醒流程及定位喚醒問題總結

android 休眠喚醒流程及定位喚醒問題總結

平臺資訊:

核心:linux 2.6.35

android:2.3.1

CPU:三星S5PV210

就從earlysuspend.c中說起,在early suspend中執行完所有驅動的early suspend後會呼叫wake_unlock,在wake_unlock函式中,如果判斷系統已經沒有喚醒鎖,則會排程休眠的工作佇列,此時就會執行佇列函式suspend。

見定義:static DECLARE_WORK(suspend_work, suspend);

suspend就是開始進行linux休眠的函式。

呼叫關係如下:

static void suspend(struct work_struct *work)
--> int pm_suspend(suspend_state_t state)
--> int enter_state(suspend_state_t state)


在此函式中要做一些準備工作:

同步檔案系統(sys_sync);

分配控制檯和凍結所有的程序(suspend_prepare)等;

然後呼叫下面這個函式;

[cpp] view plaincopyprint?
  1. int suspend_devices_and_enter(suspend_state_t state)  
  2.  {  
  3.   int error;  
  4.   gfp_t saved_mask;  
  5.   /*判斷休眠的操作函式集合指標是否被賦值,此指標會在對應的平臺電源管理模組中被賦值 
  6.   在s5pv210平臺中是在plat-samsung/pm.c中*/
  7.   if (!suspend_ops)     
  8.   return -ENOSYS;  
  9.   if (suspend_ops->begin) {  
  10.    error = suspend_ops->begin(state);  
  11.    if (error)  
  12.     goto Close;  
  13.   }  
  14.   suspend_console();//suspend console subsystem,此時printk就不能列印資訊,但還有其他方式可以進行列印
  15.   saved_mask = clear_gfp_allowed_mask(GFP_IOFS);  
  16.   suspend_test_start();  
  17.   error = dpm_suspend_start(PMSG_SUSPEND);//在此函式裡,會調到驅動註冊的所有suspend函式,如果想知道suspend
  18.   順序的話,可以在裡面打印出來。  
  19.   if (error) {  
  20.    printk(KERN_ERR "PM: Some devices failed to suspend\n");  
  21.    goto Recover_platform;  
  22.   }  
  23.   suspend_test_finish("suspend devices");  
  24.   if (suspend_test(TEST_DEVICES))  
  25.    goto Recover_platform;  
  26.  suspend_enter(state); //在此函式中會呼叫到系統的休眠功能,使系統進入sleep模式,而系統也就會停留在
  27.   休眠的地方,當喚醒的時候再繼續往下執行。  
  28.  Resume_devices: //當系統被外部中斷喚醒的時候,這裡會被執行到
  29.   suspend_test_start();  
  30.   dpm_resume_end(PMSG_RESUME);//此函式會執行resume流程,會呼叫驅動中註冊的所有resume函式。
  31.   suspend_test_finish("resume devices");  
  32.   set_gfp_allowed_mask(saved_mask);  
  33.   resume_console();  
  34.   Close:  
  35.   if (suspend_ops->end)  
  36.    suspend_ops->end();  
  37.   return error;  
  38.  Recover_platform:  
  39.   if (suspend_ops->recover)  
  40.    suspend_ops->recover();  
  41.   goto Resume_devices;  
  42.  }  
  43. staticstruct platform_suspend_ops s3c_pm_ops = {  
  44.   .enter  = s3c_pm_enter, //作業系統暫存器的介面,裡面會使系統進入休眠/喚醒狀態,在其中會保留系統的暫存器的值,設定好外部喚醒源。執行完s3c_cpu_save系統就進入了休眠模式。
  45.   當系統被喚醒時,再從s3c_cpu_save這個函式下面開始執行。  
  46.   .prepare = s3c_pm_prepare,//為建立CRC校驗做準備,分配存放CRC值的記憶體。
  47.   .finish  = s3c_pm_finish,  
  48.   .valid  = suspend_valid_only_mem,  
  49.  };//這個是s5pv210中定義的平臺的電源管理操作介面,suspend_ops會指向這個結構體變數的指標
  50. staticint suspend_enter(suspend_state_t state)  
  51.  {  
  52.   int error;  
  53.  if (suspend_ops->prepare) {  
  54.    error = suspend_ops->prepare();  
  55.    if (error)  
  56.     return error;  
  57.   }  
  58.  error = dpm_suspend_noirq(PMSG_SUSPEND);  
  59.   if (error) {  
  60.    printk(KERN_ERR "PM: Some devices failed to power down\n");  
  61.    goto Platfrom_finish;  
  62.   }  
  63.  if (suspend_ops->prepare_late) {  
  64.    error = suspend_ops->prepare_late();  
  65.    if (error)  
  66.     goto Power_up_devices;  
  67.   }  
  68.  if (suspend_test(TEST_PLATFORM))  
  69.    goto Platform_wake;  
  70.  error = disable_nonboot_cpus();  
  71.   if (error || suspend_test(TEST_CPUS))  
  72.    goto Enable_cpus;  
  73.  arch_suspend_disable_irqs();  
  74.   BUG_ON(!irqs_disabled());  
  75.  error = sysdev_suspend(PMSG_SUSPEND);  
  76.   if (!error) {  
  77.    if (!suspend_test(TEST_CORE))  
  78.     error = suspend_ops->enter(state); //呼叫此函式進行休眠
  79.    sysdev_resume();  
  80.   }  
  81.  arch_suspend_enable_irqs();  
  82.   BUG_ON(irqs_disabled());  
  83.  Enable_cpus:  
  84.   enable_nonboot_cpus();  
  85.  Platform_wake:  
  86.   if (suspend_ops->wake)  
  87.    suspend_ops->wake();  
  88.  Power_up_devices:  
  89.   dpm_resume_noirq(PMSG_RESUME);  
  90.  Platfrom_finish:  
  91.   if (suspend_ops->finish)  
  92.    suspend_ops->finish();  
  93.  return error;  
  94.  }  
int suspend_devices_and_enter(suspend_state_t state)
 {
  int error;
  gfp_t saved_mask;
  /*判斷休眠的操作函式集合指標是否被賦值,此指標會在對應的平臺電源管理模組中被賦值
  在s5pv210平臺中是在plat-samsung/pm.c中*/
  if (!suspend_ops)   
  return -ENOSYS;
  if (suspend_ops->begin) {
   error = suspend_ops->begin(state);
   if (error)
    goto Close;
  }
  suspend_console();//suspend console subsystem,此時printk就不能列印資訊,但還有其他方式可以進行列印
  saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
  suspend_test_start();
  error = dpm_suspend_start(PMSG_SUSPEND);//在此函式裡,會調到驅動註冊的所有suspend函式,如果想知道suspend
  順序的話,可以在裡面打印出來。
  if (error) {
   printk(KERN_ERR "PM: Some devices failed to suspend\n");
   goto Recover_platform;
  }
  suspend_test_finish("suspend devices");
  if (suspend_test(TEST_DEVICES))
   goto Recover_platform;
 
 suspend_enter(state); //在此函式中會呼叫到系統的休眠功能,使系統進入sleep模式,而系統也就會停留在
  休眠的地方,當喚醒的時候再繼續往下執行。
 
 Resume_devices: //當系統被外部中斷喚醒的時候,這裡會被執行到
  suspend_test_start();
  dpm_resume_end(PMSG_RESUME);//此函式會執行resume流程,會呼叫驅動中註冊的所有resume函式。
  suspend_test_finish("resume devices");
  set_gfp_allowed_mask(saved_mask);
  resume_console();
  Close:
  if (suspend_ops->end)
   suspend_ops->end();
  return error;
 
 Recover_platform:
  if (suspend_ops->recover)
   suspend_ops->recover();
  goto Resume_devices;
 }
 
static struct platform_suspend_ops s3c_pm_ops = {
  .enter  = s3c_pm_enter, //作業系統暫存器的介面,裡面會使系統進入休眠/喚醒狀態,在其中會保留系統的暫存器的值,設定好外部喚醒源。執行完s3c_cpu_save系統就進入了休眠模式。
  當系統被喚醒時,再從s3c_cpu_save這個函式下面開始執行。
  .prepare = s3c_pm_prepare,//為建立CRC校驗做準備,分配存放CRC值的記憶體。
  .finish  = s3c_pm_finish,
  .valid  = suspend_valid_only_mem,
 };//這個是s5pv210中定義的平臺的電源管理操作介面,suspend_ops會指向這個結構體變數的指標
 
static int suspend_enter(suspend_state_t state)
 {
  int error;
 
 if (suspend_ops->prepare) {
   error = suspend_ops->prepare();
   if (error)
    return error;
  }
 
 error = dpm_suspend_noirq(PMSG_SUSPEND);
  if (error) {
   printk(KERN_ERR "PM: Some devices failed to power down\n");
   goto Platfrom_finish;
  }
 
 if (suspend_ops->prepare_late) {
   error = suspend_ops->prepare_late();
   if (error)
    goto Power_up_devices;
  }
 
 if (suspend_test(TEST_PLATFORM))
   goto Platform_wake;
 
 error = disable_nonboot_cpus();
  if (error || suspend_test(TEST_CPUS))
   goto Enable_cpus;
 
 arch_suspend_disable_irqs();
  BUG_ON(!irqs_disabled());
 
 error = sysdev_suspend(PMSG_SUSPEND);
  if (!error) {
   if (!suspend_test(TEST_CORE))
    error = suspend_ops->enter(state); //呼叫此函式進行休眠
   sysdev_resume();
  }
 
 arch_suspend_enable_irqs();
  BUG_ON(irqs_disabled());
 
 Enable_cpus:
  enable_nonboot_cpus();
 
 Platform_wake:
  if (suspend_ops->wake)
   suspend_ops->wake();
 
 Power_up_devices:
  dpm_resume_noirq(PMSG_RESUME);
 
 Platfrom_finish:
  if (suspend_ops->finish)
   suspend_ops->finish();
 
 return error;
 }


遇到喚醒/休眠不了的問題的定位方法:

首先要讓串列埠打印出來,開啟核心除錯選項,在s5pv210平臺中;

Kernel hacking  --->
         Kernel debugging
System Type  --->
        S3C2410 PM Suspend debug

開啟這兩個選項後,就可以列印休眠/喚醒前後的所有資訊。

如果需要檢視在哪個驅動喚醒/休眠出問題了,可以通過列印來定位。

注:late_resume要等到android設定on到/sys/power/state才會被呼叫到。