Writing Device Drivers

detach(9E)

    int detach(dev_info_t *dip, ddi_detach_cmd_t cmd);

If a device has a reg property or a pm-hardware-state property with a value of needs-suspend-resume, then the framework calls into the driver's detach(9E) entry point to allow the driver to save the hardware state of the device to memory so that it can be restored after the system power returns. To process the DDI_SUSPEND command, detach(9E) must do the following:

If, for some reason, the driver is not able to suspend the device and save its state to memory, then it must return DDI_FAILURE, and the framework aborts the system power management operation.

Dump requests must be honored. The framework uses the dump(9E) entry point to write out the state file containing the contents of memory. See dump(9E) for restrictions imposed on the device driver when using this entry point.

If the device implements power-manageable components, the device may have had its state saved and powered off when its detach(9E) entry point is called with the DDI_SUSPEND command. In this case the driver should cancel pending timeouts and suppress the call to pm_raise_power(9F) (except for dump(9E) requests) until the device is resumed by a call to attach(9E) with a command of DDI_RESUME. The driver must keep sufficient track of its state to be able to deal appropriately with this possibility. Example 9-6 shows an example of a detach(9E) routine with the DDI_SUSPEND command implemented.


Example 9-6 detach(9E) Routine Implementing DDI_SUSPEND

int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
        struct xxstate *xsp;
        int instance;

        instance = ddi_get_instance(dip);
        xsp = ddi_get_soft_state(statep, instance);

        switch (cmd) {
        case DDI_DETACH:
          ...

        case DDI_SUSPEND:
                mutex_enter(&xsp->mu);
                xsp->xx_suspended = 1;  /* stop new operations */

                /*
                 * Sleep waiting for all the commands to be completed
                 */
                ...

                /*
                 * If a callback is outstanding which cannot be cancelled
                 * then either wait for the callback to complete or fail the
                 * suspend request
                 */
                ...

                /*
                 * This section is only needed if the driver maintains a
                 * running timeout
                 */
                if (xsp->xx_timeout_id) {
                        timeout_id_t temp_timeout_id = xsp->xx_timeout_id;

                        xsp->xx_timeout_id = 0;
                        mutex_exit(&xsp->mu);
                        untimeout(temp_timeout_id);
                        mutex_enter(&xsp->mu);
                }

                if (!xsp->xx_state_saved) {
                        /*
                         * Save device register contents into
                         * xsp->xx_device_state
                         */
                        ...
                }
                mutex_exit(&xsp->mu);
                return (DDI_SUCCESS);

        default:
                return (DDI_FAILURE);
}