File:  [MW Coherent from dump] / coherent / b / STREAMS / conf_79 / mkconf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

#define	_DDI_DKI	1
#define	_SYSV4		1

/*
 * This file contains routines for writing processed configuration data from
 * 'mkdev.c' out into a C-language configuration file, "conf.c".
 */

/*
 *-IMPORTS:
 *	<sys/compat.h>
 *		CONST
 *		PROTO
 *		ARGS ()
 *		LOCAL
 *	<kernel/v_types.h>
 *		NODEV
 *		major_t
 *		minor_t
 *	<stddef.h>
 *		size_t
 *		offsetof ()
 *		NULL
 *	<stdio.h>
 *		FILE
 *		stdout
 *		fopen ()
 *		fclose ()
 *		fprintf ()
 *	<time.h>
 *		time_t
 *		strftime ()
 *		localtime ()
 *	"ehand.h"
 *		ehand_t
 *		PUSH_HANDLER ()
 *		POP_HANDLER ()
 *		CHAIN_ERROR ()
 *		throw_error ()
 *	"mdev.h"
 *		MD_ENABLED
 *		mdev_t
 *		mdevices ()
 *	"sdev.h"
 *		sdev_sort ()
 *	"symbol.h"
 *		symbol_t
 *	"assign.h"
 *		extinfo_t
 */

#include <sys/compat.h>
#include <kernel/v_types.h>
#include <stddef.h>
#include <stdio.h>
#include <time.h>

#include "ehand.h"
#include "mdev.h"
#include "sdev.h"
#include "symbol.h"
#include "assign.h"

#include "mkconf.h"


/*
 * We define a table to ease the otherwise tedious process of building the
 * output for the entry point specifications.
 *
 * Sadly, we can't use the MDEV_... constants in this table.
 */

struct extern_tab {
	CONST char    *	flags;
	char		func;
	CONST char    *	outstr;
};

LOCAL struct extern_tab _exttab [] = {
	/*
	 * For STREAMS we have to generate an external reference to the
	 * STREAMS function table. We also have to generate stubs for the
	 * character-device entry points to map the SysV calling sequence
	 * into calls to the STREAMS-device entry points.
	 *
	 * Rather than generate those stubs here, we simply call up a generic
	 * template-style macro that will generate all the stubs we need. This
	 * is necessary since we may also be generating stubs for mapping from
	 * some non-SVR4 calling convention to SVR4 for regular devices, and
	 * the macro can deal with that, building the non-SVR4 to STREAMS
	 * mapping in one step.
	 *
	 * The stub generation happens in the second part of this table along
	 * with stub generation for regular devices.
	 */

	{ "Sc",	   0,		"DECLARE_STREAMS (%s)" },
	{ "S!c",   0,		"DECLARE_MODULE (%s)" },


	/*
	 * Now the regular device entry-point stuff.
	 */

	{ "b",     0,		"DECLARE_STRATEGY (%s)" },
	{ "b",     0,		"DECLARE_PRINT (%s)" },


	/*
	 * We assume that a STREAMS driver will only define the entry points
	 * below if it is also capable of acting as a block device or if the
	 * entry is applicable regardless of type.
	 *
	 * For practical reasons other parts of this system may not permit
	 * combination STREAMS and block drivers, because with a common entry
	 * point table for both types of device the block-mode entry points
	 * like open () will conflict with the stub generated for STREAMS.
	 */

	{ NULL,	MDEV_OPEN,	"DECLARE_OPEN (%s)" },
	{ NULL,	MDEV_CLOSE, 	"DECLARE_CLOSE (%s)" },
	{ NULL, MDEV_READ,	"DECLARE_READ (%s)" },
	{ NULL,	MDEV_WRITE,	"DECLARE_WRITE (%s)" },
	{ NULL,	MDEV_IOCTL,	"DECLARE_IOCTL (%s)" },
	{ NULL,	MDEV_CHPOLL,	"DECLARE_CHPOLL (%s)" },

	{ NULL,	MDEV_INIT,	"DECLARE_INIT (%s)" },
	{ NULL,	MDEV_STARTUP,	"DECLARE_STARTUP (%s)" },
	{ NULL,	MDEV_EXIT,	"DECLARE_EXIT (%s)" },
	{ NULL,	MDEV_HALT,	"DECLARE_HALT (%s)" },


	/*
	 * The SVR4-MP DDI/DDK defines an optional mmap () entry point
	 * for character devices, yet there is no function code for
	 * this defined in the System Files and Devices manual. Block
	 * drivers have the same problem with the size () entry.
	 */

	{ "b",	 MDEV_SIZE,	"DECLARE_SIZE (%s)" },
	{ "c",   MDEV_MMAP,	"DECLARE_MMAP (%s)" }

	/*
	 * The fork (), exec (), kenter () and kexit () entry points aren't
	 * defined for device drivers. In fact, I'm not sure what they *are*
	 * for unless it's for system services - processes that run in the
	 * kernel at higher priority than any user process (but usually at a
	 * lower priority than real-time processes).
	 *
	 * Since what Coherent has can barely be called a scheduler, these
	 * aren't defined here.
	 */
};


/*
 * Optionally write based on function test.
 */

#ifdef	USE_PROTO
LOCAL void (write_func) (FILE * out, mdev_t * mdevp, struct extern_tab * tab)
#else
LOCAL void
write_func ARGS ((out, mdevp, tab))
FILE	      *	out;
mdev_t	      *	mdevp;
struct extern_tab * tab;
#endif
{
	CONST char    *	fcheck;

	if (out == NULL || mdevp == NULL || tab == NULL)
		throw_error ("NULL pointer passed to write_func ()");

	if (tab->outstr == NULL)
		throw_error ("bad table parameter passed to write_func ()");

	if ((fcheck = tab->flags) != NULL) {
		/*
		 * Test for the logical "and" of the functions specified.
		 */

		while (* fcheck) {

			if (* fcheck == '!') {

				if (mdev_flag (mdevp, * ++ fcheck))
					return;
				fcheck ++;
			} else if (! mdev_flag (mdevp, * fcheck ++))
				return;
		}
	}

	if (tab->func && ! mdev_func (mdevp, tab->func))
		return;

	(void) fprintf (out, tab->outstr, mdevp->md_prefix->s_data);
	(void) fputc ('\n', out);
}


/*
 * Output "extern" declarations for device-driver entry points.
 */

#ifdef	USE_PROTO
LOCAL void (write_extern) (FILE * out, mdev_t * mdevp)
#else
LOCAL void
write_extern ARGS ((out, mdevp))
FILE	      *	out;
mdev_t	      *	mdevp;
#endif
{
	int		i;

	if (mdevp == NULL)
		throw_error ("NULL 'mdevp' passed to write_extern ()");

	/*
	 * Test to see whether it is a driver we are dealing with.
	 */

	if (mdev_flag (mdevp, MDEV_BLOCK) || mdev_flag (mdevp, MDEV_CHAR) ||
	    mdev_flag (mdevp, MDEV_STREAM)) {

		(void) fprintf (out, "/* entry points for \"%s\" driver */\n\n",
				mdevp->md_devname->s_data);
		(void) fprintf (out, "extern int %sdevflag;\n",
				mdevp->md_prefix->s_data);
	} else
		(void) fprintf (out, "/* entry points for \"%s\" facility */\n\n",
				mdevp->md_devname->s_data);

	for (i = 0 ; i < sizeof (_exttab) / sizeof (* _exttab) ; i ++)
		write_func (out, mdevp, & _exttab [i]);

	if (mdevp->md_interrupt)
		(void) fprintf (out, "DECLARE_INTR (%s)\n",
				mdevp->md_prefix->s_data);

	(void) fprintf (out, "\n\n");
}


/*
 * Output all the extern declarations needed to generate the tables.
 */

#ifdef	USE_PROTO
void (write_externs) (FILE * out)
#else
void
write_externs ARGS ((out))
FILE	      *	out;
#endif
{
	mdev_t	      *	mdevp;

	for (mdevp = mdevices () ; mdevp != NULL ; mdevp = mdevp->md_next)
		if (mdevp->md_configure == MD_ENABLED)
			write_extern (out, mdevp);
}


/*
 * Write a table of (init, start, exit, halt) routines.
 */

#ifdef	USE_PROTO
LOCAL void (write_ISEH) (FILE * out, char func, CONST char * name,
			 CONST char * capsname)
#else
LOCAL void
write_ISEH ARGS ((out, func, name, capsname))
FILE	      *	out;
char		func;
CONST char    *	name;
CONST char    *	capsname;
#endif
{
	mdev_t	      *	mdevp;
	int		any = 0;

	for (mdevp = mdevices () ; mdevp != NULL ; mdevp = mdevp->md_next) {

		if (mdevp->md_configure != MD_ENABLED ||
		    ! mdev_func (mdevp, func))
			continue;

		if (! any) {

			any = 1;
			(void) fprintf (out, "%s_t %stab [] = {\n", name, name);
		} else
			(void) fprintf (out, ",\n");

		(void) fprintf (out, "\t%s (%s)", capsname,
				mdevp->md_prefix->s_data);
	}

	if (any) {
		(void) fprintf (out, "\n};\n\nunsigned int n%s = sizeof "
					"(%stab) / sizeof (* %stab);\n\n",
				name, name, name);
	} else
		(void) fprintf (out, "%s_t %stab [1];\n\nunsigned int n%s"
					"= 0;\n\n",
				name, name, name);
}


/*
 * Write the init, startup, exit and halt-routine tables.
 */

#ifdef	USE_PROTO
void (write_misc) (FILE * out)
#else
void
write_misc ARGS ((out))
FILE	      *	out;
#endif
{
	write_ISEH (out, MDEV_INIT,	"init",	"INIT");
	write_ISEH (out, MDEV_STARTUP,	"start","START");
	write_ISEH (out, MDEV_EXIT,	"exit",	"EXIT");
	write_ISEH (out, MDEV_HALT,	"halt",	"HALT");
}


/*
 * A table to help simplify the process of writing out device-switch table
 * entries.
 */

typedef struct {
	char		func;
	CONST char    *	str;
	CONST char    *	nullstr;
} devtab_t;


LOCAL devtab_t _cdevswtab [] = {
	{ MDEV_OPEN,	"OPEN (%s)",	"NULL_OPEN" },
	{ MDEV_CLOSE,	"CLOSE (%s)",	"NULL_CLOSE" },
	{ MDEV_READ,	"READ (%s)",	"NULL_READ" },
	{ MDEV_WRITE,	"WRITE (%s)",	"NULL_WRITE" },
	{ MDEV_IOCTL,	"\n\t\tIOCTL (%s)",
					"\n\t\tNULL_IOCTL" },
	{ MDEV_CHPOLL,	"CHPOLL (%s)",	"NULL_CHPOLL" },
	{ MDEV_MMAP,	"MMAP (%s)",	"NULL_MMAP" },
	{	0,	NULL,		NULL }
};


LOCAL devtab_t _bdevswtab [] = {
	{ MDEV_OPEN,	"OPEN (%s)",	"NULL_OPEN" },
	{ MDEV_CLOSE,	"CLOSE (%s)",	"NULL_CLOSE" },
	{	0,	"STRATEGY (%s)", NULL },
	{	0,	"PRINT (%s)",	 NULL },
	{ MDEV_SIZE,	"SIZE (%s)",	"NULL_SIZE" },
	{	0,	NULL,		NULL }
};


/*
 * Output an entry for a device-switch table.
 */

#ifdef	USE_PROTO
LOCAL void (write_devsw_line) (FILE * out, mdev_t * mdevp, devtab_t * devtab)
#else
LOCAL void
write_devsw_line ARGS ((out, mdevp, devtab))
FILE	      *	out;
mdev_t	      *	mdevp;
devtab_t      *	devtab;
#endif
{
	(void) fprintf (out, "_ENTRY (& %sdevflag, ",
			mdevp->md_prefix->s_data);

	while (devtab->str != NULL) {

		if (devtab->func == 0 || mdev_func (mdevp, devtab->func))
			(void) fprintf (out, devtab->str,
					mdevp->md_prefix->s_data);
		else
			(void) fprintf (out, devtab->nullstr);

		if ((++ devtab)->str != NULL)
			(void) fprintf (out, ", ");
	}

	(void) fprintf (out, ")");
}


/*
 * Write an cdevsw [] and bdevsw [] tables.
 */

#ifdef	USE_PROTO
LOCAL void (write_devsw) (FILE * out, extinfo_t * extinfop)
#else
LOCAL void
write_devsw ARGS ((out, extinfop))
FILE	      *	out;
extinfo_t     *	extinfop;
#endif
{
	int		i;

	if (extinfop->ei_ncdevs > 0) {

		(void) fprintf (out, "cdevsw_t cdevsw [] = {\n");

		for (i = 0 ; i < extinfop->ei_ncdevs ; i ++) {
			mdev_t	      *	mdevp = extinfop->ei_cdevsw [i];

			if (i > 0)
				(void) fprintf (out, ",\n");

			if (mdevp == NULL)
				(void) fprintf (out, "\tNULL_CDEVSW ()");
			else if (mdev_flag (mdevp, MDEV_STREAM) != 0) {

				(void) fprintf (out, "\tSTREAMS_ENTRY (%s)",
						mdevp->md_prefix->s_data);
			} else {

				(void) fprintf (out, "\tCDEVSW");

				write_devsw_line (out, mdevp, _cdevswtab);
			}
		}

		(void) fprintf (out, "\n};\n\nunsigned int ncdevsw = sizeof "
					"(cdevsw) / sizeof (* cdevsw);\n\n");
	} else {

		(void) fprintf (out, "cdevsw_t cdevsw [1];\n\n");
		(void) fprintf (out, "unsigned int ncdevsw = 0;\n\n");
	}


	if (extinfop->ei_nbdevs > 0) {

		(void) fprintf (out, "bdevsw_t bdevsw [] = {\n");

		for (i = 0 ; i < extinfop->ei_nbdevs ; i ++) {

			if (i > 0)
				(void) fprintf (out, ",\n");

			if (extinfop->ei_bdevsw [i] != NULL) {

				(void) fprintf (out, "\tBDEVSW");

				write_devsw_line (out,
						  extinfop->ei_bdevsw [i],
						  _bdevswtab);
			} else
				(void) fprintf (out, "\tNULL_BDEVSW ()");
		}

		(void) fprintf (out, "\n};\n\nunsigned int nbdevsw = sizeof "
					"(bdevsw) /  sizeof (* bdevsw);\n\n");
	} else {

		(void) fprintf (out, "bdevsw_t bdevsw [1];\n\n");
		(void) fprintf (out, "unsigned int nbdevsw = 0;\n\n");
	}
}


/*
 * Write a STREAMS module table.
 */

#ifdef	USE_PROTO
LOCAL void (write_modtab) (FILE * out, extinfo_t * extinfop)
#else
LOCAL void
write_modtab ARGS ((out, extinfop))
FILE	      *	out;
extinfo_t     *	extinfop;
#endif
{
	int		i;

	if (extinfop->ei_nmodules > 0) {

		(void) fprintf (out, "modsw_t modsw [] = {\n");

		for (i = 0 ; i < extinfop->ei_nmodules ; i ++) {

			if (i > 0)
				(void) fprintf (out, ",\n");

			(void) fprintf (out, "\tMODSW_ENTRY (%s)",
					extinfop->ei_modules [i]->md_devname->s_data);
		}

		(void) fprintf (out, "\n};\n\nunsigned int nmodsw = sizeof "
					"(modsw) /  sizeof (* modsw);\n\n");
	} else {

		(void) fprintf (out, "modsw_t modsw [1];\n\n");
		(void) fprintf (out, "unsigned int nmodsw = 0;\n\n");
	}
}


/*
 * Write the external-to-internal device number mapping tables.
 */

#ifdef	USE_PROTO
LOCAL void (write_mappings) (FILE * out, extinfo_t * extinfop)
#else
LOCAL void
write_mappings ARGS ((out, extinfop))
FILE	      *	out;
extinfo_t     *	extinfop;
#endif
{
	int		i;

	(void) fprintf (out, "major_t _maxmajor = %d;\n\n",
			extinfop->ei_nemajors);

	(void) fprintf (out, "major_t _major [] = {");

	for (i = 0 ; i < extinfop->ei_nemajors ; i ++) {

		if (i % 8 == 0)
			(void) fprintf (out, "\n\t");

		if (extinfop->ei_etoimajor [i] == NODEV)
			(void) fprintf (out, "NODEV, ");
		else
			(void) fprintf (out, "%d, ",
					extinfop->ei_etoimajor [i]);
	}

	(void) fprintf (out, "NODEV\n};\n\n");

	(void) fprintf (out, "minor_t _minor [] = {");

	for (i = 0 ; i < extinfop->ei_nemajors ; i ++) {

		if (i % 16 == 0)
			(void) fprintf (out, "\n\t");

		(void) fprintf (out, "%d, ", extinfop->ei_minoroffset [i]);
	}

	(void) fprintf (out, "0\n};\n\n");
}


/*
 * Selection predicate for choosing "sdevice" entries that specify interrupt
 * vectors.
 */

#ifdef	USE_PROTO
LOCAL int (sel_vector) (sdev_t * sdevp)
#else
LOCAL int
sel_vector ARGS ((sdevp))
sdev_t	      *	sdevp;
#endif
{
	return sdevp->sd_itype > 0;
}


/*
 * Comparison predicate for sorting "sdevice" entries by vector number.
 */

#ifdef	USE_PROTO
LOCAL int (cmp_vector) (sdev_t * left, sdev_t * right)
#else
LOCAL int
cmp_vector ARGS ((left, right))
sdev_t	      *	left;
sdev_t	      *	right;
#endif
{
	return left->sd_vector < right->sd_vector;
}


/*
 * Function for generating tables of interrupt information.
 */

#ifdef	USE_PROTO
LOCAL void (write_vectors) (FILE * out)
#else
LOCAL void
write_vectors ARGS ((out))
FILE	      *	out;
#endif
{
	sdlist_t	veclist;
	sdev_t	      *	sdevp;
	int		i;
	unsigned long	masks [MAX_IPL + 1];


	/*
	 * We select all the "sdevice" entries that request vectors and sort
	 * them into order by vector so it's simple to determine what is
	 * going on.
	 */

	sdev_sort (& veclist, sel_vector, cmp_vector,
		   offsetof (sdev_t, sd_link));


	/*
	 * A first pass through the list determines which vectors are being
	 * used at which priority to build masks for the various levels.
	 */

	for (i = 0 ; i <= MAX_IPL ; i ++)
		masks [i] = 0;

	for (sdevp = veclist.sdl_first ; sdevp != NULL ;
					     sdevp = sdevp->sd_link) {

		masks [sdevp->sd_ipl] = 1UL << sdevp->sd_vector;
	}

	(void) fprintf (out, "intmask_t _masktab [] = {");

	for (i = 0 ; i < MAX_IPL ; i ++) {

		if (i % 4 == 0)
			(void) fprintf (out, "\n\t");

		(void) fprintf (out, "0x%xUL, ", masks [i]);

		masks [i + 1] |= masks [i];
	}

	(void) fprintf (out, "\n\t0xFFFFFFFFUL\n};\n\n");


	/*
	 * Now we generate thunks for the various interrupt entry points that
	 * can wrap up any mask-manipulation magic.
	 */

	i = -1;

	for (sdevp = veclist.sdl_first ; sdevp != NULL ;
						sdevp = sdevp->sd_link) {

		if (sdevp->sd_vector != i) {
			if (i != -1)
				(void) fprintf (out, "END_THUNK (%d)\n\n", i);

			i = sdevp->sd_vector;

			(void) fprintf (out, "BEGIN_THUNK (%d, 0x%xUL)\n",
					i, masks [sdevp->sd_ipl]);
		}

		(void) fprintf (out, "\tCALL_INTR (%d, %s)\n", i,
				sdevp->sd_mdevp->md_prefix->s_data);
	}

	if (i != -1)
		(void) fprintf (out, "END_THUNK (%d)\n\n", i);


	/*
	 * Now build a simple table which we can use to install the interrupt
	 * thunks we have built.
	 */


	if (i == -1) {

		(void) fprintf (out, "intr_t inttab [1];\n\unsigned int "
					"nintr = 0;\n\n");
		return;
	}

	(void) fprintf (out, "intr_t inttab [] = {\n");


	i = -1;

	for (sdevp = veclist.sdl_first ; sdevp != NULL ;
						sdevp = sdevp->sd_link) {

		if (sdevp->sd_vector != i) {
			if (i != -1)
				(void) fprintf (out, ",\n");

			i = sdevp->sd_vector;

			(void) fprintf (out, "\tINTR_THUNK (%d)", i);
		}
	}

	(void) fprintf (out, "\n};\n\nunsigned int nintr = sizeof (inttab) /"
				" sizeof (* inttab);\n\n");
}

#if	_REMINDER
/*
 * We output a bogus definition which needs the address of some functions we
 * want around to use this file...
 */

#ifdef	USE_PROTO
LOCAL void (write_reminder) (FILE * out)
#else
LOCAL void
write_reminder ARGS ((out))
FILE	      *	out;
#endif
{
	(void) fprintf (out, "/*\n * Make sure that the functions which use"
			     " this file are out there\n */\n\n");
	(void) fprintf (out, "__EXTERN_C_BEGIN__\n\n");
	(void) fprintf (out, "void\t\tSTREAMS_INIT\t__PROTO ((void));\n");
	(void) fprintf (out, "\n__EXTERN_C_END__\n\n");
	(void) fprintf (out, "\nvoid (* __bogus []) __PROTO ((void)) = {\n");
	(void) fprintf (out, "\tSTREAMS_INIT\n};\n");
}
#endif	/* ! _REMINDER */


/*
 * Write out a C-language configuration file with definitions for all the data
 * the implementation needs compiled from the plain-text configuration
 * database.
 */

#ifdef	__USE_PROTO__
int (write_conf_c) (CONST char * name, extinfo_t * extinfop)
#else
int
write_conf_c ARGS ((name, extinfop))
CONST char    *	name;
extinfo_t     *	extinfop;
#endif
{
	time_t		gentime;
	char		timebuf [70];
	FILE	      *	out;
	ehand_t		err;

	if (name == NULL)
		out = stdout;
	else if ((out = fopen (name, "w")) == NULL)
		throw_error ("Unable to open output file for writing");

	if (PUSH_HANDLER (err) == 0) {
		time (& gentime);

		fprintf (out, "/*\n");
		fprintf (out, " * The code in this file was automatically "
			      "generated. Do not hand-modify!\n");

#ifdef	__COHERENT__
		strncpy (timebuf, asctime (localtime (& gentime)),
			 sizeof (timebuf) - 1);
		timebuf [sizeof (timebuf) - 1] = 0;
#else
		strftime (timebuf, sizeof (timebuf) - 1, "%x %X %Z",
			  localtime (& gentime));
#endif

		fprintf (out, " * Generated at %s\n", timebuf);
		fprintf (out, " */\n\n");
		fprintf (out, "#define _KERNEL\t\t1\n");
		fprintf (out, "#define _DDI_DKI\t1\n\n");
		fprintf (out, "#include <kernel/confinfo.h>\n\n");

		write_externs (out);
		write_misc (out);
		write_devsw (out, extinfop);
		write_modtab (out, extinfop);
		write_mappings (out, extinfop);
		write_vectors (out);

#if	_REMINDER
		write_reminder (out);
#endif
		if (out != stdout)
			fclose (out);
	} else {
		if (out != stdout)
			fclose (out);
		CHAIN_ERROR (err);
	}

	POP_HANDLER (err);
	return 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.