/* (-lgl * Coherent 386 release 4.2 * Copyright (c) 1982, 1993 by Mark Williams Company. * All rights reserved. May not be copied without permission. * For copying permission and licensing info, write licensing@mwc.com -lgl) */ #ifndef __SYS_STREAM_H__ #define __SYS_STREAM_H__ /* * This ^^^^^^^^^^^^^^^^ symbol is used in the DDI/DKI header <sys/ddi.h> to * determine which #undef directives it is required to perform, on the basis * that it should avoid touching namespaces unless they have been reserved * by the inclusion of a header which reserves such classes of names. */ #include <common/ccompat.h> #include <common/__cred.h> #include <common/__caddr.h> #include <common/__types.h> #include <kernel/__pl.h> #include <kernel/_toid.h> #include <kernel/x86lock.h> #include <common/_stream.h> /* * Public section of the <sys/stream.h> file, for consumption by user * application code using access to the STREAMS messaging system, and * by STREAMS drivers. * * The information in this header is directly related to the information * published in the System V, Release 4 STREAMS Programmer's Guide, * Appendices A and B. */ /* * Message types. The particular values here may have some significance * to some macros defined later, particularly datamsg (). */ #define M_PRI 0x80 #define QPCTL M_PRI /* regular messages */ #define M_DATA 0 #define M_PROTO 1 #define M_DELAY 2 #define M_IOCTL 3 #define M_SETOPTS 4 #define M_SIG 5 #define M_CTL 6 #define M_BREAK 7 #define M_PASSFP 8 #define M_RSE 9 /* priority messages */ #define M_PCPROTO (1 + M_PRI) #define M_IOCACK (3 + M_PRI) #define M_IOCNAK (4 + M_PRI) #define M_PCSIG (5 + M_PRI) #define M_ERROR (6 + M_PRI) #define M_FLUSH (7 + M_PRI) #define M_HANGUP (8 + M_PRI) #define M_START (9 + M_PRI) #define M_STOP (10 + M_PRI) #define M_COPYIN (11 + M_PRI) #define M_COPYOUT (12 + M_PRI) #define M_IOCDATA (13 + M_PRI) #define M_PCRSE (14 + M_PRI) #define M_READ (15 + M_PRI) #define M_STARTI (16 + M_PRI) #define M_STOPI (17 + M_PRI) struct streamtab { struct qinit * st_rdinit; /* defines read QUEUE */ struct qinit * st_wrinit; /* defines write QUEUE */ struct qinit * st_muxrinit; /* for multiplexing drivers only */ struct qinit * st_muxwinit; /* for multiplexing drivers only */ }; /* * Private type definitions. */ typedef atomic_uchar_t __str_lock_t; /* * QUEUE structures - these structures are used to build streams. * * Note that "queue_t" structures occur in pairs, first the write queue, then * the read queue. The QREADR flag distinguishes them for the RD (q), WR (q) * and OTHERQ (q) macros. * * The System V DDI/DKI adds multiprocessor support to STREAMS via the notion * of "freezing" a stream, something mostly analagous to a basic lock. We can * implement this facility either in terms of the primitive machine-specific * atomic operations, or in terms of the DDI/DKI high-level lock operations. * * For now, we choose the latter. */ struct queue { struct qinit * q_qinfo; /* procedures and limits for queue */ mblk_t * q_first; /* head of message queue for QUEUE */ mblk_t * q_last; /* tail of message queue for QUEUE */ queue_t * q_next; /* next QUEUE in stream */ queue_t * q_link; /* next on STEAMS scheduling list */ __VOID__ * q_ptr; /* to private data structure */ unsigned long q_count; /* number of characters in queue */ unsigned long q_flag; /* QUEUE state */ long q_minpsz; /* minimum packet size accepted */ long q_maxpsz; /* maximum packet size accepted */ unsigned long q_hiwat; /* message queue high water mark */ unsigned long q_lowat; /* message queue low water mark */ qband_t * q_bandp; /* separate flow information */ unsigned char q_nband; /* number of priority bands */ unsigned char q_pad1 [3]; /* reserved for future use */ long q_pad2 [2]; /* reserved for future use */ /* * Data from this point are MWC extensions for multiprocessing. The * DDI/DKI revokes user's right to know about the size of the * structure, among other things. */ unsigned char q_active; /* count of active put/srv routines */ unsigned char q_lastband; /* band of last retrieved message */ __str_lock_t q_locked; /* hack implementation of freezing */ }; /* * Hack around the union above. This field should only be referred to by some * layering macros in <sys/strmlib.h> anyway, but we try and keep it clean. */ #define q_lock x.q_lock /* * Queue flag definitions : these are internal to the system, and the values * bear no relation to any definitions in System V. Drivers use these flags at * their own risk... */ #define QENAB 0x0001 /* queue is on qenable () schedule */ #define QWANTR 0x0002 /* someone wants to read from the queue */ #define QWANTW 0x0004 /* someone wants to write to the queue */ #define QFULL 0x0008 /* queue is full */ #define QREADR 0x0010 /* set for read queues */ #define QNOENB 0x0020 /* prevent queue from being enabled */ #define QBACK 0x0040 /* queue has been back-enabled */ #define QOLD 0x0080 /* pre-SVR4 open/close interface */ #define QPROCSOFF 0x0100 /* put/service routines disabled */ #define QDRAIN 0x0200 /* waiting for queue to drain */ #define QSRVACTIVE 0x0400 /* service routine is active */ /* #define QUSE ????? queue has been allocated */ /* #define QHLIST ????? SVR4, not used by this implementation */ /* * queue priority-band information. */ struct qband { struct qband * qb_next; /* next band's info */ unsigned long qb_count; /* count of bytes in band */ struct msgb * qb_first; /* beginning of band's data */ struct msgb * qb_last; /* end of band's data */ unsigned long qb_hiwat; /* high water mark for band */ unsigned long qb_lowat; /* low water mark for band */ unsigned long qb_flag; /* flags, see below */ unsigned long qb_pad1; /* reserved for future use */ }; /* Flags used in band structure */ #define QB_FULL 0x0001 /* band is considered full */ #define QB_WANTW 0x0002 /* someone wants to write to band */ #define QB_BACK 0x0004 /* queue has been back-enabled */ /* non-SVR4 flag */ #define QB_FIRST 0x0100 /* first entry in allocation unit */ /* * Message structures - the format of STREAMS messages and message data * blocks. */ struct msgb { struct msgb * b_next; /* next message on queue */ struct msgb * b_prev; /* previous message on queue */ struct msgb * b_cont; /* next message block of message */ unsigned char * b_rptr; /* first unread data byte in buffer */ unsigned char * b_wptr; /* first unwritten data byte in buffer */ struct datab * b_datap; /* data block */ unsigned char b_band; /* message priority */ unsigned char b_pad1; unsigned short b_flag; /* message flags */ long b_pad2; }; /* Flag definitions for message blocks */ #define MSGMARK 0x0001 /* last byte of message is "marked" */ #define MSGNOLOOP 0x0002 /* don't loop message to write-side of stream */ #define MSGDELIM 0x0004 /* message is delimited */ /* Extra flag definitions, for STREAMS private use only */ #define MSGTRIPLE 0x0100 /* message block is part of triple */ #define MSGFREE 0x0200 /* message block is free */ #define MSGMASK_SYSTEM 0x0300 /* system-private flags */ /* * Data structure used to control freeing of user-defined STREAMS buffer * memory (such as user memory that is temporarily mapped to kernel space * to avoid copying, or driver-dependent shared memory from an I/O space). */ struct free_rtn { void (* free_func) /* driver-dependent free routine */ __PROTO ((__VOID__ * _arg)); __VOID__ * free_arg; /* argument for free_rtn */ }; typedef struct free_rtn frtn_t; /* * Data block descriptors - several mblk_t's may refer to the same section * of STREAMS buffer memory to avoid copying. * * Note that this data structure is NOT identical to its System V counterpart. */ struct datab { frtn_t * db_frtnp; /* internal use */ unsigned char * db_base; /* first byte of buffer */ unsigned char * db_lim; /* last+1 byte of buffer */ unsigned char db_ref; /* count of messages pointing here */ unsigned char db_type; /* message type */ short db_pad1; /* reserved for future use */ long db_pad2; /* reserved for future use */ }; /* * Define one of these structures with external visibility to publish the * entry points to your STREAMS driver. */ typedef void (* __putp_t) /* put procedure */ __PROTO ((queue_t * _q, mblk_t * _mp)); typedef void (* __srvp_t) /* service procedure */ __PROTO ((queue_t * _q)); typedef int (* __qopen_t) /* open procedure */ __PROTO ((queue_t * _q, n_dev_t * _devp, int _flag, int _sflag, __cred_t * _credp)); typedef int (* __qclose_t) /* called on last close/pop */ __PROTO ((queue_t * _q, int _flag, __cred_t * _credp)); typedef int (* __qadmin_t) /* reserved for future use */ __PROTO ((void)); struct qinit { __putp_t qi_putp; /* put procedure */ __srvp_t qi_srvp; /* service procedure */ __qopen_t qi_qopen; /* called on each open */ __qclose_t qi_qclose; /* called on last close/pop */ __qadmin_t qu_qadmin; /* reserved for future use */ struct module_info * qi_minfo; /* information structure */ struct module_stat * qi_mstat; /* statistics - optional */ }; /* * General STREAMS "module information", mainly used by SysV configuration * utilities, although it also provides defaults for the queues at open time. */ struct module_info { unsigned short mi_idnum; /* module ID number */ char * mi_idname; /* module name */ long mi_minpsz; /* min packet size accepted */ long mi_maxpsz; /* max packet size accepted */ unsigned long mi_hiwat; /* hi-water mark, for flow control */ unsigned long mi_lowat; /* lo-water mark, for flow control */ }; /* Infinite message size, for use in module_info mi_minpsz/mi_maxpsz */ #define INFPSZ 0x7FFFFFFF /* * General statistics structure, useful for profiling module/driver * activity. */ struct module_stat { long ms_pcnt; /* count of calls to put proc */ long ms_scnt; /* count of calls to service proc */ long ms_ocnt; /* count of calls to open proc */ long ms_ccnt; /* count of calls to close proc */ long ms_acnt; /* count of calls to admin proc */ char * ms_xptr; /* pointer to private statistics */ short ms_xsize; /* length of private stats buffer */ }; /* * link block for multiplexed streams... this structure appears in the data * portion of I_LINK and I_UNLINK M_IOCTL messages. * * Note that the STREAMS manual documents the type of "l_index" as an "int", * but for our purposes an "n_dev_t" (which is a long) is more appropriate. */ typedef n_dev_t __muxid_t; struct linkblk { queue_t * l_qtop; /* lowest write queue of upper stream */ queue_t * l_qbot; /* highest write queue of lower stream */ __muxid_t l_index; /* unique index for lower stream */ long l_pad [5]; /* reserved for future use */ }; /* * Stream head options control message format, used as the data part of an * M_SETOPTS message set from a driver or module to the stream head. The * values for the "so_readopt" member can be found in <stropts.h> as well * as below. */ struct stroptions { unsigned long so_flags; /* options to set */ short so_readopt; /* read option */ unsigned short so_wroff; /* write offset */ long so_minpsz; /* min packet size */ long so_maxpsz; /* max packet size */ unsigned long so_hiwat; /* read queue high-water mark */ unsigned long so_lowat; /* read queue low-water mark */ unsigned char so_band; /* band for water marks */ }; /* * Flag values for the "so_flags" member, */ #define SO_ALL 0x3F /* set all options */ #define SO_READOPT 0x0001 /* set read option */ #define SO_WROFF 0x0002 /* set write offset */ #define SO_MINPSZ 0x0004 /* set min packet size */ #define SO_MAXPSZ 0x0008 /* set max packet size */ #define SO_HIWAT 0x0010 /* set read queue high-water mark */ #define SO_LOWAT 0x0020 /* set read queue low-water mark */ /* Flags above control which members to look at, below are R4 extensions */ #define SO_MREADON 0x0040 /* set read notification on */ #define SO_MREADOFF 0x0080 /* set read notification off */ #define SO_NDELON 0x0100 /* old TTY semantics for NDELAY */ #define SO_NDELOFF 0x0200 /* STREAMS semantics for NDELAY */ #define SO_ISTTY 0x0400 /* stream is acting as a terminal */ #define SO_ISNTTY 0x0800 /* stream is not acting as a terminal */ #define SO_TOSTOP 0x1000 /* stop on background writes to stream */ #define SO_TONSTOP 0x2000 /* don't stop on background writes */ #define SO_BAND 0x4000 /* water marks that affect band */ /* * Other flags relevant to the above structure are defined in <sys/stropts.h>. */ /* * Structure of data block found at head of M_IOCTL message, usually reused * for replying to M_IOCTL with an M_IOCACK or M_IOCNAK message. */ struct iocblk { int ioc_cmd; /* ioctl () command type */ __cred_t * ioc_cr; /* user's full credentials */ unsigned int ioc_id; /* M_IOCTL sequence number */ unsigned int ioc_count; /* bytes in data field */ int ioc_error; /* error code */ int ioc_rval; /* return value */ long ioc_filler [4]; /* reserved for future use */ }; /* * For compatibility with SVR3 sources */ #define ioc_uid ioc_cr->cr_uid #define ioc_gid ioc_cr->cr_gid /* * This special value of "ioc_count" is used to indicate that the stream * head has passed us a "transparent" ioctl rather than an I_STR ioctl. */ #define TRANSPARENT ((unsigned int) -1) /* * This structure defines the data format used in an M_COPYIN/M_COPYOUT * message (used to request data copying from user process space during * an ioctl ()). Note that the first three members of the "copyreq" structure * match the first three fields of the "iocblk" structure. It is intended * that drivers be able to use this property to simply use the intial message * block from M_IOCTL for all the transparent IOCTL messages. */ struct copyreq { int cq_cmd; /* ioctl command (from ioc_cmd) */ __cred_t * cq_cr; /* full credentials (from ioc_cr) */ unsigned int cq_id; /* ioctl id (from ioc_id) */ __caddr_t cq_addr; /* user address to copy data to/from */ unsigned int cq_size; /* number of bytes to copy */ int cq_flag; /* flags, see below */ mblk_t * cq_private; /* private state information */ long cq_filler [4]; /* reserved for future use */ }; /* For compatibility with old sources. */ #define cq_uid cq_cr->cr_uid #define cq_gid cq_cr->cr_gid /* cq_flag values */ #define STRCANON 0x0001 /* b_cont data block contains canonical format specifier */ #define RECOPY 0x0002 /* perform I_STR copyin again using canonical format specifier */ /* * This structure is used in the M_IOCDATA response to an M_COPYIN/M_COPYOUT, * and is laid out so that equivalent fields from the "struct copyreq" * structure remain at the same offset, ie we expect the stream head to * simply turn around our request, although it is not required to do so. */ struct copyresp { int cp_cmd; /* ioctl command (from cq_cmd) */ __cred_t * cp_cr; /* full credentials (from cq_cr) */ unsigned int cp_id; /* ioctl id (from cq_id) */ __caddr_t cp_rval; /* request status: 0 success, non-zero failure */ unsigned int cp_pad1; /* reserved */ unsigned int cp_pad2; /* reserved */ mblk_t * cp_private; /* private state information */ long cp_filler [4]; /* reserved for future use */ }; /* for compatibility with old sources */ #define cp_uid cp_cr->cr_uid #define cp_gid cp_cr->cr_gid /* * LOCAL EXTENSIONS : The methods used in the multiplexing examples in the * STREAMS V.2 manual are slightly inefficient. The following general STREAMS * queue schedling routines were defined for multiplexing drivers and device * drivers (such as Ethernet drivers) that must consume data from several * queues. * * In the STREAMS code supplied, these routines are also used for the main * streams queue scheduling, so we define them here. A consequence of this is * that a given queue may not be queued for both STREAMS execution and * multiplexing at the same time. * * The basic idea is to use qschedule () and qunschedule () to add and remove * a queue from the scheduling list. Lower queues may then getq () from the * "s_head" of the scheduling list to consume the data. Since by default this * will simply attempt to drain each scheduled queue of data before moving to * the next, the muxrobin () call adjusts the head/tail pointers to effect * a round-robin of the queues that have data. */ struct strsched { queue_t * s_head; /* next queue to read data from */ queue_t * s_tail; /* last queue to read data from */ }; /* * Message allocation priorities, used with allocb () and bufcall () */ enum { BPRI_LO, BPRI_MED, BPRI_HI }; /* * Flag values used with flushq () and flushband (). */ enum { FLUSHDATA, /* flush M_DATA, M_PROTO, M_PCPROTO, M_DELAY */ FLUSHALL /* flush all messages from queue */ }; /* * queue field numbers to be used with strqget ()/strqset (). */ typedef enum qfields { QHIWAT = 0, /* q_hiwat or qb_hiwat */ QLOWAT = 1, /* q_lowat or qb_lowat */ QMAXPSZ = 2, /* q_maxpsz */ QMINPSZ = 3, /* q_minpsz */ QCOUNT = 4, /* q_count or qb_count */ QFIRST = 5, /* q_first or qb_first */ QLAST = 6, /* q_last or qb_last */ QFLAG = 7, /* q_flag or qb_flag */ QBAD = 8 } qfields_t; #if _DDI_DKI /* * External function definitions for the STREAMS library. * * Note that prototypes are also provided for those STREAMS functions that * are available as macros. This is since this header is a more appropriate * place to encode this knowledge than the DDI/DKI required header * <sys/ddi.h>. * * The System V Release 4 Multi-Processor DDI/DKI defines some extra versions * of some common STREAMS library functions so that STREAMS driver code does * not reference the q->q_next member, since this may not be safe in a multi- * processor environment. These functions are included in this implementation * and are prototyped below to help device drivers anticipate the multi- * processor environment. */ __EXTERN_C_BEGIN__ int adjmsg __PROTO ((mblk_t * _mp, int _len)); mblk_t * allocb __PROTO ((int _size, unsigned int _pri)); queue_t * backq __PROTO ((queue_t * _q)); int bcanput __PROTO ((queue_t * _q, unsigned char _pri)); int bcanputnext __PROTO ((queue_t * _q, unsigned char _pri)); /* see <sys/bufcall.h> for a discussion of this declaration for bufcall () */ #define __STDARG_BUFCALL__ toid_t bufcall __PROTO ((unsigned int _size, int _pri, ...)); int canput __PROTO ((queue_t * _q)); int canputnext __PROTO ((queue_t * _q)); mblk_t * copyb __PROTO ((mblk_t * _bp)); mblk_t * copymsg __PROTO ((mblk_t * _mp)); int datamsg __PROTO ((unsigned char _type)); mblk_t * dupb __PROTO ((mblk_t * _bp)); mblk_t * dupmsg __PROTO ((mblk_t * _mp)); void enableok __PROTO ((queue_t * _q)); mblk_t * esballoc __PROTO ((unsigned char * _mbase, int _size, int _pri, frtn_t * _fr_rtn)); /* The following assumes __STDARG_BUFCALL__ as above */ toid_t esbbcall __PROTO ((int _pri, ...)); void flushband __PROTO ((queue_t * _q, unsigned char _pri, int _flag)); void flushq __PROTO ((queue_t * _q, int _flag)); __pl_t freezestr __PROTO ((queue_t * _q)); void freeb __PROTO ((mblk_t * _bp)); void freemsg __PROTO ((mblk_t * _mp)); int (* getadmin __PROTO ((unsigned short _mid))) __PROTO ((void)); unsigned short getmid __PROTO ((char * _name)); mblk_t * getq __PROTO ((queue_t * _q)); int insq __PROTO ((queue_t * _q, mblk_t * _emp, mblk_t * _nmp)); void linkb __PROTO ((mblk_t * _mp, mblk_t * _bp)); int msgdsize __PROTO ((mblk_t * _mp)); mblk_t * msgpullup __PROTO ((mblk_t * _mp, int _len)); void noenable __PROTO ((queue_t * _q)); queue_t * OTHERQ __PROTO ((queue_t * _q)); int pcmsg __PROTO ((__uchar_t _type)); int pullupmsg __PROTO ((mblk_t * _mp, int _len)); void put __PROTO ((queue_t * _q, mblk_t * _mp)); int putbq __PROTO ((queue_t * _q, mblk_t * _mp)); int putctl __PROTO ((queue_t * _q, int _type)); int putctl1 __PROTO ((queue_t * _q, int _type, int _param)); int putnext __PROTO ((queue_t * _q, mblk_t * _mp)); int putnextctl __PROTO ((queue_t * _q, int _type)); int putnextctl1 __PROTO ((queue_t * _q, int _type, int _param)); int putq __PROTO ((queue_t * _q, mblk_t * _mp)); void qenable __PROTO ((queue_t * _q)); void qprocsoff __PROTO ((queue_t * _rq)); void qprocson __PROTO ((queue_t * _rq)); void qreply __PROTO ((queue_t * _q, mblk_t * _mp)); int qsize __PROTO ((queue_t * _q)); queue_t * RD __PROTO ((queue_t * _q)); mblk_t * rmvb __PROTO ((mblk_t * _mp, mblk_t * _bp)); void rmvq __PROTO ((queue_t * _q, mblk_t * _mp)); int strlog __PROTO ((short _mid, short _sid, char _level, unsigned short _flags, char * _fmt, ...)); int strqget __PROTO ((queue_t * _q, qfields_t _what, unsigned char _pri, long * _valp)); int strqset __PROTO ((queue_t * _q, qfields_t _what, unsigned char _pri, long _val)); int testb __PROTO ((int _size, int _pri)); void unbufcall __PROTO ((toid_t _id)); void unfreezestr __PROTO ((queue_t * _q, __pl_t _pl)); mblk_t * unlinkb __PROTO ((mblk_t * _mp)); queue_t * WR __PROTO ((queue_t * _q)); __EXTERN_C_END__ /* * Possible values for the stream open flag "sflag" in a module or driver * open (0 implies a normal driver open) */ enum { MODOPEN = 1, /* normal module open */ CLONEOPEN /* clone device open */ }; /* * Special value for the two-byte form of the M_ERROR message. */ enum { NOERROR = 0xFF }; /* * Functions that are normally implemented as macros (although the function * versions which are prototyped above are available by including the * <sys/ddi.h> header. */ /* * NB: Borland C++ 3.1 in 'C' mode insists that if a pointer is derived from * a ternary where the arms are calculated from lvalues then dereferencing * that pointer does not yield a valid lvalue, e.g. * WR (q)->q_ptr = NULL; * it thinks is invalid, which is untrue. To fix this, the pointer value from * the ternary seems to need massaging to turn it into a proper rvalue... the * easiest way to do this is add 0 to the *result* of the ternary. This is * optimized away by basic constant-folding in even simple compilers. */ #define __HACK(exp) ((exp) + 0) #define datamsg(type) ((unsigned char) ((type) & (M_PRI - 1)) <= M_DELAY) /* There is no multiprocessor macro implementation of enableok () */ /* There is no multiprocessor macro implementation of noenable () */ #define OTHERQ(q) __HACK (((q)->q_flag & QREADR) != 0 ? (q) + 1 : (q) - 1) #define pcmsg(type) ((type) >= QPCTL) #define RD(q) __HACK (((q)->q_flag & QREADR) != 0 ? (q) : (q) - 1) #define WR(q) __HACK (((q)->q_flag & QREADR) != 0 ? (q) + 1 : (q)) #endif /* _DDI_DKI */ #endif /* ! defined (__SYS_STREAM_H__) */