The Power Management (PM) system is a
STREAMS stack serviced by the
pwrd(ADM)
daemon.
The driver at the bottom of the stack is
pwr, which typically uses the
uapm(HW)
interface to the machine's BIOS-APM firmware.
Other drivers participate in Power Management
when their associated PM STREAMS
module is pushed onto the pwr stack.
The pwr STREAMS driver neither
read(S)s
nor
write(S)s
any data, although STREAMS
modules pushed onto the stack might.
Most pwr operations are performed using
putmsg(S)
to send PM events and
getmsg(S)
to retrieve PM events.
Some operations are performed using
ioctl(S).
The pwr STREAMS
stack is an unreliable datagram protocol;
there is no acknowledgment or failure to assure that
any message was received.
The PM events (or messages) used in the
protocol consist of an event-independent control header,
an event description, and optional event-dependent data.
The control part of each message is defined in
<sys/pmmsg.h> and consists of a pmmsgblk
structure optionally followed by one or two lists of
pmaddr structures:
#pragma pack(1)
struct pmmsgblk {
uchar_t mclen; /* length of this control block */
uchar_t mtlen; /* total len (including addrs) */
ushort mflags; /* assorted flags */
struct pmaddr mfrom; /* who this message is from */
struct pmaddr mto; /* destination message is for */
};
struct pmaddr {
uchar_t atype; /* type of addr (PMADDR_xxx) */
uchar_t __areserved; /* reserved (but must be 0) */
ushort atypflgs; /* misc type-specific flags */
union {
ulong_t __aminsize;
dev_t devno; /* devno */
pid_t pid; /* process ID */
int modid; /* STREAMS ID */
struct pmdevid devid; /* APM dev ID */
struct pmxtra alist; /* pmaddr list */
char name[4]; /* ASCII string */
} a;
};
struct pmdevid {
uchar_t dclass; /* APM dev class (APMDEV_xxx) */
uchar_t dunit; /* APM unit number */
};
struct pmxtra {
ushort xoff; /* offset of list of pmaddr's */
ushort xnum; /* number pmaddr blocks in list */
};
#pragma pack()
Each PM event is addressed to (sent to)
one or more destinations. The addresses of the source of this
PM event and of each destination are encoded in one
pmaddr structure plus up to three extra
pmaddr structures.
An address requiring extra pmaddr
structures specifies the number of extra structures
in the two low order bits of the member
atypflgs (masked by PMATYPE_NUMBLKS).
Those extra structures follow immediately after the
pmaddr that requires them,
forming an array of two to four pmaddr structures.
The format of the extra structures depends on the address type.
If more than one pmaddr
is needed for either the source or destination addresses,
the source (mfrom) or destination (mto)
address is of type PMADDR_ADLIST;
the pmxtra structure alist
describes where the list of consecutive
pmaddr structures is relative to the start of the
pmmsgblk structure.
Such lists of addresses are always aligned congruent to
the size of a pmaddr structure;
the PMABLK_ADJ(n) macro rounds byte offset
n up to the proper boundary.
Lists of addresses are not recursive;
that is, a list of addresses cannot contain an address of type
PMADDR_ADLIST.
The pmmsgblk control header contains:
mclen
Length of this pmmsgblk structure in bytes.
mtlen
Total length in bytes of the control header, including the
pmmsgblk structure and any address lists (including padding).
mflags
Assorted message control flags including:
PMMFLG_ALLSRV
Normally, as soon as the PM
event is serviced by any destination,
the event is discarded.
If PMMFLG_ALLSRV is set,
an event is passed on to the next STREAMS
module for additional service
after being serviced by a destination.
In either case, STREAMS
modules are transparent if they are not destinations.
mfrom
The source of this PM event.
mto
The destination(s) of this PM event.
Should a future release or update of the system require an expanded
pmmsgblk structure, members will be added to its end.
Programs should therefore not assume that the control header is
sizeof(struct pmmsgblk) bytes long;
getmsg returns the total length of the control header
in the control structure, strbuf,
and the mclen member
contains the size in bytes of the header's
pmmsgblk structure.
The atype member in each pmaddr
structure that is not being used as an extension
in a list of addresses, determines how to interpret
the union member a and some bits in atypflgs:
atype
atypflgs
Union member
Description
PMADDR_CDEVNO
PMDEVNO_MASK
a.devno
character special device number
PMADDR_BDEVNO
PMDEVNO_MASK
a.devno
block special device number
PMADDR_SMODID
PMMODID_MASK
a.modid
STREAMS module identifier
PMADDR_ADEVID
PMAPMID_MASK
a.devid
BIOS-APM firmware identifier
PMADDR_ADLIST
a.alist
list of addresses
PMADDR_DMNAME
a.name
driver, module, or action name
PMADDR_PROCESS
PMPROC_MASK
a.pid
process identifier
PMADDR_IGNORE
ignored address
Mask
Bits
Description
PMDEVNO_MASK
PMDEVNO_ANYMAJOR
all devices (major number ignored)
PMDEVNO_ANYMINOR
all units (minor number ignored)
PMMODID_MASK
PMMODID_ANYSTREAM
all modules (STREAMS identifier ignored)
PMAPMID_MASK
PMAPMID_ANYCLASS
all BIOS-APM classes (a.devid.dclass ignored)
PMPROC_MASK
PMPROC_ANYPROCESS
all pwr stacks
Currently, only PMADDR_DMNAME names may have
extra blocks; these are the rest of the name started in the
name member.
For instance, if the module's internal name is ``plover''
then one extra pmaddr is needed.
The first four character of the name (``plov'')
are in the address' name and the second
pmaddr is an array containing the final two characters.
The remainder of the second structure should be filled with nulls
( \0 ).
There is no terminating null if the name
exactly fits in one or more pmaddr structures.
The PM event descriptions are the data part
of each message, and consist of a pmevent structure
followed by optional event-specific data:
#pragma pack(1)
struct pmevent {
ulong_t class; /* Classification (PMEVNT_xxx) */
ulong_t event; /* Event or error number */
struct timeval when; /* Time of this event or error */
};
#pragma pack()
Each pmevent structure contains the following members:
class
The category of PM event.
Classes defined by the operating system include:
Class
pwrevents(F)
Description
1
PMEVNT_APMEVENT
apm
BIOS-APM firmware-generated event
2
PMEVNT_APMERROR
apmerror
BIOS-APM firmware polling error
3
PMEVNT_SETPWR
set
place a peripheral into one of the four
PM states described in the
uapm(HW)
manual page.
event
The type of PM event. The class
determines the possible types:
PMEVNT_APMEVENT
Any of the BIOS-APM events defined in
<sys/apm.h>, such as APMEVT_STANDBY
and APMEVT_BATLOW.
These PM events are normally obtained by
periodically polling the firmware.
PMEVNT_APMERROR
Any of the BIOS-APM errors defined in
<sys/apm.h>. The periodic polling ignores
APMERR_NOEVENT errors when no PM
event occurs.
The only error possible is intended to be
APMERR_NOCONNECT
(no connection currently open to the firmware),
but some firmware is known to return
APMERR_DISABLED
(BIOS-APM firmware is currently disabled).
PMEVNT_SETPWR
Each BIOS-APM device to which this message is addressed
is put into the state defined in <sys/apm.h>, including
APMPWR_READY (Ready), APMPWR_STANDBY (Idle),
APMPWR_SUSPEND (Frozen), or APMPWR_OFF (Off).
Some machines can only Freeze the entire system.
Some machines can only turn Off individual peripherals,
but not the entire system.
Not every peripheral on all machines is controlled by the
BIOS-APM firmware; uncontrolled peripherals are
either Ready or Off but never Idle or Frozen.
See the
uapm(HW)
manual page for further discussion of the possible events,
errors, states, and <sys/apm.h>.
when
The time this PM
event was enqueued to be sent downstream towards the
pwrd daemon.
The timeval structure is defined
in <sys/select.h> and contains the
system's time in seconds since The Epoch
(tv_sec) plus the fraction of the
current second in microseconds (tv_usec).
PM events addressed to pwr
should either by sent by name to PWRXNAMEX
(pwr) or by STREAMS module ID
to PWRSTRID; both are defined in
<sys/pwr.h>. They may also be addressed to the
pwr stack's character special device number.
PM events addressed to the BIOS-APM
firmware are passed to uapm.
PM events obtained by uapm when polling the
BIOS-APM firmware are addressed to any STREAMS
module and any process, and marked for servicing by all destinations.
The pwr STREAMS driver recognizes all
ioctl requests by
uapm(HW).
uapm requests in which arg
is a pointer to something can be called in either the
traditional manner (arg points to the data) or as an
I_STRioctl (arg points to a
strioctl structure; see
streamio(M)).
Other ioctl requests recognized by pwr
are defined in <sys/pwr.h>, and include:
PWR_DAEMON
Registers or unregisters this stack as belonging to the
PM daemon (typically pwrd )
depending on the integer arg:
0
Unregister: this stack must be open for writing.
The integer return value from ioctl is
0 if no stack is currently registered;
1 if this stack was registered (and successfully unregistered);
or -1 on an error.
1
Register: this stack must be open for writing and
no other stack currently registered.
The integer return value from ioctl is
0 if this stack is already registered;
1 if this stack is now registered as the daemon;
or -1 on an error.
The last
close(S)
of the registered stack unregisters the stack.
PWR_GETCTRL
The unsigned integer return value from ioctl is
the currently registered daemon's control bits (described
in the PWR_SETCTRLioctl).
PWR_MODID
The unsigned short return value from ioctl is the
STREAMS module identification number of pwr.
PWR_SETCTRL
If this stack belongs to the currently registered daemon,
this sets the various control bits including:
PWRDMN_SEND
Send PM events (typically from the
BIOS-APM firmware) downstream towards
the currently-registered daemon.
No control bits are initialized,
and any subsequently set are cleared when the stack is unregistered.
PWR_XCLUDE
Depending on the integer arg,
this either allows or prevents further opens of this stack:
0
Additional opens are allowed.
1
Exclusive-use: no additional opens are allowed.
Exclusive-use mode can also be set by using the
O_EXCL flag in
open(S).
root (effective UID 0) cannot circumvent
the exclusive-use mode of pwr.
A STREAMS message block could not be allocated;
or the BIOS-APM firmware is currently busy.
[EBUSY]
An attempt was made to do one of the following:
open a pwr STREAMS
stack which is currently open for exclusive-use
register a stack when another stack is already registered
unregister or set the control bits on a stack which
is not registered.
[EINVAL]
An unknown uapm or pwr ioctl was attempted
or attempted with an invalid arg.
[EIO]
One of the following occurred:
a pmevent
could not be enqueued because the queue is full
a pmevent
could not be dequeued because the queue is empty
no calls to the BIOS-APM
firmware are currently allowed.
[ENOPKG]
The BIOS-APM firmware polling frequency
cannot be set and other uapm-implemented
operations are not possible because
the uapm driver is not installed.
[ENXIO]
An ioctl requiring a writable stack was
attempted on a stack not open for writing, or
boot(HW)
did not supply any information about this machine's
BIOS-APM firmware.
Other errors may occur on uapm ioctl
commands; see the
uapm(HW)
manual page for a description.
Limitations
BIOS-APM firmware from different manufacturers varies
considerably in both operation and efficacy.
What may be a safe or useful sequence of commands on one
machine may be ineffectual or worse on another.
Multiple source addresses are possible but should be avoided.
Process IDs (PIDs) in addresses are not verified.
Files
/dev/pwr/pm
pwr character special STREAMS
file (usually a
clone(M)
device)
/usr/include/sys/pwr.h
pwr ioctl
definitions
/usr/include/sys/pmmsg.h
PM STREAMS stack definitions
/usr/include/sys/types.h
various system typedef
definitions such as uchar_t