/*ARGSUSED*/ static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { /* * Use the minor number as constructed by pcihp, as the index value to * ddi_soft_state_zalloc. */ int instance = ddi_get_instance(devi); pci_state_t *pcip = NULL; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: return (DDI_SUCCESS); default: return (DDI_FAILURE); } if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci") != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "pci: 'device_type' prop create failed"); } if (ddi_soft_state_zalloc(pci_statep, instance) == DDI_SUCCESS) { pcip = ddi_get_soft_state(pci_statep, instance); } if (pcip == NULL) { goto bad_soft_state; } pcip->pci_dip = devi; pcip->pci_soft_state = PCI_SOFT_STATE_CLOSED; /* * Initialize hotplug support on this bus. At minimum * (for non hotplug bus) this would create ":devctl" minor * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls * to this bus. */ if (pcihp_init(devi) != DDI_SUCCESS) { cmn_err(CE_WARN, "pci: Failed to setup hotplug framework"); goto bad_pcihp_init; } /* Second arg: initialize for pci, not pci_express */ if (pcitool_init(devi, B_FALSE) != DDI_SUCCESS) { goto bad_pcitool_init; } pcip->pci_fmcap = DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc); mutex_init(&pcip->pci_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&pcip->pci_err_mutex, NULL, MUTEX_DRIVER, (void *)pcip->pci_fm_ibc); mutex_init(&pcip->pci_peek_poke_mutex, NULL, MUTEX_DRIVER, (void *)pcip->pci_fm_ibc); if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { pci_ereport_setup(devi); ddi_fm_handler_register(devi, pci_fm_callback, NULL); } ddi_report_dev(devi); return (DDI_SUCCESS); bad_pcitool_init: (void) pcihp_uninit(devi); bad_pcihp_init: ddi_soft_state_free(pci_statep, instance); bad_soft_state: return (DDI_FAILURE); }
static int sbbc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) { sbbc_softstate_t *softsp; int instance; uint32_t *pci_intr_enable_reg; int rc = DDI_SUCCESS; instance = ddi_get_instance(devi); if (!(softsp = ddi_get_soft_state(sbbcp, instance))) return (DDI_FAILURE); switch (cmd) { case DDI_DETACH: mutex_enter(&chosen_lock); softsp->sbbc_state |= SBBC_STATE_DETACH; mutex_exit(&chosen_lock); /* only tunnel switch the instance with iosram chosen */ if (softsp->chosen == TRUE) { if (sgsbbc_iosram_switchfrom(softsp) == DDI_FAILURE) { SBBC_ERR(CE_WARN, "Cannot unconfigure: " "tunnel switch failed\n"); return (DDI_FAILURE); } } /* Adjust linked list */ mutex_enter(&chosen_lock); sbbc_remove_instance(softsp); mutex_exit(&chosen_lock); sbbc_unmap_regs(softsp); mutex_destroy(&softsp->sbbc_lock); ddi_soft_state_free(sbbcp, instance); return (DDI_SUCCESS); case DDI_SUSPEND: mutex_enter(&softsp->sbbc_lock); if ((softsp->suspended == FALSE) && (softsp->chosen == TRUE)) { uint32_t tmp_intr_enabled = 0; /* * Disable Interrupts now, turn OFF both INT#A lines */ pci_intr_enable_reg = (uint32_t *) ((char *)softsp->sbbc_regs + SBBC_PCI_INT_ENABLE); ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, 0); /* * Set intr_in_enabled to 0 so the SC won't send * us interrupt. */ rc = iosram_read(SBBC_SC_INTR_ENABLED_KEY, 0, (caddr_t)&intr_in_enabled, sizeof (intr_in_enabled)); if (rc) { mutex_exit(&softsp->sbbc_lock); return (DDI_FAILURE); } rc = iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0, (caddr_t)&tmp_intr_enabled, sizeof (tmp_intr_enabled)); if (rc) { mutex_exit(&softsp->sbbc_lock); return (DDI_FAILURE); } } softsp->suspended = TRUE; mutex_exit(&softsp->sbbc_lock); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }
/** * Attach entry point, to attach a device to the system or resume it. * * @param pDip The module structure instance. * @param enmCmd Operation type (attach/resume). * * @returns corresponding solaris error code. */ static int VBoxVideoSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd) { LogFlow((DEVICE_NAME ":VBoxVideoSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd)); cmn_err(CE_NOTE, DEVICE_NAME ":attach\n"); switch (enmCmd) { case DDI_ATTACH: { drm_device_t *pState; int Instance = ddi_get_instance(pDip); int rc = ddi_soft_state_zalloc(g_pVBoxVideoSolarisState, Instance); if (rc == DDI_SUCCESS) { pState = ddi_get_soft_state(g_pVBoxVideoSolarisState, Instance); pState->dip = pDip; pState->driver = &g_VBoxVideoSolarisDRMDriver; /* * Register using the DRM module which will create the minor nodes */ void *pDRMHandle = drm_supp_register(pDip, pState); if (pDRMHandle) { pState->drm_handle = pDRMHandle; /* * Probe with our pci-id. * -XXX- is probing really required??? */ pState->drm_supported = DRM_UNSUPPORT; rc = drm_probe(pState, vboxvideo_pciidlist); if (rc == DDI_SUCCESS) { pState->drm_supported = DRM_SUPPORT; /* * Call the common attach DRM routine. */ rc = drm_attach(pState); if (rc == DDI_SUCCESS) { return DDI_SUCCESS; } else LogRel((DEVICE_NAME ":VBoxVideoSolarisAttach drm_attach failed.rc=%d\n", rc)); } else LogRel((DEVICE_NAME ":VBoxVideoSolarisAttach drm_probe failed.rc=%d\n", rc)); drm_supp_unregister(pDRMHandle); } else LogRel((DEVICE_NAME ":VBoxVideoSolarisAttach drm_supp_register failed.\n")); ddi_soft_state_free(g_pVBoxVideoSolarisState, Instance); } else LogRel((DEVICE_NAME ":VBoxVideoSolarisAttach failed to alloc memory for soft state.rc=%d\n", rc)); return DDI_FAILURE; } case DDI_RESUME: { /* Nothing to do here... */ return DDI_SUCCESS; } } 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 sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { int instance; sbbc_softstate_t *softsp; uint32_t *pci_intr_enable_reg; int len; #ifdef DEBUG char name[8]; #endif /* DEBUG */ instance = ddi_get_instance(devi); switch (cmd) { case DDI_ATTACH: if (ddi_soft_state_zalloc(sbbcp, instance) != 0) return (DDI_FAILURE); softsp = ddi_get_soft_state(sbbcp, instance); softsp->sbbc_instance = instance; /* * Set the dip in the soft state * And get interrupt cookies and initialize the * per instance mutex. */ softsp_init(softsp, devi); /* * Verify that an 'interrupts' property exists for * this device. If not, this instance will be ignored. */ if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, "interrupts", &len) != DDI_PROP_SUCCESS) { SBBC_ERR1(CE_WARN, "No 'interrupts' property for the " "SBBC instance %d\n", instance); return (DDI_FAILURE); } /* * Add this instance to the sbbc chosen iosram list * so that it can be used for tunnel switch. */ mutex_enter(&chosen_lock); softsp->sbbc_state = SBBC_STATE_INIT; sbbc_add_instance(softsp); /* * If this is the chosen IOSRAM and there is no master IOSRAM * yet, then let's set this instance as the master. * if there is a master alreay due to the previous tunnel switch * then keep as is even though this is the chosen. */ if (sgsbbc_iosram_is_chosen(softsp)) { ASSERT(master_iosram); softsp->iosram = master_iosram; master_iosram->sgsbbc = softsp; /* Do 'chosen' init only */ sbbc_chosen_init(softsp); } mutex_exit(&chosen_lock); #ifdef DEBUG (void) sprintf(name, "sbbc%d", instance); if (ddi_create_minor_node(devi, name, S_IFCHR, instance, NULL, NULL) == DDI_FAILURE) { mutex_destroy(&softsp->sbbc_lock); ddi_remove_minor_node(devi, NULL); ddi_soft_state_free(sbbcp, instance); return (DDI_FAILURE); } #endif /* DEBUG */ ddi_report_dev(devi); return (DDI_SUCCESS); case DDI_RESUME: if (!(softsp = ddi_get_soft_state(sbbcp, instance))) return (DDI_FAILURE); mutex_enter(&softsp->sbbc_lock); if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) { /* * Enable Interrupts now, turn on both INT#A lines */ pci_intr_enable_reg = (uint32_t *) ((char *)softsp->sbbc_regs + SBBC_PCI_INT_ENABLE); ddi_put32(softsp->sbbc_reg_handle1, pci_intr_enable_reg, (uint32_t)SBBC_PCI_ENABLE_INT_A); /* * Reset intr_in_enabled to the original value * so the SC can send us interrupt. */ if (iosram_write(SBBC_SC_INTR_ENABLED_KEY, 0, (caddr_t)&intr_in_enabled, sizeof (intr_in_enabled))) { mutex_exit(&softsp->sbbc_lock); return (DDI_FAILURE); } } softsp->suspended = FALSE; mutex_exit(&softsp->sbbc_lock); return (DDI_SUCCESS); default: return (DDI_FAILURE); } }
static int ztdummy_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct ztdummy_state *ztd; int instance, status; char *getdev_name; cyc_time_t when; cyc_handler_t hdlr; switch (cmd) { case DDI_RESUME: cmn_err(CE_CONT, "ztdummy: Ignoring attach_RESUME"); return DDI_FAILURE; case DDI_PM_RESUME: cmn_err(CE_CONT, "ztdummy: Ignoring attach_PM_RESUME"); return DDI_FAILURE; case DDI_ATTACH: break; default: cmn_err(CE_CONT, "ztdummy: unknown attach command %d", cmd); return DDI_FAILURE; } instance = ddi_get_instance(dip); if (ddi_soft_state_zalloc(ztdummy_statep, instance) != DDI_SUCCESS) { cmn_err(CE_CONT, "ztdummy%d: Failed to alloc soft state", instance); return DDI_FAILURE; } /* Get pointer to that memory */ ztd = ddi_get_soft_state(ztdummy_statep, instance); if (ztd == NULL) { cmn_err(CE_CONT, "ztdummy: Unable to allocate memory\n"); ddi_soft_state_free(ztdummy_statep, instance); return DDI_FAILURE; } ztd->dip = dip; if (ztdummy_initialize(ztd)) { cmn_err(CE_CONT, "ztdummy: Unable to intialize zaptel driver\n"); ddi_soft_state_free(ztdummy_statep, instance); return DDI_FAILURE; } /* * Setup a high-resolution timer using an undocumented API in the kernel * * For more information visit the URL below: * http://blogs.sun.com/roller/page/eschrock?entry=inside_the_cyclic_subsystem * */ hdlr.cyh_func = ztdummy_timer; hdlr.cyh_arg = 0; hdlr.cyh_level = CY_LOW_LEVEL; when.cyt_when = 0; when.cyt_interval = 1000000; /* every 1ms */ mutex_enter(&cpu_lock); ztd->cyclic = cyclic_add(&hdlr, &when); mutex_exit(&cpu_lock); if (debug) cmn_err(CE_CONT, "ztdummy: init() finished\n"); return 0; }
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 VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred) { LogFlowFunc(("VBoxDrvSolarisClose: Dev=%#x\n", Dev)); #ifndef USE_SESSION_HASH /* * Get the session and free the soft state item. */ vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev)); if (!pState) { LogRel(("VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev))); return EFAULT; } PSUPDRVSESSION pSession = pState->pSession; pState->pSession = NULL; ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev)); if (!pSession) { LogRel(("VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev))); return EFAULT; } LogFlow(("VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() )); #else const RTPROCESS Process = RTProcSelf(); const unsigned iHash = SESSION_HASH(Process); PSUPDRVSESSION pSession; /* * Remove from the hash table. */ RTSpinlockAcquire(g_Spinlock); pSession = g_apSessionHashTab[iHash]; if (pSession) { if (pSession->Process == Process) { g_apSessionHashTab[iHash] = pSession->pNextHash; pSession->pNextHash = NULL; } else { PSUPDRVSESSION pPrev = pSession; pSession = pSession->pNextHash; while (pSession) { if (pSession->Process == Process) { pPrev->pNextHash = pSession->pNextHash; pSession->pNextHash = NULL; break; } /* next */ pPrev = pSession; pSession = pSession->pNextHash; } } } RTSpinlockRelease(g_Spinlock); if (!pSession) { LogRel(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n", (int)Process)); return EFAULT; } #endif /* * Close the session. */ supdrvSessionRelease(pSession); return 0; }
/** * open() worker. */ static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred) { const bool fUnrestricted = getminor(*pDev) == 0; PSUPDRVSESSION pSession; int rc; LogFlowFunc(("VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev)); /* * Validate input */ if ( (getminor(*pDev) != 0 && getminor(*pDev) != 1) || fType != OTYP_CHR) return EINVAL; /* See mmopen for precedent. */ #ifndef USE_SESSION_HASH /* * Locate a new device open instance. * * For each open call we'll allocate an item in the soft state of the device. * The item index is stored in the dev_t. I hope this is ok... */ vbox_devstate_t *pState = NULL; unsigned iOpenInstance; for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++) { if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */ && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS) { pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance); break; } } if (!pState) { LogRel(("VBoxDrvSolarisOpen: too many open instances.\n")); return ENXIO; } /* * Create a new session. */ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession); if (RT_SUCCESS(rc)) { pSession->Uid = crgetruid(pCred); pSession->Gid = crgetrgid(pCred); pState->pSession = pSession; *pDev = makedevice(getmajor(*pDev), iOpenInstance); LogFlow(("VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() )); return 0; } /* failed - clean up */ ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance); #else /* * Create a new session. * Sessions in Solaris driver are mostly useless. It's however needed * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl() */ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession); if (RT_SUCCESS(rc)) { unsigned iHash; pSession->Uid = crgetruid(pCred); pSession->Gid = crgetrgid(pCred); /* * Insert it into the hash table. */ # error "Only one entry per process!" iHash = SESSION_HASH(pSession->Process); RTSpinlockAcquire(g_Spinlock); pSession->pNextHash = g_apSessionHashTab[iHash]; g_apSessionHashTab[iHash] = pSession; RTSpinlockRelease(g_Spinlock); LogFlow(("VBoxDrvSolarisOpen success\n")); } int instance; for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++) { vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance); if (pState) break; } if (instance >= DEVICE_MAXINSTANCES) { LogRel(("VBoxDrvSolarisOpen: All instances exhausted\n")); return ENXIO; } *pDev = makedevice(getmajor(*pDev), instance); #endif return VBoxSupDrvErr2SolarisErr(rc); }
static int acpinex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { int instance; acpinex_softstate_t *softsp; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: return (DDI_SUCCESS); default: return (DDI_FAILURE); } /* Get and check instance number. */ instance = ddi_get_instance(devi); if (instance >= ACPINEX_INSTANCE_MAX) { cmn_err(CE_WARN, "acpinex: instance number %d is out of range " "in acpinex_attach(), max %d.", instance, ACPINEX_INSTANCE_MAX - 1); return (DDI_FAILURE); } /* Get soft state structure. */ if (ddi_soft_state_zalloc(acpinex_softstates, instance) != DDI_SUCCESS) { cmn_err(CE_WARN, "!acpinex: failed to allocate soft state " "object in acpinex_attach()."); return (DDI_FAILURE); } softsp = ddi_get_soft_state(acpinex_softstates, instance); /* Initialize soft state structure */ softsp->ans_dip = devi; (void) ddi_pathname(devi, softsp->ans_path); if (ACPI_FAILURE(acpica_get_handle(devi, &softsp->ans_hdl))) { ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to get ACPI handle for %s.", softsp->ans_path); ddi_soft_state_free(acpinex_softstates, instance); return (DDI_FAILURE); } mutex_init(&softsp->ans_lock, NULL, MUTEX_DRIVER, NULL); /* Install event handler for child/descendant objects. */ if (acpinex_event_scan(softsp, B_TRUE) != DDI_SUCCESS) { cmn_err(CE_WARN, "!acpinex: failed to install event handler " "for children of %s.", softsp->ans_path); } /* nothing to suspend/resume here */ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, "pm-hardware-state", "no-suspend-resume"); (void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1); acpinex_fm_init(softsp); ddi_report_dev(devi); return (DDI_SUCCESS); }
static int simmstat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) { struct simmstat_soft_state *softsp; int instance; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: return (DDI_SUCCESS); default: return (DDI_FAILURE); } instance = ddi_get_instance(devi); if (ddi_soft_state_zalloc(simmstatp, instance) != DDI_SUCCESS) return (DDI_FAILURE); softsp = ddi_get_soft_state(simmstatp, instance); /* Set the dip in the soft state */ softsp->dip = devi; /* Get the board number from this nodes parent device. */ softsp->pdip = ddi_get_parent(softsp->dip); if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip, DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) { cmn_err(CE_WARN, "simmstat%d: unable to retrieve %s property", instance, OBP_BOARDNUM); goto bad; } DPRINTF(SIMMSTAT_ATTACH_DEBUG, ("simmstat%d: devi= 0x%p\n, " " softsp=0x%p\n", instance, (void *)devi, (void *)softsp)); /* map in the registers for this device. */ if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->simmstat_base, 0, 0)) { cmn_err(CE_WARN, "simmstat%d: unable to map registers", instance); goto bad; } /* nothing to suspend/resume here */ (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, "pm-hardware-state", "no-suspend-resume"); /* create the kstats for this device */ simmstat_add_kstats(softsp); ddi_report_dev(devi); return (DDI_SUCCESS); bad: ddi_soft_state_free(simmstatp, instance); return (DDI_FAILURE); }
/* * heci_remove - Device Removal Routine * * @pdev: PCI device information struct * * heci_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. */ static int heci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { struct iamt_heci_device *dev; int err; dev = ddi_get_soft_state(heci_soft_state_p, ddi_get_instance(dip)); ASSERT(dev != NULL); switch (cmd) { case DDI_SUSPEND: err = heci_suspend(dip); if (err) return (DDI_FAILURE); else return (DDI_SUCCESS); case DDI_DETACH: break; default: return (DDI_FAILURE); } if (dev->wd_timer) (void) untimeout(dev->wd_timer); mutex_enter(&dev->device_lock); if (dev->wd_file_ext.state == HECI_FILE_CONNECTED && dev->wd_timeout) { dev->wd_timeout = 0; dev->wd_due_counter = 0; (void) memcpy(dev->wd_data, stop_wd_params, HECI_WD_PARAMS_SIZE); dev->stop = 1; if (dev->host_buffer_is_empty && flow_ctrl_creds(dev, &dev->wd_file_ext)) { dev->host_buffer_is_empty = 0; if (!heci_send_wd(dev)) { DBG("send stop WD failed\n"); } else flow_ctrl_reduce(dev, &dev->wd_file_ext); dev->wd_pending = 0; } else dev->wd_pending = 1; dev->wd_stoped = 0; err = 0; while (!dev->wd_stoped && err != -1) { err = cv_reltimedwait(&dev->wait_stop_wd, &dev->device_lock, 10*HZ, TR_CLOCK_TICK); } if (!dev->wd_stoped) { DBG("stop wd failed to complete.\n"); } else { DBG("stop wd complete.\n"); } } mutex_exit(&dev->device_lock); if (dev->iamthif_file_ext.state == HECI_FILE_CONNECTED) { dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTING; (void) heci_disconnect_host_client(dev, &dev->iamthif_file_ext); } if (dev->wd_file_ext.state == HECI_FILE_CONNECTED) { dev->wd_file_ext.state = HECI_FILE_DISCONNECTING; (void) heci_disconnect_host_client(dev, &dev->wd_file_ext); } /* remove entry if already in list */ DBG("list del iamthif and wd file list.\n"); heci_remove_client_from_file_list(dev, dev->wd_file_ext. host_client_id); heci_remove_client_from_file_list(dev, dev->iamthif_file_ext.host_client_id); dev->iamthif_current_cb = NULL; dev->iamthif_file_ext.file = NULL; /* disable interrupts */ heci_csr_disable_interrupts(dev); ddi_remove_intr(dip, 0, dev->sc_iblk); if (dev->work) ddi_taskq_destroy(dev->work); if (dev->reinit_tsk) ddi_taskq_destroy(dev->reinit_tsk); if (dev->mem_addr) ddi_regs_map_free(&dev->io_handle); if (dev->me_clients && dev->num_heci_me_clients > 0) { kmem_free(dev->me_clients, sizeof (struct heci_me_client) * dev->num_heci_me_clients); } dev->num_heci_me_clients = 0; heci_destroy_locks(dev); ddi_remove_minor_node(dip, NULL); ddi_soft_state_free(heci_soft_state_p, ddi_get_instance(dip)); return (DDI_SUCCESS); }