summaryrefslogtreecommitdiff
path: root/sys/src/cmd/nusb
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2015-04-08 18:07:16 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2015-04-08 18:07:16 +0200
commitadfb8dff26976e201208f3f8ddc3cdc1d34cd8cb (patch)
tree1130e44b9e6f1d85a5f374bd3969d1051e68dd1b /sys/src/cmd/nusb
parentfcd45e0cdd0591e11b876da4f378c0474c21475f (diff)
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.
Diffstat (limited to 'sys/src/cmd/nusb')
-rw-r--r--sys/src/cmd/nusb/kb/kb.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/sys/src/cmd/nusb/kb/kb.c b/sys/src/cmd/nusb/kb/kb.c
index 4f951a6e3..6cddac721 100644
--- a/sys/src/cmd/nusb/kb/kb.c
+++ b/sys/src/cmd/nusb/kb/kb.c
@@ -346,27 +346,6 @@ setleds(Hiddev* f, int, uchar leds)
return usbcmd(f->dev, Rh2d|Rclass|Riface, Setreport, Reportout, 0, &leds, 1);
}
-/*
- * 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.
- */
-static void
-hdrecover(Hiddev *f)
-{
- int i;
-
- close(f->dev->dfd); /* it's for usbd now */
- devctl(f->dev, "reset");
- for(i = 0; i < 10; i++){
- sleep(500);
- if(opendevdata(f->dev, ORDWR) >= 0){
- setproto(f, f->ep->id);
- break;
- }
- /* else usbd still working... */
- }
-}
-
static void
hdfree(Hiddev *f)
{
@@ -395,6 +374,35 @@ hdfatal(Hiddev *f, char *sts)
}
static void
+hdrecover(Hiddev *f)
+{
+ char err[ERRMAX];
+ static QLock l;
+ int i;
+
+ if(canqlock(&l)){
+ close(f->dev->dfd);
+ devctl(f->dev, "reset");
+ for(i=0; i<4; i++){
+ sleep(500);
+ if(opendevdata(f->dev, ORDWR) >= 0)
+ goto Resetdone;
+ }
+ threadexitsall(err);
+ } else {
+ /* wait for reset to complete */
+ qlock(&l);
+ }
+Resetdone:
+ if(setproto(f, f->ep->id) < 0){
+ rerrstr(err, sizeof(err));
+ qunlock(&l);
+ hdfatal(f, err);
+ }
+ qunlock(&l);
+}
+
+static void
putscan(Hiddev *f, uchar sc, uchar up)
{
uchar s[2] = {SCesc1, 0};
@@ -614,10 +622,9 @@ readerproc(void* a)
rerrstr(err, sizeof(err));
else
strcpy(err, "zero read");
- if(++nerrs < 3){
- fprint(2, "%s: hid: %s: read: %s\n", argv0, f->ep->dir, err);
- if(strstr(err, "babble") != 0)
- hdrecover(f);
+ fprint(2, "%s: hid: %s: read: %s\n", argv0, f->ep->dir, err);
+ if(++nerrs <= 3){
+ hdrecover(f);
continue;
}
hdfatal(f, err);