示例#1
0
/* usb function to perform async pm_request_power_change */
int
usb_req_raise_power(dev_info_t *dip, int comp, int level,
	void (*callback)(void *, int), void *arg, usb_flags_t flags)
{
	usba_pm_req_t *pmrq;

	if (flags & USB_FLAGS_SLEEP) {

		return (pm_raise_power(dip, comp, level));
	}

	if ((pmrq = kmem_alloc(sizeof (usba_pm_req_t), KM_NOSLEEP)) ==
	    NULL) {

		return (USB_FAILURE);
	}

	pmrq->dip = dip;
	pmrq->comp = comp;
	pmrq->level = level;
	pmrq->cb = callback;
	pmrq->arg = arg;
	pmrq->flags = flags;

	if (usb_async_req(dip, usba_async_req_raise_power,
	    (void *)pmrq, USB_FLAGS_NOSLEEP | USB_FLAGS_NOQUEUE) !=
	    USB_SUCCESS) {
		kmem_free(pmrq, sizeof (usba_pm_req_t));

		return (USB_FAILURE);
	}

	return (USB_SUCCESS);
}
示例#2
0
/*
 * destroy PM components
 */
static void
uftdi_destroy_pm_components(uftdi_state_t *uf)
{
	uftdi_pm_t *pm = uf->uf_pm;
	dev_info_t *dip = uf->uf_dip;
	int rval;

	if (!pm)
		return;

	if (uf->uf_dev_state != USB_DEV_DISCONNECTED) {
		if (pm->pm_wakeup_enabled) {
			rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
			if (rval != DDI_SUCCESS) {
				USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh,
				    "uftdi_destroy_pm_components: "
				    "raising power failed, rval=%d", rval);
			}
			rval = usb_handle_remote_wakeup(dip,
			    USB_REMOTE_WAKEUP_DISABLE);
			if (rval != USB_SUCCESS) {
				USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh,
				    "uftdi_destroy_pm_components: disable "
				    "remote wakeup failed, rval=%d", rval);
			}
		}
		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
	}
	kmem_free(pm, sizeof (*pm));
	uf->uf_pm = NULL;
}
示例#3
0
/*
 * wusb_df_destroy_power_mgmt:
 *	Shut down and destroy power management and remote wakeup functionality.
 */
static void
wusb_df_destroy_power_mgmt(wusb_df_state_t *wusb_dfp)
{
	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
	    "destroy_power_mgmt enter");

	ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex));

	mutex_enter(&wusb_dfp->wusb_df_mutex);
	if (!wusb_dfp->wusb_df_pm) {
		mutex_exit(&wusb_dfp->wusb_df_mutex);
		return;
	}
	mutex_exit(&wusb_dfp->wusb_df_mutex);

	(void) wusb_df_pm_busy_component(wusb_dfp);

	mutex_enter(&wusb_dfp->wusb_df_mutex);
	if (wusb_dfp->wusb_df_dev_state != USB_DEV_DISCONNECTED) {

		if (wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) {
			mutex_exit(&wusb_dfp->wusb_df_mutex);

			(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0,
			    USB_DEV_OS_FULL_PWR);
			if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip,
			    USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) {
				USB_DPRINTF_L2(PRINT_MASK_PM,
				    wusb_dfp->wusb_df_log_hdl,
				    "wusb_df_destroy_power_mgmt: "
				    "Error disabling rmt wakeup");
			}
			mutex_enter(&wusb_dfp->wusb_df_mutex);

		}
	}
	mutex_exit(&wusb_dfp->wusb_df_mutex);

	/*
	 * Since remote wakeup is disabled now,
	 * no one can raise power
	 * and get to device once power is lowered here.
	 */
	(void) pm_lower_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_PWR_OFF);
	wusb_df_pm_idle_component(wusb_dfp);

	mutex_enter(&wusb_dfp->wusb_df_mutex);
	kmem_free(wusb_dfp->wusb_df_pm, sizeof (wusb_df_power_t));
	wusb_dfp->wusb_df_pm = NULL;
	mutex_exit(&wusb_dfp->wusb_df_mutex);
}
示例#4
0
/*
 * wusb_df_init_power_mgmt:
 *	Initialize power management and remote wakeup functionality.
 *	No mutex is necessary in this function as it's called only by attach.
 */
static void
wusb_df_init_power_mgmt(wusb_df_state_t *wusb_dfp)
{
	wusb_df_power_t *wusb_dfpm;
	uint_t		pwr_states;

	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
	    "init_power_mgmt enter");

	/*
	 * If remote wakeup is not available you may not want to do
	 * power management.
	 */
	/* Allocate the state structure */
	wusb_dfpm = kmem_zalloc(sizeof (wusb_df_power_t), KM_SLEEP);
	wusb_dfp->wusb_df_pm = wusb_dfpm;
	wusb_dfpm->wusb_df_state = wusb_dfp;
	wusb_dfpm->wusb_df_pm_capabilities = 0;
	wusb_dfpm->wusb_df_current_power = USB_DEV_OS_FULL_PWR;

	if (usb_create_pm_components(wusb_dfp->wusb_df_dip, &pwr_states) ==
	    USB_SUCCESS) {

		USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
		    "wusb_df_init_power_mgmt: created PM components");

		wusb_dfpm->wusb_df_pwr_states = (uint8_t)pwr_states;
		(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0,
		    USB_DEV_OS_FULL_PWR);

		if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip,
		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
			wusb_dfpm->wusb_df_wakeup_enabled = 1;
		} else {
			USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
			    "wusb_df_init_power_mgmt:"
			    "fail to enable remote wakeup");
		}

	} else {
		USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
		    "wusb_df_init_power_mgmt: create_pm_compts failed");
	}
	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
	    "wusb_df_init_power_mgmt: end");

}
示例#5
0
static void
usba_async_req_raise_power(void *arg)
{
	usba_pm_req_t *pmrq = (usba_pm_req_t *)arg;
	int rval;

	/*
	 * To eliminate race condition between the call to power entry
	 * point and our call to raise power level, we first mark the
	 * component busy and later idle
	 */
	(void) pm_busy_component(pmrq->dip, pmrq->comp);
	rval = pm_raise_power(pmrq->dip, pmrq->comp, pmrq->level);
	(void) pm_idle_component(pmrq->dip, pmrq->comp);
	pmrq->cb(pmrq->arg, rval);

	/* We are done with pmrq. Free it now */
	kmem_free(pmrq, sizeof (usba_pm_req_t));
}
示例#6
0
/*
 * mark device busy and raise power
 */
static int
uftdi_pm_set_busy(uftdi_state_t *uf)
{
	uftdi_pm_t	*pm = uf->uf_pm;
	dev_info_t	*dip = uf->uf_dip;
	int		rval;

	USB_DPRINTF_L4(DPRINT_PM, uf->uf_lh, "uftdi_pm_set_busy");

	if (!pm)
		return (USB_SUCCESS);

	mutex_enter(&uf->uf_lock);
	/* if already marked busy, just increment the counter */
	if (pm->pm_busy_cnt++ > 0) {
		mutex_exit(&uf->uf_lock);
		return (USB_SUCCESS);
	}

	rval = pm_busy_component(dip, 0);
	ASSERT(rval == DDI_SUCCESS);

	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
		mutex_exit(&uf->uf_lock);
		return (USB_SUCCESS);
	}

	/* need to raise power	*/
	pm->pm_raise_power = B_TRUE;
	mutex_exit(&uf->uf_lock);

	rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
	if (rval != DDI_SUCCESS) {
		USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh, "raising power failed");
	}

	mutex_enter(&uf->uf_lock);
	pm->pm_raise_power = B_FALSE;
	mutex_exit(&uf->uf_lock);

	return (USB_SUCCESS);
}
示例#7
0
/*
 * wusb_df_cpr_resume:
 *
 *	wusb_df_restore_device_state marks success by putting device back online
 */
static void
wusb_df_cpr_resume(dev_info_t *dip)
{
	int		instance = ddi_get_instance(dip);
	wusb_df_state_t	*wusb_dfp =
	    ddi_get_soft_state(wusb_df_statep, instance);

	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_dfp->wusb_df_log_hdl,
	    "resume: enter");

	/*
	 * NOTE: A pm_raise_power in wusb_df_restore_device_state will bring
	 * the power-up state of device into synch with the system.
	 */
	wusb_df_pm_busy_component(wusb_dfp);
	(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR);
	mutex_enter(&wusb_dfp->wusb_df_mutex);
	wusb_df_restore_device_state(dip, wusb_dfp);
	mutex_exit(&wusb_dfp->wusb_df_mutex);
	wusb_df_pm_idle_component(wusb_dfp);
}
示例#8
0
/*
 * wusb_df_reconnect_callback:
 *	Called with device hotplug-inserted
 *		Restore state
 */
static int
wusb_df_reconnect_callback(dev_info_t *dip)
{
	int instance = ddi_get_instance(dip);
	wusb_df_state_t	*wusb_dfp =
	    ddi_get_soft_state(wusb_df_statep, instance);

	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
	    "reconnect: enter");

	wusb_df_pm_busy_component(wusb_dfp);
	(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR);

	mutex_enter(&wusb_dfp->wusb_df_mutex);
	(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
	wusb_df_restore_device_state(dip, wusb_dfp);
	wusb_df_release_access(wusb_dfp);
	mutex_exit(&wusb_dfp->wusb_df_mutex);

	wusb_df_pm_idle_component(wusb_dfp);

	return (USB_SUCCESS);
}
示例#9
0
/*
 * create PM components
 */
static int
uftdi_create_pm_components(uftdi_state_t *uf)
{
	dev_info_t	*dip = uf->uf_dip;
	uftdi_pm_t	*pm;
	uint_t		pwr_states;

	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
		USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh,
		    "uftdi_create_pm_components: failed");
		return (USB_SUCCESS);
	}

	pm = uf->uf_pm = kmem_zalloc(sizeof (*pm), KM_SLEEP);

	pm->pm_pwr_states = (uint8_t)pwr_states;
	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
	pm->pm_wakeup_enabled = usb_handle_remote_wakeup(dip,
	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS;

	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);

	return (USB_SUCCESS);
}
示例#10
0
文件: gen_drv.c 项目: andreiw/polaris
/*ARGSUSED*/
static int
gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
{
	struct dstate *dstatep;
	ddi_eventcookie_t cookie;
	int instance;
	int rval = 0;
	char *nodename;
	int i;
	struct devctl_iocdata *dcp;
	uint_t state;
	int ret;
	int level_tmp;

	instance = MINOR_TO_INST(getminor(dev));
	dstatep = ddi_get_soft_state(dstates, instance);
	nodename = dstatep->nodename;

	if (dstatep == NULL)
		return (ENXIO);

	/*
	 * read devctl ioctl data
	 */
	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
		return (EFAULT);

	switch (cmd) {
	case GENDRV_IOFAULT_SIMULATE:
		if (ddi_get_eventcookie(dstatep->dip, DDI_DEVI_FAULT_EVENT,
			    &(cookie)) != NDI_SUCCESS)
			return (DDI_FAILURE);

		return (ndi_post_event(dstatep->dip, dstatep->dip, cookie,
			    NULL));

	case GENDRV_NDI_EVENT_TEST:
		if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_offline",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_reset",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_reset",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_quiesce",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_unquiesce",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_test_post",
		    &cookie) == NDI_SUCCESS) {
			(void) ndi_post_event(dstatep->dip, dstatep->dip,
			    cookie, NULL);
		}

		break;

	case DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME:
		/*
		 * Issue pm_power_has_changed() call on DDI_RESUME
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag |= PWR_HAS_CHANGED_ON_RESUME_FLAG;
		mutex_exit(&dstatep->lock);
		GEN_DEBUG((CE_CONT, "%s%d:"
		    " DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME", nodename,
		    instance));

		break;

	case DEVCTL_PM_FAIL_SUSPEND:
		/*
		 * Fail the suspend attempt in DDI_SUSPEND
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag |= FAIL_SUSPEND_FLAG;
		mutex_exit(&dstatep->lock);
		GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_FAIL_SUSPEND",
		    nodename, instance));

		break;

	case DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED:
		/*
		 * Use pm_power_has_changed() to power up comp 0 when
		 * enforcing the comp 0 vs comp-not 0 dependency:
		 * Power up comp 0 first, if request for comp-not-0
		 * comes in.
		 * Else, default to pm_raise_power().
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag |= PUP_WITH_PWR_HAS_CHANGED_FLAG;
		mutex_exit(&dstatep->lock);
		GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED",
		    nodename, instance));

		break;

	case DEVCTL_PM_BUSY_COMP:
		/*
		 * mark component 0 busy via a pm_busy_component() call.
		 * update the busy[] array.
		 */
		mutex_enter(&dstatep->lock);
		++dstatep->busy[0];
		GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP: comp 0:"
		    " busy=%d", nodename, instance, dstatep->busy[0]));
		mutex_exit(&dstatep->lock);
		ret = pm_busy_component(dstatep->dip, 0);
		ASSERT(ret == DDI_SUCCESS);

		break;

	case DEVCTL_PM_BUSY_COMP_TEST:
		/*
		 * test busy state on component 0
		 */
		mutex_enter(&dstatep->lock);
		state = dstatep->busy[0];
		if (copyout(&state, dcp->cpyout_buf,
		    sizeof (uint_t)) != 0) {
			cmn_err(CE_WARN, "%s%d:"
			    " DEVCTL_PM_BUSY_COMP_TEST: copyout failed\n",
			    nodename, instance);
			rval = EINVAL;
		}
		GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP_TEST:"
		    " comp 0 busy %d",
		    nodename, instance, state));
		mutex_exit(&dstatep->lock);

		break;

	case DEVCTL_PM_IDLE_COMP:
		/*
		 * mark component 0 idle via a pm_idle_component() call.
		 * NOP if dstatep->busy[0] == 0.
		 */
		mutex_enter(&dstatep->lock);
		if (dstatep->busy[0] > 0) {
			--dstatep->busy[0];
			GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_IDLE_COMP:"
			    " comp 0: busy=%d", nodename, instance,
			    dstatep->busy[0]));
			mutex_exit(&dstatep->lock);
			ret = pm_idle_component(dstatep->dip, 0);
			ASSERT(ret == DDI_SUCCESS);
		} else {
			mutex_exit(&dstatep->lock);
		}

		break;

	case DEVCTL_PM_PROM_PRINTF:
		(void) prom_printf("%s%d: PROM_PRINTF FROM GEN_DRV\n",
		    nodename, instance);

		break;

	case DEVCTL_PM_RAISE_PWR:
		/*
		 * power up both components to MAXPWR via
		 * pm_raise_power() calls. this ioctl() cmd
		 * assumes that the current level is 0
		 */
		for (i = 0; i < COMPONENTS; i++) {
			GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_RAISE_PWR:"
			    " comp %d old 0 new %d",
			    nodename, instance, i, maxpwr[i]));
			if (pm_raise_power(dstatep->dip, 0, maxpwr[i])
			    != DDI_SUCCESS) {
				rval = EINVAL;
			}
		}

		break;

	case DEVCTL_PM_CHANGE_PWR_LOW:
		/*
		 * power off both components via pm_power_has_changed() calls
		 */
		for (i = (COMPONENTS - 1); i >= 0; --i) {
			GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_LOW:"
			    " comp %d new 0",
			    nodename, instance, i));
			mutex_enter(&dstatep->lock);
			level_tmp = dstatep->level[i];
			dstatep->level[i] = 0;
			if (pm_power_has_changed(dstatep->dip, i, 0)
			    != DDI_SUCCESS) {
				dstatep->level[i] = level_tmp;
				rval = EINVAL;
			}
			mutex_exit(&dstatep->lock);
		}

		break;

	case DEVCTL_PM_CHANGE_PWR_HIGH:
		/*
		 * power up both components to MAXPWR via
		 * pm_power_has_changed() calls
		 */
		for (i = 0; i < COMPONENTS; i++) {
			GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_HIGH:"
			    " comp %d new %d",
			    nodename, instance, i, maxpwr[i]));
			mutex_enter(&dstatep->lock);
			level_tmp = dstatep->level[i];
			dstatep->level[i] = maxpwr[i];
			if (pm_power_has_changed(dstatep->dip, i, maxpwr[i])
			    != DDI_SUCCESS) {
				dstatep->level[i] = level_tmp;
				rval = EINVAL;
			}
			mutex_exit(&dstatep->lock);
		}

		break;

	case DEVCTL_PM_POWER:
		/*
		 * test if the gen_drv_power() routine has been called,
		 * then clear
		 */
		mutex_enter(&dstatep->lock);
		state = (dstatep->flag & POWER_FLAG) ? 1 : 0;
		if (copyout(&state, dcp->cpyout_buf,
		    sizeof (uint_t)) != 0) {
			cmn_err(CE_WARN, "%s%d: DEVCTL_PM_POWER:"
			    " copyout failed\n", nodename, instance);
			rval = EINVAL;
		}
		GEN_DEBUG((CE_CONT, "%s%d: %s POWER_FLAG: %d",
		    nodename, instance, "DEVCTL_PM_POWER", state));
		dstatep->flag &= ~POWER_FLAG;
		mutex_exit(&dstatep->lock);
		break;

	case DEVCTL_PM_NO_LOWER_POWER:
		/*
		 * issue to not invoke pm_lower_power() on detach
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag &= ~LOWER_POWER_FLAG;
		mutex_exit(&dstatep->lock);
		GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_NO_LOWER_POWER",
			    nodename, instance));
		break;

	default:
		return (ENOTTY);
	}

	return (rval);
}
示例#11
0
文件: gen_drv.c 项目: andreiw/polaris
static int
gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int instance = ddi_get_instance(devi);
	struct dstate *dstatep;
	int rval;
	int n_devs;
	int n_minorcomps;
	int isclone;
	ddi_eventcookie_t dev_offline_cookie, dev_reset_cookie;
	ddi_eventcookie_t bus_reset_cookie, bus_quiesce_cookie;
	ddi_eventcookie_t bus_unquiesce_cookie, bus_test_post_cookie;
	int i_init = 0;
	int level_tmp;

	int i;
	char *pm_comp[] = {
		"NAME=leaf0",
		"0=D0",
		"1=D1",
		"2=D2",
		"3=D3",
		"NAME=leaf1",
		"0=off",
		"1=blank",
		"2=on"};
	char *pm_hw_state = {"needs-suspend-resume"};


	switch (cmd) {
	case DDI_ATTACH:

		if (ddi_soft_state_zalloc(dstates, instance) !=
		    DDI_SUCCESS) {
			cmn_err(CE_CONT, "%s%d: can't allocate state\n",
			    ddi_get_name(devi), instance);

			return (DDI_FAILURE);
		}

		dstatep = ddi_get_soft_state(dstates, instance);
		dstatep->dip = devi;
		mutex_init(&dstatep->lock, NULL, MUTEX_DRIVER, NULL);

		n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "ndevs", 1);

		isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "isclone", 0);

		n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "ncomps", 1);

		GEN_DEBUG((CE_CONT,
		    "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d",
		    ddi_get_name(devi), ddi_get_instance(devi),
		    n_devs, n_minorcomps, isclone));

		if (isclone) {
			if (ddi_create_minor_node(devi, "gen", S_IFCHR,
			    INST_TO_MINOR(instance), mnodetypes[0],
			    isclone) != DDI_SUCCESS) {
				ddi_remove_minor_node(devi, NULL);
				ddi_soft_state_free(dstates, instance);
				cmn_err(CE_WARN, "%s%d: can't create minor "
				"node", ddi_get_name(devi), instance);

				return (DDI_FAILURE);
			}
			rval = DDI_SUCCESS;
		} else {
			rval = gen_create_minor_nodes(devi, dstatep);
			if (rval != DDI_SUCCESS) {
				ddi_prop_remove_all(devi);
				ddi_remove_minor_node(devi, NULL);
				ddi_soft_state_free(dstates, instance);
				cmn_err(CE_WARN, "%s%d: can't create minor "
				"nodes", ddi_get_name(devi), instance);

				return (DDI_FAILURE);
			}
		}

		if (ddi_get_eventcookie(devi, "pshot_dev_offline",
		    &dev_offline_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, dev_offline_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[0]));
		}

		if (ddi_get_eventcookie(devi, "pshot_dev_reset",
		    &dev_reset_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, dev_reset_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[1]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_reset",
		    &bus_reset_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, bus_reset_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[2]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_quiesce",
		    &bus_quiesce_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, bus_quiesce_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[3]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_unquiesce",
		    &bus_unquiesce_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi,
			    bus_unquiesce_cookie, gen_event_cb,
			    NULL, &(dstatep->gen_cb_ids[4]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_test_post",
		    &bus_test_post_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi,
			    bus_test_post_cookie, gen_event_cb,
			    NULL, &(dstatep->gen_cb_ids[5]));
		}

		/*
		 * initialize the devices' pm state
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag &= ~OPEN_FLAG;
		dstatep->flag &= ~PWR_HAS_CHANGED_ON_RESUME_FLAG;
		dstatep->flag &= ~FAIL_SUSPEND_FLAG;
		dstatep->flag &= ~PUP_WITH_PWR_HAS_CHANGED_FLAG;
		dstatep->flag |= LOWER_POWER_FLAG;
		dstatep->flag &= ~NO_INVOL_FLAG;
		dstatep->flag |= PM_SUPPORTED_FLAG;
		dstatep->busy[0] = 0;
		dstatep->busy[1] = 0;
		dstatep->level[0] = -1;
		dstatep->level[1] = -1;
		mutex_exit(&dstatep->lock);

		/*
		 * stash the nodename
		 */
		dstatep->nodename = ddi_node_name(devi);

		/*
		 * Check if the no-involuntary-power-cycles property
		 * was created. Set NO_INVOL_FLAG if so.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
		    "no-involuntary-power-cycles") == 1) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles"
			    " property was created",
			    ddi_node_name(devi), ddi_get_instance(devi)));
			mutex_enter(&dstatep->lock);
			dstatep->flag |= NO_INVOL_FLAG;
			mutex_exit(&dstatep->lock);
		}

		/*
		 * Check if the dependency-property property
		 * was created.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
		    "dependency-property") == 1) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH:\n\tdependency-property"
			    " property was created",
			    ddi_node_name(devi), ddi_get_instance(devi)));
		}

		/*
		 * create the pm-components property. two comps:
		 * 4 levels on comp0, 3 on comp 1.
		 * - skip for a "tape" device, clear PM_SUPPORTED_FLAG
		 */
		if (strcmp(ddi_node_name(devi), "tape") != 0) {
			if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
			    "pm-components", pm_comp, 9) != DDI_PROP_SUCCESS) {
				cmn_err(CE_WARN, "%s%d: %s\n",
				    ddi_node_name(devi),
				    ddi_get_instance(devi),
				    "unable to create \"pm-components\" "
				    " property.");

				return (DDI_FAILURE);
			}
		} else {
			mutex_enter(&dstatep->lock);
			dstatep->flag &= ~PM_SUPPORTED_FLAG;
			mutex_exit(&dstatep->lock);
		}

		/*
		 * Check if the pm-components property was created
		 */
		if (dstatep->flag & PM_SUPPORTED_FLAG) {
			if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
			    "pm-components") != 1) {
				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s",
				    ddi_node_name(devi),
				    ddi_get_instance(devi),
				    "\"pm-components\" property does"
				    " not exist");

				return (DDI_FAILURE);

			} else {
				GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:"
				    " created pm-components property",
				    ddi_node_name(devi),
				    ddi_get_instance(devi)));
			}
		}

		/*
		 * create the pm-hardware-state property.
		 * needed to get DDI_SUSPEND and DDI_RESUME calls
		 */
		if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
		    "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s\n",
			    ddi_node_name(devi), ddi_get_instance(devi),
			    "unable to create \"pm-hardware-state\" "
			    " property.");

			return (DDI_FAILURE);
		}

		/*
		 * set power levels to max via pm_raise_power(),
		 */
		mutex_enter(&dstatep->lock);
		i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS;
		mutex_exit(&dstatep->lock);
		for (i = i_init; i < COMPONENTS; i++) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH: pm_raise_power comp %d "
			    "to level %d", ddi_node_name(devi),
			    ddi_get_instance(devi), i, maxpwr[i]));
			if (pm_raise_power(dstatep->dip, i, maxpwr[i]) !=
			    DDI_SUCCESS) {
				cmn_err(CE_WARN,
				    "%s%d: DDI_ATTACH: pm_raise_power failed\n",
				    ddi_node_name(devi),
				    ddi_get_instance(devi));
				dstatep->level[i] = -1;

				return (DDI_FAILURE);
			}
		}

		if (rval == DDI_SUCCESS) {
			ddi_report_dev(devi);
		}
		return (rval);


	case DDI_RESUME:
		GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME", ddi_node_name(devi),
		    ddi_get_instance(devi)));

		dstatep = ddi_get_soft_state(dstates, ddi_get_instance(devi));
		if (dstatep == NULL) {

			return (DDI_FAILURE);
		}

		/*
		 * Call pm_power_has_changed() if flag
		 * PWR_HAS_CHANGED_ON_RESUME_FLAG is set,
		 * then clear the flag
		 */
		mutex_enter(&dstatep->lock);
		i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS;
		mutex_exit(&dstatep->lock);
		if (dstatep->flag & PWR_HAS_CHANGED_ON_RESUME_FLAG) {
			for (i = i_init; i < COMPONENTS; i++) {
				GEN_DEBUG((CE_CONT,
				    "%s%d: DDI_RESUME: pm_power_has_changed "
				    "comp %d to level %d", ddi_node_name(devi),
				    ddi_get_instance(devi), i, maxpwr[i]));
				mutex_enter(&dstatep->lock);
				level_tmp = dstatep->level[i];
				dstatep->level[i] = maxpwr[i];
				if (pm_power_has_changed(dstatep->dip, i,
				    maxpwr[i]) != DDI_SUCCESS) {
					cmn_err(CE_WARN,
					    "%s%d: DDI_RESUME:\n\t"
					    " pm_power_has_changed"
					    " failed: comp %d to level %d\n",
					    ddi_node_name(devi),
					    ddi_get_instance(devi),
					    i, maxpwr[i]);
					dstatep->level[i] = level_tmp;
				}
				mutex_exit(&dstatep->lock);
			}
		} else {
			/*
			 * Call pm_raise_power() instead
			 */
			for (i = i_init; i < COMPONENTS; i++) {
				GEN_DEBUG((CE_CONT,
				    "%s%d: DDI_RESUME: pm_raise_power"
				    " comp %d to level %d",
				    ddi_node_name(devi), ddi_get_instance(devi),
				    i, maxpwr[i]));
				if (pm_raise_power(dstatep->dip, i, maxpwr[i])
				    != DDI_SUCCESS) {
					cmn_err(CE_WARN,
					    "%s%d: DDI_RESUME:"
					    "\n\tpm_raise_power"
					    "failed: comp %d to level %d\n",
					    ddi_node_name(devi),
					    ddi_get_instance(devi),
					    i, maxpwr[i]);
				}
			}
		}

		return (DDI_SUCCESS);

	default:
		GEN_DEBUG((CE_WARN, "attach: default"));
		return (DDI_FAILURE);
	}
}
示例#12
0
文件: gen_drv.c 项目: andreiw/polaris
/*ARGSUSED0*/
static int
gen_power(dev_info_t *dip, int cmpt, int level)
{
	struct dstate *dstatep;
	int instance = ddi_get_instance(dip);
	char *nodename = ddi_node_name(dip);
	int level_tmp;

	GEN_DEBUG((CE_CONT, "%s%d: power: cmpt %d to level %d",
	    nodename, instance, cmpt, level));

	dstatep = ddi_get_soft_state(dstates, instance);
	if (dstatep == NULL) {

		return (DDI_FAILURE);
	}

	/*
	 * Keep track of the power levels for both components
	 * in the dstatep->comp[] array.
	 * Set comp 0 to full level if non-zero comps
	 * are being set to a higher, non-zero level.
	 */
	if (cmpt == 0) {
		mutex_enter(&dstatep->lock);
		dstatep->level[cmpt] = level;
		mutex_exit(&dstatep->lock);
	} else if (level > dstatep->level[cmpt] && level != 0 &&
	    dstatep->level[0] != COMP_0_MAXPWR) {
		/*
		 * If component 0 is not at COMP_0_MAXPWR, and component 1
		 * is being powered ON, invoke pm_raise_power() or
		 * pm_power_has_changed() based on the
		 * PUP_WITH_PWR_HAS_CHANGED_FLAG flag.
		 * PUP_WITH_PWR_HAS_CHANGED_FLAG = FALSE by default, invoking
		 * pm_raise_power().
		 */
		if (!(dstatep->flag & PUP_WITH_PWR_HAS_CHANGED_FLAG)) {
			/*
			 * first set comp 0 to level COMP_0_MAXPWR
			 */
			GEN_DEBUG((CE_CONT, "%s%d: power:  "
			    "pm_raise_power: comp 0 to level %d",
			    nodename, instance, COMP_0_MAXPWR));
			if (pm_raise_power(dip, 0, COMP_0_MAXPWR) !=
			    DDI_SUCCESS) {
				cmn_err(CE_WARN,
				    "%s%d: power: pm_raise_power() "
				    "failed: comp 0 to level %d\n",
				    nodename, instance, COMP_0_MAXPWR);

				return (DDI_FAILURE);

			} else {
				mutex_enter(&dstatep->lock);
				dstatep->level[0] = COMP_0_MAXPWR;
				/*
				 * now set the level on the non-zero comp
				 */
				dstatep->level[cmpt] = level;
				mutex_exit(&dstatep->lock);
				GEN_DEBUG((CE_CONT, "%s%d: power: "
				    "comp %d to level %d",
				    nodename, instance, cmpt, level));
			}
		} else {
			GEN_DEBUG((CE_CONT, "%s%d: power: "
			    "pm_power_has_changed: comp 0 to level %d",
			    nodename, instance, COMP_0_MAXPWR));
			mutex_enter(&dstatep->lock);
			level_tmp = dstatep->level[0];
			dstatep->level[0] = COMP_0_MAXPWR;
			if (pm_power_has_changed(dip, 0, COMP_0_MAXPWR) !=
			    DDI_SUCCESS) {
				cmn_err(CE_WARN,
				    "%s%d: power: pm_power_has_changed() "
				    "failed: comp 0 to level %d\n",
				    nodename, instance, COMP_0_MAXPWR);
				dstatep->level[0] = level_tmp;
			} else {
				/*
				 * now set the level on the non-zero comp
				 */
				GEN_DEBUG((CE_CONT, "%s%d: power:"
				    " pm_power_has_changed: comp %d"
				    " to level %d", nodename, instance,
				    cmpt, level));
				dstatep->level[cmpt] = level;
			}
			mutex_exit(&dstatep->lock);
		}
	} else {
		mutex_enter(&dstatep->lock);
		dstatep->level[cmpt] = level;
		mutex_exit(&dstatep->lock);
	}

	return (DDI_SUCCESS);
}