ret=count-i;
returnret;
}
//这个poll/select的后端实现,用于查询有没有数据可读
staticunsignedintapm_poll(structfile*fp,poll_table*wait)
{
structapm_user*as=fp->private_data;
poll_wait(fp,&apm_waitqueue,wait);
returnqueue_empty(&as->queue)?
0:
POLLIN|POLLRDNORM;
}
//这个是这个设备的核心函数,用于内核与用户空间交互
staticintapm_ioctl(structinode*inode,structfile*filp,u_intcmd,u_longarg)
{
structapm_user*as=filp->private_data;
interr=-EINVAL;
//只有超级用户才能执行回复
if(!
as->suser||!
as->writer)
return-EPERM;
switch(cmd){
caseAPM_IOC_SUSPEND:
mutex_lock(&state_lock);
as->suspend_result=-EINTR;
switch(as->suspend_state){
//这个就是当user读取到event时的状态,这是发送这个事件,意味着这是回应ack
caseSUSPEND_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;
caseSUSPEND_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,事件队列函数
staticvoidqueue_event(apm_event_tevent)
{
structapm_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);
}
staticvoidqueue_add_event(structapm_queue*q,apm_event_tevent)
{
q->event_head=(q->event_head+1)%APM_MAX_EVENTS;
if(q->event_head==q->event_tail){
staticintnotified;
if(notified++==0)
printk(KERN_ERR"apm:
aneventqueueoverflowed\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中
intpm_suspend(suspend_state_tstate)
{
if(state>PM_SUSPEND_ON&&state<=PM_SUSPEND_MAX)
returnenter_state(state);
return-EINVAL;
}
调用enter_state(),同样在supend.c中
intenter_state(suspend_state_tstate)
{
interror;
if(!
valid_state(state))
return-ENODEV;
//获得锁,参见注释
if(!
mutex_trylock(&pm_mutex))
return-EBUSY;
printk(KERN_INFO"PM:
Syncingfilesystems...");
sys_sync();
printk("done.\n");
//prepare阶段
pr_debug("PM:
Preparingsystemfor%ssleep\n",pm_states[state]);
error=suspend_prepare();
if(error)
gotoUnlock;
if(suspend_test(TEST_FREEZER))
gotoFinish;
//进入阶段
pr_debug("PM:
Entering%ssleep\n",pm_states[state]);
error=suspend_devices_and_enter(state);
//完成挂起,恢复状态
Finish:
pr_debug("PM:
Finishingwakeup.\n");
suspend_finish();
Unlock:
mutex_unlock(&pm_mutex);
returnerror;
}
4.1准备阶段,为进入supend状态做准备
staticintsuspend_prepare(void)
{
interror;
if(!
suspend_ops||!
suspend_ops->enter)
return-EPERM;
//allocateaconsole
pm_prepare_console();
//Runsuspendnotifiers
error=pm_notifier_call_chain(PM_SUSPEND_PREPARE);
if(error)
gotoFinish;
error=usermodehelper_disable();
if(error)
gotoFinish;
//进程处理
error=suspend_freeze_processes();
if(!
error)
return0;
suspend_thaw_processes();
usermodehelper_enable();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
returnerror;
}
4.2进入阶段,挂起设备。
intsuspend_devices_and_enter(suspend_state_tstate)
{
interror;
if(!
suspend_ops)
return-ENOSYS;
if(suspend_ops->begin){
error=suspend_ops->begin(state);
if(error)
gotoClose;
}
suspend_console();
suspend_test_start();
//挂起设备
error=dpm_suspend_start(PMSG_SUSPEND);
if(error){
printk(KERN_ERR"PM:
Somedevicesfailedtosuspend\n");
gotoRecover_platform;
}
suspend_test_finish("suspenddevices");
if(suspend_test(TEST_DEVICES))
gotoRecover_platform;
suspend_enter(state);
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resumedevices");
resume_console();
Close:
if(suspend_ops->end)
suspend_ops->end();
returnerror;
Recover_platform:
if(suspend_ops->recover)
suspend_ops->recover();
gotoResume_devices;
}
4.2.1挂起设备
intdpm_suspend_start(pm_message_tstate)
{
interror;
might_sleep();
error=dpm_prepare(state);
if(!
error)
error=dpm_suspend(state);
returnerror;
}
函数dpm_suspend_start()最后会调用dpm_suspend函数来挂起每个设备。
staticintdpm_suspend(pm_message_tstate)
{
structlist_headlist;
interror=0;
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
//遍历设备链表,当一个设备被注册进系统时,它同时会被加入到这个dpm_list队列中
while(!
list_empty(&dpm_list)){
structdevice*dev=to_device(dpm_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
//挂起这个设备
error=suspend_device(dev,state);
mutex_lock(&dpm_list_mtx);
if(error){
pm_dev_err(dev,state,"",error);
put_device(dev);
break;
}
dev->power.status=DPM_OFF;
//加入list队列,用于以后唤醒
if(!
list_empty(&dev->power.entry))
list_move(&dev->power.entry,&list);
put_device(dev);
}
list_splice(&list,dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
returnerror;
}
此函数又会调用suspend_device()函数挂起相应得设备,这个函数调用相应设备的suspend实现设备挂起.所以说,系统挂起时,设备也应该做相应的工作,由于设备的特殊性,这些就是留在设备里面来实现了.
staticintsuspend_device(structdevice*dev,pm_message_tstate)
{
interror=0;
down(&dev->sem);
if(dev->class){
if(dev->class->pm){
pm_dev_dbg(dev,state,"class");
error=pm_op(dev,dev->class->pm,state);
}elseif(dev->class->suspend){
pm_dev_dbg(dev,state,"legacyclass");
error=dev->class->suspend(dev,state);
suspend_report_result(dev->class->suspend,error);
}
if(error)
gotoEnd;
}
if(dev->type){
if(dev->type->pm){
pm_dev_dbg(dev,state,"type");
error=pm_op(dev,dev->type->pm,state);
}elseif(dev->type->suspend){
pm_dev_dbg(dev,state,"legacytype");
error=dev->type->suspend(dev,state);
suspend_report_result(dev->type->suspend,error);
}
if(error)
gotoEnd;
}
if(dev->bus){
if(dev->bus->pm){
pm_dev_dbg(dev,state,"");
error=pm_op(dev,dev->bus->pm,state);
}elseif(dev