分享

Windows XP下usbhub.sys驱动内部实现解析(二)

 蜗牛an 2012-07-04
Windows XP下usbhub.sys驱动内部实现解析(二)
2010-01-25 13:14

6. power dispatch

这个部分处理很有模版化的趋势,先看fdo的处理:

query power

FdoQueryPower
{
if(bQuerySystemPower)
{
newDeviceState = map system state to device state
}
if(newDeviceState == D3)
{
if(fdo had submitted wait wake irp) 
cancel it // because we are going to d3 

PoStartNextPowerIrp 
PoCallDriver
}

wait wake

FdoWaitWake
{
set complete routine = FdoWaitWakeComplete 
PoStartNextPowerIrp 
PoCallDriver
}

wait wake complete

FdoWaitWakeComplete
{
if(irp->IoStatus->Status == STATUS_SUCCESS) 

request power irp to set device state to D0 
// in the complete routine,complete children port pdo\'s 
// wait wake irp with STATUS_SUCCESS 

else 

complete all children port pdo\'s wait wake irp with error 

}

set fdo system power state

FdoSetSystemPowerState
{
if(newSystemState == S0) 

if(currentDeviceState != D0) 

save this irp 
Request set device power d0 Irp 
return pending 

// in the complete routine,call down the saved set system power irp 

start next 
call down 

else 

if(some one need wait wake) 
// hub or device that connected to the hub 

newDeviceState =map system state to device state 

else newDeviceState = D3 

if(prevDeviceState == newDeviceState) 
// didn\'t need to change device state 

start next power irp 
call down 

else 

save the set system power irp 
request set device power state irp 
return pending 

// in the complete routine,call down the 
// saved set system power irp 
}
}

fdo set device power irp

FdoSetDevicePowerIrp
{
if(newState == prevState) 

start next call down return 
}

// is not the same
if(newState != D0) 

cancel interrupt transfer 

set complete routine = FdoSetDeviceStateComplete 
call down
}


set fdo device state complete

FdoSetDeviceStateComplete
{
if(irp->IoStatus.Status != STATUS_SUCCESS) 

start next 
return success 


if(newState == D0) 

if(prevState == D3) 

query work item = FdoSetPowerD0Worker 
save this irp 
return more_process_required 

submit interrupt transfer 
start next 

return success
}

fdo set power d0 worker

FdoSetPowerD0Worker

power on all ports 
flush changes when the hub was powered off 
invalidate bus relation 
submit interrupt transfer 
start next 
complete this power irp
}

pdo的power处理相对简单很多

pdo power dispatch

PdoPowerDispatch
{
if(minor == WAIT_WAKE) 

return PdoWaitWake 


if(pdoExt->ParentFdoExt->CurrentDevicePowerState != d0) 

if(minor == set || minor == query) 

request set parent hub d0 

// complete = PdoSetHubD0ForPowerProcess 
return pending 



switch(minor) 

case query 
return PdoQueryPower 
case set 
return PdoSetPower 
default 
status = pIrp->IoStatus.Status 
start next 
complete 
break 

return status
}

PdoSetHubD0ForPowerProcess
{
     switch(minor) 
     { 
     case query 
          PdoQueryPower 
     case set 
          PdoSetPower 
     default 
         start next 
         complete 
         break 
     } 
     return success
}

pdo wait wake

PdoWaitWake
{
set cancel routine 
save this irp 

if(!pdoExt->ParentFdo->WaitWakeIrpSubmitted) 

call PoRequestPowerIrp to request a wait wake power irp to the ParentFdo stack 
start next 
return pending 
}
}

pdo query power

PdoQueryPower
{
if(bQuery == query device state) 

start next 
return SUCCESS 


newDeviceState = map system state to device state 

if(newDeviceState != D3) 

start next 
return success 


// here new device state = D3 
if(!pdoExt->WaitWakeIrp) 

start next 
return success 


// here new state == D3,and has a wait wake irp pending 
if(newSystemState >= PowerSystemHibernate) 

start next 
return success 


// device new state is d3,this state can\'t wake system 
// and the system go to a wakable state 
// so fail it 
return STATUS_UNSUCCESSFUL
}

pdo set power state

PdoSetPowerState
{
if(bSetSystemPowerState) 

start next 
complete success 
return success 


if(newState == prevState) 

start next 
complete success 
return success 


switch(newState) 

case D0: 
if(prevState == D3) 

if(pdo is suspended) 
resume it 
else if(pdo is power down) 
power it 

check port status 
if(status & connected) 

tell usbport to reinit device handle 


else 

send clear suspend request 
complete idle request 
clear remote wakeup feature 

break 
case D1 
case D2 
if(prevState == D1 || prevState == D2) 

start next 
complete success 
return success 

if(pdoExt->WaitWakeIrp) 

// set hardware to support remote wake 
enable port 
set remote wakeup feature 


tell hardware to suspend port 
break 
case D3 
complete idle notification with status = POWER_STATE_INVALID 
complete wait wake with status = POWER_STATE_INVALID 

if no one request wait wake 
cancel parent hub\'s wait wake irp 
close port 
break 


start next 
complete success 
return success
}

处理的方式都是显而易见的,遵循ms的power处理的规范,没有什么特别注意的地方,查看msdn就能找到这个处理流程的描述。唯一一个让我觉得奇怪的是它并没有按照msdn所描述的那样调用PoSetPowerState函数,而且根据我跟踪分析的大多数驱动比如pci.sys、usbstor.sys、hidclass.sys、usbhub.sys这些都没有调用PoSetPowerState函数...令我觉得很是奇怪。

再回头来看idle notification这个request,至于这个idle request是用来干什么的,改设置什么参数,参考msdn。usbhub对这个的处理方式很直接,所以发送到pdo的idle notification request都设置一个cancel routine,然后保存起来。在某些地方检查整个hub是否进入了一个idle状态,if and only if所有的port上的设备都发送了idle notification的irp的时候,hub进入了idle状态,于是hub 回调每个port所提供的回调函数,然后往自己的parent hub发送一个idle notification request。而这个idle notification irp的完成,当然是在hub自己的idle request完成的时候,一一完成自己的每个port上的idle request。

usbhub的就到这里... (结束)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多