Browse Source

Plan 9 from Bell Labs 2011-11-17

David du Colombier 12 years ago
parent
commit
3747abd0d5

+ 1 - 1
sys/lib/lp/process/generic

@@ -193,7 +193,7 @@ case empty
 	echo file is empty >[1=2]
 case cannot
 	echo cannot open file >[1=2]
-case English short extended alef limbo [Aa]scii assembler c latin rc sh \
+case English Cyrillic short extended alef limbo [Aa]scii assembler c latin rc sh \
     as mail email message/rfc822 manual HTML
 	switch ($LPCLASS) {
 	case *post*

+ 21 - 0
sys/src/9/pc/nomtrr.c

@@ -0,0 +1,21 @@
+/*
+ * dummy support for memory-type region registers.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+int
+mtrr(uvlong, uvlong, char *)
+{
+	error("mtrr support excluded");
+	return 0;
+}
+
+int
+mtrrprint(char *, long)
+{
+	return 0;
+}

+ 14 - 1
sys/src/cmd/8c/cgen.c

@@ -25,6 +25,12 @@ cgen(Node *n, Node *nn)
 	l = n->left;
 	r = n->right;
 	o = n->op;
+// Go's version does the following, but it's the wrong place: doesn't allow assignment
+//	if(o == OEXREG || nn != Z && nn->op == OEXREG) {
+//		gmove(n, nn);
+//		return;
+//	}
+
 	if(n->addable >= INDEXED) {
 		if(nn == Z) {
 			switch(o) {
@@ -244,7 +250,7 @@ cgen(Node *n, Node *nn)
 		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
 		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
 			c = l->right->vconst;
-			if(c > 0 && c <= 3) {
+			if(c > 0 && c <= 3 && nareg(1) >= 4) {
 				if(l->left->complex >= r->complex) {
 					regalloc(&nod, l->left, nn);
 					cgen(l->left, &nod);
@@ -887,6 +893,7 @@ cgen(Node *n, Node *nn)
 		break;
 
 	case OFUNC:
+		l = uncomma(l);
 		if(l->complex >= FNX) {
 			if(l->op != OIND)
 				diag(n, "bad function call");
@@ -1824,6 +1831,12 @@ copy:
 	gins(ACLD, Z, Z);
 	gins(AREP, Z, Z);
 	gins(AMOVSL, Z, Z);
+	if(w & (SZ_LONG-1)) {
+		/* odd length of packed structure */
+		gins(AMOVL, nodconst(w & (SZ_LONG-1)), &nod3);
+		gins(AREP, Z, Z);
+		gins(AMOVSB, Z, Z);
+	}
 	if(c & 4) {
 		gins(APOPL, Z, &nod3);
 		reg[D_CX]--;

+ 0 - 84
sys/src/cmd/8c/cgen64.c

@@ -188,70 +188,6 @@ storepair(Node *n, Node *nn, int f)
 		freepair(n);
 }
 
-/* generate a cast t from n to tt */
-static void
-cast(Node *n, Type *t, Node *nn)
-{
-	Node *r;
-
-	r = new(OCAST, n, Z);
-	r->type = t;
-	sugen(r, nn, 8);
-}
-
-static void
-swapregs(Node *a, Node *b)
-{
-	int t;
-
-	t = a->reg;
-	a->reg = b->reg;
-	b->reg = t;
-}
-
-static void
-swappairs(Node *a, Node *b)
-{
-	swapregs(a->left, b->left);
-	swapregs(a->right, b->right);
-}
-
-static int
-saveme(Node *n)
-{
-	int r;
-
-	r = n->reg;
-	return r >= D_AX && r <= D_DI;
-}
-
-static void
-saveit(Node *n, Node *t, Node *r)
-{
-	Node nod;
-
-	if(saveme(n)) {
-		t->reg = n->reg;
-		gins(AMOVL, t, r);
-		r->xoffset += SZ_LONG;
-		if(n->reg == D_AX) {
-			regalloc(&nod, n, Z);
-			regfree(n);
-			n->reg = nod.reg;
-		}
-	}
-}
-
-static void
-restoreit(Node *n, Node *t, Node *r)
-{
-	if(saveme(n)) {
-		t->reg = n->reg;
-		gins(AMOVL, r, t);
-		r->xoffset += SZ_LONG;
-	}
-}
-
 enum
 {
 /* 4 only, see WW */
@@ -319,26 +255,6 @@ vfunc(Node *n, Node *nn)
 	return t;
 }
 
-static int
-forcereg(Node *d, int r, int o, Node *t)
-{
-	int a;
-
-	if(d->reg != D_NONE)
-		diag(Z, "force alloc");
-	d->reg = r;
-	a = 0;
-	if(reg[r]) {
-		reg[o]++;
-		regalloc(t, d, Z);
-		a = 1;
-		gins(AMOVL, d, t);
-		reg[o]--;
-	}
-	reg[r]++;
-	return a;
-}
-
 /* try to steal a reg */
 static int
 getreg(Node **np, Node *t, int r)

+ 1 - 1
sys/src/cmd/8c/div.c

@@ -6,7 +6,7 @@
  * SIGPLAN Notices, Vol. 29, June 1994, page 61.
  */
 
-#define	TN(n)	(1ULL << (n))
+#define	TN(n)	((uvlong)1 << (n))
 #define	T31	TN(31)
 #define	T32	TN(32)
 

+ 47 - 0
sys/src/cmd/8c/enam.c

@@ -333,5 +333,52 @@ char*	anames[] =
 	"DYNT",
 	"INIT",
 	"SIGNAME",
+	"FCOMI",
+	"FCOMIP",
+	"FUCOMI",
+	"FUCOMIP",
+	"CMPXCHGB",
+	"CMPXCHGL",
+	"CMPXCHGW",
+	"CMOVLCC",
+	"CMOVLCS",
+	"CMOVLEQ",
+	"CMOVLGE",
+	"CMOVLGT",
+	"CMOVLHI",
+	"CMOVLLE",
+	"CMOVLLS",
+	"CMOVLLT",
+	"CMOVLMI",
+	"CMOVLNE",
+	"CMOVLOC",
+	"CMOVLOS",
+	"CMOVLPC",
+	"CMOVLPL",
+	"CMOVLPS",
+	"CMOVWCC",
+	"CMOVWCS",
+	"CMOVWEQ",
+	"CMOVWGE",
+	"CMOVWGT",
+	"CMOVWHI",
+	"CMOVWLE",
+	"CMOVWLS",
+	"CMOVWLT",
+	"CMOVWMI",
+	"CMOVWNE",
+	"CMOVWOC",
+	"CMOVWOS",
+	"CMOVWPC",
+	"CMOVWPL",
+	"CMOVWPS",
+	"FCMOVCC",
+	"FCMOVCS",
+	"FCMOVEQ",
+	"FCMOVHI",
+	"FCMOVLS",
+	"FCMOVNE",
+	"FCMOVNU",
+	"FCMOVUN",
 	"LAST",
 };

+ 2 - 6
sys/src/cmd/8c/gc.h

@@ -240,6 +240,7 @@ void	nextpc(void);
 void	gargs(Node*, Node*, Node*);
 void	garg1(Node*, Node*, Node*, int, Node**);
 Node*	nodconst(long);
+int	nareg(int);
 Node*	nodfconst(double);
 int	nodreg(Node*, Node*, int);
 int	isreg(Node*, int);
@@ -298,7 +299,7 @@ Reg*	rega(void);
 int	rcmp(const void*, const void*);
 void	regopt(Prog*);
 void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg*, Adr*);
+Bits	mkvar(Reg*, Adr*, int);
 void	prop(Reg*, Bits, Bits);
 void	loopit(Reg*, long);
 void	synch(Reg*, Bits);
@@ -335,11 +336,6 @@ int	BtoF(long);
 #define	D_HI	D_NONE
 #define	D_LO	D_NONE
 
-/*
- * bound
- */
-void	comtarg(void);
-
 /*
  * com64
  */

+ 1 - 0
sys/src/cmd/8c/machcap.c

@@ -53,6 +53,7 @@ machcap(Node *n)
 	case OANDAND:
 	case OOROR:
 	case ONOT:
+	case ODOT:
 		return 1;
 
 	case OASADD:

+ 16 - 2
sys/src/cmd/8c/peep.c

@@ -275,6 +275,9 @@ subprop(Reg *r0)
 		case ACWD:
 		case ACDQ:
 
+		case ASTOSB:
+		case ASTOSL:
+		case AMOVSB:
 		case AMOVSL:
 		case AFSTSW:
 			return 0;
@@ -639,10 +642,21 @@ copyu(Prog *p, Adr *v, Adr *s)
 			return 2;
 		goto caseread;
 
-	case AMOVSL:
 	case AREP:
 	case AREPN:
-		if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+		if(v->type == D_CX)
+			return 2;
+		goto caseread;
+
+	case AMOVSB:
+	case AMOVSL:
+		if(v->type == D_DI || v->type == D_SI)
+			return 2;
+		goto caseread;
+
+	case ASTOSB:
+	case ASTOSL:
+		if(v->type == D_AX || v->type == D_DI)
 			return 2;
 		goto caseread;
 

+ 17 - 8
sys/src/cmd/8c/reg.c

@@ -119,7 +119,7 @@ regopt(Prog *p)
 			r1->s1 = R;
 		}
 
-		bit = mkvar(r, &p->from);
+		bit = mkvar(r, &p->from, p->as==AMOVL);
 		if(bany(&bit))
 		switch(p->as) {
 		/*
@@ -139,7 +139,7 @@ regopt(Prog *p)
 			break;
 		}
 
-		bit = mkvar(r, &p->to);
+		bit = mkvar(r, &p->to, 0);
 		if(bany(&bit))
 		switch(p->as) {
 		default:
@@ -224,7 +224,9 @@ regopt(Prog *p)
 		 */
 		case AFMOVDP:
 		case AFMOVFP:
+		case AFMOVLP:
 		case AFMOVVP:
+		case AFMOVWP:
 		case ACALL:
 			for(z=0; z<BITS; z++)
 				addrs.b[z] |= bit.b[z];
@@ -637,7 +639,7 @@ doregbits(int r)
 }
 
 Bits
-mkvar(Reg *r, Adr *a)
+mkvar(Reg *r, Adr *a, int isro)
 {
 	Var *v;
 	int i, t, n, et, z;
@@ -651,13 +653,21 @@ mkvar(Reg *r, Adr *a)
 	t = a->type;
 	r->regu |= doregbits(t);
 	r->regu |= doregbits(a->index);
+	et = a->etype;
 
 	switch(t) {
 	default:
 		goto none;
+	case D_INDIR+D_GS:
+		if(!isro || 1)
+			goto none;
+		n = t;
+		{static Sym er; a->sym = &er;}
+		a->sym->name = "$extreg";
+		break;
 	case D_ADDR:
 		a->type = a->index;
-		bit = mkvar(r, a);
+		bit = mkvar(r, a, 0);
 		for(z=0; z<BITS; z++)
 			addrs.b[z] |= bit.b[z];
 		a->type = t;
@@ -674,7 +684,6 @@ mkvar(Reg *r, Adr *a)
 		goto none;
 	if(s->name[0] == '.')
 		goto none;
-	et = a->etype;
 	o = a->offset;
 	v = var;
 	for(i=0; i<nvar; i++) {
@@ -1008,7 +1017,7 @@ paint1(Reg *r, int bn)
 
 		if(r->use1.b[z] & bb) {
 			change += CREF * r->loop;
-			if(p->as == AFMOVL)
+			if(p->as == AFMOVL || p->as == AFMOVW)
 				if(BtoR(bb) != D_F0)
 					change = -CINF;
 			if(debug['R'] && debug['v'])
@@ -1018,7 +1027,7 @@ paint1(Reg *r, int bn)
 
 		if((r->use2.b[z]|r->set.b[z]) & bb) {
 			change += CREF * r->loop;
-			if(p->as == AFMOVL)
+			if(p->as == AFMOVL || p->as == AFMOVW)
 				if(BtoR(bb) != D_F0)
 					change = -CINF;
 			if(debug['R'] && debug['v'])
@@ -1028,7 +1037,7 @@ paint1(Reg *r, int bn)
 
 		if(STORE(r) & r->regdiff.b[z] & bb) {
 			change -= CLOAD * r->loop;
-			if(p->as == AFMOVL)
+			if(p->as == AFMOVL || p->as == AFMOVW)
 				if(BtoR(bb) != D_F0)
 					change = -CINF;
 			if(debug['R'] && debug['v'])

+ 4 - 0
sys/src/cmd/8c/sgen.c

@@ -88,6 +88,10 @@ xcom(Node *n)
 			n->addable = 11;
 		break;
 
+	case OEXREG:
+		n->addable = 12;
+		break;
+
 	case OREGISTER:
 		n->addable = 12;
 		break;

+ 19 - 2
sys/src/cmd/8c/txt.c

@@ -158,7 +158,8 @@ gargs(Node *n, Node *tn1, Node *tn2)
 	cursafe = regs;
 }
 
-int nareg(void)
+int
+nareg(int notbp)
 {
 	int i, n;
 
@@ -166,6 +167,8 @@ int nareg(void)
 	for(i=D_AX; i<=D_DI; i++)
 		if(reg[i] == 0)
 			n++;
+	if(notbp && reg[D_BP] == 0)
+		n--;
 	return n;
 }
 
@@ -306,6 +309,7 @@ regalloc(Node *n, Node *tn, Node *o)
 			if(reg[i] == 0)
 				goto out;
 		diag(tn, "out of fixed registers");
+abort();
 		goto err;
 
 	case TFLOAT:
@@ -430,6 +434,11 @@ naddr(Node *n, Adr *a)
 		a->sym = S;
 		break;
 
+	case OEXREG:
+		a->type = D_INDIR + D_GS;
+		a->offset = n->reg - 1;
+		a->etype = n->etype;
+		break;
 
 	case OIND:
 		naddr(n->left, a);
@@ -1355,7 +1364,15 @@ long
 exreg(Type *t)
 {
 
-	USED(t);
+	int o;
+
+	if(typechlp[t->etype]){
+		if(exregoffset >= 32)
+			return 0;
+		o = exregoffset;
+		exregoffset += 4;
+		return o+1;	/* +1 to avoid 0 == failure; naddr case OEXREG will -1. */
+	}
 	return 0;
 }
 

+ 2 - 0
sys/src/cmd/cc/acid.c

@@ -90,6 +90,8 @@ acidinit(void)
 		if(types[TINT]->width != types[TSHORT]->width)
 			warn(Z, "acidmember int not long or short");
 	}
+	if(types[TIND]->width == types[TUVLONG]->width)
+		acidchar[TIND] = 'Y';
 	
 }
 

+ 7 - 3
sys/src/cmd/cc/cc.h

@@ -22,11 +22,11 @@ typedef	struct	Bits	Bits;
 
 #define	NHUNK		50000L
 #define	BUFSIZ		8192
-#define	NSYMB		500
+#define	NSYMB		1500
 #define	NHASH		1024
 #define	STRINGSZ	200
 #define	HISTSZ		20
-#define YYMAXDEPTH	500
+#define YYMAXDEPTH	1500
 #define	NTERM		10
 #define	MAXALIGN	7
 
@@ -294,6 +294,7 @@ enum
 	OINDEX,
 	OFAS,
 	OREGPAIR,
+	OEXREG,
 
 	OEND
 };
@@ -477,6 +478,7 @@ EXTERN	int	packflg;
 EXTERN	int	fproundflg;
 EXTERN	int	profileflg;
 EXTERN	int	ncontin;
+EXTERN	int	newvlongcode;
 EXTERN	int	canreach;
 EXTERN	int	warnreach;
 EXTERN	Bits	zbits;
@@ -614,7 +616,7 @@ int	rsametype(Type*, Type*, int, int);
 int	sametype(Type*, Type*);
 ulong	sign(Sym*);
 ulong	signature(Type*);
-void	suallign(Type*);
+void	sualign(Type*);
 void	tmerge(Type*, Sym*);
 void	walkparam(Node*, int);
 void	xdecl(int, Type*, Sym*);
@@ -632,6 +634,8 @@ int	tcomo(Node*, int);
 int	tcomx(Node*);
 int	tlvalue(Node*);
 void	constas(Node*, Type*, Type*);
+Node*	uncomma(Node*);
+Node*	uncomargs(Node*);
 
 /*
  * con.c

+ 13 - 5
sys/src/cmd/cc/cc.y

@@ -8,12 +8,14 @@
 	struct
 	{
 		Type*	t;
-		char	c;
+		uchar	c;
 	} tycl;
 	struct
 	{
 		Type*	t1;
 		Type*	t2;
+		Type*	t3;
+		uchar	c;
 	} tyty;
 	struct
 	{
@@ -895,16 +897,22 @@ sbody:
 	{
 		$<tyty>$.t1 = strf;
 		$<tyty>$.t2 = strl;
+		$<tyty>$.t3 = lasttype;
+		$<tyty>$.c = lastclass;
 		strf = T;
 		strl = T;
 		lastbit = 0;
 		firstbit = 1;
+		lastclass = CXXX;
+		lasttype = T;
 	}
 	edecl '}'
 	{
 		$$ = strf;
 		strf = $<tyty>2.t1;
 		strl = $<tyty>2.t2;
+		lasttype = $<tyty>2.t3;
+		lastclass = $<tyty>2.c;
 	}
 
 zctlist:
@@ -995,7 +1003,7 @@ complex:
 		if($$->link != T)
 			diag(Z, "redeclare tag: %s", $2->name);
 		$$->link = $4;
-		suallign($$);
+		sualign($$);
 	}
 |	LSTRUCT sbody
 	{
@@ -1003,7 +1011,7 @@ complex:
 		sprint(symb, "_%d_", taggen);
 		$$ = dotag(lookup(), TSTRUCT, autobn);
 		$$->link = $2;
-		suallign($$);
+		sualign($$);
 	}
 |	LUNION ltag
 	{
@@ -1020,7 +1028,7 @@ complex:
 		if($$->link != T)
 			diag(Z, "redeclare tag: %s", $2->name);
 		$$->link = $4;
-		suallign($$);
+		sualign($$);
 	}
 |	LUNION sbody
 	{
@@ -1028,7 +1036,7 @@ complex:
 		sprint(symb, "_%d_", taggen);
 		$$ = dotag(lookup(), TUNION, autobn);
 		$$->link = $2;
-		suallign($$);
+		sualign($$);
 	}
 |	LENUM ltag
 	{

+ 116 - 3
sys/src/cmd/cc/com.c

@@ -1,6 +1,15 @@
 #include "cc.h"
 
+typedef struct Com Com;
+struct Com
+{
+	int	n;
+	Node	*t[500];
+};
+
 int compar(Node*, int);
+static void comma(Node*);
+static Node*	commas(Com*, Node*);
 
 void
 complex(Node *n)
@@ -15,6 +24,8 @@ complex(Node *n)
 			prtree(n, "pre complex");
 	if(tcom(n))
 		return;
+	if(debug['y'] || 1)
+		comma(n);
 	if(debug['t'])
 		if(n->op != OCONST)
 			prtree(n, "t complex");
@@ -273,8 +284,11 @@ tcomo(Node *n, int f)
 			goto bad;
 		n->type = l->type;
 		if(n->type->etype == TIND)
-		if(n->type->link->width < 1)
-			diag(n, "inc/dec of a void pointer");
+		if(n->type->link->width < 1) {
+			snap(n->type->link);
+			if(n->type->link->width < 1)
+				diag(n, "inc/dec of a void pointer");
+		}
 		break;
 
 	case OEQ:
@@ -610,6 +624,8 @@ tcomo(Node *n, int f)
 		n->addable = 1;
 		if(n->class == CEXREG) {
 			n->op = OREGISTER;
+			if(thechar == '8')
+				n->op = OEXREG;
 			n->reg = n->sym->offset;
 			n->xoffset = 0;
 			break;
@@ -881,6 +897,101 @@ tlvalue(Node *n)
 	return 0;
 }
 
+/*
+ * hoist comma operators out of expressions
+ *	(a,b) OP c => (a, b OP c)
+ *	OP(a,b) =>	(a, OP b)
+ *	a OP (b,c) => (b, a OP c)
+ */
+
+static Node*
+comargs(Com *com, Node *n)
+{
+	if(n != Z && n->op == OLIST){
+		n->left = comargs(com, n->left);
+		n->right = comargs(com, n->right);
+	}
+	return commas(com, n);
+}
+
+static Node*
+commas(Com *com, Node *n)
+{
+	Node *t;
+
+	if(n == Z)
+		return n;
+	switch(n->op){
+	case OREGISTER:
+	case OINDREG:
+	case OCONST:
+	case ONAME:
+	case OSTRING:
+		/* leaf */
+		return n;
+
+	case OCOMMA:
+		t = commas(com, n->left);
+		if(com->n >= nelem(com->t))
+			fatal(n, "comma list overflow");
+		com->t[com->n++] = t;
+		return commas(com, n->right);
+
+	case OFUNC:
+		n->left = commas(com, n->left);
+		n->right = comargs(com, n->right);
+		return n;
+
+	case OCOND:
+		n->left = commas(com, n->left);
+		comma(n->right->left);
+		comma(n->right->right);
+		return n;
+
+	case OANDAND:
+	case OOROR:
+		n->left = commas(com, n->left);
+		comma(n->right);
+		return n;
+
+	case ORETURN:
+		comma(n->left);
+		return n;
+	}
+	n->left = commas(com, n->left);
+	if(n->right != Z)
+		n->right = commas(com, n->right);
+	return n;
+}
+
+static void
+comma(Node *n)
+{
+	Com com;
+	Node *nn;
+
+	com.n = 0;
+	nn = commas(&com, n);
+	if(com.n > 0){
+if(debug['y'])print("n=%d\n", com.n);
+if(debug['y']) prtree(nn, "res");
+		if(nn != n)
+			*n = *nn;
+		while(com.n > 0){
+if(debug['y']) prtree(com.t[com.n-1], "tree");
+			nn = new1(OXXX, Z, Z);
+			*nn = *n;
+			n->op = OCOMMA;
+			n->type = nn->type;
+			n->left = com.t[--com.n];
+			n->right = nn;
+			n->lineno = n->left->lineno;
+		}
+if(debug['y']) prtree(n, "final");
+	}else if(n != nn)
+		fatal(n, "odd tree");
+}
+
 /*
  *	general rewrite
  *	(IND(ADDR x)) ==> x
@@ -934,7 +1045,8 @@ loop:
 			if(n->op == OCONST)
 				break;
 		}
-		if(nocast(l->type, n->type)) {
+		if(nocast(l->type, n->type) &&
+		   (!typefd[l->type->etype] || typeu[l->type->etype] && typeu[n->type->etype])) {
 			l->type = n->type;
 			*n = *l;
 		}
@@ -1342,6 +1454,7 @@ useless:
 	else
 		snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
 			lt, cmps[relindex(n->op)], xbuf);
+if(debug['y']) prtree(n, "strange");
 	warn(n, "useless or misleading comparison: %s", cmpbuf);
 	return 0;
 }

+ 4 - 8
sys/src/cmd/cc/dcl.c

@@ -519,7 +519,7 @@ newlist(Node *l, Node *r)
 }
 
 void
-suallign(Type *t)
+sualign(Type *t)
 {
 	Type *l;
 	long o, w;
@@ -581,7 +581,7 @@ suallign(Type *t)
 		return;
 
 	default:
-		diag(Z, "unknown type in suallign: %T", t);
+		diag(Z, "unknown type in sualign: %T", t);
 		break;
 	}
 }
@@ -1180,12 +1180,6 @@ paramconv(Type *t, int f)
 {
 
 	switch(t->etype) {
-	case TUNION:
-	case TSTRUCT:
-		if(t->width <= 0)
-			diag(Z, "incomplete structure: %s", t->tag->name);
-		break;
-
 	case TARRAY:
 		t = typ(TIND, t->link);
 		t->width = types[TIND]->width;
@@ -1283,6 +1277,8 @@ pdecl(int c, Type *t, Sym *s)
 		diag(Z, "parameter cannot have class: %s", s->name);
 		c = CPARAM;
 	}
+	if(typesu[t->etype] && t->width <= 0)
+		diag(Z, "incomplete structure: %s", t->tag->name);
 	adecl(c, t, s);
 }
 

+ 2 - 2
sys/src/cmd/cc/macbody

@@ -25,7 +25,7 @@ getsym(void)
 	char *cp;
 
 	c = getnsc();
-	if(!isalpha(c) && c != '_') {
+	if(!isalpha(c) && c != '_' && c < Runeself) {
 		unget(c);
 		return S;
 	}
@@ -33,7 +33,7 @@ getsym(void)
 		if(cp <= symb+NSYMB-4)
 			*cp++ = c;
 		c = getc();
-		if(isalnum(c) || c == '_')
+		if(isalnum(c) || c == '_' || c >= Runeself)
 			continue;
 		unget(c);
 		break;

+ 41 - 2
sys/src/cmd/cc/pgen.c

@@ -105,10 +105,20 @@ supgen(Node *n)
 	warnreach = owarn;
 }
 
+Node*
+uncomma(Node *n)
+{
+	while(n != Z && n->op == OCOMMA) {
+		cgen(n->left, Z);
+		n = n->right;
+	}
+	return n;
+}
+
 void
 gen(Node *n)
 {
-	Node *l, nod;
+	Node *l, nod, rn;
 	Prog *sp, *spc, *spb;
 	Case *cn;
 	long sbc, scc;
@@ -129,6 +139,7 @@ loop:
 		case OLABEL:
 		case OCASE:
 		case OLIST:
+		case OCOMMA:
 		case OBREAK:
 		case OFOR:
 		case OWHILE:
@@ -151,6 +162,7 @@ loop:
 		break;
 
 	case OLIST:
+	case OCOMMA:
 		gen(n->left);
 
 	rloop:
@@ -163,7 +175,7 @@ loop:
 		complex(n);
 		if(n->type == T)
 			break;
-		l = n->left;
+		l = uncomma(n->left);
 		if(l == Z) {
 			noretval(3);
 			gbranch(ORETURN);
@@ -181,6 +193,20 @@ loop:
 			gbranch(ORETURN);
 			break;
 		}
+		if(newvlongcode && !typefd[n->type->etype]){
+			regret(&rn, n);
+			regfree(&rn);
+			nod = znode;
+			nod.op = OAS;
+			nod.left = &rn;
+			nod.right = l;
+			nod.type = n->type;
+			nod.complex = l->complex;
+			cgen(&nod, Z);
+			noretval(2);
+			gbranch(ORETURN);
+			break;
+		}
 		regret(&nod, n);
 		cgen(l, &nod);
 		regfree(&nod);
@@ -531,6 +557,8 @@ usedset(Node *n, int o)
 int
 bcomplex(Node *n, Node *c)
 {
+	Node *b, nod;
+
 
 	complex(n);
 	if(n->type != T)
@@ -542,6 +570,17 @@ bcomplex(Node *n, Node *c)
 	}
 	if(c != Z && n->op == OCONST && deadheads(c))
 		return 1;
+	if(newvlongcode && typev[n->type->etype] && machcap(Z)) {
+		b = &nod;
+		b->op = ONE;
+		b->left = n;
+		b->right = new(0, Z, Z);
+		*b->right = *nodconst(0);
+		b->right->type = n->type;
+		b->type = types[TLONG];
+		cgen(b, Z);
+		return 0;
+	}
 	bool64(n);
 	boolgen(n, 1, Z);
 	return 0;

+ 1 - 0
sys/src/cmd/cc/sub.c

@@ -1485,6 +1485,7 @@ Init	onamesinit[] =
 	OINDEX,		0,	"INDEX",
 	OFAS,		0,	"FAS",
 	OREGPAIR,	0,	"REGPAIR",
+	OEXREG,		0,	"EXREG",
 	OEND,		0,	"END",
 	-1,		0,	0,
 };

+ 193 - 0
sys/src/cmd/usb/kb/hid.c

@@ -0,0 +1,193 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+#include "hid.h"
+
+/*
+ * Rough hid descriptor parsing and interpretation for mice
+ *
+ * Chain and its operations build the infrastructure needed
+ * to manipulate non-aligned fields, which do appear (sigh!).
+ */
+
+/* Get, at most, 8 bits*/
+static uchar
+get8bits(Chain *ch, int nbits)
+{
+	int b, nbyb, nbib, nlb;
+	uchar low, high;
+
+	b = ch->b + nbits - 1;
+	nbib = ch->b % 8;
+	nbyb = ch->b / 8;
+	nlb = 8 - nbib;
+	if(nlb > nbits)
+		nlb = nbits;
+
+	low = MSK(nlb) & (ch->buf[nbyb] >> nbib);
+	if(IsCut(ch->b, b))
+		high = (ch->buf[nbyb + 1] & MSK(nbib)) << nlb;
+	else
+		high = 0;
+	ch->b += nbits;
+	return high | low;
+}
+
+static void
+getbits(void *p, Chain *ch, int nbits)
+{
+	int nby, nbi, i;
+	uchar *vp;
+
+	assert(ch->e >= ch->b);
+	nby = nbits / 8;
+	nbi = nbits % 8;
+
+	vp = p;
+	for(i = 0; i < nby; i++)
+		*vp++ = get8bits(ch, 8);
+
+	if(nbi != 0)
+		*vp = get8bits(ch, nbi);
+}
+
+/* TODO check report id, when it does appear (not all devices) */
+int
+parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz)
+{
+	int i, j, l, n, isptr, hasxy, hasbut, nk;
+	int ks[MaxVals];
+	HidInterface *ifs;
+
+	ifs = temp->ifcs;
+	isptr = 0;
+	hasxy = hasbut = 0;
+	n = 0;
+	nk = 0;
+	memset(ifs, 0, sizeof *ifs * MaxIfc);
+	for(i = 0; i < repsz / 2; i += 2){
+		if(n == MaxIfc || repdesc[i] == HidEnd)
+			break;
+
+		switch(repdesc[i]){
+		case HidTypeUsg:
+			switch(repdesc[i+1]){
+			case HidX:
+				hasxy++;
+				ks[nk++] = KindX;
+				break;
+			case HidY:
+				hasxy++;
+				ks[nk++] = KindY;
+				break;
+			case HidWheel:
+				ks[nk++] = KindWheel;
+				break;
+			case HidPtr:
+				isptr++;
+				break;
+			}
+			break;
+		case HidTypeUsgPg:
+			switch(repdesc[i+1]){
+			case HidPgButts:
+				hasbut++;
+				ks[nk++] = KindButtons;
+				break;
+			}
+			break;
+		case HidTypeRepSz:
+			ifs[n].nbits = repdesc[i+1];
+			break;
+		case HidTypeCnt:
+			ifs[n].count = repdesc[i+1];
+			break;
+		case HidInput:
+			for(j = 0; j <nk; j++)
+				ifs[n].kind[j] = ks[j];
+			if(nk < ifs[n].count)
+				for(l = j; l <ifs[n].count; l++)
+					ifs[n].kind[l] = ks[j-1];
+			n++;
+			nk = 0;
+			break;
+		}
+	}
+	temp->nifcs = n;
+	if(isptr && hasxy && hasbut)
+		return 0;
+	fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n",
+		isptr, hasxy, hasbut);
+	return -1;
+}
+
+int
+parsereport(HidRepTempl *templ, Chain *rep)
+{
+	int i, j, k, ifssz;
+	ulong u;
+	uchar *p;
+	HidInterface *ifs;
+
+	ifssz = templ->nifcs;
+	ifs = templ->ifcs;
+	for(i = 0; i < ifssz; i++)
+		for(j = 0; j < ifs[i].count; j++){
+			if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){
+				fprint(2, "ptr: bad bits in parsereport");
+				return -1;
+			}
+			u =0;
+			getbits(&u, rep, ifs[i].nbits);
+			p = (uchar *)&u;
+			/* le to host */
+			ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0;
+			k = ifs[i].kind[j];
+			if(k == KindX || k == KindY || k == KindWheel){
+				/* propagate sign */
+				if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1)))
+					ifs[i].v[j] |= ~MSK(ifs[i].nbits);
+			}
+		}
+	return 0;
+}
+
+/* TODO: fmt representation */
+void
+dumpreport(HidRepTempl *templ)
+{
+	int i, j, ifssz;
+	HidInterface *ifs;
+
+	ifssz = templ->nifcs;
+	ifs = templ->ifcs;
+	for(i = 0; i < ifssz; i++){
+		fprint(2, "\tcount %#ux", ifs[i].count);
+		fprint(2, " nbits %d ", ifs[i].nbits);
+		fprint(2, "\n");
+		for(j = 0; j < ifs[i].count; j++){
+			fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]);
+			fprint(2, "v %#lux\n", ifs[i].v[j]);
+		}
+		fprint(2, "\n");
+	}
+	fprint(2, "\n");
+}
+
+/* could cache indices after parsing the descriptor */
+int
+hidifcval(HidRepTempl *templ, int kind, int n)
+{
+	int i, j, ifssz;
+	HidInterface *ifs;
+
+	ifssz = templ->nifcs;
+	ifs = templ->ifcs;
+	assert(n <= nelem(ifs[i].v));
+	for(i = 0; i < ifssz; i++)
+		for(j = 0; j < ifs[i].count; j++)
+			if(ifs[i].kind[j] == kind && n-- == 0)
+				return (int)ifs[i].v[j];
+	return 0;		/* least damage (no buttons, no movement) */
+}

+ 69 - 4
sys/src/cmd/usb/kb/hid.h

@@ -1,8 +1,12 @@
 /*
  * USB keyboard/mouse constants
  */
-enum {
 
+typedef struct Chain Chain;
+typedef struct HidInterface HidInterface;
+typedef struct HidRepTempl HidRepTempl;
+
+enum {
 	Stack = 32 * 1024,
 
 	/* HID class subclass protocol ids */
@@ -11,6 +15,7 @@ enum {
 
 	/* Requests */
 	Getproto	= 0x03,
+	Setidle		= 0x0a,
 	Setproto	= 0x0b,
 
 	/* protocols for SET_PROTO request */
@@ -39,7 +44,6 @@ enum {
 
 	MaxAcc = 3,			/* max. ptr acceleration */
 	PtrMask= 0xf,			/* 4 buttons: should allow for more. */
-
 };
 
 /*
@@ -49,8 +53,8 @@ enum {
 	/* Scan codes (see kbd.c) */
 	SCesc1		= 0xe0,		/* first of a 2-character sequence */
 	SCesc2		= 0xe1,
-	SClshift		= 0x2a,
-	SCrshift		= 0x36,
+	SClshift	= 0x2a,
+	SCrshift	= 0x36,
 	SCctrl		= 0x1d,
 	SCcompose	= 0x38,
 	Keyup		= 0x80,		/* flag bit */
@@ -58,3 +62,64 @@ enum {
 };
 
 int kbmain(Dev *d, int argc, char*argv[]);
+
+enum{
+	MaxChLen	= 16,	/* bytes */
+};
+
+struct Chain {
+	int	b;			/* offset start in bits, (first full) */
+	int	e;			/* offset end in bits (first empty) */
+	uchar	buf[MaxChLen];
+};
+
+#define MSK(nbits)		((1UL << (nbits)) - 1)
+#define IsCut(bbits, ebits)	(((ebits)/8 - (bbits)/8) > 0)
+
+enum {
+	KindPad = 0,
+	KindButtons,
+	KindX,
+	KindY,
+	KindWheel,
+
+	MaxVals	= 8,
+	MaxIfc	= 8,
+};
+
+struct HidInterface {
+	ulong	v[MaxVals];	/* one ulong per val should be enough */
+	int	kind[MaxVals];
+	int	nbits;
+	int	count;
+};
+
+struct HidRepTempl{
+	int	nifcs;
+	HidInterface ifcs[MaxIfc];
+};
+
+enum {
+	/* report types */
+	HidTypeUsgPg	= 0x05,
+	HidPgButts	= 0x09,
+
+	HidTypeRepSz	= 0x75,
+	HidTypeCnt	= 0x95,
+
+	HidTypeUsg	= 0x09,
+	HidPtr		= 0x01,
+	HidX		= 0x30,
+	HidY		= 0x31,
+	HidWheel	= 0x38,
+
+	HidInput	= 0x81,
+	HidReportId	= 0x85,
+
+	HidEnd		= 0x0c,
+};
+
+void	dumpreport(HidRepTempl *templ);
+int	hidifcval(HidRepTempl *templ, int kind, int n);
+int	parsereport(HidRepTempl *templ, Chain *rep);
+int	parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz);

+ 179 - 53
sys/src/cmd/usb/kb/kb.c

@@ -4,10 +4,11 @@
  * If there's no usb keyboard, it tries to setup the mouse, if any.
  * It should be started at boot time.
  *
- * Mouse events are converted to the format of mouse(3)'s
- * mousein file.
+ * Mouse events are converted to the format of mouse(3)'s mousein file.
  * Keyboard keycodes are translated to scan codes and sent to kbin(3).
  *
+ * If there is no keyboard, it tries to setup the mouse properly, else it falls
+ * back to boot protocol.
  */
 
 #include <u.h>
@@ -18,8 +19,8 @@
 
 enum
 {
-	Awakemsg=0xdeaddead,
-	Diemsg = 0xbeefbeef,
+	Awakemsg= 0xdeaddead,
+	Diemsg	= 0xbeefbeef,
 };
 
 typedef struct KDev KDev;
@@ -32,6 +33,9 @@ struct KDev
 	Kin*	in;		/* used to send events to kernel */
 	Channel*repeatc;	/* only for keyboard */
 	int	accel;		/* only for mouse */
+	int	bootp;		/* has associated keyboard */
+	HidRepTempl templ;
+	int	(*ptrvals)(KDev *kd, Chain *ch, int *px, int *py, int *pb);
 };
 
 /*
@@ -62,7 +66,7 @@ struct Kin
  * key code to scan code; for the page table used by
  * the logitech bluetooth keyboard.
  */
-static char sctab[256] = 
+static char sctab[256] =
 {
 [0x00]	0x0,	0x0,	0x0,	0x0,	0x1e,	0x30,	0x2e,	0x20,
 [0x08]	0x12,	0x21,	0x22,	0x23,	0x17,	0x24,	0x25,	0x26,
@@ -114,16 +118,59 @@ static Kin ptrin =
 
 static int kbdebug;
 
+static int ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb);
+static int ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb);
+
 static int
-setbootproto(KDev* f, int eid)
+setbootproto(KDev* f, int eid, uchar *, int)
 {
 	int r, id;
 
+	f->ptrvals = ptrbootpvals;
 	r = Rh2d|Rclass|Riface;
+	dprint(2, "setting boot protocol\n");
 	id = f->dev->usb->ep[eid]->iface->id;
 	return usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0);
 }
 
+static uchar ignoredesc[128];
+
+static int
+setfirstconfig(KDev* f, int eid, uchar *desc, int descsz)
+{
+	int nr, r, id, i;
+
+	dprint(2, "setting first config\n");
+	if(desc == nil){
+		descsz = sizeof ignoredesc;
+		desc = ignoredesc;
+	}
+	id = f->dev->usb->ep[eid]->iface->id;
+	r = Rh2d | Rstd | Rdev;
+	nr =usbcmd(f->dev,  r, Rsetconf, 1, id, nil, 0);
+	if(nr < 0)
+		return -1;
+	r = Rh2d | Rclass | Riface;
+	nr=usbcmd(f->dev,   r, Setidle,  0, id, nil, 0);
+	if(nr < 0)
+		return -1;
+	r = Rd2h | Rstd | Riface;
+	nr=usbcmd(f->dev,  r, Rgetdesc, Dreport<<8, id, desc, descsz);
+	if(nr < 0)
+		return -1;
+	if(kbdebug && nr > 0){
+		fprint(2, "report descriptor: ");
+		for(i = 0; i < nr; i++){
+			fprint(2, " %#2.2ux ", desc[i]);
+			if(i!= 0 && i%8 == 0)
+				fprint(2, "\n");
+		}
+		fprint(2, "\n");
+	}
+	f->ptrvals = ptrrepvals;
+	return nr;
+}
+
 /*
  * Try to recover from a babble error. A port reset is the only way out.
  * BUG: we should be careful not to reset a bundle with several devices.
@@ -136,9 +183,15 @@ recoverkb(KDev *f)
 	close(f->dev->dfd);		/* it's for usbd now */
 	devctl(f->dev, "reset");
 	for(i = 0; i < 10; i++){
+		if(i == 5)
+			f->bootp++;
 		sleep(500);
 		if(opendevdata(f->dev, ORDWR) >= 0){
-			setbootproto(f, f->ep->id);
+			if(f->bootp)
+				/* TODO func pointer */
+				setbootproto(f, f->ep->id, nil, 0);
+			else
+				setfirstconfig(f, f->ep->id, nil, 0);
 			break;
 		}
 		/* else usbd still working... */
@@ -207,36 +260,85 @@ sethipri(void)
 	char fn[30];
 	int fd;
 
-	snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid());
+	snprint(fn, sizeof fn, "/proc/%d/ctl", getpid());
 	fd = open(fn, OWRITE);
-	if(fd < 0)
-		return;
-	fprint(fd, "pri 13");
-	close(fd);
+	if(fd >= 0) {
+		fprint(fd, "pri 13");
+		close(fd);
+	}
+}
+
+static int
+ptrrepvals(KDev *kd, Chain *ch, int *px, int *py, int *pb)
+{
+	int i, x, y, b, c;
+	static char buts[] = {0x0, 0x2, 0x1};
+
+	c = ch->e / 8;
+	parsereport(&kd->templ, ch);
+
+	if(kbdebug)
+		dumpreport(&kd->templ);
+	if(c < 3)
+		return -1;
+	x = hidifcval(&kd->templ, KindX, 0);
+	y = hidifcval(&kd->templ, KindY, 0);
+	b = 0;
+	for(i = 0; i<sizeof buts; i++)
+		b |= (hidifcval(&kd->templ, KindButtons, i) & 1) << buts[i];
+	if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) > 0)	/* up */
+		b |= 0x10;
+	if(c > 3 && hidifcval(&kd->templ, KindWheel, 0) < 0)	/* down */
+		b |= 0x08;
+
+	*px = x;
+	*py = y;
+	*pb = b;
+	return 0;
+}
+
+static int
+ptrbootpvals(KDev *kd, Chain *ch, int *px, int *py, int *pb)
+{
+	int b, c;
+	char x, y;
+	static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7};
+
+	c = ch->e / 8;
+	if(c < 3)
+		return -1;
+	x = hidifcval(&kd->templ, KindX, 0);
+	y = hidifcval(&kd->templ, KindY, 0);
+
+	b = maptab[ch->buf[0] & 0x7];
+	if(c > 3 && ch->buf[3] == 1)		/* up */
+		b |= 0x08;
+	if(c > 3 && ch->buf[3] == 0xff)		/* down */
+		b |= 0x10;
+	*px = x;
+	*py = y;
+	*pb = b;
+	return 0;
 }
 
 static void
 ptrwork(void* a)
 {
-	static char maptab[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7};
-	int x, y, b, c, ptrfd;
-	int	mfd, nerrs;
-	char	buf[32];
-	char	mbuf[80];
-	KDev*	f = a;
-	int	hipri;
+	int hipri, mfd, nerrs, x, y, b, c, ptrfd;
+	char mbuf[80];
+	Chain ch;
+	KDev* f = a;
 
 	hipri = nerrs = 0;
 	ptrfd = f->ep->dfd;
 	mfd = f->in->fd;
-
-	if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf)
+	if(f->ep->maxpkt < 3 || f->ep->maxpkt > MaxChLen)
 		kbfatal(f, "weird mouse maxpkt");
 	for(;;){
-		memset(buf, 0, sizeof buf);
+		memset(ch.buf, 0, MaxChLen);
 		if(f->ep == nil)
 			kbfatal(f, nil);
-		c = read(ptrfd, buf, f->ep->maxpkt);
+		c = read(ptrfd, ch.buf, f->ep->maxpkt);
 		assert(f->dev != nil);
 		assert(f->ep != nil);
 		if(c < 0){
@@ -248,20 +350,15 @@ ptrwork(void* a)
 		}
 		if(c <= 0)
 			kbfatal(f, nil);
-		if(c < 3)
+		ch.b = 0;
+		ch.e = 8 * c;
+		if(f->ptrvals(f, &ch, &x, &y, &b) < 0)
 			continue;
+
 		if(f->accel){
-			x = scale(f, buf[1]);
-			y = scale(f, buf[2]);
-		}else{
-			x = buf[1];
-			y = buf[2];
+			x = scale(f, x);
+			y = scale(f, y);
 		}
-		b = maptab[buf[0] & 0x7];
-		if(c > 3 && buf[3] == 1)	/* up */
-			b |= 0x08;
-		if(c > 3 && buf[3] == -1)	/* down */
-			b |= 0x10;
 		if(kbdebug > 1)
 			fprint(2, "kb: m%11d %11d %11d\n", x, y, b);
 		seprint(mbuf, mbuf+sizeof(mbuf), "m%11d %11d %11d", x, y,b);
@@ -502,9 +599,10 @@ freekdev(void *a)
 }
 
 static void
-kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel)
+kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), KDev *kd)
 {
-	KDev *kd;
+	uchar desc[128];
+	int res;
 
 	qlock(&inlck);
 	if(in->fd < 0){
@@ -517,15 +615,23 @@ kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel)
 	}
 	in->ref++;	/* for kd->in = in */
 	qunlock(&inlck);
-	kd = d->aux = emallocz(sizeof(KDev), 1);
 	d->free = freekdev;
 	kd->in = in;
 	kd->dev = d;
-	if(setbootproto(kd, ep->id) < 0){
-		fprint(2, "kb: %s: bootproto: %r\n", d->dir);
-		return;
-	}
-	kd->accel = accel;
+	res = -1;
+	if(!kd->bootp)
+		res= setfirstconfig(kd, ep->id, desc, sizeof desc);
+	if(res > 0)
+		res = parsereportdesc(&kd->templ, desc, sizeof desc);
+	/* if we could not set the first config, we give up */
+	if(kd->bootp || res < 0){
+		kd->bootp = 1;
+		if(setbootproto(kd, ep->id, nil, 0) < 0){
+			fprint(2, "kb: %s: bootproto: %r\n", d->dir);
+			return;
+		}
+	}else if(kbdebug)
+		dumpreport(&kd->templ);
 	kd->ep = openep(d, ep->id);
 	if(kd->ep == nil){
 		fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id);
@@ -545,18 +651,20 @@ kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel)
 static int
 usage(void)
 {
-	werrstr("usage: usb/kb [-dkm] [-a n] [-N nb]");
+	werrstr("usage: usb/kb [-bdkm] [-a n] [-N nb]");
 	return -1;
 }
 
 int
 kbmain(Dev *d, int argc, char* argv[])
 {
-	int i, kena, pena, accel, devid;
-	Usbdev *ud;
+	int bootp, i, kena, pena, accel, devid;
 	Ep *ep;
+	KDev *kd;
+	Usbdev *ud;
 
 	kena = pena = 1;
+	bootp = 0;
 	accel = 0;
 	devid = d->id;
 	ARGBEGIN{
@@ -577,25 +685,43 @@ kbmain(Dev *d, int argc, char* argv[])
 	case 'N':
 		devid = atoi(EARGF(usage()));		/* ignore dev number */
 		break;
+	case 'b':
+		bootp++;
+		break;
 	default:
 		return usage();
 	}ARGEND;
-	if(argc != 0){
+	if(argc != 0)
 		return usage();
-	}
 	USED(devid);
 	ud = d->usb;
 	d->aux = nil;
 	dprint(2, "kb: main: dev %s ref %ld\n", d->dir, d->ref);
+
+	if(kena)
+		for(i = 0; i < nelem(ud->ep); i++)
+			if((ep = ud->ep[i]) == nil)
+				break;
+			else if(ep->iface->csp == KbdCSP)
+				bootp = 1;
+
 	for(i = 0; i < nelem(ud->ep); i++){
 		if((ep = ud->ep[i]) == nil)
 			break;
-		if(kena && ep->type == Eintr && ep->dir == Ein)
-		if(ep->iface->csp == KbdCSP)
-			kbstart(d, ep, &kbdin, kbdwork, accel);
-		if(pena && ep->type == Eintr && ep->dir == Ein)
-		if(ep->iface->csp == PtrCSP)
-			kbstart(d, ep, &ptrin, ptrwork, accel);
+		if(kena && ep->type == Eintr && ep->dir == Ein &&
+		    ep->iface->csp == KbdCSP){
+			kd = d->aux = emallocz(sizeof(KDev), 1);
+			kd->accel = 0;
+			kd->bootp = 1;
+			kbstart(d, ep, &kbdin, kbdwork, kd);
+		}
+		if(pena && ep->type == Eintr && ep->dir == Ein &&
+		    ep->iface->csp == PtrCSP){
+			kd = d->aux = emallocz(sizeof(KDev), 1);
+			kd->accel = accel;
+			kd->bootp = bootp;
+			kbstart(d, ep, &ptrin, ptrwork, kd);
+		}
 	}
 	return 0;
 }

+ 4 - 1
sys/src/cmd/usb/kb/main.c

@@ -16,7 +16,7 @@ enum
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-dkm] [-a n] [-N nb] [dev...]\n", argv0);
+	fprint(2, "usage: %s [-bdkm] [-a n] [-N nb] [dev...]\n", argv0);
 	threadexitsall("usage");
 }
 
@@ -53,6 +53,9 @@ threadmain(int argc, char **argv)
 		devid = atoi(EARGF(usage()));		/* ignore dev number */
 		USED(devid);
 		break;
+	case 'b':
+		as = seprint(as, ae, " -b");
+		break;
 	default:
 		usage();
 	}ARGEND;

+ 3 - 1
sys/src/cmd/usb/kb/mkfile

@@ -2,7 +2,9 @@
 
 TARG=kb
 OFILES=main.$O
-LIBDOFILES=kb.$O
+LIBDOFILES=kb.$O\
+	hid.$O
+
 HFILES=\
 	../lib/usb.h\
 	hid.h\