Browse Source

Plan 9 from Bell Labs 2011-02-08

David du Colombier 13 years ago
parent
commit
a2be2b198f

+ 0 - 0
dist/replica/from-scratch/plan9.db


+ 0 - 0
dist/replica/from-scratch/plan9.log


+ 1 - 1
rc/bin/patch/okay

@@ -9,6 +9,6 @@ if(! ~ $#* 1){
 i=$1
 if(! test -s $i/files || ! test -s $i/readme)
 	exit 'missing files'
-if(grep -v '^/[_a-zA-Z0-9.\-+/]+ [_a-zA-Z0-9.\-+]+$' $i/files)
+if(grep -v '^/[_a-zA-Z0-9.\-+/:]+ [_a-zA-Z0-9.\-+:]+$' $i/files)
 	exit 'bad file list' 
 exit 0

+ 0 - 2
rc/bin/usbfat:

@@ -63,8 +63,6 @@ for(d in $disks){
 				}
 			}
 		}
-		if not
-			echo $d does not exist >[1=2]
 	}
 }
 exit ''

+ 0 - 46
sys/src/9/kw/devtab.c

@@ -1,46 +0,0 @@
-/*
- * Stub.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-
-extern Dev* devtab[];
-
-void
-devtabreset(void)
-{
-	int i;
-
-	for(i = 0; devtab[i] != nil; i++) {
-		if (devtab[i]->reset == nil)
-			panic("corrupt memory: nil devtab[%d]->reset", i);
-		devtab[i]->reset();
-	}
-}
-
-void
-devtabinit(void)
-{
-	int i;
-
-	for(i = 0; devtab[i] != nil; i++)
-		devtab[i]->init();
-}
-
-void
-devtabshutdown(void)
-{
-	int i;
-
-	/*
-	 * Shutdown in reverse order.
-	 */
-	for(i = 0; devtab[i] != nil; i++)
-		;
-	for(i--; i >= 0; i--)
-		devtab[i]->shutdown();
-}

+ 10 - 24
sys/src/9/kw/devusb.c

@@ -1,5 +1,5 @@
 /*
- * USB device driver.
+ * USB device driver framework.
  *
  * This is in charge of providing access to actual HCIs
  * and providing I/O to the various endpoints of devices.
@@ -36,7 +36,6 @@
  * a generic controller driver, the problem is that details
  * regarding how to handle toggles, tokens, Tds, etc. will
  * get in the way. Thus, code is probably easier the way it is.
- *
  */
 
 #include	"u.h"
@@ -126,7 +125,7 @@ static Cmdtab epctls[] =
 	{CMpollival,	"pollival",	2},
 	{CMsamplesz,	"samplesz",	2},
 	{CMhz,		"hz",		2},
-	{CMinfo,		"info",		0},
+	{CMinfo,	"info",		0},
 	{CMdetach,	"detach",	1},
 	{CMaddress,	"address",	1},
 	{CMdebugep,	"debug",	2},
@@ -179,8 +178,7 @@ static int	usbidgen;	/* device address generator */
 char*
 seprintdata(char *s, char *se, uchar *d, int n)
 {
-	int i;
-	int l;
+	int i, l;
 
 	s = seprint(s, se, " %#p[%d]: ", d, n);
 	l = n;
@@ -1067,11 +1065,7 @@ usbread(Chan *c, void *a, long n, vlong offset)
 static long
 pow2(int n)
 {
-	long v;
-
-	for(v = 1; n > 0; n--)
-		v *= 2;
-	return v;
+	return 1 << n;
 }
 
 static void
@@ -1083,8 +1077,6 @@ setmaxpkt(Ep *ep, char* s)
 		spp = (ep->hz * ep->pollival * ep->ntds + 7999) / 8000;
 	else
 		spp = (ep->hz * ep->pollival + 999) / 1000;
-	assert(spp != 0);
-	assert(ep->samplesz != 0);	
 	ep->maxpkt = spp * ep->samplesz;
 	deprint("usb: %s: setmaxpkt: hz %ld poll %ld"
 		" ntds %d %s speed -> spp %ld maxpkt %ld\n", s,
@@ -1104,18 +1096,13 @@ setmaxpkt(Ep *ep, char* s)
 static long
 epctl(Ep *ep, Chan *c, void *a, long n)
 {
-	static char *Info = "info ";
+	int i, l, mode, nb, tt;
+	char *b, *s;
+	Cmdbuf *cb;
+	Cmdtab *ct;
 	Ep *nep;
 	Udev *d;
-	int l;
-	char *s;
-	char *b;
-	int tt;
-	int i;
-	int mode;
-	int nb;
-	Cmdtab *ct;
-	Cmdbuf *cb;
+	static char *Info = "info ";
 
 	d = ep->dev;
 
@@ -1392,9 +1379,8 @@ ctlwrite(Chan *c, void *a, long n)
 static long
 usbwrite(Chan *c, void *a, long n, vlong off)
 {
-	int q;
+	int nr, q;
 	Ep *ep;
-	int nr;
 
 	if(c->qid.type == QTDIR)
 		error(Eisdir);

+ 1 - 1
sys/src/9/kw/ether1116.c

@@ -1,5 +1,5 @@
 /*
- * marvell kirkwood ethernet (88e1116 and 88e1121) driver
+ * marvell kirkwood gigabit ethernet (88e1116 and 88e1121) driver
  * (as found in the sheevaplug, openrd and guruplug).
  * the main difference is the flavour of phy kludgery necessary.
  *

+ 0 - 6
sys/src/9/kw/fns.h

@@ -76,12 +76,6 @@ extern int tas(void *);
 extern u32int ttbget(void);
 extern void ttbput(u32int);
 
-Dev*		devtabget(int, int);
-void		devtabinit(void);
-void		devtabreset(void);
-long		devtabread(Chan*, void*, long, vlong);
-void		devtabshutdown(void);
-
 extern void intrclear(int sort, int v);
 extern void intrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name);
 extern void intrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name);

+ 3 - 0
sys/src/9/kw/lexception.s

@@ -39,6 +39,7 @@ TEXT _vsvc(SB), 1, $-4			/* SWI */
 	MOVW	$PsrMsvc, R14		/* ureg->type = PsrMsvc */
 	MOVW.W	R14, -4(R13)		/* ... */
 
+	/* avoid the ambiguity described in notes/movm.w. */
 //	MOVM.DB.W.S [R0-R14], (R13)	/* save user level registers, at end r13 points to ureg */
 	MOVM.DB.S [R0-R14], (R13)	/* save user level registers */
 	SUB	$(15*4), R13		/* r13 now points to ureg */
@@ -108,6 +109,7 @@ _vswitch:
 	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
 
 	/*
+	 * avoid the ambiguity described in notes/movm.w.
 	 * In order to get a predictable value in R13 after the stores,
 	 * separate the store-multiple from the stack-pointer adjustment.
 	 * We'll assume that the old value of R13 should be stored on the stack.
@@ -140,6 +142,7 @@ _userexcep:
 	MOVM.DB.W [R0-R2], (R13)	/* set ureg->{type, psr, pc}; r13 points to ureg->type  */
 	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
 
+	/* avoid the ambiguity described in notes/movm.w. */
 //	MOVM.DB.W.S [R0-R14], (R13)	/* save kernel level registers, at end r13 points to ureg */
 	MOVM.DB.S [R0-R14], (R13)	/* save kernel level registers */
 	SUB	$(15*4), R13		/* r13 now points to ureg */

+ 12 - 3
sys/src/9/kw/lproc.s

@@ -12,7 +12,10 @@
 TEXT touser(SB), 1, $-4
 	/* store the user stack pointer into the USR_r13 */
 	MOVM.DB.W [R0], (R13)
-	MOVM.S.IA.W (R13), [R13]
+	/* avoid the ambiguity described in notes/movm.w. */
+//	MOVM.S.IA.W (R13), [R13]
+	MOVM.S	(R13), [R13]
+	ADD	$4, R13
 
 	/* set up a PSR for user level */
 	MOVW	$(PsrMusr), R0
@@ -22,8 +25,14 @@ TEXT touser(SB), 1, $-4
 	MOVW	$(UTZERO+0x20), R0
 	MOVM.DB.W [R0], (R13)
 
-	/* return from interrupt */
-	RFE				/* MOVM.IA.S.W (R13), [R15] */
+	/*
+	 * note that 5a's RFE is not the v6 arch. instruction (0xe89d0a00,
+	 * I think), which loads CPSR from the word after the PC at (R13),
+	 * but rather the pre-v6 simulation `MOVM.IA.S.W (R13), [R15]'
+	 * (0xe8fd8000 since MOVM is LDM in this case), which loads CPSR
+	 * not from memory but from SPSR due to `.S'.
+	 */
+	RFE
 
 /*
  *  here to jump to a newly forked process

+ 2 - 2
sys/src/9/kw/main.c

@@ -410,7 +410,7 @@ reboot(void *entry, void *code, ulong size)
 	serialoq = nil;
 
 	/* shutdown devices */
-	devtabshutdown();
+	chandevshutdown();
 
 	/* call off the dog */
 	clockshutdown();
@@ -461,7 +461,7 @@ init0(void)
 	up->slash->path = newpath("/");
 	up->dot = cclone(up->slash);
 
-	devtabinit();
+	chandevinit();
 
 	if(!waserror()){
 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);

+ 0 - 1
sys/src/9/kw/mkfile

@@ -19,7 +19,6 @@ PORT=\
 	cache.$O\
 	chan.$O\
 	dev.$O\
-	devtab.$O\
 	edf.$O\
 	fault.$O\
 	latin1.$O\

+ 22 - 0
sys/src/9/kw/notes/movm.w

@@ -0,0 +1,22 @@
+gorka writes:
+---
+I have userspace on the gumstix [xscale, not omap].  The problem that
+got me in trouble was that in lexception.s (or l.s),
+
+	MOVM.DB.W [R0-R14], (R13)
+
+works differently for this architecture (and probably for others, as
+it is unclear how it should behave by reading the arm specs).  This
+happens only for kernel faults as the others (syscall, user faults)
+use MOVM.DB.W.S which uses the banked user registers.
+
+The problem is that in this arch the value of R13 saved is the value
+after R13 itself has been modified, whereas in the others (bitsy,
+pico...), it was the value before.  Adding 4*15 to the stack before
+the RFE solves the problem.
+---
+
+In fact, the 2005 ARM arch. ref. man. (ARM DDI 0100I) says, under STM (1),
+that if Rn appears in the set of registers (and isn't the first one)
+and .W is specified, the stored value of Rn is unpredictable.
+The arm v7-ar arch. ref. man. says such usage is obsolete.

+ 2 - 3
sys/src/9/omap/devusb.c

@@ -164,7 +164,7 @@ static char *spname[] =
 	[Nospeed]	"no",
 };
 
-static int	debug = 0;
+static int	debug;
 static Hcitype	hcitypes[Nhcis];
 static Hci*	hcis[Nhcis];
 static QLock	epslck;		/* add, del, lookup endpoints */
@@ -669,7 +669,7 @@ hciprobe(int cardno, int ctlrno)
 	hp = mallocz(sizeof(Hci), 1);
 	hp->ctlrno = ctlrno;
 
-	if(cardno < 0){
+	if(cardno < 0)
 		for(cardno = 0; cardno < Nhcis; cardno++){
 			if(hcitypes[cardno].type == nil)
 				break;
@@ -679,7 +679,6 @@ hciprobe(int cardno, int ctlrno)
 			if(cistrcmp(hcitypes[cardno].type, type) == 0)
 				break;
 		}
-	}
 
 	if(cardno >= Nhcis || hcitypes[cardno].type == nil){
 		free(hp);

+ 7 - 2
sys/src/9/omap/lexception.s

@@ -26,7 +26,8 @@ TEXT vtable(SB), 1, $-4
 	WORD	$_vdabt(SB)		/* data abort, switch to svc mode */
 	WORD	$_vsvc(SB)		/* reserved */
 	WORD	$_virq(SB)		/* IRQ, switch to svc mode */
-	WORD	$_vfiq(SB)		/* FIQ, switch to svc mode */
+//	WORD	$_vfiq(SB)		/* FIQ, switch to svc mode */
+	WORD	$_virq(SB)		/* FIQ, switch to svc mode */
 
 TEXT _vrst(SB), 1, $-4
 	BL	_reset(SB)
@@ -38,12 +39,14 @@ TEXT _vsvc(SB), 1, $-4			/* SWI */
 	MOVW	$PsrMsvc, R14		/* ureg->type = PsrMsvc */
 	MOVW.W	R14, -4(R13)		/* ... */
 
+	/* avoid the ambiguity described in notes/movm.w. */
 //	MOVM.DB.W.S [R0-R14], (R13)	/* save user level registers, at end r13 points to ureg */
 	MOVM.DB.S [R0-R14], (R13)	/* save user level registers */
 	SUB	$(15*4), R13		/* r13 now points to ureg */
 
 	MOVW	$setR12(SB), R12	/* Make sure we've got the kernel's SB loaded */
 
+//	MOVW	$(KSEG0+16*KiB-MACHSIZE), R10	/* m */
 	MOVW	$(L1-MACHSIZE), R10	/* m */
 	MOVW	8(R10), R9		/* up */
 
@@ -106,6 +109,7 @@ _vswitch:
 	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
 
 	/*
+	 * avoid the ambiguity described in notes/movm.w.
 	 * In order to get a predictable value in R13 after the stores,
 	 * separate the store-multiple from the stack-pointer adjustment.
 	 * We'll assume that the old value of R13 should be stored on the stack.
@@ -138,12 +142,14 @@ _userexcep:
 	MOVM.DB.W [R0-R2], (R13)	/* set ureg->{type, psr, pc}; r13 points to ureg->type  */
 	MOVM.IA	  (R3), [R0-R4]		/* restore [R0-R4] from previous mode's stack */
 
+	/* avoid the ambiguity described in notes/movm.w. */
 //	MOVM.DB.W.S [R0-R14], (R13)	/* save kernel level registers, at end r13 points to ureg */
 	MOVM.DB.S [R0-R14], (R13)	/* save kernel level registers */
 	SUB	$(15*4), R13		/* r13 now points to ureg */
 
 	MOVW	$setR12(SB), R12	/* Make sure we've got the kernel's SB loaded */
 
+//	MOVW	$(KSEG0+16*KiB-MACHSIZE), R10	/* m */
 	MOVW	$(L1-MACHSIZE), R10	/* m */
 	MOVW	8(R10), R9		/* up */
 
@@ -161,7 +167,6 @@ _userexcep:
 	RFE				/* MOVM.IA.S.W (R13), [R15] */
 
 TEXT _vfiq(SB), 1, $-4			/* FIQ */
-WAVE('%')
 	RFE				/* FIQ is special, ignore it for now */
 
 /*

+ 12 - 3
sys/src/9/omap/lproc.s

@@ -12,7 +12,10 @@
 TEXT touser(SB), 1, $-4
 	/* store the user stack pointer into the USR_r13 */
 	MOVM.DB.W [R0], (R13)
-	MOVM.S.IA.W (R13), [R13]
+	/* avoid the ambiguity described in notes/movm.w. */
+//	MOVM.S.IA.W (R13), [R13]
+	MOVM.S	(R13), [R13]
+	ADD	$4, R13
 
 	/* set up a PSR for user level */
 	MOVW	$(PsrMusr), R0
@@ -22,8 +25,14 @@ TEXT touser(SB), 1, $-4
 	MOVW	$(UTZERO+0x20), R0
 	MOVM.DB.W [R0], (R13)
 
-	/* return from interrupt */
-	RFE				/* MOVM.IA.S.W (R13), [R15] */
+	/*
+	 * note that 5a's RFE is not the v6 arch. instruction (0xe89d0a00,
+	 * I think), which loads CPSR from the word after the PC at (R13),
+	 * but rather the pre-v6 simulation `MOVM.IA.S.W (R13), [R15]'
+	 * (0xe8fd8000 since MOVM is LDM in this case), which loads CPSR
+	 * not from memory but from SPSR due to `.S'.
+	 */
+	RFE
 
 /*
  *  here to jump to a newly forked process

+ 22 - 0
sys/src/9/omap/notes/movm.w

@@ -0,0 +1,22 @@
+gorka writes:
+---
+I have userspace on the gumstix [xscale, not omap].  The problem that
+got me in trouble was that in lexception.s (or l.s),
+
+	MOVM.DB.W [R0-R14], (R13)
+
+works differently for this architecture (and probably for others, as
+it is unclear how it should behave by reading the arm specs).  This
+happens only for kernel faults as the others (syscall, user faults)
+use MOVM.DB.W.S which uses the banked user registers.
+
+The problem is that in this arch the value of R13 saved is the value
+after R13 itself has been modified, whereas in the others (bitsy,
+pico...), it was the value before.  Adding 4*15 to the stack before
+the RFE solves the problem.
+---
+
+In fact, the 2005 ARM arch. ref. man. (ARM DDI 0100I) says, under STM (1),
+that if Rn appears in the set of registers (and isn't the first one)
+and .W is specified, the stored value of Rn is unpredictable.
+The arm v7-ar arch. ref. man. says such usage is obsolete.

+ 0 - 120
sys/src/9/pc/devkbin.c

@@ -1,120 +0,0 @@
-/*
- *  keyboard scan code input from outside the kernel.
- *  to avoid duplication of keyboard map processing for usb.
- */
-
-#include	"u.h"
-#include	"../port/lib.h"
-#include	"mem.h"
-#include	"dat.h"
-#include	"fns.h"
-#include	"../port/error.h"
-
-extern	void kbdputsc(int, int);
-
-enum {
-	Qdir,
-	Qkbd,
-};
-
-Dirtab kbintab[] = {
-	".",	{Qdir, 0, QTDIR},	0,	0555,
-	"kbin",	{Qkbd, 0},		0,	0200,
-};
-
-Lock	kbinlck;
-int	kbinbusy;
-
-static Chan *
-kbinattach(char *spec)
-{
-	return devattach(L'Ι', spec);
-}
-
-static Walkqid*
-kbinwalk(Chan *c, Chan *nc, char **name, int nname)
-{
-	return devwalk(c, nc, name, nname, kbintab, nelem(kbintab), devgen);
-}
-
-static int
-kbinstat(Chan *c, uchar *dp, int n)
-{
-	return devstat(c, dp, n, kbintab, nelem(kbintab), devgen);
-}
-
-static Chan*
-kbinopen(Chan *c, int omode)
-{
-	if(!iseve())
-		error(Eperm);
-	if(c->qid.path == Qkbd){
-		lock(&kbinlck);
-		if(kbinbusy){
-			unlock(&kbinlck);
-			error(Einuse);
-		}
-		kbinbusy++;
-		unlock(&kbinlck);
-	}
-	return devopen(c, omode, kbintab, nelem(kbintab), devgen);
-}
-
-static void
-kbinclose(Chan *c)
-{
-	if(c->aux){
-		free(c->aux);
-		c->aux = nil;
-	}
-	if(c->qid.path == Qkbd)
-		kbinbusy = 0;
-}
-
-static long
-kbinread(Chan *c, void *a, long n, vlong )
-{
-	if(c->qid.type == QTDIR)
-		return devdirread(c, a, n, kbintab, nelem(kbintab), devgen);
-	return 0;
-}
-
-static long
-kbinwrite(Chan *c, void *a, long n, vlong)
-{
-	int i;
-	uchar *p = a;
-
-	if(c->qid.type == QTDIR)
-		error(Eisdir);
-	switch((int)c->qid.path){
-	case Qkbd:
-		for(i = 0; i < n; i++)
-			kbdputsc(*p++, 1);	/* external source */
-		break;
-	default:
-		error(Egreg);
-	}
-	return n;
-}
-
-Dev kbindevtab = {
-	L'Ι',
-	"kbin",
-
-	devreset,
-	devinit,
-	devshutdown,
-	kbinattach,
-	kbinwalk,
-	kbinstat,
-	kbinopen,
-	devcreate,
-	kbinclose,
-	kbinread,
-	devbread,
-	kbinwrite,
-	devbwrite,
-	devremove,
-	devwstat,
-};

+ 0 - 0
sys/src/9/omap/devkbin.c → sys/src/9/port/devkbin.c


+ 23 - 6
sys/src/cmd/usb/serial/ftdi.c

@@ -685,7 +685,7 @@ cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz)
 static void
 epreader(void *u)
 {
-	int dfd, rcount, cl;
+	int dfd, rcount, cl, ntries, recov;
 	char err[40];
 	Areader *a;
 	Channel *c;
@@ -700,20 +700,30 @@ epreader(void *u)
 	c = a->c;
 	free(a);
 
-	qlock(ser);
+	qlock(ser);	/* this makes the reader wait end of initialization too */
 	dfd = p->epin->dfd;
 	qunlock(ser);
 
+	ntries = 0;
 	pk = nil;
 	do {
 		if (pk == nil)
 			pk = emallocz(sizeof(Packser), 1);
+Eagain:
 		rcount = read(dfd, pk->b, sizeof pk->b);
 		if(serialdebug > 5)
 			dsprint(2, "%d %#ux%#ux ", rcount, p->data[0],
 				p->data[1]);
-		if(rcount < 0)
-			break;
+
+		if(rcount < 0){
+			if(ntries++ > 100)
+				break;
+			qlock(ser);
+			recov = serialrecover(ser, p, nil, "epreader: bulkin error");
+			qunlock(ser);
+			if(recov >= 0)
+				goto Eagain;
+		}
 		if(rcount == 0)
 			continue;
 		if(rcount >= ser->inhdrsz){
@@ -731,6 +741,10 @@ epreader(void *u)
 				}
 			}else
 				free(pk);
+			qlock(ser);
+			ser->recover = 0;
+			qunlock(ser);
+			ntries = 0;
 			pk = nil;
 		}
 	} while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil));
@@ -794,11 +808,14 @@ statusreader(void *u)
 }
 
 static int
-ftreset(Serial *ser)
+ftreset(Serial *ser, Serialport *p)
 {
-	Serialport *p;
 	int i;
 
+	if(p != nil){
+		ftdiwrite(p, FTRESETCTLVAL, 0, FTRESET);
+		return 0;
+	}
 	p = ser->p;
 	for(i = 0; i < Maxifc; i++)
 		if(p[i].s != nil)

+ 1 - 1
sys/src/cmd/usb/serial/prolific.c

@@ -372,7 +372,7 @@ plreadstatus(Serialport *p)
 
 	if(nr < 0 && strstr(err, "timed out") == nil){
 		dsprint(2, "serial: need to recover, status read %d %r\n", nr);
-		if(serialrecover(ser, err) < 0){
+		if(serialrecover(ser, nil, nil, err) < 0){
 			qunlock(ser);
 			return -1;
 		}

+ 49 - 14
sys/src/cmd/usb/serial/serial.c

@@ -81,35 +81,64 @@ serialdrain(Serialport *p)
 		ser->clearpipes(p);
 }
 
-/* BUG: separate reset per port */
 int
 serialreset(Serial *ser)
 {
 	Serialport *p;
-	int i;
+	int i, res;
 
+	res = 0;
 	/* cmd for reset */
 	for(i = 0; i < ser->nifcs; i++){
 		p = &ser->p[i];
 		serialdrain(p);
 	}
 	if(ser->reset != nil)
-		ser->reset(ser);
-	return 0;
+		res = ser->reset(ser, nil);
+	return res;
 }
 
-/* call this if something goes wrong */
+/* call this if something goes wrong, must be qlocked */
 int
-serialrecover(Serial *ser, char *err)
+serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err)
 {
+	if(p != nil)
+		dprint(2, "serial[%d], %s: %s, level %d\n", p->interfc,
+			p->name, err, ser->recover);
+	else
+		dprint(2, "serial[%s], global error, level %d\n",
+			ser->p[0].name, ser->recover);
+	ser->recover++;
 	if(strstr(err, "detached") != nil)
 		return -1;
-	if(ser->recover > 1)
+	if(ser->recover < 3){
+		if(ep != nil){
+			if(p->epintr != nil && ep == p->epintr)
+				unstall(ser->dev, p->epintr, Ein);
+			if(p->epin != nil && ep == p->epin)
+				unstall(ser->dev, p->epin, Ein);
+			if(p->epout != nil && ep == p->epout)
+				unstall(ser->dev, p->epout, Eout);
+			return 0;
+		}
+		if(p != nil){
+			if(p->epintr != nil)
+				unstall(ser->dev, p->epintr, Ein);
+			if(p->epin != nil)
+				unstall(ser->dev, p->epin, Ein);
+			if(p->epout != nil)
+				unstall(ser->dev, p->epout, Eout);
+		}
+		return 0;
+	}
+	if(ser->recover > 4 && ser->recover < 8)
 		serialfatal(ser);
-	ser->recover++;
+	if(ser->recover > 8){
+		ser->reset(ser, p);
+		return 0;
+	}
 	if(serialreset(ser) < 0)
 		return -1;
-	ser->recover = 0;
 	return 0;
 }
 
@@ -238,7 +267,7 @@ serialctl(Serialport *p, char *cmd)
 			else
 				nw = write(p->epout->dfd, &x, 1);
 			if(nw != 1){
-				serialrecover(ser, "");
+				serialrecover(ser, nil, p->epout, "");
 				return -1;
 			}
 			break;
@@ -260,6 +289,7 @@ serialctl(Serialport *p, char *cmd)
 		if(ser->setparam != nil && ser->setparam(p) < 0)
 			return -1;
 	}
+	ser->recover = 0;
 	return 0;
 }
 
@@ -505,7 +535,7 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
 		if(rcount < 0){
 			dsprint(2, "serial: need to recover, data read %ld %r\n",
 				count);
-			serialrecover(ser, err);
+			serialrecover(ser, nil, p->epin, err);
 		}
 		dsprint(2, "serial: read from bulk %ld\n", rcount);
 		count = rcount;
@@ -521,6 +551,8 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
 		}
 		break;
 	}
+	if(count >= 0)
+		ser->recover = 0;
 	qunlock(ser);
 	free(err);
 	free(buf);
@@ -555,7 +587,7 @@ altwrite(Serialport *p, uchar *buf, long count)
 		dsprint(2, "serial: need to recover, status in write %d %r\n",
 			nw);
 		snprint(err, sizeof err, "%r");
-		serialrecover(p->s, err);
+		serialrecover(p->s, nil, p->epout, err);
 	}
 	return nw;
 }
@@ -596,6 +628,10 @@ dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong)
 		werrstr(Eperm);
 		return -1;
 	}
+	if(count >= 0)
+		ser->recover = 0;
+	else
+		serialrecover(ser, nil, p->epout, "writing");
 	qunlock(ser);
 	return count;
 }
@@ -802,7 +838,6 @@ serialmain(Dev *dev, int argc, char* argv[])
 		werrstr("serial: no serial devices found");
 		return -1;
 	}
-
 	for(i = 0; i < ser->nifcs; i++){
 		p = &ser->p[i];
 		p->interfc = i;
@@ -841,7 +876,7 @@ serialmain(Dev *dev, int argc, char* argv[])
 			else
 				snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i);
 		}
-		fprint(2, "%s\n", p->fs.name);
+		fprint(2, "%s...", p->fs.name);
 		p->fs.dev = dev;
 		incref(dev);
 		p->fs.aux = p;

+ 2 - 2
sys/src/cmd/usb/serial/serial.h

@@ -8,7 +8,7 @@ struct Serialops {
 	int	(*getparam)(Serialport*);
 	int	(*setparam)(Serialport*);
 	int	(*clearpipes)(Serialport*);
-	int	(*reset)(Serial*);
+	int	(*reset)(Serial*, Serialport*);
 	int	(*sendlines)(Serialport*);
 	int	(*modemctl)(Serialport*, int);
 	int	(*setbreak)(Serialport*, int);
@@ -121,6 +121,6 @@ extern int serialdebug;
 
 #define	dsprint	if(serialdebug)fprint
 
-int	serialrecover(Serial *ser, char *err);
+int	serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err);
 int	serialreset(Serial *ser);
 char	*serdumpst(Serialport *p, char *buf, int bufsz);