/*ARGSUSED*/ static int mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { struct mouse_state *state; state = ddi_get_driver_private(dip); switch (cmd) { case DDI_SUSPEND: /* Ignore all data from mouse8042_intr until we fully resume */ state->ready = 0; return (DDI_SUCCESS); case DDI_DETACH: ddi_remove_intr(dip, 0, state->ms_iblock_cookie); mouse8042_dip = NULL; cv_destroy(&state->reset_cv); mutex_destroy(&state->reset_mutex); mutex_destroy(&state->ms_mutex); ddi_prop_remove_all(dip); ddi_regs_map_free(&state->ms_handle); ddi_remove_minor_node(dip, NULL); kmem_free(state, sizeof (struct mouse_state)); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }
/*ARGSUSED*/ static int logiattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int unit; struct driver_minor_data *dmdp; struct strmseinfo *logiptr = 0; #ifdef LOGI_DEBUG if (logi_debug) { PRF("logiattach entry\n"); } #endif switch (cmd) { case DDI_ATTACH: unit = ddi_get_instance(dip); for (dmdp = logi_minor_data; dmdp->name != NULL; dmdp++) { if (ddi_create_minor_node(dip, dmdp->name, dmdp->type, dmdp->minor, DDI_PSEUDO, NULL) == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); ddi_prop_remove_all(dip); #ifdef LOGI_DEBUG if (logi_debug) PRF("logiattach: " "ddi_create_minor_node failed\n"); #endif return (DDI_FAILURE); } } logiunits[unit] = dip; /* allocate and initialize state structure */ logiptr = kmem_zalloc(sizeof (struct strmseinfo), KM_SLEEP); logiptr->state = 0; /* not opened */ ddi_set_driver_private(dip, logiptr); if (ddi_add_intr(dip, (uint_t)0, &logiptr->iblock, (ddi_idevice_cookie_t *)0, logiintr, (caddr_t)logiptr) != DDI_SUCCESS) { #ifdef LOGI_DEBUG if (logi_debug) PRF("logiattach: ddi_add_intr failed\n"); #endif cmn_err(CE_WARN, "logi: cannot add intr\n"); return (DDI_FAILURE); } mutex_init(&logiptr->lock, NULL, MUTEX_DRIVER, (void *)logiptr->iblock); ddi_report_dev(dip); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }
/*ARGSUSED*/ static int logidetach(dev_info_t *dip, ddi_detach_cmd_t cmd) { dev_info_t *ldevi; struct strmseinfo *logiptr; int instance; switch (cmd) { case DDI_DETACH: /* * check if every instance can be unloaded before actually * starting to unload this one; this prevents the needless * detach/re-attach sequence */ for (instance = 0; instance < LOGI_MAXUNIT; instance++) { if (((ldevi = logiunits[instance]) == NULL) || (logiptr = ddi_get_driver_private(ldevi)) == NULL) continue; } /* * Undo what we did in logiattach & logiprobe, freeing resources * and removing things we installed. The system * framework guarantees we are not active with this devinfo * node in any other entry points at this time. */ instance = ddi_get_instance(dip); if ((instance >= LOGI_MAXUNIT) || (logiptr = ddi_get_driver_private(dip)) == NULL) return (DDI_FAILURE); logiunits[instance] = 0; ddi_prop_remove_all(dip); ddi_remove_minor_node(dip, NULL); mutex_destroy(&logiptr->lock); ddi_remove_intr(dip, 0, logiptr->iblock); kmem_free(logiptr, sizeof (struct strmseinfo)); return (DDI_SUCCESS); default: #ifdef LOGI_DEBUG if (logi_debug) { PRF("logidetach: cmd = %d unknown\n", cmd); } #endif return (DDI_FAILURE); } }
/* * wusb_df_cleanup: * clean up the driver state for detach */ static int wusb_df_cleanup(dev_info_t *dip, wusb_df_state_t *wusb_dfp) { USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl, "Cleanup: enter"); if (wusb_dfp->wusb_df_locks_initialized) { /* This must be done 1st to prevent more events from coming. */ usb_unregister_hotplug_cbs(dip); /* * At this point, no new activity can be initiated. The driver * has disabled hotplug callbacks. The Solaris framework has * disabled new opens on a device being detached, and does not * allow detaching an open device. * * The following ensures that all driver activity has drained. */ mutex_enter(&wusb_dfp->wusb_df_mutex); (void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG); wusb_df_release_access(wusb_dfp); mutex_exit(&wusb_dfp->wusb_df_mutex); /* All device activity has died down. */ wusb_df_destroy_power_mgmt(wusb_dfp); /* start dismantling */ ddi_remove_minor_node(dip, NULL); cv_destroy(&wusb_dfp->wusb_df_serial_cv); mutex_destroy(&wusb_dfp->wusb_df_mutex); } usb_client_detach(dip, wusb_dfp->wusb_df_reg); usb_free_log_hdl(wusb_dfp->wusb_df_log_hdl); if (wusb_dfp->wusb_df_devinst != NULL) { kmem_free(wusb_dfp->wusb_df_devinst, strlen(wusb_dfp->wusb_df_devinst) + 1); } ddi_soft_state_free(wusb_df_statep, ddi_get_instance(dip)); ddi_prop_remove_all(dip); return (USB_SUCCESS); }
/* * cpunex_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name. */ static int cpunex_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *cdip = (dev_info_t *)arg; int i; char caddr[MAXNAMELEN]; i = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", -1); if (i == -1) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property " "not found", ddi_node_name(cdip), ddi_get_instance(cdip)); return (DDI_NOT_WELL_FORMED); } (void) sprintf(caddr, "%d", i); ddi_set_name_addr(cdip, caddr); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); return (DDI_SUCCESS); } default: { return (ddi_ctlops(dip, rdip, op, arg, result)); } } }
/* ARGSUSED */ static int simmstat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { int instance; struct simmstat_soft_state *softsp; /* get the instance of this devi */ instance = ddi_get_instance(devi); /* get the soft state pointer for this device node */ softsp = ddi_get_soft_state(simmstatp, instance); switch (cmd) { case DDI_SUSPEND: return (DDI_SUCCESS); case DDI_DETACH: (void) fhc_bdlist_lock(softsp->board); if (fhc_bd_detachable(softsp->board)) break; else fhc_bdlist_unlock(); /* FALLTHROUGH */ default: return (DDI_FAILURE); } fhc_bdlist_unlock(); /* remove the kstat for this board */ kstat_delete(softsp->simmstat_ksp); /* unmap the registers */ ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->simmstat_base, 0, 0); /* free up the soft state */ ddi_soft_state_free(simmstatp, instance); ddi_prop_remove_all(devi); return (DDI_SUCCESS); }
static int kbad_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { int instance; register kbad_devstate_t *rsp; switch (cmd) { case DDI_DETACH: ddi_prop_remove_all(dip); instance = ddi_get_instance(dip); rsp = ddi_get_soft_state(kbad_state, instance); ddi_remove_minor_node(dip, NULL); ddi_soft_state_free(kbad_state, instance); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }
/*ARGSUSED*/ static int pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { if (cmd != DDI_DETACH) return (DDI_FAILURE); PPPT_GLOBAL_LOCK(); if (pppt_drv_busy()) { PPPT_GLOBAL_UNLOCK(); return (EBUSY); } ddi_remove_minor_node(dip, NULL); ddi_prop_remove_all(dip); pppt_global.global_svc_state = PSS_DETACHED; PPPT_GLOBAL_UNLOCK(); return (DDI_SUCCESS); }
/* * detach entry point: */ static int acebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { int instance = ddi_get_instance(dip); ebus_devstate_t *ebus_p = get_acebus_soft_state(instance); switch (cmd) { case DDI_DETACH: DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip); ddi_prop_remove_all(dip); kmem_free(ebus_p->rangep, ebus_p->range_cnt * sizeof (struct ebus_pci_rangespec)); free_acebus_soft_state(instance); return (DDI_SUCCESS); case DDI_SUSPEND: DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip); ebus_p->state = SUSPENDED; return (DDI_SUCCESS); } return (DDI_FAILURE); }
/** * Detach entry point, to detach a device to the system or suspend it. * * @param pDip The module structure instance. * @param enmCmd Operation type (detach/suspend). * * @return corresponding solaris error code. */ static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd) { LogFlowFunc(("VBoxDrvSolarisDetach\n")); switch (enmCmd) { case DDI_DETACH: { #ifndef USE_SESSION_HASH ddi_remove_minor_node(pDip, NULL); #else int instance = ddi_get_instance(pDip); vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance); ddi_remove_minor_node(pDip, NULL); ddi_soft_state_free(g_pVBoxDrvSolarisState, instance); #endif ddi_prop_remove_all(pDip); return DDI_SUCCESS; } case DDI_SUSPEND: { #if 0 RTSemFastMutexRequest(g_DevExt.mtxGip); if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0) RTTimerStop(g_DevExt.pGipTimer); RTSemFastMutexRelease(g_DevExt.mtxGip); #endif RTPowerSignalEvent(RTPOWEREVENT_SUSPEND); LogFlow(("vboxdrv: Falling to suspend mode.\n")); return DDI_SUCCESS; } default: return DDI_FAILURE; } }
static int gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { struct dstate *dstatep; int instance; int i; int rv; int rm_power; int level_tmp; #ifdef DEBUG int n_devs; int n_minorcomps; int isclone; #endif switch (cmd) { case DDI_DETACH: GEN_DEBUG((CE_CONT, "%s%d: DDI_DETACH", ddi_node_name(devi), ddi_get_instance(devi))); instance = ddi_get_instance(devi); dstatep = ddi_get_soft_state(dstates, instance); if (dstatep == NULL) { return (DDI_FAILURE); } #ifdef DEBUG 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); #endif /* DEBUG */ /* * power off component 1. */ if (dstatep->flag & PM_SUPPORTED_FLAG) { GEN_DEBUG((CE_CONT, "%s%d: DDI_DETACH: pm_lower_power comp 1 level %d", ddi_node_name(devi), ddi_get_instance(devi), MINPWR)); if (pm_lower_power(dstatep->dip, 1, MINPWR) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" "pm_lower_power failed for comp 1 to" " level %d\n", ddi_node_name(devi), ddi_get_instance(devi), MINPWR); return (DDI_FAILURE); } /* * check power level. Issue pm_power_has_changed * if not at MINPWR. */ mutex_enter(&dstatep->lock); level_tmp = dstatep->level[1]; dstatep->level[1] = MINPWR; if (dstatep->level[1] != MINPWR) { GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" " power off via pm_power_has_changed" " instead", ddi_node_name(devi), ddi_get_instance(devi))); if (pm_power_has_changed(dstatep->dip, 1, MINPWR) != DDI_SUCCESS) { GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" " pm_power_has_changed failed for" " comp 1 to level %d", ddi_node_name(devi), ddi_get_instance(devi), MINPWR)); dstatep->level[1] = level_tmp; mutex_exit(&dstatep->lock); return (DDI_FAILURE); } } mutex_exit(&dstatep->lock); } /* * If the LOWER_POWER_FLAG flag is not set, * don't call pm_lowr_power() for comp 0. * This should be used only for the XXXXX@XX,no_invol * devices that export the * no-involuntary-power-cycles property */ if (!(dstatep->flag & LOWER_POWER_FLAG) && dstatep->flag & PM_SUPPORTED_FLAG) { cmn_err(CE_NOTE, "%s%d: DDI_DETACH:\n\t" " NOT CALLING PM_LOWER_POWER():" " LOWER_POWER_FLAG NOT SET\n", ddi_node_name(devi), ddi_get_instance(devi)); } else if (dstatep->flag & PM_SUPPORTED_FLAG) { GEN_DEBUG((CE_CONT, "%s%d: DDI_DETACH: pm_lower_power comp 0 level %d", ddi_node_name(devi), ddi_get_instance(devi), MINPWR)); if (pm_lower_power(dstatep->dip, 0, MINPWR) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" "pm_lower_power failed for comp 0 to" " level %d\n", ddi_node_name(devi), ddi_get_instance(devi), MINPWR); return (DDI_FAILURE); } /* * check power level. Issue pm_power_has_changed * if not at MINPWR. */ mutex_enter(&dstatep->lock); level_tmp = dstatep->level[0]; dstatep->level[0] = MINPWR; if (dstatep->level[0] != MINPWR) { GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" " power off via pm_power_has_changed" " instead", ddi_node_name(devi), ddi_get_instance(devi))); if (pm_power_has_changed(dstatep->dip, 0, MINPWR) != DDI_SUCCESS) { GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" " pm_power_has_changed failed for" " comp 0 to level %d", ddi_node_name(devi), ddi_get_instance(devi), MINPWR)); dstatep->level[0] = level_tmp; mutex_exit(&dstatep->lock); return (DDI_FAILURE); } } mutex_exit(&dstatep->lock); } GEN_DEBUG((CE_CONT, "%s%d detaching: n_devs=%d n_minorcomps=%d isclone=%d", ddi_node_name(devi), ddi_get_instance(devi), n_devs, n_minorcomps, isclone)); for (i = 0; i < NUMEVENTS; i++) { if (dstatep->gen_cb_ids[i]) { (void) ddi_remove_event_handler(dstatep->gen_cb_ids[i]); dstatep->gen_cb_ids[i] = NULL; } } ddi_prop_remove_all(devi); ddi_remove_minor_node(devi, NULL); if (dstatep->node_type) kmem_free(dstatep->node_type, strlen(dstatep->node_type) + 1); ddi_soft_state_free(dstates, instance); return (DDI_SUCCESS); case DDI_SUSPEND: GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND", ddi_node_name(devi), ddi_get_instance(devi))); instance = ddi_get_instance(devi); dstatep = ddi_get_soft_state(dstates, instance); if (dstatep == NULL) { return (DDI_FAILURE); } /* * fail the suspend if FAIL_SUSPEND_FLAG is set. * clear the FAIL_SUSPEND_FLAG flag */ mutex_enter(&dstatep->lock); if (dstatep->flag & FAIL_SUSPEND_FLAG) { GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" " FAIL_SUSPEND_FLAG is set," " fail suspend", ddi_node_name(devi), ddi_get_instance(devi))); dstatep->flag &= ~FAIL_SUSPEND_FLAG; rv = DDI_FAILURE; } else { rv = DDI_SUCCESS; } mutex_exit(&dstatep->lock); /* * Issue ddi_removing_power() to determine if the suspend * was initiated by either CPR or DR. If CPR, the system * will be powered OFF; if this driver has set the * NO_INVOL_FLAG, then refuse to suspend. If DR, power * will not be removed, thus allow the suspend. */ if (dstatep->flag & NO_INVOL_FLAG && dstatep->flag & PM_SUPPORTED_FLAG) { GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" " check via ddi_removing_power()", ddi_node_name(devi), ddi_get_instance(devi))); rm_power = ddi_removing_power(dstatep->dip); if (rm_power < 0) { cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:" " ddi_removing_power() failed\n", ddi_node_name(devi), ddi_get_instance(devi)); } else if (rm_power == 1) { /* * CPR: power will be removed */ GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" " CPR: POWER WILL BE REMOVED, THEREFORE" " REFUSE TO SUSPEND", ddi_node_name(devi), ddi_get_instance(devi))); rv = DDI_FAILURE; } else if (rm_power == 0) { /* * DR: power will not be removed */ GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" " DR: POWER WILL NOT BE REMOVED, THEREFORE" " ALLOW THE SUSPEND", ddi_node_name(devi), ddi_get_instance(devi))); rv = DDI_SUCCESS; } } /* * power OFF via pm_power_has_changed() */ mutex_enter(&dstatep->lock); if (dstatep->flag & PM_SUPPORTED_FLAG && !(dstatep->flag & NO_INVOL_FLAG)) { level_tmp = dstatep->level[0]; dstatep->level[0] = MINPWR; GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND: pm_power_has_changed comp 0" " level %d", ddi_node_name(devi), ddi_get_instance(devi), MINPWR)); if (pm_power_has_changed(dstatep->dip, 0, MINPWR) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:\n\t" "pm_power_has_changed failed for comp 0 to" " level %d\n", ddi_node_name(devi), ddi_get_instance(devi), MINPWR); dstatep->level[0] = level_tmp; mutex_exit(&dstatep->lock); return (DDI_FAILURE); } } mutex_exit(&dstatep->lock); return (rv); default: return (DDI_FAILURE); } }
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); } }
static int gen_create_minor_nodes(dev_info_t *devi, struct dstate *dstatep) { int rval = DDI_SUCCESS; char *node_name; node_name = ddi_node_name(devi); if (strcmp(node_name, "disk_chan") == 0) { rval = gen_create_mn_disk_chan(devi); } else if (strcmp(node_name, "disk_wwn") == 0) { rval = gen_create_mn_disk_wwn(devi); } else if (strcmp(node_name, "disk_cdrom") == 0) { rval = gen_create_mn_disk_cdrom(devi); } else if (strcmp(node_name, "disk_fd") == 0) { rval = gen_create_mn_disk_fd(devi); } else if (strcmp(node_name, "cgtwenty") == 0) { rval = gen_create_display(devi); } else if (strcmp(node_name, "genzs") == 0) { rval = gen_create_serial(devi); } else if (strcmp(node_name, "net") == 0) { rval = gen_create_net(devi); } else { int instance = ddi_get_instance(devi); char *node_type; /* * Solaris may directly hang the node_type off the minor node * (without making a copy). Since we free the node_type * property below we need to make a private copy to pass * to ddi_create_minor_node to avoid devinfo snapshot panics. * We store a pointer to our copy in dstate and free it in * gen_detach after the minor nodes have been deleted by * ddi_remove_minor_node. */ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "node-type", &node_type) != 0) { cmn_err(CE_WARN, "couldn't get node-type\n"); return (DDI_FAILURE); } if (node_type) { dstatep->node_type = kmem_alloc( strlen(node_type) + 1, KM_SLEEP); (void) strcpy(dstatep->node_type, node_type); } ddi_prop_free(node_type); /* the minor name is the same as the node name */ if (ddi_create_minor_node(devi, node_name, S_IFCHR, (INST_TO_MINOR(instance)), dstatep->node_type, NULL) != DDI_SUCCESS) { if (dstatep->node_type) { kmem_free(dstatep->node_type, strlen(dstatep->node_type) + 1); dstatep->node_type = NULL; } return (DDI_FAILURE); } return (DDI_SUCCESS); } if (rval != DDI_SUCCESS) { ddi_prop_remove_all(devi); ddi_remove_minor_node(devi, NULL); } return (rval); }
/* * nx1394_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit * address). */ static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { int status; TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, ""); switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *ocdip, *cdip = (dev_info_t *)arg; dev_info_t *pdip = ddi_get_parent(cdip); int reglen, i; uint32_t *regptr; char addr[MAXNAMELEN]; TNF_PROBE_1(nx1394_bus_ctl_init_child, S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip); i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", (int **)®ptr, (uint_t *)®len); if (i != DDI_PROP_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Reg property not found", tnf_int, reason, i); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_NOT_WELL_FORMED); } ASSERT(reglen != 0); /* * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA] */ if (regptr[2] || regptr[3]) { (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0], regptr[1], regptr[2], regptr[3]); } else { (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]); } ddi_prop_free(regptr); ddi_set_name_addr(cdip, addr); /* * Check for a node with the same name & addr as the current * node. If such a node exists, return failure. */ if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) != NULL && ocdip != cdip) { cmn_err(CE_NOTE, "!%s(%d): Duplicate dev_info node found %s@%s", ddi_node_name(cdip), ddi_get_instance(cdip), ddi_node_name(ocdip), addr); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Duplicate nodes"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } /* * If HAL (parent dip) has "active-dma-flush" property, then * add property to child as well. Workaround for active * context flushing bug in Schizo rev 2.1 and 2.2. */ if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "active-dma-flush") != 0) { status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "active-dma-flush", 1); if (status != NDI_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): Unable to add " "\"active-dma-flush\" property", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Unable to add \"active-dma-flush\" " "property"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } } TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "uninitchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_IOMIN: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "iomin"); return (status); } case DDI_CTLOPS_POWER: { return (DDI_SUCCESS); } /* * These ops correspond to functions that "shouldn't" be called * by a 1394 client driver. */ case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: { cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)", ddi_node_name(dip), ddi_get_instance(dip), op, ddi_node_name(rdip), ddi_get_instance(rdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "invalid op", tnf_int, op, op); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_FAILURE); } /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ default: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (status); } } }