首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 电源管理在ARM上的实现原理(2)

Linux 电源管理在ARM上的实现原理(2)

//这个poll/select的后端实现, 用于查询有没有数据可读
static unsigned int apm_poll(struct file *fp, poll_table *wait)
{
   struct apm_user *as =fp->private_data;
   poll_wait(fp,&apm_waitqueue, wait);
   returnqueue_empty(&as->queue) ? 0 : POLLIN| POLLRDNORM;
}
//这个是这个设备的核心函数, 用于内核与用户空间交互
static int apm_ioctl(struct inode * inode, struct file *filp, u_intcmd, u_long arg)
{
   struct apm_user *as =filp->private_data;
   int err = -EINVAL;
//只有超级用户才能执行回复
   if (!as->suser|| !as->writer)
     return -EPERM;
   switch (cmd) {
    case APM_IOC_SUSPEND:
         mutex_lock(&state_lock);
           as->suspend_result = -EINTR;
           switch (as->suspend_state) {
//这个就是当user读取到event时的状态,这是发送这个事件,意味着这是回应ack
                case SUSPEND_READ:
                     as->suspend_state= SUSPEND_ACKED;
                    atomic_dec(&suspend_acks_pending);
                    mutex_unlock(&state_lock);
                    wake_up(&apm_suspend_waitqueue);
                    freezer_do_not_count();
                     wait_event(apm_suspend_waitqueue,as->suspend_state == SUSPEND_DONE);
                    freezer_count();
                     break;
                case SUSPEND_ACKTO:
                     as->suspend_result = -ETIMEDOUT;
                      mutex_unlock(&state_lock);
                     break;
                default:
                     as->suspend_state = SUSPEND_WAIT;
                      mutex_unlock(&state_lock);
                      as->suspend_result= pm_suspend(PM_SUSPEND_MEM);
            }
        mutex_lock(&state_lock);
         err= as->suspend_result;
         as->suspend_state= SUSPEND_NONE;
         mutex_unlock(&state_lock);
         break;
        }
    returnerr;
}

3, 事件队列函数

static void queue_event(apm_event_t event)
{
  struct apm_user *as;

down_read(&user_list_lock);
  list_for_each_entry(as,&apm_user_list, list) {
  if (as->reader)
//这个是将这个事件发给每个需要知道事件的apm_user
     queue_add_event(&as->queue,event);
  }
  up_read(&user_list_lock);

//唤醒等待读的进程
wake_up_interruptible(&apm_waitqueue);
}

static void queue_add_event(struct apm_queue *q, apm_event_tevent)
{
  q->event_head =(q->event_head + 1) % APM_MAX_EVENTS;
  if (q->event_head ==q->event_tail) {
    static int notified;
    if (notified++ == 0)
        printk(KERN_ERR "apm: an event queue overflowed\n");
     q->event_tail = (q->event_tail + 1) %APM_MAX_EVENTS;
   }
q->events[q->event_head] =event;
}

4,所有用户回复了,可以执行ioctl中的pm_suspend了这部分说明kernel里面的电源管理的核心函数,这部分的代码在/kernel/power/suspend.c中

int pm_suspend(suspend_state_t state)
{
  if (state > PM_SUSPEND_ON&& state <=PM_SUSPEND_MAX)
  return enter_state(state);
  return -EINVAL;
}
调用enter_state(),同样在supend.c中
int enter_state(suspend_state_t state)
{
  int error;
  if (!valid_state(state))
    return-ENODEV;
//获得锁, 参见注释
  if(!mutex_trylock(&pm_mutex))
    return-EBUSY;
  printk(KERN_INFO "PM: Syncing filesystems ...");
  sys_sync();
  printk("done.\n");
//prepare阶段
  pr_debug("PM: Preparing system for %s sleep\n",pm_states[state]);
  error = suspend_prepare();
  if (error)
    goto Unlock;
  if(suspend_test(TEST_FREEZER))
    goto Finish;
//进入阶段
  pr_debug("PM: Entering %s sleep\n",pm_states[state]);
  error = suspend_devices_and_enter(state);
//完成挂起, 恢复状态
Finish:
  pr_debug("PM: Finishing wakeup.\n");
  suspend_finish();
Unlock:
  mutex_unlock(&pm_mutex);
  return error;
}

4.1准备阶段,为进入supend状态做准备

static int suspend_prepare(void)
{
  int error;
  if (!suspend_ops ||!suspend_ops->enter)
    return -EPERM;
//allocate a console
  pm_prepare_console();
//Run suspend notifiers
  error =pm_notifier_call_chain(PM_SUSPEND_PREPARE);
  if (error)
    goto Finish;
  error =usermodehelper_disable();
  if (error)
    goto Finish;
//进程处理
   error =suspend_freeze_processes();
   if (!error)
     return 0;
  suspend_thaw_processes();
   usermodehelper_enable();
Finish:
  pm_notifier_call_chain(PM_POST_SUSPEND);
  pm_restore_console();
  return error;
}
继承事业,薪火相传
返回列表