126 lines
5.1 KiB
Plaintext
126 lines
5.1 KiB
Plaintext
Questions:
|
|
If we send an inrush IRP to A (which is inrush) and A sends it on
|
|
to B, which is not (so we'll process it normally), does anything weird happen?
|
|
|
|
Driver Rules:
|
|
1. Must call PoCallDriver for IRP_MJ_POWER regardless
|
|
of the minor code.
|
|
|
|
3. When a driver has received a power irp, and wishes to pass it
|
|
on to other drivers, the following rules apply.
|
|
|
|
a. The SystemContext field must be copied into the next stack location.
|
|
|
|
b. if a driver passes a given irp on to multiple parallel drivers
|
|
(for example, an FT driver that calls multiple disk drivers with
|
|
a single request) then the driver must pass the power irp on to
|
|
each driver one at a time. it could pass on multiple copies in
|
|
parallel, but if and only if they are not INRUSH.
|
|
|
|
4. If a single irp's stack of functions contains both Power functions and
|
|
non-power functions, the SystemContext field must be propogated accross
|
|
the non-power functions.
|
|
|
|
Example:
|
|
|
|
driver A gets MJ_PNP_POWER, MN_SET_POWER, incoming SystemContext = s0
|
|
|
|
A calls B with MJ_IOCTL, MN..., to get B to do some side function
|
|
associated with powering down (flushing a hardware cache, say)
|
|
|
|
B calls C with MJ_POWER, MN_SET_POWER, ...
|
|
|
|
Then A must pass SystemContext on to B, which must pass it on to C
|
|
(via a call to PoCallDriver) PoCallDriver may modify the SystemContext
|
|
that was passed in, so that C gets a different one.
|
|
|
|
If this is not done, when the power IRP is passed to C, PoCallDriver won't
|
|
know it's a continuation of a previous IRP, and therefore may do the wrong
|
|
thing.
|
|
|
|
(For example, if A and C have INRUSH set, and B doesn't pass on the
|
|
SystemContext value passed into A, then when B does PoCallDriver(C, irp)
|
|
it will be enqueued forever because PoCallDriver thinks it is
|
|
another, different, inrush irp.)
|
|
|
|
5. Any code that fills in a stack location with the first Power function
|
|
of that IRP's stack must set SystemContext to 0.
|
|
|
|
@@ inrush will lead to deadlocks if two inrush DOs are ever in the same
|
|
stack
|
|
!!> special context rules allow an irp to flow up and down a stack,
|
|
need to be sure this is well doc'd.
|
|
if a driver has D0_INRUSH set, and an INRUSH irp arrives, that irp
|
|
might get held up waiting for some other irp to clear in that driver.
|
|
(e.g. some other driver power state irp that didn't set power TO D0
|
|
might hold up all inrush irps in the system)
|
|
if DO is marked inrush, we will always call it at DPC level, just
|
|
to avoid confusion over what is pageable and what is not.
|
|
|
|
inrush applies only to device irps, or to device irps and system irps?
|
|
if the later, then an inrush DO can only ever see one irp at time regardless
|
|
of type!!!
|
|
!!> driver can receive a SystemPowerState irp even while INRUSH is locked.
|
|
|
|
!!> when calling any driver that does not set PAGE or INRUSH, we must call
|
|
it from a worker thread at IRQL 0, regardless of where PoCallDriver was called.
|
|
if it is an INPAGE device, we must call it from DPC at IRQL 2.
|
|
not sure about INRUSH, I think it's at DPC too.
|
|
|
|
?? how will MN_POWER_SEQUENCE and MN_WAIT_WAKE fit into all this?
|
|
|
|
DOE content
|
|
|
|
The contents of the DOE are 100% private. There is a special
|
|
declaration that allows the PoSetDeviceBusy() call to be a macro.
|
|
(Actually, best if PoSetDeviceBusy() takes a system returned pointer,
|
|
then there are no longer any fixed offsets to worry about.)
|
|
|
|
The idea is that any value not needed by every DO is stored in a
|
|
power control block (POB). Any operation that might allocate this
|
|
object must allow for failure of the allocation!!!
|
|
|
|
|
|
SPEC NOTES:
|
|
Any operation that might allocate a POB must allow for failure to allocate.
|
|
None of the DOE data is public.
|
|
|
|
|
|
Power irp rules. Allowed one DevicePowerState and one SystemPowerState
|
|
irp at a time.
|
|
|
|
Context Values:
|
|
If low order bit of the context field is 1, it is a flag.
|
|
If 0, it is a pointer.
|
|
If the whole thing is null, then no value.
|
|
So:
|
|
if (SystemContext == 0)
|
|
no context set
|
|
else if (SystemContext & 1)
|
|
test for flag values
|
|
else
|
|
it's a pointer to some structure
|
|
|
|
(need to change some code to match this.)
|
|
|
|
IRP Queues:
|
|
Use a single global holding queue. When a DO is busy, the IRP is
|
|
enqueued on the tail of this queue. Whenever a power IRP completes
|
|
AND the "pending" bit is set, run the entire list looking for an
|
|
IRP of that type for that DO, and dispatch it to the DO if we find it.
|
|
|
|
This means that each DOE has only 2 bits to mark S and D active,
|
|
and 2 bits to mark S and D pending.
|
|
|
|
If we search the entire list and do not find any Irps for that DO,
|
|
then the pending bit is cleared along with the active one.
|
|
|
|
|
|
Power IRPs, Inrush, and copying
|
|
Globally, only one IRP is allowed to be active on any INRUSH DO in
|
|
the system at any time.
|
|
|
|
Active and Pending bits have different meanings for INRUSH DevObj
|
|
than for normal devobj.
|
|
|