/* * Clean up on detach or failure of attach */ static void rmc_comm_unattach(struct rmc_comm_state *rcs, dev_info_t *dip, int instance, boolean_t drvi_init, boolean_t dp_init, boolean_t sd_init) { if (rcs != NULL) { /* * disable interrupts now */ rmc_comm_set_irq(rcs, B_FALSE); /* * driver interface termination (if it has been initialized) */ if (drvi_init) rmc_comm_drvintf_fini(rcs); /* * data protocol termination (if it has been initialized) */ if (dp_init) rmc_comm_dp_fini(rcs); /* * serial device termination (if it has been initialized) */ if (sd_init) rmc_comm_serdev_fini(rcs, dip); ddi_set_driver_private(dip, NULL); } ddi_soft_state_free(rmc_comm_statep, instance); }
/** * Virtio Detach routine that should be called from all Virtio drivers' detach * routines. * * @param pDip The module structure instance. * @param enmCmd Operation type (detach/suspend). * * @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE. */ int VirtioDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd) { LogFlowFunc((VIRTIOLOGNAME ":VirtioDetach pDip=%p enmCmd=%d\n", pDip, enmCmd)); PVIRTIODEVICE pDevice = ddi_get_driver_private(pDip); if (RT_UNLIKELY(!pDevice)) return DDI_FAILURE; if (enmCmd != DDI_DETACH) { LogRel((VIRTIOLOGNAME ":VirtioDetach: Invalid enmCmd=%#x expected DDI_DETACH.\n", enmCmd)); return DDI_FAILURE; } int rc = pDevice->pDeviceOps->pfnDetach(pDevice); if (rc == DDI_SUCCESS) { pDevice->pHyperOps->pfnDetach(pDevice); pDevice->pDeviceOps->pfnFree(pDevice); pDevice->pvDevice = NULL; pDevice->pHyperOps->pfnFree(pDevice); pDevice->pvHyper = NULL; ddi_set_driver_private(pDevice->pDip, NULL); RTMemFree(pDevice); return DDI_SUCCESS; } else LogRel((VIRTIOLOGNAME ":VirtioDetach: DeviceOps pfnDetach failed. rc=%d\n", rc)); return DDI_FAILURE; }
/* * The audio module is itself a pseudo driver, as it contains the * logic to support un-associated nodes. (Think generic /dev/mixer * and /dev/sndstat used by OSS.) */ static int audio_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { audio_dev_t *adev; /* pseudo devices don't need S/R support */ if ((cmd != DDI_ATTACH) || (dip == NULL)) { return (DDI_FAILURE); } if (ddi_get_instance(dip) != 0) { return (DDI_FAILURE); } /* this can't fail */ adev = audio_dev_alloc(dip, 0); adev->d_flags = DEV_SNDSTAT_CAP; audio_dev_set_description(adev, "Audio Common Code"); audio_dev_set_version(adev, "pseudo"); ddi_set_driver_private(dip, adev); /* look up our properties! */ if (audio_dev_register(adev) != NULL) { audio_dev_free(adev); return (DDI_FAILURE); } ddi_report_dev(dip); return (DDI_SUCCESS); }
/*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); } }
static int ddksample_attach (dev_info_t * dip, ddi_attach_cmd_t cmd) { int instance, err; oss_device_t *osdev; ddi_iblock_cookie_t iblock_cookie; ddksample_devc *devc; if (cmd != DDI_ATTACH) { cmn_err (CE_WARN, "bad attach cmd %d\n", cmd); return 0; } if (dip == NULL) { cmn_err (CE_WARN, "ddksample_attach: dip==NULL\n"); return DDI_FAILURE; } instance = ddi_get_instance (dip); cmn_err (CE_CONT, "Attach started " DRIVER_NICK "%d\n", instance); #if 0 // Pseudo drivers don't have any iblock_cookie if ((err = ddi_get_iblock_cookie (dip, 0, iblock_cookie)) != DDI_SUCCESS) { cmn_err (CE_WARN, "Cannot get iblock cookie (%d)\n", err); return DDI_FAILURE; } #endif devc = kmem_zalloc (sizeof (*devc), KM_SLEEP); mutex_init (&devc->mutex, NULL, MUTEX_DRIVER, NULL /* iblock_cookie */ ); if ((osdev = ossddk_register_device (OSSDDK_VERSION, dip, DRIVER_TYPE, instance, DRIVER_NICK, iblock_cookie, devc, DRIVER_FULLNAME)) == NULL) { cmn_err (CE_WARN, "Registering OSS DDK driver failed\n"); return DDI_FAILURE; } devc->osdev = osdev; ddksample_mixer_init (devc); /* From ddksample_mixer.c */ ddksample_audio_init (devc); /* From ddksample_audio.c */ ddi_set_driver_private (dip, (caddr_t) osdev); ddi_report_dev (dip); return DDI_SUCCESS; }
/* * dm2s_cleanup - Cleanup routine. */ static void dm2s_cleanup(dm2s_t *dm2sp) { char name[20]; DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); ASSERT(dm2sp != NULL); if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); ddi_remove_minor_node(dm2sp->ms_dip, name); } if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) mutex_destroy(&dm2sp->ms_lock); if (dm2sp->ms_clean & DM2S_CLEAN_CV) cv_destroy(&dm2sp->ms_wait); ddi_set_driver_private(dm2sp->ms_dip, NULL); ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); }
/*ARGSUSED1*/ static int dmaattach(dev_info_t *dev, ddi_attach_cmd_t cmd) { dma_softc_t *dp; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: return (DDI_SUCCESS); default: return (DDI_FAILURE); } dp = (dma_softc_t *)kmem_zalloc(sizeof (dma_softc_t), KM_SLEEP); /* * map in the device registers */ if (ddi_map_regs(dev, 0, (caddr_t *)&dp->dma_regs, 0, 0)) { cmn_err(CE_WARN, "dma%d: unable to map registers", ddi_get_instance(dev)); kmem_free(dp, sizeof (dma_softc_t)); return (DDI_FAILURE); } ddi_set_driver_private(dev, dp); dp->dma_dev = dev; mutex_enter(&dmaautolock); dp->dma_next = dma_softc; dma_softc = dp; mutex_exit(&dmaautolock); ddi_report_dev(dev); return (DDI_SUCCESS); }
static int bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int inst; bd_handle_t hdl; bd_t *bd; bd_drive_t drive; int rv; char name[16]; char kcache[32]; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: /* We don't do anything native for suspend/resume */ return (DDI_SUCCESS); default: return (DDI_FAILURE); } inst = ddi_get_instance(dip); hdl = ddi_get_parent_data(dip); (void) snprintf(name, sizeof (name), "%s%d", ddi_driver_name(dip), ddi_get_instance(dip)); (void) snprintf(kcache, sizeof (kcache), "%s_xfer", name); if (hdl == NULL) { cmn_err(CE_WARN, "%s: missing parent data!", name); return (DDI_FAILURE); } if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name); return (DDI_FAILURE); } bd = ddi_get_soft_state(bd_state, inst); if (hdl->h_dma) { bd->d_dma = *(hdl->h_dma); bd->d_dma.dma_attr_granular = max(DEV_BSIZE, bd->d_dma.dma_attr_granular); bd->d_use_dma = B_TRUE; if (bd->d_maxxfer && (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) { cmn_err(CE_WARN, "%s: inconsistent maximum transfer size!", name); /* We force it */ bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer; } else { bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer; } } else { bd->d_use_dma = B_FALSE; if (bd->d_maxxfer == 0) { bd->d_maxxfer = 1024 * 1024; } } bd->d_ops = hdl->h_ops; bd->d_private = hdl->h_private; bd->d_blkshift = 9; /* 512 bytes, to start */ if (bd->d_maxxfer % DEV_BSIZE) { cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name); bd->d_maxxfer &= ~(DEV_BSIZE - 1); } if (bd->d_maxxfer < DEV_BSIZE) { cmn_err(CE_WARN, "%s: maximum transfer size too small!", name); ddi_soft_state_free(bd_state, inst); return (DDI_FAILURE); } bd->d_dip = dip; bd->d_handle = hdl; hdl->h_bd = bd; ddi_set_driver_private(dip, bd); mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL); cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL); list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t), offsetof(struct bd_xfer_impl, i_linkage)); list_create(&bd->d_runq, sizeof (bd_xfer_impl_t), offsetof(struct bd_xfer_impl, i_linkage)); bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8, bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0); bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk", KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT); if (bd->d_ksp != NULL) { bd->d_ksp->ks_lock = &bd->d_iomutex; kstat_install(bd->d_ksp); bd->d_kiop = bd->d_ksp->ks_data; } else { /* * Even if we cannot create the kstat, we create a * scratch kstat. The reason for this is to ensure * that we can update the kstat all of the time, * without adding an extra branch instruction. */ bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP); } cmlb_alloc_handle(&bd->d_cmlbh); bd->d_state = DKIO_NONE; bzero(&drive, sizeof (drive)); bd->d_ops.o_drive_info(bd->d_private, &drive); bd->d_qsize = drive.d_qsize; bd->d_removable = drive.d_removable; bd->d_hotpluggable = drive.d_hotpluggable; if (drive.d_maxxfer && drive.d_maxxfer < bd->d_maxxfer) bd->d_maxxfer = drive.d_maxxfer; rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT, bd->d_removable, bd->d_hotpluggable, drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK, CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, 0); if (rv != 0) { cmlb_free_handle(&bd->d_cmlbh); kmem_cache_destroy(bd->d_cache); mutex_destroy(&bd->d_iomutex); mutex_destroy(&bd->d_ocmutex); mutex_destroy(&bd->d_statemutex); cv_destroy(&bd->d_statecv); list_destroy(&bd->d_waitq); list_destroy(&bd->d_runq); if (bd->d_ksp != NULL) { kstat_delete(bd->d_ksp); bd->d_ksp = NULL; } else { kmem_free(bd->d_kiop, sizeof (kstat_io_t)); } ddi_soft_state_free(bd_state, inst); return (DDI_FAILURE); } if (bd->d_ops.o_devid_init != NULL) { rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid); if (rv == DDI_SUCCESS) { if (ddi_devid_register(dip, bd->d_devid) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s: unable to register devid", name); } } } /* * Add a zero-length attribute to tell the world we support * kernel ioctls (for layered drivers). Also set up properties * used by HAL to identify removable media. */ (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0); if (bd->d_removable) { (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "removable-media", NULL, 0); } if (bd->d_hotpluggable) { (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "hotpluggable", NULL, 0); } ddi_report_dev(dip); return (DDI_SUCCESS); }
/* * dm2s_attach - Module's attach routine. */ int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance; dm2s_t *dm2sp; char name[20]; instance = ddi_get_instance(dip); /* Only one instance is supported. */ if (instance != 0) { cmn_err(CE_WARN, "only one instance is supported"); return (DDI_FAILURE); } if (cmd != DDI_ATTACH) { return (DDI_FAILURE); } if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { cmn_err(CE_WARN, "softstate allocation failure"); return (DDI_FAILURE); } dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); if (dm2sp == NULL) { ddi_soft_state_free(dm2s_softstate, instance); cmn_err(CE_WARN, "softstate allocation failure."); return (DDI_FAILURE); } dm2sp->ms_dip = dip; dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip)); dm2sp->ms_ppa = instance; /* * Get an interrupt block cookie corresponding to the * interrupt priority of the event handler. * Assert that the event priority is not re-defined to * some higher priority. */ /* LINTED */ ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, &dm2sp->ms_ibcookie) != DDI_SUCCESS) { cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); goto error; } mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, (void *)dm2sp->ms_ibcookie); dm2sp->ms_clean |= DM2S_CLEAN_LOCK; cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); dm2sp->ms_clean |= DM2S_CLEAN_CV; (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); if (ddi_create_minor_node(dip, name, S_IFCHR, instance, DDI_PSEUDO, NULL) == DDI_FAILURE) { ddi_remove_minor_node(dip, NULL); cmn_err(CE_WARN, "Device node creation failed."); goto error; } dm2sp->ms_clean |= DM2S_CLEAN_NODE; ddi_set_driver_private(dip, (caddr_t)dm2sp); ddi_report_dev(dip); return (DDI_SUCCESS); error: dm2s_cleanup(dm2sp); return (DDI_FAILURE); }
static int rmc_comm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct rmc_comm_state *rcs = NULL; sig_state_t *current_sgn_p; int instance; /* * only allow one instance */ instance = ddi_get_instance(dip); if (instance != 0) return (DDI_FAILURE); switch (cmd) { default: return (DDI_FAILURE); case DDI_RESUME: if ((rcs = rmc_comm_getstate(dip, instance, "rmc_comm_attach")) == NULL) return (DDI_FAILURE); /* this "can't happen" */ rmc_comm_hw_reset(rcs); rmc_comm_set_irq(rcs, B_TRUE); rcs->dip = dip; mutex_enter(&tod_lock); if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL && watchdog_was_active) { (void) tod_ops.tod_set_watchdog_timer(0); } mutex_exit(&tod_lock); mutex_enter(rcs->dp_state.dp_mutex); dp_reset(rcs, INITIAL_SEQID, 1, 1); mutex_exit(rcs->dp_state.dp_mutex); current_sgn_p = (sig_state_t *)modgetsymvalue( "current_sgn", 0); if ((current_sgn_p != NULL) && (current_sgn_p->state_t.sig != 0)) { CPU_SIGNATURE(current_sgn_p->state_t.sig, current_sgn_p->state_t.state, current_sgn_p->state_t.sub_state, -1); } return (DDI_SUCCESS); case DDI_ATTACH: break; } /* * Allocate the soft-state structure */ if (ddi_soft_state_zalloc(rmc_comm_statep, instance) != DDI_SUCCESS) return (DDI_FAILURE); if ((rcs = rmc_comm_getstate(dip, instance, "rmc_comm_attach")) == NULL) { rmc_comm_unattach(rcs, dip, instance, 0, 0, 0); return (DDI_FAILURE); } ddi_set_driver_private(dip, rcs); rcs->dip = NULL; /* * Set various options from .conf properties */ rcs->baud = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "baud-rate", 0); rcs->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "debug", 0); /* * the baud divisor factor tells us how to scale the result of * the SIO_BAUD_TO_DIVISOR macro for platforms which do not * use the standard 24MHz uart clock */ rcs->baud_divisor_factor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "baud-divisor-factor", SIO_BAUD_DIVISOR_MIN); /* * try to be reasonable if the scale factor contains a silly value */ if ((rcs->baud_divisor_factor < SIO_BAUD_DIVISOR_MIN) || (rcs->baud_divisor_factor > SIO_BAUD_DIVISOR_MAX)) rcs->baud_divisor_factor = SIO_BAUD_DIVISOR_MIN; /* * initialize serial device */ if (rmc_comm_serdev_init(rcs, dip) != 0) { rmc_comm_unattach(rcs, dip, instance, 0, 0, 0); return (DDI_FAILURE); } /* * initialize data protocol */ rmc_comm_dp_init(rcs); /* * initialize driver interface */ if (rmc_comm_drvintf_init(rcs) != 0) { rmc_comm_unattach(rcs, dip, instance, 0, 1, 1); return (DDI_FAILURE); } /* * Initialise devinfo-related fields */ rcs->majornum = ddi_driver_major(dip); rcs->instance = instance; rcs->dip = dip; /* * enable interrupts now */ rmc_comm_set_irq(rcs, B_TRUE); /* * All done, report success */ ddi_report_dev(dip); mutex_enter(&rmc_comm_attach_lock); rcs->is_attached = B_TRUE; mutex_exit(&rmc_comm_attach_lock); return (DDI_SUCCESS); }
/* * audioixp_attach() * * Description: * Attach an instance of the audioixp driver. This routine does * the device dependent attach tasks. * * Arguments: * dev_info_t *dip Pointer to the device's dev_info struct * ddi_attach_cmd_t cmd Attach command * * Returns: * DDI_SUCCESS The driver was initialized properly * DDI_FAILURE The driver couldn't be initialized properly */ static int audioixp_attach(dev_info_t *dip) { uint16_t cmdeg; audioixp_state_t *statep; audio_dev_t *adev; uint32_t devid; const char *name; const char *rev; /* we don't support high level interrupts in the driver */ if (ddi_intr_hilevel(dip, 0) != 0) { cmn_err(CE_WARN, "!%s%d: unsupported high level interrupt", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* allocate the soft state structure */ statep = kmem_zalloc(sizeof (*statep), KM_SLEEP); statep->dip = dip; ddi_set_driver_private(dip, statep); if (ddi_get_iblock_cookie(dip, 0, &statep->iblock) != DDI_SUCCESS) { cmn_err(CE_WARN, "!%s%d: cannot get iblock cookie", ddi_driver_name(dip), ddi_get_instance(dip)); kmem_free(statep, sizeof (*statep)); return (DDI_FAILURE); } mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, statep->iblock); /* allocate framework audio device */ if ((adev = audio_dev_alloc(dip, 0)) == NULL) { cmn_err(CE_WARN, "!%s%d: unable to allocate audio dev", ddi_driver_name(dip), ddi_get_instance(dip)); goto error; } statep->adev = adev; /* map in the registers */ if (audioixp_map_regs(statep) != DDI_SUCCESS) { audio_dev_warn(adev, "couldn't map registers"); goto error; } /* set device information -- this could be smarter */ devid = ((pci_config_get16(statep->pcih, PCI_CONF_VENID)) << 16) | pci_config_get16(statep->pcih, PCI_CONF_DEVID); name = "ATI AC'97"; switch (devid) { case IXP_PCI_ID_200: rev = "IXP150"; break; case IXP_PCI_ID_300: rev = "SB300"; break; case IXP_PCI_ID_400: if (pci_config_get8(statep->pcih, PCI_CONF_REVID) & 0x80) { rev = "SB450"; } else { rev = "SB400"; } break; case IXP_PCI_ID_SB600: rev = "SB600"; break; default: rev = "Unknown"; break; } audio_dev_set_description(adev, name); audio_dev_set_version(adev, rev); /* allocate port structures */ if ((audioixp_alloc_port(statep, IXP_PLAY) != DDI_SUCCESS) || (audioixp_alloc_port(statep, IXP_REC) != DDI_SUCCESS)) { goto error; } statep->ac97 = ac97_alloc(dip, audioixp_rd97, audioixp_wr97, statep); if (statep->ac97 == NULL) { audio_dev_warn(adev, "failed to allocate ac97 handle"); goto error; } /* set PCI command register */ cmdeg = pci_config_get16(statep->pcih, PCI_CONF_COMM); pci_config_put16(statep->pcih, PCI_CONF_COMM, cmdeg | PCI_COMM_IO | PCI_COMM_MAE); /* set up kernel statistics */ if ((statep->ksp = kstat_create(IXP_NAME, ddi_get_instance(dip), IXP_NAME, "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT)) != NULL) { kstat_install(statep->ksp); } if (audioixp_chip_init(statep) != DDI_SUCCESS) { audio_dev_warn(statep->adev, "failed to init chip"); goto error; } /* initialize the AC'97 part */ if (ac97_init(statep->ac97, adev) != DDI_SUCCESS) { audio_dev_warn(adev, "ac'97 initialization failed"); goto error; } /* set up the interrupt handler */ if (ddi_add_intr(dip, 0, &statep->iblock, NULL, audioixp_intr, (caddr_t)statep) != DDI_SUCCESS) { audio_dev_warn(adev, "bad interrupt specification"); } statep->intr_added = B_TRUE; if (audio_dev_register(adev) != DDI_SUCCESS) { audio_dev_warn(adev, "unable to register with framework"); goto error; } ddi_report_dev(dip); return (DDI_SUCCESS); error: audioixp_destroy(statep); return (DDI_FAILURE); }
static int iiattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct ii_state *xsp; int instance; int i; intptr_t flags; if (cmd != DDI_ATTACH) { return (DDI_FAILURE); } /* save the dev_info_t to be used in logging using ddi_log_sysevent */ ii_dip = dip; instance = ddi_get_instance(dip); if (ddi_soft_state_zalloc(ii_statep, instance) != 0) { cmn_err(CE_WARN, "!ii: no memory for instance %d state.", instance); return (DDI_FAILURE); } flags = 0; xsp = ddi_get_soft_state(ii_statep, instance); if (xsp == NULL) { cmn_err(CE_WARN, "!ii: attach: could not get state for instance %d.", instance); goto out; } ii_debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_debug", 0); if (ii_debug != 0) { #ifdef DEBUG cmn_err(CE_NOTE, "!ii: initializing ii version %d.%d.%d.%d", dsw_major_rev, dsw_minor_rev, dsw_micro_rev, dsw_baseline_rev); #else if (dsw_micro_rev) { cmn_err(CE_NOTE, "!ii: initializing ii vers %d.%d.%d", dsw_major_rev, dsw_minor_rev, dsw_micro_rev); } else { cmn_err(CE_NOTE, "!ii: initializing ii version %d.%d", dsw_major_rev, dsw_minor_rev); } #endif switch (ii_debug) { case 1: case 2: cmn_err(CE_NOTE, "!ii: ii_debug=%d is enabled.", ii_debug); break; default: cmn_err(CE_WARN, "!ii: Value of ii_debug=%d is not 0,1 or 2.", ii_debug); } } ii_bitmap = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_bitmap", II_WTHRU); switch (ii_bitmap) { case II_KMEM: if (ii_debug > 0) cmn_err(CE_NOTE, "!ii: ii_bitmap is in memory"); break; case II_FWC: if (ii_debug > 0) cmn_err(CE_NOTE, "!ii: ii_bitmap is on disk," " no FWC"); break; case II_WTHRU: if (ii_debug > 0) cmn_err(CE_NOTE, "!ii: ii_bitmap is on disk"); break; default: cmn_err(CE_NOTE, "!ii: ii_bitmap=%d out of range; " "defaulting WTHRU(%d)", ii_bitmap, II_WTHRU); ii_bitmap = II_WTHRU; } /* pick up these values if in ii.conf, otherwise leave alone */ i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_throttle_unit", 0); if (i > 0) { ii_throttle_unit = i; if ((ii_throttle_unit < MIN_THROTTLE_UNIT) || (ii_throttle_unit > MAX_THROTTLE_UNIT) || (ii_debug > 0)) cmn_err(CE_NOTE, "!ii: ii_throttle_unit=%d", ii_throttle_unit); } i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_throttle_delay", 0); if (i > 0) { ii_throttle_delay = i; if ((ii_throttle_delay < MIN_THROTTLE_DELAY) || (ii_throttle_delay > MIN_THROTTLE_DELAY) || (ii_debug > 0)) cmn_err(CE_NOTE, "!ii: ii_throttle_delay=%d", ii_throttle_delay); } ii_copy_direct = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "ii_copy_direct", 1); if (i > 0) { ii_copy_direct = i; if ((ii_copy_direct < 0) || (ii_copy_direct > 1)) cmn_err(CE_NOTE, "!ii: ii_copy_direct=%d", ii_copy_direct); } if (_ii_init_dev()) { cmn_err(CE_WARN, "!ii: _ii_init_dev failed"); goto out; } flags |= DIDINIT; xsp->dip = dip; xsp->instance = instance; if (ddi_create_minor_node(dip, "ii", S_IFCHR, instance, DDI_PSEUDO, 0) != DDI_SUCCESS) { cmn_err(CE_WARN, "!ii: could not create node."); goto out; } flags |= DIDNODES; ddi_set_driver_private(dip, (caddr_t)flags); ddi_report_dev(dip); ii_create_kstats(); return (DDI_SUCCESS); out: ddi_set_driver_private(dip, (caddr_t)flags); (void) iidetach(dip, DDI_DETACH); return (DDI_FAILURE); }
static int mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { struct mouse_state *state; mblk_t *mp; int instance = ddi_get_instance(dip); static ddi_device_acc_attr_t attr = { DDI_DEVICE_ATTR_V0, DDI_NEVERSWAP_ACC, DDI_STRICTORDER_ACC, }; int rc; if (cmd == DDI_RESUME) { state = (struct mouse_state *)ddi_get_driver_private(dip); /* Ready to handle inbound data from mouse8042_intr */ state->ready = 1; /* * Send a 0xaa 0x00 upstream. * This causes the vuid module to reset the mouse. */ if (state->ms_rqp != NULL) { if (mp = allocb(1, BPRI_MED)) { *mp->b_wptr++ = 0xaa; putnext(state->ms_rqp, mp); } if (mp = allocb(1, BPRI_MED)) { *mp->b_wptr++ = 0x0; putnext(state->ms_rqp, mp); } } return (DDI_SUCCESS); } if (cmd != DDI_ATTACH) return (DDI_FAILURE); if (mouse8042_dip != NULL) return (DDI_FAILURE); /* allocate and initialize state structure */ state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP); state->ms_opened = B_FALSE; state->reset_state = MSE_RESET_IDLE; state->reset_tid = 0; state->bc_id = 0; ddi_set_driver_private(dip, state); /* * In order to support virtual keyboard/mouse, we should distinguish * between internal virtual open and external physical open. * * When the physical devices are opened by application, they will * be unlinked from the virtual device and their data stream will * not be sent to the virtual device. When the opened physical * devices are closed, they will be relinked to the virtual devices. * * All these automatic switch between virtual and physical are * transparent. * * So we change minor node numbering scheme to be: * external node minor num == instance * 2 * internal node minor num == instance * 2 + 1 */ rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2, DDI_NT_MOUSE, NULL); if (rc != DDI_SUCCESS) { goto fail_1; } if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR, instance * 2 + 1) != DDI_SUCCESS) { goto fail_2; } rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr, (offset_t)0, (offset_t)0, &attr, &state->ms_handle); if (rc != DDI_SUCCESS) { goto fail_2; } rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie); if (rc != DDI_SUCCESS) { goto fail_3; } mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER, state->ms_iblock_cookie); mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER, state->ms_iblock_cookie); cv_init(&state->reset_cv, NULL, CV_DRIVER, NULL); rc = ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, mouse8042_intr, (caddr_t)state); if (rc != DDI_SUCCESS) { goto fail_3; } mouse8042_dip = dip; /* Ready to handle inbound data from mouse8042_intr */ state->ready = 1; /* Now that we're attached, announce our presence to the world. */ ddi_report_dev(dip); return (DDI_SUCCESS); fail_3: ddi_regs_map_free(&state->ms_handle); fail_2: ddi_remove_minor_node(dip, NULL); fail_1: kmem_free(state, sizeof (struct mouse_state)); return (rc); }
/** * Virtio Attach routine that should be called from all Virtio drivers' attach * routines. * * @param pDip The module structure instance. * @param enmCmd Operation type (attach/resume). * @param pDeviceOps Pointer to device ops structure. * @param pHyperOps Pointer to hypervisor ops structure. * * @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE. */ int VirtioAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd, PVIRTIODEVICEOPS pDeviceOps, PVIRTIOHYPEROPS pHyperOps) { LogFlowFunc((VIRTIOLOGNAME ":VirtioAttach: pDip=%p enmCmd=%d pDeviceOps=%p pHyperOps=%p\n", pDip, enmCmd, pDeviceOps, pHyperOps)); AssertReturn(pDip, DDI_EINVAL); AssertReturn(pDeviceOps, DDI_EINVAL); AssertReturn(pHyperOps, DDI_EINVAL); if (enmCmd != DDI_ATTACH) { LogRel((VIRTIOLOGNAME ":VirtioAttach: Invalid enmCmd=%#x expected DDI_ATTACH\n", enmCmd)); return DDI_FAILURE; } int rc = DDI_FAILURE; PVIRTIODEVICE pDevice = RTMemAllocZ(sizeof(VIRTIODEVICE)); if (RT_LIKELY(pDevice)) { pDevice->pDip = pDip; pDevice->pDeviceOps = pDeviceOps; pDevice->pHyperOps = pHyperOps; pDevice->pvDevice = pDevice->pDeviceOps->pfnAlloc(pDevice); if (RT_LIKELY(pDevice->pvDevice)) { pDevice->pvHyper = pDevice->pHyperOps->pfnAlloc(pDevice); if (RT_LIKELY(pDevice->pvHyper)) { /* * Attach hypervisor interface and obtain features supported by host. */ rc = pDevice->pHyperOps->pfnAttach(pDevice); if (rc == DDI_SUCCESS) { pDevice->fHostFeatures = pDevice->pHyperOps->pfnGetFeatures(pDevice); LogFlow((VIRTIOLOGNAME ":VirtioAttach: Host features=%#x\n", pDevice->fHostFeatures)); /* * Attach the device type interface. */ rc = pDevice->pDeviceOps->pfnAttach(pDevice); if (rc == DDI_SUCCESS) { ddi_set_driver_private(pDip, pDevice); return DDI_SUCCESS; } else LogRel((VIRTIOLOGNAME ":VirtioAttach: DeviceOps pfnAttach failed. rc=%d\n", rc)); pDevice->pHyperOps->pfnDetach(pDevice); } else LogRel((VIRTIOLOGNAME ":VirtioAttach: HyperOps pfnAttach failed. rc=%d\n", rc)); pDevice->pHyperOps->pfnFree(pDevice); } else LogRel((VIRTIOLOGNAME ":VirtioAttach: HyperOps->pfnAlloc failed!\n")); pDevice->pDeviceOps->pfnFree(pDevice); } else LogRel((VIRTIOLOGNAME ":VirtioAttach: DeviceOps->pfnAlloc failed!\n")); RTMemFree(pDevice); } else LogRel((VIRTIOLOGNAME ":VirtioAttach: failed to alloc %u bytes for device structure.\n", sizeof(VIRTIODEVICE))); return DDI_FAILURE; }
/** * At attach time, we allocate the soft state structure for the current * instance of the device. */ static int quantis_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance; quantis_soft_state_t *soft_state; ddi_device_acc_attr_t dev_acc_attr; /* Hold the device access attributes. */ int nregs; off_t regsize; char msg[MAX_MSG_LEN]; LOG_DEBUG0("attach\n"); switch (cmd) { case DDI_ATTACH: instance = ddi_get_instance(dip); snprintf(msg, MAX_MSG_LEN, "Attaching the Quantis device %d.\n", instance); LOG_DEBUG0(msg); /* * PCI devices are self-identifying devices, so we check that we * indeed have a Quantis QRNG card by checking that we have one * register page with the correct size. */ if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) { snprintf(msg, MAX_MSG_LEN, "Could not get the number of register for the Quantis device %d.\n", instance); QUANTIS_ERROR(msg); return DDI_FAILURE; } if (nregs < 4) { snprintf(msg, MAX_MSG_LEN, "The Quantis device %d has %d PCI base registers, but should have at least 4.\n", instance, nregs); QUANTIS_ERROR(msg); return DDI_FAILURE; } if (ddi_dev_regsize(dip, QUANTIS_REG_IDX, ®size) != DDI_SUCCESS) { snprintf(msg, MAX_MSG_LEN, "Could not get the register size for the Quantis device %d.\n", instance); QUANTIS_ERROR(msg); return DDI_FAILURE; } if (regsize < (int)QUANTIS_REG_LENGTH) { snprintf(msg, MAX_MSG_LEN, "The size of the Quantice device (%d) registers file is %d bytes long, " "but should be at least %u bytes long.\n", instance, (int)regsize, (unsigned int)QUANTIS_REG_LENGTH); QUANTIS_ERROR(msg); return DDI_FAILURE; } LOG_DEBUG0("After test of the validity of the card, before soft state alloc.\n"); if (ddi_soft_state_zalloc(quantis_soft_state_p, instance) != DDI_SUCCESS) { snprintf(msg, MAX_MSG_LEN, "Could not allocate soft state structure for the Quantis device %d.\n", instance); QUANTIS_ERROR(msg); return DDI_FAILURE; } soft_state = (quantis_soft_state_t *)ddi_get_soft_state(quantis_soft_state_p, instance); soft_state->dip = dip; ddi_set_driver_private(dip, (caddr_t)soft_state); soft_state->cnt = 0; /* * Initialize the mutex in the soft state. We have no interrupt, * so we can set `arg' to `NULL' */ mutex_init(&soft_state->mutex, NULL, MUTEX_DRIVER, NULL); if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_FAILURE) { snprintf(msg, MAX_MSG_LEN, "Could not create minor node for the Quantis device %d.\n", instance); QUANTIS_ERROR(msg); mutex_destroy(&soft_state->mutex); ddi_soft_state_free(quantis_soft_state_p, instance); return DDI_FAILURE; } LOG_DEBUG1("ddi_get_name %s\n", ddi_get_name(dip)); dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; if (ddi_regs_map_setup(dip, QUANTIS_REG_IDX, (caddr_t *)&soft_state->regs, 0, QUANTIS_REG_LENGTH, &dev_acc_attr, &soft_state->regs_handle) != DDI_SUCCESS) { snprintf(msg, MAX_MSG_LEN, "Could not map the registers space of the Quantis device %d.\n", instance); QUANTIS_ERROR(msg); mutex_destroy(&soft_state->mutex); ddi_soft_state_free(quantis_soft_state_p, instance); return DDI_FAILURE; } mutex_enter(&quantis_mutex); card_count++; mutex_exit(&quantis_mutex); LOG_DEBUG0("Just before mutex\n"); mutex_enter(&soft_state->mutex); LOG_DEBUG0("Just before rng_reset.\n"); quantis_rng_reset(soft_state); LOG_DEBUG0("Just before enable_modules.\n"); quantis_rng_enable_modules(soft_state, quantis_rng_modules_mask(soft_state)); LOG_DEBUG0("Just before release mutex.\n"); mutex_exit(&soft_state->mutex); snprintf(msg, MAX_MSG_LEN, "Successfully attached the Quantis device %d. Currently, %d Quantis cards are available.\n", instance, card_count); QUANTIS_INFO(msg); # ifdef DEBUG ddi_report_dev(dip); # endif return DDI_SUCCESS; case DDI_SUSPEND: case DDI_PM_SUSPEND: return DDI_SUCCESS; default: return DDI_FAILURE; } }
/* * Autoconfiguration entry points. */ int efe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { ddi_acc_handle_t pci; int types; int count; int actual; uint_t pri; efe_t *efep; mac_register_t *macp; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: efep = ddi_get_driver_private(dip); return (efe_resume(efep)); default: return (DDI_FAILURE); } /* * PCI configuration. */ if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { efe_error(dip, "unable to setup PCI configuration!"); return (DDI_FAILURE); } pci_config_put16(pci, PCI_CONF_COMM, pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_MAE | PCI_COMM_ME); pci_config_teardown(&pci); if (ddi_intr_get_supported_types(dip, &types) != DDI_SUCCESS || !(types & DDI_INTR_TYPE_FIXED)) { efe_error(dip, "fixed interrupts not supported!"); return (DDI_FAILURE); } if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count) != DDI_SUCCESS || count != 1) { efe_error(dip, "no fixed interrupts available!"); return (DDI_FAILURE); } /* * Initialize soft state. */ efep = kmem_zalloc(sizeof (efe_t), KM_SLEEP); ddi_set_driver_private(dip, efep); efep->efe_dip = dip; if (ddi_regs_map_setup(dip, 1, (caddr_t *)&efep->efe_regs, 0, 0, &efe_regs_acc_attr, &efep->efe_regs_acch) != DDI_SUCCESS) { efe_error(dip, "unable to setup register mapping!"); goto failure; } efep->efe_rx_ring = efe_ring_alloc(efep->efe_dip, RXDESCL); if (efep->efe_rx_ring == NULL) { efe_error(efep->efe_dip, "unable to allocate rx ring!"); goto failure; } efep->efe_tx_ring = efe_ring_alloc(efep->efe_dip, TXDESCL); if (efep->efe_tx_ring == NULL) { efe_error(efep->efe_dip, "unable to allocate tx ring!"); goto failure; } if (ddi_intr_alloc(dip, &efep->efe_intrh, DDI_INTR_TYPE_FIXED, 0, count, &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS || actual != count) { efe_error(dip, "unable to allocate fixed interrupt!"); goto failure; } if (ddi_intr_get_pri(efep->efe_intrh, &pri) != DDI_SUCCESS || pri >= ddi_intr_get_hilevel_pri()) { efe_error(dip, "unable to get valid interrupt priority!"); goto failure; } mutex_init(&efep->efe_intrlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); mutex_init(&efep->efe_txlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); /* * Initialize device. */ mutex_enter(&efep->efe_intrlock); mutex_enter(&efep->efe_txlock); efe_reset(efep); mutex_exit(&efep->efe_txlock); mutex_exit(&efep->efe_intrlock); /* Use factory address as default */ efe_getaddr(efep, efep->efe_macaddr); /* * Enable the ISR. */ if (ddi_intr_add_handler(efep->efe_intrh, efe_intr, efep, NULL) != DDI_SUCCESS) { efe_error(dip, "unable to add interrupt handler!"); goto failure; } if (ddi_intr_enable(efep->efe_intrh) != DDI_SUCCESS) { efe_error(dip, "unable to enable interrupt!"); goto failure; } /* * Allocate MII resources. */ if ((efep->efe_miih = mii_alloc(efep, dip, &efe_mii_ops)) == NULL) { efe_error(dip, "unable to allocate mii resources!"); goto failure; } /* * Allocate MAC resources. */ if ((macp = mac_alloc(MAC_VERSION)) == NULL) { efe_error(dip, "unable to allocate mac resources!"); goto failure; } macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; macp->m_driver = efep; macp->m_dip = dip; macp->m_src_addr = efep->efe_macaddr; macp->m_callbacks = &efe_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; macp->m_margin = VLAN_TAGSZ; if (mac_register(macp, &efep->efe_mh) != 0) { efe_error(dip, "unable to register with mac!"); goto failure; } mac_free(macp); ddi_report_dev(dip); return (DDI_SUCCESS); failure: if (macp != NULL) { mac_free(macp); } if (efep->efe_miih != NULL) { mii_free(efep->efe_miih); } if (efep->efe_intrh != NULL) { (void) ddi_intr_disable(efep->efe_intrh); (void) ddi_intr_remove_handler(efep->efe_intrh); (void) ddi_intr_free(efep->efe_intrh); } mutex_destroy(&efep->efe_txlock); mutex_destroy(&efep->efe_intrlock); if (efep->efe_tx_ring != NULL) { efe_ring_free(&efep->efe_tx_ring); } if (efep->efe_rx_ring != NULL) { efe_ring_free(&efep->efe_rx_ring); } if (efep->efe_regs_acch != NULL) { ddi_regs_map_free(&efep->efe_regs_acch); } kmem_free(efep, sizeof (efe_t)); return (DDI_FAILURE); }
/* * audio1575_attach() * * Description: * Attach an instance of the audio1575 driver. This routine does the * device dependent attach tasks. When it is completed, it registers * with the audio framework. * * Arguments: * dev_info_t *dip Pointer to the device's dev_info struct * * Returns: * DDI_SUCCESS The driver was initialized properly * DDI_FAILURE The driver couldn't be initialized properly */ static int audio1575_attach(dev_info_t *dip) { audio1575_state_t *statep; audio_dev_t *adev; uint32_t devid; const char *name; const char *rev; int maxch; /* allocate the soft state structure */ statep = kmem_zalloc(sizeof (*statep), KM_SLEEP); ddi_set_driver_private(dip, statep); statep->dip = dip; /* * We want the micboost enabled by default as well. */ (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, AC97_PROP_MICBOOST, 1); /* allocate common audio dev structure */ adev = audio_dev_alloc(dip, 0); if (adev == NULL) { audio_dev_warn(NULL, "unable to allocate audio dev"); goto error; } statep->adev = adev; /* map in the audio registers */ if (audio1575_map_regs(statep) != DDI_SUCCESS) { audio_dev_warn(adev, "couldn't map registers"); goto error; } /* Enable PCI I/O and Memory Spaces */ audio1575_pci_enable(statep); devid = (pci_config_get16(statep->pcih, PCI_CONF_VENID) << 16) | pci_config_get16(statep->pcih, PCI_CONF_DEVID); switch (devid) { case 0x10b95455: name = "Uli M1575 AC'97"; rev = "M5455"; break; default: name = "Uli AC'97"; rev = "Unknown"; break; } /* set device information -- this should check PCI config space */ audio_dev_set_description(adev, name); audio_dev_set_version(adev, rev); statep->ac97 = ac97_alloc(dip, audio1575_read_ac97, audio1575_write_ac97, statep); ASSERT(statep->ac97 != NULL); /* * Override "max-channels" property to prevent configuration * of 4 or 6 (or possibly even 8!) channel audio. The default * is to support as many channels as the hardware can do. */ maxch = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "max-channels", ac97_num_channels(statep->ac97)); if (maxch < 2) { maxch = 2; } statep->maxch = min(maxch, 6) & ~1; /* allocate port structures */ if ((audio1575_alloc_port(statep, M1575_PLAY, statep->maxch) != DDI_SUCCESS) || (audio1575_alloc_port(statep, M1575_REC, 2) != DDI_SUCCESS)) { goto error; } if (audio1575_chip_init(statep) != DDI_SUCCESS) { audio_dev_warn(adev, "failed to init chip"); goto error; } if (ac97_init(statep->ac97, adev) != DDI_SUCCESS) { audio_dev_warn(adev, "ac'97 initialization failed"); goto error; } /* register with the framework */ if (audio_dev_register(adev) != DDI_SUCCESS) { audio_dev_warn(adev, "unable to register with framework"); goto error; } /* everything worked out, so report the device */ ddi_report_dev(dip); return (DDI_SUCCESS); error: audio1575_destroy(statep); return (DDI_FAILURE); }