Writing Device Drivers

Device Power Management Interfaces

A device driver that supports a device with power-manageable components must notify the system of the existence of these components and their normal power values, and notify the system of the component state transitions from idle to busy and vice versa.

The notification of the existence of the components and their normal power values is typically done in the driver's attach(9E) entry point as part of driver initialization. The following interfaces handle creating and destroying device components and setting and getting the normal power levels of device components.

pm_create_components()

	int pm_create_components(dev_info_t *dip, int components);

pm_create_components(9F) notifies the system that the device indicated by dip has the number of components indicated by components. This function is called in the attach(9E) routine of the device driver.

pm_destroy_components()

	void pm_destroy_components(dev_info_t *dip);

pm_destroy_components(9F) removes all the components associated with the device indicated by dip from the system. This function is called in the detach(9E) routine.

pm_set_normal_power()

	pm_set_normal_power(dev_info_t *dip, int component, int level);

pm_set_normal_power(9F) sets the normal power level for the specified component. Whenever the system turns the component on again, it calls into the driver to set the current power level to normal power level.

pm_get_normal_power()

	pm_get_normal_power(dev_info_t *dip, int component);

pm_get_normal_power(9F) retrieves the current setting of the normal power level for a component.

Busy-Idle State Transitions

The driver must keep the framework informed of device state transitions from idle to busy or busy to idle. Where these transitions happen is entirely device specific. Some components are created and marked busy and never change. Some are created and never marked busy (components created by pm_create_components(9F) are created in an idle state). For example, a frame buffer currently supports two components: component 0 represents the frame buffer electronics and is always busy, and component 1 represents the monitor and is always idle (but dependent on the keyboard and mouse).


Note -

Component 0 represents the state of the device that would be lost if power is removed.


Some devices, such as the keyboard and mouse, are never marked busy but have their idle time reset each time a keystroke or mouse event is processed. The transitions from idle to busy and from busy to idle depend on the nature of the device and the abstraction represented by the specific component. For example, SCSI disk target drivers typically export a single component, which represents whether the SCSI target disk drive is spun up or not. It is marked busy whenever there is an outstanding request to the drive and idle when the last queued request finishes.

The following interfaces notify the Power Management framework of busy-idle state transitions.

pm_busy_component()

	int pm_busy_component(dev_info_t *dip, int component);

pm_busy_component(9F) marks the component as busy.

While the component is busy, it will not be powered off. If the component is already powered off, then marking it busy doesn't change its power level. The driver needs to call ddi_dev_is_needed(9F) for this purpose. Calls to pm_busy_component(9F) are stacked and require a corresponding number of calls to pm_idle_component(9F) to idle the component.

pm_idle_component()

	int pm_idle_component(dev_info_t *dip, int component);

pm_idle_component(9F) marks component as idle. An idle component is subject to being powered off.

pm_idle_component(9F) must be called once for each call to pm_busy_component(9F) in order to idle the component.

Device Power State Transitions

A device driver can call ddi_dev_is_needed(9F) to request that a component be set to a given power level. This is necessary before using a component that has been powered off. For example, a SCSI disk target driver's read(9E) or write(9E) routine might need to spin up the disk if it had been powered off before completing the read or write. ddi_dev_is_needed(9F) notifies the Power Management framework of device state transitions.

ddi_dev_is_needed()

	int ddi_dev_is_needed(dev_info_t *dip, int component,
 						 int level);

ddi_dev_is_needed(9F) is called when the driver discovers that a component needed for some operation has been powered off. This interface arranges for the driver to be called to set the current power level of the component to the level specified in the request. All the devices that depend on this component are also brought back to normal power by this call.

When a component has been powered off by pm(7D) and a request or interrupt occurs that requires the component to be powered up, the driver must call ddi_dev_is_needed(9F) so that the framework can restore the component (and all of the devices that depend on it) to normal power.