STREAMS Programming Guide

Exit Print View

Updated: July 2014
 
 

pts Example

The following real example was taken from the Oracle Solaris operating environment. The driver pts(7D) is the pseudo terminal slave driver.

Example 11-1  Stream Pseudo Terminal Module
/*
 * Slave Stream Pseudo Terminal Module
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/cmn_err.h>
#include <sys/modctl.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

static int ptsopen (queue_t*, dev_t*, int, int, cred_t);
static int ptsclose (queue_t*, int, cred_t*);
static int ptswput (queue_t*, mblk_t*);
static int ptsrsrv (queue_t*);
static int ptswsrv (queue_t*);

static int pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
      void *arg,void **result);

static struct module_info pts_info = {
		0xface,
		"pts",
		0,
		512,
		512,
		128
};

static struct qinit ptsrint = {
		NULL,
		ptsrsrv,
		ptsopen,
		ptsclose,
		NULL,
		&pts_info,
		NULL
};

static struct qinit ptswint = {
		ptswput,
		ptswsrv,
		NULL,
		NULL,
		NULL,
		&pts_info,
		NULL
};

static struct streamtab ptsinfo = {
		&ptsrint,
		&ptswint,
		NULL,
		NULL
};

static int pts_identify(dev_info_t *devi);
static int pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
static int pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
static dev_info_t *pts_dip;				/* private copy of devinfo ptr */

extern kmutex_t pt_lock;
extern pt_cnt;
static struct cb_ops cb_pts_ops = {
   nulldev,       /* cb_open */ 
   nulldev,       /* cb_close */ 
   nodev,         /* cb_strategy */
   nodev,         /* cb_print */
   nodev,         /* cb_dump */
   nodev,         /* cb_read */
   nodev,         /* cb_write */
   nodev,         /* cb_ioctl */
   nodev,         /* cb_devmap */
   nodev,         /* cb_mmap */
   nodev,         /* cb_segmap */
   nochpoll,      /* cb_chpoll */
   ddi_prop_op,   /* cb_prop_op */
   &ptsinfo,      /* cb_stream */
   D_MP           /* cb_flag */
};

static struct dev_ops pts_ops = {
   DEVO_REV,      /* devo_rev */
   0,             /* devo_refcnt */   
   pts_devinfo,   /* devo_getinfo */ 
   pts_identify,  /* devo_identify */
   nulldev,       /* devo_probe */
   pts_attach,    /* devo_attach */
   pts_detach,    /* devo_detach */
   nodev,         /* devo_reset */
   &cb_pts_ops,   /* devo_cb_ops */
   (struct bus_ops*) NULL   /* devo_bus_ops */
};

/*
 * Module linkage information for the kernel.
 */

static struct modldrv modldrv = {
			&mod_driverops, 		/* Type of module: a pseudo driver */
			"Slave Stream Pseudo Terminal driver'pts'",
			&pts_ops,				/* driver ops */
};

static struct modlinkage modlinkage = {
		MODREV_1,
		(void *)&modldrv,
		NULL
};

int
_init(void)
{
		return (mod_install(&modlinkage));
}

int
_fini(void)
{
		return (mod_remove(&modlinkage));
}

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

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

static int
pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
		int i;
		char name[5];

		if (cmd != DDI_ATTACH)
			return (DDI_FAILURE);
	
		for (i = 0; i < pt_cnt; i++) {
			(void) sprintf(name, "%d", i);
			if (ddi_create_minor_node(devi, name, S_IFCHR, i, NULL, 0) 
						== DDI_FAILURE) {
				ddi_remove_minor_node(devi, NULL);
				return (DDI_FAILURE);
			}
		}
		return (DDI_SUCCESS);
}

static int
pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
		ddi_remove_minor_node(devi, NULL);
		return (DDI_SUCCESS);
}

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

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

/* the open, close, wput, rsrv, and wsrv routines are presented
 * here solely for the sake of showing how they interact with the
 * configuration data structures and routines. Therefore, the 
 * bulk of their code is not included.
 */
static int
ptsopen(rqp, devp, oflag, sflag, credp)
		queue_t *rqp; 	/* pointer to the read side queue */
		dev_t   *devp;			/* pointer to stream tail's dev */
		int	 oflag; 			/* the user open(2) supplied flags */
		int 	sflag; 			/* open state flag */
		cred_t  *credp;		/* credentials */
{
		qprocson(rqp);
		return (0);
}

static int
ptsclose(rqp, flag, credp)
		queue_t		*rqp;
		int			flag;
		cred_t		*credp;
{
		qprocsoff(rqp);
		return (0);
}

static int
ptswput(qp, mp)
		queue_t		*qp;
		mblk_t		*mp;
{
		return (0);
}

static int
ptsrsrv(qp)
		queue_t *qp;
{
		return (0);
}

static int
ptswsrv(qp)
		queue_t 	*qp;
{
		return (0);
}