平台信息:

内核: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)等;

然后调用下面这个函数;

  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.    
  27.  suspend_enter(state); //在此函数中会调用到系统的休眠功能,使系统进入sleep模式,而系统也就会停留在  
  28.   休眠的地方,当唤醒的时候再继续往下执行。  
  29.    
  30.  Resume_devices: //当系统被外部中断唤醒的时候,这里会被执行到  
  31.   suspend_test_start();  
  32.   dpm_resume_end(PMSG_RESUME);//此函数会执行resume流程,会调用驱动中注册的所有resume函数。  
  33.   suspend_test_finish("resume devices");  
  34.   set_gfp_allowed_mask(saved_mask);  
  35.   resume_console();  
  36.   Close:  
  37.   if (suspend_ops->end)  
  38.    suspend_ops->end();  
  39.   return error;  
  40.    
  41.  Recover_platform:  
  42.   if (suspend_ops->recover)  
  43.    suspend_ops->recover();  
  44.   goto Resume_devices;  
  45.  }  
  46.    
  47. static struct platform_suspend_ops s3c_pm_ops = {  
  48.   .enter  = s3c_pm_enter, //操作系统寄存器的接口,里面会使系统进入休眠/唤醒状态,在其中会保留系统的寄存器的值,设置好外部唤醒源。执行完s3c_cpu_save系统就进入了休眠模式。  
  49.   当系统被唤醒时,再从s3c_cpu_save这个函数下面开始执行。  
  50.   .prepare = s3c_pm_prepare,//为建立CRC校验做准备,分配存放CRC值的内存。  
  51.   .finish  = s3c_pm_finish,  
  52.   .valid  = suspend_valid_only_mem,  
  53.  };//这个是s5pv210中定义的平台的电源管理操作接口,suspend_ops会指向这个结构体变量的指针  
  54.    
  55. static int suspend_enter(suspend_state_t state)  
  56.  {  
  57.   int error;  
  58.    
  59.  if (suspend_ops->prepare) {  
  60.    error = suspend_ops->prepare();  
  61.    if (error)  
  62.     return error;  
  63.   }  
  64.    
  65.  error = dpm_suspend_noirq(PMSG_SUSPEND);  
  66.   if (error) {  
  67.    printk(KERN_ERR "PM: Some devices failed to power down\n");  
  68.    goto Platfrom_finish;  
  69.   }  
  70.    
  71.  if (suspend_ops->prepare_late) {  
  72.    error = suspend_ops->prepare_late();  
  73.    if (error)  
  74.     goto Power_up_devices;  
  75.   }  
  76.    
  77.  if (suspend_test(TEST_PLATFORM))  
  78.    goto Platform_wake;  
  79.    
  80.  error = disable_nonboot_cpus();  
  81.   if (error || suspend_test(TEST_CPUS))  
  82.    goto Enable_cpus;  
  83.    
  84.  arch_suspend_disable_irqs();  
  85.   BUG_ON(!irqs_disabled());  
  86.    
  87.  error = sysdev_suspend(PMSG_SUSPEND);  
  88.   if (!error) {  
  89.    if (!suspend_test(TEST_CORE))  
  90.     error = suspend_ops->enter(state); //调用此函数进行休眠  
  91.    sysdev_resume();  
  92.   }  
  93.    
  94.  arch_suspend_enable_irqs();  
  95.   BUG_ON(irqs_disabled());  
  96.    
  97.  Enable_cpus:  
  98.   enable_nonboot_cpus();  
  99.    
  100.  Platform_wake:  
  101.   if (suspend_ops->wake)  
  102.    suspend_ops->wake();  
  103.    
  104.  Power_up_devices:  
  105.   dpm_resume_noirq(PMSG_RESUME);  
  106.    
  107.  Platfrom_finish:  
  108.   if (suspend_ops->finish)  
  109.    suspend_ops->finish();  
  110.    
  111.  return error;  
  112.  }  
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才会被调用到。

Logo

更多推荐