Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
9.  STREAMS Drivers STREAMS Driver Code Samples Printer Driver Example  Previous   Contents   Next 
   
 

Example 9-2 shows the required driver configuration entry points _init(9E), _fini(9E), and _info(9E). In addition to installing the driver using mod_install(9F), the _init entry point also initializes the per-instance driver structure using ddi_soft_state_init(9F). _fini(9E) performs the complementary calls to mod_remove(9F) and ddi_soft_state_fini(9F) to unload the driver and release the resources used by the soft-state routines.


Example 9-2 Configuration Entry Points

int
_init(void)
{
	int e;

	if ((e = ddi_soft_state_init(&lp_state,
	 sizeof (struct lp), 1)) != 0) {
		return (e);
	}

	if ((e = mod_install(&modlinkage)) != 0) {
		ddi_soft_state_fini(&lp_state);
	}

	return (e);
}

int
_fini(void)
{
	int e;

	if ((e = mod_remove(&modlinkage)) != 0) {
		return (e);
	}
	ddi_soft_state_fini(&lp_state);
	return (e);
}

int
_info(struct modinfo *modinfop)
{
	return (mod_info(&modlinkage, modinfop));
}

Example 9-3 shows the lp driver's implementation of the initialization entry points. In lpidentify, the driver ensures that the name of the device being attached is "lp".

lpattach first uses ddi_soft_state_zalloc(9F) to allocate a per-instance structure for the printer being attached. Next it creates a node in the device tree for the printer using ddi_create_minor_node(9F); user programs use the node to access the device. lpattach then registers the driver interrupt handler because the sample is driver pseudo-hardware, the driver uses soft interrupts. A driver for a real printer would use ddi_add_intr(9F) instead of ddi_add_softintr(9F). A driver for a real printer would also need to perform any other required hardware initialization in lpattach. Finally, lpattach initializes the per-instance mutex.

In lpdetach, the driver undoes everything it did in lpattach.

lpgetinfo uses the soft-state structures to obtain the required information.


Example 9-3 Initialization Entry Points

static int
lpidentify(dev_info_t *dip)
{
	if (strcmp(ddi_get_name(dip), "lp") == 0) {
		return (DDI_IDENTIFIED);
	} else
		return (DDI_NOT_IDENTIFIED);
}

static int
lpattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
	int instance;
	struct lp *lpp;

	switch (cmd) {

	case DDI_ATTACH:

		instance = ddi_get_instance(dip);

		if (ddi_soft_state_zalloc(lp_state, instance) != DDI_SUCCESS) {
			cmn_err(CE_CONT, "%s%d: can't allocate state\n",
			 ddi_get_name(dip), instance);
			return (DDI_FAILURE);
		} else
			lpp = ddi_get_soft_state(lp_state, instance);

		if (ddi_create_minor_node(dip, "strlp", S_IFCHR,
		 instance, NULL, 0) == DDI_FAILURE) {
			ddi_remove_minor_node(dip, NULL);
			goto attach_failed;

		}

		lpp->dip = dip;
		ddi_set_driver_private(dip, (caddr_t)lpp);

		/* add (soft) interrupt */


		if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &lpp->siid,
		 &lpp->iblock_cookie, 0, lpintr, (caddr_t)lpp)
		 != DDI_SUCCESS) {
			ddi_remove_minor_node(dip, NULL);
			goto attach_failed;
		}

		mutex_init(&lpp->lp_lock, "lp lock", MUTEX_DRIVER,
		 (void *)lpp->iblock_cookie);


		ddi_report_dev(dip);
		return (DDI_SUCCESS);

	default:
		return (DDI_FAILURE);
	}

attach_failed:
	/*
	 * Use our own detach routine to toss
	 * away any stuff we allocated above.
	 */
	(void) lpdetach(dip, DDI_DETACH);
	return (DDI_FAILURE);
}

static int
lpdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
	int instance;
	struct lp *lpp;

	switch (cmd) {

	case DDI_DETACH:
		/*
		 * Undo what we did in lpattach, freeing resources
		 * and removing things we installed. The system
		 * framework guarantees we are not active with this devinfo
		 * node in any other entry points at this time.
		 */
		ddi_prop_remove_all(dip);
		instance = ddi_get_instance(dip);
		lpp = ddi_get_soft_state(lp_state, instance);
		ddi_remove_minor_node(dip, NULL);
		ddi_remove_softintr(lpp->siid);
		ddi_soft_state_free(lp_state, instance);
		return (DDI_SUCCESS);

	default:
		return (DDI_FAILURE);
	}
}

/*ARGSUSED*/
static int
lpgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
          void **result)
{
	struct lp *lpp;
	int error = DDI_FAILURE;

	switch (infocmd) {
	case DDI_INFO_DEVT2DEVINFO:
		if ((lpp = ddi_get_soft_state(lp_state,
		 getminor((dev_t)arg))) != NULL) {
			*result = lpp->dip;
			error = DDI_SUCCESS;
		} else
			*result = NULL;
		break;

	case DDI_INFO_DEVT2INSTANCE:
		*result = (void *)getminor((dev_t)arg);
		error = DDI_SUCCESS;
		break;

	default:
		break;
	}

	return (error);
}

 
 
 
  Previous   Contents   Next