Example #1
0
/*
 *  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);
}
Example #4
0
/*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;
}
Example #6
0
/*
 * 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);
}
Example #7
0
/*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);
}
Example #8
0
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);
}
Example #9
0
/*
 * 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);
}
Example #10
0
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);
}
Example #11
0
/*
 * 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);
}
Example #12
0
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;
}
Example #15
0
/**
 * 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, &regsize) != 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;
  }
}
Example #16
0
/*
 * 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);
}
Example #17
0
/*
 * 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);
}