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

Example 9-10 contains the initialization routines.


Example 9-10 Initialization Routines for the Loop-around Driver

static int
loop_identify(dev_info_t *devi)
{
	  if (strcmp(ddi_get_name(devi), "loop") == 0)
			return (DDI_IDENTIFIED);
	  else
			return (DDI_NOT_IDENTIFIED);
}

static int
loop_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	  if (cmd != DDI_ATTACH)
			return (DDI_FAILURE);

	  if (ddi_create_minor_node(devi, "loopmajor", S_IFCHR, 0, NULL, 0) 
				== DDI_FAILURE) {
			ddi_remove_minor_node(devi, NULL);
			return (DDI_FAILURE);
	  }
	  if (ddi_create_minor_node(devi, "loopx", S_IFCHR, 0, NULL, CLONE_DEV)
				 == DDI_FAILURE) {
			ddi_remove_minor_node(devi, NULL);
			return (DDI_FAILURE);
	  }

	  loop_dip = devi;

	  return (DDI_SUCCESS);
}

static int
loop_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
	  if (cmd != DDI_DETACH)
			return (DDI_FAILURE);

	  ddi_remove_minor_node(devi, NULL);
	  return (DDI_SUCCESS);
}

/*ARGSUSED*/
static int
loop_devinfo(
	  dev_info_t *dip, 
	  ddi_info_cmd_t infocmd, 
	  void *arg, 
	  void **result)
{
	  int error;

	  switch (infocmd) {
	  case DDI_INFO_DEVT2DEVINFO:
			if (loop_dip == NULL) {
				error = DDI_FAILURE;
			} else {
				*result = (void *) loop_dip;
				error = DDI_SUCCESS;
			}
			break;
	  case DDI_INFO_DEVT2INSTANCE:
			*result = (void *)0;
			error = DDI_SUCCESS;
			break;
	  default:
			error = DDI_FAILURE;
	  }
	  return (error);

}

The open procedure (in Example 9-11) includes canonical clone processing that enables a single file system node to yield a new minor device/vnode each time the driver is opened. In loopopen, sflag can be CLONEOPEN, indicating that the driver picks an unused minor device. In this case, the driver scans its private loop_loop data structure to find an unused minor device number. If sflag is not set to CLONEOPEN, the passed-in minor device specified by getminor(*devp) is used.


Example 9-11 Opening the Loop-Around Driver

/*ARGSUSED*/
static int loopopen(
		queue_t *q,
		dev_t *devp,
		int flag,
		int sflag,
		cred_t *credp)
{
		struct loop *loop;
		minor_t newminor;

		if (q->q_ptr) /* already open */
			return(0);

		/*
		 * If CLONEOPEN, pick a minor device number to use.
		 * Otherwise, check the minor device range.
		 */

		if (sflag == CLONEOPEN) {
			for (newminor = 0; newminor < loop_cnt; newminor++ ) {
				if (loop_loop[newminor].qptr == NULL)
					break;
			}
		} else
			newminor = getminor(*devp);

		if (newminor >= loop_cnt)
			return(ENXIO);

		/*
		 * construct new device number and reset devp
		 * getmajor gets the major number
		 */

		*devp = makedevice(getmajor(*devp), newminor);
		loop = &loop_loop[newminor];
		WR(q)->q_ptr = (char *) loop;
		q->q_ptr = (char *) loop;
		loop->qptr = WR(q);
		loop->oqptr = NULL;

		qprocson(q);

		return(0);
}

Because the messages are switched to the read queue following the other stream's read side, the driver needs a put procedure only on its write side. loopwput (in Example 9-12) shows another use of an ioctl(2). The driver supports the ioc_cmd value LOOP_SET in the iocblk(9S) of the M_IOCTL message. LOOP_SET makes the driver connect the current open stream to the stream indicated in the message. The second block of the M_IOCTL message holds an integer that specifies the minor device number of the stream to which to connect.

The LOOP_SET ioctl(2) processing involves several checks:

 
 
 
  Previous   Contents   Next