pwr -- Power Management STREAMS protocol


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:

Length of this pmmsgblk structure in bytes.

Total length in bytes of the control header, including the pmmsgblk structure and any address lists (including padding).

Assorted message control flags including:

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.

The source of this PM event.

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 driver, module, or action name
PMADDR_IGNORE ignored address

 |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  |              |       | driver, module, |
 |               |              |              | or action name  |
 |PMADDR_PROCESS | PMPROC_MASK  |        | 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)

 |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)            |
 |             |                   | 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:

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.

 |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.    |

The type of PM event. The class determines the possible types:

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.

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).

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>.

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_STR ioctl (arg points to a strioctl structure; see streamio(M)).

Other ioctl requests recognized by pwr are defined in <sys/pwr.h>, and include:

Registers or unregisters this stack as belonging to the PM daemon (typically pwrd ) depending on the integer arg:

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.

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.

The unsigned integer return value from ioctl is the currently registered daemon's control bits (described in the PWR_SETCTRL ioctl).

The unsigned short return value from ioctl is the STREAMS module identification number of pwr.

If this stack belongs to the currently registered daemon, this sets the various control bits including:

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.

Depending on the integer arg, this either allows or prevents further opens of this stack:

Additional opens are allowed.

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.


In addition to the various errors described in the open(S), ioctl(S), getmsg(S), putmsg(S), and streamio(M) manual pages, the following errors are also possible:

A STREAMS message block could not be allocated; or the BIOS-APM firmware is currently busy.

An attempt was made to do one of the following:

An unknown uapm or pwr ioctl was attempted or attempted with an invalid arg.

One of the following occurred:

The BIOS-APM firmware polling frequency cannot be set and other uapm-implemented operations are not possible because the uapm driver is not installed.

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.


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.


pwr character special STREAMS file (usually a clone(M) device)

pwr ioctl definitions

PM STREAMS stack definitions

various system typedef definitions such as uchar_t

definition of the timeval structure

See also

getmsg(S), ioctl(S), open(S), putmsg(S), pwrd(ADM), pwrdump(ADM), pwrsend(ADM), pwrsh(ADM), streamio(M), uapm(HW)
© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003