changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: nusb/kb: always try to recover on error, fix recover for multi-function devices

changeset 4411: b79b383c8ae0
parent 4410: 1d44e3322df1
child 4412: de32ddc1b04b
author: cinap_lenrek@felloff.net
date: Wed, 08 Apr 2015 18:07:16 +0200
files: sys/src/cmd/nusb/kb/kb.c
description: nusb/kb: always try to recover on error, fix recover for multi-function devices

when we get an i/o error, always call hdrecover() which
will reset the port and reinitialize the interface of
the calling processes endpoint.

handle the case when we have multi-function device with
multiple reader procs in hdrecover(). the sequence is
as follows:

1) any of the reader procs encounters i/o error and calls hdrecover(),
acquires qlock and initiates port reset.
2) any other readerprocs will now encounter i/o error (due to reset) and also call
hdrecover() but will be waiting on the qlock for reset to complete.
3) first process completes reset and reinitializes its interface with setproto()
and then releases the qlock for the other readers todo the same.
     1.1--- a/sys/src/cmd/nusb/kb/kb.c
     1.2+++ b/sys/src/cmd/nusb/kb/kb.c
     1.3@@ -346,27 +346,6 @@ setleds(Hiddev* f, int, uchar leds)
     1.4 	return usbcmd(f->dev, Rh2d|Rclass|Riface, Setreport, Reportout, 0, &leds, 1);
     1.5 }
     1.6 
     1.7-/*
     1.8- * Try to recover from a babble error. A port reset is the only way out.
     1.9- * BUG: we should be careful not to reset a bundle with several devices.
    1.10- */
    1.11-static void
    1.12-hdrecover(Hiddev *f)
    1.13-{
    1.14-	int i;
    1.15-
    1.16-	close(f->dev->dfd);		/* it's for usbd now */
    1.17-	devctl(f->dev, "reset");
    1.18-	for(i = 0; i < 10; i++){
    1.19-		sleep(500);
    1.20-		if(opendevdata(f->dev, ORDWR) >= 0){
    1.21-			setproto(f, f->ep->id);
    1.22-			break;
    1.23-		}
    1.24-		/* else usbd still working... */
    1.25-	}
    1.26-}
    1.27-
    1.28 static void
    1.29 hdfree(Hiddev *f)
    1.30 {
    1.31@@ -395,6 +374,35 @@ hdfatal(Hiddev *f, char *sts)
    1.32 }
    1.33 
    1.34 static void
    1.35+hdrecover(Hiddev *f)
    1.36+{
    1.37+	char err[ERRMAX];
    1.38+	static QLock l;
    1.39+	int i;
    1.40+
    1.41+	if(canqlock(&l)){
    1.42+		close(f->dev->dfd);
    1.43+		devctl(f->dev, "reset");
    1.44+		for(i=0; i<4; i++){
    1.45+			sleep(500);
    1.46+			if(opendevdata(f->dev, ORDWR) >= 0)
    1.47+				goto Resetdone;
    1.48+		}
    1.49+		threadexitsall(err);
    1.50+	} else {
    1.51+		/* wait for reset to complete */
    1.52+		qlock(&l);
    1.53+	}
    1.54+Resetdone:
    1.55+	if(setproto(f, f->ep->id) < 0){
    1.56+		rerrstr(err, sizeof(err));
    1.57+		qunlock(&l);
    1.58+		hdfatal(f, err);
    1.59+	}
    1.60+	qunlock(&l);
    1.61+}
    1.62+
    1.63+static void
    1.64 putscan(Hiddev *f, uchar sc, uchar up)
    1.65 {
    1.66 	uchar s[2] = {SCesc1, 0};
    1.67@@ -614,10 +622,9 @@ readerproc(void* a)
    1.68 				rerrstr(err, sizeof(err));
    1.69 			else
    1.70 				strcpy(err, "zero read");
    1.71-			if(++nerrs < 3){
    1.72-				fprint(2, "%s: hid: %s: read: %s\n", argv0, f->ep->dir, err);
    1.73-				if(strstr(err, "babble") != 0)
    1.74-					hdrecover(f);
    1.75+			fprint(2, "%s: hid: %s: read: %s\n", argv0, f->ep->dir, err);
    1.76+			if(++nerrs <= 3){
    1.77+				hdrecover(f);
    1.78 				continue;
    1.79 			}
    1.80 			hdfatal(f, err);