Subject: Multi-valued locators
To: None <tech-kern@NetBSD.ORG>
From: Lennart Augustsson <augustss@cs.chalmers.se>
List: tech-kern
Date: 01/07/1998 00:18:55
Hi!

I've made a stab at allowing locators with multiple values.
You could call it a hack, but I call it a light weight change. :-)
Since 1.3 is out the door now I'm hoping for some feedback
on this suggestion.  With enough thumbs up, I'll commit it.

	-- Lennart

[Apologies to those of you who got this twice.]

Multi-valued locators
=====================

The changes to config to support locators with multiple values are
minimal and fully backwards compatible.  No changes are needed to the
kernel configuration code unless you need to use multiple values, and
even then the changes are small.

Use
---

Old locator definition syntax:

locdef ::= locname
	   locname = value
	   [ locname = value ]

Added syntax for multiple values:

	   locname[number]
	   locname[number] = { value, ... }
	   [ locname[number] = { value, ... } ]

Old locator use syntax:

	   locname value

Added syntax for multiple values:

	   locname value,value,...


An example, the ISA bus definition.

The old definition:

device	isa {[port = -1], [size = 0],
	     [iomem = -1], [iosiz = 0],
	     [irq = -1], [drq = -1], [drq2 = -1]}

The new definition, supporting 4 port ranges and 2 drqs.

device	isa {[port[4] = {-1,-1,-1,-1}], 
	     [size[4] = { 0,0,0,0 } ],
	     [iomem = -1], [iosiz = 0],
	     [irq = -1], [drq[2] = {-1,-1}] }


Using this we can now have this SB line (covering the DSP
and MIDI UART):

sb0	at isa? port 0x220,0x300 irq 5 drq 1,5	# SoundBlaster



Implementation
--------------

A definition of a multi-valued locator is treated as a definition of
several normal locators.  E.g. `port[4]' is treated as the definition
of `port', `port#1', `port#2', and `port#3'.  Note that these names
will not clash with normal names since `#' is not a valid character
in a name.
The use of a multi-valued locator will similarely give the values
to these pseude-names.

The files that are generated by config are per usual, except that `#' is
replaced by `_' where necessary to generate a valid name.

For the ISA bus we get:

ioconf.c:
...
const char *isacf_locnames[] = { "port", "port#1", "port#2", "port#3", "size", "size#1", "size#2", "size#3", "iomem", "iosiz", "irq", "drq", "drq#1", NULL};
...

locators.h:
...
extern const char *isacf_locnames[];
#define ISACF_PORT 0
#define ISACF_PORT_DEFAULT -1
#define ISACF_PORT_1 1
#define ISACF_PORT_1_DEFAULT -1
#define ISACF_PORT_2 2
#define ISACF_PORT_2_DEFAULT -1
#define ISACF_PORT_3 3
#define ISACF_PORT_3_DEFAULT -1
#define ISACF_SIZE 4
#define ISACF_SIZE_DEFAULT 0
#define ISACF_SIZE_1 5
#define ISACF_SIZE_1_DEFAULT 0
#define ISACF_SIZE_2 6
#define ISACF_SIZE_2_DEFAULT 0
#define ISACF_SIZE_3 7
#define ISACF_SIZE_3_DEFAULT 0
#define ISACF_IOMEM 8
#define ISACF_IOMEM_DEFAULT -1
#define ISACF_IOSIZ 9
#define ISACF_IOSIZ_DEFAULT 0
#define ISACF_IRQ 10
#define ISACF_IRQ_DEFAULT -1
#define ISACF_DRQ 11
#define ISACF_DRQ_DEFAULT -1
#define ISACF_DRQ_1 12
#define ISACF_DRQ_1_DEFAULT -1

To use these new multi-valued locators properly the ISA
autoconfiguration code has to be changed.  We can pick
if we want to make multiple `ia_iobase' or if we want
to make it an 4 element array.  Either choice works,
we just need to fill in the values in the right way.



config diffs
============
Index: config.h
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/config.h,v
retrieving revision 1.34
diff -c -r1.34 config.h
*** config.h	1997/10/18 07:59:03	1.34
--- config.h	1998/01/06 22:02:35
***************
*** 76,81 ****
--- 76,83 ----
  #endif
  
  
+ #define ARRCHR '#'
+ 
  /*
   * Name/value lists.  Values can be strings or pointers and/or can carry
   * integers.  The names can be NULL, resulting in simple value lists.
Index: gram.y
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/gram.y,v
retrieving revision 1.19
diff -c -r1.19 gram.y
*** gram.y	1997/10/18 07:59:10	1.19
--- gram.y	1998/01/06 22:02:43
***************
*** 76,81 ****
--- 76,82 ----
  #define	new_s(s)	new0(NULL, s, NULL, 0, NULL)
  #define	new_p(p)	new0(NULL, NULL, p, 0, NULL)
  #define	new_px(p, x)	new0(NULL, NULL, p, 0, x)
+ #define	new_sx(s, x)	new0(NULL, s, NULL, 0, x)
  
  #define	fx_atom(s)	new0(s, NULL, NULL, FX_ATOM, NULL)
  #define	fx_not(e)	new0(NULL, NULL, NULL, FX_NOT, e)
***************
*** 86,91 ****
--- 87,97 ----
  static	void	setmachine __P((const char *, const char *));
  static	void	check_maxpart __P((void));
  
+ static	void	app __P((struct nvlist *, struct nvlist *));
+ 
+ static	struct nvlist *mk_nsis __P((const char *, int, struct nvlist *, int));
+ static	struct nvlist *mk_ns __P((const char *, struct nvlist *));
+ 
  %}
  
  %union {
***************
*** 119,124 ****
--- 125,131 ----
  %type	<str>	atname
  %type	<list>	loclist_opt loclist locdef
  %type	<str>	locdefault
+ %type	<list>	values locdefaults
  %type	<list>	attrs_opt attrs
  %type	<list>	locators locator
  %type	<list>	dev_spec
***************
*** 265,282 ****
  
  /* loclist order matters, must use right recursion */
  loclist:
! 	locdef ',' loclist		{ ($$ = $1)->nv_next = $3; } |
  	locdef				{ $$ = $1; };
  
  /* "[ WORD locdefault ]" syntax may be unnecessary... */
  locdef:
  	WORD locdefault 		{ $$ = new_nsi($1, $2, 0); } |
  	WORD				{ $$ = new_nsi($1, NULL, 0); } |
! 	'[' WORD locdefault ']'		{ $$ = new_nsi($2, $3, 1); };
  
  locdefault:
  	'=' value			{ $$ = $2; };
  
  value:
  	WORD				{ $$ = $1; } |
  	EMPTY				{ $$ = $1; } |
--- 272,296 ----
  
  /* loclist order matters, must use right recursion */
  loclist:
! 	locdef ',' loclist		{ $$ = $1; app($1, $3); } |
  	locdef				{ $$ = $1; };
  
  /* "[ WORD locdefault ]" syntax may be unnecessary... */
  locdef:
  	WORD locdefault 		{ $$ = new_nsi($1, $2, 0); } |
  	WORD				{ $$ = new_nsi($1, NULL, 0); } |
! 	'[' WORD locdefault ']'		{ $$ = new_nsi($2, $3, 1); } |
! 	WORD '[' NUMBER ']' 		{ $$ = mk_nsis($1, $3, NULL, 0); } |
! 	WORD '[' NUMBER ']' locdefaults	{ $$ = mk_nsis($1, $3, $5, 0); } |
! 	'[' WORD '[' NUMBER ']' locdefaults ']'
! 					{ $$ = mk_nsis($2, $4, $6, 1); };
  
  locdefault:
  	'=' value			{ $$ = $2; };
  
+ locdefaults:
+ 	'=' '{' values '}'		{ $$ = $3; };
+ 
  value:
  	WORD				{ $$ = $1; } |
  	EMPTY				{ $$ = $1; } |
***************
*** 284,289 ****
--- 298,307 ----
  					    (void)sprintf(bf, FORMAT($1), $1);
  					    $$ = intern(bf); };
  
+ values:
+ 	value ',' values		{ $$ = new_sx($1, $3); } |
+ 	value				{ $$ = new_s($1); };
+ 
  signed_number:
  	NUMBER				{ $$ = $1; } |
  	'-' NUMBER			{ $$ = -$2; };
***************
*** 406,416 ****
  	WORD				{ $$ = $1; };
  
  locators:
! 	locators locator		{ ($$ = $2)->nv_next = $1; } |
  	/* empty */			{ $$ = NULL; };
  
  locator:
! 	WORD value			{ $$ = new_ns($1, $2); } |
  	WORD '?'			{ $$ = new_ns($1, NULL); };
  
  flags_opt:
--- 424,434 ----
  	WORD				{ $$ = $1; };
  
  locators:
! 	locators locator		{ $$ = $2; app($2, $1); } |
  	/* empty */			{ $$ = NULL; };
  
  locator:
! 	WORD values			{ $$ = mk_ns($1, $2); } |
  	WORD '?'			{ $$ = new_ns($1, NULL); };
  
  flags_opt:
***************
*** 475,477 ****
--- 493,551 ----
  		stop("cannot proceed without maxpartitions specifier");
  	}
  }
+ 
+ static void
+ app(p, q)
+ 	struct nvlist *p, *q;
+ {
+ 	while (p->nv_next)
+ 		p = p->nv_next;
+ 	p->nv_next = q;
+ }
+ 
+ static struct nvlist *
+ mk_nsis(name, count, adefs, opt)
+ 	const char *name;
+ 	int count;
+ 	struct nvlist *adefs;
+ 	int opt;
+ {
+ 	struct nvlist *defs = adefs;
+ 	struct nvlist **p;
+ 	char buf[200];
+ 	int i;
+ 
+ 	if (count <= 0) {
+ 		fprintf(stderr, "config: array with <= 0 size: %s\n", name);
+ 		exit(1);
+ 	}
+ 	p = &defs;
+ 	for(i = 0; i < count; i++) {
+ 		if (*p == NULL)
+ 			*p = new_s("0");
+ 		sprintf(buf, "%s%c%d", name, ARRCHR, i);
+ 		(*p)->nv_name = i == 0 ? name : intern(buf);
+ 		(*p)->nv_int = i > 0 || opt;
+ 		p = &(*p)->nv_next;
+ 	}
+ 	*p = 0;
+ 	return defs;
+ }
+ 
+ 
+ static struct nvlist *
+ mk_ns(name, vals)
+ 	const char *name;
+ 	struct nvlist *vals;
+ {
+ 	struct nvlist *p;
+ 	char buf[200];
+ 	int i;
+ 
+ 	for(i = 0, p = vals; p; i++, p = p->nv_next) {
+ 		sprintf(buf, "%s%c%d", name, ARRCHR, i);
+ 		p->nv_name = i == 0 ? name : intern(buf);
+ 	}
+ 	return vals;
+ }
+ 
Index: mkheaders.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/mkheaders.c,v
retrieving revision 1.16
diff -c -r1.16 mkheaders.c
*** mkheaders.c	1997/10/18 07:59:21	1.16
--- mkheaders.c	1998/01/06 22:02:43
***************
*** 241,246 ****
--- 241,248 ----
  			for (cp = namedup; *cp; cp++)
  				if (islower(*cp))
  					*cp = toupper(*cp);
+ 				else if (*cp == ARRCHR)
+ 					*cp = '_';
  			if (fprintf(fp, "#define %sCF_%s %d\n",
  				    locdup, namedup, i) < 0)
  				return 1;
Index: mkioconf.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/config/mkioconf.c,v
retrieving revision 1.44
diff -c -r1.44 mkioconf.c
*** mkioconf.c	1997/10/18 07:59:25	1.44
--- mkioconf.c	1998/01/06 22:02:45
***************
*** 66,71 ****
--- 66,73 ----
  
  #define	SEP(pos, max)	(((u_int)(pos) % (max)) == 0 ? "\n\t" : " ")
  
+ #define ARRNAME(n, l) (strchr((n), ARRCHR) && strncmp((n), (l), strlen((l))) == 0)
+ 
  /*
   * NEWLINE can only be used in the emitXXX functions.
   * In most cases it can be subsumed into an fprintf.
***************
*** 191,200 ****
  	if (a->a_locs) {
  		if (fprintf(fp, "const char *%scf_locnames[] = { ", name) < 0)
  			return (1);
! 		for (nv = a->a_locs; nv; nv = nv->nv_next) {
  			if (fprintf(fp, "\"%s\", ", nv->nv_name) < 0)
  				return (1);
- 		}
  		if (fprintf(fp, "NULL};\n") < 0)
  			return (1);
  	}
--- 193,201 ----
  	if (a->a_locs) {
  		if (fprintf(fp, "const char *%scf_locnames[] = { ", name) < 0)
  			return (1);
! 		for (nv = a->a_locs; nv; nv = nv->nv_next)
  			if (fprintf(fp, "\"%s\", ", nv->nv_name) < 0)
  				return (1);
  		if (fprintf(fp, "NULL};\n") < 0)
  			return (1);
  	}
***************
*** 251,256 ****
--- 252,258 ----
  	struct attr *a;
  	char *loc;
  	char locbuf[20];
+ 	const char *lastname = "";
  
  	if (fprintf(fp, "\n\
  #define NORM FSTATE_NOTFOUND\n\
***************
*** 273,282 ****
  			return (1);
  		a = i->i_atattr;
  		nv = a->a_locs;
! 		for (nv = a->a_locs, v = 0; nv != NULL; nv = nv->nv_next, v++)
! 			if (fprintf(fp, " %s %s",
! 			    nv->nv_name, i->i_locs[v]) < 0)
! 				return (1);
  		if (fputs(" */\n", fp) < 0)
  			return (-1);
  
--- 275,291 ----
  			return (1);
  		a = i->i_atattr;
  		nv = a->a_locs;
! 		for (nv = a->a_locs, v = 0; nv != NULL; nv = nv->nv_next, v++) {
! 			if (ARRNAME(nv->nv_name, lastname)) {
! 				if (fprintf(fp, ",%s", i->i_locs[v]) < 0)
! 					return (1);
! 			} else {
! 				if (fprintf(fp, " %s %s",
! 					    nv->nv_name, i->i_locs[v]) < 0)
! 					return (1);
! 				lastname = nv->nv_name;
! 			}
! 		}
  		if (fputs(" */\n", fp) < 0)
  			return (-1);