Part I Application Programming Interface
2. STREAMS Application-Level Components
3. STREAMS Application-Level Mechanisms
4. Application Access to the STREAMS Driver and Module Interfaces
7. STREAMS Framework - Kernel Level
8. STREAMS Kernel-Level Mechanisms
11. Configuring STREAMS Drivers and Modules
14. Debugging STREAMS-based Applications
B. Kernel Utility Interface Summary
As described in Chapter 9, STREAMS Drivers and as seen in the previous data structures, there are four STREAMS driver entry points:
The following real example was taken from the 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); }