~kris/9p

9hist

d40538d962c3d5081ee9ca8c8f939e2a54c2f828 — David du Colombier 24 years ago 7015d11
Plan 9 from Bell Labs 2001-11-20
M alphapc/screen.h => alphapc/screen.h +1 -1
@@ 122,7 122,7 @@ enum {
};

/* mouse.c */
extern void mousectl(char*[], int);
extern void mousectl(Cmdbuf*);

/* screen.c */
extern int		hwaccel;	/* use hw acceleration; default on */

M ip/arp.c => ip/arp.c +55 -38
@@ 27,6 27,12 @@ char *arpstate[] =
	"WAIT",
};

enum
{
	CMadd,
	CMflush,
};

/*
 *  one per Fs
 */


@@ 38,6 44,13 @@ struct Arp
	Arpent	cache[NCACHE];
};

static
Cmdtab arpcmd[] =
{
	CMadd,	"add",	0,
	CMflush,	"flush",	1,
};

char *Ebadarp = "bad arp";

#define haship(s) ((s)[IPaddrlen-1]%NHASH)


@@ 256,56 269,40 @@ arpwrite(Fs *fs, char *s, int len)
	Arp *arp;
	Block *bp;
	Arpent *a;
	Cmdbuf *cb;
	Cmdtab *ct;
	Medium *m;
	char *f[4], buf[256];
	uchar ip[IPaddrlen], mac[MAClen];

	arp = fs->arp;

	if(len == 0)
		error(Ebadarp);
	if(len >= sizeof(buf))
		len = sizeof(buf)-1;
	strncpy(buf, s, len);
	buf[len] = 0;
	if(len > 0 && buf[len-1] == '\n')
		buf[len-1] = 0;

	n = tokenize(buf, f, 4);
	if(strcmp(f[0], "flush") == 0){
		qlock(arp);
		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
			memset(a->ip, 0, sizeof(a->ip));
			memset(a->mac, 0, sizeof(a->mac));
			a->hash = nil;
			a->state = 0;
			a->used = 0;
			while(a->hold != nil) {
				bp = a->hold->list;
				freeblist(a->hold);
				a->hold = bp;
			}
		}
		memset(arp->hash, 0, sizeof(arp->hash));
		qunlock(arp);
	} else if(strcmp(f[0], "add") == 0) {
		switch(n) {
	cb = parsecmd(s, len);
	if(waserror()){
		free(cb);
		nexterror();
	}

	ct = lookupcmd(cb, arpcmd, nelem(arpcmd));

	switch(ct->index){
	case CMadd:
		switch(cb->nf) {
		default:
			error(Ebadarg);
			cmderror(cb, Ecmdargs);
		case 3:
			parseip(ip, f[1]);
			parseip(ip, cb->f[1]);
			r = v4lookup(fs, ip+IPv4off);
			if(r == nil)
				error("Destination unreachable");
				error("destination unreachable");
			m = r->ifc->m;
			n = parsemac(mac, f[2], m->maclen);
			n = parsemac(mac, cb->f[2], m->maclen);
			break;
		case 4:
			m = ipfindmedium(f[1]);
			m = ipfindmedium(cb->f[1]);
			if(m == nil)
				error(Ebadarp);
			parseip(ip, f[2]);
			n = parsemac(mac, f[3], m->maclen);
			parseip(ip, cb->f[2]);
			n = parsemac(mac, cb->f[3], m->maclen);
			break;
		}



@@ 313,9 310,29 @@ arpwrite(Fs *fs, char *s, int len)
			error(Ebadarp);

		m->ares(fs, V6, ip, mac, n, 0);
	} else
		error(Ebadarp);
		break;

	case CMflush:
		qlock(arp);
		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
			memset(a->ip, 0, sizeof(a->ip));
			memset(a->mac, 0, sizeof(a->mac));
			a->hash = nil;
			a->state = 0;
			a->used = 0;
			while(a->hold != nil) {
				bp = a->hold->list;
				freeblist(a->hold);
				a->hold = bp;
			}
		}
		memset(arp->hash, 0, sizeof(arp->hash));
		qunlock(arp);
		break;
	}

	poperror();
	free(cb);
	return len;
}


M ip/devip.c => ip/devip.c +50 -15
@@ 54,6 54,30 @@ QLock	fslock;
Fs	*ipfs[Nfs];	/* attached fs's */
Queue	*qlog;

enum
{
	CMaddmulti,
	CMannounce,
	CMbind,
	CMconnect,
	CMremmulti,
	CMtos,
	CMttl,
	CMwildcard,
};

Cmdtab ipctlmsg[] =
{
	CMaddmulti,	"addmulti",	0,
	CMannounce,	"announce",	0,
	CMbind,		"bind",		0,
	CMconnect,	"connect",	0,
	CMremmulti,	"remmulti",	0,
	CMtos,		"tos",		0,
	CMttl,		"ttl",			0,
	CMwildcard,	"*",			0,
};

extern	void nullmediumlink(void);
extern	void pktmediumlink(void);
	long ndbwrite(Fs *f, char *a, ulong off, int n);


@@ 1023,6 1047,7 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
	Proto *x;
	char *p;
	Cmdbuf *cb;
	Cmdtab *ct;
	uchar ia[IPaddrlen], ma[IPaddrlen];
	Fs *f;
	char *a;


@@ 1049,9 1074,7 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
	case Qiproute:
		return routewrite(f, ch, a, n);
	case Qlog:
		p = netlogctl(f, a, n);
		if(p != nil)
			error(p);
		netlogctl(f, a, n);
		return n;
	case Qndb:
		return ndbwrite(f, a, offset, n);


@@ 1069,19 1092,27 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
		}
		if(cb->nf < 1)
			error("short control request");
		if(strcmp(cb->f[0], "connect") == 0)

		ct = lookupcmd(cb, ipctlmsg, nelem(ipctlmsg));
		switch(ct->index){
		case CMconnect:
			connectctlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "announce") == 0)
			break;
		case CMannounce:
			announcectlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "bind") == 0)
			break;
		case CMbind:
			bindctlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "ttl") == 0)
			break;
		case CMttl:
			ttlctlmsg(c, cb);
		else if(strcmp(cb->f[0], "tos") == 0)
			break;
		case CMtos:
			tosctlmsg(c, cb);
		else if(strcmp(cb->f[0], "addmulti") == 0){
			if(cb->nf < 2)
				error("addmulti needs interface address");
			break;
		case CMaddmulti:
			if(cb->nf != 2 && cb->nf != 3)
				cmderror(cb, Ecmdargs);
			if(cb->nf == 2){
				if(!ipismulticast(c->raddr))
					error("addmulti for a non multicast address");


@@ 1094,19 1125,23 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
				parseip(ia, cb->f[1]);
				ipifcaddmulti(c, ma, ia);
			}
		} else if(strcmp(cb->f[0], "remmulti") == 0){
			break;
		case CMremmulti:
			if(cb->nf < 2)
				error("remmulti needs interface address");
			if(!ipismulticast(c->raddr))
				error("remmulti for a non multicast address");
			parseip(ia, cb->f[1]);
			ipifcremmulti(c, c->raddr, ia);
		} else if(x->ctl != nil) {
			break;
		case CMwildcard:
			if(x->ctl == nil)
				cmderror(cb, "unknown control request");
			p = x->ctl(c, cb->f, cb->nf);
			if(p != nil)
				error(p);
		} else
			error("unknown control request");
		}

		qunlock(c);
		free(cb);
		poperror();

M ip/ip.h => ip/ip.h +1 -1
@@ 336,7 336,7 @@ enum
void	netloginit(Fs*);
void	netlogopen(Fs*);
void	netlogclose(Fs*);
char*	netlogctl(Fs*, char*, int);
void	netlogctl(Fs*, char*, int);
long	netlogread(Fs*, void*, ulong, long);
void	netlog(Fs*, int, char*, ...);
void	ifcloginit(Fs*);

M ip/iproute.c => ip/iproute.c +41 -22
@@ 16,6 16,22 @@ Route*	v4freelist;
Route*	v6freelist;
RWlock	routelock;

enum
{
	RWadd,
	RWflush,
	RWremove,
	RWtag,
};

static
Cmdtab routecmd[] = {
	RWadd,		"add",		4,
	RWflush,	"flush",	2,
	RWremove,	"remove",	3,
	RWtag,		"tag",		2,
};

static void
freeroute(Route *r)
{


@@ 763,6 779,7 @@ routewrite(Fs *f, Chan *c, char *p, int n)
	int h, changed;
	char *tag;
	Cmdbuf *cb;
	Cmdtab *ct;
	uchar addr[IPaddrlen];
	uchar mask[IPaddrlen];
	uchar gate[IPaddrlen];


@@ 774,7 791,25 @@ routewrite(Fs *f, Chan *c, char *p, int n)
		nexterror();
	}

	if(strcmp(cb->f[0], "flush") == 0){
	ct = lookupcmd(cb, routecmd, nelem(routecmd));

	switch(ct->index){
	case RWadd:
		parseip(addr, cb->f[1]);
		parseipmask(mask, cb->f[2]);
		parseip(gate, cb->f[3]);
		tag = "none";
		if(c != nil){
			a = c->aux;
			tag = a->tag;
		}
		if(memcmp(addr, v4prefix, IPv4off) == 0)
			v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
		else
			v6addroute(f, tag, addr, mask, gate, 0);
		break;

	case RWflush:
		tag = cb->f[1];
		for(h = 0; h < nelem(f->v4root); h++)
			for(changed = 1; changed;){


@@ 788,34 823,18 @@ routewrite(Fs *f, Chan *c, char *p, int n)
				changed = routeflush(f, f->v6root[h], tag);
				wunlock(&routelock);
			}
	} else if(strcmp(cb->f[0], "remove") == 0){
		if(cb->nf < 3)
			error(Ebadarg);
		break;

	case RWremove:
		parseip(addr, cb->f[1]);
		parseipmask(mask, cb->f[2]);
		if(memcmp(addr, v4prefix, IPv4off) == 0)
			v4delroute(f, addr+IPv4off, mask+IPv4off, 1);
		else
			v6delroute(f, addr, mask, 1);
	} else if(strcmp(cb->f[0], "add") == 0){
		if(cb->nf < 4)
			error(Ebadarg);
		parseip(addr, cb->f[1]);
		parseipmask(mask, cb->f[2]);
		parseip(gate, cb->f[3]);
		tag = "none";
		if(c != nil){
			a = c->aux;
			tag = a->tag;
		}
		if(memcmp(addr, v4prefix, IPv4off) == 0)
			v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
		else
			v6addroute(f, tag, addr, mask, gate, 0);
	} else if(strcmp(cb->f[0], "tag") == 0) {
		if(cb->nf < 2)
			error(Ebadarg);
		break;

	case RWtag:
		a = c->aux;
		na = newipaux(a->owner, cb->f[1]);
		c->aux = na;

M ip/netlog.c => ip/netlog.c +47 -28
@@ 53,7 53,21 @@ static Netlogflag flags[] =
	{ nil,		0, },
};

static char Ebadnetctl[] = "unknown netlog ctl message";
char Ebadnetctl[] = "too few arguments for netlog control message";

enum
{
	CMset,
	CMclear,
	CMonly,
};

static
Cmdtab routecmd[] = {
	CMset,		"set",		0,
	CMclear,	"clear",	0,
	CMonly,		"only",		0,
};

void
netloginit(Fs *f)


@@ 150,48 164,52 @@ netlogread(Fs *f, void *a, ulong, long n)
	return n;
}

char*
netlogctl(Fs *f, char* s, int len)
void
netlogctl(Fs *f, char* s, int n)
{
	int i, n, set;
	int i, set;
	Netlogflag *fp;
	char *fields[10], *p, buf[256];
	Cmdbuf *cb;
	Cmdtab *ct;

	if(len == 0)
		return Ebadnetctl;
	cb = parsecmd(s, n);
	if(waserror()){
		free(cb);
		nexterror();
	}

	if(cb->nf < 2)
		error(Ebadnetctl);

	if(len >= sizeof(buf))
		len = sizeof(buf)-1;
	strncpy(buf, s, len);
	buf[len] = 0;
	if(len > 0 && buf[len-1] == '\n')
		buf[len-1] = 0;
	ct = lookupcmd(cb, routecmd, nelem(routecmd));

	n = tokenize(buf, fields, 10);
	if(n < 2)
		return Ebadnetctl;
	SET(set);

	if(strcmp("set", fields[0]) == 0)
	switch(ct->index){
	case CMset:
		set = 1;
	else if(strcmp("clear", fields[0]) == 0)
		break;

	case CMclear:
		set = 0;
	else if(strcmp("only", fields[0]) == 0){
		parseip(f->alog->iponly, fields[1]);
		break;

	case CMonly:
		parseip(f->alog->iponly, cb->f[1]);
		if(ipcmp(f->alog->iponly, IPnoaddr) == 0)
			f->alog->iponlyset = 0;
		else
			f->alog->iponlyset = 1;
		return nil;
	} else
		return Ebadnetctl;
		free(cb);
		return;

	p = strchr(fields[n-1], '\n');
	if(p)
		*p = 0;
	default:
		cmderror(cb, "unknown ip control message");
	}

	for(i = 1; i < n; i++){
		for(fp = flags; fp->name; fp++)
			if(strcmp(fp->name, fields[i]) == 0)
			if(strcmp(fp->name, cb->f[i]) == 0)
				break;
		if(fp->name == nil)
			continue;


@@ 201,7 219,8 @@ netlogctl(Fs *f, char* s, int len)
			f->alog->logmask &= ~fp->mask;
	}

	return nil;
	free(cb);
	poperror();
}

void

M pc/devfloppy.c => pc/devfloppy.c +45 -19
@@ 92,7 92,7 @@ FController	fl;
 *  predeclared
 */
static int	cmddone(void*);
static void	floppyformat(FDrive*, char*);
static void	floppyformat(FDrive*, Cmdbuf*);
static void	floppykproc(void*);
static void	floppypos(FDrive*,long);
static int	floppyrecal(FDrive*);


@@ 116,6 116,22 @@ Dirtab floppydir[]={
};
#define NFDIR	2	/* directory entries/drive */

enum
{
	CMdebug,
	CMeject,
	CMformat,
	CMreset,
};

static Cmdtab floppyctlmsg[] =
{
	CMdebug,	"debug",	1,
	CMeject,	"eject",	1,
	CMformat,	"format",	0,
	CMreset,	"reset",	1,
};

static void
fldump(void)
{


@@ 396,14 412,14 @@ floppyread(Chan *c, void *a, long n, vlong off)
	return rv;
}

#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
static long
floppywrite(Chan *c, void *a, long n, vlong off)
{
	FDrive *dp;
	long rv, i;
	char *aa = a;
	char ctlmsg[64];
	Cmdbuf *cb;
	Cmdtab *ct;
	ulong offset = off;

	rv = 0;


@@ 433,28 449,36 @@ floppywrite(Chan *c, void *a, long n, vlong off)
		break;
	case Qctl:
		rv = n;
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}
		qlock(&fl);
		if(waserror()){
			qunlock(&fl);
			nexterror();
		}
		if(n >= sizeof(ctlmsg))
			n = sizeof(ctlmsg) - 1;
		memmove(ctlmsg, aa, n);
		ctlmsg[n] = 0;
		if(SNCMP(ctlmsg, "eject") == 0){
		ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg));
		switch(ct->index){
		case CMeject:
			floppyeject(dp);
		} else if(SNCMP(ctlmsg, "reset") == 0){
			break;
		case CMformat:
			floppyformat(dp, cb);
			break;
		case CMreset:
			fl.confused = 1;
			floppyon(dp);
		} else if(SNCMP(ctlmsg, "format") == 0){
			floppyformat(dp, ctlmsg);
		} else if(SNCMP(ctlmsg, "debug") == 0){
			break;
		case CMdebug:
			floppydebug = 1;
		} else
			error(Ebadctl);
			break;
		}
		poperror();
		qunlock(&fl);
		poperror();
		free(cb);
		break;
	default:
		panic("floppywrite: bad qid");


@@ 893,20 917,19 @@ floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
 *  format a track
 */
static void
floppyformat(FDrive *dp, char *params)
floppyformat(FDrive *dp, Cmdbuf *cb)
{
 	int cyl, h, sec;
	ulong track;
	uchar *buf, *bp;
	FType *t;
	char *f[3];

	/*
	 *  set the type
	 */
	if(tokenize(params, f, 3) > 1){
	if(cb->nf == 2){
		for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
			if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
			if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){
				dp->t = t;
				floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
				break;


@@ 914,9 937,12 @@ floppyformat(FDrive *dp, char *params)
		}
		if(t >= &floppytype[nelem(floppytype)])
			error(Ebadarg);
	} else {
	} else if(cb->nf == 1){
		floppysetdef(dp);
		t = dp->t;
	} else {
		cmderror(cb, "invalid floppy format command");
		SET(t);
	}

	/*

M pc/devpccard.c => pc/devpccard.c +36 -24
@@ 241,6 241,18 @@ static ulong mantissa[16] = {

static char Enocard[] = "No card in slot";

enum
{
	CMdown,
	CMpower,
};

static Cmdtab pccardctlmsg[] =
{
	CMdown,		"down",	2,
	CMpower,	"power",	1,
};

static void cbint(Ureg *, void *);
static int powerup(Cardbus *);
static void configure(Cardbus *);


@@ 1314,37 1326,37 @@ pccardwrite(Chan *c, void *v, long n, vlong)
{
	Rune r;
	ulong n0;
	int i, nf;
	char buf[255], *field[Ncmd], *device;
	char *device;
	Cmdbuf *cbf;
	Cmdtab *ct;
	Cardbus *cb;

	n0 = n;
	switch(TYPE(c)){
	case Qctl:
		cb = &cbslots[SLOTNO(c)];
		if(n > sizeof(buf)-1) n = sizeof(buf)-1;
		memmove(buf, v, n);
		buf[n] = '\0';

		nf = tokenize(buf, field, Ncmd);
		for (i = 0; i != nf; i++) {
			if (!strcmp(field[i], "down")) {

				if (i + 1 < nf && *field[i + 1] == '#') {
					device = field[++i];
					device += chartorune(&r, device);
					if ((n = devno(r, 1)) >= 0 && devtab[n]->config)
						devtab[n]->config(0, device, nil);
				}
				qengine(cb, CardEjected);
			}
			else if (!strcmp(field[i], "power")) {
				if ((cb->cb_regs[SocketState] & SS_CCD) == 0)
					qengine(cb, CardDetected);
			}
			else
				error(Ebadarg);

		cbf = parsecmd(v, n);
		if(waserror()){
			free(cbf);
			nexterror();
		}
		ct = lookupcmd(cbf, pccardctlmsg, nelem(pccardctlmsg));
		switch(ct->index){
		case CMdown:
			device = cbf->f[1];
			device += chartorune(&r, device);
			if ((n = devno(r, 1)) >= 0 && devtab[n]->config)
				devtab[n]->config(0, device, nil);
			qengine(cb, CardEjected);
			break;
		case CMpower:
			if ((cb->cb_regs[SocketState] & SS_CCD) == 0)
				qengine(cb, CardDetected);
			break;
		}
		poperror();
		free(cbf);
		break;
	}
	return n0 - n;

M pc/devusb.c => pc/devusb.c +114 -61
@@ 279,6 279,7 @@ struct Ctlr {

static	Ctlr	ubus;
static	char	Estalled[] = "usb endpoint stalled";
static	char	Ebadusbmsg[] = "invalid parameters to USB ctl message";

static	QLock	usbstate;	/* protects name space state */
static	Udev*	usbdev[32];


@@ 287,6 288,42 @@ static struct {
	Endpt*	f;
} activends;

enum
{
	BCMdisable,
	BCMenable,
	BCMreset,
};

enum
{
	CMclass,
	CMdata,
	CMdebug,
	CMep,
	CMmaxpkt,
	CMspeed,
	CMunstall,
};

static Cmdtab usbbusctlmsg[] =
{
	BCMdisable,	"disable",	2,
	BCMenable,	"enable",	2,
	BCMreset,	"reset",	2,
};

static Cmdtab usbctlmsg[] =
{
	CMclass,	"class",	4,
	CMdata,		"data",		3,
	CMdebug,	"debug",	3,
	CMep,		"ep",		6,
	CMmaxpkt,	"maxpkt",	3,
	CMspeed,	"speed",	2,
	CMunstall,	"unstall",	2,
};

static long readusb(Endpt*, void*, long);
static long writeusb(Endpt*, void*, long, int);



@@ 2003,93 2040,109 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
{
	Udev *d;
	Endpt *e;
	int id, nw, nf, t, i;
	Cmdbuf *cb;
	Cmdtab *ct;
	int id, nw, t, i;
	char cmd[50], *fields[10];

	if(c->qid.type == QTDIR)
		error(Egreg);
	t = QID(c->qid);
	if(t == Qbusctl){
		if(n >= sizeof(cmd)-1)
			n = sizeof(cmd)-1;
		memmove(cmd, a, n);
		cmd[n] = 0;
		nf = tokenize(cmd, fields, nelem(fields));
		if(nf < 2)
			error(Ebadarg);
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}

		ct = lookupcmd(cb, usbbusctlmsg, nelem(usbbusctlmsg));
		id = strtol(fields[1], nil, 0);
		if(id != 1 && id != 2)
			error(Ebadarg);	/* there are two ports on the root hub */
		if(strcmp(fields[0], "reset") == 0)
			portreset(id);
		else if(strcmp(fields[0], "enable") == 0)
			portenable(id, 1);
		else if(strcmp(fields[0], "disable") == 0)
			cmderror(cb, "usb port number not 1 or 2 in");
		switch(ct->index){
		case BCMdisable:
			portenable(id, 0);
		else
			error(Ebadarg);
			break;
		case BCMenable:
			portenable(id, 1);
			break;
		case BCMreset:
			portreset(id);
			break;
		}
	
		poperror();
		free(cb);
		return n;
	}
	d = usbdevice(c);
	t = QID(c->qid);
	switch(t){
	case Qctl:
		if(n >= sizeof(cmd)-1)
			n = sizeof(cmd)-1;
		memmove(cmd, a, n);
		cmd[n] = 0;
		nf = tokenize(cmd, fields, nelem(fields));
		if(nf > 1 && strcmp(fields[0], "speed") == 0){
			d->ls = strtoul(fields[1], nil, 0) == 0;
		} else if(nf > 3 && strcmp(fields[0], "class") == 0){
			i = strtoul(fields[2], nil, 0);
			d->npt = strtoul(fields[1], nil, 0);
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}

		ct = lookupcmd(cb, usbctlmsg, nelem(usbctlmsg));
		switch(ct->index){
		case CMspeed:
			d->ls = strtoul(cb->f[1], nil, 0) == 0;
			break;
		case CMclass:
			i = strtoul(cb->f[2], nil, 0);
			d->npt = strtoul(cb->f[1], nil, 0);
			/* class config# csp ( == class subclass proto) */
			if (i < 0 || i >= nelem(d->ep)
			 || d->npt > nelem(d->ep) || i >= d->npt)
				error(Ebadarg);
			if (i == 0) {
				d->csp = strtoul(fields[3], nil, 0);
			}
				cmderror(cb, Ebadusbmsg);
			if (i == 0)
				d->csp = strtoul(cb->f[3], nil, 0);
			if(d->ep[i] == nil)
				d->ep[i] = devendpt(d, i, 1);
			d->ep[i]->csp = strtoul(fields[3], nil, 0);
		}else if(nf > 2 && strcmp(fields[0], "data") == 0){
			i = strtoul(fields[1], nil, 0);
			d->ep[i]->csp = strtoul(cb->f[3], nil, 0);
			break;
		case CMdata:
			i = strtoul(cb->f[1], nil, 0);
			if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
				error(Ebadarg);
				error(Ebadusbmsg);
			e = d->ep[i];
			e->data01 = strtoul(fields[2], nil, 0) != 0;
		}else if(nf > 2 && strcmp(fields[0], "maxpkt") == 0){
			i = strtoul(fields[1], nil, 0);
			e->data01 = strtoul(cb->f[2], nil, 0) != 0;
			break;
		case CMmaxpkt:
			i = strtoul(cb->f[1], nil, 0);
			if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
				error(Ebadarg);
				error(Ebadusbmsg);
			e = d->ep[i];
			e->maxpkt = strtoul(fields[2], nil, 0);
			e->maxpkt = strtoul(cb->f[2], nil, 0);
			if(e->maxpkt > 1500)
				e->maxpkt = 1500;
		}else if(nf > 2 && strcmp(fields[0], "debug") == 0){
			i = strtoul(fields[1], nil, 0);
			break;
		case CMdebug:
			i = strtoul(cb->f[1], nil, 0);
			if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil)
				error(Ebadarg);
				error(Ebadusbmsg);
			if (i == -1)
				debug = 0;
			else {
				debug = 1;
				e = d->ep[i];
				e->debug = strtoul(fields[2], nil, 0);
				e->debug = strtoul(cb->f[2], nil, 0);
			}
		}else if(nf > 1 && strcmp(fields[0], "unstall") == 0){
			i = strtoul(fields[1], nil, 0);
			break;
		case CMunstall:
			i = strtoul(cb->f[1], nil, 0);
			if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
				error(Ebadarg);
				error(Ebadusbmsg);
			e = d->ep[i];
			e->err = nil;
		}else if(nf == 6 && strcmp(fields[0], "ep") == 0){
			break;
		case CMep:
			/* ep n `bulk' mode maxpkt nbuf     OR
			 * ep n period mode samplesize KHz
			 */
			i = strtoul(fields[1], nil, 0);
			i = strtoul(cb->f[1], nil, 0);
			if(i < 0 || i >= nelem(d->ep)) {
				XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep));
				error(Ebadarg);


@@ 2104,7 2157,7 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
			}
			if (e->active)
				error(Eperm);
			if(strcmp(fields[2], "bulk") == 0){
			if(strcmp(cb->f[2], "bulk") == 0){
				Ctlr *ub;

				e->iso = 0;


@@ 2119,34 2172,34 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
						panic("usbwrite: allocqh");
				}
				queueqh(e->epq);
				e->mode = strcmp(fields[3],"r") == 0? OREAD :
					  	strcmp(fields[3],"w") == 0? OWRITE : ORDWR;
				i = strtoul(fields[4], nil, 0);
				e->mode = strcmp(cb->f[3],"r") == 0? OREAD :
					  	strcmp(cb->f[3],"w") == 0? OWRITE : ORDWR;
				i = strtoul(cb->f[4], nil, 0);
				if(i < 8 || i > 1023)
					i = 8;
				e->maxpkt = i;
				i = strtoul(fields[5], nil, 0);
				i = strtoul(cb->f[5], nil, 0);
				if(i >= 1 && i <= 32)
					e->nbuf = i;
			} else {
				/* ep n period mode samplesize KHz */
				i = strtoul(fields[2], nil, 0);
				i = strtoul(cb->f[2], nil, 0);
				if(i > 0 && i <= 1000){
					e->pollms = i;
				}else {
					XPRINT("field 4: 0 <= %d <= 1000\n", i);
					error(Ebadarg);
				}
				e->mode = strcmp(fields[3],"r") == 0? OREAD :
					  	strcmp(fields[3],"w") == 0? OWRITE : ORDWR;
				i = strtoul(fields[4], nil, 0);
				e->mode = strcmp(cb->f[3],"r") == 0? OREAD :
					  	strcmp(cb->f[3],"w") == 0? OWRITE : ORDWR;
				i = strtoul(cb->f[4], nil, 0);
				if(i >= 1 && i <= 8){
					e->samplesz = i;
				}else {
					XPRINT("field 4: 0 < %d <= 8\n", i);
					error(Ebadarg);
				}
				i = strtoul(fields[5], nil, 0);
				i = strtoul(cb->f[5], nil, 0);
				if(i >= 1 && i <= 100000){
					/* Hz */
					e->hz = i;


@@ 2161,10 2214,10 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
			}
			poperror();
			qunlock(&usbstate);
		}else {
			XPRINT("command %s, fields %d\n", fields[0], nf);
			error(Ebadarg);
		}
	
		poperror();
		free(cb);
		return n;

	case Qsetup:	/* SETUP endpoint 0 */

M pc/devvga.c => pc/devvga.c +90 -87
@@ 28,6 28,36 @@ static Dirtab vgadir[] = {
	"vgaovlctl",	{ Qvgaovlctl, 0 },	0, 	0660,
};

enum {
	CMactualsize,
	CMblank,
	CMblanktime,
	CMdrawinit,
	CMhwaccel,
	CMhwblank,
	CMhwgc,
	CMlinear,
	CMpalettedepth,
	CMpanning,
	CMsize,
	CMtype,
};

static Cmdtab vgactlmsg[] = {
	CMactualsize,	"actualsize",	2,
	CMblank,	"blank",	1,
	CMblanktime,	"blanktime",	2,
	CMdrawinit,	"drawinit",	1,
	CMhwaccel,	"hwaccel",	2,
	CMhwblank,	"hwblank",	2,
	CMhwgc,		"hwgc",		2,
	CMlinear,	"linear",	0,
	CMpalettedepth,	"palettedepth",	2,
	CMpanning,	"panning",	2,
	CMsize,		"size",		3,
	CMtype,		"type",		2,
};

static void
vgareset(void)
{


@@ 175,25 205,21 @@ vgaread(Chan* c, void* a, long n, vlong off)
static char Ebusy[] = "vga already configured";

static void
vgactl(char* a)
vgactl(Cmdbuf *cb)
{
	int align, i, n, size, x, y, z;
	char *chanstr, *field[6], *p;
	int align, i, size, x, y, z;
	char *chanstr, *p;
	ulong chan;
	Cmdtab *ct;
	VGAscr *scr;
	extern VGAdev *vgadev[];
	extern VGAcur *vgacur[];

	n = tokenize(a, field, nelem(field));
	if(n < 1)
		error(Ebadarg);

	scr = &vgascreen[0];
	if(strcmp(field[0], "hwgc") == 0){
		if(n < 2)
			error(Ebadarg);

		if(strcmp(field[1], "off") == 0){
	ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg));
	switch(ct->index){
	case CMhwgc:
		if(strcmp(cb->f[1], "off") == 0){
			lock(&cursor);
			if(scr->cur){
				if(scr->cur->disable)


@@ 205,7 231,7 @@ vgactl(char* a)
		}

		for(i = 0; vgacur[i]; i++){
			if(strcmp(field[1], vgacur[i]->name))
			if(strcmp(cb->f[1], vgacur[i]->name))
				continue;
			lock(&cursor);
			if(scr->cur && scr->cur->disable)


@@ 216,13 242,11 @@ vgactl(char* a)
			unlock(&cursor);
			return;
		}
	}
	else if(strcmp(field[0], "type") == 0){
		if(n < 2)
			error(Ebadarg);
		break;

	case CMtype:
		for(i = 0; vgadev[i]; i++){
			if(strcmp(field[1], vgadev[i]->name))
			if(strcmp(cb->f[1], vgadev[i]->name))
				continue;
			if(scr->dev && scr->dev->disable)
				scr->dev->disable(scr);


@@ 231,14 255,13 @@ vgactl(char* a)
				scr->dev->enable(scr);
			return;
		}
	}
	else if(strcmp(field[0], "size") == 0){
		if(n < 3)
			error(Ebadarg);
		break;

	case CMsize:
		if(drawhasclients())
			error(Ebusy);

		x = strtoul(field[1], &p, 0);
		x = strtoul(cb->f[1], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)


@@ 252,7 275,7 @@ vgactl(char* a)

		z = strtoul(p, &p, 0);

		chanstr = field[2];
		chanstr = cb->f[2];
		if((chan = strtochan(chanstr)) == 0)
			error("bad channel");



@@ 266,14 289,12 @@ vgactl(char* a)
		vgascreenwin(scr);
		cursoron(1);
		return;
	}
	else if(strcmp(field[0], "actualsize") == 0){

	case CMactualsize:
		if(scr->gscreen == nil)
			error("set the screen size first");

		if(n < 2)
			error(Ebadarg);
		x = strtoul(field[1], &p, 0);
		x = strtoul(cb->f[1], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)


@@ 289,60 310,48 @@ vgactl(char* a)
		physgscreenr = Rect(0,0,x,y);
		scr->gscreen->clipr = physgscreenr;
		return;
	}
	else if(strcmp(field[0], "palettedepth") == 0){
		if(n < 2)
			error(Ebadarg);

		x = strtoul(field[1], &p, 0);
	
	case CMpalettedepth:
		x = strtoul(cb->f[1], &p, 0);
		if(x != 8 && x != 6)
			error(Ebadarg);

		scr->palettedepth = x;
		return;
	}
	else if(strcmp(field[0], "drawinit") == 0){

	case CMdrawinit:
		memimagedraw(scr->gscreen, scr->gscreen->r, memblack, ZP, nil, ZP);
		if(scr && scr->dev && scr->dev->drawinit)
			scr->dev->drawinit(scr);
		return;
	}
	else if(strcmp(field[0], "linear") == 0){
		if(n < 2)
	
	case CMlinear:
		if(cb->nf!=2 && cb->nf!=3)
			error(Ebadarg);

		size = strtoul(field[1], 0, 0);
		if(n < 3)
		size = strtoul(cb->f[1], 0, 0);
		if(cb->nf == 2)
			align = 0;
		else
			align = strtoul(field[2], 0, 0);
			align = strtoul(cb->f[2], 0, 0);
		if(screenaperture(size, align))
			error("not enough free address space");
		return;
	}
/*	else if(strcmp(field[0], "memset") == 0){
		if(n < 4)
			error(Ebadarg);
		memset((void*)strtoul(field[1], 0, 0), atoi(field[2]), atoi(field[3]));
/*	
	case CMmemset:
		memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3]));
		return;
	}
*/
	else if(strcmp(field[0], "blank") == 0){
		if(n < 1)
			error(Ebadarg);

	case CMblank:
		drawblankscreen(1);
		return;
	}
	else if(strcmp(field[0], "blanktime") == 0){
		if(n < 2)
			error(Ebadarg);
		blanktime = strtoul(field[1], 0, 0);
	
	case CMblanktime:
		blanktime = strtoul(cb->f[1], 0, 0);
		return;
	}
	else if(strcmp(field[0], "panning") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "on") == 0){

	case CMpanning:
		if(strcmp(cb->f[1], "on") == 0){
			if(scr == nil || scr->cur == nil)
				error("set screen first");
			if(!scr->cur->doespanning)


@@ 350,37 359,33 @@ vgactl(char* a)
			scr->gscreen->clipr = scr->gscreen->r;
			panning = 1;
		}
		else if(strcmp(field[1], "off") == 0){
		else if(strcmp(cb->f[1], "off") == 0){
			scr->gscreen->clipr = physgscreenr;
			panning = 0;
		}else
			error(Ebadarg);
			break;
		return;
	}
	else if(strcmp(field[0], "hwaccel") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "on") == 0)

	case CMhwaccel:
		if(strcmp(cb->f[1], "on") == 0)
			hwaccel = 1;
		else if(strcmp(field[1], "off") == 0)
		else if(strcmp(cb->f[1], "off") == 0)
			hwaccel = 0;
		else
			error(Ebadarg);
			break;
		return;
	}
	else if(strcmp(field[0], "hwblank") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "on") == 0)
	
	case CMhwblank:
		if(strcmp(cb->f[1], "on") == 0)
			hwblank = 1;
		else if(strcmp(field[1], "off") == 0)
		else if(strcmp(cb->f[1], "off") == 0)
			hwblank = 0;
		else
			error(Ebadarg);
			break;
		return;
	}

	error(Ebadarg);
	cmderror(cb, "bad VGA control message");
}

char Enooverlay[] = "No overlay support";


@@ 388,8 393,8 @@ char Enooverlay[] = "No overlay support";
static long
vgawrite(Chan* c, void* a, long n, vlong off)
{
	char *p;
	ulong offset = off;
	Cmdbuf *cb;
	VGAscr *scr;

	switch((ulong)c->qid.path){


@@ 400,16 405,14 @@ vgawrite(Chan* c, void* a, long n, vlong off)
	case Qvgactl:
		if(offset || n >= READSTR)
			error(Ebadarg);
		p = malloc(READSTR);
		cb = parsecmd(a, n);
		if(waserror()){
			free(p);
			free(cb);
			nexterror();
		}
		memmove(p, a, n);
		p[n] = 0;
		vgactl(p);
		vgactl(cb);
		poperror();
		free(p);
		free(cb);
		return n;

	case Qvgaovl:

M pc/mouse.c => pc/mouse.c +64 -29
@@ 27,6 27,30 @@ static int packetsize;
static int resolution;
static int accelerated;

enum
{
	CMaccelerated,
	CMintellimouse,
	CMlinear,
	CMps2,
	CMps2intellimouse,
	CMres,
	CMreset,
	CMserial,
};

static Cmdtab mousectlmsg[] =
{
	CMaccelerated,		"accelerated",		0,
	CMintellimouse,		"intellimouse",		1,
	CMlinear,		"linear",		1,
	CMps2,			"ps2",			1,
	CMps2intellimouse,	"ps2intellimouse",	1,
	CMres,			"res",			0,
	CMreset,		"reset",		1,
	CMserial,		"serial",		0,
};

/*
 *  setup a serial mouse
 */


@@ 232,35 256,35 @@ resetmouse(void)
}

void
mousectl(char* field[], int n)
mousectl(Cmdbuf *cb)
{
	if(strncmp(field[0], "serial", 6) == 0){
		switch(n){
		case 1:
			serialmouse(atoi(field[0]+6), 0, 1);
			break;
		case 2:
			serialmouse(atoi(field[1]), 0, 0);
			break;
		case 3:
		default:
			serialmouse(atoi(field[1]), field[2], 0);
			break;
		}
	} else if(strcmp(field[0], "ps2") == 0){
	Cmdtab *ct;

	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
	switch(ct->index){
	case CMaccelerated:
		setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
		break;
	case CMintellimouse:
		setintellimouse();
		break;
	case CMlinear:
		setlinear();
		break;
	case CMps2:
		ps2mouse();
	} else if(strcmp(field[0], "ps2intellimouse") == 0){
		break;
	case CMps2intellimouse:
		ps2mouse();
		setintellimouse();
	} else if(strcmp(field[0], "accelerated") == 0){
		setaccelerated(n == 1 ? 1 : atoi(field[1]));
	} else if(strcmp(field[0], "linear") == 0){
		setlinear();
	} else if(strcmp(field[0], "res") == 0){
		if(n >= 2)
			n = atoi(field[1]);
		setres(n);
	} else if(strcmp(field[0], "reset") == 0){
		break;
	case CMres:
		if(cb->nf >= 2)
			setres(atoi(cb->f[1]));
		else
			setres(1);
		break;
	case CMreset:
		resetmouse();
		if(accelerated)
			setaccelerated(accelerated);


@@ 268,9 292,20 @@ mousectl(char* field[], int n)
			setres(resolution);
		if(intellimouse)
			setintellimouse();
	} else if(strcmp(field[0], "intellimouse") == 0){
		setintellimouse();
		break;
	case CMserial:
		switch(cb->nf){
		case 1:
			serialmouse(atoi(cb->f[0]+6), 0, 1);
			break;
		case 2:
			serialmouse(atoi(cb->f[1]), 0, 0);
			break;
		case 3:
		default:
			serialmouse(atoi(cb->f[1]), cb->f[2], 0);
			break;
		}
		break;
	}
	else
		error(Ebadctl);
}

M pc/screen.h => pc/screen.h +1 -1
@@ 122,7 122,7 @@ enum {
};

/* mouse.c */
extern void mousectl(char*[], int);
extern void mousectl(Cmdbuf*);

/* screen.c */
extern int		hwaccel;	/* use hw acceleration; default on */

M pc/vgamach64xx.c => pc/vgamach64xx.c +43 -39
@@ 1007,14 1007,11 @@ mach64xxdrawinit(VGAscr *scr)
}

static void
ovl_configure(VGAscr *scr, Chan *c, int nfields, char **field)
ovl_configure(VGAscr *scr, Chan *c, char **field)
{
	int w, h;
	char *format;

	if (nfields != 4) 
		error(Ebadarg);

	w = (int)strtol(field[1], nil, 0);
	h = (int)strtol(field[2], nil, 0);
	format = field[3];


@@ 1071,14 1068,11 @@ ovl_configure(VGAscr *scr, Chan *c, int nfields, char **field)
}

static void
ovl_enable(VGAscr *scr, Chan *c, int nfields, char **field)
ovl_enable(VGAscr *scr, Chan *c, char **field)
{
	int x, y, w, h;
	long h_inc, v_inc;

	if (nfields != 5) 
		error(Ebadarg);

	x = (int)strtol(field[1], nil, 0);
	y = (int)strtol(field[2], nil, 0);
	w = (int)strtol(field[3], nil, 0);


@@ 1114,11 1108,8 @@ ovl_enable(VGAscr *scr, Chan *c, int nfields, char **field)
}

static void
ovl_status(VGAscr *scr, Chan *, int nfields, char **field)
ovl_status(VGAscr *scr, Chan *, char **field)
{
	if (nfields != 1) 
		error(Ebadarg);

	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %ld\n",
		   scr->dev->name, field[0], mach64type->m64_id,
		   mach64type->m64_vtgt? "yes": "no",


@@ 1132,19 1123,17 @@ ovl_status(VGAscr *scr, Chan *, int nfields, char **field)
}
	
static void
ovl_openctl(VGAscr *, Chan *c, int nfields, char **)
ovl_openctl(VGAscr *, Chan *c, char **)
{
	if (nfields != 1) 
		error(Ebadarg);
	if (ovl_chan) 
		error(Einuse);
	ovl_chan = c;
}

static void
ovl_closectl(VGAscr *scr, Chan *c, int nfields, char **)
ovl_closectl(VGAscr *scr, Chan *c, char **)
{
	if (c != ovl_chan || nfields != 1) return;
	if (c != ovl_chan) return;

	waitforidle(scr);
	scr->mmio[mmoffset[OverlayScaleCntl]] &=


@@ 1153,39 1142,54 @@ ovl_closectl(VGAscr *scr, Chan *c, int nfields, char **)
	ovl_width = ovl_height = ovl_fib = 0;
}

static struct {
	char *ovl_command;
	void	 (*ovl_f)(VGAscr *, Chan *, int, char **);
} ovl_cmds[] = {
	{	"openctl",		ovl_openctl	},
	{	"configure", 	ovl_configure,	},
	{	"enable",		ovl_enable,	},
	{	"closectl",		ovl_closectl	},
	{	"status",		ovl_status		},
enum
{
	CMclosectl,
	CMconfigure,
	CMenable,
	CMopenctl,
	CMstatus,
};

static void (*ovl_cmds[])(VGAscr *, Chan *, char **) =
{
	[CMclosectl]	ovl_closectl,
	[CMconfigure]	ovl_configure,
	[CMenable]	ovl_enable,
	[CMopenctl]	ovl_openctl,
	[CMstatus]	ovl_status,
};

static Cmdtab mach64xxcmd[] =
{
	CMclosectl,	"closectl",	1,
	CMconfigure,	"configure",	4,
	CMenable,	"enable",	5,
	CMopenctl,	"openctl",	1,
	CMstatus,	"status",	1,
};

static void
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int)
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int n)
{
#define MAXARGS	10
	char *field[MAXARGS];
	int nfields, i;
	Cmdbuf *cb;
	Cmdtab *ct;

	if (!mach64type->m64_vtgt) 
		error(Enodev);

	nfields = tokenize(a, field, nelem(field));
	if (nfields < 1) 
		error(Ebadarg);
	cb = parsecmd(a, n);
	if(waserror()){
		free(cb);
		nexterror();
	}

	for (i = 0; i != nelem(ovl_cmds); i++)
		if (!strcmp(field[0], ovl_cmds[i].ovl_command))
			break;
	ct = lookupcmd(cb, mach64xxcmd, nelem(mach64xxcmd));

	if (i == nelem(ovl_cmds))
		error(Ebadarg);
	ovl_cmds[ct->index](scr, c, cb->f);

	ovl_cmds[i].ovl_f(scr, c, nfields, field);
	poperror();
	free(cb);
}

static int

M port/devmouse.c => port/devmouse.c +41 -17
@@ 43,6 43,20 @@ struct Mouseinfo
	uchar	qfull;	/* queue is full */
};

enum
{
	CMbuttonmap,
	CMswap,
	CMwildcard,
};

static Cmdtab mousectlmsg[] =
{
	CMbuttonmap,	"buttonmap",	0,
	CMswap,		"swap",		1,
	CMwildcard,	"*",			0,
};

Mouseinfo	mouse;
Cursorinfo	cursor;
int		mouseshifted;


@@ 307,8 321,10 @@ mousewrite(Chan *c, void *va, long n, vlong)
{
	char *p;
	Point pt;
	char buf[64], *field[3];
	int nf, b, msec;
	Cmdbuf *cb;
	Cmdtab *ct;
	char buf[64];
	int b, msec;

	p = va;
	switch((ulong)c->qid.path){


@@ 336,29 352,37 @@ mousewrite(Chan *c, void *va, long n, vlong)
		return n;

	case Qmousectl:
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, va, n);
		if(buf[n - 1] == '\n')
			buf[n-1] = 0;
		else
			buf[n] = 0;
		nf = tokenize(buf, field, 3);
		if(strcmp(field[0], "swap") == 0){
		cb = parsecmd(va, n);
		if(waserror()){
			free(cb);
			nexterror();
		}

		ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));

		switch(ct->index){
		case CMswap:
			if(mouseswap)
				setbuttonmap("123");
			else
				setbuttonmap("321");
			mouseswap ^= 1;
		}
		else if(strcmp(field[0], "buttonmap") == 0){
			if(nf == 1)
			break;

		case CMbuttonmap:
			if(cb->nf == 1)
				setbuttonmap("123");
			else
				setbuttonmap(field[1]);
				setbuttonmap(cb->f[1]);
			break;

		case CMwildcard:
			mousectl(cb);
			break;
		}
		else
			mousectl(field, nf);

		free(cb);
		poperror();
		return n;

	case Qmousein:

M port/devproc.c => port/devproc.c +1 -3
@@ 73,6 73,7 @@ Dirtab procdir[] =
	"profile",	{Qprofile},	0,			0400,
};

static
Cmdtab proccmd[] = {
	CMclose,		"close",		2,
	CMclosefiles,	"closefiles",	1,


@@ 1060,9 1061,6 @@ procctlreq(Proc *p, char *va, int n)
		nexterror();
	}

	if(cb->nf <= 0)
		error(Ebadctl);

	ct = lookupcmd(cb, proccmd, nelem(proccmd));

	switch(ct->index){

M port/error.h => port/error.h +1 -1
@@ 22,7 22,6 @@ extern char Etoosmall[];	/* read or write too small */
extern char Enoport[];		/* network port not available */
extern char Ehungup[];		/* i/o on hungup channel */
extern char Ebadctl[];		/* bad process or channel control request */
extern char Eargctl[];		/* wrong number of arguments in control request */
extern char Enodev[];		/* no free devices */
extern char Eprocdied[];	/* process exited */
extern char Enochild[];		/* no living children */


@@ 48,3 47,4 @@ extern char Enoattach[];	/* mount/attach disallowed */
extern char Eshortstat[];	/* stat buffer too small */
extern char Ebadstat[];		/* malformed stat buffer */
extern char Enegoff[];		/* negative i/o offset */
extern char Ecmdargs[];		/* wrong #args in control message */

M port/parse.c => port/parse.c +31 -7
@@ 68,23 68,47 @@ parsecmd(char *p, int n)
}

/*
 * Reconstruct original message, for error diagnostic
 */
void
cmderror(Cmdbuf *cb, char *s)
{
	int i;
	char *p, *e;

	p = up->genbuf;
	e = p+ERRMAX-10;
	p = seprint(p, e, "%s \"", s);
	for(i=0; i<cb->nf; i++){
		if(i > 0)
			p = seprint(p, e, " ");
		p = seprint(p, e, "%q", cb->f[i]);
	}
	strcpy(p, "\"");
	error(up->genbuf);
}

/*
 * Look up entry in table
 */
Cmdtab*
lookupcmd(Cmdbuf *cb, Cmdtab *ct, int nct)
lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
{
	int i;
	Cmdtab *ct;

	if(cb->nf == 0)
		error(Ebadctl);
		error("empty control message");

	for(i=0; i<nct; i++, ct++){
		if(strcmp(cb->f[0], ct->cmd) != 0)
	for(ct = ctab, i=0; i<nctab; i++, ct++){
		if(strcmp(ct->cmd, "*") !=0)	/* wildcard always matches */
		if(strcmp(ct->cmd, cb->f[0]) != 0)
			continue;
		if(ct->narg!=0 && ct->narg!=cb->nf)
			error(Eargctl);
		if(ct->narg != 0 && ct->narg != cb->nf)
			cmderror(cb, Ecmdargs);
		return ct;
	}
	error(Ebadctl);

	cmderror(cb, "unknown control message");
	return nil;
}

M port/portfns.h => port/portfns.h +1 -0
@@ 38,6 38,7 @@ void		closemount(Mount*);
void		closepgrp(Pgrp*);
void		closergrp(Rgrp*);
long		clrfpintr(void);
void		cmderror(Cmdbuf*, char*);
int		cmount(Chan**, Chan*, int, char*);
void		cnameclose(Cname*);
void		confinit(void);