usb/ 775 0 0 0 11450326605 73375ustar00syssysusb/audio/ 775 0 0 0 11457773434 104555ustar00syssysusb/audio/audio.c 664 0 0 23407 11412732163 11731ustar00syssys/* * USB audio driver for Plan 9 * This needs a full rewrite. * As it is, it does not check for all errors, * mixes the audio data structures with the usb configuration, * may cross nil pointers, and is hard to debug and fix. * Also, it does not issue a dettach request to the endpoint * after the device is unplugged. This means that the old * endpoint would still be around until manually reclaimed. */ #include #include #include #include "usb.h" #include "audio.h" #include "audioctl.h" #define STACKSIZE 16*1024 extern char* srvpost; char * mntpt; Channel *controlchan; int verbose; int setrec = 0; int defaultspeed[2] = {44100, 44100}; Dev *buttondev; Dev *epdev[2]; static void audio_endpoint(Dev *, Desc *dd) { byte *b = (uchar*)&dd->data; int n = dd->data.bLength; char *hd; switch(b[2]){ case 0x01: if(usbdebug){ fprint(2, "CS_ENDPOINT for attributes 0x%x, lockdelayunits %d, lockdelay %#ux, ", b[3], b[4], b[5] | (b[6]<<8)); if(b[3] & has_setspeed) fprint(2, "has sampling-frequency control"); else fprint(2, "does not have sampling-frequency control"); if(b[3] & 0x1<<1) fprint(2, ", has pitch control"); else fprint(2, ", does not have pitch control"); if(b[3] & 0x1<<7) fprint(2, ", max packets only"); fprint(2, "\n"); } if(dd->conf == nil) sysfatal("conf == nil"); if(dd->iface == nil) sysfatal("iface == nil"); if(dd->altc == nil) sysfatal("alt == nil"); if(dd->altc->aux == nil) dd->altc->aux= mallocz(sizeof(Audioalt),1); ((Audioalt*)dd->altc->aux)->caps |= b[3]; break; case 0x02: if(usbdebug){ fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ", b[3], b[4], b[5], b[6], b[7]); fprint(2, "freq0 %d, freq1 %d\n", b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16)); } break; default: if(usbdebug){ hd = hexstr(b, n); fprint(2, "CS_INTERFACE: %s\n", hd); free(hd); } } } enum { None, Volumeset, Volumeget, Altset, Altget, Speedget, }; void controlproc(void *) { /* Proc that looks after /dev/usb/%d/ctl */ int i, nf; char *req, *args[8]; Audiocontrol *c; long value[8]; Channel *replchan; while(req = recvp(controlchan)){ int rec; nf = tokenize(req, args, nelem(args)); if(nf < 3) sysfatal("controlproc: not enough arguments"); replchan = (Channel*)strtol(args[0], nil, 0); if(strcmp(args[2], "playback") == 0) rec = Play; else if(strcmp(args[2], "record") == 0) rec = Record; else{ /* illegal request */ dprint(2, "%s must be record or playback", args[2]); if(replchan) chanprint(replchan, "%s must be record or playback", args[2]); free(req); continue; } c = nil; for(i = 0; i < Ncontrol; i++){ c = &controls[rec][i]; if(strcmp(args[1], c->name) == 0) break; } if(i == Ncontrol){ dprint(2, "Illegal control name: %s", args[1]); if(replchan) chanprint(replchan, "Illegal control name: %s", args[1]); }else if(!c->settable){ dprint(2, "%s %s is not settable", args[1], args[2]); if(replchan) chanprint(replchan, "%s %s is not settable", args[1], args[2]); }else if(nf < 4){ dprint(2, "insufficient arguments for %s %s", args[1], args[2]); if(replchan) chanprint(replchan, "insufficient arguments for %s %s", args[1], args[2]); }else if(ctlparse(args[3], c, value) < 0){ if(replchan) chanprint(replchan, "parse error in %s %s", args[1], args[2]); }else{ dprint(2, "controlproc: setcontrol %s %s %s\n", rec?"in":"out", args[1], args[3]); if(setcontrol(rec, args[1], value) < 0){ if(replchan) chanprint(replchan, "setting %s %s failed", args[1], args[2]); }else{ if(replchan) chanprint(replchan, "ok"); } ctlevent(); } free(req); } } void buttonproc(void *) { int i, fd, b; char err[32]; byte buf[1]; Audiocontrol *c; fd = buttondev->dfd; c = &controls[Play][Volume_control]; for(;;){ if((b = read(fd, buf, 1)) < 0){ rerrstr(err, sizeof err); if(strcmp(err, "interrupted") == 0){ dprint(2, "read interrupted\n"); continue; } sysfatal("read %s/data: %r", buttondev->dir); } if(b == 0 || buf[0] == 0){ continue; }else if(buf[0] == 1){ if(c->chans == 0) c->value[0] += c->step; else for(i = 1; i < 8; i++) if(c->chans & 1 << i) c->value[i] += c->step; chanprint(controlchan, "0 volume playback %A", c); }else if(buf[0] == 2){ if(c->chans == 0) c->value[0] -= c->step; else for(i = 1; i < 8; i++) if(c->chans & 1 << i) c->value[i] -= c->step; chanprint(controlchan, "0 volume playback %A", c); }else if(usbdebug){ fprint(2, "button"); for(i = 0; i < b; i++) fprint(2, " %#2.2x", buf[i]); fprint(2, "\n"); } } } void usage(void) { fprint(2, "usage: usbaudio [-dpV] [-N nb] [-m mountpoint] [-s srvname] " "[-v volume] [dev]\n"); threadexitsall("usage"); } void threadmain(int argc, char **argv) { char *devdir; int i; long value[8], volume[8]; Audiocontrol *c; char *p; extern int attachok; Ep *ep; int csps[] = { Audiocsp, 0}; devdir = nil; volume[0] = Undef; for(i = 0; i<8; i++) value[i] = 0; fmtinstall('A', Aconv); fmtinstall('U', Ufmt); quotefmtinstall(); ARGBEGIN{ case 'N': p = EARGF(usage()); /* ignore dev nb */ break; case 'd': usbdebug++; verbose++; break; case 'm': mntpt = EARGF(usage()); break; case 'p': attachok++; break; case 's': srvpost = EARGF(usage()); break; case 'v': volume[0] = strtol(EARGF(usage()), &p, 0); for(i = 1; i < 8; i++) volume[i] = volume[0]; break; case 'V': verbose++; break; default: usage(); }ARGEND switch(argc){ case 0: break; case 1: devdir = argv[0]; break; default: usage(); } if(devdir == nil) if(finddevs(matchdevcsp, csps, &devdir, 1) < 1){ fprint(2, "No usb audio\n"); threadexitsall("usbaudio not found"); } ad = opendev(devdir); if(ad == nil) sysfatal("opendev: %r"); if(configdev(ad) < 0) sysfatal("configdev: %r"); for(i = 0; i < nelem(ad->usb->ddesc); i++) if(ad->usb->ddesc[i] != nil) switch(ad->usb->ddesc[i]->data.bDescriptorType){ case AUDIO_INTERFACE: audio_interface(ad, ad->usb->ddesc[i]); break; case AUDIO_ENDPOINT: audio_endpoint(ad, ad->usb->ddesc[i]); break; } controlchan = chancreate(sizeof(char*), 8); for(i = 0; i < nelem(ad->usb->ep); i++) if((ep = ad->usb->ep[i]) != nil){ if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Eout) endpt[0] = ep->id; if(ep->iface->csp == CSP(Claudio, 2, 0) && ep->dir == Ein) endpt[1] = ep->id; if(buttonendpt<0 && Class(ep->iface->csp) == Clhid) buttonendpt = ep->id; } if(endpt[0] != -1){ if(verbose) fprint(2, "usb/audio: playback on ep %d\n", endpt[0]); interface[0] = ad->usb->ep[endpt[0]]->iface->id; } if(endpt[1] != -1){ if(verbose) fprint(2, "usb/audio: record on ep %d\n", endpt[0]); interface[1] = ad->usb->ep[endpt[1]]->iface->id; } if(verbose && buttonendpt >= 0) fprint(2, "usb/audio: buttons on ep %d\n", buttonendpt); if(endpt[Play] >= 0){ if(verbose) fprint(2, "Setting default play parameters: %d Hz, %d channels at %d bits\n", defaultspeed[Play], 2, 16); if(findalt(Play, 2, 16, defaultspeed[Play]) < 0){ if(findalt(Play, 2, 16, 48000) < 0) sysfatal("Can't configure playout for %d or %d Hz", defaultspeed[Play], 48000); fprint(2, "Warning, can't configure playout for %d Hz, configuring for %d Hz instead\n", defaultspeed[Play], 48000); defaultspeed[Play] = 48000; } value[0] = 2; if(setcontrol(Play, "channels", value) == Undef) sysfatal("Can't set play channels"); value[0] = 16; if(setcontrol(Play, "resolution", value) == Undef) sysfatal("Can't set play resolution"); } if(endpt[Record] >= 0){ setrec = 1; if(verbose) fprint(2, "Setting default record parameters: " "%d Hz, %d channels at %d bits\n", defaultspeed[Record], 2, 16); i = 2; while(findalt(Record, i, 16, defaultspeed[Record]) < 0) if(i == 2 && controls[Record][Channel_control].max == 1){ fprint(2, "Warning, can't configure stereo " "recording, configuring mono instead\n"); i = 1; }else break; if(findalt(Record, i, 16, 48000) < 0){ endpt[Record] = -1; /* disable recording */ setrec = 0; fprint(2, "Warning, can't configure record for %d Hz or %d Hz\n", defaultspeed[Record], 48000); }else fprint(2, "Warning, can't configure record for %d Hz, " "configuring for %d Hz instead\n", defaultspeed[Record], 48000); defaultspeed[Record] = 48000; if(setrec){ value[0] = i; if(setcontrol(Record, "channels", value) == Undef) sysfatal("Can't set record channels"); value[0] = 16; if(setcontrol(Record, "resolution", value) == Undef) sysfatal("Can't set record resolution"); } } getcontrols(); /* Get the initial value of all controls */ value[0] = defaultspeed[Play]; if(endpt[Play] >= 0 && setcontrol(Play, "speed", value) < 0) sysfatal("can't set play speed"); value[0] = defaultspeed[Record]; if(endpt[Record] >= 0 && setcontrol(Record, "speed", value) < 0) fprint(2, "%s: can't set record speed\n", argv0); value[0] = 0; setcontrol(Play, "mute", value); if(volume[0] != Undef){ c = &controls[Play][Volume_control]; if(*p == '%' && c->min != Undef) for(i = 0; i < 8; i++) volume[i] = (volume[i]*c->max + (100-volume[i])*c->min)/100; if(c->settable) setcontrol(Play, "volume", volume); c = &controls[Record][Volume_control]; if(c->settable && setrec) setcontrol(Record, "volume", volume); } if(buttonendpt > 0){ buttondev = openep(ad, buttonendpt); if(buttondev == nil) sysfatal("openep: buttons: %r"); if(opendevdata(buttondev, OREAD) < 0) sysfatal("open buttons fd: %r"); proccreate(buttonproc, nil, STACKSIZE); } proccreate(controlproc, nil, STACKSIZE); proccreate(serve, nil, STACKSIZE); threadexits(nil); } 00syssysusb/audio/audio.h 664 0 0 4002 11202312257 11677ustar00syssysenum { master_chan = 0x00, Speed_control = 0x00, /* Items below are defined by USB standard: */ Mute_control = 0x01, Volume_control = 0x02, Bass_control = 0x03, Mid_control = 0x04, Treble_control = 0x05, Equalizer_control = 0x06, Agc_control = 0x07, Delay_control = 0x08, Bassboost_control = 0x09, Loudness_control = 0x0a, /* Items below are defined by implementation: */ Channel_control = 0x0b, Resolution_control = 0x0c, Ncontrol, Selector_control = 0x0d, sampling_freq_control = 0x01, Audiocsp = 0x000101, /* audio.control.0 */ AUDIO_INTERFACE = 0x24, AUDIO_ENDPOINT = 0x25, }; #define AS_GENERAL 1 #define FORMAT_TYPE 2 #define FORMAT_SPECIFIC 3 #define PCM 1 #define PCM8 2 #define IEEE_FLOAT 3 #define ALAW 4 #define MULAW 5 #define SAMPLING_FREQ_CONTROL 0x01 typedef struct Audioalt Audioalt; struct Audioalt { int nchan; int res; int subframesize; int minfreq, maxfreq; /* continuous freqs */ int freqs[8]; /* discrete freqs */ int caps; /* see below for meanings */ }; enum { /* Audioalt->caps bits */ has_setspeed = 0x1, /* has a speed_set command */ has_pitchset = 0x2, /* has a pitch_set command */ has_contfreq = 0x4, /* frequency continuously variable */ has_discfreq = 0x8, /* discrete set of frequencies */ onefreq = 0x10, /* only one frequency */ maxpkt_only = 0x80, /* packets must be padded to max size */ }; typedef uchar byte; extern int setrec; extern int verbose; extern int defaultspeed[2]; extern Dev *ad; extern Dev *buttondev; extern Channel *controlchan; extern Dev *epdev[2]; void audio_interface(Dev *d, Desc *dd); void setalt(Dev *d, int endpt, int value); int getalt(Dev *d, int endpt); int setspeed(int rec, int speed); int setcontrol(int rec, char *name, long *value); int getspecialcontrol(int rec, int ctl, int req, long *value); int getcontrol(int rec, char *name, long *value); int findalt(int rec, int nchan, int res, int speed); void getcontrols(void); void serve(void *); int nbchanprint(Channel *c, char *fmt, ...); int Aconv(Fmt *fp); /* illegal request */ dprint(2, "%s must be record or playback", args[2]); if(replchan) chanprint(replchan, "%s must be record or playback", args[2]); free(req); continue; } c = nil; for(i = 0; i < Ncontrol; i++){ c = &controls[rec][i]; if(strcmp(args[1], c->name) == 0) break; } if(i == Ncontrol){ dprint(2, "Illegal control name: %s", args[1]); if(replchan) chanprint(replchan, "Illegal control name: %s", args[1]); }else if(!c->settable){ dprint(2, "%s %s is not susb/audio/audioctl.c 664 0 0 42706 11202312257 12432ustar00syssys#include #include #include #include "usb.h" #include "audio.h" #include "audioctl.h" int endpt[2] = {-1, -1}; int interface[2] = {-1, -1}; int featureid[2] = {-1, -1}; int selectorid[2] = {-1, -1}; int mixerid[2] = {-1, -1}; int curalt[2] = {-1, -1}; int buttonendpt = -1; int id; Dev *ad; Audiocontrol controls[2][Ncontrol] = { { [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, [Mid_control] = { "mid", 0, {0}, 0, 0, Undef}, [Treble_control] = { "treble", 0, {0}, 0, 0, Undef}, [Equalizer_control] = { "equalizer", 0, {0}, 0, 0, Undef}, [Agc_control] = { "agc", 0, {0}, 0, 0, Undef}, [Delay_control] = { "delay", 0, {0}, 0, 0, Undef}, [Bassboost_control] = { "bassboost", 0, {0}, 0, 0, Undef}, [Loudness_control] = { "loudness", 0, {0}, 0, 0, Undef}, [Channel_control] = { "channels", 0, {0}, 0, 2, Undef}, [Resolution_control] = { "resolution", 0, {0}, 0, 16, Undef}, // [Selector_control] = { "selector", 0, {0}, 0, 0, Undef}, }, { [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, [Mid_control] = { "mid", 0, {0}, 0, 0, Undef}, [Treble_control] = { "treble", 0, {0}, 0, 0, Undef}, [Equalizer_control] = { "equalizer", 0, {0}, 0, 0, Undef}, [Agc_control] = { "agc", 0, {0}, 0, 0, Undef}, [Delay_control] = { "delay", 0, {0}, 0, 0, Undef}, [Bassboost_control] = { "bassboost", 0, {0}, 0, 0, Undef}, [Loudness_control] = { "loudness", 0, {0}, 0, 0, Undef}, [Channel_control] = { "channels", 0, {0}, 0, 2, Undef}, [Resolution_control] = { "resolution", 0, {0}, 0, 16, Undef}, // [Selector_control] = { "selector", 0, {0}, 0, 0, Undef}, } }; int setaudioalt(int rec, Audiocontrol *c, int control) { dprint(2, "setcontrol %s: Set alt %d\n", c->name, control); curalt[rec] = control; if(usbcmd(ad, Rh2d|Rstd|Riface, Rsetiface, control, interface[rec], nil, 0) < 0){ dprint(2, "setcontrol: setupcmd %s failed\n", c->name); return -1; } return control; } int findalt(int rec, int nchan, int res, int speed) { Ep *ep; Audioalt *a; Altc *da; int i, j, k, retval; retval = -1; controls[rec][Channel_control].min = 1000000; controls[rec][Channel_control].max = 0; controls[rec][Channel_control].step = Undef; controls[rec][Resolution_control].min = 1000000; controls[rec][Resolution_control].max = 0; controls[rec][Resolution_control].step = Undef; for(i = 0; i < nelem(ad->usb->ep); i++){ if((ep = ad->usb->ep[i]) == nil) continue; if(ep->iface == nil){ fprint(2, "\tno interface\n"); return 0; } if(ep->iface->csp != CSP(Claudio, 2, 0)) continue; if((rec == Play && (ep->addr & 0x80)) || (rec == Record && (ep->addr & 0x80) == 0)) continue; for(j = 0; j < 16; j++){ if((da = ep->iface->altc[j]) == nil || (a = da->aux) == nil) continue; if(a->nchan < controls[rec][Channel_control].min) controls[rec][Channel_control].min = a->nchan; if(a->nchan > controls[rec][Channel_control].max) controls[rec][Channel_control].max = a->nchan; if(a->res < controls[rec][Resolution_control].min) controls[rec][Resolution_control].min = a->res; if(a->res > controls[rec][Resolution_control].max) controls[rec][Resolution_control].max = a->res; controls[rec][Channel_control].settable = 1; controls[rec][Channel_control].readable = 1; controls[rec][Resolution_control].settable = 1; controls[rec][Resolution_control].readable = 1; controls[rec][Speed_control].settable = 1; controls[rec][Speed_control].readable = 1; if(a->nchan == nchan && a->res == res){ if(speed == Undef) retval = j; else if(a->caps & (has_discfreq|onefreq)){ for(k = 0; k < nelem(a->freqs); k++){ if(a->freqs[k] == speed){ retval = j; break; } } }else{ if(speed >= a->minfreq && speed <= a->maxfreq) retval = j; } } } } if(usbdebug && retval < 0) fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed); return retval; } int setspeed(int rec, int speed) { int ps, n, no, dist, i; Audioalt *a; Altc *da; Ep *ep; uchar buf[3]; if(rec == Record && !setrec) return Undef; if(curalt[rec] < 0){ fprint(2, "Must set channels and resolution before speed\n"); return Undef; } if(endpt[rec] < 0) sysfatal("endpt[%s] not set", rec?"Record":"Playback"); ep = ad->usb->ep[endpt[rec]]; if(ep->iface == nil) sysfatal("no interface"); if(curalt[rec] < 0) sysfatal("curalt[%s] not set", rec?"Record":"Playback"); da = ep->iface->altc[curalt[rec]]; a = da->aux; if(a->caps & onefreq){ dprint(2, "setspeed %d: onefreq\n", speed); /* speed not settable, but packet size must still be set */ speed = a->freqs[0]; }else if(a->caps & has_contfreq){ dprint(2, "setspeed %d: contfreq\n", speed); if(speed < a->minfreq) speed = a->minfreq; else if(speed > a->maxfreq) speed = a->maxfreq; dprint(2, "Setting continuously variable %s speed to %d\n", rec?"record":"playback", speed); }else if(a->caps & has_discfreq){ dprint(2, "setspeed %d: discfreq\n", speed); dist = 1000000; no = -1; for(i = 0; a->freqs[i] > 0; i++) if(abs(a->freqs[i] - speed) < dist){ dist = abs(a->freqs[i] - speed); no = i; } if(no == -1){ dprint(2, "no = -1\n"); return Undef; } speed = a->freqs[no]; dprint(2, "Setting discreetly variable %s speed to %d\n", rec?"record":"playback", speed); }else{ dprint(2, "can't happen\n?"); return Undef; } if(a->caps & has_setspeed){ dprint(2, "Setting %s speed to %d Hz;", rec?"record":"playback", speed); buf[0] = speed; buf[1] = speed >> 8; buf[2] = speed >> 16; n = endpt[rec]; if(rec) n |= 0x80; if(usbcmd(ad, Rh2d|Rclass|Rep, Rsetcur, sampling_freq_control<<8, n, buf, 3) < 0){ fprint(2, "Error in setupcmd\n"); return Undef; } if((n=usbcmd(ad, Rd2h|Rclass|Rep, Rgetcur, sampling_freq_control<<8, n, buf, 3)) < 0){ fprint(2, "Error in setupreq\n"); return Undef; } if(n != 3) fprint(2, "Error in setupreply: %d\n", n); else{ n = buf[0] | buf[1] << 8 | buf[2] << 16; if(buf[2] || n == 0){ dprint(2, "Speed out of bounds %d (0x%x)\n", n, n); }else if(n != speed && ad->usb->vid == 0x077d && (ad->usb->did == 0x0223 || ad->usb->did == 0x07af)){ /* Griffin iMic responds incorrectly to sample rate inquiry */ dprint(2, " reported as %d (iMic bug?);", n); }else speed = n; } dprint(2, " speed now %d Hz;", speed); } ps = ((speed * da->interval + 999) / 1000) * controls[rec][Channel_control].value[0] * controls[rec][Resolution_control].value[0]/8; if(ps > ep->maxpkt){ fprint(2, "%s: setspeed(rec %d, speed %d): packet size %d > " "maximum packet size %d\n", argv0, rec, speed, ps, ep->maxpkt); return Undef; } dprint(2, "Configuring %s endpoint for %d Hz\n", rec?"record":"playback", speed); epdev[rec] = openep(ad, endpt[rec]); if(epdev[rec] == nil) sysfatal("openep rec %d: %r", rec); devctl(epdev[rec], "pollival %d", da->interval); devctl(epdev[rec], "samplesz %ld", controls[rec][Channel_control].value[0] * controls[rec][Resolution_control].value[0]/8); devctl(epdev[rec], "hz %d", speed); /* NO: the client uses the endpoint file directly if(opendevdata(epdev[rec], rec ? OREAD : OWRITE) < 0) sysfatal("openep rec %d: %r", rec); */ return speed; } long getspeed(int rec, int which) { int i, n; Audioalt *a; Altc *da; Ep *ep; uchar buf[3]; int r; if(curalt[rec] < 0){ fprint(2, "Must set channels and resolution before getspeed\n"); return Undef; } if(endpt[rec] < 0) sysfatal("endpt[%s] not set", rec?"Record":"Playback"); dprint(2, "getspeed: endpt[%d] == %d\n", rec, endpt[rec]); ep = ad->usb->ep[endpt[rec]]; if(ep->iface == nil) sysfatal("no interface"); if(curalt[rec] < 0) sysfatal("curalt[%s] not set", rec?"Record":"Playback"); da = ep->iface->altc[curalt[rec]]; a = da->aux; if(a->caps & onefreq){ dprint(2, "getspeed: onefreq\n"); if(which == Rgetres) return Undef; return a->freqs[0]; /* speed not settable */ } if(a->caps & has_setspeed){ dprint(2, "getspeed: has_setspeed, ask\n"); n = endpt[rec]; if(rec) n |= 0x80; r = Rd2h|Rclass|Rep; if(usbcmd(ad,r,which,sampling_freq_control<<8, n, buf, 3) < 0) return Undef; if(n == 3){ if(buf[2]){ dprint(2, "Speed out of bounds\n"); if((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8) return a->freqs[buf[0] | buf[1] << 8]; } return buf[0] | buf[1] << 8 | buf[2] << 16; } dprint(2, "getspeed: n = %d\n", n); } if(a->caps & has_contfreq){ dprint(2, "getspeed: has_contfreq\n"); if(which == Rgetcur) return controls[rec][Speed_control].value[0]; if(which == Rgetmin) return a->minfreq; if(which == Rgetmax) return a->maxfreq; if(which == Rgetres) return 1; } if(a->caps & has_discfreq){ dprint(2, "getspeed: has_discfreq\n"); if(which == Rgetcur) return controls[rec][Speed_control].value[0]; if(which == Rgetmin) return a->freqs[0]; for(i = 0; i < 8 && a->freqs[i] > 0; i++) ; if(which == Rgetmax) return a->freqs[i-1]; if(which == Rgetres) return Undef; } dprint(2, "can't happen\n?"); return Undef; } int setcontrol(int rec, char *name, long *value) { int i, ctl, m; byte buf[3]; int type, req, control, index, count; Audiocontrol *c; c = nil; for(ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; if(strcmp(name, c->name) == 0) break; } if(ctl == Ncontrol){ dprint(2, "setcontrol: control not found\n"); return -1; } if(c->settable == 0){ dprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl); if(c->chans){ for(i = 0; i < 8; i++) if((c->chans & 1 << i) && c->value[i] != value[i]) return -1; return 0; } if(c->value[0] != value[0]) return -1; return 0; } if(c->chans){ value[0] = 0; // set to average m = 0; for(i = 1; i < 8; i++) if(c->chans & 1 << i){ if(c->min != Undef && value[i] < c->min) value[i] = c->min; if(c->max != Undef && value[i] > c->max) value[i] = c->max; value[0] += value[i]; m++; }else value[i] = Undef; if(m) value[0] /= m; }else{ if(c->min != Undef && value[0] < c->min) value[0] = c->min; if(c->max != Undef && value[0] > c->max) value[0] = c->max; } req = Rsetcur; count = 1; switch(ctl){ default: dprint(2, "setcontrol: can't happen\n"); return -1; case Speed_control: if((rec != Record || setrec) && (value[0] = setspeed(rec, value[0])) < 0) return -1; c->value[0] = value[0]; return 0; case Equalizer_control: /* not implemented */ return -1; case Resolution_control: control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]); if(control < 0 || setaudioalt(rec, c, control) < 0){ dprint(2, "setcontrol: can't find setting for %s\n", c->name); return -1; } c->value[0] = value[0]; controls[rec][Speed_control].value[0] = defaultspeed[rec]; return 0; case Volume_control: case Delay_control: count = 2; /* fall through */ case Mute_control: case Bass_control: case Mid_control: case Treble_control: case Agc_control: case Bassboost_control: case Loudness_control: type = Rh2d|Rclass|Riface; control = ctl<<8; index = featureid[rec]<<8; break; case Selector_control: type = Rh2d|Rclass|Riface; control = 0; index = selectorid[rec]<<8; break; case Channel_control: control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]); if(control < 0 || setaudioalt(rec, c, control) < 0){ dprint(2, "setcontrol: can't find setting for %s\n", c->name); return -1; } c->value[0] = value[0]; controls[rec][Speed_control].value[0] = defaultspeed[rec]; return 0; } if(c->chans){ for(i = 1; i < 8; i++) if(c->chans & 1 << i){ switch(count){ case 2: buf[1] = value[i] >> 8; case 1: buf[0] = value[i]; } if(usbcmd(ad, type, req, control | i, index, buf, count) < 0){ dprint(2, "setcontrol: setupcmd %s failed\n", controls[rec][ctl].name); return -1; } c->value[i] = value[i]; } }else{ switch(count){ case 2: buf[1] = value[0] >> 8; case 1: buf[0] = value[0]; } if(usbcmd(ad, type, req, control, index, buf, count) < 0){ dprint(2, "setcontrol: setupcmd %s failed\n", c->name); return -1; } } c->value[0] = value[0]; return 0; } int getspecialcontrol(int rec, int ctl, int req, long *value) { byte buf[3]; int m, n, i; int type, control, index, count, signedbyte; short svalue; count = 1; signedbyte = 0; switch(ctl){ default: return Undef; case Speed_control: value[0] = getspeed(rec, req); return 0; case Channel_control: case Resolution_control: if(req == Rgetmin) value[0] = controls[rec][ctl].min; if(req == Rgetmax) value[0] = controls[rec][ctl].max; if(req == Rgetres) value[0] = controls[rec][ctl].step; if(req == Rgetcur) value[0] = controls[rec][ctl].value[0]; return 0; case Volume_control: case Delay_control: count = 2; /* fall through */ case Bass_control: case Mid_control: case Treble_control: case Equalizer_control: signedbyte = 1; type = Rd2h|Rclass|Riface; control = ctl<<8; index = featureid[rec]<<8; break; case Selector_control: type = Rd2h|Rclass|Riface; control = 0; index = selectorid[rec]<<8; break; case Mute_control: case Agc_control: case Bassboost_control: case Loudness_control: if(req != Rgetcur) return Undef; type = Rd2h|Rclass|Riface; control = ctl<<8; index = featureid[rec]<<8; break; } if(controls[rec][ctl].chans){ m = 0; value[0] = 0; // set to average for(i = 1; i < 8; i++){ value[i] = Undef; if(controls[rec][ctl].chans & 1 << i){ n=usbcmd(ad, type,req, control|i,index,buf,count); if(n < 0) return Undef; if(n != count) return -1; switch (count){ case 2: svalue = buf[1] << 8 | buf[0]; if(req == Rgetcur){ value[i] = svalue; value[0] += svalue; m++; }else value[0] = svalue; break; case 1: svalue = buf[0]; if(signedbyte && (svalue&0x80)) svalue |= 0xFF00; if(req == Rgetcur){ value[i] = svalue; value[0] += svalue; m++; }else value[0] = svalue; } } } if(m) value[0] /= m; return 0; } value[0] = Undef; if(usbcmd(ad, type, req, control, index, buf, count) != count) return -1; switch (count){ case 2: svalue = buf[1] << 8 | buf[0]; value[0] = svalue; break; case 1: svalue = buf[0]; if(signedbyte && (svalue&0x80)) svalue |= 0xFF00; value[0] = svalue; } return 0; } int getcontrol(int rec, char *name, long *value) { int i; for(i = 0; i < Ncontrol; i++){ if(strcmp(name, controls[rec][i].name) == 0) break; } if(i == Ncontrol) return -1; if(controls[rec][i].readable == 0) return -1; if(getspecialcontrol(rec, i, Rgetcur, value) < 0) return -1; memmove(controls[rec][i].value, value, sizeof controls[rec][i].value); return 0; } void getcontrols(void) { int rec, ctl, i; Audiocontrol *c; long v[8]; for(rec = 0; rec < 2; rec++){ if(rec == Record && !setrec) continue; for(ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; if(c->readable){ if(verbose) fprint(2, "%s %s control", rec?"Record":"Playback", controls[rec][ctl].name); c->min = (getspecialcontrol(rec, ctl, Rgetmin, v) < 0) ? Undef : v[0]; if(verbose && c->min != Undef) fprint(2, ", min %ld", c->min); c->max = (getspecialcontrol(rec, ctl, Rgetmax, v) < 0) ? Undef : v[0]; if(verbose && c->max != Undef) fprint(2, ", max %ld", c->max); c->step = (getspecialcontrol(rec, ctl, Rgetres, v) < 0) ? Undef : v[0]; if(verbose && c->step != Undef) fprint(2, ", step %ld", c->step); if(getspecialcontrol(rec, ctl, Rgetcur, c->value) == 0){ if(verbose){ if(c->chans){ fprint(2, ", values"); for(i = 1; i < 8; i++) if(c->chans & 1 << i) fprint(2, "[%d] %ld ", i, c->value[i]); }else fprint(2, ", value %ld", c->value[0]); } } if(verbose) fprint(2, "\n"); }else{ c->min = Undef; c->max = Undef; c->step = Undef; c->value[0] = Undef; dprint(2, "%s %s control not settable\n", rec?"Playback":"Record", controls[rec][ctl].name); } } } } int ctlparse(char *s, Audiocontrol *c, long *v) { int i, j, nf, m; char *vals[9]; char *p; long val; nf = tokenize(s, vals, nelem(vals)); if(nf <= 0) return -1; if(c->chans){ j = 0; m = 0; SET(val); v[0] = 0; // will compute average of v[i] for(i = 1; i < 8; i++) if(c->chans & 1 << i){ if(j < nf){ val = strtol(vals[j], &p, 0); if(val == 0 && *p != '\0' && *p != '%') return -1; if(*p == '%' && c->min != Undef) val = (val*c->max + (100-val)*c->min)/100; j++; } v[i] = val; v[0] += val; m++; }else v[i] = Undef; if(m) v[0] /= m; }else{ val = strtol(vals[0], &p, 0); if(*p == '%' && c->min != Undef) val = (val*c->max + (100-val)*c->min)/100; v[0] = val; } return 0; } int Aconv(Fmt *fp) { char str[256]; Audiocontrol *c; int fst, i; char *p; c = va_arg(fp->args, Audiocontrol*); p = str; if(c->chans){ fst = 1; for(i = 1; i < 8; i++) if(c->chans & 1 << i){ p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]); fst = 0; } seprint(p, str+sizeof str, "'"); }else seprint(p, str+sizeof str, "%ld", c->value[0]); return fmtstrcpy(fp, str); } eed; } long getspeed(int rec, int which) { int i, n; Auusb/audio/audioctl.h 664 0 0 1152 11202312257 12405ustar00syssysenum{ Undef = 0x80000000, Play = 0, Record = 1, }; typedef struct Audiocontrol Audiocontrol; struct Audiocontrol { char *name; uchar readable; uchar settable; uchar chans; /* 0 is master, non-zero is bitmap */ long value[8]; /* 0 is master; value[0] == Undef -> all values Undef */ long min, max, step; }; extern Audiocontrol controls[2][Ncontrol]; extern int endpt[2]; extern int interface[2]; extern int featureid[2]; extern int selectorid[2]; extern int mixerid[2]; extern int buttonendpt; int ctlparse(char *s, Audiocontrol *c, long *v); void ctlevent(void); #pragma varargck type "A" Audiocontrol* getspeed: n = %d\n", n); } if(a->caps & has_contfreq){ dprint(2, "getspeed: has_contfreq\n"); if(which == Rgetcur) return controls[rec][Speed_control].value[0]; if(which == Rgetmin) return a->minfreq; if(which == Rgetmax) return a->maxfreq; if(which == Rgetres) return 1; } if(a->caps & has_discfreq){ dprint(2, "getspeed: has_discfreq\n"); if(which == Rgetcur) return contusb/audio/audiofs.c 664 0 0 42454 11202312257 12260ustar00syssys#include #include #include #include #include #include #include "usb.h" #include "audio.h" #include "audioctl.h" int attachok; #define STACKSIZE 16*1024 enum { OPERM = 0x3, /* mask of all permission types in open mode */ }; typedef struct Fid Fid; typedef struct Audioctldata Audioctldata; typedef struct Worker Worker; struct Audioctldata { long offoff; /* offset of the offset for audioctl */ long values[2][Ncontrol][8]; /* last values transmitted */ char *s; int ns; }; enum { Busy = 0x01, Open = 0x02, Eof = 0x04, }; struct Fid { QLock; int fid; Dir *dir; ushort flags; short readers; void *fiddata; /* file specific per-fid data (used for audioctl) */ Fid *next; }; struct Worker { Fid *fid; ushort tag; Fcall *rhdr; Dir *dir; Channel *eventc; Worker *next; }; enum { /* Event channel messages for worker */ Work = 0x01, Check = 0x02, Flush = 0x03, }; enum { Qdir, Qvolume, Qaudioctl, Qaudiostat, Nqid, }; Dir dirs[] = { [Qdir] = {0,0,{Qdir, 0,QTDIR},0555|DMDIR,0,0,0, ".", nil,nil,nil}, [Qvolume] = {0,0,{Qvolume, 0,QTFILE},0666,0,0,0, "volume", nil,nil,nil}, [Qaudioctl] = {0,0,{Qaudioctl, 0,QTFILE},0666,0,0,0, "audioctl",nil,nil,nil}, [Qaudiostat] = {0,0,{Qaudiostat,0,QTFILE},0666,0,0,0, "audiostat",nil,nil,nil}, }; int messagesize = 4*1024+IOHDRSZ; uchar mdata[8*1024+IOHDRSZ]; uchar mbuf[8*1024+IOHDRSZ]; Fcall thdr; Fcall rhdr; Worker *workers; char srvfile[64], mntdir[64], epdata[64], audiofile[64]; int mfd[2], p[2]; char user[32]; char *srvpost; Channel *procchan; Channel *replchan; Fid *fids; Fid* newfid(int); void io(void *); void usage(void); extern char *mntpt; char *rflush(Fid*), *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), *rversion(Fid*); char *(*fcalls[])(Fid*) = { [Tflush] rflush, [Tversion] rversion, [Tauth] rauth, [Tattach] rattach, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat, }; char Eperm[] = "permission denied"; char Enotdir[] = "not a directory"; char Enoauth[] = "no authentication in ramfs"; char Enotexist[] = "file does not exist"; char Einuse[] = "file in use"; char Eexist[] = "file exists"; char Enotowner[] = "not owner"; char Eisopen[] = "file already open for I/O"; char Excl[] = "exclusive use file already open"; char Ename[] = "illegal name"; char Ebadctl[] = "unknown control message"; int notifyf(void *, char *s) { if(strncmp(s, "interrupt", 9) == 0) return 1; return 0; } void post(char *name, char *envname, int srvfd) { int fd; char buf[32]; fd = create(name, OWRITE, attachok?0666:0600); if(fd < 0) return; sprint(buf, "%d",srvfd); if(write(fd, buf, strlen(buf)) != strlen(buf)) sysfatal("srv write"); close(fd); putenv(envname, name); } /* * BUG: If audio is later used on a different name space, the * audio/audioin files are not there because of the bind trick. * We should actually implement those files despite the binds. * If audio is used from within the same ns nothing would change, * otherwise, whoever would mount the audio files could still * play/record audio (unlike now). */ void serve(void *) { int i; ulong t; if(pipe(p) < 0) sysfatal("pipe failed"); mfd[0] = p[0]; mfd[1] = p[0]; atnotify(notifyf, 1); strcpy(user, getuser()); t = time(nil); for(i = 0; i < Nqid; i++){ dirs[i].uid = user; dirs[i].gid = user; dirs[i].muid = user; dirs[i].atime = t; dirs[i].mtime = t; } if(mntpt == nil){ snprint(mntdir, sizeof(mntdir), "/dev"); mntpt = mntdir; } if(usbdebug) fmtinstall('F', fcallfmt); procrfork(io, nil, STACKSIZE, RFFDG|RFNAMEG); close(p[0]); /* don't deadlock if child fails */ if(srvpost){ sprint(srvfile, "/srv/%s", srvpost); remove(srvfile); post(srvfile, "usbaudio", p[1]); } if(mount(p[1], -1, mntpt, MBEFORE, "") < 0) sysfatal("mount failed"); if(endpt[Play] >= 0 && devctl(epdev[Play], "name audio") < 0) fprint(2, "audio: name audio: %r\n"); if(endpt[Record] >= 0 && devctl(epdev[Record], "name audioin") < 0) fprint(2, "audio: name audioin: %r\n"); threadexits(nil); } char* rversion(Fid*) { Fid *f; if(thdr.msize < 256) return "max messagesize too small"; if(thdr.msize < messagesize) messagesize = thdr.msize; rhdr.msize = messagesize; if(strncmp(thdr.version, "9P2000", 6) != 0) return "unknown 9P version"; else rhdr.version = "9P2000"; for(f = fids; f; f = f->next) if(f->flags & Busy) rclunk(f); return nil; } char* rauth(Fid*) { return "usbaudio: no authentication required"; } char* rflush(Fid *) { Worker *w; int waitflush; do { waitflush = 0; for(w = workers; w; w = w->next) if(w->tag == thdr.oldtag){ waitflush++; nbsendul(w->eventc, thdr.oldtag << 16 | Flush); } if(waitflush) sleep(50); } while(waitflush); dprint(2, "flush done on tag %d\n", thdr.oldtag); return 0; } char* rattach(Fid *f) { f->flags |= Busy; f->dir = &dirs[Qdir]; rhdr.qid = f->dir->qid; if(attachok == 0 && strcmp(thdr.uname, user) != 0) return Eperm; return 0; } static Fid* doclone(Fid *f, int nfid) { Fid *nf; nf = newfid(nfid); if(nf->flags & Busy) return nil; nf->flags |= Busy; nf->flags &= ~Open; nf->dir = f->dir; return nf; } char* dowalk(Fid *f, char *name) { int t; if(strcmp(name, ".") == 0) return nil; if(strcmp(name, "..") == 0){ f->dir = &dirs[Qdir]; return nil; } if(f->dir != &dirs[Qdir]) return Enotexist; for(t = 1; t < Nqid; t++){ if(strcmp(name, dirs[t].name) == 0){ f->dir = &dirs[t]; return nil; } } return Enotexist; } char* rwalk(Fid *f) { Fid *nf; char *rv; int i; Dir *savedir; if(f->flags & Open) return Eisopen; rhdr.nwqid = 0; nf = nil; savedir = f->dir; /* clone if requested */ if(thdr.newfid != thdr.fid){ nf = doclone(f, thdr.newfid); if(nf == nil) return "new fid in use"; f = nf; } /* if it's just a clone, return */ if(thdr.nwname == 0 && nf != nil) return nil; /* walk each element */ rv = nil; for(i = 0; i < thdr.nwname; i++){ rv = dowalk(f, thdr.wname[i]); if(rv != nil){ if(nf != nil) rclunk(nf); else f->dir = savedir; break; } rhdr.wqid[i] = f->dir->qid; } rhdr.nwqid = i; /* we only error out if no walk */ if(i > 0) rv = nil; return rv; } Audioctldata * allocaudioctldata(void) { int i, j, k; Audioctldata *a; a = emallocz(sizeof(Audioctldata), 1); for(i = 0; i < 2; i++) for(j=0; j < Ncontrol; j++) for(k=0; k < 8; k++) a->values[i][j][k] = Undef; return a; } char * ropen(Fid *f) { if(f->flags & Open) return Eisopen; if(thdr.mode != OREAD && (f->dir->mode & 0x2) == 0) return Eperm; qlock(f); if(f->dir == &dirs[Qaudioctl] && f->fiddata == nil) f->fiddata = allocaudioctldata(); qunlock(f); rhdr.iounit = 0; rhdr.qid = f->dir->qid; f->flags |= Open; return nil; } char * rcreate(Fid*) { return Eperm; } int readtopdir(Fid*, uchar *buf, long off, int cnt, int blen) { int i, m, n; long pos; n = 0; pos = 0; for(i = 1; i < Nqid; i++){ m = convD2M(&dirs[i], &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; } pos += m; } return n; } enum { Chunk = 1024, }; int makeaudioctldata(Fid *f) { int rec, ctl, i, diff; long *actls; /* 8 of them */ char *p, *e; Audiocontrol *c; Audioctldata *a; if((a = f->fiddata) == nil) sysfatal("fiddata"); if((p = a->s) == nil) a->s = p = emallocz(Chunk, 0); e = p + Chunk - 1; /* e must point *at* last byte, not *after* */ for(rec = 0; rec < 2; rec++) for(ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; actls = a->values[rec][ctl]; diff = 0; if(c->chans){ for(i = 1; i < 8; i++) if((c->chans & 1<value[i] != actls[i]) diff = 1; }else if(c->value[0] != actls[0]) diff = 1; if(diff){ p = seprint(p, e, "%s %s %A", c->name, rec? "in": "out", c); memmove(actls, c->value, sizeof c->value); if(c->min != Undef){ p = seprint(p, e, " %ld %ld", c->min, c->max); if(c->step != Undef) p = seprint(p, e, " %ld", c->step); } p = seprint(p, e, "\n"); } } assert(strlen(a->s) < Chunk); a->ns = p - a->s; return a->ns; } void readproc(void *x) { int n, cnt; ulong event; vlong off; uchar *mdata; Audioctldata *a; Fcall *rhdr; Fid *f; Worker *w; w = x; mdata = emallocz(8*1024+IOHDRSZ, 0); while(event = recvul(w->eventc)){ if(event != Work) continue; f = w->fid; rhdr = w->rhdr; a = f->fiddata; off = rhdr->offset; cnt = rhdr->count; assert(a->offoff == off); /* f is already locked */ for(;;){ qunlock(f); event = recvul(w->eventc); qlock(f); ddprint(2, "readproc unblocked fid %d %lld\n", f->fid, f->dir->qid.path); switch (event & 0xffff){ case Work: sysfatal("readproc phase error"); case Check: if(f->fiddata && makeaudioctldata(f) == 0) continue; break; case Flush: if((event >> 16) == rhdr->tag){ ddprint(2, "readproc flushing fid %d, tag %d\n", f->fid, rhdr->tag); goto flush; } continue; } if(f->fiddata){ rhdr->data = a->s; rhdr->count = a->ns; break; } yield(); } if(rhdr->count > cnt) rhdr->count = cnt; if(rhdr->count) f->flags &= ~Eof; ddprint(2, "readproc:->%F\n", rhdr); n = convS2M(rhdr, mdata, messagesize); if(write(mfd[1], mdata, n) != n) sysfatal("mount write"); flush: w->tag = NOTAG; f->readers--; assert(f->readers == 0); free(rhdr); w->rhdr = nil; qunlock(f); sendp(procchan, w); } threadexits(nil); } char* rread(Fid *f) { int i, n, cnt, rec, div; vlong off; char *p; Audiocontrol *c; Audioctldata *a; Worker *w; static char buf[1024]; rhdr.count = 0; off = thdr.offset; cnt = thdr.count; if(cnt > messagesize - IOHDRSZ) cnt = messagesize - IOHDRSZ; rhdr.data = (char*)mbuf; if(f->dir == &dirs[Qdir]){ n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); rhdr.count = n; return nil; } if(f->dir == &dirs[Qvolume]){ p = buf; n = sizeof buf; for(rec = 0; rec < 2; rec++){ c = &controls[rec][Volume_control]; if(c->readable){ div = c->max - c->min; i = snprint(p, n, "audio %s %ld\n", rec? "in": "out", (c->min != Undef? 100*(c->value[0]-c->min)/(div? div: 1): c->value[0])); p += i; n -= i; } c = &controls[rec][Treble_control]; if(c->readable){ div = c->max - c->min; i = snprint(p, n, "treb %s %ld\n", rec? "in": "out", (c->min != Undef? 100*(c->value[0]-c->min)/(div? div: 1): c->value[0])); p += i; n -= i; } c = &controls[rec][Bass_control]; if(c->readable){ div = c->max - c->min; i = snprint(p, n, "bass %s %ld\n", rec? "in": "out", (c->min != Undef? 100*(c->value[0]-c->min)/(div? div: 1): c->value[0])); p += i; n -= i; } c = &controls[rec][Speed_control]; if(c->readable){ i = snprint(p, n, "speed %s %ld\n", rec? "in": "out", c->value[0]); p += i; n -= i; } } n = sizeof buf - n; if(off > n) rhdr.count = 0; else{ rhdr.data = buf + off; rhdr.count = n - off; if(rhdr.count > cnt) rhdr.count = cnt; } return nil; } if(f->dir == &dirs[Qaudioctl]){ Fcall *hdr; qlock(f); a = f->fiddata; if(off - a->offoff < 0){ /* there was a seek */ a->offoff = off; a->ns = 0; } do { if(off - a->offoff < a->ns){ rhdr.data = a->s + (off - a->offoff); rhdr.count = a->ns - (off - a->offoff); if(rhdr.count > cnt) rhdr.count = cnt; qunlock(f); return nil; } if(a->offoff != off){ a->ns = 0; a->offoff = off; rhdr.count = 0; qunlock(f); return nil; } } while(makeaudioctldata(f) != 0); assert(a->offoff == off); /* Wait for data off line */ f->readers++; w = nbrecvp(procchan); if(w == nil){ w = emallocz(sizeof(Worker), 1); w->eventc = chancreate(sizeof(ulong), 1); w->next = workers; workers = w; proccreate(readproc, w, 4096); } hdr = emallocz(sizeof(Fcall), 0); w->fid = f; w->tag = thdr.tag; assert(w->rhdr == nil); w->rhdr = hdr; hdr->count = cnt; hdr->offset = off; hdr->type = thdr.type+1; hdr->fid = thdr.fid; hdr->tag = thdr.tag; sendul(w->eventc, Work); return (char*)~0; } return Eperm; } char* rwrite(Fid *f) { long cnt, value; char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p; int nlines, i, nf, nnf, rec, ctl; Audiocontrol *c; Worker *w; static char buf[256]; rhdr.count = 0; cnt = thdr.count; if(cnt > messagesize - IOHDRSZ) cnt = messagesize - IOHDRSZ; err = nil; if(f->dir == &dirs[Qvolume] || f->dir == &dirs[Qaudioctl]){ thdr.data[cnt] = '\0'; nlines = getfields(thdr.data, lines, 2*Ncontrol, 1, "\n"); for(i = 0; i < nlines; i++){ dprint(2, "line: %s\n", lines[i]); nf = tokenize(lines[i], fields, 4); if(nf == 0) continue; if(nf == 3) if(strcmp(fields[1], "in") == 0 || strcmp(fields[1], "record") == 0) rec = 1; else if(strcmp(fields[1], "out") == 0 || strcmp(fields[1], "playback") == 0) rec = 0; else{ dprint(2, "bad1\n"); return Ebadctl; } else if(nf == 2) rec = 0; else{ dprint(2, "bad2 %d\n", nf); return Ebadctl; } c = nil; if(strcmp(fields[0], "audio") == 0) /* special case */ fields[0] = "volume"; for(ctl = 0; ctl < Ncontrol; ctl++){ c = &controls[rec][ctl]; if(strcmp(fields[0], c->name) == 0) break; } if(ctl == Ncontrol){ dprint(2, "bad3\n"); return Ebadctl; } if(f->dir == &dirs[Qvolume] && ctl != Speed_control && c->min != Undef && c->max != Undef){ nnf = tokenize(fields[nf-1], subfields, nelem(subfields)); if(nnf <= 0 || nnf > 8){ dprint(2, "bad4\n"); return Ebadctl; } p = buf; for(i = 0; i < nnf; i++){ value = strtol(subfields[i], nil, 0); value = ((100 - value)*c->min + value*c->max) / 100; if(p == buf){ dprint(2, "rwrite: %s %s '%ld", c->name, rec? "record": "playback", value); }else dprint(2, " %ld", value); if(p == buf) p = seprint(p, buf+sizeof buf, "0x%p %s %s '%ld", replchan, c->name, rec? "record": "playback", value); else p = seprint(p, buf+sizeof buf, " %ld", value); } dprint(2, "'\n"); seprint(p, buf+sizeof buf-1, "'"); chanprint(controlchan, buf); }else{ dprint(2, "rwrite: %s %s %q", c->name, rec? "record": "playback", fields[nf-1]); chanprint(controlchan, "0x%p %s %s %q", replchan, c->name, rec? "record": "playback", fields[nf-1]); } p = recvp(replchan); if(p){ if(strcmp(p, "ok") == 0){ free(p); p = nil; } if(err == nil) err = p; } } for(w = workers; w; w = w->next) nbsendul(w->eventc, Qaudioctl << 16 | Check); rhdr.count = thdr.count; return err; } return Eperm; } char * rclunk(Fid *f) { Audioctldata *a; qlock(f); f->flags &= ~(Open|Busy); assert(f->readers ==0); if(f->fiddata){ a = f->fiddata; if(a->s) free(a->s); free(a); f->fiddata = nil; } qunlock(f); return 0; } char * rremove(Fid *) { return Eperm; } char * rstat(Fid *f) { Audioctldata *a; if(f->dir == &dirs[Qaudioctl]){ qlock(f); if(f->fiddata == nil) f->fiddata = allocaudioctldata(); a = f->fiddata; if(a->ns == 0) makeaudioctldata(f); f->dir->length = a->offoff + a->ns; qunlock(f); } rhdr.nstat = convD2M(f->dir, mbuf, messagesize - IOHDRSZ); rhdr.stat = mbuf; return 0; } char * rwstat(Fid*) { return Eperm; } Fid * newfid(int fid) { Fid *f, *ff; ff = nil; for(f = fids; f; f = f->next) if(f->fid == fid) return f; else if(ff == nil && (f->flags & Busy) == 0) ff = f; if(ff == nil){ ff = emallocz(sizeof *ff, 1); ff->next = fids; fids = ff; } ff->fid = fid; ff->flags &= ~(Busy|Open); ff->dir = nil; return ff; } void io(void *) { char *err, e[32]; int n; close(p[1]); procchan = chancreate(sizeof(Channel*), 8); replchan = chancreate(sizeof(char*), 0); for(;;){ /* * reading from a pipe or a network device * will give an error after a few eof reads * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error */ n = read9pmsg(mfd[0], mdata, messagesize); if(n == 0) continue; if(n < 0){ rerrstr(e, sizeof e); if(strcmp(e, "interrupted") == 0){ dprint(2, "read9pmsg interrupted\n"); continue; } return; } if(convM2S(mdata, n, &thdr) == 0) continue; ddprint(2, "io:<-%F\n", &thdr); rhdr.data = (char*)mdata + messagesize; if(!fcalls[thdr.type]) err = "bad fcall type"; else err = (*fcalls[thdr.type])(newfid(thdr.fid)); if(err == (char*)~0) continue; /* handled off line */ if(err){ rhdr.type = Rerror; rhdr.ename = err; }else{ rhdr.type = thdr.type + 1; rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; ddprint(2, "io:->%F\n", &rhdr); n = convS2M(&rhdr, mdata, messagesize); if(write(mfd[1], mdata, n) != n) sysfatal("mount write"); } } int newid(void) { int rv; static int id; static Lock idlock; lock(&idlock); rv = ++id; unlock(&idlock); return rv; } void ctlevent(void) { Worker *w; for(w = workers; w; w = w->next) nbsendul(w->eventc, Qaudioctl << 16 | Check); } ong *actls; /* 8 of them */ char *p, *e; Audiocontrol *c; Audioctldata *a; if((a = f->fiddata) == nil) sysfatal("fiddata"); if((p = a->s) == nil) a->s = p = emallocz(Chunk, 0); e = p + Chunk - 1; /* eusb/audio/audiosub.c 664 0 0 17517 11202312257 12443ustar00syssys#include #include #include #include "usb.h" #include "audio.h" #include "audioctl.h" typedef struct Namelist Namelist; struct Namelist { short index; char *name; }; Namelist terminal_types[] = { { 0x100, "USB Terminal, undefined type"}, { 0x101, "USB Streaming"}, { 0x201, "Microphone"}, { 0x301, "Speaker"}, { 0x603, "Line connector"}, { 0x605, "S/PDIF"}, { 0, nil } }; units[2][8]; /* rec and play units */ nunits[2]; /* number in use */ char * namefor(Namelist *list, int item) { while(list->name){ if(list->index == item) return list->name; list++; } return ""; } static int findunit(int nr) { int rec, i; for(rec = 0; rec < 2; rec++) for(i = 0; i < nunits[rec]; i++) if(units[rec][i] == nr) return rec; return -1; } void audio_interface(Dev *, Desc *dd) { byte *b = (uchar*)&dd->data; byte *bb = b; int nb = dd->data.bLength; int ctl, ch, u, x; byte *p; int class, subclass; Audioalt *aa; char *hd; class = Class(dd->iface->csp); subclass = Subclass(dd->iface->csp); dprint(2, "%d.%d: ", class, subclass); switch (subclass){ case 1: // control switch (b[2]){ case 0x01: dprint(2, "Class-Specific AC Interface Header Descriptor\n"); dprint(2, "\tAudioDevClass release (bcd)%c%c%c%c, " "TotalLength %d, InCollection %d aInterfaceNr %d\n", '0'+((b[4]>>4)&0xf), '0'+(b[4]&0xf), '0'+((b[3]>>4)&0xf), '0'+(b[3]&0xf), b[5]|(b[6]<<8), b[7], b[8]); break; case 0x02: // input dprint(2, "Audio Input Terminal Descriptor\n"); dprint(2, "\tbTerminalId %d, wTerminalType " "0x%x (%s), bAssocTerminal %d bNrChannels %d, " "wChannelConfig %d, iChannelNames %d iTerminal %d\n", b[3], b[4]|(b[5]<<8), namefor(terminal_types, b[4]|(b[5]<<8)), b[6], b[7], b[8]|(b[9]<<8), b[10], b[11]); if((b[4]|b[5]<<8) == 0x101){ if(verbose) fprint(2, "Audio output unit %d\n", b[3]); /* USB streaming input: play interface */ units[Play][nunits[Play]++] = b[3]; }else{ if(verbose) fprint(2, "Dev can record from %s\n", namefor(terminal_types, b[4]|(b[5]<<8))); /* Non-USB input: record interface */ units[Record][nunits[Record]++] = b[3]; } break; case 0x03: // output if(usbdebug){ fprint(2, "Audio Output Terminal Descriptor\n"); fprint(2, "\tbTerminalId %d, wTerminalType 0x%x (%s), bAssocTerminal %d bSourceId %d, iTerminal %d\n", b[3], b[4]|(b[5]<<8), namefor(terminal_types, b[4]|(b[5]<<8)), b[6], b[7], b[8]); } if((b[4]|b[5]<<8) == 0x101){ if(verbose) fprint(2, "Audio input unit %d\n", b[3]); /* USB streaming output: record interface */ units[Record][nunits[Record]++] = b[3]; if(verbose) fprint(2, "Dev can play to %s\n", namefor(terminal_types, b[4]|(b[5]<<8))); /* Non-USB output: play interface */ units[Play][nunits[Play]++] = b[3]; } break; case 0x04: if(verbose) fprint(2, "Audio Mixer Unit %d\n", b[3]); if(usbdebug){ fprint(2, "\t%d bytes:", nb); for(ctl = 0; ctl < nb; ctl++) fprint(2, " 0x%2.2x", b[ctl]); fprint(2, "\n\tbUnitId %d, bNrInPins %d", b[3], b[4]); } if(b[4]){ dprint(2, ", baSourceIDs: [%d", b[5]); u = findunit(b[5]); for(ctl = 1; ctl < b[4]; ctl++){ if(u < 0) u = findunit(b[5+ctl]); else if((x = findunit(b[5+ctl])) >= 0 && u != x && verbose) fprint(2, "\tMixer %d for I & O \n", b[3]); dprint(2, ", %d", b[5+ctl]); } dprint(2, "]\n"); if(u >= 0){ units[u][nunits[u]++] = b[3]; if(mixerid[u] >= 0) fprint(2, "Second mixer (%d, %d) on %s\n", mixerid[u], b[3], u?"record":"playback"); mixerid[u] = b[3]; } if(usbdebug){ fprint(2, "Channels %d, config %d, ", b[ctl+5], b[ctl+5+1] | b[ctl+5+2] << 8); x = b[ctl+5] * b[4]; fprint(2, "programmable: %d bits, 0x", x); x = (x + 7) >> 3; while(x--) fprint(2, "%2.2x", b[ctl+x+5+4]); } } break; case 0x05: if(verbose) fprint(2, "Audio Selector Unit %d\n", b[3]); dprint(2, "\tbUnitId %d, bNrInPins %d", b[3], b[4]); if(b[4]){ u = findunit(b[5]); dprint(2, ", baSourceIDs: %s [%d", u?"record":"playback", b[5]); for(ctl = 1; ctl < b[4]; ctl++){ if(u < 0) u = findunit(b[5+ctl]); else if((x = findunit(b[5+ctl])) >= 0 && u != x && verbose) fprint(2, "\tSelector %d for I & O\n", b[3]); dprint(2, ", %d", b[5+ctl]); } dprint(2, "]\n"); if(u >= 0){ units[u][nunits[u]++] = b[3]; if(selectorid[u] >= 0) fprint(2, "Second selector (%d, %d) on %s\n", selectorid[u], b[3], u?"record":"playback"); selectorid[u] = b[3]; controls[u][Selector_control].readable = 1; controls[u][Selector_control].settable = 1; controls[u][Selector_control].chans = 0; } } break; case 0x06: // feature if(verbose) fprint(2, "Audio Feature Unit %d", b[3]); dprint(2, "\tbUnitId %d, bSourceId %d, bControlSize %d\n", b[3], b[4], b[5]); u = findunit(b[4]); if(u >= 0){ if(verbose) fprint(2, " for %s\n", u?"Record":"Playback"); units[u][nunits[u]++] = b[3]; if(featureid[u] >= 0) if(verbose) fprint(2, "Second feature unit (%d, %d)" " on %s\n", featureid[u], b[3], u?"record":"playback"); featureid[u] = b[3]; }else if(verbose) fprint(2, ", not known what for\n"); p = b + 6; for(ctl = 1; ctl < 0x0b; ctl++) if((1<<(ctl-1)) & (b[6] | ((b[5]>1)?(b[7]<<8):0))){ if(verbose) fprint(2, "\t%s control on master channel\n", controls[0][ctl].name); if(u >= 0){ controls[u][ctl].readable = 1; controls[u][ctl].settable = 1; controls[u][ctl].chans = 0; } } p += (b[5]>1)?2:1; for(ch = 0; ch < (nb - 8)/b[5]; ch++){ for(ctl = 1; ctl < 0x0b; ctl++) if((1<<(ctl-1)) & (p[0] | ((b[5]>1)?(p[1]<<8):0))){ if(verbose) fprint(2, "\t%s control on channel %d\n", controls[0][ctl].name, ch+1); if(u >= 0){ controls[u][ctl].readable = 1; controls[u][ctl].settable = 1; controls[u][ctl].chans |= 1 <<(ch+1); } } p += (b[5]>1)?2:1; } break; default: hd = hexstr(bb, nb); fprint(2, "audio control unknown: %s\n", hd); free(hd); } break; case 2: // stream switch (b[2]){ case 0x01: dprint(2, "Audio stream for TerminalID %d, delay %d, format_tag %#ux\n", b[3], b[4], b[5] | (b[6]<<8)); break; case 0x02: aa = (Audioalt *)dd->altc->aux; if(aa == nil){ aa = mallocz(sizeof(Audioalt), 1); dd->altc->aux = aa; } if(verbose){ if(b[4] <= 2) fprint(2, "Interface %d: %s, %d bits, ", dd->iface->id, (b[4] == 1)?"mono":"stereo", b[6]); else fprint(2, "Interface %d, %d channels, %d bits, ", dd->iface->id, b[4], b[6]); } if(b[7] == 0){ if(verbose) fprint(2, "frequency variable between %d and %d\n", b[8] | b[9]<<8 | b[10]<<16, b[11] | b[12]<<8 | b[13]<<16); aa->minfreq = b[8] | b[9]<<8 | b[10]<<16; aa->maxfreq = b[11] | b[12]<<8 | b[13]<<16; aa->caps |= has_contfreq; }else{ if(verbose) fprint(2, "discrete frequencies are:"); for(ch = 0; ch < b[7] && ch < 8; ch++){ aa->freqs[ch] = b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16; if(verbose) fprint(2, " %d", b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16); } if(ch < 8) aa->freqs[ch] = -1; if(verbose) fprint(2, "\n"); if(ch > 1) aa->caps |= has_discfreq; /* more than one frequency */ else aa->caps |= onefreq; /* only one frequency */ } aa->nchan = b[4]; aa->res = b[6]; aa->subframesize = b[5]; break; default: if(usbdebug){ hd = hexstr(bb, nb); fprint(2, "audio stream unknown: %s\n", hd); free(hd); } } break; case 3: // midi default: if(usbdebug){ hd = hexstr(bb, nb); fprint(2, "Unknown audio stream type: CS_INTERFACE: %s\n", hd); free(hd); } } } usb/audio/mkfile 664 0 0 516 11202312257 11605ustar00syssys #include #include #include #include #include "scsireq.h" #include "usb.h" #include "usbfs.h" #include "ums.h" enum { Qdir = 0, Qctl, Qraw, Qdata, Qmax, }; typedef struct Dirtab Dirtab; struct Dirtab { char *name; int mode; }; static Dirtab dirtab[] = { [Qdir] "/", DMDIR|0555, [Qctl] "ctl", 0664, /* nothing secret here */ [Qraw] "raw", 0640, [Qdata] "data", 0640, }; /* * These are used by scuzz scsireq */ int exabyte, force6bytecmds; long maxiosize = MaxIOsize; static int diskdebug; static int getmaxlun(Dev *dev) { uchar max; int r; max = 0; r = Rd2h|Rclass|Riface; if(usbcmd(dev, r, Getmaxlun, 0, 0, &max, 1) < 0){ dprint(2, "disk: %s: getmaxlun failed: %r\n", dev->dir); }else{ max &= 017; /* 15 is the max. allowed */ dprint(2, "disk: %s: maxlun %d\n", dev->dir, max); } return max; } static int umsreset(Ums *ums) { int r; r = Rh2d|Rclass|Riface; if(usbcmd(ums->dev, r, Umsreset, 0, 0, nil, 0) < 0){ fprint(2, "disk: reset: %r\n"); return -1; } return 0; } static int umsrecover(Ums *ums) { if(umsreset(ums) < 0) return -1; if(unstall(ums->dev, ums->epin, Ein) < 0) dprint(2, "disk: unstall epin: %r\n"); /* do we need this when epin == epout? */ if(unstall(ums->dev, ums->epout, Eout) < 0) dprint(2, "disk: unstall epout: %r\n"); return 0; } static void umsfatal(Ums *ums) { int i; devctl(ums->dev, "detach"); for(i = 0; i < ums->maxlun; i++) usbfsdel(&ums->lun[i].fs); } static int umscapacity(Umsc *lun) { uchar data[32]; lun->blocks = 0; lun->capacity = 0; lun->lbsize = 0; if(SRrcapacity(lun, data) < 0 && SRrcapacity(lun, data) < 0) return -1; lun->blocks = GETBELONG(data); lun->lbsize = GETBELONG(data+4); if(lun->blocks == 0xFFFFFFFF){ if(SRrcapacity16(lun, data) < 0){ lun->lbsize = 0; lun->blocks = 0; return -1; }else{ lun->lbsize = GETBELONG(data + 8); lun->blocks = (uvlong)GETBELONG(data)<<32 | GETBELONG(data + 4); } } lun->blocks++; /* SRcapacity returns LBA of last block */ lun->capacity = (vlong)lun->blocks * lun->lbsize; return 0; } static int umsinit(Ums *ums) { uchar i; Umsc *lun; int some; umsreset(ums); ums->maxlun = getmaxlun(ums->dev); ums->lun = mallocz((ums->maxlun+1) * sizeof(*ums->lun), 1); some = 0; for(i = 0; i <= ums->maxlun; i++){ lun = &ums->lun[i]; lun->ums = ums; lun->umsc = lun; lun->lun = i; lun->flags = Fopen | Fusb | Frw10; if(SRinquiry(lun) < 0 && SRinquiry(lun) < 0){ dprint(2, "disk: lun %d inquiry failed\n", i); continue; } switch(lun->inquiry[0]){ case Devdir: case Devworm: /* a little different than the others */ case Devcd: case Devmo: break; default: fprint(2, "disk: lun %d is not a disk (type %#02x)\n", i, lun->inquiry[0]); continue; } SRstart(lun, 1); /* * we ignore the device type reported by inquiry. * Some devices return a wrong value but would still work. */ some++; lun->inq = smprint("%.48s", (char *)lun->inquiry+8); umscapacity(lun); } if(some == 0){ dprint(2, "disk: all luns failed\n"); devctl(ums->dev, "detach"); return -1; } return 0; } /* * called by SR*() commands provided by scuzz's scsireq */ long umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status) { Cbw cbw; Csw csw; int n, nio; Ums *ums; ums = umsc->ums; memcpy(cbw.signature, "USBC", 4); cbw.tag = ++ums->seq; cbw.datalen = data->count; cbw.flags = data->write? CbwDataOut: CbwDataIn; cbw.lun = umsc->lun; if(cmd->count < 1 || cmd->count > 16) print("disk: umsrequest: bad cmd count: %ld\n", cmd->count); cbw.len = cmd->count; assert(cmd->count <= sizeof(cbw.command)); memcpy(cbw.command, cmd->p, cmd->count); memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count); werrstr(""); /* we use %r later even for n == 0 */ if(diskdebug){ fprint(2, "disk: cmd: tag %#lx: ", cbw.tag); for(n = 0; n < cbw.len; n++) fprint(2, " %2.2x", cbw.command[n]&0xFF); fprint(2, " datalen: %ld\n", cbw.datalen); } if(write(ums->epout->dfd, &cbw, CbwLen) != CbwLen){ fprint(2, "disk: cmd: %r\n"); goto Fail; } nio = data->count; if(data->count != 0){ if(data->write) n = nio = write(ums->epout->dfd, data->p, data->count); else{ memset(data->p, data->count, 0); n = nio = read(ums->epin->dfd, data->p, data->count); } if(diskdebug) if(n < 0) fprint(2, "disk: data: %r\n"); else fprint(2, "disk: data: %d bytes\n", n); if(n <= 0) if(data->write == 0) unstall(ums->dev, ums->epin, Ein); } n = read(ums->epin->dfd, &csw, CswLen); if(n <= 0){ /* n == 0 means "stalled" */ unstall(ums->dev, ums->epin, Ein); n = read(ums->epin->dfd, &csw, CswLen); } if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){ dprint(2, "disk: read n=%d: status: %r\n", n); goto Fail; } if(csw.tag != cbw.tag){ dprint(2, "disk: status tag mismatch\n"); goto Fail; } if(csw.status >= CswPhaseErr){ dprint(2, "disk: phase error\n"); goto Fail; } if(csw.dataresidue == 0 || ums->wrongresidues) csw.dataresidue = data->count - nio; if(diskdebug){ fprint(2, "disk: status: %2.2ux residue: %ld\n", csw.status, csw.dataresidue); if(cbw.command[0] == ScmdRsense){ fprint(2, "sense data:"); for(n = 0; n < data->count - csw.dataresidue; n++) fprint(2, " %2.2x", data->p[n]); fprint(2, "\n"); } } switch(csw.status){ case CswOk: *status = STok; break; case CswFailed: *status = STcheck; break; default: dprint(2, "disk: phase error\n"); goto Fail; } ums->nerrs = 0; return data->count - csw.dataresidue; Fail: *status = STharderr; if(ums->nerrs++ > 15){ fprint(2, "disk: %s: too many errors: device detached\n", ums->dev->dir); umsfatal(ums); }else umsrecover(ums); return -1; } static int dwalk(Usbfs *fs, Fid *fid, char *name) { int i; Qid qid; qid = fid->qid; if((qid.type & QTDIR) == 0){ werrstr("walk in non-directory"); return -1; } if(strcmp(name, "..") == 0) return 0; for(i = 1; i < nelem(dirtab); i++) if(strcmp(name, dirtab[i].name) == 0){ qid.path = i | fs->qid; qid.vers = 0; qid.type = dirtab[i].mode >> 24; fid->qid = qid; return 0; } werrstr(Enotfound); return -1; } static void dostat(Usbfs *fs, int path, Dir *d) { Dirtab *t; Umsc *lun; t = &dirtab[path]; d->qid.path = path; d->qid.type = t->mode >> 24; d->mode = t->mode; d->name = t->name; lun = fs->aux; if(path == Qdata) d->length = lun->capacity; else d->length = 0; } static int dirgen(Usbfs *fs, Qid, int i, Dir *d, void*) { i++; /* skip dir */ if(i >= Qmax) return -1; else{ dostat(fs, i, d); d->qid.path |= fs->qid; return 0; } } static int dstat(Usbfs *fs, Qid qid, Dir *d) { int path; path = qid.path & ~fs->qid; dostat(fs, path, d); d->qid.path |= fs->qid; return 0; } static int dopen(Usbfs *fs, Fid *fid, int) { ulong path; Umsc *lun; path = fid->qid.path & ~fs->qid; lun = fs->aux; switch(path){ case Qraw: lun->phase = Pcmd; break; } return 0; } /* * Upon SRread/SRwrite errors we assume the medium may have changed, * and ask again for the capacity of the media. * BUG: How to proceed to avoid confussing dossrv?? */ static long dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) { long bno, nb, len, off, n; ulong path; char buf[1024], *p; char *s, *e; Umsc *lun; Ums *ums; Qid q; q = fid->qid; path = fid->qid.path & ~fs->qid; ums = fs->dev->aux; lun = fs->aux; qlock(ums); switch(path){ case Qdir: count = usbdirread(fs, q, data, count, offset, dirgen, nil); break; case Qctl: e = buf + sizeof(buf); s = seprint(buf, e, "%s lun %ld: ", fs->dev->dir, lun - &ums->lun[0]); if(lun->flags & Finqok) s = seprint(s, e, "inquiry %s ", lun->inq); if(lun->blocks > 0) s = seprint(s, e, "geometry %llud %ld", lun->blocks, lun->lbsize); s = seprint(s, e, "\n"); count = usbreadbuf(data, count, offset, buf, s - buf); break; case Qraw: if(lun->lbsize <= 0 && umscapacity(lun) < 0){ qunlock(ums); return -1; } switch(lun->phase){ case Pcmd: qunlock(ums); werrstr("phase error"); return -1; case Pdata: lun->data.p = (uchar*)data; lun->data.count = count; lun->data.write = 0; count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status); lun->phase = Pstatus; if(count < 0){ lun->lbsize = 0; /* medium may have changed */ qunlock(ums); return -1; } break; case Pstatus: n = snprint(buf, sizeof buf, "%11.0ud ", lun->status); count = usbreadbuf(data, count, 0LL, buf, n); lun->phase = Pcmd; break; } break; case Qdata: if(lun->lbsize <= 0 && umscapacity(lun) < 0){ qunlock(ums); return -1; } bno = offset / lun->lbsize; nb = (offset + count + lun->lbsize - 1) / lun->lbsize - bno; if(bno + nb > lun->blocks) nb = lun->blocks - bno; if(bno >= lun->blocks || nb == 0){ count = 0; break; } if(nb * lun->lbsize > maxiosize) nb = maxiosize / lun->lbsize; p = emallocz(nb * lun->lbsize, 0); /* could use a static buffer */ lun->offset = offset / lun->lbsize; n = SRread(lun, p, nb * lun->lbsize); if(n < 0){ free(p); lun->lbsize = 0; /* medium may have changed */ qunlock(ums); return -1; } len = count; off = offset % lun->lbsize; if(off + len > n) len = n - off; count = len; memmove(data, p + off, len); free(p); break; } qunlock(ums); return count; } static long dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong offset) { int bno, nb, len, off; ulong path; char *p; Ums *ums; Umsc *lun; char *data; ums = fs->dev->aux; lun = fs->aux; path = fid->qid.path & ~fs->qid; data = buf; qlock(ums); switch(path){ default: qunlock(ums); werrstr(Eperm); return -1; case Qctl: qunlock(ums); dprint(2, "usb/disk: ctl ignored\n"); return count; case Qraw: if(lun->lbsize <= 0 && umscapacity(lun) < 0){ qunlock(ums); return -1; } switch(lun->phase){ case Pcmd: if(count != 6 && count != 10){ qunlock(ums); werrstr("bad command length"); return -1; } memmove(lun->rawcmd, data, count); lun->cmd.p = lun->rawcmd; lun->cmd.count = count; lun->cmd.write = 1; lun->phase = Pdata; break; case Pdata: lun->data.p = (uchar*)data; lun->data.count = count; lun->data.write = 1; count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status); lun->phase = Pstatus; if(count < 0){ lun->lbsize = 0; /* medium may have changed */ qunlock(ums); return -1; } break; case Pstatus: lun->phase = Pcmd; qunlock(ums); werrstr("phase error"); return -1; } break; case Qdata: if(lun->lbsize <= 0 && umscapacity(lun) < 0){ qunlock(ums); return -1; } bno = offset / lun->lbsize; nb = (offset + count + lun->lbsize-1) / lun->lbsize - bno; if(bno + nb > lun->blocks) nb = lun->blocks - bno; if(bno >= lun->blocks || nb == 0){ count = 0; break; } if(nb * lun->lbsize > maxiosize) nb = maxiosize / lun->lbsize; p = emallocz(nb * lun->lbsize, 0); off = offset % lun->lbsize; len = count; if(off || (len % lun->lbsize) != 0){ lun->offset = offset / lun->lbsize; count = SRread(lun, p, nb * lun->lbsize); if(count < 0){ free(p); lun->lbsize = 0; /* medium may have changed */ qunlock(ums); return -1; } if(off + len > count) len = count - off; } memmove(p+off, data, len); lun->offset = offset / lun->lbsize; count = SRwrite(lun, p, nb * lun->lbsize); if(count < 0){ free(p); lun->lbsize = 0; /* medium may have changed */ qunlock(ums); return -1; } if(off+len > count) len = count - off; count = len; free(p); break; } qunlock(ums); return count; } int findendpoints(Ums *ums) { Ep *ep; Usbdev *ud; ulong csp, sc; int i, epin, epout; epin = epout = -1; ud = ums->dev->usb; for(i = 0; i < nelem(ud->ep); i++){ if((ep = ud->ep[i]) == nil) continue; csp = ep->iface->csp; sc = Subclass(csp); if(!(Class(csp) == Clstorage && (Proto(csp) == Protobulk))) continue; if(sc != Subatapi && sc != Sub8070 && sc != Subscsi) fprint(2, "disk: subclass %#ulx not supported. trying anyway\n", sc); if(ep->type == Ebulk){ if(ep->dir == Eboth || ep->dir == Ein) if(epin == -1) epin = ep->id; if(ep->dir == Eboth || ep->dir == Eout) if(epout == -1) epout = ep->id; } } dprint(2, "disk: ep ids: in %d out %d\n", epin, epout); if(epin == -1 || epout == -1) return -1; ums->epin = openep(ums->dev, epin); if(ums->epin == nil){ fprint(2, "disk: openep %d: %r\n", epin); return -1; } if(epout == epin){ incref(ums->epin); ums->epout = ums->epin; }else ums->epout = openep(ums->dev, epout); if(ums->epout == nil){ fprint(2, "disk: openep %d: %r\n", epout); closedev(ums->epin); return -1; } if(ums->epin == ums->epout) opendevdata(ums->epin, ORDWR); else{ opendevdata(ums->epin, OREAD); opendevdata(ums->epout, OWRITE); } if(ums->epin->dfd < 0 || ums->epout->dfd < 0){ fprint(2, "disk: open i/o ep data: %r\n"); closedev(ums->epin); closedev(ums->epout); return -1; } dprint(2, "disk: ep in %s out %s\n", ums->epin->dir, ums->epout->dir); devctl(ums->epin, "timeout 2000"); devctl(ums->epout, "timeout 2000"); if(usbdebug > 1 || diskdebug > 2){ devctl(ums->epin, "debug 1"); devctl(ums->epout, "debug 1"); devctl(ums->dev, "debug 1"); } return 0; } static int usage(void) { werrstr("usage: usb/disk [-d] [-N nb]"); return -1; } static void umsdevfree(void *a) { Ums *ums = a; if(ums == nil) return; closedev(ums->epin); closedev(ums->epout); ums->epin = ums->epout = nil; free(ums->lun); free(ums); } static Usbfs diskfs = { .walk = dwalk, .open = dopen, .read = dread, .write = dwrite, .stat = dstat, }; int diskmain(Dev *dev, int argc, char **argv) { Ums *ums; Umsc *lun; int i, devid; devid = dev->id; ARGBEGIN{ case 'd': scsidebug(diskdebug); diskdebug++; break; case 'N': devid = atoi(EARGF(usage())); break; default: return usage(); }ARGEND if(argc != 0) { return usage(); } ums = dev->aux = emallocz(sizeof(Ums), 1); ums->maxlun = -1; ums->dev = dev; dev->free = umsdevfree; if(findendpoints(ums) < 0){ werrstr("disk: endpoints not found"); return -1; } /* * SanDISK 512M gets residues wrong. */ if(dev->usb->vid == 0x0781 && dev->usb->did == 0x5150) ums->wrongresidues = 1; if(umsinit(ums) < 0){ dprint(2, "disk: umsinit: %r\n"); return -1; } for(i = 0; i <= ums->maxlun; i++){ lun = &ums->lun[i]; lun->fs = diskfs; snprint(lun->fs.name, sizeof(lun->fs.name), "sdU%d.%d", devid, i); lun->fs.dev = dev; incref(dev); lun->fs.aux = lun; usbfsadd(&lun->fs); } return 0; } dev, ums->epin, Ein); } n = read(ums->epin->dfd, &csw, CswLen); if(n <= 0){ /* n == 0 means "stalled" */ unstall(ums->dev, ums->epin, Ein); n = read(ums->epin->dfd, &csw, CswLen); } if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){ dprint(2, "disk: read n=%d: status: %r\n", n); goto Fail; } if(csw.tag != cbw.tag){ dprint(2, "disk: status tag mismatch\n"); gousb/disk/main.c 664 0 0 2232 11412732223 11353ustar00syssys/* * usb/disk - usb mass storage file server */ #include #include #include #include #include "scsireq.h" #include "usb.h" #include "usbfs.h" #include "ums.h" enum { Arglen = 80, }; static void usage(void) { fprint(2, "usage: %s [-Dd] [-N nb] [-m mnt] [-s srv] [dev...]\n", argv0); threadexitsall("usage"); } static int csps[] = { CSP(Clstorage,Subatapi,Protobulk), CSP(Clstorage,Sub8070,Protobulk), CSP(Clstorage,Subscsi,Protobulk), 0, }; void threadmain(int argc, char **argv) { char args[Arglen]; char *as, *ae, *srv, *mnt; srv = nil; mnt = "/n/disk"; quotefmtinstall(); ae = args+sizeof(args); as = seprint(args, ae, "disk"); ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'N': as = seprint(as, ae, " -N %s", EARGF(usage())); break; case 'm': mnt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); }ARGEND rfork(RFNOTEG); threadsetgrp(threadid()); fmtinstall('U', Ufmt); usbfsinit(srv, mnt, &usbdirfs, MBEFORE); startdevs(args, argv, argc, matchdevcsp, csps, diskmain); threadexits(nil); } return -1; else{ dostat(fs, i, d); d->qid.path |= fs->qid; return 0; } } static int dstat(Usbfs *fs, Qid qid, Dir *d) { int path; path = qid.path & ~fs->qid; dostat(fs, path, d); d->qid.path |= fs->qid; return 0; } static int dopen(Usbfs *fs, Fid *fid, int) { ulong path; Umsc *lun; path = fid->qid.path & ~fs->qid; lun = fs->aux; swusb/disk/mkfile 664 0 0 747 11202312257 11444ustar00syssysscsierrs.c usb/disk/mkscsierrs 775 0 0 643 11202312257 12360ustar00syssys#!/bin/rc cat < #include typedef struct Err Err; struct Err { int n; char *s; }; static Err scsierrs[] = { EOF grep '^[0-9a-c][0-9a-c][0-9a-c][0-9a-c][ ]' /sys/lib/scsicodes | sed -e 's/^(....) (.*)/ {0x\1, "\2"},\n/' cat <lun/unit in SRreqsense * we set the rp->sense[0] bit Sd0valid in SRreqsense * This does not use libdisk to retrieve the scsi error to make * user we see the diagnostics if we boot with debug enabled. * */ #include #include /* * BUGS: * no luns * and incomplete in many other ways */ #include "scsireq.h" enum { Debug = 0, }; /* * exabyte tape drives, at least old ones like the 8200 and 8505, * are dumb: you have to read the exact block size on the tape, * they don't take 10-byte SCSI commands, and various other fine points. */ extern int exabyte, force6bytecmds; static int debug = Debug; static char *scmdnames[256] = { [ScmdTur] "Tur", [ScmdRewind] "Rewind", [ScmdRsense] "Rsense", [ScmdFormat] "Format", [ScmdRblimits] "Rblimits", [ScmdRead] "Read", [ScmdWrite] "Write", [ScmdSeek] "Seek", [ScmdFmark] "Fmark", [ScmdSpace] "Space", [ScmdInq] "Inq", [ScmdMselect6] "Mselect6", [ScmdMselect10] "Mselect10", [ScmdMsense6] "Msense6", [ScmdMsense10] "Msense10", [ScmdStart] "Start", [ScmdRcapacity] "Rcapacity", [ScmdRcapacity16] "Rcap16", [ScmdExtread] "Extread", [ScmdExtwrite] "Extwrite", [ScmdExtseek] "Extseek", [ScmdSynccache] "Synccache", [ScmdRTOC] "RTOC", [ScmdRdiscinfo] "Rdiscinfo", [ScmdRtrackinfo] "Rtrackinfo", [ScmdReserve] "Reserve", [ScmdBlank] "Blank", [ScmdCDpause] "CDpause", [ScmdCDstop] "CDstop", [ScmdCDplay] "CDplay", [ScmdCDload] "CDload", [ScmdCDscan] "CDscan", [ScmdCDstatus] "CDstatus", [Scmdgetconf] "getconf", }; long SRready(ScsiReq *rp) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; return SRrequest(rp); } long SRrewind(ScsiReq *rp) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdRewind; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; if(SRrequest(rp) >= 0){ rp->offset = 0; return 0; } return -1; } long SRreqsense(ScsiReq *rp) { uchar cmd[6]; ScsiReq req; long status; if(rp->status == Status_SD){ rp->status = STok; return 0; } memset(cmd, 0, sizeof cmd); cmd[0] = ScmdRsense; cmd[4] = sizeof(req.sense); memset(&req, 0, sizeof(req)); if(rp->flags&Fusb) req.flags |= Fusb; req.lun = rp->lun; req.unit = rp->unit; req.fd = rp->fd; req.umsc = rp->umsc; req.cmd.p = cmd; req.cmd.count = sizeof cmd; req.data.p = rp->sense; req.data.count = sizeof(rp->sense); req.data.write = 0; status = SRrequest(&req); rp->status = req.status; if(status != -1) rp->sense[0] |= Sd0valid; return status; } long SRformat(ScsiReq *rp) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdFormat; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 6; rp->data.write = 0; return SRrequest(rp); } long SRrblimits(ScsiReq *rp, uchar *list) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdRblimits; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = list; rp->data.count = 6; rp->data.write = 0; return SRrequest(rp); } static int dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes) { long n; n = nbytes / rp->lbsize; if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){ PUTBE24(cmd+1, rp->offset); cmd[4] = n; cmd[5] = 0; return 6; } cmd[0] |= ScmdExtread; cmd[1] = 0; PUTBELONG(cmd+2, rp->offset); cmd[6] = 0; cmd[7] = n>>8; cmd[8] = n; cmd[9] = 0; return 10; } static int seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes) { long n; /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */ cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0; n = nbytes / rp->lbsize; PUTBE24(cmd+2, n); cmd[5] = 0; return 6; } long SRread(ScsiReq *rp, void *buf, long nbytes) { uchar cmd[10]; long n; if((nbytes % rp->lbsize) || nbytes > maxiosize){ rp->status = Status_BADARG; return -1; } /* set up scsi read cmd */ cmd[0] = ScmdRead; if(rp->flags & Fseqdev) rp->cmd.count = seqdevrw(rp, cmd, nbytes); else rp->cmd.count = dirdevrw(rp, cmd, nbytes); rp->cmd.p = cmd; rp->data.p = buf; rp->data.count = nbytes; rp->data.write = 0; /* issue it */ n = SRrequest(rp); if(n != -1){ /* it worked? */ rp->offset += n / rp->lbsize; return n; } /* request failed; maybe we just read a short record? */ if (exabyte) { fprint(2, "read error\n"); rp->status = STcheck; return n; } if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid)) return -1; /* compute # of bytes not read */ n = GETBELONG(rp->sense+3) * rp->lbsize; if(!(rp->flags & Fseqdev)) return -1; /* device is a tape or something similar */ if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 || rp->sense[2] & Sd2ili && n > 0) rp->data.count = nbytes - n; else return -1; n = rp->data.count; if (!rp->readblock++ || debug) fprint(2, "SRread: tape data count %ld%s\n", n, (rp->sense[2] & Sd2ili? " with ILI": "")); rp->status = STok; rp->offset += n / rp->lbsize; return n; } long SRwrite(ScsiReq *rp, void *buf, long nbytes) { uchar cmd[10]; long n; if((nbytes % rp->lbsize) || nbytes > maxiosize){ rp->status = Status_BADARG; return -1; } /* set up scsi write cmd */ cmd[0] = ScmdWrite; if(rp->flags & Fseqdev) rp->cmd.count = seqdevrw(rp, cmd, nbytes); else rp->cmd.count = dirdevrw(rp, cmd, nbytes); rp->cmd.p = cmd; rp->data.p = buf; rp->data.count = nbytes; rp->data.write = 1; /* issue it */ if((n = SRrequest(rp)) == -1){ if (exabyte) { fprint(2, "write error\n"); rp->status = STcheck; return n; } if(rp->status != Status_SD || rp->sense[2] != Sd2eom) return -1; if(rp->sense[0] & Sd0valid){ n -= GETBELONG(rp->sense+3) * rp->lbsize; rp->data.count = nbytes - n; } else rp->data.count = nbytes; n = rp->data.count; } rp->offset += n / rp->lbsize; return n; } long SRseek(ScsiReq *rp, long offset, int type) { uchar cmd[10]; switch(type){ case 0: break; case 1: offset += rp->offset; if(offset >= 0) break; /*FALLTHROUGH*/ default: rp->status = Status_BADARG; return -1; } memset(cmd, 0, sizeof cmd); if(offset <= Max24off && (rp->flags & Frw10) == 0){ cmd[0] = ScmdSeek; PUTBE24(cmd+1, offset & Max24off); rp->cmd.count = 6; }else{ cmd[0] = ScmdExtseek; PUTBELONG(cmd+2, offset); rp->cmd.count = 10; } rp->cmd.p = cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; SRrequest(rp); if(rp->status == STok) return rp->offset = offset; return -1; } long SRfilemark(ScsiReq *rp, ulong howmany) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdFmark; PUTBE24(cmd+2, howmany); rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; return SRrequest(rp); } long SRspace(ScsiReq *rp, uchar code, long howmany) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdSpace; cmd[1] = code; PUTBE24(cmd+2, howmany); rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; /* * what about rp->offset? */ return SRrequest(rp); } long SRinquiry(ScsiReq *rp) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdInq; cmd[4] = sizeof rp->inquiry; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; memset(rp->inquiry, 0, sizeof rp->inquiry); rp->data.p = rp->inquiry; rp->data.count = sizeof rp->inquiry; rp->data.write = 0; if(SRrequest(rp) >= 0){ rp->flags |= Finqok; return 0; } rp->flags &= ~Finqok; return -1; } long SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdMselect6; if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) cmd[1] = 0x10; cmd[4] = nbytes; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = list; rp->data.count = nbytes; rp->data.write = 1; return SRrequest(rp); } long SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes) { uchar cmd[10]; memset(cmd, 0, sizeof cmd); if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2) cmd[1] = 0x10; cmd[0] = ScmdMselect10; cmd[7] = nbytes>>8; cmd[8] = nbytes; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = list; rp->data.count = nbytes; rp->data.write = 1; return SRrequest(rp); } long SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdMsense6; cmd[2] = page; cmd[4] = nbytes; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = list; rp->data.count = nbytes; rp->data.write = 0; return SRrequest(rp); } long SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes) { uchar cmd[10]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdMsense10; cmd[2] = page; cmd[7] = nbytes>>8; cmd[8] = nbytes; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = list; rp->data.count = nbytes; rp->data.write = 0; return SRrequest(rp); } long SRstart(ScsiReq *rp, uchar code) { uchar cmd[6]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdStart; cmd[4] = code; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = cmd; rp->data.count = 0; rp->data.write = 1; return SRrequest(rp); } long SRrcapacity(ScsiReq *rp, uchar *data) { uchar cmd[10]; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdRcapacity; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = data; rp->data.count = 8; rp->data.write = 0; return SRrequest(rp); } long SRrcapacity16(ScsiReq *rp, uchar *data) { uchar cmd[16]; uint i; i = 32; memset(cmd, 0, sizeof cmd); cmd[0] = ScmdRcapacity16; cmd[1] = 0x10; cmd[10] = i>>24; cmd[11] = i>>16; cmd[12] = i>>8; cmd[13] = i; rp->cmd.p = cmd; rp->cmd.count = sizeof cmd; rp->data.p = data; rp->data.count = i; rp->data.write = 0; return SRrequest(rp); } void scsidebug(int d) { debug = d; if(debug) fprint(2, "scsidebug on\n"); } static long request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status) { long n, r; char buf[16]; /* this was an experiment but it seems to be a good idea */ *status = STok; /* send SCSI command */ if(write(fd, cmd->p, cmd->count) != cmd->count){ fprint(2, "scsireq: write cmd: %r\n"); *status = Status_SW; return -1; } /* read or write actual data */ werrstr(""); if(data->write) n = write(fd, data->p, data->count); else { n = read(fd, data->p, data->count); if (n < 0) memset(data->p, 0, data->count); else if (n < data->count) memset(data->p + n, 0, data->count - n); } if (n != data->count && n <= 0) { if (debug) fprint(2, "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n", (data->write? "write": "read"), data->count, cmd->p[0]); } else if (n != data->count && (data->write || debug)) fprint(2, "request: %s %ld of %ld bytes of actual data\n", (data->write? "wrote": "read"), n, data->count); /* read status */ buf[0] = '\0'; r = read(fd, buf, sizeof buf-1); if(exabyte && r <= 0 || !exabyte && r < 0){ fprint(2, "scsireq: read status: %r\n"); *status = Status_SW; return -1; } if (r >= 0) buf[r] = '\0'; *status = atoi(buf); if(n < 0 && (exabyte || *status != STcheck)) fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", *status); return n; } static char* seprintcmd(char *s, char* e, char *cmd, int count, int args) { uint c; if(count < 6) return seprint(s, e, ""); c = cmd[0]; if(scmdnames[c] != nil) s = seprint(s, e, "%s", scmdnames[c]); else s = seprint(s, e, "cmd:%#02uX", c); if(args != 0) switch(c){ case ScmdRsense: case ScmdInq: case ScmdMselect6: case ScmdMsense6: s = seprint(s, e, " sz %d", cmd[4]); break; case ScmdSpace: s = seprint(s, e, " code %d", cmd[1]); break; case ScmdStart: s = seprint(s, e, " code %d", cmd[4]); break; } return s; } static char* seprintdata(char *s, char *se, uchar *p, int count) { int i; if(count == 0) return s; for(i = 0; i < 20 && i < count; i++) s = seprint(s, se, " %02x", p[i]); return s; } static void SRdumpReq(ScsiReq *rp) { char buf[128]; char *s; char *se; se = buf+sizeof(buf); s = seprint(buf, se, "lun %d ", rp->lun); s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1); s = seprint(s, se, " [%ld]", rp->data.count); if(rp->cmd.write) seprintdata(s, se, rp->data.p, rp->data.count); fprint(2, "scsi⇒ %s\n", buf); } static void SRdumpRep(ScsiReq *rp) { char buf[128]; char *s; char *se; se = buf+sizeof(buf); s = seprint(buf, se, "lun %d ", rp->lun); s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0); switch(rp->status){ case STok: s = seprint(s, se, " good [%ld] ", rp->data.count); if(rp->cmd.write == 0) s = seprintdata(s, se, rp->data.p, rp->data.count); break; case STnomem: s = seprint(s, se, " buffer allocation failed"); break; case STharderr: s = seprint(s, se, " controller error"); break; case STtimeout: s = seprint(s, se, " bus timeout"); break; case STcheck: s = seprint(s, se, " check condition"); break; case STcondmet: s = seprint(s, se, " condition met/good"); break; case STbusy: s = seprint(s, se, " busy"); break; case STintok: s = seprint(s, se, " intermediate/good"); break; case STintcondmet: s = seprint(s, se, " intermediate/condition met/good"); break; case STresconf: s = seprint(s, se, " reservation conflict"); break; case STterminated: s = seprint(s, se, " command terminated"); break; case STqfull: s = seprint(s, se, " queue full"); break; default: s = seprint(s, se, " sts=%#x", rp->status); } USED(s); fprint(2, "scsi↠%s\n", buf); } static char* scsierr(ScsiReq *rp) { int ec; switch(rp->status){ case 0: return ""; case Status_SD: ec = (rp->sense[12] << 8) | rp->sense[13]; return scsierrmsg(ec); case Status_SW: return "software error"; case Status_BADARG: return "bad argument"; case Status_RO: return "device is read only"; default: return "unknown"; } } static void SRdumpErr(ScsiReq *rp) { char buf[128]; char *se; se = buf+sizeof(buf); seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0); print("\t%s status: %s\n", buf, scsierr(rp)); } long SRrequest(ScsiReq *rp) { long n; int status; retry: if(debug) SRdumpReq(rp); if(rp->flags&Fusb) n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status); else n = request(rp->fd, &rp->cmd, &rp->data, &status); rp->status = status; if(status == STok) rp->data.count = n; if(debug) SRdumpRep(rp); switch(status){ case STok: break; case STcheck: if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1) rp->status = Status_SD; if(debug || exabyte) SRdumpErr(rp); werrstr("%s", scsierr(rp)); return -1; case STbusy: sleep(1000); goto retry; default: if(debug || exabyte) SRdumpErr(rp); werrstr("%s", scsierr(rp)); return -1; } return n; } int SRclose(ScsiReq *rp) { if((rp->flags & Fopen) == 0){ rp->status = Status_BADARG; return -1; } close(rp->fd); rp->flags = 0; return 0; } static int dirdevopen(ScsiReq *rp) { ulong blocks; uchar data[8]; if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1) return -1; rp->lbsize = GETBELONG(data+4); blocks = GETBELONG(data); if(blocks == 0xffffffff){ if(SRrcapacity16(rp, data) == -1) return -1; rp->lbsize = GETBELONG(data + 8); blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4); } /* some newer dev's don't support 6-byte commands */ if(blocks > Max24off && !force6bytecmds) rp->flags |= Frw10; return 0; } static int seqdevopen(ScsiReq *rp) { uchar mode[16], limits[6]; if(SRrblimits(rp, limits) == -1) return -1; if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){ rp->flags |= Fbfixed; rp->lbsize = limits[4]<<8 | limits[5]; return 0; } /* * On some older hardware the optional 10-byte * modeselect command isn't implemented. */ if (force6bytecmds) rp->flags |= Fmode6; if(!(rp->flags & Fmode6)){ /* try 10-byte command first */ memset(mode, 0, sizeof mode); mode[3] = 0x10; /* device-specific param. */ mode[7] = 8; /* block descriptor length */ /* * exabytes can't handle this, and * modeselect(10) is optional. */ if(SRmodeselect10(rp, mode, sizeof mode) != -1){ rp->lbsize = 1; return 0; /* success */ } /* can't do 10-byte commands, back off to 6-byte ones */ rp->flags |= Fmode6; } /* 6-byte command */ memset(mode, 0, sizeof mode); mode[2] = 0x10; /* device-specific param. */ mode[3] = 8; /* block descriptor length */ /* * bsd sez exabytes need this bit (NBE: no busy enable) in * vendor-specific page (0), but so far we haven't needed it. mode[12] |= 8; */ if(SRmodeselect6(rp, mode, 4+8) == -1) return -1; rp->lbsize = 1; return 0; } static int wormdevopen(ScsiReq *rp) { long status; uchar list[MaxDirData]; if (SRstart(rp, 1) == -1 || (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1) return -1; /* nbytes = list[0]<<8 | list[1]; */ /* # of bytes of block descriptors of 8 bytes each; not even 1? */ if((list[6]<<8 | list[7]) < 8) rp->lbsize = 2048; else /* last 3 bytes of block 0 descriptor */ rp->lbsize = GETBE24(list+13); return status; } int SRopenraw(ScsiReq *rp, char *unit) { char name[128]; if(rp->flags & Fopen){ rp->status = Status_BADARG; return -1; } memset(rp, 0, sizeof *rp); rp->unit = unit; sprint(name, "%s/raw", unit); if((rp->fd = open(name, ORDWR)) == -1){ rp->status = STtimeout; return -1; } rp->flags = Fopen; return 0; } int SRopen(ScsiReq *rp, char *unit) { if(SRopenraw(rp, unit) == -1) return -1; SRready(rp); if(SRinquiry(rp) >= 0){ switch(rp->inquiry[0]){ default: fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]); rp->status = Status_SW; break; case Devdir: case Devcd: case Devmo: if(dirdevopen(rp) == -1) break; return 0; case Devseq: rp->flags |= Fseqdev; if(seqdevopen(rp) == -1) break; return 0; case Devprint: rp->flags |= Fprintdev; return 0; case Devworm: rp->flags |= Fwormdev; if(wormdevopen(rp) == -1) break; return 0; case Devjuke: rp->flags |= Fchanger; return 0; } } SRclose(rp); return -1; } memset(cmd, 0, sizeof cmd);usb/disk/scsireq.h 664 0 0 16430 11354447335 12146ustar00syssys/* * This is /sys/src/cmd/scuzz/scsireq.c * changed to add more debug support, to keep * disk compiling without a scuzz that includes these changes. */ /* this file is also included by usb/disk and cdfs */ typedef struct Umsc Umsc; #pragma incomplete Umsc enum { /* fundamental constants/defaults */ NTargetID = 8, /* number of target IDs */ CtlrID = 7, /* default controller target ID */ MaxDirData = 255, /* max. direct data returned */ LBsize = 512, /* default logical-block size */ }; typedef struct { uchar *p; long count; uchar write; } ScsiPtr; typedef struct { int flags; char *unit; /* unit directory */ int lun; ulong lbsize; ulong offset; /* in blocks of lbsize bytes */ int fd; Umsc *umsc; /* lun */ ScsiPtr cmd; ScsiPtr data; int status; /* returned status */ uchar sense[MaxDirData]; /* returned sense data */ uchar inquiry[MaxDirData]; /* returned inquiry data */ int readblock; /* flag: read a block since open */ } ScsiReq; enum { /* software flags */ Fopen = 0x0001, /* open */ Fseqdev = 0x0002, /* sequential-access device */ Fwritten = 0x0004, /* device written */ Fronly = 0x0008, /* device is read-only */ Fwormdev = 0x0010, /* write-once read-multiple device */ Fprintdev = 0x0020, /* printer */ Fbfixed = 0x0040, /* fixed block size */ Fchanger = 0x0080, /* medium-changer device */ Finqok = 0x0100, /* inquiry data is OK */ Fmode6 = 0x0200, /* use 6-byte modeselect */ Frw10 = 0x0400, /* use 10-byte read/write */ Fusb = 0x0800, /* USB transparent scsi */ }; enum { STnomem =-4, /* buffer allocation failed */ STharderr =-3, /* controller error of some kind */ STtimeout =-2, /* bus timeout */ STok = 0, /* good */ STcheck = 0x02, /* check condition */ STcondmet = 0x04, /* condition met/good */ STbusy = 0x08, /* busy */ STintok = 0x10, /* intermediate/good */ STintcondmet = 0x14, /* intermediate/condition met/good */ STresconf = 0x18, /* reservation conflict */ STterminated = 0x22, /* command terminated */ STqfull = 0x28, /* queue full */ }; enum { /* status */ Status_SD = 0x80, /* sense-data available */ Status_SW = 0x83, /* internal software error */ Status_BADARG = 0x84, /* bad argument to request */ Status_RO = 0x85, /* device is read-only */ }; enum { /* SCSI command codes */ ScmdTur = 0x00, /* test unit ready */ ScmdRewind = 0x01, /* rezero/rewind */ ScmdRsense = 0x03, /* request sense */ ScmdFormat = 0x04, /* format unit */ ScmdRblimits = 0x05, /* read block limits */ ScmdRead = 0x08, /* read */ ScmdWrite = 0x0A, /* write */ ScmdSeek = 0x0B, /* seek */ ScmdFmark = 0x10, /* write filemarks */ ScmdSpace = 0x11, /* space forward/backward */ ScmdInq = 0x12, /* inquiry */ ScmdMselect6 = 0x15, /* mode select */ ScmdMselect10 = 0x55, /* mode select */ ScmdMsense6 = 0x1A, /* mode sense */ ScmdMsense10 = 0x5A, /* mode sense */ ScmdStart = 0x1B, /* start/stop unit */ ScmdRcapacity = 0x25, /* read capacity */ ScmdRcapacity16 = 0x9e, /* long read capacity */ ScmdExtread = 0x28, /* extended read */ ScmdExtwrite = 0x2A, /* extended write */ ScmdExtseek = 0x2B, /* extended seek */ ScmdSynccache = 0x35, /* flush cache */ ScmdRTOC = 0x43, /* read TOC data */ ScmdRdiscinfo = 0x51, /* read disc information */ ScmdRtrackinfo = 0x52, /* read track information */ ScmdReserve = 0x53, /* reserve track */ ScmdBlank = 0xA1, /* blank *-RW media */ ScmdCDpause = 0x4B, /* pause/resume */ ScmdCDstop = 0x4E, /* stop play/scan */ ScmdCDplay = 0xA5, /* play audio */ ScmdCDload = 0xA6, /* load/unload */ ScmdCDscan = 0xBA, /* fast forward/reverse */ ScmdCDstatus = 0xBD, /* mechanism status */ Scmdgetconf = 0x46, /* get configuration */ ScmdEInitialise = 0x07, /* initialise element status */ ScmdMMove = 0xA5, /* move medium */ ScmdEStatus = 0xB8, /* read element status */ ScmdMExchange = 0xA6, /* exchange medium */ ScmdEposition = 0x2B, /* position to element */ ScmdReadDVD = 0xAD, /* read dvd structure */ ScmdReportKey = 0xA4, /* read dvd key */ ScmdSendKey = 0xA3, /* write dvd key */ ScmdClosetracksess= 0x5B, ScmdRead12 = 0xA8, ScmdSetcdspeed = 0xBB, ScmdReadcd = 0xBE, /* vendor-specific */ ScmdFwaddr = 0xE2, /* first writeable address */ ScmdTreserve = 0xE4, /* reserve track */ ScmdTinfo = 0xE5, /* read track info */ ScmdTwrite = 0xE6, /* write track */ ScmdMload = 0xE7, /* medium load/unload */ ScmdFixation = 0xE9, /* fixation */ }; enum { /* sense data byte 0 */ Sd0valid = 0x80, /* valid sense data present */ /* sense data byte 2 */ /* incorrect-length indicator, difference in bytes 3—6 */ Sd2ili = 0x20, Sd2eom = 0x40, /* end of medium (tape) */ Sd2filemark = 0x80, /* at a filemark (tape) */ /* command byte 1 */ Cmd1fixed = 1, /* use fixed-length blocks */ Cmd1sili = 2, /* don't set Sd2ili */ /* limit of block #s in 24-bit ccbs */ Max24off = (1<<21) - 1, /* 2â²â± - 1 */ /* mode pages */ Allmodepages = 0x3F, }; /* scsi device types, from the scsi standards */ enum { Devdir, /* usually disk */ Devseq, /* usually tape */ Devprint, Dev3, Devworm, /* also direct, but special */ Devcd, /* also direct */ Dev6, Devmo, /* also direct */ Devjuke, }; /* p arguments should be of type uchar* */ #define GETBELONG(p) ((ulong)(p)[0]<<24 | (ulong)(p)[1]<<16 | (p)[2]<<8 | (p)[3]) #define PUTBELONG(p, ul) ((p)[0] = (ul)>>24, (p)[1] = (ul)>>16, \ (p)[2] = (ul)>>8, (p)[3] = (ul)) #define GETBE24(p) ((ulong)(p)[0]<<16 | (p)[1]<<8 | (p)[2]) #define PUTBE24(p, ul) ((p)[0] = (ul)>>16, (p)[1] = (ul)>>8, (p)[2] = (ul)) extern long maxiosize; long SRready(ScsiReq*); long SRrewind(ScsiReq*); long SRreqsense(ScsiReq*); long SRformat(ScsiReq*); long SRrblimits(ScsiReq*, uchar*); long SRread(ScsiReq*, void*, long); long SRwrite(ScsiReq*, void*, long); long SRseek(ScsiReq*, long, int); long SRfilemark(ScsiReq*, ulong); long SRspace(ScsiReq*, uchar, long); long SRinquiry(ScsiReq*); long SRmodeselect6(ScsiReq*, uchar*, long); long SRmodeselect10(ScsiReq*, uchar*, long); long SRmodesense6(ScsiReq*, uchar, uchar*, long); long SRmodesense10(ScsiReq*, uchar, uchar*, long); long SRstart(ScsiReq*, uchar); long SRrcapacity(ScsiReq*, uchar*); long SRrcapacity16(ScsiReq*, uchar*); long SRblank(ScsiReq*, uchar, uchar); /* MMC CD-R/CD-RW commands */ long SRsynccache(ScsiReq*); long SRTOC(ScsiReq*, void*, int, uchar, uchar); long SRrdiscinfo(ScsiReq*, void*, int); long SRrtrackinfo(ScsiReq*, void*, int, int); long SRcdpause(ScsiReq*, int); /* MMC CD audio commands */ long SRcdstop(ScsiReq*); long SRcdload(ScsiReq*, int, int); long SRcdplay(ScsiReq*, int, long, long); long SRcdstatus(ScsiReq*, uchar*, int); long SRgetconf(ScsiReq*, uchar*, int); /* old CD-R/CD-RW commands */ long SRfwaddr(ScsiReq*, uchar, uchar, uchar, uchar*); long SRtreserve(ScsiReq*, long); long SRtinfo(ScsiReq*, uchar, uchar*); long SRwtrack(ScsiReq*, void*, long, uchar, uchar); long SRmload(ScsiReq*, uchar); long SRfixation(ScsiReq*, uchar); long SReinitialise(ScsiReq*); /* CHANGER commands */ long SRestatus(ScsiReq*, uchar, uchar*, int); long SRmmove(ScsiReq*, int, int, int, int); long SRrequest(ScsiReq*); int SRclose(ScsiReq*); int SRopenraw(ScsiReq*, char*); int SRopen(ScsiReq*, char*); void makesense(ScsiReq*); long umsrequest(struct Umsc*, ScsiPtr*, ScsiPtr*, int*); void scsidebug(int); char* scsierrmsg(int n); first */ memset(mode, 0, sizeof mode); mode[3] = 0x10; /* device-specific param. */ mode[7] = 8; /* block descriptor length */ /* * exabytes can't handle this, and * modeselect(10) is optional. */ if(SRmodeselecusb/disk/ums.h 664 0 0 3202 11354447430 11246ustar00syssys/* * mass storage transport protocols and subclasses, * from usb mass storage class specification overview rev 1.2 */ typedef struct Umsc Umsc; typedef struct Ums Ums; typedef struct Cbw Cbw; /* command block wrapper */ typedef struct Csw Csw; /* command status wrapper */ enum { Protocbi = 0, /* control/bulk/interrupt; mainly floppies */ Protocb = 1, /* " with no interrupt; mainly floppies */ Protobulk = 0x50, /* bulk only */ Subrbc = 1, /* reduced blk cmds */ Subatapi = 2, /* cd/dvd using sff-8020i or mmc-2 cmd blks */ Subqic = 3, /* QIC-157 tapes */ Subufi = 4, /* floppy */ Sub8070 = 5, /* removable media, atapi-like */ Subscsi = 6, /* scsi transparent cmd set */ Subisd200 = 7, /* ISD200 ATA */ Subdev = 0xff, /* use device's value */ Umsreset = 0xFF, Getmaxlun = 0xFE, MaxIOsize = 256*1024, /* max. I/O size */ // Maxlun = 256, Maxlun = 32, CMreset = 1, Pcmd = 0, Pdata, Pstatus, CbwLen = 31, CbwDataIn = 0x80, CbwDataOut = 0x00, CswLen = 13, CswOk = 0, CswFailed = 1, CswPhaseErr = 2, }; /* these are 600 bytes each; ScsiReq is not tiny */ struct Umsc { ScsiReq; uvlong blocks; vlong capacity; uchar rawcmd[10]; uchar phase; char *inq; Ums *ums; Usbfs fs; }; struct Ums { QLock; Dev *dev; Dev *epin; Dev *epout; Umsc *lun; uchar maxlun; int seq; int nerrs; int wrongresidues; }; /* * USB transparent SCSI devices */ struct Cbw { char signature[4]; /* "USBC" */ long tag; long datalen; uchar flags; uchar lun; uchar len; char command[16]; }; struct Csw { char signature[4]; /* "USBS" */ long tag; long dataresidue; uchar status; }; int diskmain(Dev*, int, char**); usb/ether/ 775 0 0 0 11457773434 104635ustar00syssysusb/ether/asix.c 664 0 0 23556 11202312257 11602ustar00syssys/* * Asix USB ether adapters * I got no documentation for it, thus the bits * come from other systems; it's likely this is * doing more than needed in some places and * less than required in others. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #include "ether.h" enum { /* Asix commands */ Cswmii = 0x06, /* set sw mii */ Crmii = 0x07, /* read mii reg */ Cwmii = 0x08, /* write mii reg */ Chwmii = 0x0a, /* set hw mii */ Creeprom = 0x0b, /* read eeprom */ Cwdis = 0x0e, /* write disable */ Cwena = 0x0d, /* write enable */ Crrxctl = 0x0f, /* read rx ctl */ Cwrxctl = 0x10, /* write rx ctl */ Cwipg = 0x12, /* write ipg */ Crmac = 0x13, /* read mac addr */ Crphy = 0x19, /* read phy id */ Cwmedium = 0x1b, /* write medium mode */ Crgpio = 0x1e, /* read gpio */ Cwgpio = 0x1f, /* write gpios */ Creset = 0x20, /* reset */ Cwphy = 0x22, /* select phy */ /* reset codes */ Rclear = 0x00, Rprte = 0x04, Rprl = 0x08, Riprl = 0x20, Rippd = 0x40, Gpiogpo1en = 0x04, /* gpio1 enable */, Gpiogpo1 = 0x08, /* gpio1 value */ Gpiogpo2en = 0x10, /* gpio2 enable */ Gpiogpo2 = 0x20, /* gpio2 value */ Gpiorse = 0x80, /* gpio reload serial eeprom */ Pmask = 0x1F, Pembed = 0x10, /* embedded phy */ Mfd = 0x002, /* media */ Mac = 0x004, Mrfc = 0x010, Mtfc = 0x020, Mjfe = 0x040, Mre = 0x100, Mps = 0x200, Mall772 = Mfd|Mrfc|Mtfc|Mps|Mac|Mre, Mall178 = Mps|Mfd|Mac|Mrfc|Mtfc|Mjfe|Mre, Ipgdflt = 0x15|0x0c|0x12, /* default ipg0, 1, 2 */ Rxctlso = 0x80, Rxctlab = 0x08, Rxctlsep = 0x04, Rxctlamall = 0x02, /* all multicast */ Rxctlprom = 0x01, /* promiscuous */ /* MII */ Miibmcr = 0x00, /* basic mode ctrl reg. */ Bmcrreset = 0x8000, /* reset */ Bmcranena = 0x1000, /* auto neg. enable */ Bmcrar = 0x0200, /* announce restart */ Miiad = 0x04, /* advertise reg. */ Adcsma = 0x0001, Ad1000f = 0x0200, Ad1000h = 0x0100, Ad10h = 0x0020, Ad10f = 0x0040, Ad100h = 0x0080, Ad100f = 0x0100, Adpause = 0x0400, Adall = Ad10h|Ad10f|Ad100h|Ad100f, Miimctl = 0x14, /* marvell ctl */ Mtxdly = 0x02, Mrxdly = 0x80, Mtxrxdly = 0x82, Miic1000 = 0x09, }; static int asixset(Dev *d, int c, int v) { int r; int ec; r = Rh2d|Rvendor|Rdev; ec = usbcmd(d, r, c, v, 0, nil, 0); if(ec < 0) deprint(2, "%s: asixset %x %x: %r\n", argv0, c, v); return ec; } static int asixget(Dev *d, int c, uchar *buf, int l) { int r; int ec; r = Rd2h|Rvendor|Rdev; ec = usbcmd(d, r, c, 0, 0, buf, l); if(ec < 0) deprint(2, "%s: asixget %x: %r\n", argv0, c); return ec; } static int getgpio(Dev *d) { uchar c; if(asixget(d, Crgpio, &c, 1) < 0) return -1; return c; } static int getphy(Dev *d) { uchar buf[2]; if(asixget(d, Crphy, buf, sizeof(buf)) < 0) return -1; deprint(2, "%s: phy addr %#ux\n", argv0, buf[1]); return buf[1]; } static int getrxctl(Dev *d) { uchar buf[2]; int r; memset(buf, 0, sizeof(buf)); if(asixget(d, Crrxctl, buf, sizeof(buf)) < 0) return -1; r = GET2(buf); deprint(2, "%s: rxctl %#x\n", argv0, r); return r; } static int getmac(Dev *d, uchar buf[]) { if(asixget(d, Crmac, buf, Eaddrlen) < 0) return -1; return Eaddrlen; } static int miiread(Dev *d, int phy, int reg) { int r; uchar v[2]; r = Rd2h|Rvendor|Rdev; if(usbcmd(d, r, Crmii, phy, reg, v, 2) < 0){ dprint(2, "%s: miiwrite: %r\n", argv0); return -1; } r = GET2(v); if(r == 0xFFFF) return -1; return r; } static int miiwrite(Dev *d, int phy, int reg, int val) { int r; uchar v[2]; if(asixset(d, Cswmii, 0) < 0) return -1; r = Rh2d|Rvendor|Rdev; PUT2(v, val); if(usbcmd(d, r, Cwmii, phy, reg, v, 2) < 0){ deprint(2, "%s: miiwrite: %#x %#x %r\n", argv0, reg, val); return -1; } if(asixset(d, Chwmii, 0) < 0) return -1; return 0; } static int eepromread(Dev *d, int i) { int r; int ec; uchar buf[2]; r = Rd2h|Rvendor|Rdev; ec = usbcmd(d, r, Creeprom, i, 0, buf, sizeof(buf)); if(ec < 0) deprint(2, "%s: eepromread %d: %r\n", argv0, i); ec = GET2(buf); deprint(2, "%s: eeprom %#x = %#x\n", argv0, i, ec); if(ec == 0xFFFF) ec = -1; return ec; } /* * No doc. we are doing what Linux does as closely * as we can. */ static int ctlrinit(Ether *ether) { Dev *d; int i; int bmcr; int gpio; int ee17; int rc; d = ether->dev; switch(ether->cid){ default: fprint(2, "%s: card known but not implemented\n", argv0); return -1; case A88178: deprint(2, "%s: setting up A88178\n", argv0); gpio = getgpio(d); if(gpio < 0) return -1; deprint(2, "%s: gpio sts %#x\n", argv0, gpio); asixset(d, Cwena, 0); ee17 = eepromread(d, 0x0017); asixset(d, Cwdis, 0); asixset(d, Cwgpio, Gpiorse|Gpiogpo1|Gpiogpo1en); if((ee17 >> 8) != 1){ asixset(d, Cwgpio, 0x003c); asixset(d, Cwgpio, 0x001c); asixset(d, Cwgpio, 0x003c); }else{ asixset(d, Cwgpio, Gpiogpo1en); asixset(d, Cwgpio, Gpiogpo1|Gpiogpo1en); } asixset(d, Creset, Rclear); sleep(150); asixset(d, Creset, Rippd|Rprl); sleep(150); asixset(d, Cwrxctl, 0); if(getmac(d, ether->addr) < 0) return -1; ether->phy = getphy(d); if(ee17 < 0 || (ee17 & 0x7) == 0){ miiwrite(d, ether->phy, Miimctl, Mtxrxdly); sleep(60); } miiwrite(d, ether->phy, Miibmcr, Bmcrreset|Bmcranena); miiwrite(d, ether->phy, Miiad, Adall|Adcsma|Adpause); miiwrite(d, ether->phy, Miic1000, Ad1000f); bmcr = miiread(d, ether->phy, Miibmcr); if((bmcr & Bmcranena) != 0){ bmcr |= Bmcrar; miiwrite(d, ether->phy, Miibmcr, bmcr); } asixset(d, Cwmedium, Mall178); asixset(d, Cwrxctl, Rxctlso|Rxctlab); break; case A88772: deprint(2, "%s: setting up A88772\n", argv0); if(asixset(d, Cwgpio, Gpiorse|Gpiogpo2|Gpiogpo2en) < 0) return -1; ether->phy = getphy(d); dprint(2, "%s: phy %#x\n", argv0, ether->phy); if((ether->phy & Pmask) == Pembed){ /* embedded 10/100 ethernet */ rc = asixset(d, Cwphy, 1); }else rc = asixset(d, Cwphy, 0); if(rc < 0) return -1; if(asixset(d, Creset, Rippd|Rprl) < 0) return -1; sleep(150); if((ether->phy & Pmask) == Pembed) rc = asixset(d, Creset, Riprl); else rc = asixset(d, Creset, Rprte); if(rc < 0) return -1; sleep(150); rc = getrxctl(d); deprint(2, "%s: rxctl is %#x\n", argv0, rc); if(asixset(d, Cwrxctl, 0) < 0) return -1; if(getmac(d, ether->addr) < 0) return -1; if(asixset(d, Creset, Rprl) < 0) return -1; sleep(150); if(asixset(d, Creset, Riprl|Rprl) < 0) return -1; sleep(150); miiwrite(d, ether->phy, Miibmcr, Bmcrreset); miiwrite(d, ether->phy, Miiad, Adall|Adcsma); bmcr = miiread(d, ether->phy, Miibmcr); if((bmcr & Bmcranena) != 0){ bmcr |= Bmcrar; miiwrite(d, ether->phy, Miibmcr, bmcr); } if(asixset(d, Cwmedium, Mall772) < 0) return -1; if(asixset(d, Cwipg, Ipgdflt) < 0) return -1; if(asixset(d, Cwrxctl, Rxctlso|Rxctlab) < 0) return -1; deprint(2, "%s: final rxctl: %#x\n", argv0, getrxctl(d)); break; } if(etherdebug){ fprint(2, "%s: ether: phy %#x addr ", argv0, ether->phy); for(i = 0; i < sizeof(ether->addr); i++) fprint(2, "%02x", ether->addr[i]); fprint(2, "\n"); } return 0; } static long asixbread(Ether *e, Buf *bp) { ulong nr; ulong hd; Buf *rbp; rbp = e->aux; if(rbp == nil || rbp->ndata < 4){ rbp->rp = rbp->data; rbp->ndata = read(e->epin->dfd, rbp->rp, sizeof(bp->data)); if(rbp->ndata < 0) return -1; } if(rbp->ndata < 4){ werrstr("short frame"); deprint(2, "%s: asixbread got %d bytes\n", argv0, rbp->ndata); rbp->ndata = 0; return 0; } hd = GET4(rbp->rp); nr = hd & 0xFFFF; hd = (hd>>16) & 0xFFFF; if(nr != (~hd & 0xFFFF)){ if(0)deprint(2, "%s: asixread: bad header %#ulx %#ulx\n", argv0, nr, (~hd & 0xFFFF)); werrstr("bad usb packet header"); rbp->ndata = 0; return 0; } rbp->rp += 4; if(nr < 6 || nr > Epktlen){ if(nr < 6) werrstr("short frame"); else werrstr("long frame"); deprint(2, "%s: asixbread %r (%ld)\n", argv0, nr); rbp->ndata = 0; return 0; } bp->rp = bp->data + Hdrsize; memmove(bp->rp, rbp->rp, nr); bp->ndata = nr; rbp->rp += 4 + nr; rbp->ndata -= (4 + nr); return bp->ndata; } static long asixbwrite(Ether *e, Buf *bp) { ulong len; long n; deprint(2, "%s: asixbwrite %d bytes\n", argv0, bp->ndata); assert(bp->rp - bp->data >= Hdrsize); bp->ndata &= 0xFFFF; len = (0xFFFF0000 & ~(bp->ndata<<16)) | bp->ndata; bp->rp -= 4; PUT4(bp->rp, len); bp->ndata += 4; if((bp->ndata % e->epout->maxpkt) == 0){ PUT4(bp->rp+bp->ndata, 0xFFFF0000); bp->ndata += 4; } n = write(e->epout->dfd, bp->rp, bp->ndata); deprint(2, "%s: asixbwrite wrote %ld bytes\n", argv0, n); if(n <= 0) return n; return n; } static int asixpromiscuous(Ether *e, int on) { int rxctl; deprint(2, "%s: aixprompiscuous %d\n", argv0, on); rxctl = getrxctl(e->dev); if(on != 0) rxctl |= Rxctlprom; else rxctl &= ~Rxctlprom; return asixset(e->dev, Cwrxctl, rxctl); } static int asixmulticast(Ether *e, uchar *addr, int on) { int rxctl; USED(addr); USED(on); /* BUG: should write multicast filter */ rxctl = getrxctl(e->dev); if(e->nmcasts != 0) rxctl |= Rxctlamall; else rxctl &= ~Rxctlamall; deprint(2, "%s: asixmulticast %d\n", argv0, e->nmcasts); return asixset(e->dev, Cwrxctl, rxctl); } static void asixfree(Ether *ether) { deprint(2, "%s: aixfree %#p\n", argv0, ether); free(ether->aux); ether->aux = nil; } int asixreset(Ether *ether) { Cinfo *ip; Dev *dev; dev = ether->dev; for(ip = cinfo; ip->vid != 0; ip++) if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){ ether->cid = ip->cid; if(ctlrinit(ether) < 0){ deprint(2, "%s: init failed: %r\n", argv0); return -1; } deprint(2, "%s: asix reset done\n", argv0); ether->aux = emallocz(sizeof(Buf), 1); ether->bread = asixbread; ether->bwrite = asixbwrite; ether->free = asixfree; ether->promiscuous = asixpromiscuous; ether->multicast = asixmulticast; ether->mbps = 100; /* BUG */ return 0; } return -1; } usb/ether/cdc.c 664 0 0 2121 11202312257 11330ustar00syssys/* * Standard usb ethernet communications device. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #include "ether.h" static int okclass(Iface *iface) { return Class(iface->csp) == Clcomms && Subclass(iface->csp) == Scether; } static int getmac(Ether *ether) { int i; Usbdev *ud; uchar *b; Desc *dd; char *mac; ud = ether->dev->usb; for(i = 0; i < nelem(ud->ddesc); i++) if((dd = ud->ddesc[i]) != nil && okclass(dd->iface)){ b = (uchar*)&dd->data; if(b[1] == Dfunction && b[2] == Fnether){ mac = loaddevstr(ether->dev, b[3]); if(mac != nil && strlen(mac) != 12){ free(mac); mac = nil; } if(mac != nil){ parseaddr(ether->addr, mac); free(mac); return 0; } } } return -1; } int cdcreset(Ether *ether) { /* * Assume that all communication devices are going to * be std. ethernet communication devices. Specific controllers * must have been probed first. * NB: This ignores unions. */ if(ether->dev->usb->class == Clcomms) return getmac(ether); return -1; } lab = 0x08, Rxctlsep = 0x04, Rxctlamall = 0x02, /* all multicast */ Rxctlprom = 0x01, /* promiscuous */ /* MII */ Miibmcr = 0x00, /* basic mode ctrl reg. */ Bmcrreset = 0x8000, /* reset */ Bmcranena = 0x1000, /* auto neg. enable */ Bmcrar = 0x0200, /* announce restart */ Miiad = 0x04, /* advertise reg. */ Adcsma = 0x0001, Ad1000f = 0x0200, Ad1000h = 0x0100, Ad10h = 0x0020, Ad10f = 0x0040usb/ether/ether.c 664 0 0 53731 11412732245 11751ustar00syssys/* * usb/ether - usb ethernet adapter. * BUG: This should use /dev/etherfile to * use the kernel ether device code. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #include "ether.h" typedef struct Dirtab Dirtab; enum { /* Qids. Maintain order (relative to dirtabs structs) */ Qroot = 0, Qclone, Qaddr, Qifstats, Qstats, Qndir, Qndata, Qnctl, Qnifstats, Qnstats, Qntype, Qmax, }; struct Dirtab { char *name; int qid; int mode; }; typedef int (*Resetf)(Ether*); /* * Controllers by vid/vid. Used to locate * specific adapters that do not implement cdc ethernet * Keep null terminated. */ Cinfo cinfo[] = { /* Asix controllers. * Only A88178 and A881772 are implemented. * Others are easy to add by borrowing code * from other systems. */ {0x077b, 0x2226, A8817x}, {0x0b95, 0x1720, A8817x}, {0x0557, 0x2009, A8817x}, {0x0411, 0x003d, A8817x}, {0x0411, 0x006e, A88178}, {0x6189, 0x182d, A8817x}, {0x07aa, 0x0017, A8817x}, {0x1189, 0x0893, A8817x}, {0x1631, 0x6200, A8817x}, {0x04f1, 0x3008, A8817x}, {0x0b95, 0x1780, A88178}, /* Geoff */ {0x13b1, 0x0018, A88772}, {0x1557, 0x7720, A88772}, {0x07d1, 0x3c05, A88772}, {0x2001, 0x3c05, A88772}, {0x1737, 0x0039, A88178}, {0x050d, 0x5055, A88178}, {0x05ac, 0x1402, A88772}, /* Apple */ {0x0b95, 0x772a, A88772}, {0x14ea, 0xab11, A88178}, {0x0db0, 0xa877, A88772}, {0, 0, 0}, }; /* * Each etherU%d is the root of our file system, * which is added to the usb root directory. We only * have to concern ourselfs with each /etherU%d subtree. * * NB: Maintain order in dirtabs, relative to the Qids enum. */ static Dirtab rootdirtab[] = { "/", Qroot, DMDIR|0555, /* etherU%d */ "clone", Qclone, 0666, "addr", Qaddr, 0444, "ifstats", Qifstats, 0444, "stats", Qstats, 0444, /* one dir per connection here */ nil, 0, 0, }; static Dirtab conndirtab[] = { "%d", Qndir, DMDIR|0555, "data", Qndata, 0666, "ctl", Qnctl, 0666, "ifstats", Qnifstats, 0444, "stats", Qnstats, 0444, "type", Qntype, 0444, nil, 0, }; int etherdebug; Resetf ethers[] = { asixreset, cdcreset, /* keep last */ }; static int qtype(vlong q) { return q&0xFF; } static int qnum(vlong q) { return (q >> 8) & 0xFFFFFF; } static uvlong mkqid(int n, int t) { uvlong q; q = (n&0xFFFFFF) << 8 | t&0xFF; return q; } static void freebuf(Ether *e, Buf *bp) { if(0)deprint(2, "%s: freebuf %#p\n", argv0, bp); if(bp != nil){ qlock(e); e->nbufs--; qunlock(e); sendp(e->bc, bp); } } static Buf* allocbuf(Ether *e) { Buf *bp; bp = nbrecvp(e->bc); if(bp == nil){ qlock(e); if(e->nabufs < Nconns){ bp = emallocz(sizeof(Buf), 1); e->nabufs++; setmalloctag(bp, getcallerpc(&e)); deprint(2, "%s: %d buffers\n", argv0, e->nabufs); } qunlock(e); } if(bp == nil) bp = recvp(e->bc); bp->rp = bp->data + Hdrsize; bp->ndata = 0; if(0)deprint(2, "%s: allocbuf %#p\n", argv0, bp); qlock(e); e->nbufs++; qunlock(e); return bp; } static Conn* newconn(Ether *e) { int i; Conn *c; qlock(e); for(i = 0; i < nelem(e->conns); i++){ c = e->conns[i]; if(c == nil || c->ref == 0){ if(c == nil){ c = emallocz(sizeof(Conn), 1); c->rc = chancreate(sizeof(Buf*), 2); c->nb = i; } c->ref = 1; if(i == e->nconns) e->nconns++; e->conns[i] = c; deprint(2, "%s: newconn %d\n", argv0, i); qunlock(e); return c; } } qunlock(e); return nil; } static char* seprintaddr(char *s, char *se, uchar *addr) { int i; for(i = 0; i < Eaddrlen; i++) s = seprint(s, se, "%02x", addr[i]); return s; } void dumpframe(char *tag, void *p, int n) { Etherpkt *ep; char buf[128]; char *s, *se; int i; ep = p; if(n < Eaddrlen * 2 + 2){ fprint(2, "short packet (%d bytes)\n", n); return; } se = buf+sizeof(buf); s = seprint(buf, se, "%s [%d]: ", tag, n); s = seprintaddr(s, se, ep->s); s = seprint(s, se, " -> "); s = seprintaddr(s, se, ep->d); s = seprint(s, se, " type 0x%02ux%02ux ", ep->type[0], ep->type[1]); n -= Eaddrlen * 2 + 2; for(i = 0; i < n && i < 16; i++) s = seprint(s, se, "%02x", ep->data[i]); if(n >= 16) fprint(2, "%s...\n", buf); else fprint(2, "%s\n", buf); } static char* seprintstats(char *s, char *se, Ether *e) { qlock(e); s = seprint(s, se, "in: %ld\n", e->nin); s = seprint(s, se, "out: %ld\n", e->nout); s = seprint(s, se, "input errs: %ld\n", e->nierrs); s = seprint(s, se, "output errs: %ld\n", e->noerrs); s = seprint(s, se, "mbps: %d\n", e->mbps); s = seprint(s, se, "prom: %ld\n", e->prom.ref); s = seprint(s, se, "addr: "); s = seprintaddr(s, se, e->addr); s = seprint(s, se, "\n"); qunlock(e); return s; } static char* seprintifstats(char *s, char *se, Ether *e) { int i; Conn *c; qlock(e); s = seprint(s, se, "ctlr id: %#x\n", e->cid); s = seprint(s, se, "phy: %#x\n", e->phy); s = seprint(s, se, "exiting: %s\n", e->exiting ? "y" : "n"); s = seprint(s, se, "conns: %d\n", e->nconns); s = seprint(s, se, "allocated bufs: %d\n", e->nabufs); s = seprint(s, se, "used bufs: %d\n", e->nbufs); for(i = 0; i < nelem(e->conns); i++){ c = e->conns[i]; if(c == nil) continue; if(c->ref == 0) s = seprint(s, se, "c[%d]: free\n", i); else{ s = seprint(s, se, "c[%d]: refs %ld t %#x h %d p %d\n", c->nb, c->ref, c->type, c->headersonly, c->prom); } } qunlock(e); return s; } static void etherdump(Ether *e) { char buf[256]; if(etherdebug == 0) return; seprintifstats(buf, buf+sizeof(buf), e); fprint(2, "%s: ether %#p:\n%s\n", argv0, e, buf); } static Conn* getconn(Ether *e, int i, int idleok) { Conn *c; qlock(e); if(i < 0 || i >= e->nconns) c = nil; else{ c = e->conns[i]; if(idleok == 0 && c != nil && c->ref == 0) c = nil; } qunlock(e); return c; } static void filldir(Usbfs *fs, Dir *d, Dirtab *tab, int cn) { d->qid.path = mkqid(cn, tab->qid); d->qid.path |= fs->qid; d->mode = tab->mode; if((d->mode & DMDIR) != 0) d->qid.type = QTDIR; else d->qid.type = QTFILE; if(tab->qid == Qndir) sprint(d->name, "%d", cn); else d->name = tab->name; } static int rootdirgen(Usbfs *fs, Qid, int i, Dir *d, void *) { Ether *e; Dirtab *tab; int cn; e = fs->aux; i++; /* skip root */ cn = 0; if(i < nelem(rootdirtab) - 1) /* null terminated */ tab = &rootdirtab[i]; else{ cn = i - nelem(rootdirtab) + 1; if(cn < e->nconns) tab = &conndirtab[0]; else return -1; } filldir(fs, d, tab, cn); return 0; } static int conndirgen(Usbfs *fs, Qid q, int i, Dir *d, void *) { Dirtab *tab; i++; /* skip root */ if(i < nelem(conndirtab) - 1) /* null terminated */ tab = &conndirtab[i]; else return -1; filldir(fs, d, tab, qnum(q.path)); return 0; } static int fswalk(Usbfs *fs, Fid *fid, char *name) { int cn, i; char *es; Dirtab *tab; Ether *e; Qid qid; e = fs->aux; qid = fid->qid; qid.path &= ~fs->qid; if((qid.type & QTDIR) == 0){ werrstr("walk in non-directory"); return -1; } if(strcmp(name, "..") == 0){ /* must be /etherU%d; i.e. our root dir. */ fid->qid.path = mkqid(0, Qroot) | fs->qid; fid->qid.vers = 0; fid->qid.type = QTDIR; return 0; } switch(qtype(qid.path)){ case Qroot: if(name[0] >= '0' && name[0] <= '9'){ es = name; cn = strtoul(name, &es, 10); if(cn >= e->nconns || *es != 0){ werrstr(Enotfound); return -1; } fid->qid.path = mkqid(cn, Qndir) | fs->qid; fid->qid.vers = 0; return 0; } /* fall */ case Qndir: if(qtype(qid.path) == Qroot) tab = rootdirtab; else tab = conndirtab; cn = qnum(qid.path); for(i = 0; tab[i].name != nil; tab++) if(strcmp(tab[i].name, name) == 0){ fid->qid.path = mkqid(cn, tab[i].qid)|fs->qid; fid->qid.vers = 0; if((tab[i].mode & DMDIR) != 0) fid->qid.type = QTDIR; else fid->qid.type = QTFILE; return 0; } break; default: sysfatal("usb: ether: fswalk bug"); } return -1; } static Dirtab* qdirtab(vlong q) { int i, qt; Dirtab *tab; qt = qtype(q); if(qt < nelem(rootdirtab) - 1){ /* null terminated */ tab = rootdirtab; i = qt; }else{ tab = conndirtab; i = qt - (nelem(rootdirtab) - 1); assert(i < nelem(conndirtab) - 1); } return &tab[i]; } static int fsstat(Usbfs *fs, Qid qid, Dir *d) { filldir(fs, d, qdirtab(qid.path), qnum(qid.path)); return 0; } static int fsopen(Usbfs *fs, Fid *fid, int omode) { int qt; vlong qid; Conn *c; Dirtab *tab; Ether *e; qid = fid->qid.path & ~fs->qid; e = fs->aux; qt = qtype(qid); tab = qdirtab(qid); omode &= 3; if(omode != OREAD && (tab->mode&0222) == 0){ werrstr(Eperm); return -1; } switch(qt){ case Qclone: c = newconn(e); if(c == nil){ werrstr("no more connections"); return -1; } fid->qid.type = QTFILE; fid->qid.path = mkqid(c->nb, Qnctl)|fs->qid; fid->qid.vers = 0; break; case Qndata: case Qnctl: case Qnifstats: case Qnstats: case Qntype: c = getconn(e, qnum(qid), 1); if(c == nil) sysfatal("usb: ether: fsopen bug"); incref(c); break; } etherdump(e); return 0; } static int prom(Ether *e, int set) { if(e->promiscuous != nil) return e->promiscuous(e, set); return 0; } static void fsclunk(Usbfs *fs, Fid *fid) { int qt; vlong qid; Buf *bp; Conn *c; Ether *e; e = fs->aux; qid = fid->qid.path & ~fs->qid; qt = qtype(qid); switch(qt){ case Qndata: case Qnctl: case Qnifstats: case Qnstats: case Qntype: if(fid->omode != ONONE){ c = getconn(e, qnum(qid), 0); if(c == nil) sysfatal("usb: ether: fsopen bug"); if(decref(c) == 0){ while((bp = nbrecvp(c->rc)) != nil) freebuf(e, bp); qlock(e); if(c->prom != 0) if(decref(&e->prom) == 0) prom(e, 0); c->prom = c->type = 0; qunlock(e); } } break; } etherdump(e); } int parseaddr(uchar *m, char *s) { int i, n; uchar v; if(strlen(s) < 12) return -1; if(strlen(s) > 12 && strlen(s) < 17) return -1; for(i = n = 0; i < strlen(s); i++){ if(s[i] == ':') continue; if(s[i] >= 'A' && s[i] <= 'F') v = 10 + s[i] - 'A'; else if(s[i] >= 'a' && s[i] <= 'f') v = 10 + s[i] - 'a'; else if(s[i] >= '0' && s[i] <= '9') v = s[i] - '0'; else return -1; if(n&1) m[n/2] |= v; else m[n/2] = v<<4; n++; } return 0; } static long fsread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) { int cn, qt; char *s, *se; char buf[2048]; /* keep this large for ifstats */ Buf *bp; Conn *c; Ether *e; Qid q; q = fid->qid; q.path &= ~fs->qid; e = fs->aux; s = buf; se = buf+sizeof(buf); qt = qtype(q.path); cn = qnum(q.path); switch(qt){ case Qroot: count = usbdirread(fs, q, data, count, offset, rootdirgen, nil); break; case Qaddr: s = seprintaddr(s, se, e->addr); count = usbreadbuf(data, count, offset, buf, s - buf); break; case Qnifstats: /* BUG */ case Qifstats: s = seprintifstats(s, se, e); if(e->seprintstats != nil) s = e->seprintstats(s, se, e); count = usbreadbuf(data, count, offset, buf, s - buf); break; case Qnstats: /* BUG */ case Qstats: s = seprintstats(s, se, e); count = usbreadbuf(data, count, offset, buf, s - buf); break; case Qndir: count = usbdirread(fs, q, data, count, offset, conndirgen, nil); break; case Qndata: c = getconn(e, cn, 0); if(c == nil){ werrstr(Eio); return -1; } bp = recvp(c->rc); if(bp == nil) return -1; if(etherdebug > 1) dumpframe("etherin", bp->rp, bp->ndata); count = usbreadbuf(data, count, 0LL, bp->rp, bp->ndata); freebuf(e, bp); break; case Qnctl: s = seprint(s, se, "%11d ", cn); count = usbreadbuf(data, count, offset, buf, s - buf); break; case Qntype: c = getconn(e, cn, 0); if(c == nil) s = seprint(s, se, "%11d ", 0); else s = seprint(s, se, "%11d ", c->type); count = usbreadbuf(data, count, offset, buf, s - buf); break; default: sysfatal("usb: ether: fsread bug"); } return count; } static int typeinuse(Ether *e, int t) { int i; for(i = 0; i < e->nconns; i++) if(e->conns[i]->ref > 0 && e->conns[i]->type == t) return 1; return 0; } static int isloopback(Ether *e, Buf *) { return e->prom.ref > 0; /* BUG: also loopbacks and broadcasts */ } static int etherctl(Ether *e, Conn *c, char *buf) { uchar addr[Eaddrlen]; int t; deprint(2, "%s: etherctl: %s\n", argv0, buf); if(strncmp(buf, "connect ", 8) == 0){ t = atoi(buf+8); qlock(e); if(typeinuse(e, t)){ werrstr("type already in use"); qunlock(e); return -1; } c->type = atoi(buf+8); qunlock(e); return 0; } if(strncmp(buf, "nonblocking", 11) == 0){ if(buf[11] == '\n' || buf[11] == 0) e->nblock = 1; else e->nblock = atoi(buf + 12); deprint(2, "%s: nblock %d\n", argv0, e->nblock); return 0; } if(strncmp(buf, "promiscuous", 11) == 0){ if(c->prom == 0) incref(&e->prom); c->prom = 1; return prom(e, 1); } if(strncmp(buf, "headersonly", 11) == 0){ c->headersonly = 1; return 0; } if(strncmp(buf, "addmulti ", 9) == 0 || strncmp(buf, "remmulti ", 9) == 0){ if(parseaddr(addr, buf+9) < 0){ werrstr("bad address"); return -1; } if(e->multicast == nil) return 0; if(strncmp(buf, "add", 3) == 0){ e->nmcasts++; return e->multicast(e, addr, 1); }else{ e->nmcasts--; return e->multicast(e, addr, 0); } } if(e->ctl != nil) return e->ctl(e, buf); werrstr(Ebadctl); return -1; } static long etherbread(Ether *e, Buf *bp) { deprint(2, "%s: etherbread\n", argv0); bp->rp = bp->data + Hdrsize; bp->ndata = -1; bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize); if(bp->ndata < 0){ deprint(2, "%s: etherbread: %r\n", argv0); /* keep { and } */ }else deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata); return bp->ndata; } static long etherbwrite(Ether *e, Buf *bp) { long n; deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata); n = write(e->epout->dfd, bp->rp, bp->ndata); if(n < 0){ deprint(2, "%s: etherbwrite: %r\n", argv0); /* keep { and } */ }else deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n); if(n <= 0) return n; if((bp->ndata % e->epout->maxpkt) == 0){ deprint(2, "%s: short pkt write\n", argv0); write(e->epout->dfd, "", 1); } return n; } static long fswrite(Usbfs *fs, Fid *fid, void *data, long count, vlong) { int cn, qt; char buf[128]; Buf *bp; Conn *c; Ether *e; Qid q; q = fid->qid; q.path &= ~fs->qid; e = fs->aux; qt = qtype(q.path); cn = qnum(q.path); switch(qt){ case Qndata: c = getconn(e, cn, 0); if(c == nil){ werrstr(Eio); return -1; } bp = allocbuf(e); if(count > sizeof(bp->data)-Hdrsize) count = sizeof(bp->data)-Hdrsize; memmove(bp->rp, data, count); bp->ndata = count; if(etherdebug > 1) dumpframe("etherout", bp->rp, bp->ndata); if(e->nblock == 0) sendp(e->wc, bp); else if(nbsendp(e->wc, bp) == 0){ deprint(2, "%s: (out) packet lost\n", argv0); freebuf(e, bp); } break; case Qnctl: c = getconn(e, cn, 0); if(c == nil){ werrstr(Eio); return -1; } if(count > sizeof(buf) - 1) count = sizeof(buf) - 1; memmove(buf, data, count); buf[count] = 0; if(etherctl(e, c, buf) < 0) return -1; break; default: sysfatal("usb: ether: fsread bug"); } return count; } static int openeps(Ether *e, int epin, int epout) { e->epin = openep(e->dev, epin); if(e->epin == nil){ fprint(2, "ether: in: openep %d: %r\n", epin); return -1; } if(epout == epin){ incref(e->epin); e->epout = e->epin; }else e->epout = openep(e->dev, epout); if(e->epout == nil){ fprint(2, "ether: out: openep %d: %r\n", epout); closedev(e->epin); return -1; } if(e->epin == e->epout) opendevdata(e->epin, ORDWR); else{ opendevdata(e->epin, OREAD); opendevdata(e->epout, OWRITE); } if(e->epin->dfd < 0 || e->epout->dfd < 0){ fprint(2, "ether: open i/o ep data: %r\n"); closedev(e->epin); closedev(e->epout); return -1; } dprint(2, "ether: ep in %s maxpkt %d; ep out %s maxpkt %d\n", e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt); /* time outs are not activated for I/O endpoints */ if(usbdebug > 2 || etherdebug > 2){ devctl(e->epin, "debug 1"); devctl(e->epout, "debug 1"); devctl(e->dev, "debug 1"); } return 0; } static int usage(void) { werrstr("usage: usb/ether [-d] [-N nb]"); return -1; } static Usbfs etherfs = { .walk = fswalk, .open = fsopen, .read = fsread, .write = fswrite, .stat = fsstat, .clunk = fsclunk, }; static void shutdownchan(Channel *c) { Buf *bp; while((bp=nbrecvp(c)) != nil) free(bp); chanfree(c); } static void etherfree(Ether *e) { int i; Buf *bp; if(e->free != nil) e->free(e); closedev(e->epin); closedev(e->epout); if(e->rc == nil){ /* not really started */ free(e); return; } for(i = 0; i < e->nconns; i++) if(e->conns[i] != nil){ while((bp = nbrecvp(e->conns[i]->rc)) != nil) free(bp); chanfree(e->conns[i]->rc); free(e->conns[i]); } shutdownchan(e->bc); shutdownchan(e->rc); shutdownchan(e->wc); e->epin = e->epout = nil; devctl(e->dev, "detach"); free(e); } static void etherdevfree(void *a) { Ether *e = a; if(e != nil) etherfree(e); } /* must return 1 if c wants bp; 0 if not */ static int cwantsbp(Conn *c, Buf *bp) { if(c->ref != 0 && (c->prom != 0 || c->type < 0 || c->type == bp->type)) return 1; return 0; } static void etherwriteproc(void *a) { Ether *e = a; Buf *bp; Channel *wc; wc = e->wc; while(e->exiting == 0){ bp = recvp(wc); if(bp == nil || e->exiting != 0){ free(bp); break; } e->nout++; if(e->bwrite(e, bp) < 0) e->noerrs++; if(isloopback(e, bp) && e->exiting == 0) sendp(e->rc, bp); /* send to input queue */ else freebuf(e, bp); } deprint(2, "%s: writeproc exiting\n", argv0); closedev(e->dev); } static void setbuftype(Buf *bp) { uchar *p; bp->type = 0; if(bp->ndata >= Ehdrsize){ p = bp->rp + Eaddrlen*2; bp->type = p[0]<<8 | p[1]; } } static void etherexiting(Ether *e) { devctl(e->dev, "detach"); e->exiting = 1; close(e->epin->dfd); e->epin->dfd = -1; close(e->epout->dfd); e->epout->dfd = -1; nbsend(e->wc, nil); } static void etherreadproc(void *a) { int i, n, nwants; Buf *bp, *dbp; Ether *e = a; while(e->exiting == 0){ bp = nbrecvp(e->rc); if(bp == nil){ bp = allocbuf(e); /* leak() may think we leak */ if(e->bread(e, bp) < 0){ freebuf(e, bp); break; } if(bp->ndata == 0){ /* may be a short packet; continue */ if(0)dprint(2, "%s: read: short\n", argv0); freebuf(e, bp); continue; }else setbuftype(bp); } e->nin++; nwants = 0; for(i = 0; i < e->nconns; i++) nwants += cwantsbp(e->conns[i], bp); for(i = 0; nwants > 0 && i < e->nconns; i++) if(cwantsbp(e->conns[i], bp)){ n = bp->ndata; if(e->conns[i]->type == -2 && n > 64) n = 64; if(nwants-- == 1){ bp->ndata = n; dbp = bp; bp = nil; }else{ dbp = allocbuf(e); memmove(dbp->rp, bp->rp, n); dbp->ndata = n; dbp->type = bp->type; } if(nbsendp(e->conns[i]->rc, dbp) == 0){ e->nierrs++; freebuf(e, dbp); } } freebuf(e, bp); } deprint(2, "%s: writeproc exiting\n", argv0); etherexiting(e); closedev(e->dev); usbfsdel(&e->fs); } static void setalt(Dev *d, int ifcid, int altid) { if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0) dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid); } static int ifaceinit(Ether *e, Iface *ifc, int *ei, int *eo) { Ep *ep; int epin, epout, i; if(ifc == nil) return -1; epin = epout = -1; for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++) if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){ if(ep->dir == Eboth || ep->dir == Ein) if(epin == -1) epin = ep->id; if(ep->dir == Eboth || ep->dir == Eout) if(epout == -1) epout = ep->id; } if(epin == -1 || epout == -1) return -1; dprint(2, "ether: ep ids: in %d out %d\n", epin, epout); for(i = 0; i < nelem(ifc->altc); i++) if(ifc->altc[i] != nil) setalt(e->dev, ifc->id, i); *ei = epin; *eo = epout; return 0; } static int etherinit(Ether *e, int *ei, int *eo) { int ctlid, datid, i, j; Conf *c; Desc *desc; Iface *ctlif, *datif; Usbdev *ud; *ei = *eo = -1; ud = e->dev->usb; /* look for union descriptor with ethernet ctrl interface */ for(i = 0; i < nelem(ud->ddesc); i++){ if((desc = ud->ddesc[i]) == nil) continue; if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion) continue; ctlid = desc->data.bbytes[1]; datid = desc->data.bbytes[2]; if((c = desc->conf) == nil) continue; ctlif = datif = nil; for(j = 0; j < nelem(c->iface); j++){ if(c->iface[j] == nil) continue; if(c->iface[j]->id == ctlid) ctlif = c->iface[j]; if(c->iface[j]->id == datid) datif = c->iface[j]; if(datif != nil && ctlif != nil){ if(Subclass(ctlif->csp) == Scether && ifaceinit(e, datif, ei, eo) != -1) return 0; break; } } } /* try any other one that seems to be ok */ for(i = 0; i < nelem(ud->conf); i++) if((c = ud->conf[i]) != nil) for(j = 0; j < nelem(c->iface); j++) if(ifaceinit(e, c->iface[j], ei, eo) != -1) return 0; dprint(2, "%s: no valid endpoints", argv0); return -1; } int ethermain(Dev *dev, int argc, char **argv) { int epin, epout, i, devid; Ether *e; devid = dev->id; ARGBEGIN{ case 'd': if(etherdebug == 0) fprint(2, "ether debug on\n"); etherdebug++; break; case 'N': devid = atoi(EARGF(usage())); break; default: return usage(); }ARGEND if(argc != 0) { return usage(); } e = dev->aux = emallocz(sizeof(Ether), 1); e->dev = dev; dev->free = etherdevfree; for(i = 0; i < nelem(ethers); i++) if(ethers[i](e) == 0) break; if(i == nelem(ethers)) return -1; if(e->init == nil) e->init = etherinit; if(e->init(e, &epin, &epout) < 0) return -1; if(e->bwrite == nil) e->bwrite = etherbwrite; if(e->bread == nil) e->bread = etherbread; if(openeps(e, epin, epout) < 0) return -1; e->fs = etherfs; snprint(e->fs.name, sizeof(e->fs.name), "etherU%d", devid); e->fs.dev = dev; e->fs.aux = e; e->bc = chancreate(sizeof(Buf*), Nconns); e->rc = chancreate(sizeof(Buf*), Nconns/2); e->wc = chancreate(sizeof(Buf*), Nconns*2); incref(e->dev); proccreate(etherwriteproc, e, 16*1024); incref(e->dev); proccreate(etherreadproc, e, 16*1024); deprint(2, "%s: dev ref %ld\n", argv0, dev->ref); incref(e->dev); usbfsadd(&e->fs); return 0; } ; int t; deprint(2, "%s: etherctl: %usb/ether/ether.h 664 0 0 4627 11233462433 11736ustar00syssystypedef struct Ether Ether; typedef struct Etherops Etherops; typedef struct Conn Conn; typedef struct Cinfo Cinfo; typedef struct Buf Buf; typedef struct Etherpkt Etherpkt; enum { /* controller ids */ Cdc = 0, A8817x, /* Asis */ A88178, A88179, A88772, Eaddrlen = 6, Epktlen = 1514, Ehdrsize = 2*Eaddrlen + 2, Maxpkt = 2000, /* no jumbo packets here */ Nconns = 8, /* max number of connections */ Nbufs = 8, /* max number of buffers */ Scether = 6, /* ethernet cdc subclass */ Fnheader = 0, /* Functions */ Fnunion = 6, Fnether = 15, Cdcunion = 6, /* CDC Union descriptor subtype */ }; struct Buf { int type; int ndata; uchar* rp; uchar data[Hdrsize+Maxpkt]; }; struct Conn { Ref; /* one per file in use */ int nb; int type; int headersonly; int prom; Channel*rc; /* [2] of Buf* */ }; struct Etherops { int (*init)(Ether*, int *epin, int *epout); long (*bread)(Ether*, Buf*); long (*bwrite)(Ether*, Buf*); int (*ctl)(Ether*, char*); int (*promiscuous)(Ether*, int); int (*multicast)(Ether*, uchar*, int); char* (*seprintstats)(char*, char*, Ether*); void (*free)(Ether*); void* aux; }; struct Ether { QLock; QLock wlck; /* write one at a time */ int epinid; /* epin address */ int epoutid; /* epout address */ Dev* dev; Dev* epin; Dev* epout; int cid; /* ctlr id */ int phy; /* phy id */ Ref prom; /* nb. of promiscuous conns */ int exiting; /* shutting down */ int wrexited; /* write process died */ uchar addr[Eaddrlen]; /* mac */ int nconns; /* nb. of entries used in... */ Conn* conns[Nconns]; /* connections */ int nabufs; /* nb. of allocated buffers */ int nbufs; /* nb. of buffers in use */ int nblock; /* nonblocking (output)? */ long nin; long nout; long nierrs; long noerrs; int mbps; int nmcasts; Channel*rc; /* read channel (of Buf*) */ Channel*wc; /* write channel (of Buf*) */ Channel*bc; /* free buf. chan. (of Buf*) */ Etherops; Usbfs fs; }; struct Cinfo { int vid; /* usb vendor id */ int did; /* usb device/product id */ int cid; /* controller id assigned by us */ }; struct Etherpkt { uchar d[Eaddrlen]; uchar s[Eaddrlen]; uchar type[2]; uchar data[1500]; }; int ethermain(Dev *dev, int argc, char **argv); int asixreset(Ether*); int cdcreset(Ether*); int parseaddr(uchar *m, char *s); void dumpframe(char *tag, void *p, int n); extern Cinfo cinfo[]; extern int etherdebug; #define deprint if(etherdebug)fprint *e, int epin, int epout) { e->epin = openep(e->dev, epin); if(e->epin == nil){ fprint(2, "ether: in:usb/ether/main.c 664 0 0 3113 11412732237 11534ustar00syssys/* * usb/ether - usb ethernet adapter. * BUG: This should use /dev/etherfile to * use the kernel ether device code. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #include "ether.h" enum { Arglen = 80, }; static void usage(void) { fprint(2, "usage: %s [-Dd] [-N nb] [-m mnt] [-s srv] [dev...]\n", argv0); threadexitsall("usage"); } /* * Ether devices may be weird. * Be optimistic and try to use any communication * device or one of the `vendor specific class' devices * that we know are ethernets. */ static int matchether(char *info, void*) { Cinfo *ip; char buf[50]; /* * I have an ether reporting comms.0.0 */ if(strstr(info, "comms") != nil) return 0; for(ip = cinfo; ip->vid != 0; ip++){ snprint(buf, sizeof(buf), "vid %#06x did %#06x", ip->vid, ip->did); if(strstr(info, buf) != nil) return 0; } return -1; } void threadmain(int argc, char **argv) { char args[Arglen]; char *as, *ae, *srv, *mnt; srv = nil; mnt = "/net"; quotefmtinstall(); ae = args+sizeof(args); as = seprint(args, ae, "ether"); ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'N': as = seprint(as, ae, " -N %s", EARGF(usage())); break; case 'm': mnt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); }ARGEND rfork(RFNOTEG); threadsetgrp(threadid()); fmtinstall('U', Ufmt); usbfsinit(srv, mnt, &usbdirfs, MAFTER|MCREATE); startdevs(args, argv, argc, matchether, nil, ethermain); threadexits(nil); } ->exiting != 0){ free(bp); break; } e->nout++; if(e->bwrite(e, bp) < 0) e->noerrs++; if(isloopback(e, bp) && e->exiting == 0) sendp(e->rc, bp); /* send to input queue */ else freebuf(e, bp); } deprint(2, "%s: writeproc exiting\n", argv0); closedev(e->dev); } static void setbuftype(Buf *bp) { uchar *p; bp->type = 0; if(bp->ndata >= Ehdrsize){ p = bp->rp + Eaddrlen*2; bp->type = p[0]<<8 | p[1]; } }usb/ether/mkfile 664 0 0 575 11223230427 11621ustar00syssysiface); j++) if(ifaceinit(e, c->iface[j], ei, eo) != -1) return 0; dprint(2, "%s: no valid endpoints", argv0); return -1; } int ethermain(Dev *dev, int argc, char **argv) { int epin, epout, i, devid; Ether *e; devid = dev->id; ARGBEGIN{ case 'd': if(etherdebug == 0) fprint(2, "ether debug on\n"); etherdebug++; break; case 'N': devid = atoi(EARGusb/kb/kb.c 664 0 0 27211 11412732275 10520ustar00syssys/* * USB Human Interaction Device: keyboard and mouse. * * 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. * Keyboard keycodes are translated to scan codes and sent to kbin(3). * */ #include #include #include #include "usb.h" #include "hid.h" enum { Awakemsg=0xdeaddead, Diemsg = 0xbeefbeef, }; typedef struct KDev KDev; typedef struct Kin Kin; struct KDev { Dev* dev; /* usb device*/ Dev* ep; /* endpoint to get events */ Kin* in; /* used to send events to kernel */ Channel*repeatc; /* only for keyboard */ int accel; /* only for mouse */ }; /* * Kbdin and mousein files must be shared among all instances. */ struct Kin { int ref; int fd; char* name; }; /* * Map for the logitech bluetooth mouse with 8 buttons and wheels. * { ptr ->mouse} * { 0x01, 0x01 }, // left * { 0x04, 0x02 }, // middle * { 0x02, 0x04 }, // right * { 0x40, 0x08 }, // up * { 0x80, 0x10 }, // down * { 0x10, 0x08 }, // side up * { 0x08, 0x10 }, // side down * { 0x20, 0x02 }, // page * besides wheel and regular up/down report the 4th byte as 1/-1 */ /* * key code to scan code; for the page table used by * the logitech bluetooth keyboard. */ static char sctab[256] = { [0x00] 0x0, 0x0, 0x0, 0x0, 0x1e, 0x30, 0x2e, 0x20, [0x08] 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, [0x10] 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, [0x18] 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x2, 0x3, [0x20] 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, [0x28] 0x1c, 0x1, 0xe, 0xf, 0x39, 0xc, 0xd, 0x1a, [0x30] 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, [0x68] 0x55, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, [0x70] 0x78, 0x79, 0x7a, 0x7b, 0x0, 0x0, 0x0, 0x0, [0x78] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, [0x80] 0x73, 0x72, 0x0, 0x0, 0x0, 0x7c, 0x0, 0x0, [0x88] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0x90] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0x98] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xa0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xa8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xb0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xb8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xc0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xc8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xd0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xd8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xe0] 0x1d, 0x2a, 0x38, 0x7d, 0x61, 0x36, 0x64, 0x7e, [0xe8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x73, 0x72, 0x71, [0xf0] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, [0xf8] 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; static QLock inlck; static Kin kbdin = { .ref = 0, .name = "#Ι/kbin", .fd = -1, }; static Kin ptrin = { .ref = 0, .name = "#m/mousein", .fd = -1, }; static int kbdebug; static int setbootproto(KDev* f, int eid) { int r, id; r = Rh2d|Rclass|Riface; id = f->dev->usb->ep[eid]->iface->id; return usbcmd(f->dev, r, Setproto, Bootproto, id, nil, 0); } /* * 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 recoverkb(KDev *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){ setbootproto(f, f->ep->id); break; } /* else usbd still working... */ } } static void kbfatal(KDev *kd, char *sts) { Dev *dev; if(sts != nil) fprint(2, "kb: fatal: %s\n", sts); else fprint(2, "kb: exiting\n"); if(kd->repeatc != nil) nbsendul(kd->repeatc, Diemsg); dev = kd->dev; kd->dev = nil; if(kd->ep != nil) closedev(kd->ep); kd->ep = nil; devctl(dev, "detach"); closedev(dev); /* * free(kd); done by closedev. */ threadexits(sts); } static int scale(KDev *f, int x) { int sign = 1; if(x < 0){ sign = -1; x = -x; } switch(x){ case 0: case 1: case 2: case 3: break; case 4: x = 6 + (f->accel>>2); break; case 5: x = 9 + (f->accel>>1); break; default: x *= MaxAcc; break; } return sign*x; } /* * ps2 mouse is processed mostly at interrupt time. * for usb we do what we can. */ static void sethipri(void) { char fn[30]; int fd; snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid()); fd = open(fn, OWRITE); if(fd < 0) return; fprint(fd, "pri 13"); close(fd); } 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; hipri = nerrs = 0; ptrfd = f->ep->dfd; mfd = f->in->fd; if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) kbfatal(f, "weird mouse maxpkt"); for(;;){ memset(buf, 0, sizeof buf); if(f->ep == nil) kbfatal(f, nil); c = read(ptrfd, buf, f->ep->maxpkt); assert(f->dev != nil); assert(f->ep != nil); if(c < 0){ dprint(2, "kb: mouse: %s: read: %r\n", f->ep->dir); if(++nerrs < 3){ recoverkb(f); continue; } } if(c <= 0) kbfatal(f, nil); if(c < 3) continue; if(f->accel){ x = scale(f, buf[1]); y = scale(f, buf[2]); }else{ x = buf[1]; y = buf[2]; } 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); if(write(mfd, mbuf, strlen(mbuf)) < 0) kbfatal(f, "mousein i/o"); if(hipri == 0){ sethipri(); hipri = 1; } } } static void stoprepeat(KDev *f) { sendul(f->repeatc, Awakemsg); } static void startrepeat(KDev *f, uchar esc1, uchar sc) { ulong c; if(esc1) c = SCesc1 << 8 | (sc & 0xff); else c = sc; sendul(f->repeatc, c); } static void putscan(int kbinfd, uchar esc, uchar sc) { uchar s[2] = {SCesc1, 0}; if(sc == 0x41){ kbdebug += 2; return; } if(sc == 0x42){ kbdebug = 0; return; } if(kbdebug) fprint(2, "sc: %x %x\n", (esc? SCesc1: 0), sc); s[1] = sc; if(esc && sc != 0) write(kbinfd, s, 2); else if(sc != 0) write(kbinfd, s+1, 1); } static void repeatproc(void* a) { KDev *f; Channel *repeatc; int kbdinfd; ulong l, t, i; uchar esc1, sc; /* * too many jumps here. * Rewrite instead of debug, if needed. */ f = a; repeatc = f->repeatc; kbdinfd = f->in->fd; l = Awakemsg; Repeat: if(l == Diemsg) goto Abort; while(l == Awakemsg) l = recvul(repeatc); if(l == Diemsg) goto Abort; esc1 = l >> 8; sc = l; t = 160; for(;;){ for(i = 0; i < t; i += 5){ if(l = nbrecvul(repeatc)) goto Repeat; sleep(5); } putscan(kbdinfd, esc1, sc); t = 30; } Abort: chanfree(repeatc); threadexits("aborted"); } #define hasesc1(sc) (((sc) > 0x47) || ((sc) == 0x38)) static void putmod(int fd, uchar mods, uchar omods, uchar mask, uchar esc, uchar sc) { /* BUG: Should be a single write */ if((mods&mask) && !(omods&mask)) putscan(fd, esc, sc); if(!(mods&mask) && (omods&mask)) putscan(fd, esc, Keyup|sc); } /* * This routine diffs the state with the last known state * and invents the scan codes that would have been sent * by a non-usb keyboard in that case. This also requires supplying * the extra esc1 byte as well as keyup flags. * The aim is to allow future addition of other keycode pages * for other keyboards. */ static uchar putkeys(KDev *f, uchar buf[], uchar obuf[], int n, uchar dk) { int i, j; uchar uk; int fd; fd = f->in->fd; putmod(fd, buf[0], obuf[0], Mctrl, 0, SCctrl); putmod(fd, buf[0], obuf[0], (1<ep->dfd; if(f->ep->maxpkt < 3 || f->ep->maxpkt > sizeof buf) kbfatal(f, "weird maxpkt"); f->repeatc = chancreate(sizeof(ulong), 0); if(f->repeatc == nil) kbfatal(f, "chancreate failed"); proccreate(repeatproc, f, Stack); memset(lbuf, 0, sizeof lbuf); dk = nerrs = 0; for(;;){ memset(buf, 0, sizeof buf); c = read(kbdfd, buf, f->ep->maxpkt); assert(f->dev != nil); assert(f->ep != nil); if(c < 0){ rerrstr(err, sizeof(err)); fprint(2, "kb: %s: read: %s\n", f->ep->dir, err); if(strstr(err, "babble") != 0 && ++nerrs < 3){ recoverkb(f); continue; } } if(c <= 0) kbfatal(f, nil); if(c < 3) continue; if(kbdbusy(buf + 2, c - 2)) continue; if(usbdebug > 2 || kbdebug > 1){ fprint(2, "kbd mod %x: ", buf[0]); for(i = 2; i < c; i++) fprint(2, "kc %x ", buf[i]); fprint(2, "\n"); } dk = putkeys(f, buf, lbuf, f->ep->maxpkt, dk); memmove(lbuf, buf, c); nerrs = 0; } } static void freekdev(void *a) { KDev *kd; kd = a; if(kd->in != nil){ qlock(&inlck); if(--kd->in->ref == 0){ close(kd->in->fd); kd->in->fd = -1; } qunlock(&inlck); } dprint(2, "freekdev\n"); free(kd); } static void kbstart(Dev *d, Ep *ep, Kin *in, void (*f)(void*), int accel) { KDev *kd; qlock(&inlck); if(in->fd < 0){ in->fd = open(in->name, OWRITE); if(in->fd < 0){ fprint(2, "kb: %s: %r\n", in->name); qunlock(&inlck); return; } } 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; kd->ep = openep(d, ep->id); if(kd->ep == nil){ fprint(2, "kb: %s: openep %d: %r\n", d->dir, ep->id); return; } if(opendevdata(kd->ep, OREAD) < 0){ fprint(2, "kb: %s: opendevdata: %r\n", kd->ep->dir); closedev(kd->ep); kd->ep = nil; return; } incref(d); proccreate(f, kd, Stack); } static int usage(void) { werrstr("usage: usb/kb [-dkm] [-a n] [-N nb]"); return -1; } int kbmain(Dev *d, int argc, char* argv[]) { int i, kena, pena, accel, devid; Usbdev *ud; Ep *ep; kena = pena = 1; accel = 0; devid = d->id; ARGBEGIN{ case 'a': accel = strtol(EARGF(usage()), nil, 0); break; case 'd': kbdebug++; break; case 'k': kena = 1; pena = 0; break; case 'm': kena = 0; pena = 1; break; case 'N': devid = atoi(EARGF(usage())); /* ignore dev number */ break; default: return usage(); }ARGEND; 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); 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); } return 0; } , 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, [0x38] 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, [0x40] 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x63, 0x46, [0x48] 0x77, 0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d, [0x50] 0x4b, 0x50, 0x48, 0x45, 0x35, 0x37, 0x4a, 0x4e, [0x58] 0x1c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, [0x60] 0x48, 0x49, 0x52, 0x53, 0x56, 0x7f, 0x74, 0x75, [usb/kb/main.c 664 0 0 2136 11412732266 11027ustar00syssys#include #include #include #include "usb.h" #include "hid.h" typedef struct Parg Parg; enum { Ndevs = 10, Arglen = 80, Nargs = 10, }; static void usage(void) { fprint(2, "usage: %s [-dkm] [-a n] [-N nb] [dev...]\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char **argv) { char args[Arglen]; char *as, *ae; int accel, pena, devid; int csps[] = { KbdCSP, PtrCSP, 0 }; quotefmtinstall(); pena = 1; ae = args+sizeof(args); as = seprint(args, ae, "kb"); ARGBEGIN{ case 'a': accel = strtol(EARGF(usage()), nil, 0); as = seprint(as, ae, " -a %d", accel); break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'k': as = seprint(as, ae, " -k"); pena = 0; break; case 'm': as = seprint(as, ae, " -m"); pena = 1; break; case 'N': devid = atoi(EARGF(usage())); /* ignore dev number */ USED(devid); break; default: usage(); }ARGEND; rfork(RFNOTEG); fmtinstall('U', Ufmt); threadsetgrp(threadid()); if(pena == 0) csps[1] = 0; startdevs(args, argv, argc, matchdevcsp, csps, kbmain); threadexits(nil); } setbootproto(f, f->ep->id); break; } /* else usbd still working... */ } } static void kbfatal(KDev *kd, char *sts) { Dev *dev; if(sts != nil) fprint(2, "kb: fatal: %s\n", sts); else fprint(2, "kb: exiting\n"); if(kd->repeatc != nil) nbsendul(kd->repeatc, Diemsg); dev = kd->dev; kd->dev = nil; if(kd->ep != nil) closedev(kd->ep); kd->ep = nil; devctl(dev, "detach"); closedev(dev); /* usb/kb/mkfile 664 0 0 573 11202312257 11103ustar00syssys #include #include #include "usb.h" /* * epN.M -> N */ static int nameid(char *s) { char *r; char nm[20]; r = strrchr(s, 'p'); if(r == nil) return -1; strecpy(nm, nm+sizeof(nm), r+1); r = strchr(nm, '.'); if(r == nil) return -1; *r = 0; return atoi(nm); } Dev* openep(Dev *d, int id) { char *mode; /* How many modes? */ Ep *ep; Altc *ac; Dev *epd; Usbdev *ud; char name[40]; if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) return nil; if(d->cfd < 0 || d->usb == nil){ werrstr("device not configured"); return nil; } ud = d->usb; if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){ werrstr("bad enpoint number"); return nil; } ep = ud->ep[id]; mode = "rw"; if(ep->dir == Ein) mode = "r"; if(ep->dir == Eout) mode = "w"; snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id); if(access(name, AEXIST) == 0){ dprint(2, "%s: %s already exists; trying to open\n", argv0, name); epd = opendev(name); if(epd != nil) epd->maxpkt = ep->maxpkt; /* guess */ return epd; } if(devctl(d, "new %d %d %s", id, ep->type, mode) < 0){ dprint(2, "%s: %s: new: %r\n", argv0, d->dir); return nil; } epd = opendev(name); if(epd == nil) return nil; epd->id = id; if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0) fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir); else dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt); epd->maxpkt = ep->maxpkt; ac = ep->iface->altc[0]; if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0) fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir); else dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds); /* * For iso endpoints and high speed interrupt endpoints the pollival is * actually 2â¿ and not n. * The kernel usb driver must take that into account. * It's simpler this way. */ if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0) if(devctl(epd, "pollival %d", ac->interval) < 0) fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir); return epd; } Dev* opendev(char *fn) { Dev *d; int l; if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) return nil; d = emallocz(sizeof(Dev), 1); incref(d); l = strlen(fn); d->dfd = -1; /* * +30 to allocate extra size to concat "/" * we should probably remove that feature from the manual * and from the code after checking out that nobody relies on * that. */ d->dir = emallocz(l + 30, 0); strcpy(d->dir, fn); strcpy(d->dir+l, "/ctl"); d->cfd = open(d->dir, ORDWR|OCEXEC); d->dir[l] = 0; d->id = nameid(fn); if(d->cfd < 0){ werrstr("can't open endpoint %s: %r", d->dir); free(d->dir); free(d); return nil; } dprint(2, "%s: opendev %#p %s\n", argv0, d, fn); return d; } int opendevdata(Dev *d, int mode) { char buf[80]; /* more than enough for a usb path */ seprint(buf, buf+sizeof(buf), "%s/data", d->dir); d->dfd = open(buf, mode|OCEXEC); return d->dfd; } enum { /* * Max device conf is also limited by max control request size as * limited by Maxctllen in the kernel usb.h (both limits are arbitrary). */ Maxdevconf = 4 * 1024, /* asking for 16K kills Newsham's disk */ }; int loaddevconf(Dev *d, int n) { uchar *buf; int nr; int type; if(n >= nelem(d->usb->conf)){ werrstr("loaddevconf: bug: out of configurations in device"); fprint(2, "%s: %r\n", argv0); return -1; } buf = emallocz(Maxdevconf, 0); type = Rd2h|Rstd|Rdev; nr = usbcmd(d, type, Rgetdesc, Dconf<<8|n, 0, buf, Maxdevconf); if(nr < Dconflen){ free(buf); return -1; } if(d->usb->conf[n] == nil) d->usb->conf[n] = emallocz(sizeof(Conf), 1); nr = parseconf(d->usb, d->usb->conf[n], buf, nr); free(buf); return nr; } Ep* mkep(Usbdev *d, int id) { Ep *ep; d->ep[id] = ep = emallocz(sizeof(Ep), 1); ep->id = id; return ep; } static char* mkstr(uchar *b, int n) { Rune r; char *us; char *s; char *e; if(n <= 2 || (n & 1) != 0) return strdup("none"); n = (n - 2)/2; b += 2; us = s = emallocz(n*UTFmax+1, 0); e = s + n*UTFmax+1; for(; --n >= 0; b += 2){ r = GET2(b); s = seprint(s, e, "%C", r); } return us; } char* loaddevstr(Dev *d, int sid) { uchar buf[128]; int type; int nr; if(sid == 0) return estrdup("none"); type = Rd2h|Rstd|Rdev; nr=usbcmd(d, type, Rgetdesc, Dstr<<8|sid, 0, buf, sizeof(buf)); return mkstr(buf, nr); } int loaddevdesc(Dev *d) { uchar buf[Ddevlen+255]; int nr; int type; Ep *ep0; type = Rd2h|Rstd|Rdev; nr = sizeof(buf); memset(buf, 0, Ddevlen); if((nr=usbcmd(d, type, Rgetdesc, Ddev<<8|0, 0, buf, nr)) < 0) return -1; /* * Several hubs are returning descriptors of 17 bytes, not 18. * We accept them and leave number of configurations as zero. * (a get configuration descriptor also fails for them!) */ if(nr < Ddevlen){ print("%s: %s: warning: device with short descriptor\n", argv0, d->dir); if(nr < Ddevlen-1){ werrstr("short device descriptor (%d bytes)", nr); return -1; } } d->usb = emallocz(sizeof(Usbdev), 1); ep0 = mkep(d->usb, 0); ep0->dir = Eboth; ep0->type = Econtrol; ep0->maxpkt = d->maxpkt = 8; /* a default */ nr = parsedev(d, buf, nr); if(nr >= 0){ d->usb->vendor = loaddevstr(d, d->usb->vsid); if(strcmp(d->usb->vendor, "none") != 0){ d->usb->product = loaddevstr(d, d->usb->psid); d->usb->serial = loaddevstr(d, d->usb->ssid); } } return nr; } int configdev(Dev *d) { int i; if(d->dfd < 0) opendevdata(d, ORDWR); if(loaddevdesc(d) < 0) return -1; for(i = 0; i < d->usb->nconf; i++) if(loaddevconf(d, i) < 0) return -1; return 0; } static void closeconf(Conf *c) { int i; int a; if(c == nil) return; for(i = 0; i < nelem(c->iface); i++) if(c->iface[i] != nil){ for(a = 0; a < nelem(c->iface[i]->altc); a++) free(c->iface[i]->altc[a]); free(c->iface[i]); } free(c); } void closedev(Dev *d) { int i; Usbdev *ud; if(d==nil || decref(d) != 0) return; dprint(2, "%s: closedev %#p %s\n", argv0, d, d->dir); if(d->free != nil) d->free(d->aux); if(d->cfd >= 0) close(d->cfd); if(d->dfd >= 0) close(d->dfd); d->cfd = d->dfd = -1; free(d->dir); d->dir = nil; ud = d->usb; d->usb = nil; if(ud != nil){ free(ud->vendor); free(ud->product); free(ud->serial); for(i = 0; i < nelem(ud->ep); i++) free(ud->ep[i]); for(i = 0; i < nelem(ud->ddesc); i++) free(ud->ddesc[i]); for(i = 0; i < nelem(ud->conf); i++) closeconf(ud->conf[i]); free(ud); } free(d); } static char* reqstr(int type, int req) { char *s; static char* ds[] = { "dev", "if", "ep", "oth" }; static char buf[40]; if(type&Rd2h) s = seprint(buf, buf+sizeof(buf), "d2h"); else s = seprint(buf, buf+sizeof(buf), "h2d"); if(type&Rclass) s = seprint(s, buf+sizeof(buf), "|cls"); else if(type&Rvendor) s = seprint(s, buf+sizeof(buf), "|vnd"); else s = seprint(s, buf+sizeof(buf), "|std"); s = seprint(s, buf+sizeof(buf), "|%s", ds[type&3]); switch(req){ case Rgetstatus: s = seprint(s, buf+sizeof(buf), " getsts"); break; case Rclearfeature: s = seprint(s, buf+sizeof(buf), " clrfeat"); break; case Rsetfeature: s = seprint(s, buf+sizeof(buf), " setfeat"); break; case Rsetaddress: s = seprint(s, buf+sizeof(buf), " setaddr"); break; case Rgetdesc: s = seprint(s, buf+sizeof(buf), " getdesc"); break; case Rsetdesc: s = seprint(s, buf+sizeof(buf), " setdesc"); break; case Rgetconf: s = seprint(s, buf+sizeof(buf), " getcnf"); break; case Rsetconf: s = seprint(s, buf+sizeof(buf), " setcnf"); break; case Rgetiface: s = seprint(s, buf+sizeof(buf), " getif"); break; case Rsetiface: s = seprint(s, buf+sizeof(buf), " setif"); break; } USED(s); return buf; } static int cmdreq(Dev *d, int type, int req, int value, int index, uchar *data, int count) { int ndata, n; uchar *wp; uchar buf[8]; char *hd, *rs; assert(d != nil); if(data == nil){ wp = buf; ndata = 0; }else{ ndata = count; wp = emallocz(8+ndata, 0); } wp[0] = type; wp[1] = req; PUT2(wp+2, value); PUT2(wp+4, index); PUT2(wp+6, count); if(data != nil) memmove(wp+8, data, ndata); if(usbdebug>2){ hd = hexstr(wp, ndata+8); rs = reqstr(type, req); fprint(2, "%s: %s val %d|%d idx %d cnt %d out[%d] %s\n", d->dir, rs, value>>8, value&0xFF, index, count, ndata+8, hd); free(hd); } n = write(d->dfd, wp, 8+ndata); if(wp != buf) free(wp); if(n < 0) return -1; if(n != 8+ndata){ dprint(2, "%s: cmd: short write: %d\n", argv0, n); return -1; } return n; } static int cmdrep(Dev *d, void *buf, int nb) { char *hd; nb = read(d->dfd, buf, nb); if(nb >0 && usbdebug > 2){ hd = hexstr(buf, nb); fprint(2, "%s: in[%d] %s\n", d->dir, nb, hd); free(hd); } return nb; } int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count) { int i, r, nerr; char err[64]; /* * Some devices do not respond to commands some times. * Others even report errors but later work just fine. Retry. */ r = -1; *err = 0; for(i = nerr = 0; i < Uctries; i++){ if(type & Rd2h) r = cmdreq(d, type, req, value, index, nil, count); else r = cmdreq(d, type, req, value, index, data, count); if(r > 0){ if((type & Rd2h) == 0) break; r = cmdrep(d, data, count); if(r > 0) break; if(r == 0) werrstr("no data from device"); } nerr++; if(*err == 0) rerrstr(err, sizeof(err)); sleep(Ucdelay); } if(r > 0 && i >= 2) /* let the user know the device is not in good shape */ fprint(2, "%s: usbcmd: %s: required %d attempts (%s)\n", argv0, d->dir, i, err); return r; } int unstall(Dev *dev, Dev *ep, int dir) { int r; if(dir == Ein) dir = 0x80; else dir = 0; r = Rh2d|Rstd|Rep; if(usbcmd(dev, r, Rclearfeature, Fhalt, ep->id|dir, nil, 0)<0){ werrstr("unstall: %s: %r", ep->dir); return -1; } if(devctl(ep, "clrhalt") < 0){ werrstr("clrhalt: %s: %r", ep->dir); return -1; } return 0; } /* * To be sure it uses a single write. */ int devctl(Dev *dev, char *fmt, ...) { char buf[128]; va_list arg; char *e; va_start(arg, fmt); e = vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); return write(dev->cfd, buf, e-buf); } usb/lib/devs.c 664 0 0 6065 11421072466 11222ustar00syssys#include #include #include #include "usb.h" typedef struct Parg Parg; enum { Ndevs = 32, Arglen = 500, Nargs = 64, Stack = 16 * 1024, }; struct Parg { char* args; Dev* dev; int (*f)(Dev*,int,char**); Channel*rc; }; static void workproc(void *a) { Parg *pa; char args[Arglen]; char *argv[Nargs]; int argc; Channel *rc; Dev *d; int (*f)(Dev*,int,char**); pa = a; strecpy(args, args+sizeof(args), pa->args); /* don't leak */ d = pa->dev; f = pa->f; rc = pa->rc; free(pa->args); free(pa); argc = tokenize(args, argv, nelem(argv)-1); argv[argc] = nil; if(f(d, argc, argv) < 0){ closedev(d); fprint(2, "%s: devmain: %r\n", argv0); sendul(rc, -1); threadexits("devmain: %r"); } sendul(rc, 0); threadexits(nil); } int matchdevcsp(char *info, void *a) { char sbuf[40]; int *csps; csps = a; for(; *csps != 0; csps++){ snprint(sbuf, sizeof(sbuf), "csp %#08ux", *csps); if(strstr(info, sbuf) != nil) return 0; } return -1; } int finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs) { int fd, i, n, nd, nr; char *nm; char dbuf[512], fbuf[40]; Dir *d; fd = open("/dev/usb", OREAD); if(fd < 0) sysfatal("/dev/usb: %r"); nd = dirreadall(fd, &d); close(fd); if(nd < 2) sysfatal("/dev/usb: no devs"); for(i = n = 0; i < nd && n < ndirs; i++){ nm = d[i].name; if(strcmp(nm, "ctl") == 0 || strstr(nm, ".0") == nil) continue; snprint(fbuf, sizeof(fbuf), "/dev/usb/%s/ctl", nm); fd = open(fbuf, OREAD); if(fd < 0) continue; /* may be gone */ nr = read(fd, dbuf, sizeof(dbuf)-1); close(fd); if(nr < 0) continue; dbuf[nr] = 0; if(strstr(dbuf, "enabled ") != nil && strstr(dbuf, " busy") == nil) if(matchf(dbuf, farg) == 0) dirs[n++] = smprint("/dev/usb/%s", nm); } free(d); if(usbdebug > 1) for(nd = 0; nd < n; nd++) fprint(2, "finddevs: %s\n", dirs[nd]); return n; } void startdevs(char *args, char *argv[], int argc, int (*mf)(char*, void*), void *ma, int (*df)(Dev*, int, char**)) { int i, ndirs, ndevs; char *dirs[Ndevs]; char **dp; Parg *parg; Dev *dev; Channel *rc; if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) sysfatal("#u: %r"); if(argc > 0){ ndirs = argc; dp = argv; }else{ dp = dirs; ndirs = finddevs(mf, ma, dp, Ndevs); if(ndirs == nelem(dirs)) fprint(2, "%s: too many devices\n", argv0); } ndevs = 0; rc = chancreate(sizeof(ulong), 0); if(rc == nil) sysfatal("no memory"); for(i = 0; i < ndirs; i++){ fprint(2, "%s: startdevs: opening #%d %s\n", argv0, i, dp[i]); dev = opendev(dp[i]); if(dev == nil) fprint(2, "%s: %s: %r\n", argv0, dp[i]); else if(configdev(dev) < 0){ fprint(2, "%s: %s: config: %r\n", argv0, dp[i]); closedev(dev); }else{ dprint(2, "%s: %U", argv0, dev); parg = emallocz(sizeof(Parg), 0); parg->args = estrdup(args); parg->dev = dev; parg->rc = rc; parg->f = df; proccreate(workproc, parg, Stack); if(recvul(rc) == 0) ndevs++; } if(dp != argv) free(dirs[i]); } chanfree(rc); if(ndevs == 0) sysfatal("no unhandled devices found"); } usb->conf[n] == nil) d->usb->conf[n] = emallocz(sizeof(Conf), 1); nr = parseconf(d->usb, d->usb->conf[n], buf, nr); free(buf); return nr; } Ep* mkep(Usbdev *d, int id) { Ep *ep; d->ep[id] = ep = emallocz(sizeof(Ep), 1); ep->id = id; return ep; } static char* mkstr(uchar *b, int n) { Rune r; char *us; char *s; char *e; if(n <= 2 || (n & 1) != 0) return strdup("none"); n = (n - 2)/2; b += 2; us = s = emallocz(n*UTFmax+1, 0); e = s + usb/lib/dump.c 664 0 0 6545 11325635214 11230ustar00syssys#include #include #include #include #include "usb.h" int usbdebug; static char *edir[] = {"in", "out", "inout"}; static char *etype[] = {"ctl", "iso", "bulk", "intr"}; static char* cnames[] = { "none", "audio", "comms", "hid", "", "", "", "printer", "storage", "hub", "data" }; static char* devstates[] = { "detached", "attached", "enabled", "assigned", "configured" }; char* classname(int c) { static char buf[30]; if(c >= 0 && c < nelem(cnames)) return cnames[c]; else{ seprint(buf, buf+30, "%d", c); return buf; } } char * hexstr(void *a, int n) { int i; char *dbuff, *s, *e; uchar *b; b = a; dbuff = s = emallocz(1024, 0); *s = 0; e = s + 1024; for(i = 0; i < n; i++) s = seprint(s, e, " %.2ux", b[i]); if(s == e) fprint(2, "%s: usb/lib: hexdump: bug: small buffer\n", argv0); return dbuff; } static char * seprintiface(char *s, char *e, Iface *i) { int j; Altc *a; Ep *ep; char *eds, *ets; s = seprint(s, e, "\t\tiface csp %s.%uld.%uld\n", classname(Class(i->csp)), Subclass(i->csp), Proto(i->csp)); for(j = 0; j < Naltc; j++){ a=i->altc[j]; if(a == nil) break; s = seprint(s, e, "\t\t alt %d attr %d ival %d", j, a->attrib, a->interval); if(a->aux != nil) s = seprint(s, e, " devspec %p\n", a->aux); else s = seprint(s, e, "\n"); } for(j = 0; j < Nep; j++){ ep = i->ep[j]; if(ep == nil) break; eds = ets = ""; if(ep->dir <= nelem(edir)) eds = edir[ep->dir]; if(ep->type <= nelem(etype)) ets = etype[ep->type]; s = seprint(s, e, "\t\t ep id %d addr %d dir %s type %s" " itype %d maxpkt %d ntds %d\n", ep->id, ep->addr, eds, ets, ep->isotype, ep->maxpkt, ep->ntds); } return s; } static char* seprintconf(char *s, char *e, Usbdev *d, int ci) { int i; Conf *c; char *hd; c = d->conf[ci]; s = seprint(s, e, "\tconf: cval %d attrib %x %d mA\n", c->cval, c->attrib, c->milliamps); for(i = 0; i < Niface; i++) if(c->iface[i] == nil) break; else s = seprintiface(s, e, c->iface[i]); for(i = 0; i < Nddesc; i++) if(d->ddesc[i] == nil) break; else if(d->ddesc[i]->conf == c){ hd = hexstr((uchar*)&d->ddesc[i]->data, d->ddesc[i]->data.bLength); s = seprint(s, e, "\t\tdev desc %x[%d]: %s\n", d->ddesc[i]->data.bDescriptorType, d->ddesc[i]->data.bLength, hd); free(hd); } return s; } int Ufmt(Fmt *f) { int i; Dev *d; Usbdev *ud; char buf[1024]; char *s, *e; s = buf; e = buf+sizeof(buf); d = va_arg(f->args, Dev*); if(d == nil) return fmtprint(f, "\n"); s = seprint(s, e, "%s", d->dir); ud = d->usb; if(ud == nil) return fmtprint(f, "%s %ld refs\n", buf, d->ref); s = seprint(s, e, " csp %s.%uld.%uld", classname(Class(ud->csp)), Subclass(ud->csp), Proto(ud->csp)); s = seprint(s, e, " vid %#ux did %#ux", ud->vid, ud->did); s = seprint(s, e, " refs %ld\n", d->ref); s = seprint(s, e, "\t%s %s %s\n", ud->vendor, ud->product, ud->serial); for(i = 0; i < Nconf; i++){ if(ud->conf[i] == nil) break; else s = seprintconf(s, e, ud, i); } return fmtprint(f, "%s", buf); } char* estrdup(char *s) { char *d; d = strdup(s); if(d == nil) sysfatal("strdup: %r"); setmalloctag(d, getcallerpc(&s)); return d; } void* emallocz(ulong size, int zero) { void *x; x = malloc(size); if(x == nil) sysfatal("malloc: %r"); if(zero) memset(x, 0, size); setmalloctag(x, getcallerpc(&size)); return x; } value); PUT2(wp+4, index); PUT2(wp+6, count); if(data != nil) memmove(wp+8, data, ndata); if(usbdebug>2){ hd = hexstr(wp, ndata+8); rs = reqstr(tusb/lib/fs.c 664 0 0 31251 11326123763 10705ustar00syssys/* * Framework for USB devices that provide a file tree. * The main process (usbd or the driver's main proc) * calls fsinit() to start FS operation. * * One or more drivers call fsstart/fsend to register * or unregister their operations for their subtrees. * * root dir has qids with 0 in high 32 bits. * for other files we keep the device id in there. * The low 32 bits for directories at / must be 0. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #undef dprint #define dprint if(usbfsdebug)fprint typedef struct Rpc Rpc; enum { Nproc = 3, /* max nb. of cached FS procs */ Nofid = ~0, /* null value for fid number */ Notag = ~0, /* null value for tags */ Dietag = 0xdead, /* fake tag to ask outproc to die */ Stack = 16 * 1024, /* Fsproc requests */ Run = 0, /* call f(r) */ Exit, /* terminate */ }; struct Rpc { Fcall t; Fcall r; Fid* fid; int flushed; Rpc* next; char data[Bufsize]; }; int usbfsdebug; char Enotfound[] = "file not found"; char Etoosmall[] = "parameter too small"; char Eio[] = "i/o error"; char Eperm[] = "permission denied"; char Ebadcall[] = "unknown fs call"; char Ebadfid[] = "fid not found"; char Einuse[] = "fid already in use"; char Eisopen[] = "it is already open"; char Ebadctl[] = "unknown control request"; static char *user; static ulong epoch; static ulong msgsize = Msgsize; static int fsfd = -1; static Channel *outc; /* of Rpc* */ static QLock rpclck; /* protect vars in this block */ static Fid *freefids; static Fid *fids; static Rpc *freerpcs; static Rpc *rpcs; static Channel*procc; static Channel*endc; static Usbfs* fsops; static void fsioproc(void*); static void schedproc(void*) { Channel *proc[Nproc]; int nproc; Channel *p; Alt a[] = { {procc, &proc[0], CHANSND}, {endc, &p, CHANRCV}, {nil, nil, CHANEND} }; memset(proc, 0, sizeof(proc)); nproc = 0; for(;;){ if(nproc == 0){ proc[0] = chancreate(sizeof(Rpc*), 0); proccreate(fsioproc, proc[0], Stack); nproc++; } switch(alt(a)){ case 0: proc[0] = nil; if(nproc > 1){ proc[0] = proc[nproc-1]; proc[nproc-1] = nil; } nproc--; break; case 1: if(nproc < nelem(proc)) proc[nproc++] = p; else sendp(p, nil); break; default: sysfatal("alt"); } } } static void dump(void) { Rpc *rpc; Fid *fid; qlock(&rpclck); fprint(2, "dump:\n"); for(rpc = rpcs; rpc != nil; rpc = rpc->next) fprint(2, "rpc %#p %F next %#p\n", rpc, &rpc->t, rpc->next); for(fid = fids; fid != nil; fid = fid->next) fprint(2, "fid %d qid %#llux omode %d aux %#p\n", fid->fid, fid->qid.path, fid->omode, fid->aux); fprint(2, "\n"); qunlock(&rpclck); } static Rpc* newrpc(void) { Rpc *r; qlock(&rpclck); r = freerpcs; if(r != nil) freerpcs = r->next; else r = emallocz(sizeof(Rpc), 0); r->next = rpcs; rpcs = r; r->t.tag = r->r.tag = Notag; r->t.fid = r->r.fid = Nofid; r->t.type = r->r.type = 0; r->flushed = 0; r->fid = nil; r->r.data = (char*)r->data; qunlock(&rpclck); return r; } static void freerpc(Rpc *r) { Rpc **l; if(r == nil) return; qlock(&rpclck); for(l = &rpcs; *l != nil && *l != r; l = &(*l)->next) ; assert(*l == r); *l = r->next; r->next = freerpcs; freerpcs = r; r->t.type = 0; r->t.tag = 0x77777777; qunlock(&rpclck); } static void flushrpc(int tag) { Rpc *r; qlock(&rpclck); for(r = rpcs; r != nil; r = r->next) if(r->t.tag == tag){ r->flushed = 1; break; } qunlock(&rpclck); } static Fid* getfid(int fid, int alloc) { Fid *f; qlock(&rpclck); for(f = fids; f != nil && f->fid != fid; f = f->next) ; if(f != nil && alloc != 0){ /* fid in use */ qunlock(&rpclck); return nil; } if(f == nil && alloc != 0){ if(freefids != nil){ f = freefids; freefids = freefids->next; }else f = emallocz(sizeof(Fid), 1); f->fid = fid; f->aux = nil; f->omode = ONONE; f->next = fids; fids = f; } qunlock(&rpclck); return f; } static void freefid(Fid *f) { Fid **l; if(f == nil) return; if(fsops->clunk != nil) fsops->clunk(fsops, f); qlock(&rpclck); for(l = &fids; *l != nil && *l != f; l = &(*l)->next) ; assert(*l == f); *l = f->next; f->next = freefids; freefids = f; qunlock(&rpclck); } static Rpc* fserror(Rpc *rpc, char* fmt, ...) { va_list arg; char *c; va_start(arg, fmt); c = (char*)rpc->data; vseprint(c, c+sizeof(rpc->data), fmt, arg); va_end(arg); rpc->r.type = Rerror; rpc->r.ename = (char*)rpc->data; return rpc; } static Rpc* fsversion(Rpc *r) { if(r->t.msize < 256) return fserror(r, Etoosmall); if(strncmp(r->t.version, "9P2000", 6) != 0) return fserror(r, "wrong version"); if(r->t.msize < msgsize) msgsize = r->t.msize; r->r.msize = msgsize; r->r.version = "9P2000"; return r; } static Rpc* fsattach(Rpc *r) { static int already; /* Reload user because at boot it could be still none */ user=getuser(); if(already++ > 0 && strcmp(r->t.uname, user) != 0) return fserror(r, Eperm); if(r->fid == nil) return fserror(r, Einuse); r->r.qid.type = QTDIR; r->r.qid.path = fsops->qid; r->r.qid.vers = 0; r->fid->qid = r->r.qid; return r; } static Rpc* fswalk(Rpc *r) { int i; Fid *nfid, *ofid; if(r->fid->omode != ONONE) return fserror(r, Eisopen); nfid = nil; ofid = r->fid; if(r->t.newfid != r->t.fid){ nfid = getfid(r->t.newfid, 1); if(nfid == nil) return fserror(r, Einuse); nfid->qid = r->fid->qid; if(fsops->clone != nil) fsops->clone(fsops, ofid, nfid); else nfid->aux = r->fid->aux; r->fid = nfid; } r->r.nwqid = 0; for(i = 0; i < r->t.nwname; i++) if(fsops->walk(fsops, r->fid, r->t.wname[i]) < 0) break; else r->r.wqid[i] = r->fid->qid; r->r.nwqid = i; if(i != r->t.nwname && r->t.nwname > 0){ if(nfid != nil) freefid(nfid); r->fid = ofid; } if(i == 0 && r->t.nwname > 0) return fserror(r, "%r"); return r; } static void fsioproc(void* a) { long rc; Channel *p = a; Rpc *rpc; Fcall *t, *r; Fid *fid; dprint(2, "%s: fsioproc pid %d\n", argv0, getpid()); while((rpc = recvp(p)) != nil){ t = &rpc->t; r = &rpc->r; fid = rpc->fid; rc = -1; dprint(2, "%s: fsioproc pid %d: req %d\n", argv0, getpid(), t->type); switch(t->type){ case Topen: rc = fsops->open(fsops, fid, t->mode); if(rc >= 0){ r->iounit = 0; r->qid = fid->qid; fid->omode = t->mode & 3; } break; case Tread: rc = fsops->read(fsops, fid, r->data, t->count, t->offset); if(rc >= 0){ if(rc > t->count) print("%s: bug: read %ld bytes > %ud wanted\n", argv0, rc, t->count); r->count = rc; } /* * TODO: if we encounter a long run of continuous read * errors, we should do something more drastic so that * our caller doesn't just spin its wheels forever. */ break; case Twrite: rc = fsops->write(fsops, fid, t->data, t->count, t->offset); r->count = rc; break; default: sysfatal("fsioproc: bad type"); } if(rc < 0) sendp(outc, fserror(rpc, "%r")); else sendp(outc, rpc); sendp(endc, p); } chanfree(p); dprint(2, "%s: fsioproc %d exiting\n", argv0, getpid()); threadexits(nil); } static Rpc* fsopen(Rpc *r) { Channel *p; if(r->fid->omode != ONONE) return fserror(r, Eisopen); if((r->t.mode & 3) != OREAD && (r->fid->qid.type & QTDIR) != 0) return fserror(r, Eperm); p = recvp(procc); sendp(p, r); return nil; } int usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg) { int i, n, nd; char name[Namesz]; Dir d; memset(&d, 0, sizeof(d)); d.name = name; d.uid = d.gid = d.muid = user; d.atime = time(nil); d.mtime = epoch; d.length = 0; for(i = n = 0; gen(f, q, i, &d, arg) >= 0; i++){ if(usbfsdebug > 1) fprint(2, "%s: dir %d q %#llux: %D\n", argv0, i, q.path, &d); nd = convD2M(&d, (uchar*)data+n, cnt-n); if(nd <= BIT16SZ) break; if(off > 0) off -= nd; else n += nd; d.name = name; d.uid = d.gid = d.muid = user; d.atime = time(nil); d.mtime = epoch; d.length = 0; } return n; } long usbreadbuf(void *data, long count, vlong offset, void *buf, long n) { if(offset >= n) return 0; if(offset + count > n) count = n - offset; memmove(data, (char*)buf + offset, count); return count; } static Rpc* fsread(Rpc *r) { Channel *p; if(r->fid->omode != OREAD && r->fid->omode != ORDWR) return fserror(r, Eperm); p = recvp(procc); sendp(p, r); return nil; } static Rpc* fswrite(Rpc *r) { Channel *p; if(r->fid->omode != OWRITE && r->fid->omode != ORDWR) return fserror(r, Eperm); p = recvp(procc); sendp(p, r); return nil; } static Rpc* fsclunk(Rpc *r) { freefid(r->fid); return r; } static Rpc* fsno(Rpc *r) { return fserror(r, Eperm); } static Rpc* fsstat(Rpc *r) { Dir d; char name[Namesz]; memset(&d, 0, sizeof(d)); d.name = name; d.uid = d.gid = d.muid = user; d.atime = time(nil); d.mtime = epoch; d.length = 0; if(fsops->stat(fsops, r->fid->qid, &d) < 0) return fserror(r, "%r"); r->r.stat = (uchar*)r->data; r->r.nstat = convD2M(&d, (uchar*)r->data, msgsize); return r; } static Rpc* fsflush(Rpc *r) { /* * Flag it as flushed and respond. * Either outproc will reply to the flushed request * before responding to flush, or it will never reply to it. * Note that we do NOT abort the ongoing I/O. * That might leave the affected endpoints in a failed * state. Instead, we pretend the request is aborted. * * Only open, read, and write are processed * by auxiliary processes and other requests wil never be * flushed in practice. */ flushrpc(r->t.oldtag); return r; } Rpc* (*fscalls[])(Rpc*) = { [Tversion] fsversion, [Tauth] fsno, [Tattach] fsattach, [Twalk] fswalk, [Topen] fsopen, [Tcreate] fsno, [Tread] fsread, [Twrite] fswrite, [Tclunk] fsclunk, [Tremove] fsno, [Tstat] fsstat, [Twstat] fsno, [Tflush] fsflush, }; static void outproc(void*) { static uchar buf[Bufsize]; Rpc *rpc; int nw; static int once = 0; if(once++ != 0) sysfatal("more than one outproc"); for(;;){ do rpc = recvp(outc); while(rpc == nil); /* a delayed reply */ if(rpc->t.tag == Dietag) break; if(rpc->flushed){ dprint(2, "outproc: tag %d flushed\n", rpc->t.tag); freerpc(rpc); continue; } dprint(2, "-> %F\n", &rpc->r); nw = convS2M(&rpc->r, buf, sizeof(buf)); if(nw == sizeof(buf)) fprint(2, "%s: outproc: buffer is too small\n", argv0); if(nw <= BIT16SZ) fprint(2, "%s: conS2M failed\n", argv0); else if(write(fsfd, buf, nw) != nw){ fprint(2, "%s: outproc: write: %r", argv0); /* continue and let the reader abort us */ } if(usbfsdebug > 1) dump(); freerpc(rpc); } dprint(2, "%s: outproc: exiting\n", argv0); } static void usbfs(void*) { Rpc *rpc; int nr; static int once = 0; if(once++ != 0) sysfatal("more than one usbfs proc"); outc = chancreate(sizeof(Rpc*), 1); procc = chancreate(sizeof(Channel*), 0); endc = chancreate(sizeof(Channel*), 0); if(outc == nil || procc == nil || endc == nil) sysfatal("chancreate: %r"); threadcreate(schedproc, nil, Stack); proccreate(outproc, nil, Stack); for(;;){ rpc = newrpc(); do{ nr = read9pmsg(fsfd, rpc->data, sizeof(rpc->data)); }while(nr == 0); if(nr < 0){ dprint(2, "%s: usbfs: read: '%r'", argv0); if(fsops->end != nil) fsops->end(fsops); else closedev(fsops->dev); rpc->t.tag = Dietag; sendp(outc, rpc); break; } if(convM2S((uchar*)rpc->data, nr, &rpc->t) <=0){ dprint(2, "%s: convM2S failed\n", argv0); freerpc(rpc); continue; } dprint(2, "<- %F\n", &rpc->t); rpc->r.tag = rpc->t.tag; rpc->r.type = rpc->t.type + 1; rpc->r.fid = rpc->t.fid; if(fscalls[rpc->t.type] == nil){ sendp(outc, fserror(rpc, Ebadcall)); continue; } if(rpc->t.fid != Nofid){ if(rpc->t.type == Tattach) rpc->fid = getfid(rpc->t.fid, 1); else rpc->fid = getfid(rpc->t.fid, 0); if(rpc->fid == nil){ sendp(outc, fserror(rpc, Ebadfid)); continue; } } sendp(outc, fscalls[rpc->t.type](rpc)); } dprint(2, "%s: ubfs: eof: exiting\n", argv0); } void usbfsinit(char* srv, char *mnt, Usbfs *f, int flag) { int fd[2]; int sfd; int afd; char sfile[40]; fsops = f; if(pipe(fd) < 0) sysfatal("pipe: %r"); user = getuser(); epoch = time(nil); fmtinstall('D', dirfmt); fmtinstall('M', dirmodefmt); fmtinstall('F', fcallfmt); fsfd = fd[1]; procrfork(usbfs, nil, Stack, RFNAMEG); /* no RFFDG */ if(srv != nil){ snprint(sfile, sizeof(sfile), "#s/%s", srv); remove(sfile); sfd = create(sfile, OWRITE, 0660); if(sfd < 0) sysfatal("post: %r"); snprint(sfile, sizeof(sfile), "%d", fd[0]); if(write(sfd, sfile, strlen(sfile)) != strlen(sfile)) sysfatal("post: %r"); close(sfd); } if(mnt != nil){ sfd = dup(fd[0], -1); /* debug */ afd = fauth(sfd, ""); if(afd >= 0) sysfatal("authentication required??"); if(mount(sfd, -1, mnt, flag, "") < 0) sysfatal("mount: %r"); } close(fd[0]); } c* newrpc(void) { Rpc *r; qlock(&rpclck); r = freerpcs; if(r != nil) freerpcs = r->next; else r = emallocz(sizeof(Rpc), 0); r->next = rpcs; rpcs = r; r->t.tag = r->r.tag = Notag; r->t.fid = r->r.fid = Nofid; r->t.type = r->r.type = 0; r->flushed = 0; r->fid = nil; r->r.data = (char*)r->data; qunlock(&rpclck); return r; } usb/lib/fsdir.c 664 0 0 15531 11405763571 11414ustar00syssys#include #include #include #include #include "usb.h" #include "usbfs.h" typedef struct Rpc Rpc; enum { Incr = 3, /* increments for fs array */ Dtop = 0, /* high 32 bits for / */ Qdir = 0, /* low 32 bits for /devdir */ }; QLock fslck; static Usbfs** fs; static int nfs; static int fsused; static int exitonclose = 1; void usbfsexits(int y) { exitonclose = y; } static int qiddev(uvlong path) { return (int)(path>>32) & 0xFF; } static int qidfile(uvlong path) { return (int)(path & 0xFFFFFFFFULL); } static uvlong mkqid(int qd, int qf) { return ((uvlong)qd << 32) | (uvlong)qf; } void usbfsdirdump(void) { int i; qlock(&fslck); fprint(2, "%s: fs list: (%d used %d total)\n", argv0, fsused, nfs); for(i = 1; i < nfs; i++) if(fs[i] != nil) if(fs[i]->dev != nil) fprint(2, "%s\t%s dev %#p refs %ld\n", argv0, fs[i]->name, fs[i]->dev, fs[i]->dev->ref); else fprint(2, "%s:\t%s\n", argv0, fs[i]->name); qunlock(&fslck); } void usbfsadd(Usbfs *dfs) { int i, j; dprint(2, "%s: fsadd %s\n", argv0, dfs->name); qlock(&fslck); for(i = 1; i < nfs; i++) if(fs[i] == nil) break; if(i >= nfs){ if((nfs%Incr) == 0){ fs = realloc(fs, sizeof(Usbfs*) * (nfs+Incr)); if(fs == nil) sysfatal("realloc: %r"); for(j = nfs; j < nfs+Incr; j++) fs[j] = nil; } if(nfs == 0) /* do not use entry 0 */ nfs++; fs[nfs++] = dfs; }else fs[i] = dfs; dfs->qid = mkqid(i, 0); fsused++; qunlock(&fslck); } static void usbfsdelnth(int i) { if(fs[i] != nil){ dprint(2, "%s: fsdel %s", argv0, fs[i]->name); if(fs[i]->dev != nil){ dprint(2, " dev %#p ref %ld\n", fs[i]->dev, fs[i]->dev->ref); }else dprint(2, "no dev\n"); if(fs[i]->end != nil) fs[i]->end(fs[i]); closedev(fs[i]->dev); fsused--; } fs[i] = nil; if(fsused == 0 && exitonclose != 0){ fprint(2, "%s: all file systems gone: exiting\n", argv0); threadexitsall(nil); } } void usbfsdel(Usbfs *dfs) { int i; qlock(&fslck); for(i = 0; i < nfs; i++) if(dfs == nil || fs[i] == dfs){ usbfsdelnth(i); if(dfs != nil) break; } qunlock(&fslck); } static void fsend(Usbfs*) { dprint(2, "%s: fsend\n", argv0); usbfsdel(nil); } void usbfsgone(char *dir) { int i; qlock(&fslck); /* devices may have more than one fs */ for(i = 0; i < nfs; i++) if(fs[i] != nil && fs[i]->dev != nil) if(strcmp(fs[i]->dev->dir, dir) == 0) usbfsdelnth(i); qunlock(&fslck); } static void fsclone(Usbfs*, Fid *o, Fid *n) { int qd; Dev *dev; void (*xfsclone)(Usbfs *fs, Fid *of, Fid *nf); xfsclone = nil; dev = nil; qd = qiddev(o->qid.path); qlock(&fslck); if(qd != Dtop && fs[qd] != nil && fs[qd]->clone != nil){ dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsclone = fs[qd]->clone; } qunlock(&fslck); if(xfsclone != nil){ xfsclone(fs[qd], o, n); } if(dev != nil) closedev(dev); } static int fswalk(Usbfs*, Fid *fid, char *name) { Qid q; int qd, qf; int i; int rc; Dev *dev; Dir d; int (*xfswalk)(Usbfs *fs, Fid *f, char *name); q = fid->qid; qd = qiddev(q.path); qf = qidfile(q.path); q.type = QTDIR; q.vers = 0; if(strcmp(name, "..") == 0) if(qd == Dtop || qf == Qdir){ q.path = mkqid(Dtop, Qdir); fid->qid = q; return 0; } if(qd != 0){ qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfswalk = fs[qd]->walk; qunlock(&fslck); rc = xfswalk(fs[qd], fid, name); if(dev != nil) closedev(dev); return rc; } qlock(&fslck); for(i = 0; i < nfs; i++) if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){ q.path = mkqid(i, Qdir); fs[i]->stat(fs[i], q, &d); /* may be a file */ fid->qid = d.qid; qunlock(&fslck); return 0; } qunlock(&fslck); werrstr(Enotfound); return -1; } static int fsopen(Usbfs*, Fid *fid, int mode) { int qd; int rc; Dev *dev; int (*xfsopen)(Usbfs *fs, Fid *f, int mode); qd = qiddev(fid->qid.path); if(qd == Dtop) return 0; qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsopen = fs[qd]->open; qunlock(&fslck); if(xfsopen != nil) rc = xfsopen(fs[qd], fid, mode); else rc = 0; if(dev != nil) closedev(dev); return rc; } static int dirgen(Usbfs*, Qid, int n, Dir *d, void *) { int i; Dev *dev; char *nm; qlock(&fslck); for(i = 0; i < nfs; i++) if(fs[i] != nil && n-- == 0){ d->qid.type = QTDIR; d->qid.path = mkqid(i, Qdir); d->qid.vers = 0; dev = fs[i]->dev; if(dev != nil) incref(dev); nm = d->name; fs[i]->stat(fs[i], d->qid, d); d->name = nm; strncpy(d->name, fs[i]->name, Namesz); if(dev != nil) closedev(dev); qunlock(&fslck); return 0; } qunlock(&fslck); return -1; } static long fsread(Usbfs*, Fid *fid, void *data, long cnt, vlong off) { int qd; int rc; Dev *dev; Qid q; long (*xfsread)(Usbfs *fs, Fid *f, void *data, long count, vlong ); q = fid->qid; qd = qiddev(q.path); if(qd == Dtop) return usbdirread(nil, q, data, cnt, off, dirgen, nil); qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfsread = fs[qd]->read; qunlock(&fslck); rc = xfsread(fs[qd], fid, data, cnt, off); if(dev != nil) closedev(dev); return rc; } static long fswrite(Usbfs*, Fid *fid, void *data, long cnt, vlong off) { int qd; int rc; Dev *dev; long (*xfswrite)(Usbfs *fs, Fid *f, void *data, long count, vlong ); qd = qiddev(fid->qid.path); if(qd == Dtop) sysfatal("fswrite: not for usbd /"); qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } dev = fs[qd]->dev; if(dev != nil) incref(dev); xfswrite = fs[qd]->write; qunlock(&fslck); rc = xfswrite(fs[qd], fid, data, cnt, off); if(dev != nil) closedev(dev); return rc; } static void fsclunk(Usbfs*, Fid* fid) { int qd; Dev *dev; void (*xfsclunk)(Usbfs *fs, Fid *f); dev = nil; qd = qiddev(fid->qid.path); qlock(&fslck); if(qd != Dtop && fs[qd] != nil){ dev=fs[qd]->dev; if(dev != nil) incref(dev); xfsclunk = fs[qd]->clunk; }else xfsclunk = nil; qunlock(&fslck); if(xfsclunk != nil){ xfsclunk(fs[qd], fid); } if(dev != nil) closedev(dev); } static int fsstat(Usbfs*, Qid qid, Dir *d) { int qd; int rc; Dev *dev; int (*xfsstat)(Usbfs *fs, Qid q, Dir *d); qd = qiddev(qid.path); if(qd == Dtop){ d->qid = qid; d->name = "usb"; d->length = 0; d->mode = 0555|DMDIR; return 0; } qlock(&fslck); if(fs[qd] == nil){ qunlock(&fslck); werrstr(Eio); return -1; } xfsstat = fs[qd]->stat; dev = fs[qd]->dev; if(dev != nil) incref(dev); qunlock(&fslck); rc = xfsstat(fs[qd], qid, d); if(dev != nil) closedev(dev); return rc; } Usbfs usbdirfs = { .walk = fswalk, .clone = fsclone, .clunk = fsclunk, .open = fsopen, .read = fsread, .write = fswrite, .stat = fsstat, .end = fsend, }; usb/lib/mkfile 664 0 0 513 11210007025 11240ustar00syssys #include #include #include #include "usb.h" int parsedev(Dev *xd, uchar *b, int n) { Usbdev *d; DDev *dd; char *hd; d = xd->usb; assert(d != nil); dd = (DDev*)b; if(usbdebug>1){ hd = hexstr(b, Ddevlen); fprint(2, "%s: parsedev %s: %s\n", argv0, xd->dir, hd); free(hd); } if(dd->bLength < Ddevlen){ werrstr("short dev descr. (%d < %d)", dd->bLength, Ddevlen); return -1; } if(dd->bDescriptorType != Ddev){ werrstr("%d is not a dev descriptor", dd->bDescriptorType); return -1; } d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol); d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0; d->class = dd->bDevClass; d->nconf = dd->bNumConfigurations; if(d->nconf == 0) dprint(2, "%s: %s: no configurations\n", argv0, xd->dir); d->vid = GET2(dd->idVendor); d->did = GET2(dd->idProduct); d->dno = GET2(dd->bcdDev); d->vsid = dd->iManufacturer; d->psid = dd->iProduct; d->ssid = dd->iSerialNumber; if(n > Ddevlen && usbdebug>1) fprint(2, "%s: %s: parsedev: %d bytes left", argv0, xd->dir, n - Ddevlen); return Ddevlen; } static int parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp, Altc **app) { int class, subclass, proto; int ifid, altid; DIface *dip; Iface *ip; assert(d != nil && c != nil); if(n < Difacelen){ werrstr("short interface descriptor"); return -1; } dip = (DIface *)b; ifid = dip->bInterfaceNumber; if(ifid < 0 || ifid >= nelem(c->iface)){ werrstr("bad interface number %d", ifid); return -1; } if(c->iface[ifid] == nil) c->iface[ifid] = emallocz(sizeof(Iface), 1); ip = c->iface[ifid]; class = dip->bInterfaceClass; subclass = dip->bInterfaceSubClass; proto = dip->bInterfaceProtocol; ip->csp = CSP(class, subclass, proto); if(d->csp == 0) /* use csp from 1st iface */ d->csp = ip->csp; /* if device has none */ if(d->class == 0) d->class = class; ip->id = ifid; if(c == d->conf[0] && ifid == 0) /* ep0 was already there */ d->ep[0]->iface = ip; altid = dip->bAlternateSetting; if(altid < 0 || altid >= nelem(ip->altc)){ werrstr("bad alternate conf. number %d", altid); return -1; } if(ip->altc[altid] == nil) ip->altc[altid] = emallocz(sizeof(Altc), 1); *ipp = ip; *app = ip->altc[altid]; return Difacelen; } extern Ep* mkep(Usbdev *, int); static int parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp) { int i, dir, epid; Ep *ep; DEp *dep; assert(d != nil && c != nil && ip != nil && altc != nil); if(n < Deplen){ werrstr("short endpoint descriptor"); return -1; } dep = (DEp *)b; altc->attrib = dep->bmAttributes; /* here? */ altc->interval = dep->bInterval; epid = dep->bEndpointAddress & 0xF; assert(epid < nelem(d->ep)); if(dep->bEndpointAddress & 0x80) dir = Ein; else dir = Eout; ep = d->ep[epid]; if(ep == nil){ ep = mkep(d, epid); ep->dir = dir; }else if((ep->addr & 0x80) != (dep->bEndpointAddress & 0x80)) ep->dir = Eboth; ep->maxpkt = GET2(dep->wMaxPacketSize); ep->ntds = 1 + ((ep->maxpkt >> 11) & 3); ep->maxpkt &= 0x7FF; ep->addr = dep->bEndpointAddress; ep->type = dep->bmAttributes & 0x03; ep->isotype = (dep->bmAttributes>>2) & 0x03; ep->conf = c; ep->iface = ip; for(i = 0; i < nelem(ip->ep); i++) if(ip->ep[i] == nil) break; if(i == nelem(ip->ep)){ werrstr("parseendpt: bug: too many end points on interface " "with csp %#lux", ip->csp); fprint(2, "%s: %r\n", argv0); return -1; } *epp = ip->ep[i] = ep; return Dep; } static char* dname(int dtype) { switch(dtype){ case Ddev: return "device"; case Dconf: return "config"; case Dstr: return "string"; case Diface: return "interface"; case Dep: return "endpoint"; case Dreport: return "report"; case Dphysical: return "phys"; default: return "desc"; } } int parsedesc(Usbdev *d, Conf *c, uchar *b, int n) { int len, nd, tot; Iface *ip; Ep *ep; Altc *altc; char *hd; assert(d != nil && c != nil); tot = 0; ip = nil; ep = nil; altc = nil; for(nd = 0; nd < nelem(d->ddesc); nd++) if(d->ddesc[nd] == nil) break; while(n > 2 && b[0] != 0 && b[0] <= n){ len = b[0]; if(usbdebug>1){ hd = hexstr(b, len); fprint(2, "%s:\t\tparsedesc %s %x[%d] %s\n", argv0, dname(b[1]), b[1], b[0], hd); free(hd); } switch(b[1]){ case Ddev: case Dconf: werrstr("unexpected descriptor %d", b[1]); ddprint(2, "%s\tparsedesc: %r", argv0); break; case Diface: if(parseiface(d, c, b, n, &ip, &altc) < 0){ ddprint(2, "%s\tparsedesc: %r\n", argv0); return -1; } break; case Dep: if(ip == nil || altc == nil){ werrstr("unexpected endpoint descriptor"); break; } if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){ ddprint(2, "%s\tparsedesc: %r\n", argv0); return -1; } break; default: if(nd == nelem(d->ddesc)){ fprint(2, "%s: parsedesc: too many " "device-specific descriptors for device" " %s %s\n", argv0, d->vendor, d->product); break; } d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0); d->ddesc[nd]->iface = ip; d->ddesc[nd]->ep = ep; d->ddesc[nd]->altc = altc; d->ddesc[nd]->conf = c; memmove(&d->ddesc[nd]->data, b, len); ++nd; } n -= len; b += len; tot += len; } return tot; } int parseconf(Usbdev *d, Conf *c, uchar *b, int n) { DConf* dc; int l; int nr; char *hd; assert(d != nil && c != nil); dc = (DConf*)b; if(usbdebug>1){ hd = hexstr(b, Dconflen); fprint(2, "%s:\tparseconf %s\n", argv0, hd); free(hd); } if(dc->bLength < Dconflen){ werrstr("short configuration descriptor"); return -1; } if(dc->bDescriptorType != Dconf){ werrstr("not a configuration descriptor"); return -1; } c->cval = dc->bConfigurationValue; c->attrib = dc->bmAttributes; c->milliamps = dc->MaxPower*2; l = GET2(dc->wTotalLength); if(n < l){ werrstr("truncated configuration info"); return -1; } n -= Dconflen; b += Dconflen; nr = 0; if(n > 0 && (nr=parsedesc(d, c, b, n)) < 0) return -1; n -= nr; if(n > 0 && usbdebug>1) fprint(2, "%s:\tparseconf: %d bytes left\n", argv0, n); return l; } [i]->dev; if(dev != nil) increfusb/lib/usb.a8 664 0 0 301006 11456140501 12154ustar00rminnichsys! __.SYMDEF 1287176513 0 0 644 630 ` TŒFusbfsdirdumpDŒFusbdirfsTŒFusbfsexitsTŒFusbfsdelDŒFfslckTŒFusbfsaddTŒFusbfsgoneT×usbdirreadD×EioD×EbadctlD×EtoosmallT×usbreadbufT×usbfsinitD×usbfsdebugD×EnotfoundD×EinuseD×EpermD×fscallsD×EbadcallD×EisopenD×EbadfidT€ parsedescT€ parseconfT€ parsedevTh{estrdupTh{hexstrTh{classnameDh{usbdebugTh{UfmtTh{emalloczT]finddevsT]startdevsT]matchdevcspTºopenepTºusbcmdTºloaddevdescTºconfigdevTºunstallTºmkepTºclosedevTºdevctlTºloaddevstrTºopendevTºopendevdataTºloaddevconfdev.8 1287176513 0 0 664 23079 ` ~EnameidÜ>,A~@sp @ p  Sp pA p  SLF5=strrchr =p  & AX  .string-; > /dev/usb-; > #u/devp> D p SpASLO׿®= access =~@ dp @~@ idp @ &AP6 D p Sp> D p SpA p SLi"P= bind =p @p @ &AU7 device -!; > not confp!> Dp!SL·áP=werrstr!=p"A£"p$U &% AU%J<&% AU%K iguredb-&;( > ad enpoi-&;0 > nt numbep&>' Dp&S&=p'A£'p)  a) Qp)pO p*>: D~?modep*üÿÿÿ?s+P&+AX+`= Dp,üÿÿÿ?~?epp- øÿÿÿ?s-P&-AX-f<-.;8 > rrwrwp.>? Dp.üÿÿÿ?-/;@ > /dev/us-/;H > b/ep%d.%~?namea/Äÿÿÿ?p/Sp/(Ap/Sp/>A Dp/Sp/Up/ Sp/ SLD$s5=snprint/=a0Äÿÿÿ? p0 Sp0AS0 =&0AX0Œ d%s: %s-1;X > already-1;` > exists;-1;h > trying -1;p > to open p1Ap1Sp1>R Dp1SLzaò=argv0p1=p1Sa1Äÿÿÿ?p1 SLJ”§Š=fprint1=a2Äÿÿÿ? p2 SLÈnbk=opendev2=p2 &3AO3Š new %d p7 @ p7 Sp7>y D p7 Sp7 @ p7 Sp7øÿÿÿ? s7P p7  Sp7üÿÿÿ? p7 SL€$ö=devctl7=&7AP7¨<&8=AO8¦<-8;€ > %d %s%s-8;ˆ > : %s: nep8Ap8Sp8>† Dp8Sp8=p8Sp8 @p8Op8 S8=p9A£9a;Äÿÿÿ? p; S;=&<AX<¯ @ p> O-?; > w: %r m-?;˜ > axpkt %d~?epdp?ðÿÿÿ?p?Sp?>— D p? Sp?øÿÿÿ? p?P p? S?=p?ðÿÿÿ? p?øÿÿÿ? &?AP?É<-@;  > %s: %s:-@;¨ > openep:-@;° > maxpkt:p@Ap@Sp@>¡ Dp@Sp@=p@Sp@Rp@ S@=p@ðÿÿÿ? p@øÿÿÿ? W@Ø<&B=AOBØ<-B;¸ > %r %s:-B;À > %s: max-B;È > pkt %d pBApBSpB>½ DpBSpB=pBSpBRpB SpBQpBSB=pBðÿÿÿ? pBøÿÿÿ? pCQ pC RpDQpDO~?acpDôÿÿÿ?-E;Ð > ntds %dpE Q&EASEêÐ D pE SpE Q pE SE=pEðÿÿÿ? pEøÿÿÿ? &EAUEë %s: %s: -F;à > openep: -F;è > ntds: %rpFApFSpF>Ø DpFSpF=pFSpFRpF SF=pFðÿÿÿ? pFøÿÿÿ? WF<&H=AOH<-H;ð > %s: %s-H;ø > : ntds %pHApHSpH>ò DpHSpH=pHSpHRpH SpH QpHSH=pHðÿÿÿ? pHøÿÿÿ? &Qôÿÿÿ?AOQ d pollipR SpR> D pR SpRôÿÿÿ? pRP pR SR=pRðÿÿÿ? &RAPR)<-S; > val %d%-S; > s: %s: o-S; > penep: p-S;  > ollival:pSApSSpS> DpSSpS=pSSpSRpS SS=pSðÿÿÿ? pT £T£TÜX=$A-];( > %r /de-];0 > v/usb#up]>- D p] Sp]AS] =&]AP]<6 D p] Sp]>9 D p] Sp]A p] S] =&]AU]= /dev/cplüÿÿÿ? plP pløÿÿÿ? al QplSpl>> DplSl =pmüÿÿÿ? pmP pm Spm"A pm SLO׿®=!openm!=pmüÿÿÿ? pmQpnQpnøÿÿÿ? onAPpo@ po So>poüÿÿÿ? poQppQ&pAPp‚<-q;@ > tlcan't-q;H > open en-q;P > dpoint %pq>C DpqSpqQpqSq=prüÿÿÿ?prOprSL0f‹j="freer"=psüÿÿÿ?psSs"=ptA£t&v=AOv<-v;X > s: %r%s-v;` > : opende-v;h > v %#p %spvApvSpv>^ DpvSpv=pvSpv  Spv@pvSv=pvüÿÿÿ? pw £w£wLûï=#opendevdataÜ{#=hA-;p > %s/dat~?$bufa°ÿÿÿ$?pSa$?pSp>r DpS~@%dp%@pOp SL¦`o=&seprint&=a€°ÿÿÿ$? p€ S~@'modep€'@ ‡€ A p€ S€!=p€%@ p€ Qp Q££Lûï=(loaddevconfÜŽ(=0A~@)n&”)@AU”·<-•;x > aloadde-•;€ > vconf: b-•;ˆ > ug: out -•; > of confi-•;˜ > guration-•;  > s in devp•>z Dp•S•=-–;¨ > ice%s: p–Ap–Sp–>¬ Dp–Sp–=p–S–=p—ÿÿÿÿA£—p™A p™ Sp™AS™=pš€A p›%@ p› Sp› Sp›A p› Sp›)@ ‡›A p›  Sp›ASp›üÿÿÿ$?p›Sp›A p› SLïûS|=*usbcmd›*=p›)@p›%@ p›&œ A~?+nrpœøÿÿÿ+?PœÕ.mkstrܲ.>(Ap²)@ &¹ AS¹  %r nonepº>´ D pº SLßëe'=/strdupº/=£ºp»  »þÿÿÿA&»€A²»ÿÿÿÿA¯»A~@0b ¼A0@p½)@a½O C½ p½ Sp½AS½=p½0@ p½ ~?1usp½øÿÿÿ1?p¾)@ a¾ P p¾ a¾ OC¾~?ep¾ðÿÿÿ?W¿)¹ D pÁ SwÁ  pÁ  SÁ&=pÁ0@ pÁ WÁ& %CnonepÎ>¼ D pÎ SLßëe'=estrdupÎ=£ÎpÏ€A pÐ%@ pÐ SpÐ SpÐA pÐ SpÐ  ‡ÐA pÐ  SpÐASaЀÿÿÿ$? pÐ SpЀA pÐ SÐ*=aÑ€ÿÿÿ$? pÑ SpÑSÑ.>£Ñ£ÑL ­ýA=loaddevdescÜÕ=DA~?typepÜ€Aäþÿÿ?pÝAèþÿÿ+?aÞïþÿÿ$?pÞSpÞASpÞApÞSL£Xýù=memsetÞ=pß%@ pß Spßäþÿÿ? pß SpßA pß SpßA pß  SpßASaßïþÿÿ$? pß Spßèþÿÿ+? pß Sß*=&ßAPß{ %s: %s:-ç;È > warning-ç;Ð > : device-ç;Ø > with sh-ç;à > ort desc-ç;è > riptor pç>Á DpçSpç=pçSpç%@pçOpçSLuˆ‘=printç=pçèþÿÿ+? &é APé<-ê;ð > short de-ê;ø > vice des-ê; > criptor -ê; > (%d bytepê>ð DpêSpê Sê=pëÿÿÿÿA£ëpî°A pî SpîA pî Sî=pî%@ pîQpïQ pï SpïASï-=pï%@ oðAOoñAOpòARpòA pò Opó Saóïþÿÿ$? pó Spóèþÿÿ+? pó SL» „D= parsedevó =pó%@ póèþÿÿ+?&ôèþÿÿ+?AUôË .string-ö; > s)nonepöQ pöP pö Spö> D pö SL´§,= strcmpö =pö%@ &öAOöËcloseconfÜ>A~@cp@ & AXû<£pAW %s: clos-&;  > edev %#pp&Ap&Sp&> Dp&Sp&=p&Sp&  Sp&Rp&S&=p&%@ p'$R&'AO'Gp<üÿÿÿ ? W< %s dev~>ds$34-F;>>- D-F;>>1 D-F;>>4 D-F;0 > ifepo-F; >>7 D~>reqstrÜC>A~@typepI@ I€A&IAOI²<~>buf$34pJ>D pJ SpJ>(D pJ SpJ>; D pJ SJ&=pJ WJº<-L;8 > thd2hhpL>D pL SpL>(D pL SpL>? D pL SL&=pL pM@ M A&MAOMÆ<-N;@ > 2d|clspN SpN>(D pN SpN>C D pN SN&=pN WNÙ(D pP SpP>H D pP SP&=pP WPÙ<-R;H > |vnd|stpR SpR>(D pR SpR>M D pR SR&=pR pS SpS>(D pS SpS>R D pS SpS@ SA pS > pS  SS&=pS W`6 d|%s gpV SpV>(D pV SpV>V D pV SV&=pV WVå<-W;X > etsts cpW SpW>(D pW SpW>^ D pW SW&=pW WWå<-X;` > lrfeat -X;h > setfeatpX SpX>(D pX SpX>g D pX SX&=pX WXå<-Y;p > setaddrpY SpY>(D pY SpY>p D pY SY&=pY WYå<-Z;x > getdespZ SpZ>(D pZ SpZ>y D pZ SZ&=pZ WZå<-[;€ > c setdep[ Sp[>(D p[ Sp[>‚ D p[ S[&=p[ W[å<-\;ˆ > sc getcp\ Sp\>(D p\ Sp\>‹ D p\ S\&=p\ W\å<-]; > nf setcp] Sp]>(D p] Sp]>“ D p] S]&=p] W]å<-^;˜ > nf getip^ Sp^>(D p^ Sp^>› D p^ S^&=p^ W^å<-_;  > f setifp_ Sp_>(D p_ Sp_>¢ D p_ S_&=p_ W_å<~@reqp_@&_AQ_GD£b£b~>cmdreqÜf>LA&m%@AOmW d != nipm>© DpmSL¼ì?;=_assertm=~@data&n@AXn`p~ @ p~ -;° > l%s: %s-;¸ > val %d|-;À > %d idx %-;È > d cnt %d-;Ð > out[%d]pApSp>² DpS~@'dp'@pOpSp  Sp ¯ApSp  ÿApSp!@pSp@pSpüÿÿÿ? Ap Spèÿÿÿ&?p$S~=(fprint(=p‚èÿÿÿ&?p‚S~=)free‚)=p‚ôÿÿÿ"? p„'@ p„ P p„ Sp„ ôÿÿÿ"?p„ Sp„üÿÿÿ? „A p„ SL %s %s:-Š;à > cmd: sh-Š;è > ort writpŠApŠSpŠ>Ý DpŠS~=-argv0pŠ-=pŠSpŠ  SŠ(=p‹ÿÿÿÿA£‹p ££~>.cmdrepÜ‘.> Ap•'@ p• P p• S~@/bufp•/@ p• S~@0nbp•0@ p• SL e: %d %-˜;ø > s: in[%dp˜Ap˜Sp˜>÷ Dp˜Sp˜'@p˜Op˜Sp˜0@p˜ Sp˜ üÿÿÿ&?p˜ S˜(=p™üÿÿÿ&?p™S™)=p™0@ p› £›£›~=usbcmdÜŸ=pApŸ@pŸ @pŸ!@ pŸ@ pŸ@ p¨ÿÿÿÿA ~?erro©A´ÿÿÿ?pªA~?nerrpªôÿÿÿ?pªüÿÿÿ ?Wªp¬ W¬.p® &¯ A~?rp¯ øÿÿÿ?S¯Gp² &³AS³A ] %s no-¶; > data fr-¶; > om devicp¶> Dp¶S~=werrstr¶=C¸ôÿÿÿ?r¹´ÿÿÿ?&¹AX¹P e%s: us-¿;  > bcmd: %s-¿;( > : requir-¿;0 > ed %d at-¿;8 > tempts (p¿Ap¿Sp¿> Dp¿Sp¿-=p¿Sp¿'@p¿Op¿ Sp¿üÿÿÿ ?p¿Sa¿´ÿÿÿ?p¿S¿(=p¿øÿÿÿ? pÁ £Á£ÁL@á>í=unstallÜÅ=(A~@ dir&É @AXÉw .string-Ï;@ > %s) uns-Ï;H > tall: %spÏ>E DpÏSpÏQpÏSÏ=pÐÿÿÿÿA£Ð-Ò;P > : %rclrpÒ SpÒ>U D pÒ S~= devctlÒ =&ÒAPÒž<-Ó;X > haltclr-Ó;` > halt: %spÓ>] DpÓSpÓ @pÓOpÓSÓ=pÔÿÿÿÿA£ÔpÖA£Ö£ÖÜÝ = A~@fmtaã@~?bufaä€ÿÿÿ? pä Saä? pä Spä@ pä S~?argpä|ÿÿÿ?pä SLR7=vseprintä=pæ @ pæP pæ Saæ€ÿÿÿ? pæ Saæ€ÿÿÿ? pæ Öæ  pæ Sæ*=£æ£æ-æ;h > : %r5æ>A5æ >pA5æ>(AIæúdevs.8 1287176513 0 0 664 7694 ` ~EworkprocÜ>A~@ap@ ~?argsaþÿÿ?pSaüÿÿÿ?pS~?pap üÿÿÿ?pPpSLÓ–ÍF=strecpy=püÿÿÿ? pP~?dpüüÿÿ?pP~?fpøüÿÿ?p P~?rcpýÿÿ?p Pp SL0f‹j= free  =p!üÿÿÿ?p!S! =a"þÿÿ? p" S~? argva"ýÿÿ ? p" Sp"?A p" SL¸#×3= tokenize" =p#Aýÿÿ ?p$üüÿÿ? p$ Sp$Sa$ýÿÿ ? p$ Sp$øüÿÿ?$&$AP$: .string-&; > %s: devm-&; > ain: %r p&Ap&Sp&> Dp&SLzaò=argv0p&=p&SLJ”§Š=fprint&=p'ýÿÿ?p'Sp'ÿÿÿÿAp'SLMóV==sendul'=-(; > devmainp(> Dp(SL¼ì?;=threadexits(=p*ýÿÿ?p*Sp*AS*=p+AS+=£+L(!b[=matchdevcspÜ0=DAp5@ W6G : %rcsp-7; > %#08ux~?sbufa7Øÿÿÿ?p7Sp7(Ap7Sp7> Dp7S~?cspsp7 Ôÿÿÿ?p7Pp7 SLD$s5=snprint7=~@infop8@ p8 Sa8Øÿÿÿ? p8 SLi})ì=strstr8=p8Ôÿÿÿ? &8AO8^ /dev/usbpF>( D pF SpFASLO׿®=openF=pF &GA~?fdpGüÿÿÿ?PGo<-H;0 > /dev/uspH>1 DpHSL·áP=sysfatalH=pHüÿÿÿ? pI SaI¼ýÿÿ? pI SLvŽ’Å=dirreadallI=~?ndpIðÿÿÿ?pJüÿÿÿ?pJSLÃ)»=closeJ=&Kðÿÿÿ?APK|<-L;8 > b: %r/d-L;@ > ev/usb: -L;H > no devspL>> DpLSL=pMA~?npMôÿÿÿ?~? ipMøÿÿÿ ?WMƒP D pO SL´§,=#strcmpO#=&OAOO T D pO SO=&OAOO  ctl.0/-Q;X > dev/usb/~?$fbufaQÀýÿÿ$?pQSpQ(ApQSpQ>W DpQSpQèÿÿÿ"?pQ SQ=aRÀýÿÿ$? pR SpRASR=&SAPS± %s/ctle-Z;h > nabled aZèýÿÿ%? pZ SpZ>g D pZ SZ=&ZAOZÏp D pZ SZ=&ZAOZÐ busy/d-\;x > ev/usb/%p\>v D p\ Sp\èÿÿÿ"? p\ SLò¬ˆ$=*smprint\*=p\ôÿÿÿ? C\ôÿÿÿ?~@+dirsp\+@ a\ R p\PW\€ sfindde-a;ˆ > vs: %s paApaSpa>‚ DpaSpa  pa ðÿÿÿ?pa+@ pa QpaSa=paðÿÿÿ? Waê /dev/usb-p;˜ > #u/devpp> D pp SppASLO׿®=.accessp.=&pAPp™ D pp Spp>œ D pp SppA pp SLi"P=/bindp/=&pAUp #u: %rpq>¡ DpqSq=~@0argc&s0@ASs %s: too -z;° > many devpzApzSpz>¨ DpzSpz=pzSz=~?ndevsp|Aôÿÿÿ?p}A p} Sp}ASLËÖô=chancreate}=p}dÿÿÿ?&~dÿÿÿ?AX~8<-;¸ > ices no-;À > memoryp>¾ DpS=p€A W€= %s: star-;Ð > tdevs: o-;Ø > pening #pApSp>È DpSp=pSp  Sp  p üÿÿÿ ?ppÿÿÿ? p QpS=p‚üÿÿÿ ? p‚pÿÿÿ? p‚ R p‚ SLÈnbk=opendev‚=&ƒAXƒ`<-„;à > %d %s %-„;è > s: %s: %p„Ap„Sp„>ç Dp„Sp„=p„Sp„üÿÿÿ ? p„pÿÿÿ? p„ Qp„ S„=p„üÿÿÿ ? W„œ<~? devp…hÿÿÿ ?p…SL ­ýA= configdev… =p…= &…AP…u<-†;ð > r %s: %-†;ø > s: confip†Ap†Sp†>ó Dp†Sp† Sp†üÿÿÿ ? p†pÿÿÿ? p† Qp† S†=p‡hÿÿÿ ?p‡S‡ =p‡üÿÿÿ ? W‡œ<&‰,=AO‰<-‰; > g: %r %p‰Ap‰Sp‰> Dp‰Sp‰ Sp‰hÿÿÿ ?p‰ S‰=pŠA pŠ SpŠASL;ø„= emalloczŠ =~? pargpŠlÿÿÿ ?~@ argsp‹ @ p‹ SLßëe'=estrdup‹=p‹lÿÿÿ ? p‹QpŒhÿÿÿ ? pŒ Q~?rcpdÿÿÿ? p  Q~@dfpŽ@ pŽ Q~>workprocp>DpSp Sp@ApSLS]Å)=proccreate=pdÿÿÿ? p SL(ö(+=recvul=püÿÿÿ ? &AXœ.string-˜;> s: %Uno-˜;> unhandl-˜;> ed devic-˜; > es foundp˜>Dp˜S˜=£˜-˜;(> 5˜>0AI˜dump.8 1287176513 0 0 664 9436 ` ~Eedir~>.string-M;>>D-M;>>D-M;> inouti-M;>>D-N;> noutctl~>etype-N;>> D-N;>>D-N;> isobul-N;>>D-N; >>D-Q;> kintrn~>cnames-Q;>>D-Q; > oneaudi-Q;>>$D-Q;(> ocomms-Q;>>*D-Q; >>0D-Q;>>4D-R;>>5D-R;>>6D-R;0> hidp-R;>>7D-R;8> rinters-R; >>?D-R;@> torageh-R;$>>GD-R;H> ubdata-R;(>>KD-V;P> detached~>devstates-V;>>PD-V;X> attache-V;>>YD-V;`> denable-V;>>bD-V;h> dassign-V; >>jD-V;p> edconfi-V;>>sDL’´q¼=classnameÜZ=A~@cpZ@ &^ AU^<&^  AU^£_W_<-a;x> gured%d~>buf$1pa>DpaSpa>DpaSpa>~DpaSpa  SL¦`o= seprinta =pb>D£b£bLðÁc“= hexstrÜg =,A~@ apm @~? bpmìÿÿÿ ?pnA pn SpnASL;ø„= emalloczn =pn ~?dbuffpnøÿÿÿ?ooAO pA~?eppðÿÿÿ?pqA Wq& %.2uxpr Sprðÿÿÿ? pr Spr>D pr Sprìÿÿÿ ? pr  ~?ipr üÿÿÿ?sr R pr  Sr =prüÿÿÿ? pr Wr#<&s ðÿÿÿ?Xs?<-t;ˆ> %s: usb/-t;> lib: hex-t;˜> dump: bu-t; > g: small-t;¨> buffer ptAptSpt>ˆDptSLzaò=argv0pt=ptSLJ”§Š=fprintt=puøÿÿÿ?£u£u~>seprintifaceÜy>DA-€;°> iface-€;¸> csp %s.-€;À> %uld.%ul~@ip€@ p€P €ÿA p€ S€=p€@ ~?.safep€äÿÿÿ?~@sp€@ p€ S~@ep€@ p€ Sp€>±D p€ Sp€äÿÿÿ? p€  Sp€Q Í€A €ÿA p€ Sp€Q Í€A €ÿA p€ S€ =p€ p‚A W‚a d a-†;Ð> lt %d at-†;Ø> tr %d ivp† Sp†@ p† Sp†>ËD p† S~?jp† üÿÿÿ?p†  Sp†O p† S~?ap†øÿÿÿ?p†O p† S† =p†@ p†øÿÿÿ? p† pˆR&ˆAOˆ†<-‰;à> al %d d-‰;è> evspec %p‰ Sp‰ Sp‰>æD p‰ Sp‰R p‰  S‰ =p‰üÿÿÿ? p‰ W‰óD p‹ S‹ =p‹üÿÿÿ? p‹ W‹^õDp‘ s’Q&’AR’¤ s”Q&”AR”©-–;ð> p -–;ø> ep id -–;> %d addr -–;> %d dir %-–;> s type %-–;> s itype -–; > %d maxpk-–;(> t %d ntdp– Sp–@ p– Sp–>öD p– Sp–Q p–  Ss–Q p– Sp– Sp–Ss–Q p– Sp–Q p–  Sp– Q p– $S– =p–üÿÿÿ? p– W–seprintconfÜŸ>,A~@cip¥ @ ~@dp¥@ a¥ Qp¥0O-¦;0> s %d c-¦;8> onf: cva-¦;@> l %d att-¦;H> rib %x %p¦@ p¦ Sp¦@ p¦ Sp¦>6D p¦ Sp¦O p¦  Sp¦O p¦ S~?cp¦øÿÿÿ?p¦O p¦ S¦ =p¦@p¦p¦@p¨A W¨Üp¬@p¬üÿÿÿ? p¬p¬@W¬Ù d mA -³;X> dev desc-³;`> %x[%d]:p³@ p³ Sp³@ p³ Sp³>VD p³ Sa³V p³°P s³P p³  Sa³V p³°P s³P p³ S~? hdp³ôÿÿÿ ?p³S³ =p³@p¶ôÿÿÿ ?p¶SL0f‹j=!free¶!=p¶@p¶@p¶üÿÿÿ? W¶ö<-È;h> %s mD pÈ SLC;ñ-=%fmtprintÈ%=£È-É;p> ldev> %pÉ S~?&epÉìûÿÿ&?pÉSpÉ>wD pÉ S~?'dpÉøÿÿÿ'?pÉO pÉ  SÉ =pÉøÿÿÿ'? ~?(spÉðûÿÿ(?pÊR&ËAXËV<-Ì;x> s%s %ldpÌ#@ pÌ SpÌ>zD pÌ SaÌôûÿÿ$? pÌ SpÌR pÌ  SÌ%=£Ì-Í;€> refs -Í;ˆ> csp %s.%-Í;> uld.%uld~?)udpÍôÿÿÿ)?pÍO ÍÿA pÍ SÍ=pÍôÿÿÿ)? pÍäûÿÿ?pÍðûÿÿ(? pÍ SpÍìûÿÿ&? pÍ SpÍ>‡D pÍ SpÍäûÿÿ? pÍ  SpÍQ ÍÍA ÍÿA pÍ SpÍQ ÍÍA ÍÿA pÍ SÍ =pÍôÿÿÿ)? -Ï;˜> vid %#-Ï; > ux did %pÏSpÏìûÿÿ&? pÏ SpÏ>™D pÏ SpÏR pÏ  SpÏR pÏ SÏ =-Ð;¨> #ux refpÐSpÐìûÿÿ&? pÐ SpÐ>¬D pÐ SpÐøÿÿÿ'? pÐP pÐ  SÐ =pÐôÿÿÿ)? -Ñ;°> s %ld -Ñ;¸> %s %s %spÑSpÑìûÿÿ&? pÑ SpÑ>·D pÑ SpÑQ pÑ  SpÑQ pÑ SpÑQ pÑ SÑ =pÑ pÒA WÒ•pÖüÿÿÿ? pÖ WÖ’ÂD pØ SaØôûÿÿ$? pØ SØ%=£Ø£ØLßëe'=*estrdupÜÜ*=A~@+spà+@ pà SLßëe'=,strdupà,=&áApáüÿÿÿ'?Xá¼<-â;À> %sstr-â;È> dup: %rpâ>ÅDpâSL·áP=-sysfatalâ-=aã+@ pã SLÀ"S]=.getcallerpcã.=pãôÿÿÿ?pãüÿÿÿ'?pãSpãôÿÿÿ?pãSL§ب=/setmalloctagã/=päüÿÿÿ'?£ä£äÜè =A~@0sizepì0@ pì SLØŠ\‰=1mallocì1=pì &íA~?xpíüÿÿÿ?XíÔ<-î;Ð> malloc: pî>ÐDpîSî-=pîüÿÿÿ? ~@zero&ï@AOïÛ.string-ò;Ø> %r~>cnames5ò>,A~>etype5ò>A5ò>àAL½ÕQA=usbdebug5ò=A5ò>A~>devstates5ò>A~> edir5ò > AIòparse.8 1287176513 0 0 664 13892 ` ~E.string-S;> d != nilpS>DpSSL¼ì?;=_assertS=pSüÿÿÿ? ~@bpT@ ~?ddpT øÿÿÿ?L½ÕQA=usbdebug&U=ASU& %s: par-W;> sedev %spWApWSpW> DpWSLzaò= argv0pW =pWSpW@pWOpW S~? hdpW ôÿÿÿ ?pW SLJ”§Š= fprintW =pXôÿÿÿ ?pXSL0f‹j= freeX =pXüÿÿÿ? pXøÿÿÿ? sZQ&ZALZ2<-[;> : %s sh-[; > ort dev -[;(> descr. (-[;0> %d < %d)p[>Dp[Ss[Qp[Sp[Ap[SL·áP=werrstr[=p\ÿÿÿÿA£\s^Q&^AO^<<-_;8> %d is n-_;@> ot a dev-_;H> descripp_>9Dp_Ss_Qp_S_=p`ÿÿÿÿA£`sbQ¬bAsbQ ‡b pb sbQ ¬bA ‡b pbRpc@ scQpcPpcpR pcPsdQ pd (RseQ pe ,Rpf,R&fAXf_<&g=AOg_<-g;P> tor%s: -g;X> %s: no c-g;`> onfigurapgApgSpg>TDpgSpg =pgSpg@pgOpg Sg =pgüÿÿÿ? pgøÿÿÿ? sh Q hÿA¬hAshQ hÿA ‡h phRsi Q iÿA¬iAsi Q iÿA ‡i piRsj Q jÿA¬jAsj Q jÿA ‡j pj RskQ pk RslQ pl  RsmQ pm $R~@n&n@ASn~<&n=AQn tions %-o;p> s: %s: p-o;x> arsedev:-o;€> %d bytepoApoSpo>oDpoSpo =poSpo@poOpo Spo@ oîÿÿÿApoSo =pqA£q£q~>parseifaceÜu>,A~@d&|@AO|”<~@c&|@AX|• s leftd-|;> != nil -|;˜> && c != p|>Dp|S|=&} @ AP} <-~; > nilshor-~;¨> t interf-~;°> ace descp~>¤Dp~S~=pÿÿÿÿA£p@~?dipp‚èÿÿÿ?s‚Vp‚&ƒAUƒ©<&ƒAPƒ© riptorb-„;À> ad inter-„;È> face nump„>¿Dp„Sp„S„=p…ÿÿÿÿA£…~?ifidp‡ðÿÿÿ?p‡@ a‡Qp‡ O&‡AX‡¿ ber %db-—;Ø> ad alter-—;à> nate con-—;è> f. numbep—>×Dp—Sp—S—=p˜ÿÿÿÿA£˜~?altidpšìÿÿÿ?pš  ~?ippš äÿÿÿ?ašQpšO&šAXšparseendptܤ>(A~@altcp¤ @ ~@ipp¤@&ª@AOª<&ª@AXª r %dd !-ª;ø> = nil &&-ª;> c != ni-ª;> l && ip -ª;> != nil &-ª;> & altc !pª>õDpªSª=pª @ pª@&«@AP«,<-¬; > = nilsh-¬;(> ort endp-¬;0> oint des-¬;8> criptorp¬>&Dp¬S¬=p­ÿÿÿÿA£­p¯@ s°R p° Qs±R p± Q~?depp³ ìÿÿÿ?s³R ³Ap³&´A~?epidp´ôÿÿÿ?P´9 epid < n-´;H> elem(d->p´>@Dp´S´=p´ôÿÿÿ?p´@p´ìÿÿÿ? sµR µ€A&µAOµE<~?dirp¶Aøÿÿÿ?W¶F ep)pars-Ë;X> eendpt: -Ë;`> bug: too-Ë;h> many en-Ë;p> d points-Ë;x> on inte-Ë;€> rface wi-Ë;ˆ> th csp %pË>TDpËSpËVpËSË=-Í;> #lux%s:pÍApÍSpÍ>•DpÍSpÍ =pÍSÍ =pÎÿÿÿÿA£Î~@!epppÐ!@aÐV pÐ HQpÐ OpÑA£Ñ£Ñ~>"dnameÜÕ">AWଠ%r devpØ>D£Ø-Ù; > iceconfpÙ>¤D£Ù-Ú;¨> igstrinpÚ>«D£Ú-Û;°> ginterfpÛ>²D£Û-Ü;¸> aceendppÜ>¼D£Ü-Ý;À> ointreppÝ>ÅD£Ý-Þ;È> ortphyspÞ>ÌD£Þpß>ÑD£ß~@#dtypepß#@&ßAQß· descd -ì;Ø> != nil &-ì;à> & c != npì>ÖDpìSì=~?%totpíAôÿÿÿ%?~?&ippîAðÿÿÿ&?~?'eppïAìÿÿÿ'?~?(altcpðAèÿÿÿ(?~?)ndpñAøÿÿÿ)?WñÒ il%s: -ù;ð> parsedes-ù;ø> c %s %x[-ù;> %d] %s pù@ sùP pù Sù">pù@ ~?+.safepùÜÿÿÿ+?pùApùSpù>ëDpùSpù =pùSpùÜÿÿÿ+?pù SsùPpùSsùPpùSpùäÿÿÿ ?pùSù =pûäÿÿÿ ?pûSû =W"• unexpect-;> ed descr-;> iptor %dp>DpSp@sOpS=&=AS<-; > %s pars-;(> edesc: %pApSp>!DpSp =pS =W&AP9<&=AS7<-;0> r%s par-;8> sedesc: pApSp>2DpSp =pS =pÿÿÿÿA£W<& ðÿÿÿ&?AO ?<& èÿÿÿ(?AO ? %r unex- ;H> pected e- ;P> ndpoint - ;X> descriptp >DDp S =W &AP_<&=AS]<-;`> or%s pa-;h> rsedesc:pApSp>cDpSp =pS =pÿÿÿÿA£W<&øÿÿÿ)?€AXp<-;p> %r %s:-;x> parsede-;€> sc: too -;ˆ> many dev-;> ice-spec-;˜> ific des-; > criptors-;¨> for dev-;°> ice %s %pApSp>uDpSp =pSp@pOp Sp@pOpS =W s d != -2;À> nil && c-2;È> != nilp2>»Dp2S2=p2@p2@ p2 @ p3 ~?.dcp3üÿÿÿ.?&4=AS4Ó %s: pars-6;Ø> econf %p6Ap6Sp6>ÐDp6Sp6 =p6Sp6 ðÿÿÿ ?p6  S6 =p7ðÿÿÿ ?p7S7 =p7@p7@ p7 @ p7üÿÿÿ.? s9Q&9 AL9Û<-:;à> s short-:;è> configu-:;ð> ration d-:;ø> escriptop:>ãDp:S:=p;ÿÿÿÿA£;s=Q&=AO=ã<->;> rnot a ->;> configur->;> ation de->;> scriptorp>>Dp>S>=p?ÿÿÿÿA£?sAQ pA TsBQ pB TsCQ CpCTsDQ DÿA¬DAsDQ DÿA ‡D ~?/lpDøÿÿÿ/?&E øÿÿÿ/?PEø<-F; > truncat-F;(> ed confi-F;0> gurationpF>!DpFSF=pGÿÿÿÿA£GÖI A J ApKA &L ASL info%s-P;@> : parsec-P;H> onf: %d -P;P> bytes lepPApPSpP>>DpPSpP =pPSpP  SP =pQøÿÿÿ/?£Q£Q-Q;X> ft 5Q>`AIQfs.8 1287176513 0 0 664 28495 ` ~E msgsize-; > A~> fsfd-; >ÿÿÿÿA~> schedprocÜ >pA~> proccp! >~?ap!¤ÿÿÿ?~?proca!ôÿÿÿ?p!¨ÿÿÿ?p!A¬ÿÿÿ?~>endcp!>p!¼ÿÿÿ?~?pa!ìÿÿÿ?p!Àÿÿÿ?p!AÄÿÿÿ?p!AÔÿÿÿ?p!AØÿÿÿ?p!AÜÿÿÿ?a"ôÿÿÿ?p"Sp"ASp" Ap"SL£Xýù=memset"=p#A W<fsioprocp'>Dp'Sp'ôÿÿÿ?p'Sp'@Ap'SLS]Å)=proccreate'=C(ðÿÿÿ?W;F.stringp:>Dp:SL·áP=sysfatal:=p:ðÿÿÿ? W:)dumpÜ@>,A~>rpclckpE>DpESL+l=qlockE=-F;> altdumppFApFSpF>DpFSLJ”§Š=fprintF=~>rpcspG> WG` : rpc %-H;> #p %F ne-H;> xt %#p pHApHSpH> DpHSpH SpH  SpH üÿÿÿ ?pH(PpHSH=WH\<~>!fidspI!> WIs fid %d q-J;(> id %#llu-J;0> x omode -J;8> %d aux %pJApJSpJ> DpJSpJQpJSpJQpJ SpJQpJSpJQpJSpJ øÿÿÿ"?pJQpJSJ=WJoDDpLSL=pM>DpMSL+l=#qunlockM#=£M~>$newrpcÜQ$>ApU>DpUSU=~>%freerpcspV%> &W AOW™WXž p[ (Rp\ >q]ÿÿARp]ÿÿA q] Rp^ÿÿÿÿARp^ÿÿÿÿA p^ Ro_ARp_A o_ Rp`A$RpaA Rpb  ~?'rpb üÿÿÿ'? b,A pb (Rpc>DpcSc#=pdüÿÿÿ'?£d£d~>(freerpcÜh(>A~@)r&k)@AXkº<£lpm>DpmSm=pm)@ pn>D WnÄ #p *lpp>FDppSL¼ì?;=+_assertp+=pp)@ ppüÿÿÿ*? pq pq(Q pq Opr%> pr (Qps %>otAQquwwAQpv>DpvSv#=£v~>,flushrpcÜz,>Ap~>Dp~S~=~@-tagp~-@ p> WìDp„S„#=£„~>.getfid܈.>ApŒ>DpŒSŒ=~@/allocpŒ/@ ~>0freefidspŒ0> ~@1fidpŒ1@ p!> WDpS#=p‘A£‘&“ A~?fp“ üÿÿÿ?X“<&“ AX“W–( pœ Qp üÿÿÿ?p !>pŸ>DpŸSŸ#=p üÿÿÿ?£ £ ~>freefidܤ>A~@fp¤@ ~>fsopsp¤> &¨ AX¨;<£©pª@P&ªAOªBDp¬S¬=p¬@ p­>!D W­L == r*lp¯>NDp¯S¯+=p¯@ p¯üÿÿÿ*? p° p°Q p° Op±0> p± Qp² 0>p³>Dp³S³#=£³~>fserrorÜ·> A~@fmta¼@p¼ ~@rpcp½@ ½,Ap¾S ¾€ Ap¾Sp¾@p¾S~?argp¾ üÿÿÿ?p¾  SLR7= vseprint¾ =p¾@oÀkAOpÁ Á,A pÁ O£Â£Â~> fsversionÜÆ >ApÆ)@ pÈ Q&ÈALȆ£É-Ê;P> == f9PpÊQ pÊ SpÊ>VD pÊ SpÊA pÊ SLÃa·= strncmpÊ =~> msgsizepÊ > pÊ)@ &ÊAOÊ–<-Ë;X> 2000wro-Ë;`> ng versipË SpË>]D pË SË>£ËpÌ Q&Ì LÌšpÎ Q-Ï;h> on9P200pÏ>kD pÏ  QpÐ £Ð£Ð~>fsattachÜÔ> ALtí|(=getuserÙ=pÙ)@ pÙ ~>userpÙ>~>already$27pÚ>CÚ>&ÚASÚ±£ÛpÜ R&ÜAXÜ¿£Ýo߀A(Rpà> pà(QpàRpà,Qpà Rpá páA$Rpâ R âApâ  âApâA !â¡âyâpã £ã£ã~>fswalkÜç> Apç)@ pì TpìO&ìÿÿÿÿAOìÝ£ípïA ~?nfidpï øÿÿÿ?pð T~?ofidpðôÿÿÿ?pñ TpñT &ñ Oñpò)@ pò &óAXóó£ôpõ õApõ T õApõA !õ¡õyõpö>pö<O&öAOö p÷Sp÷ôÿÿÿ?p÷Sp÷ øÿÿÿ?p÷ Sp÷>p÷<O÷p÷øÿÿÿ? p÷)@ W÷ pþ Spþ T pþ Spþ  ~?ipþ üÿÿÿ?pþ  aþ R pþP pþ Spþ>pþ8Oþpþøÿÿÿ? pþüÿÿÿ? pþ)@ &þAPþ-püÿÿÿ? p)@ pôÿÿÿ? p  T& AXO.stringp >rD p  S >£ p  £ £ ~>fsioprocÜ>8A~@ap@~?ppøÿÿÿ?L½ÕQA=usbfsdebug&=AOh<-;p> 0%r%s:-;x> fsiopro-;€> c pid %dLçGÂI=getpid=~? .safepàÿÿÿ ?pApSp>uDpSLzaò=!argv0p!=pSpàÿÿÿ ?p S~="fprint"=Wk p &AOj %s: fs-;> ioproc p-;˜> id %d: r=pàÿÿÿ ?pApSp>ŠDpSp!=pSpàÿÿÿ ?p Spðÿÿÿ$?sOpS"=pèÿÿÿ'? p> pðÿÿÿ$? W:ß eq %d %-*;¨> s: bug: -*;°> read %ld-*;¸> bytes >-*;À> %ud wanp*>§Dp*Sp*!=p*Sp* üÿÿÿ(?p* Sp*Pp* SLuˆ‘=)print*)=p*üÿÿÿ(? p,ìÿÿÿ%?p, OW3Ž ted fsi-9;Ð> oproc: b-9;Ø> ad typep9>ÍDp9S~=*sysfatal9*=p9üÿÿÿ(? W9ŽàD p< S<>p<àÿÿÿ ?~>+outcp<+>p<Sp<àÿÿÿ ?p<S~=,sendp<,=W<ú+>p>Sp>ôÿÿÿ&?p>S>,=~>-endcp?->p?Sp?øÿÿÿ?p?S?,=W?i %r%s: f-B;è> sioproc -B;ð> %d exitiB=pBàÿÿÿ ?pBApBSpB>ãDpBSpB!=pBSpBàÿÿÿ ?pB SB"=pCASL¼ì?;=/threadexitsC/=£C~>0fsopenÜG0>A~@1rpG1@ pK QpKO&KÿÿÿÿAOK£LsMQ MA&MAOM'£N~>proccpO> pO SO#=pPSpP1@pPSP,=pQA£Q£QLøHj=usbdirreadÜU=˜A~?da[ÿÿÿ?p[Sp[ASp[<Ap[S~=memset[=~?namea\Ìÿÿÿ?p\¼ÿÿÿ?p]>p]Èÿÿÿ?p]Äÿÿÿ?p]Àÿÿÿ?p^ASL€.=time^=p^¬ÿÿÿ?~>epochp_>p_°ÿÿÿ?p`A´ÿÿÿ?p`A¸ÿÿÿ?paA~?npaøÿÿÿ?pa WaR ng %s: -c;> dir %d q-c;> %#llux:pcApcSpc>üDpcSpc!=pcSpcüÿÿÿ?pc Spc @pcSpc @pcSacÿÿÿ?pcSc"=adÿÿÿ? pd S~@ datapd @ pdøÿÿÿ? ad R pd S~@cntpd@ Ödøÿÿÿ? pd SLâ]r"=convD2Md=pd &eAQeƒuserpl>plÈÿÿÿ?plÄÿÿÿ?plÀÿÿÿ?pmASm=pmüÿÿÿ? pm¬ÿÿÿ?pn>pn°ÿÿÿ?poA´ÿÿÿ?poA¸ÿÿÿ?WoOfsreadÜ€>Ap€1@ p„ Qp„O&„AO„äfserror…>£…p†> p† S†#=p‡Sp‡1@p‡S‡,=pˆA£ˆ£ˆ~>fswriteÜŒ>ApŒ1@ p QpO&AOþ£‘p’> p’ S’#=p“Sp“1@p“S“,=p”A£”£”~>fsclunkܘ>Apš1@pš OpšS~>freefidš>p›1@£›£›~>fsnoÜŸ> Ap¡1@ p¡ Sp¡=D p¡ S¡>£¡£¡~>fsstatÜ¥>„AaªÄÿÿÿ?pªSpªASpª<ApªSª=a«œÿÿÿ?p«ðÿÿÿ?p¬>p¬üÿÿÿ?p¬øÿÿÿ?p¬ôÿÿÿ?p­AS­=~> fsopsp­ > p­àÿÿÿ?p®>p®äÿÿÿ?p¯Aèÿÿÿ?p¯Aìÿÿÿ?p° Sp°1@p° U °Aa°Sp°A !°¡°y°a°Äÿÿÿ? p° Sp°PQ°p°1@ &°AP°H<~>!.string-±;!> %D %rp± Sp±>!D p± S±>£±p²  ²,A p²  Qa³Äÿÿÿ? p³ Sp³  ³,A p³ S~>"msgsizep³"> p³ S³=p³1@ q³Qp´ £´£´~>#fsflushܸ#>ApÆ1@wÆ OpÆS~>$flushrpcÆ$>pÇ1@£Ç£ÇLè Â=%fscalls~>&fsversion-Ë;%=>&D-Ì;˜%=>D~>'fsattach-Í; %=>'D~>(fswalk-Î;¸%=>(D-Ï;À%=>0D-Ð;È%=>D-Ñ;Ð%=>D-Ò;Ø%=>D-Ó;à%=>D-Ô;è%=>D-Õ;ð%=>D-Ö;ø%=>D-×;°%=>#D~>)outprocÜÛ)>A~>*once$48pâ*>Câ*>&âAOâh<-ã;!> more tha-ã; !> n one oupã>!DpãS~=+sysfatalã+=Wük,outcpæ,> pæ S~=-recvpæ-=~=.usbfsdebugpæ.= pæ Wæl tprocou-ë;0!> tproc: t-ë;8!> ag %d flpëApëSpë>.!DpëS~?/rpcpë üÿÿÿ/?wëQpëS~=0fprintë0=pëüÿÿÿ/? pì S~>1freerpcì1>Wíi<&ï AOï—<-ï;@!> ushed -pïApïSpï>G!DpïSpï pï üÿÿÿ/? ïApïSï0=pïüÿÿÿ/? pð  pð üÿÿÿ/? ðA pð S~>buf$48pð>D pð Spð€ A pð SL{ƒŠz=convS2Mð=pð &ñ€ A~?nwpñøÿÿÿ?Xñ¬<-ò;H!> > %F %s-ò;P!> : outpro-ò;X!> c: buffe-ò;`!> r is too-ò;h!> small pòApòSpò>N!DpòS~=argv0pò=pòSò0=pòøÿÿÿ? &ó AQó¶<-ô;p!> %s: conS-ô;x!> 2M failepôApôSpô>p!DpôSpô=pôSô0=WôÅ<~>fsfdpõ> põ Spõ>D põ Spõ SL d %s: o-ö;ˆ!> utproc: -ö;!> write: %pöApöSpö>ƒ!DpöSpö=pöSö0=&ù.=ASùÈ<~>dumpú>pûüÿÿÿ/?pûSû1>Wûi<&ý AOýÕ<-ý;˜!> r%s: ou-ý; !> tproc: e-ý;¨!> xiting pýApýSpý>š!DpýSpý=pýSý0=£ý~>usbfsÜ> A~> once$53p >C >&AOÞ<-;°!> more tha-;¸!> n one us-;À!> bfs procp>°!DpS+=p A p  Sp A p  S~= chancreate  =p ,>p A p  Sp AS  =~> proccp  >p A p  Sp AS  =~> endcp  >& ,>AO ò<&  >AX ó chancre-;Ð!> ate: %rp>É!DpS+=~> schedprocp> DpSpASp@ApSLS]Å)=threadcreate=p>)DpSpASp@ApS~=proccreate=W8newrpc>p W p Sp  p üÿÿÿ/? ,A p Sp€ A p SLù z=read9pmsg=püÿÿÿ/? W <&AP;<&.=AO%<-;Ø!> %s: usbf-;à!> s: read:pApSp>Ø!DpSp=pS0=p >pTO&AO/pSp >pTOW3p0OpSLM½D=closedev=püÿÿÿ/?q­ÞAOp,>pSpüÿÿÿ/?pS~=sendp=W '%r'%s-!;ð!> : convM2-!;ø!> S failedp!Ap!Sp!>î!Dp!Sp!=p!S!0=p!üÿÿÿ/? p" S"1>W#<&% AO%[<-%;!> <- %F p%Ap%Sp%>!Dp%Sp% S%0=p%üÿÿÿ/? w&Q q& Qs'Q C' o' Qp(Q p( Qs)Q&)%=AX)p~?.safep*ðÿÿÿ?p*,>p*Sp*ðÿÿÿ?p*S*=W+getfid/>p/üÿÿÿ/? p/ QW/„p1üÿÿÿ/? p1 Qp2 Q&2AX2’p3ðÿÿÿ?p3,>p3Sp3ðÿÿÿ?p3S3=W4p7Sp7ðÿÿÿ?p7S7=W7<&9.=AO9¦<-9;!> %s: ubf-9;!> s: eof: -9;!> exiting p9Ap9Sp9> !Dp9Sp9=p9S90=£9L?þÔŒ=usbfsinitÜ==TA~@fpD@pD >~?fdaEøÿÿÿ? pE SLˆ3Ù=pipeE=&EAPE²<-F; !> pipe: %pF>!!DpFSF+=~=getuserG=~>userpG>pHAS~=timeH=~> epochpH >pJDApJSL®¹e¸=!dirfmtpJ=!DpJSL‚ÄØÍ="fmtinstallJ"=pKMApKSL®¹e¸=#dirmodefmtpK=#DpKSK"=pLFApLSL®¹e¸=$fcallfmtpL=$DpLSL"=pMüÿÿÿ?pM>pN>DpNSpNASpN@ApNSpNApN SLØ”i¡=%procrforkN%=~@&srvpN&@ &O AOO <~>'.string-P;('> r#s/%s~?(sfileaPÈÿÿÿ(?pPSpP(ApPSpP>*'DpPSpP  SLD$s5=)snprintP)=aQÈÿÿÿ(?pQSLz“€8=*removeQ*=aRÈÿÿÿ(? pR SpRA pR SpR°A pR SLö³k‡=+createR+=&SA~?,sfdpSôÿÿÿ,?PSë<-T;0'> post: %rpT>0'DpTS~=-sysfatalT-=aUÈÿÿÿ(?pUSpU(ApUSpU>9'DpUSpUøÿÿÿ?pU SU)=aVÈÿÿÿ(? pV SLÍ V=.strlenV.=pVÀÿÿÿ?aVÈÿÿÿ(? pV SV.=pV¼ÿÿÿ?pVôÿÿÿ,? pV SaVÈÿÿÿ(? pV SpV¼ÿÿÿ? pV SV=&VÀÿÿÿ?OV<-W;8'> %dpostpW><'DpWSW-=pXôÿÿÿ,?pXSLÃ)»=/closeX/=~@0mnt&Z0@AOZ,E'D p\ SL_EÍ3=fauth\=&]AU]<-^;@'> : %rau-^;H'> thentica-^;P'> tion req-^;X'> uired??p^>F'Dp^S^-=p_ôÿÿÿ,? p_ Sp_ÿÿÿÿA p_ Sp_0@ p_ S~@flagp_ @ p_  Sp_>`'D p_ SLó»Õz=mount_=&_AP_,<-`;`'> mount: p`>a'Dp`S`-=pbøÿÿÿ?pbSb/=£b-b;h'> %r~=Ebadctl5b=A~>fids5b>A5b >A~=Eio5b= A~=Enotfound5b=A~=Einuse5b=A~> fsfd5b >A~> once$535b >A~> once$485b >A~> procc5b >A5b >A~> freerpcs5b >A~>outc5b>A~>rpcs5b>A~>msgsize5b>A~=Eisopen5b=A~=Etoosmall5b=A~>already$275b>A5b>A~>fsops5b>A5b'>pA~=fscalls5b=üA~>buf$485b>€ A~=Eperm5b=A~=usbfsdebug5b=A~>rpclck5b>A~=Ebadcall5b=A~>freefids5b>A~=Ebadfid5b=AIbúfsdir.8 1287176513 0 0 664 15166 ` ~Eexitonclose-Ø;>ALWé½=usbfsexitsÜÛ=A~@ypÝ@pÝ>£Ý~>qiddevÜá>A~@pathpã@pãA ãÿA£ã£ã~>qidfileÜç>Apé@ éÿÿÿÿApéA £é£é~>mkqidÜí>A~@qfpï@ pï ¯ïA ~@ qdpï @ pï  ¯ïA pï  pïA ‡ï ‡ï  ~@ .retpï @pï Opï O£ï£ïL)¡L= usbfsdirdumpÜó =$ALb„9Ö= fslckp÷= Dp÷SL+l= qlock÷ =~>.string-ø;> %s: fs l-ø;> ist: (%d-ø;> used %d-ø;> total) pøApøSpø>DpøSLzaò=argv0pø=pøS~>fsusedpø>pø S~>nfspø>pøSLJ”§Š=fprintø=~>fspø> pùA Wù5Pù3 %s %s d-ü;(> ev %#p r-ü;0> efs %ld püApüSpü>!DpüSpü=püSpü  pü Qpü Spü  pü Qpü0OpüS~?ipü üÿÿÿ?pü  pü Qpü0OpüOpüSü=pü> püüÿÿÿ? Wüc<-ÿ;8> %s: %s pÿApÿSpÿ>9DpÿSpÿ=pÿSpÿ üÿÿÿ?pÿ  pÿ Qpÿ Sÿ=pÿ> pÿüÿÿÿ? Wÿ2 %s: fsapApSp>ADpSp=pS~@dfsp@p S=p = Dp S  =p >p > p A W ~ püÿÿÿ? p&Ap>XŸ<-;H> dd %s r-;P> ealloc: p>ODpSL·áP=sysfatal=p>p> püÿÿÿ? p  W¤aUp@ p OW¶C>p= DpS=£~>usbfsdelnthÜ >Ap =~@ip @ p > &" RAO"<&#AO#Õ<-#;X> %r%s: f-#;`> sdel %sp#Ap#Sp#>[Dp#Sp#=p#Sp# Rp# S#=p#=p#@ p#> p$ Rp$0O&$AO$ê<&%AO%é<-%;h> dev %#p-%;p> ref %ldp%Ap%Sp%>hDp%Sp% Rp%0Op%Sp% Rp%0Op%Op% S%=p%@ p%> W%ó<&(AO(ó<-(;x> no devp(Ap(Sp(>zDp(S(=p(@ p(> p) Rp)TO&)AO)þ p+ Rp+0Op+SLM½D=closedev+=p+@ p+> /,>p.A R&/>AX/ <&/>AX/  %s: al-0;ˆ> l file s-0;> ystems g-0;˜> one: exip0Ap0Sp0>‚Dp0Sp0=p0S0=p1ASL¼ì?;=threadexitsall1=£1Lv<&û= usbfsdelÜ6 =Ap:= Dp:S: =p:@ p;A W;P;<&< AO<( p< Q&< O<(p=@ p=üÿÿÿ!? &> AO>0"fsendÜE">A&G=AOG?<-G; > ting %s-G;¨> : fsend pGApGSpG>¦DpGSpG=pGSG=pHASH =£HL¼ì?;=#usbfsgoneÜL#=ApP= DpPSP =pP> pRA WRLPRJ pTüÿÿÿ!? &TAXTipU> pUüÿÿÿ!? WUI&fscloneÜZ&> A~?'xfsclonep`Aôÿÿÿ'?~?(devpaAøÿÿÿ(?~@)opb)@ pbQ pb SpbQ pb Sb>~?*qdpbüÿÿÿ*?pc= DpcSc =pc> pcüÿÿÿ*? &d AOd‚ pgüÿÿÿ*? ph  ph Qph<Ophôÿÿÿ'?pj= DpjSj=pjôÿÿÿ'? &k AOk¦ pl QplSpl)@plS~@,npl,@plSl &nøÿÿÿ(?AOn«-fswalkÜs->„A~@.fidp}.@ }A~?/qa}ðÿÿÿ/?p}A !}¡}y}p~ðÿÿÿ/? p~ Sp~ôÿÿÿ/? p~ S~>p~ìÿÿÿ*?pðÿÿÿ/? p Spôÿÿÿ/? p S>~?0qfpèÿÿÿ0?o€Aüÿÿÿ/?p‚Aøÿÿÿ/?~@1namepƒ1@ pƒ Spƒ>±D pƒ Sƒ%=pƒìÿÿÿ*? &ƒAXƒÝ<&„ AO„Ï<&„èÿÿÿ0?AO„Ïp†.@ †Aa†ðÿÿÿ/?p†A !†¡†y†p‡A£‡&‰ AO‰ &‹ RAX‹î p“ Rp“8O~?xfswalkp“œÿÿÿ?p”= Dp”S”=p•ìÿÿÿ*? p•> p• R p• Sp•.@ p• Sp•1@ p• Sp•œÿÿÿ?•p•Üÿÿÿ(? ~?rcp•àÿÿÿ?&– AO–  p›A W›P› pœäÿÿÿ!? &œAOœ*p> päÿÿÿ!? pž  pž QpžSažSažðÿÿÿ/?pžA !ž¡žyž~?daž ÿÿÿ?pžSpž  pž QpžPOžpŸ.@ ŸAaŸ¨ÿÿÿ?pŸA !Ÿ¡ŸyŸp = Dp S =p¡A£¡W¡fsopenÜ©>$Ap°.@ p°Q p° Sp°Q p° S~>qiddev°>&±Ap±üÿÿÿ*?X±b &´ RAX´q p¼ Rp¼DO~? xfsopenp¼ðÿÿÿ ?p½= Dp½S½=p½ðÿÿÿ ? &¾ AO¾Ž p¿ R p¿ Sp¿.@ p¿ S~@ modep¿ @ p¿ S¿ p¿øÿÿÿ?W¿ dirgenÜÈ >,ApÎ= DpÎSÎ =~@ dpÎ @pÎ>pÎ> pÎ,@ pÏA WϤ mkqidÒ >pÒ> pÒ @ pÓARpÔüÿÿÿ!? pÔ  pÔ QpÔ0O&ÕApÕøÿÿÿ(?OÕÄ pÖ @ p×,R~?nmp×ôÿÿÿ?pØüÿÿÿ!? pØ  pØ QpØSpØ  ØAaØSpØA !Ø¡ØyØpØ SpØüÿÿÿ!? pØ  pØ QpØPOØpØ @ pÙôÿÿÿ? pÙ ,QpÚ,QpÚSpÚüÿÿÿ!? pÚ> pÚ QpÚSpÚ(ApÚSL0[ë=strncpyÚ=pÚøÿÿÿ(? &Û AOÛèfsreadÜå>TApí.@ íAaíäÿÿÿ/?píA !í¡íyípîäÿÿÿ/? pî Spîèÿÿÿ/? pî Sî>&ïApïüÿÿÿ*?Xï D pð $SpðA(SLøHj=usbdirreadð=£ðpñ=DpñS~=qlockñ=pñüÿÿÿ*? ~>fspñ> &ò RAXò' pú RpúHO~?xfsreadpúàÿÿÿ?pû=DpûSû=püüÿÿÿ*? pü> pü R pü Spü.@ pü Spü@ pü Spü @ pü  Spü@ pü Spü@ pü Spüàÿÿÿ?üpüôÿÿÿ(? püøÿÿÿ?&ý AOýLfswriteÜ>0Ap .@ p Q p  Sp Q p  S >& Ap üÿÿÿ*?X \<~>.string- ;°> ..fswr- ;¸> ite: not- ;À> for usbp >´Dp S~=sysfatal =p =Dp S =p üÿÿÿ*? p > & RAXk p RpLO~?xfswritepðÿÿÿ?p=DpS=püÿÿÿ*? p> p R p Sp.@ p Sp@ p Sp @ p  Sp@ p Sp@ p Spðÿÿÿ?pôÿÿÿ(? pøÿÿÿ?& AOfsclunkÜ >Ap&Aøÿÿÿ(?p'.@ p'Q p' Sp'Q p' S'>p'üÿÿÿ*?p(=Dp(S(=p(> p(üÿÿÿ*? &) AO)¦ p,üÿÿÿ*? p-  p- Qp-@O~?xfsclunkp-ôÿÿÿ?W-· p2 Qp2Sp2.@p2S2 &4øÿÿÿ(?AO4É!fsstatÜ9!>0A~@"qidp@"@ p@ Sp@"@ p@ S@>p@ @ &AApAüÿÿÿ*?XAâ d /usbpC>ÌD pC ,QpDA$QpDA(QpEm€AQpFA£FpH=DpHSH=pHüÿÿÿ*? pH> &I RAXIñ pS R pS SaSSaS"@pSA !S¡SySpS @ pS SpSðÿÿÿ#?SpSôÿÿÿ(? pSøÿÿÿ?&T AOT-D-\;<$=>&D-];@$=>D-^;D$=>D-_;H$=>D-`;L$=>D-a;P$=>!D~>%fsend-b;T$=>%D5b$=XA~>&nfs5b&>A5b>A5b=A~>'exitonclose5b'>A5b>ÐA~>(fsused5b(>AIb>P;<&< AO<( p< Q&< O<(p=@ p=üÿÿÿ!? &> AO>0"fsendÜE">A&G=AOG?<-G; > ting %s-G;¨> : fsend pGApGSpG>¦DpGSpG=pGSG=pHASH =£HL¼ì?;=#usbfsgoneÜL#=ApPusb/lib/usb.h 664 0 0 17350 11321671244 11074ustar00syssystypedef struct Altc Altc; typedef struct Conf Conf; typedef struct DConf DConf; typedef struct DDesc DDesc; typedef struct DDev DDev; typedef struct DEp DEp; typedef struct DIface DIface; typedef struct Desc Desc; typedef struct Dev Dev; typedef struct Ep Ep; typedef struct Iface Iface; typedef struct Usbdev Usbdev; enum { /* fundamental constants */ Nep = 16, /* max. endpoints per usb device & per interface */ /* tunable parameters */ Nconf = 16, /* max. configurations per usb device */ Nddesc = 8*Nep, /* max. device-specific descriptors per usb device */ Niface = 16, /* max. interfaces per configuration */ Naltc = 16, /* max. alt configurations per interface */ Uctries = 4, /* no. of tries for usbcmd */ Ucdelay = 50, /* delay before retrying */ /* request type */ Rh2d = 0<<7, /* host to device */ Rd2h = 1<<7, /* device to host */ Rstd = 0<<5, /* types */ Rclass = 1<<5, Rvendor = 2<<5, Rdev = 0, /* recipients */ Riface = 1, Rep = 2, /* endpoint */ Rother = 3, /* standard requests */ Rgetstatus = 0, Rclearfeature = 1, Rsetfeature = 3, Rsetaddress = 5, Rgetdesc = 6, Rsetdesc = 7, Rgetconf = 8, Rsetconf = 9, Rgetiface = 10, Rsetiface = 11, Rsynchframe = 12, Rgetcur = 0x81, Rgetmin = 0x82, Rgetmax = 0x83, Rgetres = 0x84, Rsetcur = 0x01, Rsetmin = 0x02, Rsetmax = 0x03, Rsetres = 0x04, /* dev classes */ Clnone = 0, /* not in usb */ Claudio = 1, Clcomms = 2, Clhid = 3, Clprinter = 7, Clstorage = 8, Clhub = 9, Cldata = 10, /* standard descriptor sizes */ Ddevlen = 18, Dconflen = 9, Difacelen = 9, Deplen = 7, /* descriptor types */ Ddev = 1, Dconf = 2, Dstr = 3, Diface = 4, Dep = 5, Dreport = 0x22, Dfunction = 0x24, Dphysical = 0x23, /* feature selectors */ Fdevremotewakeup = 1, Fhalt = 0, /* device state */ Detached = 0, Attached, Enabled, Assigned, Configured, /* endpoint direction */ Ein = 0, Eout, Eboth, /* endpoint type */ Econtrol = 0, Eiso = 1, Ebulk = 2, Eintr = 3, /* endpoint isotype */ Eunknown = 0, Easync = 1, Eadapt = 2, Esync = 3, /* config attrib */ Cbuspowered = 1<<7, Cselfpowered = 1<<6, Cremotewakeup = 1<<5, /* report types */ Tmtype = 3<<2, Tmitem = 0xF0, Tmain = 0<<2, Tinput = 0x80, Toutput = 0x90, Tfeature = 0xB0, Tcoll = 0xA0, Tecoll = 0xC0, Tglobal = 1<<2, Tusagepage = 0x00, Tlmin = 0x10, Tlmax = 0x20, Tpmin = 0x30, Tpmax = 0x40, Tunitexp = 0x50, Tunit = 0x60, Trepsize = 0x70, TrepID = 0x80, Trepcount = 0x90, Tpush = 0xA0, Tpop = 0xB0, Tlocal = 2<<2, Tusage = 0x00, Tumin = 0x10, Tumax = 0x20, Tdindex = 0x30, Tdmin = 0x40, Tdmax = 0x50, Tsindex = 0x70, Tsmin = 0x80, Tsmax = 0x90, Tsetdelim = 0xA0, Treserved = 3<<2, Tlong = 0xFE, }; /* * Usb device (when used for ep0s) or endpoint. * RC: One ref because of existing, another one per ogoing I/O. * per-driver resources (including FS if any) are released by aux * once the last ref is gone. This may include other Devs using * to access endpoints for actual I/O. */ struct Dev { Ref; char* dir; /* path for the endpoint dir */ int id; /* usb id for device or ep. number */ int dfd; /* descriptor for the data file */ int cfd; /* descriptor for the control file */ int maxpkt; /* cached from usb description */ Ref nerrs; /* number of errors in requests */ Usbdev* usb; /* USB description */ void* aux; /* for the device driver */ void (*free)(void*); /* idem. to release aux */ }; /* * device description as reported by USB (unpacked). */ struct Usbdev { ulong csp; /* USB class/subclass/proto */ int vid; /* vendor id */ int did; /* product (device) id */ int dno; /* device release number */ char* vendor; char* product; char* serial; int vsid; int psid; int ssid; int class; /* from descriptor */ int nconf; /* from descriptor */ Conf* conf[Nconf]; /* configurations */ Ep* ep[Nep]; /* all endpoints in device */ Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */ }; struct Ep { uchar addr; /* endpt address, 0-15 (|0x80 if Ein) */ uchar dir; /* direction, Ein/Eout */ uchar type; /* Econtrol, Eiso, Ebulk, Eintr */ uchar isotype; /* Eunknown, Easync, Eadapt, Esync */ int id; int maxpkt; /* max. packet size */ int ntds; /* nb. of Tds per µframe */ Conf* conf; /* the endpoint belongs to */ Iface* iface; /* the endpoint belongs to */ }; struct Altc { int attrib; int interval; void* aux; /* for the driver program */ }; struct Iface { int id; /* interface number */ ulong csp; /* USB class/subclass/proto */ Altc* altc[Naltc]; Ep* ep[Nep]; void* aux; /* for the driver program */ }; struct Conf { int cval; /* value for set configuration */ int attrib; int milliamps; /* maximum power in this config. */ Iface* iface[Niface]; }; /* * Device-specific descriptors. * They show up mixed with other descriptors * within a configuration. * These are unknown to the library but handed to the driver. */ struct DDesc { uchar bLength; uchar bDescriptorType; uchar bbytes[1]; /* extra bytes allocated here to keep the rest of it */ }; struct Desc { Conf* conf; /* where this descriptor was read */ Iface* iface; /* last iface before desc in conf. */ Ep* ep; /* last endpt before desc in conf. */ Altc* altc; /* last alt.c. before desc in conf. */ DDesc data; /* unparsed standard USB descriptor */ }; /* * layout of standard descriptor types */ struct DDev { uchar bLength; uchar bDescriptorType; uchar bcdUSB[2]; uchar bDevClass; uchar bDevSubClass; uchar bDevProtocol; uchar bMaxPacketSize0; uchar idVendor[2]; uchar idProduct[2]; uchar bcdDev[2]; uchar iManufacturer; uchar iProduct; uchar iSerialNumber; uchar bNumConfigurations; }; struct DConf { uchar bLength; uchar bDescriptorType; uchar wTotalLength[2]; uchar bNumInterfaces; uchar bConfigurationValue; uchar iConfiguration; uchar bmAttributes; uchar MaxPower; }; struct DIface { uchar bLength; uchar bDescriptorType; uchar bInterfaceNumber; uchar bAlternateSetting; uchar bNumEndpoints; uchar bInterfaceClass; uchar bInterfaceSubClass; uchar bInterfaceProtocol; uchar iInterface; }; struct DEp { uchar bLength; uchar bDescriptorType; uchar bEndpointAddress; uchar bmAttributes; uchar wMaxPacketSize[2]; uchar bInterval; }; #define Class(csp) ((csp) & 0xff) #define Subclass(csp) (((csp)>>8) & 0xff) #define Proto(csp) (((csp)>>16) & 0xff) #define CSP(c, s, p) ((c) | (s)<<8 | (p)<<16) #define GET2(p) (((p)[1] & 0xFF)<<8 | ((p)[0] & 0xFF)) #define PUT2(p,v) {(p)[0] = (v); (p)[1] = (v)>>8;} #define GET4(p) (((p)[3]&0xFF)<<24 | ((p)[2]&0xFF)<<16 | \ ((p)[1]&0xFF)<<8 | ((p)[0]&0xFF)) #define PUT4(p,v) {(p)[0] = (v); (p)[1] = (v)>>8; \ (p)[2] = (v)>>16; (p)[3] = (v)>>24;} #define dprint if(usbdebug)fprint #define ddprint if(usbdebug > 1)fprint #pragma varargck type "U" Dev* #pragma varargck argpos devctl 2 int Ufmt(Fmt *f); char* classname(int c); void closedev(Dev *d); int configdev(Dev *d); int devctl(Dev *dev, char *fmt, ...); void* emallocz(ulong size, int zero); char* estrdup(char *s); int matchdevcsp(char *info, void *a); int finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs); char* hexstr(void *a, int n); int loaddevconf(Dev *d, int n); int loaddevdesc(Dev *d); char* loaddevstr(Dev *d, int sid); Dev* opendev(char *fn); int opendevdata(Dev *d, int mode); Dev* openep(Dev *d, int id); int parseconf(Usbdev *d, Conf *c, uchar *b, int n); int parsedesc(Usbdev *d, Conf *c, uchar *b, int n); int parsedev(Dev *xd, uchar *b, int n); void startdevs(char *args, char *argv[], int argc, int (*mf)(char*,void*), void*ma, int (*df)(Dev*,int,char**)); int unstall(Dev *dev, Dev *ep, int dir); int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count); extern int usbdebug; /* more messages for bigger values */  =£5~>!fsstatÜ9!>0A~@"qidp@"@ p@ Sp@"@ p@ S@>p@ @ &AApAüÿÿÿ*?XAâ d /usbpC>Ìusb/lib/usbdev.a8 664 0 0 1153670 11457541724 12725ustar00rminnichsys! __.SYMDEF 1287570388 0 0 644 814 ` D¢ÏuconsopsT¢ÏuconsmatchD¢ÏuconsinfoT4‰plmatchD4‰plopsD4‰plinfoTÖýserialmainTÖýserdumpstTÖýserialresetDÖýserialdebugDÖýpformatTÖýserialrecoverD‚ftinfoD‚ftopsT‚cpdataT‚ftmatchT$!kbmainTÐcdcresetTDÍasixresetTbparseaddrDbethersTbdumpframeDbetherdebugDbcinfoTbethermainT|scsierrmsgT,ŽSRopenrawT,ŽSRrcapacity16T,ŽSRwriteT,ŽSRmodeselect6T,ŽSRcloseT,ŽSRreadyT,ŽSRmodesense10T,ŽSRformatT,ŽSRreadT,ŽscsidebugT,ŽSRopenT,ŽSRmodeselect10T,ŽSRseekT,ŽSRinquiryT,ŽSRreqsenseT,ŽSRstartT,ŽSRrewindT,ŽSRfilemarkT,ŽSRmodesense6T,ŽSRspaceT,ŽSRrcapacityT,ŽSRrequestT,ŽSRrblimitsTrdiskmainDrforce6bytecmdsDrexabyteTrumsrequestTrfindendpointsDrmaxiosizedisk.8 1287564421 0 0 664 35453 ` ~E7 ~>dirtab~>.string-Q;>>D-Q;>m€A-R;>>D-R; >´A-S;> /ctlra-S;>>D-S;> A-T;>> D-T;> ALGò^=maxiosize-[;=A~>getmaxlunÜ`>,A~?maxoeAÿÿÿÿ?pf¡A ~@devpg@ pg Spg SpgþA pg SpgA SpgASagÿÿÿÿ? pg SpgA pg SLïûS|=usbcmdg=pg@ L½ÕQA=usbdebugpg= &gAPg<&h AOh<-h;> wdatad-h;> isk: %s:-h;> getmaxl-h; > un failephAphSph>DphSphQphSLJ”§Š= fprinth =Wh)< jAÿÿÿÿ?&k AOk)<-k;(> d: %r d-k;0> isk: %s:-k;8> maxlun pkApkSpk>/DpkSpkQpkSskÿÿÿÿ?pk Sk =smÿÿÿÿ?£m£m~> umsresetÜq >(Apu!A ~@ umspv @ pvP pv Spv SpvÿA pv SpvA SpvASpvASpvASv=&vAPvB<-w;@> %d disk-w;H> : reset:pwApwSpw>DDpwSw =pxÿÿÿÿA£xpzA£z£z~> umsrecoverÜ~ >Ap€ @ p€ S€ >p€ @ &€AP€Ní= unstall‚ =&‚AP‚]<&ƒ=AOƒ]<-ƒ;P> %r dis-ƒ;X> k: unsta-ƒ;`> ll epin:pƒApƒSpƒ>UDpƒSƒ =p† @ p†P p† Sp† @ p†P p† Sp†A p† S† =&†AP†o<&‡=AO‡o<-‡;h> %r dis-‡;p> k: unsta-‡;x> ll epoutp‡Ap‡Sp‡>mDp‡S‡ =pˆA£ˆ£ˆ~>umsfatalÜŒ>A-;€> : %r dep @pOpSp>†DpSL€$ö=devctl=p @ p‘A W‘umscapacityÜ–>0A~@lunp–@ pšA<QpšA@Qp›ADQp›AHQpœA Qp S~?dataaàÿÿÿ? p SLñçQ=SRrcapacity=p@&AP£umsinitܱ>$Ap· @p·S· >p¸ @ p¸P p¸ S¸>p¸ @ o¸ Qs¹ Q C¹ =¹¸A p¹ Sp¹A p¹ SL;ø„=mallocz¹=p¹ @ p¹P~?somepºAôÿÿÿ?o»A W»0 tachdis-Â;> k: lun %-Â;˜> d inquir-Â; > y failedpÂApÂSpÂ>DpÂSs pÂS =oÂÿÿÿÿ? WÃ- disk: -Ì;°> lun %d i-Ì;¸> s not a -Ì;À> disk (ty-Ì;È> pe %#02xpÌApÌSpÌ>ªDpÌSsÌ pÌSsÌ7QpÌ SÌ =oÌÿÿÿÿ? WÎ- ) %.48spÖ>ÓD pÖ SpÖøÿÿÿ? Ö?A pÖ SLò¬ˆ$=smprintÖ=pÖøÿÿÿ? pÖXQp× S×>o×ÿÿÿÿ? W×-<&Ùôÿÿÿ?AXÙ”<&Ú=AOÚŒ<-Ú;Ø> disk: a-Ú;à> ll luns -Ú;è> failed pÚApÚSpÚ>ÙDpÚSÚ =pÛ @pÛOpÛSpÛ>ðDpÛSÛ=pÜÿÿÿÿA£ÜpÞA£Þ£ÞLÀY†P=umsrequestÜæ=TA~@umscpí@pí\O~? umspíÄÿÿÿ ?-ï;ð> detachU~?!cbwaïàÿÿÿ!?pïSpï>÷DpïSpïApïSL4!Ù¾="memcpyï"=~@#datapï#@ ~@$cmdpï$@ pðÄÿÿÿ ? Cð$Ppð$Ppðäÿÿÿ!?pñRpñèÿÿÿ!?sòR %ò AOò¯ SBCdisk-õ;> : umsreq-õ;> uest: ba-õ;> d cmd co-õ;> unt: %ldpõ>üDpõSpõQpõSLuˆ‘=%printõ%=põ$@ p÷Qo÷îÿÿÿ!?pøQ&øAQøÇ cmd->c-ø;(> ount <= -ø;0> sizeof(c-ø;8> bw.commapø>"DpøSL¼ì?;=&_assertø&=pø$@ aùïÿÿÿ!?pùSpùQpùSpùQpùSù"=pù$@ púQ aú ïÿÿÿ!?púSpúASpúQpúA Öú pú SL£Xýù='memsetú'=pü>DDpüSL·áP=(werrstrü(=~>)diskdebug&þ)>AOþ<-ÿ;@> nd)dis-ÿ;H> k: cmd: -ÿ;P> tag %#lxpÿApÿSpÿ>EDpÿSpÿäÿÿÿ!?pÿSÿ =pA Wí : %2.2pApSp>[DpSaïÿÿÿ!? ~?*np Ìÿÿÿ*?r R ÿApS =pÌÿÿÿ*? Wê<-;`> x datal-;h> en: %ld pApSp>bDpSpèÿÿÿ!?pS =pÄÿÿÿ ? pP p P p Saàÿÿÿ!? p SpA p SL disk: c-;x> md: %r pApSp>qDpS =WAON<& Ap Ìÿÿÿ*?PG<-;€> disk: da-;ˆ> ta: %r pApSp>€DpS =pÌÿÿÿ*? WN<-;> disk: da-;˜> ta: %d bpApSp>DpSp S =pÌÿÿÿ*? & AQ\ ytes US&  Ap Ìÿÿÿ*?Xˆ¦D p SpA p SLÃa·=/strncmp/=pÌÿÿÿ*? &AXˆ BSdisk:- ;°> read n=- ;¸> %d: stat- ;À> us: %r p Ap Sp >«Dp Sp  S  =W!› disk: st-$;Ð> atus tag-$;Ø> mismatcp$Ap$Sp$>ÈDp$S$ =W%¦ h disk:-(;è> phase ep(Ap(Sp(>ãDp(S( =W)ï<&+Øÿÿÿ.?AO+®AO-à<-.;ð> rror di-.;ø> sk: stat-.;> us: %2.2-.;> ux resid-.;> ue: %ld p.Ap.Sp.>öDp.Ss.Üÿÿÿ.?p.Sp.Øÿÿÿ.?p. S. =r0ïÿÿÿ!?&0AX0à<-1;> sense dp1Ap1Sp1>Dp1S1 =p1#@ p2A W2Ë ata: %2p3Ap3Sp3>%Dp3Sp3Q p3 Ìÿÿÿ*?s3 Rp3S3 =p3#@ p3Ìÿÿÿ*? W3È,Dp4S4 =WAð .2x di-?;0> sk: phas-?;8> e error p?Ap?Sp?>.Dp?S? =W@ü disk: %-H;H> s: too m-H;P> any erro-H;X> rs: devi-H;`> ce detacpHApHSpH>ADpHSpHÄÿÿÿ ?pHOpHOpHSH =pIÄÿÿÿ ?pISI>WIpLÿÿÿÿA£L£L~>1dwalkÜP1>$A~@fidpU@ UA~?qidaUìÿÿÿ?pUA !U¡UyUsVøÿÿÿ? V€A&VAXV(<~>.string-W;h> hed wal-W;p> k in non-W;x> -directopW>mDpWSW(=pXÿÿÿÿA£X~@namep[@ p[ Sp[>ƒD p[ SL´§,=strcmp[=&[AX[1dirtabp_ > p_ S_=p_üÿÿÿ? &_AX_Y<~@fsp`@ `(A p`Pp`P p`  p`  ¯`A ‡` ‡`  p` ìÿÿÿ?p` ðÿÿÿ?paAôÿÿÿ?pb >¯bAobøÿÿÿ?pc@ cAacìÿÿÿ?pcA !c¡cycpdA£dWd3 dostatÜk > A~@ pathpk @~@ dpk @ ap>pp pq pqR¯qA pq  RprO¯rAorRpsT ps RptT pt ,Rpu@pu4O&vAXvz dirgenÜ} >A~@ ip} @ C &€ AU€…p„@ „(A p„Pp„P p„ @ ‡„Q‡„  Qp…A£…£…~>dstatÜŠ>ApŠ@ pŽ  Ž(A pŽQ pŽQ „Ž „Ž ~@qidpŽ@ Ž  pŽ@ Ž  p Sp Sp @pS >p@ (A pPpP p @ ‡Q‡  Qp‘A£‘£‘~>dopenÜ•> Ap•@pš š(A pšQ pšQ „š „š pš@ šA pšT pšT š  š  p›4U W Ãdreadܪ>pApª@p´ ´A~?qa´Äûÿÿ?p´A !´¡´y´pµ@ µ(A pµQ pµQ „µ „µ pµ  µA pµT pµT µ  µ  ~?pathpµ èÿÿÿ?p¶@p¶0Op¶ O p·@p·4Op·Øûÿÿ?p¸ Ôûÿÿ ?p¸ SL+l=qlock¸=p¸@ p¸Øûÿÿ?W q D p» $Sp»A(SLøHj=usbdirread»=p» @W¼ë<~?bufa¾èÿÿÿ?-¿;€> ry..%s-¿;ˆ> lun %lda¿èûÿÿ? p¿ S~?ep¿Üûÿÿ?p¿Sp¿>†D p¿ Sp¿0T p¿P p¿  S~?.safep¿¼ûÿÿ?p¿Ôûÿÿ ? p¿R p¿ Ö¿  p¿™/A=¿ p¿ Í¿A¯¿A ¿ p¿¼ûÿÿ?p¿ SL¦`o=seprint¿=~?lunp¿Øûÿÿ? p¿ pÀR ÀA&ÀAOÀ)<-Á;> : inquipÁ SpÁÜûÿÿ? pÁ SpÁ>“D pÁ SpÁXR pÁ  SÁ=pÁØûÿÿ? pÁ p  Â<A pÂPpÂP & ARÂ5 ry %s g-Ã; > eometry -Ã;¨> %llud %lpà SpÃÜûÿÿ? pà SpÃ>ŸD pà SpÃ<R pà  SpÃ@R pà Spà R pà SÃ=pà pÅ SpÅÜûÿÿ? pÅ SpÅ>²D pÅ SÅ=pÆ#@ pÆ SpÆ @ pÆ SpÆ@ pÆ SpÆ@ pÆ  SaÆèûÿÿ? pÆ SaÆèûÿÿ? pÆ ÖÆ  pÆ SLÏ¡Ç=usbreadbufÆ=pÆ @WÇëumscapacityÉ>pÉØûÿÿ?&ÉAUÉb d phas-Ð;¸> e errorpÐ>´DpÐSÐ(=pÑÿÿÿÿA£ÑpÓ#@ pÓ (UpÔ @ pÔ ,UoÕA0UpÖSpÖ ÖA pÖ SpÖ Ö(A pÖ SpÖ Ö4A pÖ  S~= umsrequestÖ =pÖØûÿÿ? o×AVQ&ØApØ @PØŒ %11.0ud aßèûÿÿ? pß SpßA pß Spß>ÀD pß Spß4U pß  SLD$s5="snprintß"=pà#@ pà Spà @ pà SpàASpàA Saàèûÿÿ? pà SpàSà=pà @páØûÿÿ?oáAVOWâhpæØûÿÿ?&æAUæ¶0dwriteÜ 0>HAp @ p 0Qp  Op 4Qp àÿÿÿ?  (A p Q p Q „  „  p @  A p T p T       p  ìÿÿÿ?~@1bufp 1@~?datap Üÿÿÿ?p äÿÿÿ!?p S =p  @ p àÿÿÿ? Ws .string- ;È> usb/dis- ;Ð> k: ctl i- ;Ø> gnored p Ap Sp >ÉDp S~=fprint =p!  @£! p#  Q&# AR# ¹p#  @ p# àÿÿÿ? &# AU# º bad comm-+ ;è> and lengp+ >àDp+ S+ =p, ÿÿÿÿA£, p.   . LAp. Sp. Üÿÿÿ?p. Sp.  S. /=p. àÿÿÿ? p/   / LA p/  Qp0  @ p0   Qo1 A$Qo2 AVQW3 À thphasepC >óDpC SC =pD ÿÿÿÿA£D sD VQ&D AOD Á<&D AOD Þ<&D AOD ùpH àÿÿÿ? &H AUH  errord-Š ;> isk: sub-Š ;> class %#-Š ;> ulx not -Š ;> supporte-Š ; > d. tryin-Š ;(> g anywaypŠ ApŠ SpŠ >ÿDpŠ SpŠ  SŠ =pŠ äÿÿÿ ?pŠ èÿÿÿ ?pŠ ìÿÿÿ? pŠ üÿÿÿ? s‹ P&‹ AX‹ j disk: -” ;8> ep ids: -” ;@> in %d oup” Ap” Sp” >2Dp” Sp” Sp”  S” =p” äÿÿÿ ?p” èÿÿÿ ?&• ÿÿÿÿAO• {<&• ÿÿÿÿAO• { t %d di-™ ;P> sk: open-™ ;X> ep %d: %p™ Ap™ Sp™ >NDp™ Sp™  S™ =pš ÿÿÿÿA£š &œ   Xœ š r disk:-¢ ;h> openep -¢ ;p> %d: %r p¢ Ap¢ Sp¢ >cDp¢ Sp¢ äÿÿÿ ?p¢ S¢ =p£  @p£ Op£ SLM½D=closedev£ =p¤ ÿÿÿÿA£¤ p¦ Qp¦ Q &¦  X¦ » disk: op-­ ;€> en i/o e-­ ;ˆ> p data: p­ Ap­ Sp­ >xDp­ S­ =p®  @p® Op® S® =p¯  @p¯ Op¯ S¯ =p° ÿÿÿÿA£° &² =AO² ì<-² ;> %r disk-² ;˜> : ep in -² ; > %s out %p² Ap² Sp² >”Dp² Sp² Pp² Op² Sp² Pp² Op²  S² =p²  @ -´ ;¨> s timeo-´ ;°> ut 2000p´ Pp´ Sp´ >«Dp´ S~=devctl´ =-µ ;¸> timeout pµ  @pµ Opµ Spµ >¸Dpµ Sµ =&· =AQ· ü<~>diskdebug&· >AQ· ü 2000debp¸  @p¸ Op¸ Sp¸ >ÅDp¸ S¸ =-¹ ;È> ug 1debp¹  @p¹ Op¹ Sp¹ >ÍDp¹ S¹ =-º ;Ð> ug 1debpº  @pº Opº Spº >ÕDpº Sº =p¼ A£¼ £¼ ~>usageÜÀ >A- ;Ø> ug 1usa- ;à> ge: usb/- ;è> disk [-d- ;ð> ] [-N nbp >ÝDp S =pà ÿÿÿÿA£Ã £Ã ~>umsdevfreeÜÇ >A~@apÉ @ &Ë  AXË <£Ì ~?umspÍ  üÿÿÿ?pÍ PpÍ SÍ =pÎ üÿÿÿ?pÎ OpÎ SÎ =pÎ üÿÿÿ? pÏ ARpÏ A pÏ  RpÐ RpÐ SÐ *=pÑ üÿÿÿ?pÑ SÑ *=£Ñ ~>diskfs~>dwalk-Õ ;8>>D~>dopen-Ö ;D>>D~>dread-× ;H>>D-Ø ;L>>0D~>dstat-Ù ;P>>DLé›pZ=diskmainÜÝ =8A~@ argvpÝ  @ ~@!devpã !@pã O~?"devidpã ðÿÿÿ"?Lzaò=#argv0&ä #=AXä <pæ SLWé½=(scsidebugæ (=pæ  @ pæ ìÿÿÿ&? Cç >Wè qúD pê  ìÿÿÿ&?rê Q %ê  AOê €L)¡L=)abortê )=pê A~?*.safepê Üÿÿÿ*?pê Üÿÿÿ*? pê  SLz“€8=+atoiê +=pê  @ pê ìÿÿÿ&? pê ðÿÿÿ"?Wë q<í >£í wí æÿÿÿ%?&í NAOí y<&í dAOí r£ð pó 0A pó  Spó A pó  S~=,emalloczó ,=pó !@ pó  Roô ÿA Opõ  Opö >D pö  $Rp÷ üÿÿÿ?p÷ S÷  =p÷ !@ p÷ üÿÿÿ? &÷ AP÷ ¸<-ø ;ø> ]disk:-ø ;> endpoin-ø ;> ts not fpø >ûDpø Sø =pù ÿÿÿÿA£ù pÿ Ppÿ O&ÿ AXÿ À-umsinit ->p üÿÿÿ? & AP Ð<& =AO Î<- ;> ounddis- ;> k: umsin- ; > it: %r p Ap Sp >Dp S =p ÿÿÿÿA£ p A W Õp A ! ¡ y - ;(> sdU%d.%dp  ~?.lunp  øÿÿÿ.? `Ap Sp (Ap Sp >(Dp Sp ðÿÿÿ"?p  Sp  ôÿÿÿ?p  S~=/snprint /=p !@ p øÿÿÿ.?p  Op  S =p øÿÿÿ.?p ”O  `Ap SLv<&û=0usbfsadd 0=p üÿÿÿ? p ôÿÿÿ? W Ò ~=1maxiosize5 1=A5 >AL½ÕQA=exabyte5 =A5 >XA~>dirtab5 > AL½ÕQA=force6bytecmds5 =A5 >8AI ñscsireq.8 1287564422 0 0 664 30484 ` ~Escmdnames~>.string-;>>D-;> TurRewi-;>>D-;> ndRsens-; >> D-;> eFormat-;>>D- ;> Rblimit- ;>>D-!; >>"D-"; > sReadW-";(>>'D-#;(> riteSee-#;,>>-D-$;0> kFmark-$;@>>2D-%;D>>8D-&;8> SpaceIn-&;H>>>D-';@> qMselec-';T>>BD-(;H> t6Msele-(;T>>KD-);P> ct10Mse-);h>>UD-*;X> nse6Mse-*;h>>]D-+;`> nse10St-+;l>>fD-,;h> artRcap-,;”>>lD--;p> acityRc--;x>>vD-.;x> ap16Ext-.; >>}D-/;€> readExt-/;¨>>…D-0;ˆ> writeEx-0;¬>>ŽD-2;> tseekSy-2;˜> nccache-2;Ô>>–D-3; >> D-4; > RTOCRdi-4;D>>¥D-5;¨> scinfoR-5;°> trackinf-5;H>>¯D-6;¸> oReserv-6;L>>ºD-7;À> eBlank-7;„>>ÂD-9;È> CDpause-9;,>>ÈD-:;8>>ÐD-;;Ð> CDstopC-;;”>>×D-<;Ø> DplayCD-<;˜>>ÞD-=;à> loadCDs-=;è>>åD->;è> canCDst->;ô>>ìD-?;ð> atusget-?;>>õDLõÛˆS=SRreadyÜC=A~?cmdaGúÿÿÿ?pGSpGASpGApGSL£Xýù=memsetG=~@rppG@ aHúÿÿÿ? pH QpIA QaJúÿÿÿ? pJ (QpKA,QoLA0QpM SLõÛˆS=SRrequestM=£M£MLõÛˆS=SRrewindÜQ=AaUúÿÿÿ?pUSpUASpUApUSU=pU@ oVAúÿÿÿ?aWúÿÿÿ? pW QpXA QaYúÿÿÿ? pY (QpZA,Qo[A0Qp\ S\=&\AU\+dirdevrwÜ£>Ap£@ ~@cmdp£@ p§ T ~?.safep§ ôÿÿÿ?~@nbytesp§@p§A 2§ôÿÿÿ?p§ p¨T&¨ÿÿAR¨<&¨ AS¨žseqdevrwܹ>Ap¹@ p¹@ p¾Q ¾@A &¾ AO¾ÎpÓ@ pÓ QWÓpÕ@ pÕ QaÖöÿÿÿ? pÖ Q~@bufp×@ p× (QpØ@ pØ ,QoÙA0QpÜ SÜ=pÜ@ pÜ &ÝÿÿÿÿA~?npÝðÿÿÿ?OÝ confrea-ä;> d error päApäSpä>ýDpäSLJ”§Š=fprintä=på@påA4Opæðÿÿÿ?£æpè4T&è€AXè,T ‡ë pë T pë èÿÿÿ?|ëèÿÿÿ?pë pìT ìA&ìAXìBdebug&ö>AXö_ SRread:-÷;> tape da-÷;> ta count-÷; > %ld%s -÷;(> with ILp÷Ap÷Sp÷> Dp÷Sp÷ ðÿÿÿ?p÷ Ss÷:T ÷ A &÷ AO÷k(DW÷l2Dp÷ S÷=p÷ðÿÿÿ? p÷@ pùA4Tpú T pú èÿÿÿ?pú púA 2úèÿÿÿ? úTpû £û£ûLÒ~öÇ=SRwriteÜÿ=$Apÿ@ pÿ@ p R p èÿÿÿ?p pA 2èÿÿÿ?& AX‡<& =Q‡p @ p  QW žp@ p Qaöÿÿÿ? p Qp@ p (Qp@ p ,QoA0Qp S=p@p@ ppðÿÿÿ?&ÿÿÿÿAXÙ<&=AO¸<-;0> Iwrite-;8> error pApSp>3DpS=p@pA4Opðÿÿÿ?£p4T&€AX¿T ‡ p T p èÿÿÿ?|èÿÿÿ?Öp Ö p ,TWØ ÿÿAQ>Q >A&>AO>O [<-;@> scsidebupApSp>@DpS=£~>0requestÜ0>4A~@1cmdp1@ ~@statusp @pAO~@fdp@ p SpQ p SpQ p SL.string-;H> g on sc-;P> sireq: w-;X> rite cmdpApSp>NDpS=p @pƒAOpÿÿÿÿA£p">fDp"SL·áP=werrstr"=p"@ p"+@ s#Q%#AO#…AO-Â<-.;`> : %r r-.;h> equest: -.;p> tried to-.;x> %s %ld -.;€> bytes of-.;ˆ> data fo-.;> r cmd 0x-.;˜> %x but g-.; > ot %r w-.;¨> ritereap.Ap.Sp.>gDp.Ss.R %. AO.¹§DW.º­Dp.Sp.Rp. Sp.1@p.Os.Op.S.=W.ÝAO2Í dreques-3;¸> t: %s %l-3;À> d of %ld-3;È> bytes o-3;Ð> f actual-3;Ø> data w-3;à> rotereap3Ap3Sp3>²Dp3Ss3R %3 AO3×ßDW3ØåDp3Sp3  Sp3Rp3S3=~?bufo7Aèÿÿÿ?p8@ p8 Sa8èÿÿÿ? p8 Sp8A p8 S8=p8= p8 &9 AO9ì<&9 AQ9ì dscsire-:;ð> q: read -:;ø> status: p:Ap:Sp:>êDp:S:=p; @p;ƒAOp<ÿÿÿÿA£<&> AU>þ %r scsi-B;> req: sta-B;> tus 0x%2-B;> .2uX: da-B; > ta trans-B;(> fer: %r pBApBSpB>DpBSpBQpBSB=pDüÿÿÿ?£D£D~> seprintcmdÜH >A~@ spH @ ~@ epH @ ~@ count&L @APL!<-M;0> 1D pM SL¦`o=seprintM=£MpN1@ rNR ~>scmdnames&O >AOO1<-P;8> cmd>%spP SpP SpP>=D pP S~?cpP üÿÿÿ?pP > pP  SP=pP @ pP1@ pP WP;<-R;@> cmd:%#02pR SpR SpR>@D pR SpR üÿÿÿ?pR  SR=pR @ pR1@ pR ~@args&S@AOSj uX sz %pY SpY SpY>KD pY SrYR pY  SY=pY WZ><-\;P> d code p\ Sp\ Sp\>RD p\ Sr\R p\  S\=p\ W]><-_;X> %d codep_ Sp_ Sp_>[D p_ Sr_R p_  S_=p_ W`><&`AO`?<&`AO`QseprintdataÜg>Apg @ &k @AXks %d %02pn S~@sepn@ pn Spn>dD pn S~@ppn@ pn  pn üÿÿÿ-?sn R pn  Sn=pnüÿÿÿ-? pn WnuSRdumpReqÜs>¤Aay?-z;h> xlun %daz€ÿÿÿ? pz S~?sepzxÿÿÿ?pzSpz>jD pz S~@rppz@ pzP pz  Sz=pz@ p{Sp{xÿÿÿ? p{ Sp{R p{ Sp{ R p{  Sp{A p{ S{ >-|;p> [%ld]p|Sp|xÿÿÿ? p| Sp|>rD p| Sp|@ p|,P p|  S|=p|@ p| s}$Q%}AO}»-;x> scsi⇒pApSp>yDpSa€ÿÿÿ?pS=£~>SRdumpRep܃>¤Aa‰?-Š;€> %s lunaŠ€ÿÿÿ? pŠ SpŠxÿÿÿ?pŠSpŠ>…D pŠ SpŠ@ pŠP pŠ  SŠ=pŠ@ p‹Sp‹xÿÿÿ? p‹ Sp‹R p‹ Sp‹ R p‹  Sp‹AS‹ >p‹@ p‹xÿÿÿ? p‹ WµJ %d go-Ž;> od [%ld]pŽ SpŽ SpŽ>D pŽ SpŽ,T pŽ  SŽ=pŽ@ pŽ s$R&AXóp W‘Ý<-“;˜> buffe-“; > r alloca-“;¨> tion faip“ Sp“ Sp“>šD p“ S“=p“ W”Ý<-–;°> led con-–;¸> troller p– Sp– Sp–>´D p– S–=p– W—Ý<-™;À> error b-™;È> us timeop™ Sp™ Sp™>ÆD p™ S™=p™ WšÝ<-œ;Ð> ut chec-œ;Ø> k conditpœ Spœ Spœ>ÓD pœ Sœ=pœ WÝ<-Ÿ;à> ion con-Ÿ;è> dition m-Ÿ;ð> et/goodpŸ SpŸ SpŸ>äD pŸ SŸ=pŸ W ÝøD p¢ S¢=p¢ W£Ý<-¥;ø> busy i-¥;> ntermedi-¥;> ate/goodp¥ Sp¥ Sp¥>þD p¥ S¥=p¥ W¦Ý<-¨;> interm-¨;> ediate/c-¨; > ondition-¨;(> met/goop¨ Sp¨ Sp¨>D p¨ S¨=p¨ W©Ý<-«;0> d reser-«;8> vation c-«;@> onflictp« Sp« Sp«>2D p« S«=p« W¬Ý<-®;H> command-®;P> terminap® Sp® Sp®>HD p® S®=p® W¯Ý<-±;X> ted que-±;`> ue fullp± Sp± Sp±>\D p± S±=p± W²Ý<-´;h> sts=%#xp´ Sp´ Sp´>hD p´ Sp´4T p´  S´=p´ W´Ý scsiâ†p·Ap·Sp·>qDp·Sa·€ÿÿÿ?p·S·=£·~>scsierrÜ»>Ap»@ W͇}D£ÁsÃDQ¬ÃAsÃEQ ‡Ã pÄSL’´q¼=scsierrmsgÄ=£Ä-Æ;x> %s so-Æ;€> ftware epÆ>~D£Æ-È;ˆ> rrorbad-È;> argumenpÈ>D£È-Ê;˜> tdevice-Ê; > is readpÊ>šD£Ê-Ì;¨> onlyunpÌ>®D£ÌpÌ4Q&̃AQÌSRdumpErrÜÑ>¤ApÑ@ aÖ?pÖ a×€ÿÿÿ?p×Sp× Sp×Qp×Sp× Qp× Sp×AS× >-Ø;°> known %-Ø;¸> s statuspØ@ pØ SØ>~?.safepØtÿÿÿ?pØ>¶DpØSaØ€ÿÿÿ?pØSpØtÿÿÿ?pØSLuˆ‘=printØ=£Ø~=SRrequestÜÜ= ApÜ@ Wá²<~>debug&â>AOâ·pã@ päQ äA&äAOäÊpç@ pç pçüÿÿÿ"?pèøÿÿÿ ? pè 4Q&éøÿÿÿ ?AXéÝAOëãpìüÿÿÿ"? pì@ WÿAXóö<~=$exabyte&ó$=AXóöpô@ -õ;À> : %s %spõ Sõ>põðÿÿÿ?põ>ÆDpõSpõðÿÿÿ?põSõ=pöÿÿÿÿA£öpøèApøSLo Öò=%sleepø%=pø@ Wù±<&û>AXû <&û$=AXû pü@ pý Sý>pýðÿÿÿ?pý>ÉDpýSpýðÿÿÿ?pýSý=pþÿÿÿÿA£þpþøÿÿÿ ?&þAOþå<&þAOþæ<&þAOþ(dirdevopenÜ(>Ap@ p SpA p S)=&ÿÿÿÿAOG+seqdevopenÜ&+>,Ap*@ p* S~?,limitsa*êÿÿÿ,? p* S~=-SRrblimits*-=p*@ &*ÿÿÿÿAX*¤1wormdevopenÜX1>Ap]@ p] Sp]A p] S~=SRstart]=&]ÿÿÿÿAO].string-w;È> %s%s/r~?nameaw€ÿÿÿ?pwSpw>ÌDpwSpw SLµó¡=sprintw=ay€ÿÿÿ? py SpyA py SLO׿®= openy =py@ pyQ&yÿÿÿÿAXy: awunkno-‹;Ø> wn devic-‹;à> e type 0p‹Ap‹Sp‹>ÓDp‹Ss‹7Qp‹S~= fprint‹ =p‹@ pŒƒA4QWRp’@ &’ÿÿÿÿAX’cp˜@ &˜ÿÿÿÿAX˜lp¢@ &¢ÿÿÿÿAX¢x x%.2x 5¬>A5¬>ðA5¬>AI¬scsierrs.8 1287564422 0 0 664 64938 ` ~E.string-;> no addit-;> ional se-;> nse info-;> rmation~>scsierrs-;>>D-;>A-; > filemark-;(> detecte-; >> D-;>A-;0> dend-of-;8> -partiti-;@> on/mediu-;H> m detect-;>>2D-;>A-;P> edsetma-;X> rk detec-;>>SD- ; >A- ;`> tedbegi- ;h> nning-of- ;p> -partiti- ;x> on/mediu- ;€> m detect- ;$>>dD-";(>A-";ˆ> edend-o-";> f-data d-";˜> etected-";,>>‹D-$;0>A-$; > i/o proc-$;¨> ess term-$;4>> D-&;8>A-&;°> inatedp-&;¸> rogramma-&;À> ble earl-&;È> y warnin-&;Ð> g detect-&;<>>·D-(;@>A-(;Ø> edaudio-(;à> play op-(;è> eration -(;ð> in progr-(;D>>ÛD-*;H>A-*;ø> essaudi-*;> o play o-*;> peration-*;> paused-*;L>>üD-,;P>A-,;> audio pl-,; > ay opera-,;(> tion suc-,;0> cessfull-,;8> y comple-,;T>>D-.;X>A-.;@> tedaudi-.;H> o play o-.;P> peration-.;X> stopped-.;`> due to -.;\>>DD-0;`>A-0;h> errorno-0;p> current-0;x> audio s-0;€> tatus to-0;ˆ> return-0;d>>nD-2;h>A-2;> operatio-2;˜> n in pro-2;l>>D-4;p>A-4; > gresscl-4;¨> eaning r-4;°> equested-4;t>>¦D-6;x>A-6;¸> erase o-6;À> peration-6;È> in prog-6;|>>¹D-8;€>A-8;Ð> ressloc-8;Ø> ate oper-8;à> ation in-8;è> progres-8;„>>ÕD-:;ˆ>A-:;ð> srewind-:;ø> operati-:;> on in pr-:;Œ>>òD-<;>A-<;> ogresss-<;> et capac-<;> ity oper-<; > ation in-<;(> progres-<;”>>D->;˜>A->;0> sverify->;8> operati->;@> on in pr->;œ>>2D-@; >A-@;H> ogressn-@;P> o index/-@;X> sector s-@;¤>>OD-B;¨>A-B;`> ignalno-B;h> seek co-B;¬>>fD-D;°>A-D;p> mpletep-D;x> eriphera-D;€> l device-D;ˆ> write f-D;´>>wD-F;¸>A-F;> aultno -F;˜> write cu-F;¼>>•D-H;À>A-H; > rrentex-H;¨> cessive -H;°> write er-H;Ä>>¦D-J;È>A-J;¸> rorslog-J;À> ical uni-J;È> t not re-J;Ð> ady, cau-J;Ø> se not r-J;à> eportabl-J;Ì>>½D-L;Ð>A-L;è> elogica-L;ð> l unit i-L;ø> s in pro-L;> cess of -L;> becoming-L;Ô>>êD-N;Ø>A-N;> readyl-N;> ogical u-N; > nit not -N;(> ready, i-N;0> nitializ-N;8> ing comm-N;@> and requ-N;Ü>>D-P;à>A-P;H> iredlog-P;P> ical uni-P;X> t not re-P;`> ady, man-P;h> ual inte-P;p> rvention-P;x> require-P;ä>>MD-R;è>A-R;€> dlogica-R;ˆ> l unit n-R;> ot ready-R;˜> , format-R; > in prog-R;ì>>‚D-T;ð>A-T;¨> resslog-T;°> ical uni-T;¸> t not re-T;À> ady, reb-T;È> uild in -T;Ð> progress-T;ô>>­D-V;ø>A-V;Ø> logical-V;à> unit no-V;è> t ready,-V;ð> recalcu-V;ø> lation i-V;> n progre-V;ü>>ÙD-X;>A-X;> sslogic-X;> al unit -X;> not read-X; > y, opera-X;(> tion in -X;0> progress-X;>> D-Z;>A-Z;8> logical-Z;@> unit no-Z;H> t ready,-Z;P> long wr-Z;X> ite in p-Z;`> rogress-Z; >>9D-\;> A-\;h> logical -\;p> unit not-\;x> ready, -\;€> self-tes-\;ˆ> t in pro-\;>>hD-^;> A-^;> gresslo-^;˜> gical un-^; > it not a-^;¨> ccessibl-^;°> e, asymm-^;¸> etric ac-^;À> cess sta-^;È> te trans-^;>>–D-`; > A-`;Ð> itionlo-`;Ø> gical un-`;à> it not a-`;è> ccessibl-`;ð> e, targe-`;ø> t port i-`;> n standb-`;> y state-`;$>>ÖD-b;(> A-b;> logical -b;> unit not-b; > accessi-b;(> ble, tar-b;0> get port-b;8> in unav-b;@> ailable -b;,>>D-d;0>A-d;H> statelo-d;P> gical un-d;X> it not r-d;`> eady, au-d;h> xiliary -d;p> memory n-d;x> ot acces-d;4>>ND-f;8>A-f;€> siblelo-f;ˆ> gical un-f;> it not r-f;˜> eady, no-f; > tify (en-f;¨> able spi-f;°> nup) req-f;<>>†D-h;@>A-h;¸> uiredlo-h;À> gical un-h;È> it not r-h;Ð> eady, of-h;D>>¾D-j;H>A-j;Ø> flinelo-j;à> gical un-j;è> it not r-j;ð> eady, sa-j;ø> creatio-j;> n in pro-j;L>>ÞD-l;P>A-l;> gresslo-l;> gical un-l;> it not r-l; > eady, sp-l;(> ace allo-l;0> cation i-l;8> n progre-l;T>>D-n;X>A-n;@> sslogic-n;H> al unit -n;P> not read-n;X> y, robot-n;`> ics disa-n;\>>CD-p;`>A-p;h> bledlog-p;p> ical uni-p;x> t not re-p;€> ady, con-p;ˆ> figurati-p;> on requi-p;d>>mD-r;h>A-r;˜> redlogi-r; > cal unit-r;¨> not rea-r;°> dy, cali-r;¸> bration -r;À> required-r;l>>œD-t;p>A-t;È> logical-t;Ð> unit no-t;Ø> t ready,-t;à> a door -t;è> is open-t;t>>ÉD-v;x>A-v;ð> logical -v;ø> unit not-v;> ready, -v;> operatin-v;> g in seq-v;> uential -v;|>>ðD-x;€>A-x; > modelog-x;(> ical uni-x;0> t does n-x;8> ot respo-x;@> nd to se-x;H> lection-x;„>>%D-z;ˆ>A-z;P> no refer-z;X> ence pos-z;`> ition fo-z;Œ>>PD-|;>A-|;h> undmult-|;p> iple per-|;x> ipheral -|;€> devices -|;ˆ> selected-|;”>>lD-~;˜>A-~;> logical-~;˜> unit co-~; > mmunicat-~;¨> ion fail-~;œ>>‘D-€; >A-€;°> urelogi-€;¸> cal unit-€;À> communi-€;È> cation t-€;Ð> ime-out-€;¤>>´D-‚;¨>A-‚;Ø> logical -‚;à> unit com-‚;è> municati-‚;ð> on parit-‚;ø> y error-‚;¬>>ØD-„;°>A-„;> logical -„;> unit com-„;> municati-„;> on crc e-„; > rror (ul-„;(> tra-dma/-„;´>>D-†;¸>A-†;0> 32)unre-†;8> achable -†;@> copy tar-†;¼>>4D-ˆ;À> A-ˆ;H> gettrac-ˆ;P> k follow-ˆ;X> ing erro-ˆ;Ä>>LD-Š;È> A-Š;`> rtracki-Š;h> ng servo-Š;p> failure-Š;Ì>>bD-Œ;Ð> A-Œ;x> focus s-Œ;€> ervo fai-Œ;Ô>>yD-Ž;Ø> A-Ž;ˆ> lurespi-Ž;> ndle ser-Ž;˜> vo failu-Ž;Ü>>D-;à> A-; > rehead -;¨> select f-;ä>>£D-’;è> A-’;°> aulterr-’;¸> or log o-’;À> verflow-’;ì>>µD-”;ð> A-”;È> warning-”;ô>>ÈD-–;ø> A-–;Ð> warning -–;Ø> - specif-–;à> ied temp-–;è> erature -–;ð> exceeded-–;ü>>ÐD-˜;> A-˜;ø> warning-˜; > - enclo-˜; > sure deg-˜;>>ùD-š;> A-š; > radedwa-š; > rning - -š; > backgrou-š;( > nd self--š;0 > test fai-š; >> D-œ;> A-œ;8 > ledwarn-œ;@ > ing - ba-œ;H > ckground-œ;P > pre-sca-œ;X > n detect-œ;` > ed mediu-œ;h > m error-œ;>>< D-ž;> A-ž;p > warning -ž;x > - backgr-ž;€ > ound med-ž;ˆ > ium scan-ž; > detecte-ž;˜ > d medium-ž;>>p D- ; > A- ;  > errorw- ;¨ > arning -- ;° > non-vol- ;¸ > atile ca- ;À > che now - ;È > volatile- ;$>>§ D-¢;(> A-¢;Ð > warning-¢;Ø > - degra-¢;à > ded powe-¢;è > r to non-¢;ð > -volatil-¢;ø > e cache-¢;,>>Ñ D-¤;0> A-¤; > warning -¤; > - power -¤; > loss exp-¤;4>> D-¦;8> A-¦; > ectedwr-¦; > ite erro-¦;<>> D-¨;@> A-¨;( > rwrite -¨;0 > error - -¨;8 > recovere-¨;@ > d with a-¨;H > uto real-¨;P > location-¨;D>>* D-ª;H> A-ª;X > write e-ª;` > rror - a-ª;h > uto real-ª;p > location-ª;x > failed-ª;L>>Y D-¬;P> A-¬;€ > write er-¬;ˆ > ror - re-¬; > commend -¬;˜ > reassign-¬;T>>€ D-®;X> A-®;  > mentcom-®;¨ > pression-®;° > check m-®;¸ > iscompar-®;À > e error-®;\>>¥ D-°;`> A-°;È > data exp-°;Ð > ansion o-°;Ø > ccurred -°;à > during c-°;è > ompressi-°;d>>È D-²;h> A-²;ð > onblock-²;ø > not com-²; > pressibl-²;l>>ó D-´;p> A-´; > ewrite -´; > error - -´; > recovery-´; > needed-´;t>> D-¶;x> A-¶;( > write er-¶;0 > ror - re-¶;8 > covery f-¶;|>>( D-¸;€> A-¸;@ > ailedwr-¸;H > ite erro-¸;P > r - loss-¸;X > of stre-¸;„>>F D-º;ˆ> A-º;` > amingwr-º;h > ite erro-º;p > r - padd-º;x > ing bloc-º;€ > ks added-º;Œ>>f D-¼;> A-¼;ˆ > auxilia-¼; > ry memor-¼;˜ > y write -¼;”>>‰ D-¾;˜> A-¾;  > errorwr-¾;¨ > ite erro-¾;° > r - unex-¾;¸ > pected u-¾;À > nsolicit-¾;È > ed data-¾;œ>>¦ D-À; >A-À;Ð > id crc o-À;Ø > r ecc er-À;¤>>Ð D-Â;¨>A-Â;à > rorlogi-Â;è > cal bloc-Â;ð > k guard -Â;ø > check fa-Â;¬>>ä D-Ä;°>A-Ä; > iledlog-Ä; > ical blo-Ä; > ck appli-Ä; > cation t-Ä; > ag check-Ä;( > failed-Ä;´>> D-Æ;¸>A-Æ;0 > logical -Æ;8 > block re-Æ;@ > ference -Æ;H > tag chec-Æ;P > k failed-Æ;¼>>0 D-È;À>A-È;X > unrecov-È;` > ered rea-È;h > d error-È;Ä>>Y D-Ê;È>A-Ê;p > read ret-Ê;x > ries exh-Ê;Ì>>p D-Ì;Ð>A-Ì;€ > austede-Ì;ˆ > rror too-Ì; > long to-Ì;˜ > correct-Ì;Ô>>‡ D-Î;Ø>A-Î;  > multipl-Î;¨ > e read e-Î;Ü>>¡ D-Ð;à>A-Ð;° > rrorsun-Ð;¸ > recovere-Ð;À > d read e-Ð;È > rror - a-Ð;Ð > uto real-Ð;Ø > locate f-Ð;ä>>¶ D-Ò;è>A-Ò;à > ailedl--Ò;è > ec uncor-Ò;ð > rectable-Ò;ì>>æ D-Ô;ð>A-Ô;ø > errorc-Ô; > irc unre-Ô; > covered -Ô;ô>>ÿ D-Ö;ø>A-Ö; > errorda-Ö; > ta re-sy-Ö; > nchroniz-Ö;( > ation er-Ö;ü>> D-Ø;>A-Ø;0 > rorinco-Ø;8 > mplete b-Ø;@ > lock rea-Ø;>>4 D-Ú;> A-Ú;H > dno gap-Ú; >>J D-Ü;> A-Ü;P > foundm-Ü;X > iscorrec-Ü;` > ted erro-Ü;>>W D-Þ;> A-Þ;h > runreco-Þ;p > vered re-Þ;x > ad error-Þ;€ > - recom-Þ;ˆ > mend rea-Þ; > ssignmen-Þ;>>j D-à; > A-à;˜ > tunreco-à;  > vered re-à;¨ > ad error-à;° > - recom-à;¸ > mend rew-à;À > rite the-à;$>>š D-â;(>A-â;È > dataer-â;Ð > ror read-â;Ø > ing isrc-â;à > number-â;,>>Î D-ä;0>A-ä;è > read err-ä;ð > or - los-ä;ø > s of str-ä;4>>è D-æ;8>A-æ;> eaminga-æ;> uxiliary-æ;> memory -æ;> read err-æ;<>>D-è;@>A-è; > orread -è;(> error - -è;0> failed r-è;8> etransmi-è;@> ssion re-è;D>>#D-ê;H>A-ê;H> questre-ê;P> ad error-ê;X> - lba m-ê;`> arked ba-ê;h> d by app-ê;p> lication-ê;x> client-ê;L>>ND-ì;P>A-ì;€> address -ì;ˆ> mark not-ì;> found f-ì;˜> or id fi-ì;T>>€D-î;X>A-î; > eldaddr-î;¨> ess mark-î;°> not fou-î;¸> nd for d-î;À> ata fiel-î;\>>¤D-ð;`>A-ð;È> drecord-ð;Ð> ed entit-ð;Ø> y not fo-ð;d>>ÊD-ò;h>A-ò;à> undreco-ò;è> rd not f-ò;l>>äD-ô;p>A-ô;ð> oundfil-ô;ø> emark or-ô;> setmark-ô;> not fou-ô;t>>õD-ö;x>A-ö;> ndend-o-ö;> f-data n-ö; > ot found-ö;|>>D-ø;€>A-ø;(> block s-ø;0> equence -ø;„>>)D-ú;ˆ>A-ú;8> errorre-ú;@> cord not-ú;H> found --ú;P> recomme-ú;X> nd reass-ú;`> ignment-ú;Œ>>>D-ü;>A-ü;h> record n-ü;p> ot found-ü;x> - data -ü;€> auto-rea-ü;ˆ> llocated-ü;”>>hD-þ;˜>A-þ;> locate -þ;˜> operatio-þ; > n failur-þ;œ>>‘D-; >A-;¨> erandom-;°> positio-;¸> ning err-;¤>>ªD-;¨>A-;À> ormecha-;È> nical po-;Ð> sitionin-;Ø> g error-;¬>>ÃD-;°>A-;à> position-;è> ing erro-;ð> r detect-;ø> ed by re-;> ad of me-;´>>àD-;¸>A-;> diumdat-;> a synchr-;> onizatio-; > n mark e-;¼>> D-;À>A-;(> rrordat-;0> a sync e-;8> rror - d-;@> ata rewr-;Ä>>-D- ;È>A- ;H> ittenda- ;P> ta sync - ;X> error - - ;`> recommen- ;h> d rewrit- ;Ì>>ND- ;Ð>A- ;p> edata s- ;x> ync erro- ;€> r - data- ;ˆ> auto-re- ;> allocate- ;Ô>>rD-;Ø>A-;˜> ddata s-; > ync erro-;¨> r - reco-;°> mmend re-;¸> assignme-;Ü>>šD-;à>A-;À> ntrecov-;È> ered dat-;Ð> a with n-;Ø> o error -;à> correcti-;è> on appli-;ä>>ÃD-;è>A-;ð> edrecov-;ø> ered dat-;> a with r-;ì>>óD-;ð>A-;> etriesr-;> ecovered-;> data wi-; > th posit-;(> ive head-;0> offset-;ô>>D-;ø>A-;8> recovere-;@> d data w-;H> ith nega-;P> tive hea-;X> d offset-;ü>>8D-;>A-;`> recover-;h> ed data -;p> with ret-;x> ries and-;€> /or circ-;ˆ> applied-;>>aD-;>A-;> recover-;˜> ed data -; > using pr-;¨> evious s-;°> ector id-; >>‘D-;>A-;¸> recover-;À> ed data -;È> without -;Ð> ecc - da-;Ø> ta auto--;à> realloca-;>>¹D-;>A-;è> tedreco-;ð> vered da-;ø> ta witho-;> ut ecc --;> recomme-;> nd reass-;> ignment-;>>ìD- ; >A- ; > recovere- ;(> d data w- ;0> ithout e- ;8> cc - rec- ;@> ommend r- ;$>> D-";(> A-";H> ewriter-";P> ecovered-";X> data wi-";`> thout ec-";h> c - data-";p> rewritt-";,>>OD-$;0>A-$;x> enrecov-$;€> ered dat-$;ˆ> a with e-$;> rror cor-$;˜> rection -$; > applied-$;4>>{D-&;8>A-&;¨> recovere-&;°> d data w-&;¸> ith erro-&;À> r corr. -&;È> & retrie-&;Ð> s applie-&;<>>¨D-(;@>A-(;Ø> drecove-(;à> red data-(;è> - data -(;ð> auto-rea-(;ø> llocated-(;D>>ÚD-*;H>A-*;> recover-*;> ed data -*;> with cir-*;L>>D-,;P>A-,;> crecove-,; > red data-,;(> with l--,;T>>D-.;X>A-.;0> ecrecov-.;8> ered dat-.;@> a - reco-.;H> mmend re-.;P> assignme-.;\>>3D-0;`>A-0;X> ntrecov-0;`> ered dat-0;h> a - reco-0;p> mmend re-0;d>>[D-2;h>A-2;x> writere-2;€> covered -2;ˆ> data wit-2;> h ecc - -2;˜> data rew-2;l>>~D-4;p>A-4; > rittenr-4;¨> ecovered-4;°> data wi-4;¸> th linki-4;t>>§D-6;x>A-6;À> ngdefec-6;È> t list e-6;|>>ÃD-8;€>A-8;Ð> rrordef-8;Ø> ect list-8;à> not ava-8;„>>ÕD-:;ˆ>A-:;è> ilabled-:;ð> efect li-:;ø> st error-:;> in prim-:;> ary list-:;Œ>>ïD-<;>A-<;> defect -<;> list err-<; > or in gr-<;(> own list-<;”>>D->;˜>A->;0> paramet->;8> er list ->;@> length e->;œ>>1D-@; >A-@;H> rrorsyn-@;P> chronous-@;X> data tr-@;`> ansfer e-@;¤>>MD-B;¨>A-B;h> rrordef-B;p> ect list-B;x> not fou-B;¬>>mD-D;°>A-D;€> ndprima-D;ˆ> ry defec-D;> t list n-D;˜> ot found-D;´>>ƒD-F;¸>A-F; > grown d-F;¨> efect li-F;°> st not f-F;¼>>¡D-H;À> A-H;¸> oundinv-H;À> alid com-H;È> mand ope-H;Ð> ration c-H;Ä>>½D-J;È> A-J;Ø> odeacce-J;à> ss denie-J;è> d - init-J;ð> iator pe-J;ø> nding-en-J;Ì>>ÜD-L;Ð> A-L;> rolleda-L;> ccess de-L;> nied - n-L;> o access-L; > rights-L;Ô>>D-N;Ø> A-N;(> access d-N;0> enied - -N;8> invalid -N;@> mgmt id -N;Ü>>(D-P;à> A-P;H> keyille-P;P> gal comm-P;X> and whil-P;`> e in wri-P;h> te capab-P;p> le state-P;ä>>LD-R;è> A-R;x> obsolet-R;ì>>yD-T;ð> A-T;€> eillega-T;ˆ> l comman-T;> d while -T;˜> in expli-T; > cit addr-T;¨> ess mode-T;ô>>‚D-V;ø> A-V;°> illegal-V;¸> command-V;À> while i-V;È> n implic-V;Ð> it addre-V;Ø> ss mode-V;ü>>±D-X;> A-X;à> access d-X;è> enied - -X;ð> enrollme-X;ø> nt confl-X;>>àD-Z;> A-Z;> ictacce-Z;> ss denie-Z;> d - inva-Z;> lid lu i-Z; > dentifie-Z; >>D-\;> A-\;(> raccess-\;0> denied -\;8> - invali-\;@> d proxy -\;>>*D-^;> A-^;H> tokenac-^;P> cess den-^;X> ied - ac-^;`> l lun co-^;>>ND-`; >!A-`;h> nflictl-`;p> ogical b-`;x> lock add-`;€> ress out-`;ˆ> of rang-`;$>>oD-b;(>!A-b;> einvali-b;˜> d elemen-b; > t addres-b;,>>’D-d;0>!A-d;¨> sinvali-d;°> d addres-d;¸> s for wr-d;4>>ªD-f;8>!A-f;À> iteinva-f;È> lid writ-f;Ð> e crossi-f;Ø> ng layer-f;<>>ÄD-h;@>"A-h;à> jumpil-h;è> legal fu-h;ð> nction (-h;ø> use 20 0-h;> 0, 24 00-h;> , or 26 -h;D>>æD-j;H>$A-j;> 00)inva-j;> lid fiel-j; > d in cdb-j;L>>D-l;P>$A-l;(> cdb dec-l;0> ryption -l;T>>)D-n;X>$A-n;8> errorob-n;\>>>D-p;`>$A-p;@> soleteo-p;H> bsolete-p;d>>GD-r;h>$A-r;P> security-r;X> audit v-r;`> alue fro-r;l>>PD-t;p>$A-t;h> zensecu-t;p> rity wor-t;x> king key-t;€> frozen-t;t>>lD-v;x>$A-v;ˆ> nonce no-v;> t unique-v;|>>ˆD-x;€>$A-x;˜> nonce t-x; > imestamp-x;¨> out of -x;„>>™D-z;ˆ>$A-z;°> rangein-z;¸> valid xc-z;Œ>>¶D-|;>%A-|;À> dblogic-|;È> al unit -|;Ð> not supp-|;”>>ÃD-~;˜>&A-~;Ø> ortedin-~;à> valid fi-~;è> eld in p-~;ð> arameter-~;œ>>ÞD-€; >&A-€;ø> listpa-€;> rameter -€;> not supp-€;¤>>þD-‚;¨>&A-‚;> ortedpa-‚;> rameter -‚; > value in-‚;¬>>D-„;°>&A-„;(> validth-„;0> reshold -„;8> paramete-„;@> rs not s-„;H> upported-„;´>>.D-†;¸>&A-†;P> invalid-†;X> release-†;`> of pers-†;h> istent r-†;p> eservati-†;¼>>QD-ˆ;À>&A-ˆ;x> ondata -ˆ;€> decrypti-ˆ;ˆ> on error-ˆ;Ä>>{D-Š;È>&A-Š;> too man-Š;˜> y target-Š; > descrip-Š;Ì>>‘D-Œ;Ð>&A-Œ;¨> torsuns-Œ;°> upported-Œ;¸> target -Œ;À> descript-Œ;È> or type -Œ;Ô>>­D-Ž;Ø>&A-Ž;Ð> codetoo-Ž;Ø> many se-Ž;à> gment de-Ž;è> scriptor-Ž;Ü>>ÕD-;à> &A-;ð> sunsupp-;ø> orted se-;> gment de-;> scriptor-;> type co-;ä>>òD-’;è> &A-’;> deunexp-’; > ected in-’;(> exact se-’;ì>>D-”;ð> &A-”;0> gmentin-”;8> line dat-”;@> a length-”;H> exceede-”;ô>>6D-–;ø> &A-–;P> dinvali-–;X> d operat-–;`> ion for -–;h> copy sou-–;p> rce or d-–;x> estinati-–;ü>>RD-˜;>&A-˜;€> ondata -˜;ˆ> decrypti-˜;> on key f-˜;˜> ail limi-˜; > t reache-˜;>>ƒD-š;>&A-š;¨> dincomp-š;°> lete key-š;¸> -associa-š;À> ted data-š; >>ªD-œ;>&A-œ;È> setven-œ;Ð> dor spec-œ;Ø> ific key-œ;à> referen-œ;è> ce not f-œ;>>ÍD-ž;>'A-ž;ð> oundwri-ž;ø> te prote-ž;>>õD- ; >'A- ;> ctedhar- ;> dware wr- ;> ite prot- ;$>>D-¢;(>'A-¢;> ectedlo-¢; > gical un-¢;(> it softw-¢;0> are writ-¢;8> e protec-¢;,>>D-¤;0>'A-¤;@> tedasso-¤;H> ciated w-¤;P> rite pro-¤;4>>DD-¦;8>'A-¦;X> tectper-¦;`> sistent -¦;h> write pr-¦;<>>]D-¨;@>'A-¨;p> otectpe-¨;x> rmanent -¨;€> write pr-¨;D>>vD-ª;H>'A-ª;ˆ> otectco-ª;> nditiona-ª;˜> l write -ª; > protect-ª;L>>ŽD-¬;P>'A-¬;¨> space al-¬;°> location-¬;¸> failed -¬;À> write pr-¬;T>>¨D-®;X>(A-®;È> otectno-®;Ð> t ready -®;Ø> to ready-®;à> change,-®;è> medium -®;ð> may have-®;ø> changed-®;\>>ÎD-°;`>(A-°;> import -°;> or expor-°;> t elemen-°;> t access-°;d>>D-²;h>(A-²; > edforma-²;(> t-layer -²;0> may have-²;8> changed-²;l>>#D-´;p>(A-´;@> import/-´;H> export e-´;P> lement a-´;X> ccessed,-´;`> medium -´;h> changed-´;t>>AD-¶;x>)A-¶;p> power on-¶;x> , reset,-¶;€> or bus -¶;ˆ> device r-¶;> eset occ-¶;|>>pD-¸;€>)A-¸;˜> urredpo-¸; > wer on o-¸;¨> ccurred-¸;„>>žD-º;ˆ>)A-º;°> scsi bus-º;¸> reset o-º;À> ccurred-º;Œ>>°D-¼;>)A-¼;È> bus devi-¼;Ð> ce reset-¼;Ø> functio-¼;à> n occurr-¼;”>>ÈD-¾;˜>)A-¾;è> eddevic-¾;ð> e intern-¾;ø> al reset-¾;œ>>ëD-À; >)A-À;> transce-À;> iver mod-À;> e change-À;> d to sin-À; > gle-ende-À;¤>>D-Â;¨>)A-Â;(> dtransc-Â;0> eiver mo-Â;8> de chang-Â;@> ed to lv-Â;¬>>*D-Ä;°>)A-Ä;H> di_t ne-Ä;P> xus loss-Ä;X> occurre-Ä;´>>JD-Æ;¸>*A-Æ;`> dparame-Æ;h> ters cha-Æ;¼>>bD-È;À>*A-È;p> ngedmod-È;x> e parame-È;€> ters cha-È;Ä>>uD-Ê;È>*A-Ê;ˆ> ngedlog-Ê;> paramet-Ê;˜> ers chan-Ê;Ì>>D-Ì;Ð>*A-Ì; > gedrese-Ì;¨> rvations-Ì;°> preempt-Ì;Ô>>¤D-Î;Ø>*A-Î;¸> edreser-Î;À> vations -Î;È> released-Î;Ü>>»D-Ð;à>*A-Ð;Ð> registr-Ð;Ø> ations p-Ð;à> reempted-Ð;ä>>ÑD-Ò;è>*A-Ò;è> asymmet-Ò;ð> ric acce-Ò;ø> ss state-Ò;> changed-Ò;ì>>éD-Ô;ð>*A-Ô;> implici-Ô;> t asymme-Ô;> tric acc-Ô; > ess stat-Ô;(> e transi-Ô;0> tion fai-Ô;ô>> D-Ö;ø>*A-Ö;8> ledprio-Ö;@> rity cha-Ö;ü>><D-Ø;> *A-Ø;H> ngedcap-Ø;P> acity da-Ø;X> ta has c-Ø;>>MD-Ú;> *A-Ú;`> hangede-Ú;h> rror his-Ú;p> tory i_t-Ú;x> nexus c-Ú; >>gD-Ü;> *A-Ü;€> learede-Ü;ˆ> rror his-Ü;> tory sna-Ü;˜> pshot re-Ü;>>‡D-Þ;> *A-Þ; > leasede-Þ;¨> rror rec-Þ;°> overy at-Þ;¸> tributes-Þ;À> have ch-Þ;>>§D-à; >*A-à;È> angedti-à;Ð> mestamp -à;Ø> changed-à;$>>ÎD-â;(>*A-â;à> data enc-â;è> ryption -â;ð> paramete-â;ø> rs chang-â;> ed by an-â;> other i_-â;> t nexus-â;,>>àD-ä;0>*A-ä;> data enc-ä; > ryption -ä;(> paramete-ä;0> rs chang-ä;8> ed by ve-ä;@> ndor spe-ä;H> cific ev-ä;4>>D-æ;8>*A-æ;P> entdata-æ;X> encrypt-æ;`> ion key -æ;h> instance-æ;p> counter-æ;x> has cha-æ;<>>TD-è;@>*A-è;€> ngedsa -è;ˆ> creation-è;> capabil-è;˜> ities da-è; > ta has c-è;D>>…D-ê;H>+A-ê;¨> hangedc-ê;°> opy cann-ê;¸> ot execu-ê;À> te since-ê;È> host ca-ê;Ð> nnot dis-ê;Ø> connect-ê;L>>¯D-ì;P>,A-ì;à> command -ì;è> sequence-ì;T>>àD-î;X>,A-î;ð> errort-î;ø> oo many -î;> windows -î;> specifie-î;\>>÷D-ð;`>,A-ð;> dinvali-ð;> d combin-ð; > ation of-ð;(> windows-ð;0> specifi-ð;d>>D-ò;h>,A-ò;8> edcurre-ò;@> nt progr-ò;H> am area -ò;P> is not e-ò;l>>;D-ô;p>,A-ô;X> mptycur-ô;`> rent pro-ô;h> gram are-ô;p> a is emp-ô;t>>]D-ö;x>,A-ö;x> tyilleg-ö;€> al power-ö;ˆ> conditi-ö;> on reque-ö;|>>{D-ø;€>,A-ø;˜> stpersi-ø; > stent pr-ø;¨> event co-ø;„>>›D-ú;ˆ>,A-ú;°> nflictp-ú;¸> revious -ú;À> busy sta-ú;Œ>>·D-ü;>,A-ü;È> tusprev-ü;Ð> ious tas-ü;Ø> k set fu-ü;à> ll statu-ü;”>>ÌD-þ;˜> ,A-þ;è> sprevio-þ;ð> us reser-þ;ø> vation c-þ; > onflict -þ;œ>>êD-; > ,A-; > statusp-; > artition-; > or coll-; > ection c-;( > ontains -;0 > user obj-;¤>> D-;¨> ,A-;8 > ectsnot-;@ > reserve-;¬>>= D-;°>0A-;H > dincomp-;P > atible m-;X > edium in-;` > stalled-;´>>J D-;¸>0A-;h > cannot r-;p > ead medi-;x > um - unk-;€ > nown for-;¼>>h D-;À>0A-;ˆ > matcann-; > ot read -;˜ > medium --;  > incompa-;¨ > tible fo-;Ä>>Œ D- ;È>0A- ;° > rmatcle- ;¸ > aning ca- ;À > rtridge - ;È > installe- ;Ì>>µ D- ;Ð>0A- ;Ð > dcannot- ;Ø > write m- ;à > edium - - ;è > unknown - ;Ô>>Ò D-;Ø>0A-;ð > formatc-;ø > annot wr-;!> ite medi-;!> um - inc-;!> ompatibl-;!> e format-;Ü>>÷ D-;à>0A-; !> cannot -;(!> format m-;0!> edium - -;8!> incompat-;@!> ible med-;ä>>!!D-;è>0A-;H!> iumclea-;P!> ning fai-;ì>>L!D-;ð>0A-;X!> lurecan-;`!> not writ-;h!> e - appl-;p!> ication -;x!> code mis-;ô>>]!D-;ø> 0A-;€!> matchcu-;ˆ!> rrent se-;!> ssion no-;˜!> t fixate-; !> d for ap-;ü>>†!D-;> 0A-;¨!> pendcle-;°!> aning re-;¸!> quest re-;>>­!D-;> 0A-;À!> jectedw-;È!> orm medi-;Ð!> um - ove-;Ø!> rwrite a-;à!> ttempted-; >>Ç!D-;>0A-;è!> medium -;ð!> not form-;>>é!D-;>0A-;ø!> attedin-;"> compatib-;"> le volum-;>>þ!D- ; >0A- ;"> e typei- ;"> ncompati- ; "> ble volu- ;("> me quali- ;$>>"D-";(>0A-";0"> fiercle-";8"> aning vo-";@"> lume exp-";,>>5"D-$;0>1A-$;H"> iredmed-$;P"> ium form-$;X"> at corru-$;4>>M"D-&;8>1A-&;`"> ptedfor-&;h"> mat comm-&;p"> and fail-&;<>>e"D-(;@>1A-(;x"> edzoned-(;€"> formatt-(;ˆ"> ing fail-(;"> ed due t-(;˜"> o spare -(; "> linking-(;D>>{"D-*;H>2A-*;¨"> no defec-*;°"> t spare -*;¸"> location-*;À"> availab-*;L>>¨"D-,;P>2A-,;È"> ledefec-,;Ð"> t list u-,;Ø"> pdate fa-,;T>>Ë"D-.;X>3A-.;à"> ilureta-.;è"> pe lengt-.;ð"> h error-.;\>>æ"D-0;`>4A-0;ø"> enclosur-0;#> e failur-0;d>>ø"D-2;h>5A-2;#> eenclos-2;#> ure serv-2;#> ices fai-2;l>> #D-4;p>5A-4; #> lureuns-4;(#> upported-4;0#> enclosu-4;8#> re funct-4;t>>%#D-6;x>5A-6;@#> ionencl-6;H#> osure se-6;P#> rvices u-6;X#> navailab-6;|>>D#D-8;€>5A-8;`#> leenclo-8;h#> sure ser-8;p#> vices tr-8;x#> ansfer f-8;„>>c#D-:;ˆ>5A-:;€#> ailuree-:;ˆ#> nclosure-:;#> service-:;˜#> s transf-:; #> er refus-:;Œ>>‡#D-<;>5A-<;¨#> edenclo-<;°#> sure ser-<;¸#> vices ch-<;À#> ecksum e-<;”>>«#D->;˜>6A->;È#> rrorrib->;Ð#> bon, ink->;Ø#> , or ton->;à#> er failu->;œ>>Í#D-@; >7A-@;è#> reround-@;ð#> ed param-@;¤>>ë#D-B;¨>8A-B;ø#> etereve-B;$> nt statu-B;$> s notifi-B;¬>>ý#D-D;°>8A-D;$> catione-D;$> sn - pow-D; $> er manag-D;($> ement cl-D;0$> ass even-D;´>>$D-F;¸>8A-F;8$> tesn - -F;@$> media cl-F;H$> ass even-F;¼>>:$D-H;À>8A-H;P$> tesn - -H;X$> device b-H;`$> usy clas-H;h$> s event-H;Ä>>R$D-J;È>8A-J;p$> thin pro-J;x$> visionin-J;€$> g soft t-J;ˆ$> hreshold-J;$> reached-J;Ì>>p$D-L;Ð>9A-L;˜$> saving -L; $> paramete-L;¨$> rs not s-L;°$> upported-L;Ô>>™$D-N;Ø>:A-N;¸$> medium -N;À$> not pres-N;Ü>>¹$D-P;à>:A-P;È$> entmedi-P;Ð$> um not p-P;Ø$> resent --P;à$> tray cl-P;ä>>Ì$D-R;è>:A-R;è$> osedmed-R;ð$> ium not -R;ø$> present -R;%> - tray o-R;ì>>í$D-T;ð>:A-T;%> penmedi-T;%> um not p-T;%> resent --T; %> loadabl-T;ô>> %D-V;ø>:A-V;(%> emedium-V;0%> not pre-V;8%> sent - m-V;@%> edium au-V;H%> xiliary -V;P%> memory a-V;X%> ccessibl-V;ü>>*%D-X; >;A-X;`%> esequen-X;h%> tial pos-X;p%> itioning-X; >>b%D-Z; >;A-Z;x%> errort-Z;€%> ape posi-Z;ˆ%> tion err-Z;%> or at be-Z;˜%> ginning--Z; %> of-mediu-Z; >>%D-\; >;A-\;¨%> mtape p-\;°%> osition -\;¸%> error at-\;À%> end-of--\; >>ª%D-^; >;A-^;È%> mediumt-^;Ð%> ape or e-^;Ø%> lectroni-^;à%> c vertic-^;è%> al forms-^;ð%> unit no-^;ø%> t ready-^; >>Ï%D-`; >;A-`;&> slew fai-`;$ >>&D-b;( >;A-b;&> lurepap-b;, >> &D-d;0 >;A-d;&> er jamf-d;&> ailed to-d; &> sense t-d;(&> op-of-fo-d;4 >>&D-f;8 >;A-f;0&> rmfaile-f;8&> d to sen-f;@&> se botto-f;H&> m-of-for-f;< >>3&D-h;@ >;A-h;P&> mreposi-h;X&> tion err-h;D >>R&D-j;H > ;A-j;`&> orread -j;h&> past end-j;p&> of medi-j;L >>c&D-l;P > ;A-l;x&> umread -l;€&> past beg-l;ˆ&> inning o-l;&> f medium-l;T >>{&D-n;X > ;A-n;˜&> positio-n; &> n past e-n;¨&> nd of me-n;\ >>™&D-p;` > ;A-p;°&> diumpos-p;¸&> ition pa-p;À&> st begin-p;È&> ning of -p;d >>µ&D-r;h >;A-r;Ð&> mediumm-r;Ø&> edium ma-r;à&> gazine n-r;è&> ot acces-r;l >>×&D-t;p >;A-t;ð&> sibleme-t;ø&> dium mag-t;'> azine re-t;t >>ö&D-v;x >;A-v;'> movedme-v;'> dium mag-v;'> azine in-v;| >>'D-x;€ >;A-x; '> sertedm-x;('> edium ma-x;0'> gazine l-x;„ >>''D-z;ˆ >;A-z;8'> ockedme-z;@'> dium mag-z;H'> azine un-z;Œ >>>'D-|; >;A-|;P'> lockedm-|;X'> echanica-|;`'> l positi-|;h'> oning or-|;p'> changer-|;” >>W'D-~;˜ >;A-~;x'> errorr-~;€'> ead past-~;ˆ'> end of -~;'> user obj-~;œ >>'D-€;  >;A-€;˜'> ectelem-€; '> ent disa-€;¤ >>œ'D-‚;¨ >;A-‚;¨'> bledele-‚;°'> ment ena-‚;¬ >>­'D-„;° >;A-„;¸'> bleddat-„;À'> a transf-„;È'> er devic-„;Ð'> e remove-„;´ >>½'D-†;¸ >;A-†;Ø'> ddata t-†;à'> ransfer -†;è'> device i-†;ð'> nserted-†;¼ >>Ú'D-ˆ;À >@A-ˆ;ø'> ram fail-ˆ;(> ure (sho-ˆ;(> uld use -ˆ;Ä >>ø'D-Š;È >AA-Š;(> 40 nn)d-Š;(> ata path-Š; (> failure-Š;((> (should-Š;0(> use 40 -Š;Ì >>(D-Œ;Ð >BA-Œ;8(> nn)powe-Œ;@(> r-on or -Œ;H(> self-tes-Œ;P(> t failur-Œ;X(> e (shoul-Œ;`(> d use 40-Œ;Ô >><(D-Ž;Ø >CA-Ž;h(> nn)mes-Ž;p(> sage err-Ž;Ü >>m(D-;à >DA-;x(> orinter-;€(> nal targ-;ˆ(> et failu-;ä >>{(D-’;è >qDA-’;(> reata d-’;˜(> evice fa-’; (> iled set-’;¨(> feature-’;ì >>“(D-”;ð >EA-”;°(> sselect-”;¸(> or rese-”;À(> lect fai-”;ô >>²(D-–;ø >FA-–;È(> lureuns-–;Ð(> uccessfu-–;Ø(> l soft r-–;ü >>Í(D-˜; >GA-˜;à(> esetscs-˜;è(> i parity-˜; >>å(D-š; >GA-š;ð(> errord-š;ø(> ata phas-š;)> e crc er-š;)> ror dete-š; >>÷(D-œ; >GA-œ;)> ctedscs-œ;)> i parity-œ; )> error d-œ;()> etected -œ;0)> during s-œ;8)> t data p-œ; >>)D-ž; >GA-ž;@)> haseinf-ž;H)> ormation-ž;P)> unit iu-ž;X)> crc erro-ž;`)> r detect-ž; >>E)D- ; >GA- ;h)> edasync- ;p)> hronous - ;x)> informat- ;€)> ion prot- ;ˆ)> ection e- ;)> rror det- ;$ >>k)D-¢;( >GA-¢;˜)> ectedpr-¢; )> otocol s-¢;¨)> ervice c-¢;°)> rc error-¢;, >>ž)D-¤;0 >GA-¤;¸)> phy tes-¤;À)> t functi-¤;È)> on in pr-¤;4 >>¹)D-¦;8 >HA-¦;Ð)> ogressi-¦;Ø)> nitiator-¦;à)> detecte-¦;è)> d error -¦;ð)> message -¦;ø)> received-¦;< >>×)D-¨;@ >IA-¨;*> invalid-¨;*> message-¨;D >>*D-ª;H >JA-ª;*> errorc-ª;*> ommand p-ª; *> hase err-ª;L >>*D-¬;P >KA-¬;(*> ordata -¬;0*> phase er-¬;T >>+*D-®;X >KA-®;8*> rorinva-®;@*> lid targ-®;H*> et port -®;P*> transfer-®;X*> tag rec-®;\ >><*D-°;` >KA-°;`*> eivedto-°;h*> o much w-°;p*> rite dat-°;d >>f*D-²;h >KA-²;x*> aack/na-²;€*> k timeou-²;l >>z*D-´;p >KA-´;ˆ*> tnak re-´;t >>Š*D-¶;x >KA-¶;*> ceivedd-¶;˜*> ata offs-¶; *> et error-¶;| >>—*D-¸;€ >KA-¸;¨*> initiat-¸;°*> or respo-¸;¸*> nse time-¸;„ >>©*D-º;ˆ >KA-º;À*> outconn-º;È*> ection l-º;Œ >>Ä*D-¼; >LA-¼;Ð*> ostlogi-¼;Ø*> cal unit-¼;à*> failed -¼;è*> self-con-¼;ð*> figurati-¼;” >>Ô*D-¾;˜ >PA-¾;ø*> onwrite-¾;+> append -¾;œ >>û*D-À;  >PA-À;+> errorwr-À;+> ite appe-À;+> nd posit-À; +> ion erro-À;¤ >>+D-Â;¨ >PA-Â;(+> rpositi-Â;0+> on error-Â;8+> related-Â;@+> to timi-Â;¬ >>*+D-Ä;° >QA-Ä;H+> ngerase-Ä;P+> failure-Ä;´ >>K+D-Æ;¸ >QA-Æ;X+> erase f-Æ;`+> ailure --Æ;h+> incompl-Æ;p+> ete eras-Æ;x+> e operat-Æ;€+> ion dete-Æ;¼ >>Y+D-È;À >RA-È;ˆ+> ctedcar-È;+> tridge f-È;Ä >>+D-Ê;È >SA-Ê;˜+> aultmed-Ê; +> ia load -Ê;¨+> or eject-Ê;°+> failed-Ê;Ì >>+D-Ì;Ð >SA-Ì;¸+> unload t-Ì;À+> ape fail-Ì;Ô >>¸+D-Î;Ø >SA-Î;È+> uremedi-Î;Ð+> um remov-Î;Ø+> al preve-Î;Ü >>Ì+D-Ð;à >SA-Ð;à+> ntedmed-Ð;è+> ium remo-Ð;ð+> val prev-Ð;ø+> ented by-Ð;,> data tr-Ð;,> ansfer e-Ð;ä >>å+D-Ò;è >SA-Ò;,> lementm-Ò;,> edium th-Ò; ,> read or -Ò;(,> unthread-Ò;0,> failure-Ò;ì >>,D-Ô;ð >TA-Ô;8,> scsi to-Ô;@,> host sy-Ô;H,> stem int-Ô;P,> erface f-Ô;ô >>9,D-Ö;ø >UA-Ö;X,> ailures-Ö;`,> ystem re-Ö;h,> source f-Ö;ü >>_,D-Ø; >UA-Ø;p,> ailures-Ø;x,> ystem bu-Ø;€,> ffer ful-Ø; >>w,D-Ú; >UA-Ú;ˆ,> linsuff-Ú;,> icient r-Ú;˜,> eservati-Ú; ,> on resou-Ú; >>Š,D-Ü; >UA-Ü;¨,> rcesins-Ü;°,> ufficien-Ü;¸,> t resour-Ü; >>­,D-Þ; >UA-Þ;À,> cesinsu-Þ;È,> fficient-Þ;Ð,> registr-Þ;Ø,> ation re-Þ;à,> sources-Þ; >>Ä,D-à; >UA-à;è,> insuffic-à;ð,> ient acc-à;ø,> ess cont-à;-> rol reso-à;$ >>è,D-â;( >UA-â;-> urcesau-â;-> xiliary -â;-> memory o-â; -> ut of sp-â;, >>-D-ä;0 >UA-ä;(-> acequot-ä;0-> a error-ä;4 >>,-D-æ;8 >UA-æ;8-> maximum -æ;@-> number o-æ;H-> f supple-æ;P-> mental d-æ;X-> ecryptio-æ;`-> n keys e-æ;h-> xceeded-æ;< >>8-D-è;@ > UA-è;p-> medium a-è;x-> uxiliary-è;€-> memory -è;ˆ-> not acce-è;D >>p-D-ê;H > UA-ê;-> ssibled-ê;˜-> ata curr-ê; -> ently un-ê;¨-> availabl-ê;L >>—-D-ì;P > UA-ì;°-> einsuff-ì;¸-> icient p-ì;À-> ower for-ì;È-> operati-ì;T >>²-D-î;X >WA-î;Ð-> onunabl-î;Ø-> e to rec-î;à-> over tab-î;è-> le-of-co-î;\ >>Ó-D-ð;` >XA-ð;ð-> ntentsg-ð;ø-> eneratio-ð;.> n does n-ð;.> ot exist-ð;d >>÷-D-ò;h >YA-ò;.> updated-ò;.> block r-ò;l >>.D-ô;p >ZA-ô; .> eadoper-ô;(.> ator req-ô;0.> uest or -ô;8.> state ch-ô;@.> ange inp-ô;t >>$.D-ö;x >ZA-ö;H.> utopera-ö;P.> tor medi-ö;X.> um remov-ö;`.> al reque-ö;| >>K.D-ø;€ >ZA-ø;h.> stopera-ø;p.> tor sele-ø;x.> cted wri-ø;€.> te prote-ø;„ >>k.D-ú;ˆ >ZA-ú;ˆ.> ctopera-ú;.> tor sele-ú;˜.> cted wri-ú; .> te permi-ú;Œ >>‹.D-ü; >[A-ü;¨.> tlog ex-ü;°.> ception-ü;” >>ª.D-þ;˜ >[A-þ;¸.> threshol-þ;À.> d condit-þ;È.> ion met-þ;œ >>¸.D-;  >[A-;Ð.> log coun-;Ø.> ter at m-;¤ >>Ð.D-;¨ >[A-;à.> aximuml-;è.> og list -;ð.> codes ex-;ø.> hausted-;¬ >>ç.D-;° >\A-;/> rpl stat-;/> us chang-;´ >>/D-;¸ >\A-;/> espindl-;/> es synch-; /> ronized-;¼ >>/D-;À >\A-;(/> spindles-;0/> not syn-;8/> chronize-;Ä >>(/D- ;È >`A- ;@/> dlamp f- ;Ì >>B/D- ;Ð >aA- ;H/> ailurev- ;P/> ideo acq- ;X/> uisition- ;Ô >>O/D-;Ø >aA-;`/> erroru-;h/> nable to-;p/> acquire-;Ü >>g/D-;à >aA-;x/> videoo-;€/> ut of fo-;ä >>/D-;è >bA-;ˆ/> cusscan-;/> head po-;˜/> sitionin-; /> g error-;ì >>Œ/D-;ð >cA-;¨/> end of u-;°/> ser area-;¸/> encount-;À/> ered on -;È/> this tra-;ô >>¨/D-;ø >cA-;Ð/> ckpacke-;Ø/> t does n-;à/> ot fit i-;è/> n availa-;ð/> ble spac-;ü >>Ó/D-; >dA-;ø/> eillega-;0> l mode f-;0> or this -; >>ú/D-; >dA-;0> trackin-;0> valid pa-; 0> cket siz-; >>0D-; >eA-;(0> evoltag-;00> e fault-; >>*0D-; >fA-;80> automati-;@0> c docume-;H0> nt feede-;P0> r cover -; >>80D- ; >fA- ;X0> upautom- ;`0> atic doc- ;h0> ument fe- ;p0> eder lif- ;$ >>[0D-";( >fA-";x0> t updoc-";€0> ument ja-";ˆ0> m in aut-";0> omatic d-";˜0> ocument -";, >>}0D-$;0 >fA-$; 0> feederd-$;¨0> ocument -$;°0> miss fee-$;¸0> d automa-$;À0> tic in d-$;È0> ocument -$;4 >>§0D-&;8 >gA-&;Ð0> feederc-&;Ø0> onfigura-&;à0> tion fai-&;< >>×0D-(;@ >gA-(;è0> lurecon-(;ð0> figurati-(;ø0> on of in-(;1> capable -(;1> logical -(;1> units fa-(;D >>í0D-*;H >gA-*;1> iledadd-*; 1> logical-*;(1> unit fa-*;L >>1D-,;P >gA-,;01> iledmod-,;81> ificatio-,;@1> n of log-,;H1> ical uni-,;P1> t failed-,;T >>51D-.;X >gA-.;X1> exchang-.;`1> e of log-.;h1> ical uni-.;p1> t failed-.;\ >>Y1D-0;` >gA-0;x1> remove -0;€1> of logic-0;ˆ1> al unit -0;d >>y1D-2;h >gA-2;1> faileda-2;˜1> ttachmen-2; 1> t of log-2;¨1> ical uni-2;°1> t failed-2;l >>—1D-4;p >gA-4;¸1> creatio-4;À1> n of log-4;È1> ical uni-4;Ð1> t failed-4;t >>¹1D-6;x >gA-6;Ø1> assign -6;à1> failure -6;è1> occurred-6;| >>Ù1D-8;€ > gA-8;ð1> multipl-8;ø1> y assign-8;2> ed logic-8;2> al unit-8;„ >>ñ1D-:;ˆ > gA-:;2> set targ-:;2> et port -:; 2> groups c-:;(2> ommand f-:;Œ >>2D-<; > gA-<;02> ailedat-<;82> a device-<;@2> feature-<;H2> not ena-<;” >>62D->;˜ >hA->;P2> bledlog->;X2> ical uni->;`2> t not co->;h2> nfigured->;œ >>U2D-@;  >iA-@;p2> data lo-@;x2> ss on lo-@;€2> gical un-@;¤ >>q2D-B;¨ >iA-B;ˆ2> itmulti-B;2> ple logi-B;˜2> cal unit-B; 2> failure-B;¬ >>‹2D-D;° >iA-D;¨2> sparity-D;°2> /data mi-D;´ >>ª2D-F;¸ >jA-F;¸2> smatchi-F;À2> nformati-F;È2> onal, re-F;Ð2> fer to l-F;¼ >>¿2D-H;À >kA-H;Ø2> ogstate-H;à2> change -H;è2> has occu-H;Ä >>Û2D-J;È >kA-J;ð2> rredred-J;ø2> undancy -J;3> level go-J;3> t better-J;Ì >>õ2D-L;Ð >kA-L;3> redunda-L;3> ncy leve-L; 3> l got wo-L;Ô >>3D-N;Ø >lA-N;(3> rserebu-N;03> ild fail-N;83> ure occu-N;Ü >>,3D-P;à >qA-P;@3> rreddec-P;H3> ompressi-P;P3> on excep-P;X3> tion lon-P;`3> g algori-P;ä >>E3D-R;è >rA-R;h3> thm ids-R;p3> ession f-R;x3> ixation -R;ì >>o3D-T;ð >rA-T;€3> errorse-T;ˆ3> ssion fi-T;3> xation e-T;˜3> rror wri-T; 3> ting lea-T;ô >>†3D-V;ø >rA-V;¨3> d-inses-V;°3> sion fix-V;¸3> ation er-V;À3> ror writ-V;È3> ing lead-V;ü >>­3D-X; >rA-X;Ð3> -outses-X;Ø3> sion fix-X;à3> ation er-X;è3> ror - in-X;ð3> complete-X;ø3> track i-X;4> n sessio-X; >>Õ3D-Z; >rA-Z;4> nempty -Z;4> or parti-Z;4> ally wri-Z; 4> tten res-Z;(4> erved tr-Z; >> 4D-\; >rA-\;04> ackno m-\;84> ore trac-\;@4> k reserv-\;H4> ations a-\; >>44D-^; >rA-^;P4> llowedr-^;X4> mz exten-^;`4> sion is -^;h4> not allo-^; >>W4D-`; >rA-`;p4> wedno m-`;x4> ore test-`;€4> zone ex-`;ˆ4> tensions-`;4> are all-`;$ >>t4D-b;( >sA-b;˜4> owedcd -b; 4> control -b;, >>4D-d;0 >sA-d;¨4> errorpo-d;°4> wer cali-d;¸4> bration -d;À4> area alm-d;È4> ost full-d;4 >>®4D-f;8 >sA-f;Ð4> power c-f;Ø4> alibrati-f;à4> on area -f;è4> is full-f;< >>Ñ4D-h;@ >sA-h;ð4> power ca-h;ø4> libratio-h;5> n area e-h;D >>ð4D-j;H >sA-j;5> rrorpro-j;5> gram mem-j;5> ory area-j; 5> update -j;(5> failure-j;L >> 5D-l;P >sA-l;05> program -l;85> memory a-l;@5> rea is f-l;T >>05D-n;X >sA-n;H5> ullrma/-n;P5> pma is a-n;X5> lmost fu-n;\ >>L5D-p;` >sA-p;`5> llcurre-p;h5> nt power-p;p5> calibra-p;x5> tion are-p;€5> a almost-p;d >>c5D-r;h >sA-r;ˆ5> fullcu-r;5> rrent po-r;˜5> wer cali-r; 5> bration -r;¨5> area is -r;l >>Ž5D-t;p >sA-t;°5> fullrdz-t;¸5> is full-t;t >>µ5D-v;x >tA-v;À5> securit-v;È5> y error-v;| >>Á5D-x;€ >tA-x;Ð5> unable t-x;Ø5> o decryp-x;„ >>Ð5D-z;ˆ >tA-z;à5> t datau-z;è5> nencrypt-z;ð5> ed data -z;ø5> encounte-z;6> red whil-z;6> e decryp-z;Œ >>ç5D-|; >tA-|;6> tinginc-|;6> orrect d-|; 6> ata encr-|;(6> yption k-|;” >>6D-~;˜ >tA-~;06> eycrypt-~;86> ographic-~;@6> integri-~;H6> ty valid-~;P6> ation fa-~;œ >>36D-€;  >tA-€;X6> ilederr-€;`6> or decry-€;h6> pting da-€;¤ >>]6D-‚;¨ >tA-‚;p6> taunkno-‚;x6> wn signa-‚;€6> ture ver-‚;ˆ6> ificatio-‚;¬ >>s6D-„;° >tA-„;6> n keyen-„;˜6> cryption-„; 6> paramet-„;¨6> ers not -„;°6> useable-„;´ >>–6D-†;¸ >tA-†;¸6> digital -†;À6> signatur-†;È6> e valida-†;Ð6> tion fai-†;¼ >>¸6D-ˆ;À > tA-ˆ;Ø6> lureenc-ˆ;à6> ryption -ˆ;è6> mode mis-ˆ;ð6> match on-ˆ;Ä >>Ý6D-Š;È > tA-Š;ø6> readen-Š;7> crypted -Š;7> block no-Š;7> t raw re-Š;7> ad enabl-Š;Ì >>þ6D-Œ;Ð > tA-Œ; 7> edincor-Œ;(7> rect enc-Œ;07> ryption -Œ;87> paramete-Œ;Ô >>#7D-Ž;Ø > tA-Ž;@7> rsunabl-Ž;H7> e to dec-Ž;P7> rypt par-Ž;X7> ameter l-Ž;Ü >>C7D-;à >tA-;`7> istsa c-;h7> reation -;p7> paramete-;x7> r value -;€7> invalid-;ä >>d7D-’;è >tA-’;ˆ7> sa creat-’;7> ion para-’;˜7> meter va-’; 7> lue reje-’;ì >>ˆ7D-”;ð >tA-”;¨7> ctedinv-”;°7> alid sa -”;ô >>­7D-–;ø >!tA-–;¸7> usageda-–;À7> ta encry-–;È7> ption co-–;Ð7> nfigurat-–;Ø7> ion prev-–;ü >>¾7D-˜;>0tA-˜;à7> entedsa-˜;è7> creatio-˜;ð7> n parame-˜;ø7> ter not -˜;8> supporte-˜;>>æ7D-š;>@tA-š;8> dauthen-š;8> tication-š;8> failed-š; >> 8D-œ;>atA-œ; 8> external-œ;(8> data en-œ;08> cryption-œ;88> key man-œ;@8> ager acc-œ;H8> ess erro-œ;>> 8D-ž;>btA-ž;P8> rextern-ž;X8> al data -ž;`8> encrypti-ž;h8> on key m-ž;p8> anager e-ž;>>R8D- ; >ctA- ;x8> rrorext- ;€8> ernal da- ;ˆ8> ta encry- ;8> ption ke- ;˜8> y not fo- ;$>>}8D-¢;(>dtA-¢; 8> undexte-¢;¨8> rnal dat-¢;°8> a encryp-¢;¸8> tion req-¢;À8> uest not-¢;È8> authori-¢;,>>¤8D-¤;0>qtA-¤;Ð8> zedlogi-¤;Ø8> cal unit-¤;à8> access -¤;è8> not auth-¤;4>>Ô8D-¦;8>ytA-¦;ð8> orizeds-¦;ø8> ecurity -¦;9> conflict-¦;9> in tran-¦;9> slated d-¦;<>>÷8DL’´q¼=scsierrmsgÜ«=A~@np«@ p¯A W¯&° X°£±W±<-²;9> evicesc-²; 9> si errorp²>9D£²£²-²;(9> 5²>09A5²>@AI²ether.8 1287564422 0 0 664 51622 ` ~Erootdirtab~>.string-“;>>D-“;>m€A-”;> /clone-”; >>D-”;>A-”;>¶A-•;>>D-•;>A-•; >$A-–;> addrifs-–;$>> D-–;(>A-–;,>$A-—;> tatssta-—;0>>D-—;4>A-—;8>$A~>conndirtab-ž;>>D-ž;>A-ž;>m€A-Ÿ;> ts%dda-Ÿ; >>D-Ÿ;>A-Ÿ;>¶A- ;>>#D- ;>A- ; >¶A-¡; > tactli-¡;$>>'D-¡;(>A-¡;,>$A-¢;(> fstatss-¢;0>>/D-¢;4> A-¢;8>$A-£;0> tatstyp-£;<>>5D-£;@> A-£;D>$AL ãÐ>=ethersLœéVB=asixreset-«;==DLœéVB=cdcreset-¬;==D~>qtypeÜ°>A~@ qp² @ ²ÿAp²A £²£²~> qnumܶ >Ap¸ @ p¸ @ ͸ A ¯¸A ¸ÿÿÿA p¸A p¸ £¸£¸~> mkqidܼ > A~@ npÀ @ ÀÿÿÿA¬ÀA~@ tpÀ @ ÀÿA ‡À pÀ ~?qpÀøÿÿÿ?¯ÀA pÀ üÿÿÿ?~@.retpÁ@ pÁøÿÿÿ?pÁPpÁüÿÿÿ?pÁP£Á£Á~>freebufÜÅ>A~@bp&È@AOÈ2<~@epÉ@pÉSL+l=qlockÉ=pÉ@ /ÊxPpË SL+l=qunlockË=pÌ@pÌ OpÌSpÌ@pÌSLD+fº=sendpÌ=£Ì~>allocbufÜÑ>ApÕ@ pÕ P pÕ SLoÀD¸=nbrecvpÕ=pÕ &ÖA~?bppÖüÿÿÿ?XÖd e%s: %d-Ü;@> bufferspÜApÜSpÜ>:DpÜSLzaò=argv0pÜ=pÜSpÜ@pÜtOpÜ SLJ”§Š=fprintÜ=pÞ@pÞSÞ=pÞüÿÿÿ? &à AXàk!newconnÜì!> Apñ@pñSñ=pñ@pòA Wò… %s: ne-þ;P> wconn %dpþApþSpþ>JDpþSpþ=pþSpþ  Sþ=pþ@pÿSÿ=pøÿÿÿ#?£W‚%seprintaddrÜ%>A~@&sp&@ p A W ÆZD p  S~@(addrp (@ p   p  üÿÿÿ"?s  R p   SL¦`o=)seprint )=p üÿÿÿ"? p  W à %02xs-;`> hort pac-;h> ket (%d -;p> bytes) pApSp>_DpSp S=£~?-bufaüÿÿÿ-?-;x> %s [%d]:a|ÿÿÿ-? p S~?.septÿÿÿ.?pSp>xD p S~@/tagp/@ p  Sp S)=p Sp tÿÿÿ.? p  Sp üÿÿÿ,? A p  S %>p!Sp!tÿÿÿ.? p! Sp!>‚D p! S!)=p"Sp"tÿÿÿ.? p" Sp"üÿÿÿ,? p" S"%>p"üÿÿÿ,? -#;€> -> -#;ˆ> type 0x%-#;> 02ux%02up#Sp#tÿÿÿ.? p# Sp#>‡D p# Ss# R p#  Ss# R p# S#)=p# Ö$A @p%A W% x %02xp& Sp&tÿÿÿ.? p& Sp&>›D p& Sp&  p& pÿÿÿ"?p&üÿÿÿ,? a& R s&P p&  S&)=p&pÿÿÿ"? p& W&<&' @AU'4 Dp(Sa(|ÿÿÿ-?p(S(=W(;<-*; > %s... %p*Ap*Sp*>§Dp*Sa*|ÿÿÿ-?p*S*=£*~>0seprintstatsÜ.0>Ap0@p0S0=-1;¨> s in: %p1&@ p1 S~@1sep11@ p1 Sp1>«D p1 Sp1@ p1€P p1  S1)=-2;°> ld out:p2Sp21@ p2 Sp2>´D p2 Sp2@ p2„P p2  S2)=-3;¸> %ld in-3;À> put errsp3Sp31@ p3 Sp3>¾D p3 Sp3@ p3ˆP p3  S3)=-4;È> : %ld o-4;Ð> utput er-4;Ø> rs: %ld p4Sp41@ p4 Sp4>ÏD p4 Sp4@ p4ŒP p4  S4)=-5;à> mbps: %p5Sp51@ p5 Sp5>áD p5 Sp5@ p5P p5  S5)=-6;è> d prom:p6Sp61@ p6 Sp6>ëD p6 Sp6@ p6<P p6  S6)=-7;ð> %ld adp7Sp71@ p7 Sp7>öD p7 S7)=p8Sp81@ p8 Sp8@ 8HA p8 S8%>p9Sp91@ p9 Sp9>ýD p9 S9)=p9&@p:@p:S:=p;&@£;£;~>seprintifstatsÜ?>0ApD@pDSD=-E;ø> dr: c-E;> tlr id: pE&@ pE SpE1@ pE SpE>ÿD pE SpE@ pE4P pE  SE)=-F;> %#x phypFSpF1@ pF SpF> D pF SpF@ pF8P pF  SF)=-G;> : %#x e-G;> xiting: -G; > %s ynpGSpG1@ pG SpG>D pG SpG@ pG@Q &G AOG³$D WG´&D pG  SG)=-H;(> conns: %pHSpH1@ pH SpH>(D pH SpH@ pHPP pH  SH)=-I;0> d alloc-I;8> ated bufpISpI1@ pI SpI>3D pI SpI@ pItP pI  SI)=-J;@> s: %d u-J;H> sed bufspJSpJ1@ pJ SpJ>GD pJ SpJ@ pJxP pJ  SJ)=pJ pJ&@pKA WKØ : %d c[-P;X> %d]: frepP SpP1@ pP SpP>VD pP SpP  SP)=pPüÿÿÿ"? pP pP&@WP<-R;`> e c[%d]-R;h> : refs %-R;p> ld t %#x-R;x> h %d p pR SpR1@ pR SpR>cD pR SpRQ pR  SpRQ pR SpRQ pR SpR Q pR SpRQ pR SR)=pRüÿÿÿ"? pR pR&@WRÕetherdumpÜ[>A&_=AX_ <£`aaÿÿÿ-?paSaa-?paSpa@paSa>-b;€> %d %s: -b;ˆ> ether %#pbApbSpb>„DpbSpb=pbSpb@pb Sabÿÿÿ-?pbSb=£b~>getconnÜf>Apj@pjSj=pj@ ~@ipj@ &k AUk,filldirÜw>A~@dpy@ yApyS~@cnpy @pyS~@ tabpy @pyOpySy >py @ py@ ~@ fspz @ z(A pzPpzP ‡zR‡z  Rp{T p{ Rp|R |€A&|AO|Z .string-; > p: %s %p,RpSp>— DpSp @pSLµó¡= sprint =Wh rootdirgen܇ >$Ap‡ @ p‡@ p4T CŽ pA & APvrootdirtaba‘ >p‘ W‘conndirtabp•>D W•pšA£š£š~>conndirgenÜž> Apž@ C¢ &£ AP£’~?tabp¤üÿÿÿ?W¤”qnum§>p§ôÿÿÿ?p§ @p§Sp§@p§Sp§üÿÿÿ?p§Sp§ôÿÿÿ?p§ S§>p¨A£¨£¨~>fswalkܬ>@Ap¬ @ p´4Q~?ep´ìÿÿÿ?~@fidpµ@ µA~?qidaµÜÿÿÿ?pµA !µ¡µyµp¶  ¶(A p¶Pp¶P „¶„¶ ¶Üÿÿÿ? ¶ àÿÿÿ?s·èÿÿÿ? ·€A&·AX·Â<-¸;˜ > dwalk i-¸;  > n non-di-¸;¨ > rectoryp¸>š Dp¸SL·áP=werrstr¸=p¹ÿÿÿÿA£¹~@namep¼@ p¼ Sp¼>° D p¼ SL´§,=strcmp¼=&¼AX¼Ýmkqid¾>p¾@ p¾ @ ¾(A p¾Pp¾P ~?.safep¾Ðÿÿÿ? ‡¾ p¾Ôÿÿÿ? ‡¾  p¾Rp¾ Rp¿A RoÀ€ARpÁA£ÁWäfpÌ@ pÌ @ Ì(A pÌPpÌP pÌÐÿÿÿ? ‡Ì pÌÔÿÿÿ? ‡Ì  pÌRpÌ RpÍA RpÎA£ÎpÒÜÿÿÿ? pÒ SpÒàÿÿÿ? pÒ S~> qtypeÒ >&ÒAXÒDpÓðÿÿÿ?WÓDpÕðÿÿÿ?pÖÜÿÿÿ? pÖ SpÖàÿÿÿ? pÖ SÖ>pÖðÿÿÿ? ~?!cnpÖüÿÿÿ!?p×A W×(pÙ@ pÙ @ Ù(A pÙPpÙP pÙÐÿÿÿ? ‡Ù pÙÔÿÿÿ? ‡Ù  pÙRpÙ RpÚA RpÛøÿÿÿ"? aÛ P ¬ÛA pÛðÿÿÿ? aÛ QpÛO Û€A&ÛAOÛ] ..usb: -ã;¸ > ether: f-ã;À > swalk bupã>³ DpãSL·áP=#sysfatalã#=WãÞpã@ &ãAOãß<&ãAOã$qdirtabÜé$>Apî@ pî Spî@ pî Sî >&ïAPïD pñ WñŒD pó ôÿÿÿ?pô ôûÿÿÿA &õ Apõ üÿÿÿ"?Põ‡ gi < ne-õ;Ð > lem(conn-õ;Ø > dirtab) põ>Ê DpõSL¼ì?;=%_assertõ%=põôÿÿÿ? põüÿÿÿ"? a÷ Q ¬÷A a÷ R£÷£÷~>&fsstatÜû&>A~@'qidpý'@ pý Spý'@ pý Sý$>pýüÿÿÿ?pý'@ pý Spý'@ pý Sý>pýøÿÿÿ?pý @pýSpý@pýSpýüÿÿÿ?pýSpýøÿÿÿ?pý Sý>pþA£þ£þ~>(fsopenÜ(>4Ap @ p   (A p Pp P „ „  p @ A p R p R    ~?)qidp  ôÿÿÿ)?p  øÿÿÿ)?p 4Tp èÿÿÿ?p ôÿÿÿ)? p  Sp øÿÿÿ)? p  S  >~?*qtp üÿÿÿ*?p ôÿÿÿ)? p  Sp øÿÿÿ)? p  S $>~@+omodep +@ A & AOÏ-newconn->p &AXâ<-;à > - 1no m-;è > ore conn-;ð > ectionsp>ä DpS=pÿÿÿÿA£p@oAOaÜÿÿÿ?pSpPpSpApS>p@ p @ (A pPpP pÜÿÿÿ? ‡ pàÿÿÿ? ‡  pRp RpA RWÖp#àÿÿÿ?p#èÿÿÿ? p# Sp#àÿÿÿ? p# Sp#A p# S#>p# &$A~?.cp$ðÿÿÿ.?X$ <-%;ø > usb: eth-%; > er: fsopp%>ø Dp%S%#=p%ðÿÿÿ.? p& SLO‘{Õ=/incref&/=W'Öp*A£*£*~>0promÜ.0> A~@1ep.1@ p0´Q&0AO01fsclunkÜ6>0Ap6 @ p>4P~?ep>èÿÿÿ? ?(A p?Pp?P „?„? p?@ ?A p?R p?R ? ?  p? ôÿÿÿ)?p? øÿÿÿ)?p@ôÿÿÿ)? p@ Sp@øÿÿÿ)? p@ S@ >WWpHàÿÿÿ?pHèÿÿÿ? pH SpHàÿÿÿ? pH SpHAS~>getconnH>pH &IApIìÿÿÿ.?XId<-J; > en bugu-J; > sb: ethe-J; > r: fsopepJ> DpJSJ#=pJìÿÿÿ.? pK SL—q\ð=decrefK=&KAXKŽfreebufM>WMipRìÿÿÿ.?pRìÿÿÿ.? pRAQpRA pR OpSèÿÿÿ?pSS~= qunlockS =WVK<&VAQV— etherdumpX >£XLÕv@= parseaddrÜ\ =A~@ spa @ pa SLÍ V= strlena =&a APa¨fsreadÜz>`A~@fspz@ p„@ „A~?qa„Ô÷ÿÿ?p„A !„¡„y„p…  …(A p…Pp…P „…„… …Ô÷ÿÿ? … Ø÷ÿÿ?p†4Qp†ä÷ÿÿ?~?bufa‡ð÷ÿÿ?~?sp‡ôÿÿÿ?aˆðÿÿÿ?~?sepˆðÿÿÿ?p‰Ô÷ÿÿ? p‰ Sp‰Ø÷ÿÿ? p‰ S‰ >p‰øÿÿÿ*?pŠÔ÷ÿÿ? pŠ SpŠØ÷ÿÿ? pŠ S~>qnumŠ>pŠ@pŠôÿÿÿ?pŠðÿÿÿ? pŠä÷ÿÿ? pŠ WÁ"rootdirgenp>D p $SpA(SLøHj=usbdirread=p WŽ3seprintaddr>p‘@ p‘ Sp‘ @ p‘ Sp‘@ p‘ Sp‘@ p‘  Sa‘ð÷ÿÿ? p‘ Sa‘ð÷ÿÿ? p‘ Ö‘  p‘ SLÏ¡Ç=usbreadbuf‘=p‘ W’3seprintifstats–>p–ä÷ÿÿ? p– p—¼Q&—AO—pseprintstatsž>pŸ@ pŸ SpŸ @ pŸ SpŸ@ pŸ SpŸ@ pŸ  SaŸð÷ÿÿ? pŸ SaŸð÷ÿÿ? pŸ ÖŸ  pŸ SŸ=pŸ W 3 conndirgenp£> D p£ $Sp£A(S£=p£ W¤3&§AX§¶%.string-¯; %> n bugetp¯>&%Dp¯Sp¯Qp¯S~?&bpp¯ ì÷ÿÿ&?p¯Qp¯S~='dumpframe¯'=p¯ì÷ÿÿ&? p°@ p° Sp° @ p° Sp°ASp°A Sp°Q p° Sp° ì÷ÿÿ&?p°Q p° S°=p° @p±ä÷ÿÿ?p±Sp±ì÷ÿÿ&?p±S±>p± @ W²3<-´;(%> herin%1p´Sp´ Sp´>.%D p´ Sp´  S~=(seprint´(=pµ@ pµ Spµ @ pµ Spµ@ pµ Spµ@ pµ  Saµð÷ÿÿ? pµ Saµð÷ÿÿ? pµ Öµ  pµ Sµ=pµ W¶3p¸ôÿÿÿ? p¸ðÿÿÿ? &¹AX¹<-º;0%> 1d %11dpº Spº Spº>4%D pº SpºA Sº(=pº Wº <-¼;8%> %11d p¼ Sp¼ Sp¼>:%D p¼ Sp¼O p¼  S¼(=p¼ p½@ p½ Sp½ @ p½ Sp½@ p½ Sp½@ p½  Sa½ð÷ÿÿ? p½ Sa½ð÷ÿÿ? p½  Ö½  p½ S½=p½ W¾3<-À;@%> usb: eth-À;H%> er: fsrepÀ>@%DpÀS~=)sysfatalÀ)=pÀ @ WÀ3*typeinuseÜÆ*>A~@+tpÆ+@~@,epÆ,@ pÊA WÊG-isloopbackÜÑ->ApÓ,@pÓ<O&ÓASÓd.etherctlÜ×.>$A&Ü$=AOÜs<-Ü;P%> ad bug%-Ü;X%> s: ether-Ü;`%> ctl: %s pÜApÜSpÜ>W%DpÜS~=/argv0pÜ/=pÜS~@0bufpÜ0@pÜ S~=1fprintÜ1=-Ý;h%> connectpÝ0@ pÝ SpÝ>i%D pÝ SpÝA pÝ SLÃa·=strncmpÝ=pÝ0@ &ÝAXÝŸ&àAOà”<-á;p%> type a-á;x%> lready ipá>r%DpáSá"=pâ,@pâSâ =pãÿÿÿÿA£ãpå0@ åA på Så=~@cpå@ påPpæ,@pæSæ =pçA£ç-é;€%> n useno-é;ˆ%> nblockinpé Spé>†%D pé Spé A pé Sé=pé,@ pé0@ &éAXéÅ g%s: nb-î;˜%> lock %d pîApîSpî>’%DpîSpî/=pîSpî|Rpî Sî1=pïA£ï-ñ; %> promiscpñ Spñ>¡%D pñ Spñ A pñ Sñ=&ñAXñÝpromõ>£õ-÷;¨%> uoushea-÷;°%> dersonlyp÷0@ p÷ Sp÷>­%D p÷ Sp÷ A p÷ S÷=&÷AX÷ê addmult-û;À%> i remmupû0@ pû Spû>¹%D pû Spû A pû Sû=pû0@ &ûAOûÿÃ%D pû Spû A pû Sû=pû0@ pû,@ &ûAOûÿ lti bad-ý;Ð%> addresspý>Í%DpýSý"=pþÿÿÿÿA£þp ,@p ¸O& AX Ù%D p  Sp A p  S =p ,@ & AX & etherbreadÜ  >A~@ bpp  @ & $=AO H<- ;Ø%> add%s:- ;à%> etherbrp Ap Sp >Ý%Dp Sp /=p S 1=p  @ p    ŒA p  Qp ÿÿÿÿAQp ,@ p ,P p  P p  Sp Q p  Sp ÐA p  SL ead %s:- ;ð%> etherbr- ;ø%> ead: %r p Ap Sp >í%Dp Sp  S 1=p  @ W q<&  AO q<- ;%> %s: eth- ;%> erbread:- ;%> got %d p Ap Sp >%Dp Sp  Sp Qp  S 1=p  @ p Q£ £ ~> etherbwriteÜ  > Ap  @ &$ $=AO$ ‚<-$ ;%> bytes %-$ ; %> s: ether-$ ;(%> bwrite %-$ ;0%> d bytes p$ Ap$ Sp$ >%Dp$ Sp$ /=p$ Sp$ Qp$  S$ 1=p$  @ p% ,@ p% 0P p%  P p%  Sp% Q p%  Sp% Q p%  SL %s: eth-' ;@%> erbwritep' Ap' Sp' >9%Dp' Sp' /=p' S' 1=p' üÿÿÿ? W' ¥<&) $=AO) ¥<-) ;H%> : %r %s-) ;P%> : etherb-) ;X%> write wr-) ;`%> ote %ld p) Ap) Sp) >N%Dp) Sp) /=p) Sp)   S) 1=p) üÿÿÿ? &*  AQ* © bytes %-- ;p%> s: short-- ;x%> pkt wrip- Ap- Sp- >o%Dp- Sp- /=p- S- 1=p. ,@p. 0Op.  Op. Sp. >„%Dp. Sp. Ap. S.  =~?np. üÿÿÿ? p0  £0 £0 ~>fswriteÜ4 >¸Ap4 @ ~@fidp= @ = Aa= \ÿÿÿ?p= A != ¡= y= p>   > (A p> Pp> P „> „>  > \ÿÿÿ? >  `ÿÿÿ?p? 4Q~?ep? lÿÿÿ?~?qp@ \ÿÿÿ? p@  Sp@ `ÿÿÿ? p@  S~>qtype@ >~?qtp@ øÿÿÿ?pA \ÿÿÿ? pA  SpA `ÿÿÿ? pA  SA >pA lÿÿÿ? pA  Wf [getconnD >&E AXE öallocbufI >pI  @ pI  &J  ÐASJ þ te ethpO >…%DpO SpO QpO SpO QpO SO '=pO lÿÿÿ? pO tÿÿÿ? pP |R&P AXP  erout%s-S ;%> : (out) -S ;˜%> packet lpS ApS SpS >Ž%DpS SpS /=pS SS 1=pT lÿÿÿ?pT SpT tÿÿÿ?pT S~>freebufT >WV êpX  @ &Y A~?cpY pÿÿÿ?XY ?&a APa V ost usb-e ;¨%> : ether:-e ;°%> fsread pe >¥%Dpe Se )=We ê!openepsÜk !>A~@"epm "@ pm (P pm  S~@#epinpm #@ pm  SLøW V=$openepm $=pm #@ ~@%epoutpm %@ pm "@ pm ,Qpn ,Q&n AXn z<~>&.string-o ;¸&> bugethe-o ;À&> r: in: o-o ;È&> penep %dpo Apo Spo >¼&Dpo Spo  So 1=pp ÿÿÿÿA£p &r   Xr ƒ : %r et-x ;Ø&> her: out-x ;à&> : openep-x ;è&> %d: %r px Apx Spx >Ö&Dpx Spx %@px Sx 1=py "@py ,Opy SLM½D='closedevy '=pz ÿÿÿÿA£z p| ,Qp| 0Q &|  X| ¤ ether: -ƒ ;ø&> open i/o-ƒ ;&> ep datapƒ Apƒ Spƒ >ñ&Dpƒ Sƒ 1=p„ "@p„ ,Op„ S„ '=p… "@p… 0Op… S… '=p† ÿÿÿÿA£† L½ÕQA=)usbdebug&ˆ )=AOˆ Û<-ˆ ;&> : %r et-ˆ ;&> her: ep -ˆ ;&> in %s ma-ˆ ; &> xpkt %d;-ˆ ;(&> ep out -ˆ ;0&> %s maxpkpˆ Apˆ Spˆ >&Dpˆ Spˆ ,Ppˆ Opˆ Spˆ ,Ppˆ Opˆ  Spˆ 0Ppˆ Opˆ Spˆ 0Ppˆ Opˆ Sˆ 1=pˆ "@ & )=AQ à<~=*etherdebug& *=AQ à t %d depŽ ,PpŽ SpŽ >>&DpŽ SL€$ö=+devctlŽ +=- ;@&> bug 1dep "@p 0Op Sp >F&Dp S +=- ;H&> bug 1dep "@p (Op Sp >N&Dp S +=p“ A£“ £“ ~>,usageÜ— ,>A-™ ;P&> bug 1us-™ ;X&> age: usb-™ ;`&> /ether [-™ ;h&> -d] [-N p™ >V&Dp™ S~=-werrstr™ -=pš ÿÿÿÿA£š £š ~>.etherfs~>/fswalk-ž ;8.>>/D~>0fsopen-Ÿ ;D.>>0D~>1fsread-  ;H.>>1D-¡ ;L.>>D~>fsstat-¢ ;P.>>D~>fsclunk-£ ;@.>>D~>shutdownchanܧ >AW« ÿetherfreeܱ >Ap± "@ p¶ ÀP&¶ AO¶  pÆ "@pÆ ˜OpÆ SÆ >pÇ "@pÇ œOpÇ SÇ >pÇ "@ pÈ A0RpÈ A pÈ  ,R-É ;p&> nb]detapÉ (RpÉ SpÉ >t&DpÉ SÉ +=pÊ "@pÊ SÊ =£Ê ~> etherdevfreeÜÎ  >A~@ apÐ  @&Ò AOÒ o £Ó ~> cwantsbpÜØ  >ApØ @ pÚ P&Ú AOÚ ‚ etherwriteprocÜà > Apâ  @~?epâ üÿÿÿ?pæ üÿÿÿ?pæ œO~?wcpæ ôÿÿÿ?Wç ‘ isloopbackð >pð øÿÿÿ? pð üÿÿÿ? &ð AOð ¸ Wó  <&õ *=AOõ Ë <-õ ;x&> ch%s: w-õ ;€&> riteproc-õ ;ˆ&> exitingpõ Apõ Spõ >{&Dpõ S~=argv0põ =põ S~=fprintõ =pö üÿÿÿ?pö (Opö Sö '=£ö ~>setbuftypeÜú >A~@bppú @ pþ ARpÿ R&ÿ AUÿ Ý etherexitingÜ > A- ;&> detach~@ep @p (Op Sp >’&Dp S +=p @ p A@Pp ,Pp  Op SLÃ)»=close =p @ p ,Pp ÿÿÿÿA Op 0Pp  Op S =p @ p 0Pp ÿÿÿÿA Op œPp Sp ASLD+fº=nbsend =£ ~>etherreadprocÜ >,Ap  @~?ep èÿÿÿ?W  allocbuf >p èÿÿÿ? p  Sp ðÿÿÿ?p Sp ¨R p èÿÿÿ? p ðÿÿÿ? & AP  freebuf  >W ÿ W$ þ p& èÿÿÿ? C( €T~?!nwantsp) Aôÿÿÿ!?p* A W* . p+ üÿÿÿ ? p+ èÿÿÿ? + ôÿÿÿ!?W+ + p- üÿÿÿ ?p- èÿÿÿ? &- AO- ‘ ~?#dbpp7 ìÿÿÿ#?p7 Op7 Sp7 ðÿÿÿ?p7 Op7 Sp7 øÿÿÿ"?p7 S~=$memmove7 $=p7 üÿÿÿ ?p7 ìÿÿÿ#?p7 èÿÿÿ? p8 øÿÿÿ"? p8  Up9 ðÿÿÿ? p9 P p9  Up;   a; R p; TP p; P p;  Sp; ìÿÿÿ#?p; S~=%nbsendp; %=p; üÿÿÿ ?p; èÿÿÿ? &; AX; ‘ p= üÿÿÿ ?p= èÿÿÿ? W= ? W@ þ <&B *=AOB   <-B ;˜&> %s: wri-B ; &> teproc e-B ;¨&> xiting pB ApB SpB >™&DpB SpB =pB SB =pC èÿÿÿ?pC SC >pD èÿÿÿ?pD (OpD SD '=pE èÿÿÿ? E ÈApE SLv<&û=&usbfsdelE &=£E ~>'setaltÜI '> A~@(dpK (@ pK  SpK A pK  SpK  A pK  S~@)altidpK )@ pK   S~@*ifcidpK *@ pK  SpK ASpK ASLïûS|=+usbcmdK +=&K APK É <~=,usbdebug&L ,=AOL É <~>-.string-L ;°-> %s: seta-L ;¸-> lt ifc %-L ;À-> d alt %dpL ApL SpL >°-DpL SpL =pL SpL *@pL  SpL )@pL SL =£L ~>.ifaceinitÜP .>(A~@/ifcpP /@&U AXU Ð : %r et-e ;Ð-> her: ep -e ;Ø-> ids: in -e ;à-> %d out %pe Ape Spe >Î-Dpe Spe  Spe  Se =pe /@pe ôÿÿÿ1?pe øÿÿÿ0? pf A Wf  ph /@ph ðÿÿÿ ? ph ôÿÿÿ1?ph øÿÿÿ0? Wh  <~@eipj @pj  O~@eopk  @pk Opl A£l £l ~>etherinitÜp ><Apx @px @ px ÿÿÿÿAQpx ÿÿÿÿA px  Opy @py (Opy O~?udpy Üÿÿÿ?p| Aôÿÿÿ ?W| ? &’ ÿÿÿÿAX’ Ž ~? ip ôÿÿÿ ? p ðÿÿÿ ? & ÿÿÿÿAO » d %s: n-Ÿ ;ð-> o valid -Ÿ ;ø-> endpointpŸ ApŸ SpŸ >ë-DpŸ SpŸ =pŸ SŸ =p  ÿÿÿÿA£  £  Lé›pZ= ethermainܤ  =8A~@ argvp¤  @ ~@ devp©  @p© O~?devidp© ðÿÿÿ?&ª =AXª Õ sether -­ ;-> debug onp­ Ap­ Sp­ >-Dp­ S­ =p­  @ p­ èÿÿÿ? C® =W¯  -D p±  èÿÿÿ?r± Q %±  AO±  usage± >L)¡L=abort± =p± A~?.safep± Øÿÿÿ?p± Øÿÿÿ? p±  S~=atoi± =p±  @ p± èÿÿÿ? p± ðÿÿÿ?W²  <´ >£´ w´ âÿÿÿ?&´ NAO´  <&´ dAO´  <· >£· p¹  A p¹  Sp¹ A p¹  S~=emallocz¹ =p¹  @ p¹  Qp¹  pº  (O~>etherdevfreep» >D p»  $Qp½ A W½ N D pà  ¤RpÄ  SaÄ üÿÿÿ0? pÄ  SaÄ øÿÿÿ1? pÄ  SpÄ  ìÿÿÿ?pÄ ¤RÄ pÄ ìÿÿÿ? &Ä APÄ q etherbwritepÇ >D pÇ  ¬QpÈ ¨Q&È AXÈ { <~>etherbreadpÉ >D pÉ  ¨QpË  SpË üÿÿÿ0? pË  SpË øÿÿÿ1? pË  S~>openepsË >pË ìÿÿÿ? &Ë APË † etherfsaÍ >pÍ A !Í ¡Í yÍ -Î ;-> etherpÎ   Î ÈApÎ SpÎ (ApÎ SpÎ >-DpÎ SpÎ ðÿÿÿ?pÎ  SLD$s5= snprintÎ  =pÎ ìÿÿÿ? pÏ  @ pÏ  øQpÐ  üQpÑ A pÑ  SpÑ A pÑ  S~=!chancreateÑ !=pÑ ìÿÿÿ? pÑ  PpÒ A pÒ  SpÒ A pÒ  SÒ !=pÒ ìÿÿÿ? pÒ ˜PpÓ A pÓ  SpÓ A pÓ  SÓ !=pÓ ìÿÿÿ? pÓ œQpÔ (QpÔ S~="increfÔ "=~>#etherwriteprocpÕ >#DpÕ SpÕ ìÿÿÿ?pÕ SpÕ @ApÕ SLS]Å)=$proccreateÕ $=pÖ ìÿÿÿ?pÖ (OpÖ SÖ "=~>%etherreadprocp× >%Dp× Sp× ìÿÿÿ?p× Sp× @Ap× S× $=&Ø =AOØ Ñ <-Ø ;-> U%d%s: -Ø ; -> dev ref pØ ApØ SpØ >-DpØ S~=&argv0pØ &=pØ SpØ  @pØ OpØ  S~='fprintØ '=pÙ ìÿÿÿ?pÙ (OpÙ SÙ "=pÚ ìÿÿÿ? Ú ÈApÚ SLv<&û=(usbfsaddÚ (=pÛ A£Û £Û -Û ;(-> %ld 5Û =A~>)rootdirtab5Û )>HA5Û ->0A5Û =A5Û >XA~>*conndirtab5Û *>TA~=+cinfo5Û +=AIÛ asix.8 1287564422 0 0 664 19279 ` ~EasixsetÜ>,Ap¢@A ~@dp£@ p£ Sp£ S~@cp£@ p£ S~@vp£@ p£  Sp£ASp£ASp£ASLïûS|=usbcmd£=p£ &¤A~?ecp¤øÿÿÿ?P¤.string-¥;> %s: asix-¥;> set %x %p¥Ap¥Sp¥>Dp¥SLzaò= argv0p¥ =p¥Sp¥@p¥ Sp¥@p¥SLJ”§Š= fprint¥ =p¥øÿÿÿ? p¦ £¦£¦~> asixgetܪ >,Ap¯ÀA p°@ p° Sp° Sp°@ p° Sp°A Sp°AS~@ bufp° @ p° S~@ lp° @ p° S°=p° &±Ap±øÿÿÿ?P±@<&²=AO²@<-²;> x: %r %-²;> s: asixg-²; > et %x: %p²Ap²Sp²>Dp²Sp² =p²Sp²@p² S² =p²øÿÿÿ? p³ £³£³~>getgpioÜ·>Ap»@ p» Sp»A p» S~?ca»ÿÿÿÿ? p» Sp»A p»  S» >&»AP»QgetphyÜÁ>ApÅ@ pÅ SpÅA pÅ S~?bufaÅþÿÿÿ? pÅ SpÅA pÅ  SÅ >&ÅAPÅb r %s: p-Ç;0> hy addr pÇApÇSpÇ>+DpÇSpÇ =pÇSsÇÿÿÿÿ?pÇ SÇ =sÈÿÿÿÿ?£È£È~>getrxctlÜÌ> AaÑþÿÿÿ?pÑSpÑASpÑApÑSL£Xýù=memsetÑ=pÒ@ pÒ SpÒA pÒ SaÒþÿÿÿ? pÒ SpÒA pÒ  SÒ >&ÒAPÒ„ %#ux %s-Õ;@> : rxctl pÕApÕSpÕ>>DpÕSpÕ =pÕS~?rpÕ øÿÿÿ?pÕ  SÕ =pÕøÿÿÿ? pÖ £Ö£Ö~>getmacÜÚ>ApÜ@ pÜ SpÜA pÜ S~@bufpÜ@ pÜ SpÜA pÜ  SÜ >&ÜAPܨmiireadÜâ>,ApçÀA pè@ pè Spè SpèA pè S~@phypè@ pè  S~@regpè@ pè S~?vaèúÿÿÿ? pè SpèA pè Sè=&èAPèÈ %#x %s:-é;P> miiwritpéApéSpé>MDpéSpé =péSé =pêÿÿÿÿA£êsìûÿÿÿ? ìÿA¬ìAsìúÿÿÿ? ìÿA ‡ì &íÿÿAXíÒmiiwriteÜô>,Apù@ pù SpùA pù SpùASù>~@valpù @ &ùAPùà e: %r %-þ;`> s: miiwr-þ;h> ite: %#x-þ;p> %#x %r pþApþSpþ>_DpþSpþ =pþSpþ@pþ Spþ @pþSþ =pÿÿÿÿÿA£ÿp@ p Sp A p SpAS>&APeepromreadÜ>0Ap ÀA p@ p Sp Sp A p S~@ip@ p  SpAS~? bufaöÿÿÿ ? p SpA p S=&AP-<&=AO-<-;x> %s: eep-;€> romread -;ˆ> %d: %r pApSp>yDpSp =pSp@p S =s÷ÿÿÿ ? ÿA¬Asöÿÿÿ ? ÿA ‡ p &=AOB<-;> %s: eepr-;˜> om %#x =pApSp>DpSp =pSp@p Sp øÿÿÿ?p S =pøÿÿÿ? & ÿÿAXE!ctlrinitÜ!>4A~@"etherp"@ p= p = p&(R~?#dp&üÿÿÿ#?W‹* %#x %s-);¨> : card k-);°> nown but-);¸> not imp-);À> lementedp)Ap)Sp)>¦Dp)Sp) S) =p*ÿÿÿÿA£*&- AO-`<--;È> %s: se--;Ð> tting up--;Ø> A88178 p-Ap-Sp->ÊDp-Sp- S- =p.üÿÿÿ#? p. S.>p. &/AP/h %s: gpi-1;è> o sts %#p1Ap1Sp1>áDp1Sp1 =p1Sp1  S1 =p2üÿÿÿ#?p2Sp2 Ap2Sp2AS2>p3üÿÿÿ#? p3 Sp3A p3 S3>~?$ee17p3ìÿÿÿ$?p4üÿÿÿ#?p4Sp4Ap4Sp4AS4>p5üÿÿÿ#?p5Sp5Ap5Sp5ŒAp5S5>p5üÿÿÿ#? p6ìÿÿÿ$?¯6A&6AO6¥p8üÿÿÿ#?p8Sp8Ap8Sp8Ap8S8>p9üÿÿÿ#?p9Sp9Ap9Sp9<Ap9S9>W9²p<üÿÿÿ#?p<Sp<Ap<Sp< Ap<S<>p>üÿÿÿ#?p>Sp> Ap>Sp>AS>>p?–Ap?SLo Öò=%sleep?%=p@üÿÿÿ#?p@Sp@ Ap@Sp@HAp@S@>pA–ApASA%=pBüÿÿÿ#?pBSpBApBSpBASB>pCüÿÿÿ#? pC SpC"@ CHA pC SC>&CAPCÕpE"@ pEìÿÿÿ$? pE8R&F AUFâpH<ApHSH%=pH"@ pJüÿÿÿ#?pJSpJ8RpJSpJASpJApJ SJ>pKüÿÿÿ#?pKSpK"@pK8OpKSpKApKSpKáApK SK>pLüÿÿÿ#?pLSpL"@pL8OpLSpL ApLSpLApL SL>pMüÿÿÿ#? pM SpM"@ pM8P pM SpMASM>pM NA&NAON<‡OA pPüÿÿÿ#?pPSpP"@pP8OpPSpPASpP  SP>pRüÿÿÿ#?pRSpRApRSpRvApRSR>pSüÿÿÿ#?pSSpSApSSpSˆApSSS>WTO<&W AOW6<-W;ð> x %s: s-W;ø> etting u-W;> p A88772pWApWSpW>óDpWSpW SW =pXüÿÿÿ#? pX SpXA pX SpX°A pX SX>&XAPXApZ"@ pZ8Q&[=AO[R<-[;> %s: php[Ap[Sp[> Dp[Sp[ =p[Sp[8Qp[ S[ =p["@ p\8Q \A&\AX\_p^ W^fp` &a APaj&cAPcupg Wgpi &j APj‘pm &n=AOn¢<-n;> y %#x %-n;> s: rxctl-n; > is %#x pnApnSpn>DpnSpn =pnSpn  Sn =poüÿÿÿ#? po SpoA po SpoASo>&oAPo¬&qAPq¶&uAPuÁ&xAPxÏp}üÿÿÿ#?p}Sp}"@p}8Op}Sp}Ap}Sp}áAp} S}>p~üÿÿÿ#? p~ Sp~"@ p~8P p~ Sp~AS~>p~ A&AOù<‡€A püÿÿÿ#?pSp"@p8OpSpASp  S>pƒüÿÿÿ#? pƒ SpƒA pƒ Spƒ6A pƒ Sƒ>&ƒAPƒ&…AP…&‡AP‡ %s: fin-‰;0> al rxctlp‰üÿÿÿ#? p‰ S‰>~?&.safep‰àÿÿÿ&?p‰Ap‰Sp‰>)Dp‰Sp‰ =p‰Sp‰àÿÿÿ&?p‰ S‰ =WŠO : %#x %-Ž;@> s: ether-Ž;H> : phy %#-Ž;P> x addr pŽApŽSpŽ>?DpŽSpŽ =pŽSpŽ"@pŽ8OpŽ SŽ =pA WAXDpSp  ~?'ip øÿÿÿ'?p"@ a QsHOpS =pøÿÿÿ'? W>]Dp‘S‘ =p“A£“£“~>(asixbreadܘ(>(A~@)ep˜)@ ~@*bpp˜*@ pžÄR &Ÿ AOŸb %02x s-¦;`> hort frap¦>_Dp¦SL·áP=-werrstr¦-=&§=AO§‰<-§;h> me%s: a-§;p> sixbread-§;x> got %d p§Ap§Sp§>kDp§Sp§ =p§Sp§ôÿÿÿ+?p§Op§ S§ =p¨ôÿÿÿ+?p¨AOp©A£©p«Qs«O «ÿA¬«Ap«Q s«P «ÿA ¬«A ‡« p«Q s«P «ÿA ¬«A ‡« p«Q s«P «ÿA ‡« p« ¬ÿÿAp¬ p­ Í­A ­ÿÿA„® ®ÿÿA&® O®°<-±;€> bytes b-±;ˆ> ad usb p-±;> acket hep±>‡Dp±S±-=p²ôÿÿÿ+?p²AOp³A£³ µAQ&¶ AM¶¶<&¶ êAR¶¶ adersho-¸; > rt framep¸>Dp¸S¸-=W¸À<-º;¨> long frpº>©DpºSº-=&»=AO»Ë<-»;°> ame%s: -»;¸> asixbrea-»;À> d %r (%lp»Ap»Sp»>´Dp»Sp» =p»Sp»üÿÿÿ.?p» S» =p¼ôÿÿÿ+?p¼AOp½A£½p¿  ¿ŒA p¿ TpÀTpÀSpÀQpÀSpÀ üÿÿÿ.?pÀ SL4!Ù¾=/memmoveÀ/=pÀôÿÿÿ+? pÀ*@ pÀüÿÿÿ.? pÁ Rp  ÂA  Tpà  ÃA Öà TpÄR£Ä£Ä~>0asixbwriteÜÈ0> ApÈ*@ &Í=AOÍô<-Í;È> d) %s: -Í;Ð> asixbwri-Í;Ø> te %d bypÍApÍSpÍ>ÌDpÍSpÍ =pÍSpÍTpÍ SÍ =pÍ*@ pÎTÖÎ  ÎôÿÿÿA&΀AUÎú tes bp--Î;è> >rp - bp-Î;ð> ->data >-Î;ø> = HdrsizpÎ>åDpÎSL¼ì?;=1_assertÎ1=pÎ*@ ÏÿÿATpÐT¬ÐA„Ð ÐÿÿApÐT ‡Ð pÐ ÖÑATpÒToÒ OpÒ ÍÒApÒT oÒPpÒ ÍÒApÒT oÒPpÒ ÍÒApÒT oÒP ÓATpÔTÇÔpÔ)@ pÔ0P pÔP pÔ ðÿÿÿ&?:Ôðÿÿÿ&?&Ô AXÔ0 e%s: as-Ù;> ixbwrite-Ù;> wrote %-Ù;> ld bytespÙApÙSpÙ>DpÙSpÙ =pÙS~?npÙ øÿÿÿ?pÙ  SÙ =pÙøÿÿÿ? &Ú AQÚJasixpromiscuousÜà>A&ä=AOäY<-ä; > %s: ai-ä;(> xprompis-ä;0> cuous %dpäApäSpä>"DpäSpä =päS~@onpä@pä Sä =på)@ på(P på Så>på &æ@AOæb<‡çA Wçc< éþÿÿÿA pê)@ pê(P pê SpêA pê Spê S~>asixsetê>£ê£ê~>asixmulticastÜî>Apõ)@ põ(P põ Sõ>põ)@ põ pö”R&öAOöy<‡÷A ~?rxctlp÷ üÿÿÿ?W÷{< ùýÿÿÿA pù üÿÿÿ?~=etherdebug&ú=AOúˆ<~> .string-ú;8 > %s: as-ú;@ > ixmultic-ú;H > ast %d púApúSpú>: DpúS~= argv0pú =púSpú”Rpú S~= fprintú =pú)@ púüÿÿÿ? pû(R pû SpûA pû Spû Sû>£û£û~> asixfreeÜÿ >A&=AOœ<-;P > %s: aixf-;X > ree %#p pApSp>P DpSp =pSp"@p S =p"@pÄOpSL0f‹j= free =p"@pAÄO£LœéVB=asixresetÜ=Ap"@ p (T LN¼uÍ=cinfop =D W «p= p = &APË<& AOÉ<-;` > %s: ini-;h > t failedpApSp>a DpSp S =pÿÿÿÿA£& AOÓ<-;p > : %r %s-;x > : asix r-;€ > eset donpApSp>v DpSp S =p\A p SpA p SL;ø„=emallocz=p"@ pÄQp>(D p ¨Qp>0D p ¬Qp> D p ÀQp>D p ´Qp>D p ¸QpdAQpA£W¨ e 5 >AIúcdc.8 1287564422 0 0 664 2072 ` ~EokclassÜH>A~@ifacepH@ pJQ JÿA &J AXJ getmacÜN>$A~@etherpV@pV(OpVO~?udpVøÿÿÿ?~?ipXAüÿÿÿ?WX&YAXY*£upvÿÿÿÿA£v£vIvkb.8 1287564422 0 0 664 24762 ` ~Esctab-y;>A-y;>0A-y;>.A-y;> A-z;>A-z; >!A-z; >"A-z; >#A-z; >A-z; >$A-z;>%A-z;>&A-{;>2A-{;>1A-{;>A-{;>A-{;>A-{;>A-{;>A-{;>A-|;>A-|;>/A-|;>A-|;>-A-|;>A-|;>,A-|;>A-|;>A-}; >A-};!>A-};">A-};#>A-};$>A-};%> A-};&> A-};'> A-~;(>A-~;)>A-~;*>A-~;+>A-~;,>9A-~;-> A-~;.> A-~;/>A-;0>A-;1>+A-;2>+A-;3>'A-;4>(A-;5>)A-;6>3A-;7>4A-€;8>5A-€;9>:A-€;:>;A-€;;><A-€;<>=A-€;=>>A-€;>>?A-€;?>@A-;@>AA-;A>BA-;B>CA-;C>DA-;D>WA-;E>XA-;F>cA-;G>FA-‚;H>wA-‚;I>RA-‚;J>GA-‚;K>IA-‚;L>SA-‚;M>OA-‚;N>QA-‚;O>MA-ƒ;P>KA-ƒ;Q>PA-ƒ;R>HA-ƒ;S>EA-ƒ;T>5A-ƒ;U>7A-ƒ;V>JA-ƒ;W>NA-„;X>A-„;Y>OA-„;Z>PA-„;[>QA-„;\>KA-„;]>LA-„;^>MA-„;_>GA-…;`>HA-…;a>IA-…;b>RA-…;c>SA-…;d>VA-…;e>A-…;f>tA-…;g>uA-†;h>UA-†;i>YA-†;j>ZA-†;k>[A-†;l>\A-†;m>]A-†;n>^A-†;o>_A-‡;p>xA-‡;q>yA-‡;r>zA-‡;s>{A-ˆ;>qA-‰;€>sA-‰;>rA-‰;…>|A-•;à>A-•;á>*A-•;â>8A-•;ã>}A-•;ä>aA-•;å>6A-•;æ>dA-•;ç>~A-–;í>sA-–;î>rA-–;ï>qA~>.string-Ÿ;> #Ι/kbin~>kbdin-Ÿ;>>D- ;>ÿÿÿÿA-¥;> #m/mous~>ptrin-¥;>> D-¦;>ÿÿÿÿA~>setbootprotoܬ>,A~@fp¬@ p°!A p±Tp±O~@eidp±@ a± Op±pOp±Op±Op²T p² Sp² Sp² A p² Sp²A Sp²Sp²ASp²ASLïûS|=usbcmd²=£²£²~> recoverkbܺ >Ap¾@p¾Op¾ Op¾SLÃ)»= close¾ =-¿;> einresep¿@p¿Op¿Sp¿>Dp¿SL€$ö= devctl¿ =pÀA WÀ'WÄ%kbfatalÜË>A~@stspË@ &Ï AOÏL<-Ð;> tkb: fa-Ð; > tal: %s pÐApÐSpÐ>DpÐSpÐ SLJ”§Š=fprintÐ=~@kdpÐ@ WÐR<-Ò;(> kb: exipÒApÒSpÒ>)DpÒSÒ=pÒ@ pÓ P&ÓAOÓ[ ting depÚüÿÿÿ?pÚSpÚ>6DpÚSÚ =pÛüÿÿÿ?pÛSÛ=pß@pßSL¼ì?;=threadexitsß=£ß~>scaleÜã>Apã@ ~@xpã@ påA &ç APçzsethipriÜ>@A-;8> tach/pr-;@> oc/%d/ctLçGÂI=getpid=~?.safepÔÿÿÿ?~?fnaâÿÿÿ?pSpApSp>=DpSpÔÿÿÿ?p SLD$s5=snprint=a âÿÿÿ? p  Sp A p  SLO׿®=open =& AP ±<£ - ;H> lpri 13~?fdp Üÿÿÿ?p Sp >JDp S =p Üÿÿÿ?p S  =£ ~> maptab$11-; >A-; >A-; >A-; >A-; >A-; >A-; >A~>!ptrworkÜ!>¸A~@"ap"@ pA~?#nerrspäÿÿÿ#?~?$hipriplÿÿÿ$?pPp O~?%ptrfdpìÿÿÿ%?pPpO~?&mfdpèÿÿÿ&?pPpO&AUÏ<~?'fp pÿÿÿ'?pPpO& AQÏ weird m- ;X> ouse maxp  pÿÿÿ'?p  Sp >QDp S >WH×p$pÿÿÿ'? p%ìÿÿÿ%? p% Sa%Äÿÿÿ(? p% Sp%Q p%P p% SL pktf->d-&;h> ev != nip&>dDp&SL¼ì?;=,_assert&,=p&pÿÿÿ'? p'Q&'AO'û lf->ep p'>rDp'S',=p'pÿÿÿ'? &(ðÿÿÿ+?AP( != nilk-);€> b: mouse-);ˆ> : %s: re-);> ad: %r p)Ap)Sp)>Dp)Sp)Qp)Op)S)=p)pÿÿÿ'? C*äÿÿÿ#?p*äÿÿÿ#?&*AP*W,Õ<&/ðÿÿÿ+?AQ/p0pÿÿÿ'? &1ðÿÿÿ+?AP1~?.xp4üÿÿÿ.?p5pÿÿÿ'? p5 Sr5Æÿÿÿ(? p5 S5>p5 W5/p: &;ðÿÿÿ+?AS;8A ~>/kbdebug&?/>AS?P<-@;˜> kb: m%11-@; > d %11d %p@Ap@Sp@>˜Dp@Sp@üÿÿÿ.?p@S~?0yp@ øÿÿÿ0?p@  S~?1bp@ ôÿÿÿ1?p@ S@=p@øÿÿÿ0? p@ôÿÿÿ1? -A;¨> 11d m%1-A;°> 1d %11d ~?mbufaAtÿÿÿ?pASaAÄÿÿÿ?pASpA>­DpASpAüÿÿÿ.?pA SpA SpA SL¦`o=seprintA=aBtÿÿÿ? pB SLÍ V=strlenB=pBdÿÿÿ?pBèÿÿÿ&? pB SaBtÿÿÿ? pB SpBdÿÿÿ? pB SL.string-C;¸> %11dmou-C;À> sein i/opCpÿÿÿ'?pCSpC>½DpCSC>&Dlÿÿÿ$?AXDq<E>pFAlÿÿÿ$?WFÕ<£F~>stoprepeatÜL> A~@fpN@pN OpNSpN­Þ­ÞApNSLMóV==sendulN=£N~> startrepeatÜR >A~@ scoR @ ~@ esc1%V @AOV„ putscanÜ^ >Ao^ @ ~? so`àAþÿÿÿ ?o`Aÿÿÿÿ ?sb &bAAXb•< cA/>£dsf &fBAXfš£h&j/>AOjª<-k;È> sc: %x pkApkSpk>ÉDpkS~@esc%k@AOk¤repeatprocÜt>0Ap€"@ p P~?repeatcpøÿÿÿ?p‚Pp‚O~?kbdinfdp‚ôÿÿÿ?pƒ­Þ­ÞA W„Î<&… ï¾ï¾AX…Ñp•A W•ä %x aborp™>ÔDp™S~=threadexits™=£™~>putmodÜ¡>A~@masko¡ @ ~@modss¤@s¤  ¤ &¤AO¤<~@omodss¤@s¤  ¤ &¤AO¤o¥ @ s¦@s¦  ¦ &¦AX¦,£§~>"putkeysܳ">0Ap¹@p¹Op¹O ~?#fdpº ðÿÿÿ#?pº S~@$bufpº$@sºOpºS~@%obufpº%@sºOpºSpºApº SpºASpºApºSº>p»ðÿÿÿ#?p»Sp»$@s»Op»Sp»%@s»Op»Sp»Ap» Sp»ASp»*Ap»S»>p¼ðÿÿÿ#?p¼Sp¼$@s¼Op¼Sp¼%@s¼Op¼Sp¼ Ap¼ Sp¼ASp¼6Ap¼S¼>p½ðÿÿÿ#?p½Sp½$@s½Op½Sp½%@s½Op½Sp½Ap½ Sp½ASp½8Ap½S½>p¾ðÿÿÿ#?p¾Sp¾$@s¾Op¾Sp¾%@s¾Op¾Sp¾@Ap¾ Sp¾Ap¾Sp¾8Ap¾S¾>p¾%@~@&np¾ &@ pÁAWÁˆ'sctab Æ>'DsÆOoÆ pÇðÿÿÿ#?pÇSsÇ  &Ç GARÇ®oÇ(@ pÈ@pÈSsÈ  &È GARÈÁpÈ%@pÈüÿÿÿ?pÈ &@ WÈ…<~?)ukoÍA÷ÿÿÿ)?pÎAWÎÒ'DsÓOoÓ pÔðÿÿÿ#?pÔSsÔ  &Ô GARÔöpÔ%@pÔüÿÿÿ?pÔ &@ WÔÏ<%×÷ÿÿÿ)?AO× oÙA(@sÛ(@£Û£Û~>*kbdbusyÜß*>Apß&@pß$@ pãA Wã+kbdworkÜê+>4A~@,apï,@ pñPpñ O~?-kbdfdpñôÿÿÿ-?póPpóO&óAUó;<~?.fpó èþÿÿ.?póPpóO&ó@AQó; tedweir-ô;à> d maxpktpô èþÿÿ.?pô Spô>ÜDpôS~>/kbfatalô/>pöA pö SpöASLËÖô=0chancreateö0=pöèþÿÿ.? pö Qp÷ Q&÷AX÷N<-ø;è> chancre-ø;ð> ate failpø Spø>éDpøSø/>pøèþÿÿ.? pú>DpúSpú Spú€ApúSLS]Å)=1proccreateú1=~?lbufaûoÿÿÿ?pûSpûASpû@ApûS~=memsetû=püA~?nerrspüðÿÿÿ?~?dkoüïÿÿÿ?W`.string-;ø> edf->de-;> v != nilp>ûDpS~= _assert =pèþÿÿ.?pO&AO} f->ep !p> DpS =&üÿÿÿ?AP¢<~? erraïþÿÿ ?pSp€ApSL2~ï*= rerrstr =-;> = nilkb-;> : %s: re-; > ad: %s pApSp>DpSpèþÿÿ.?pOpOpSaïþÿÿ ?p S~= fprint =aïþÿÿ ? p Sp>(D p SLi})ì= strstr =&AOrecoverkb>W^<& üÿÿÿ?AQ ¨& üÿÿÿ?AP «&AO´kbdebug&>AQ¹ babblek-;0> bd mod %pApSp>/DpSs¯ÿÿÿ?pS =pA WÅ x: kc %pApSp><DpSp øÿÿÿ?s ¯ÿÿÿ?pS =pøÿÿÿ? WÂCDpS =pèþÿÿ.? p Sa¯ÿÿÿ? p Saoÿÿÿ? p Spèþÿÿ.? pP pP p  Ssïÿÿÿ? p S">soïÿÿÿ?aoÿÿÿ?pSa¯ÿÿÿ?pSpüÿÿÿ?pSL4!Ù¾=memmove=pAðÿÿÿ?W^<£~>freekdevÜ>Ap!,@~?kdp!üÿÿÿ?p"üÿÿÿ?p"O&"AO" <~>inlckp#>Dp#SL+l=qlock#=p#üÿÿÿ? p$Q /$Pp$P&$AX$Dp(SL+l=qunlock(=&*=AO*<-*;@> x frep*Ap*Sp*>EDp*S* =p+üÿÿÿ?p+SL0f‹j=free+=£+~>kbstartÜ/>Ap3>Dp3S3=~@inp3@ p4Q&4AP41 ekdev k-7;P> b: %s: %p7Ap7Sp7>ODp7Sp7Qp7S7 =p8>Dp8S8=£9C<Qp=>Dp=S==p>A p> Sp>A p> SL;ø„=emallocz>=~@dp>@ p> Rp?>D p? $Rp@@ p@ OpA OpBüÿÿÿ?pBS~@eppB@ pBP pB S~>setbootprotoB>pB@ &BAPBR<-C;X> r kb: %-C;`> s: bootp-C;h> roto: %rpCApCSpC>[DpCSpCQpCSC =£DpFüÿÿÿ?~@ accelpF @ pF OpG SpG@ pGP pG SLøW V=!openepG!=pGüÿÿÿ? pGQpHQ&HAXHk<-I;p> kb: %s-I;x> : openep-I;€> %d: %r pIApISpI>rDpISpI@pIOpISpI@pIOpI SI =£JpLQ pL SpLAS~="opendevdataL"=&LAPL<-M;ˆ> kb: %s:-M;> opendev-M;˜> data: %rpMApMSpM>‰DpMSpMüÿÿÿ?pMOpMOpMSM =pNüÿÿÿ?pNOpNS~=#closedevN#=pOüÿÿÿ?pOAO£PpS@pSSLO‘{Õ=$increfS$=~@%fpT %@pTSpTüÿÿÿ?pTSpT€ApTST1=£T~>&usageÜX&>A-Z; > usage:-Z;¨> usb/kb -Z;°> [-dkm] [-Z;¸> -a n] [-pZ>¢DpZSL·áP='werrstrZ'=p[ÿÿÿÿA£[£[Lé›pZ=(kbmainÜ_(=DA~@)argvp_)@ peA~?*penapeôÿÿÿ*?~?+kenapeøÿÿÿ+?~?,accelpfAðÿÿÿ,?pg@pgO~?-devidpgìÿÿÿ-?Lzaò=.argv0&h.=AXh£ÆD pj àÿÿÿ1?rjQ %j AOjßL)¡L=abortj=pjA~?.safepjÐÿÿÿ?pjÐÿÿÿ? pj SpjASpjASLB]wQ=strtolj=pj)@ pjàÿÿÿ1? pjðÿÿÿ,?Wk×Wn× N nb]px>ÇD px àÿÿÿ1?rxQ %x AOxx=pxApxÐÿÿÿ?pxÐÿÿÿ? px SLz“€8=atoix=px)@ pxàÿÿÿ1? pxìÿÿÿ-?Wy×<{&>£{w{Úÿÿÿ0?&{dAQ{!£~p@pO~?udpèÿÿÿ?p‚@p‚A O&ƒ=AOƒ><-ƒ;È> kb: main-ƒ;Ð> : dev %s-ƒ;Ø> ref %ldpƒApƒSpƒ>ÈDpƒSpƒ@pƒOpƒSpƒ@pƒOpƒ Sƒ =p„A W„C kbdinp‰> Dp‰S~> kbdworkp‰> Dp‰ Sp‰ðÿÿÿ,?p‰S‰>p‰üÿÿÿ? p‰äÿÿÿ? &Šôÿÿÿ*?AOŠl ptrinpŒ> DpŒS~> ptrworkpŒ> DpŒ SpŒðÿÿÿ,?pŒSŒ>pŒüÿÿÿ? WŒ@ .string-Ž;à > ~>sctab5Ž>A5Ž>A5Ž > A5Ž > A5Ž>A5Ž >èA~>maptab$115Ž>AIŽftdi.8 1287570388 0 0 664 31616 ` ~E~E;h=A->;l=ÀðA-?;t=A-?;x=òA-@;€=R A-@;„=!A-A;Œ=R A-A;=!A-B;˜=R A-B;œ=!A-C;¤=R A-C;¨=!A-D;°=R A-D;´="A-E;¼=R A-E;À=!"A-F;È=R A-F;Ì="A-G;Ô=R A-G;Ø=""A-H;à=R A-H;ä="A-I;ì=R A-I;ð=#"A-J;ø=R A-J;ü=$A-K;=R A-K;=!$A-L;=R A-L;=1$A-M;=R A-M; =A$A-N;(=R A-N;,=$A-O;4=R A-O;8="$A-P;@=R A-P;D=2$A-Q;L=R A-Q;P=B$A-R;X=R A-R;\=$A-S;d=R A-S;h=#$A-T;p=R A-T;t=3$A-U;|=R A-U;€=C$A-V;ˆ=R A-V;Œ=(A-W;”=R A-W;˜=!(A-X; =R A-X;¤=1(A-Y;¬=R A-Y;°=A(A-Z;¸=R A-Z;¼=Q(A-[;Ä=R A-[;È=a(A-\;Ð=R A-\;Ô=q(A-];Ü=R A-];à=(A-^;è=R A-^;ì=(A-_;ô=R A-_;ø="(A-`;=R A-`;=2(A-a; =R A-a;=B(A-b;=R A-b;=R(A-c;$=R A-c;(=b(A-d;0=R A-d;4=r(A-e;<=R A-e;@=‚(A-f;H=R A-f;L=(A-g;T=R A-g;X=#(A-h;`=R A-h;d=3(A-i;l=R A-i;p=C(A-j;x=R A-j;|=S(A-k;„=R A-k;ˆ=c(A-l;=R A-l;”=s(A-m;œ=R A-m; =ƒ(A-n;¨=Í A-n;¬=A-o;´=9 A-o;¸=!A-p;À=A-p;Ä=xúA-q;Ì=A-q;Ð=PøA-r;Ø=A-r;Ü=püA-s;ä=A-s;è=qüA-t;ð=A-t;ô=rüA-u;ü=A-u;=süA-v;=A-v; =èA-w;=A-w;= èA-x; =A-x;$= èA-y;,=A-y;0= èA-z;8=A-z;<= èA-{;D=A-{;H= èA-|;P=A-|;T=èA-};\=A-};`=èA-~;h=A-~;l=ˆèA-;t=A-;x=‰èA-€;€=A-€;„=ŠèA-;Œ=A-;=‹èA-‚;˜=A-‚;œ=ŒèA-ƒ;¤=A-ƒ;¨=èA-„;°=A-„;´=ŽèA-…;¼=A-…;À=èA-†;È=A-†;Ì=[ûA-‡;Ô=A-‡;Ø=ZûA-ˆ;à=A-ˆ;ä=XûA-‰;ì=A-‰;ð=nðA-Š;ø=A-Š;ü=ÈæA-‹;=A-‹;=oðA-Œ;=A-Œ;=YûA-;=A-; =\ûA-Ž;(=A-Ž;,=]ûA-;4=A-;8=^ûA-;@=A-;D=_ûA-‘;L=A-‘;P=hðA-’;X=A-’;\=iðA-“;d=A-“;h=jðA-”;p=A-”;t=kðA-•;|=A-•;€=lðA-–;ˆ=A-–;Œ=mðA-—;”=A-—;˜=ðàA-˜; =A-˜;¤=ñàA-™;¬=A-™;°=òàA-š;¸=A-š;¼=óàA-›;Ä=A-›;È=ôàA-œ;Ð=A-œ;Ô=öàA-;Ü=A-;à=èàA-ž;è=A-ž;ì=éàA-Ÿ;ô=A-Ÿ;ø=HôA- ;=A- ;=IôA-¡; =A-¡;=JôA-¢;=A-¢;=KôA-£;$=A-£;(=LôA-¤;0=A-¤;4=ÐùA-¥;<=A-¥;@=ÑùA-¦;H=A-¦;L=ÐúA-§;T=< A-§;X=A-¨;`=< A-¨;d=A-©;l=”A-©;p=A-ª;x=”A-ª;|=A-«;„=A-«;ˆ=€öA-¬;=A-¬;”=`ýA-­;œ=VA-­; =¬A-®;¨=VA-®;¬=¬A-¯;´=VA-¯;¸=¬A-°;À=A-°;Ä= åA-±;Ì=A-±;Ð=rƒA-²;Ø=A-²;Ü=ÀóA-³;ä=A-³;è=ÁóA-´;ð=A-´;ô=ˆÓA-µ;ü=A-µ;=‰ÓA-¶;=A-¶; =ŠÓA-·;=A-·;=‹ÓA-¸; =A-¸;$=ŒÓA-¹;,=A-¹;0=ÓA-º;8=A-º;<=ŽÓA-»;D=A-»;H=ÓA-¼;P=BA-¼;T=A-½;\=A-½;`=HåA-¾;h=A-¾;l=èîA-¿;t=A-¿;x=éîA-À;€=A-À;„=êîA-Á;Œ=A-Á;=ëîA-Â;˜=A-Â;œ=ìîA-Ã;¤=A-Ã;¨=íîA-Ä;°=A-Ä;´=îîA-Å;¼=A-Å;À=ïîA-Æ;È=A-Æ;Ì=ˆìA-Ç;Ô=A-Ç;Ø=‰ìA-È;à=îÞA-È;ä=A-É;ì=A-É;ð=(ßA-Ê;ø=A-Ê;ü=0ßA-Ë;=A-Ë;=2ßA-Ì;=A-Ì;=1ßA-Í;=A-Í; =3ßA-Î;(=F A-Î;,= A-Ï;4=F A-Ï;8=! A-Ð;@=: A-Ð;D=A-Ñ;L=A-Ñ;P= ÿA-Ò;X=A-Ò;\=êA-Ó;d=A-Ó;h=ÜA-Ô;p=A-Ô;t=ÜA-Õ;|=A-Õ;€=ˆúA-Ö;ˆ=A-Ö;Œ=ÐÇA-×;”=A-×;˜=‘ÉA-Ø; =& A-Ø;¤=A-Ù;¬=PPA-Ù;°=A-Ú;¸=A-Ú;¼= ÝA-Û;Ä=`A-Û;È=`A~>ftdireadÜæ>0A~@reqpæ @ ~@ppæ@ pëP~?serpëøÿÿÿ?&í AOí .string-ï;> serial: -ï;> ftdiread-ï;> %#p [%d-ï;> ] req: %-ï; > #x val: -ï;(> %#x idx:-ï;0> %d buf:%pïApïSpï>DpïSpï SpïÈPpï Spï S~@ valpï @pïSpï@pïS~@ bufpï @pïSLJ”§Š= fprintï =pï @ pñøÿÿÿ? pñP pñ SpñÀA pñ Spñ Spñ @ pñ  Spñ@ pñ Spñ @ pñ SpñA pñ SLïûS|= usbcmdñ =pñ &ò=AOò6<-ò;8> p seria-ò;@> l: ftdir-ò;H> ead res:pòApòSpò>;DpòS~? respò üÿÿÿ ?pò Sò =pòüÿÿÿ ? pó £ó£ó~>ftdiwriteÜ÷>,Ap÷@ püPpüøÿÿÿ?pþÈPCþ‡þ@&ÿ=AOÿP<-ÿ;P> %d seri-ÿ;X> al: ftdi-ÿ;`> write %#-ÿ;h> p [%d] r-ÿ;p> eq: %#x -ÿ;x> val: %#x-ÿ;€> idx:%d pÿApÿSpÿ>TDpÿSpÿ SpÿÈPpÿ Spÿ @pÿSpÿ @pÿSpÿ@pÿSÿ =p øÿÿÿ? p P p  Sp @A p  Sp  @ p  Sp  @ p   Sp @ p  Sp ASp AS  =p  & =AO i<- ;ˆ> serial:- ;> ftdiwri- ;˜> te res:%p Ap Sp >‰Dp Sp  üÿÿÿ ?p  S  =p üÿÿÿ ? p  £ £ ~>ftmodemctlÜ >Ap @ ~@set& @AX yp A£ p AxPp  Sp ASp Ap Sp Ap  S >p A£ £ ~>ft232ambaudbase2divÜ > A~@basep @& €A² ÿÿÿÿA¯ AÇ ~@baud: @p   A& AX ft232ambaud2divÜ2 > Ap4 @ p4  Sp4 lÜA p4  S4 >w4 £4 £4 ~>divfrac-7 ;>A-7 ;>A-7 ; >A-7 ;>A-7 ;>A-7 ;>A-7 ;>A~>ft232bmbaudbase2divÜ: > Ap? @&? €A²? ÿÿÿÿA¯? AÇ? :? @p?  ¯@ Ap@   @ A p@  > ¬@ A ‡@  p@  &C AXC Âft232bmbaud2divÜK > ApM @ pM  SpM lÜA pM  SM >£M £M ~>customdivÜQ > A~@serpQ @ pS PpS OpS O&S AXS Ü d seria-X ;¨> l: weird-X ;°> custom -X ;¸> divisor pX ApX SpX >£DpX SX  =pY A£Y £Y ~>ftbaudcalcdivÜ] >Ap] @ p] @ &b  –AXb pb @ pb @ pb  &b AXb w p  W Kw’ p’  W“  <&™  ÀÆ-AQ™ Rpš  Wš Vpœ  W  pŸ  W   ftsetparamܦ >$Ap¦ @ ~?valq¬ Aúÿÿÿ?p­ tQ&­ AX­ y<ˆ® Aúÿÿÿ?W® ‚ serial:-Å ;È> setparapÅ ApÅ SpÅ >ÁDpÅ SÅ  =pÅ @ pÇ  SwÇ úÿÿÿ? pÇ  SpÇ ASpÇ A pÇ   SÇ >pÇ @ &È APÈ ¯<£É pË  SpË xQ pË  SË >pË @ &Ì APÌ ·<£Í pÏ Q pÏ  SpÏ pQ pÏ  SÏ >pÐ @ pÐ  SpÐ SpÐ  ÍÐ A Ð A pÐ  SpÐ A pÐ   SÐ >pÐ  &Ò =AOÒ Ñ<-Ò ;Ð> m seria-Ò ;Ø> l: setpa-Ò ;à> ram res:pÒ ApÒ SpÒ >ÓDpÒ SpÒ  üÿÿÿ ?pÒ  SÒ  =pÒ üÿÿÿ ? pÓ  £Ó £Ó ~>ftgettypeÜØ >,ApØ @ ~?pkszpÞ @Aðÿÿÿ?~?baudbasepà 6nAìÿÿÿ?~? outhdrszpá Aøÿÿÿ ?pâ Tpâ Opâ  Opã Tpã Opã 0Opä ATTpå A Wå å %d ser- ;ð> ial: war- ;ø> ning: dn- ;> o %d too- ;> low for- ;> multi-i- ;> nterface- ; > device p Ap Sp >íDp Sp S  =p @ W <& AP  serial:- ;0> detecte- ;8> d type: p Ap Sp >)Dp Sp Tp S  =£ LÖ“:=!ftmatchÜ !=TAp =D W < %#x vid- ;H> %#06x d- ;P> id %#06x~?"bufa Êÿÿÿ"?p Sp 2Ap Sp >EDp Sp Pp  S~?#ipp  üÿÿÿ#?p Pp SLD$s5=$snprint $=&! =AO! V<-! ;X> serial:-! ;`> %s %s p! Ap! Sp! >YDp! Sa! Êÿÿÿ"?p! S~@%infop! %@p!  S!  =p" %@ p"  Sa" Êÿÿÿ"? p"  SLi})ì=&strstr" &=p" üÿÿÿ#? &" AO" k<&# @AO# ip& @p& SL+l=(qunlock& (=p( A£( W( 9)ftuseinhdrÜ/ )>A~@*bp/ *@ p/ @ s1 Q 1 A&1 AO1 x A PW> Ž+ftsetouthdrÜN +>ApN @ pP Q P ,ApP O&P AOP ±-wait4dataÜV ->Ap[ @p[ O ~?.serp]  øÿÿÿ.?p]  S] (=p^ @ p^ ÌP p^  Sp^ A p^  SLMóV==/sendul^ /=~?0dp^ üÿÿÿ0?p_ øÿÿÿ.?p_ S_ '=~@1countp_ 1@ p_ @ &` üÿÿÿ0?AQ` Ì count >=ph >hDph SL¼ì?;=_asserth =ph 1@ ph @ pi ØQ&i AUi à 0p->nd-i ;x> ata >= 0pi >sDpi Si =pi 1@ pi @ ~@datapj @pj Spj   j ÜApj Spj  SL4!Ù¾=memmovej =pj @ pk ØR&k AOk ûwait4writeÜs >$A~@ppy @py O p{  ðÿÿÿ.? { ,A p{ P p{ 1@ {   p{  Sp{ A p{  SL;ø„=emallocz{ =p| @ p|  S~?bp| ôÿÿÿ?p| Sp| 1@ p|  S| +>p} ôÿÿÿ? ~? offp} üÿÿÿ ?a}  Op} Sp} @p} Sp} 1@p} S} =p @p Op  O~? fdp øÿÿÿ ?p€ ðÿÿÿ.?p€ S€ (=p øÿÿÿ ? p  Sp ôÿÿÿ? p  Sp 1@ üÿÿÿ ? p  SL shutdownchanÜ”  >AW˜ :p¦ ðÿÿÿ?p¦ @ p¦ @ p¦ üÿÿÿ? p§  Ö§  &§ S§ iepreaderܳ >dA~>.string-½ ;€> epreadep½ >Dp½ SL·áP=threadsetname½ =~@up¾ @ p¿ P ~?ppÀ  ¸ÿÿÿ?pÀ Q~?serpÀ ¼ÿÿÿ?pÁ P~? cpÁ Äÿÿÿ ?p  S  =pÄ ¼ÿÿÿ?pÄ SÄ '=pÅ ¸ÿÿÿ?pÅ  OpÅ  O~?!dfdpÅ üÿÿÿ!?pÆ ¼ÿÿÿ?pÆ SÆ (=pÈ A Wå ­ r proct-å ;> imed out&å  APå ­<&å  A~?"rcountpå  øÿÿÿ"?På ¬<~?#erraå Ìÿÿÿ#? på  Spå >D på  Så &=~?$pkpå Àÿÿÿ$? på øÿÿÿ"? &å AOå ¬ %d %#uxpÎ ApÎ SpÎ >™DpÎ SpÎ  øÿÿÿ"?pÎ  SpÎ ¸ÿÿÿ?sÎ ÜOpÎ  SpÎ ¸ÿÿÿ?sÎ ÝOpÎ S~='fprintÎ '=pÎ Àÿÿÿ$? pÎ øÿÿÿ"? &Ð  APÐ × %#ux %s-è ;¨> : error -è ;°> reading -è ;¸> %s: %r pè Apè Spè >¦Dpè SLzaò=)argv0pè )=pè Spè ¸ÿÿÿ? è Apè  Sè '=pè Àÿÿÿ$? pé  Sé  =pê Äÿÿÿ ?pê Spê ASLD+fº=*nbsendpê *=pê ¸ÿÿÿ? pë ÌP&ë AOë ÀDpï SL€$ö=,devctlï ,=pð ¼ÿÿÿ?pð Opð SLM½D=-closedevð -=pñ ¸ÿÿÿ? ñ Apñ SLv<&û=.usbfsdelñ .=£ñ ~>/statusreaderÜõ />,Apþ @ pÿ  ðÿÿÿ?pÿ Ppÿ ìÿÿÿ?- ;À> detachs- ;È> tatusrea- ;Ð> der threp >ÇDp S =p A p  Sp €A p  SLËÖô=0chancreate 0=p øÿÿÿ ?p A p  Sp A p  S =p ðÿÿÿ? p  O~?1ap üÿÿÿ1?p øÿÿÿ ? p  Op ìÿÿÿ?p Op SLO‘{Õ=incref =p >Dp Sp üÿÿÿ1?p Sp @Ap SLS]Å)=proccreate =W W adseria- ;à> l: statu- ;è> s readerp Ap Sp >ÛDp Sp ØQp S '=p ðÿÿÿ? W { %d se- ;ø> rial: st- ;> atus rea- ;> der to c- ;> onsume: p Ap Sp >öDp Sp ØQp S '=p ðÿÿÿ? p ÌQ p  S~=recvul =& AP Ž- ;> %d detap ìÿÿÿ?p Op Sp >Dp S ,=p ìÿÿÿ?p Op S -=p ðÿÿÿ?  Ap S .=£ ~>ftresetÜ" > A~@serp' @ ' XA p( A W( ´ ftdiwrite*  >p* üÿÿÿ? p* øÿÿÿ? W* ± ftinitÜ/  >(A~@ pp/  @ p5 Q p6 Q&6 AO6  ftdiread7  >&8 AP8 è chpre-s-: ;(> et: late-: ;0> ncy is %p: >#Dp: Sp: øÿÿÿ ?p: SLuˆ‘=print: =p;  @p; Sp;  Ap; Sp; Ap; Sp; Ap;  S;  >p<  @ p<  Sp<  A p<  Sp< A p<  Sp< A p<   Sa< øÿÿÿ ? p<  S<  >&= AP=  ÿÿÿÿA£> -? ;8> d post--? ;@> set: lat-? ;H> ency is p? >;Dp? Sp? øÿÿÿ ?p? S? =pA  @pA SpA  ApA SpA ApA SpA  ApA  SA  >pB A£B pD PpD SD =pE >/DpE SpE  @pE SpE  ApE SLS]Å)=threadcreateE =pF A£F £F ~>ftsetbreakÜJ >ApL  @ pL  S~@val&L @AOL )£L £L ~>ftclearpipesÜP >ApS  @pS SpS ApS SpS ASpS A SS  >pT  @pT SpT ApT SpT ASpT A ST  >pU A£U £U ~>setctllineÜY >AoY @ p[  @ p[  Ss[   ¬[ A s[   ‡[   p[  Sp[ ASp[ A p[   S[  >£[ £[ ~>updatectlstÜ_ >Ap_ @ p_  @ pa ŒP&a AOa Z<†b  lPWb ^setctlÜh >Aph  @ pm Q po Ppo Opo O&o AXo l %d seri-p ;X> al: cann-p ;`> ot set l-p ;h> ines for-p ;p> this depp App Spp >TDpp Sp '=pq  @pq Spq Apq Sq >pq  @pr AœOpr A pr  ŒOps ÿÿÿÿA£s pw  Spw Apw Sw >pw  @ px  Ssx lQ ‡x A px  Sx >&y APy Š<£z p|  @p| Sp| Ap| S| >p|  @ p}  Ss} lQ ‡} A p}  S} >&~ AP~ ˜<£ p A£ £ ~>ftsendlinesÜ… >A&‰ &=AO‰ ¦<-‰ ;x> vice se-‰ ;€> rial: se-‰ ;ˆ> ndlines:-‰ ;> %#2.2x p‰ Ap‰ Sp‰ >~Dp‰ Sp‰  @s‰ lOp‰ S‰ '=pŠ  @ pŠ  SŠ >pŠ  &‹ &=AO‹ ²<-‹ ;˜> serial:-‹ ; > sendlin-‹ ;¨> es res: p‹ Ap‹ Sp‹ >™Dp‹ Sp‹  S‹ '=pŒ A£Œ £Œ ~>ftsetepsÜ >Ap•  @p• O-— ;°> %d maxpp— >´D p—  Sp—  ~?serp— øÿÿÿ? — A p— P p—  SLò¬ˆ$=smprint— =p—  p˜  @p˜  Op˜ S~?sp˜  üÿÿÿ?p˜  S˜ ,=p™ üÿÿÿ?p™ S~=free™ =~>.string-› ;¸> kt %dma-› ;À> xpkt %dp› >¾D p›  Sp› øÿÿÿ? › A p› P p›  S› =p›  pœ  @pœ Opœ Spœ  üÿÿÿ?pœ  Sœ ,=p üÿÿÿ?p S =pž A£ž £ž L#Âó=ftops-¢ ;=> D-£ ;=>D~>ftsetparam-¤ ; =>D-¥ ;=>D-¦ ;=>D-§ ;=>D~>ftmodemctl-¨ ;=>D-© ; =>D~> wait4data-ª ;(=> D~>!wait4write-« ;,=>!D~>"divfrac5« "> A~=#ftinfo5« #=ÜA5« =0A5« >ÈAI« serial.8 1287570388 0 0 664 35618 ` ~Edirtab~>.string- ;>>D- ;>m€A- ;>>D- ;>°A- ;> /eiaUe- ;>>D- ; >´A~>serialfatalÜ >AL½ÕQA=serialdebug& =AO <- ;> iaUctls- ;> erial: f- ;> atal err- ; > or, detap Ap Sp >Dp SLJ”§Š=fprint =- ;(> ching d~@serp @p Op Sp >/Dp SL€$ö=devctl =~?ip Aøÿÿÿ?W  serialdrainÜ*  >A~@ pp*  @ p/ Q p0 pQ p2 pQ&2 ÿÿÿÿAX2 E<£3 p4  ~?serp4  üÿÿÿ? 4 Ap4 O&4 AP4 MpJ øÿÿÿ? pJ @ WJ g etachde~@errpU @ pU  SpU >6D pU  SLi})ì=strstrU =pU @ &U AOU pX @ CY QpZ  SZ =&Z APZ serialctlÜa >€Aph  @ph O~?serph üÿÿÿ?pi A~?linespi Ôÿÿÿ?~?setpi Øÿÿÿ?~?drainpi Üÿÿÿ?~@cmdpj @ pj  S~?faj ”ÿÿÿ? pj  Spj A pj  SL¸#×3=tokenizej =pj  @ ~?nfpj ìÿÿÿ?pk Aôÿÿÿ?Wk ¸ tachedbpl ôÿÿÿ? pl  ”ÿÿÿ? pl  Spl >?D pl  Spl A pl  SLÃa·=strncmpl =pl  @ &l AXl Ò reakser-‘ ;H> ial: %c,-‘ ;P> unsure p‘ Ap‘ Sp‘ >EDp‘ Sp‘  S‘ =p‘  @ W’ í]DpÝ SÝ =pÞ ÿÿÿÿA£Þ Wà í<&à  lAQà ²pë  @ &ì Ôÿÿÿ?AOì Ï<&ì Øÿÿÿ?AOì Ð ctl noLzaò=(pformat-ö ;(=>^DLu‘­Þ=)serdumpstÜù )=$Apù  @ ~@*bufpù *@ pþ Tpþ ôÿÿÿ?~@+bufszp +@ a  Q- ;`> emsb%d p  S~?,ep üÿÿÿ,?p Sp >dD p  Sp pT p   SL¦`o=-seprint -=p Sp üÿÿÿ,? p  Sp >iD p  Sp  @ p ˜P p   S -=- ;h> c%d d%p Sp üÿÿÿ,? p  Sp >nD p  Sp  @ p œP p   S -=- ;p> d e%d p Sp üÿÿÿ,? p  Sp >sD p  Sp  @ p ”P p   S -=p Sp üÿÿÿ,? p  Sp >xD p  Sp  @ p €P p   S -=- ;x> l%d m%dp Sp üÿÿÿ,? p  Sp >}D p  Sp  @ p xP p   S -=p  @ p  ~?.sp øÿÿÿ.?p |R& AP ;‚D p  Sp |R p (= r  R p   S -=p  W P<- ;€> p%c pp  Sp üÿÿÿ,? p  Sp >‡D p  Sp ?A p   S -=p  - ;ˆ> %c r%d p  Sp üÿÿÿ,? p  Sp >ŒD p  Sp  @ p ŒP p   S -=p Sp üÿÿÿ,? p  Sp >‘D p  Sp  @ p tP p   S -=- ;> s%d i%p Sp üÿÿÿ,? p  Sp >–D p  Sp  @ p „P p   S -=- ;˜> d dev(p Sp üÿÿÿ,? p  Sp >›D p  Sp A S -=- ; > %d) typ- ;¨> e(%d) p Sp üÿÿÿ,? p  Sp >¥D p  Sp ôÿÿÿ? p P p   S -=- ;°> framing(p Sp üÿÿÿ,? p  Sp >°D p  Sp  @ p ¸P p   S -=- ;¸> %d) ove- ;À> rruns(%dp Sp üÿÿÿ,? p  Sp >½D p  Sp  @ p ÀP p   S -=- ;È> ) berr(p Sp üÿÿÿ,? p  Sp >ËD p  Sp  @ p °P p   S -=- ;Ð> %d) se- ;Ø> rr(%d) p Sp üÿÿÿ,? p  Sp >ÕD p  Sp  @ p ¼P p   S -=£ £ ~>/serinitÜ />Ap  @ ~?0resp Aüÿÿÿ0?p R p  Q& AO ¯1dwalkÜ* 1>,A~@fidp1 @ 1 A~?qida1 èÿÿÿ?p1 A !1 ¡1 y1 s2 ôÿÿÿ? 2 €A&2 AX2 Ï<~>.string-3 ;à> walk in -3 ;è> non-direp3 >àDp3 SL·áP=werrstr3 =p4 ÿÿÿÿA£4 -7 ;ð> ctory..~@namep7 @ p7  Sp7 >öD p7  SL´§,=strcmp7 =~@fsp7 @ p7 @ &7 AX7 à dirtabpA   > pA  SpA äÿÿÿ? A A pA  SLò¬ˆ$= smprintA  =pB @ pB  S~? dnamepB øÿÿÿ ?pB SB =pB üÿÿÿ ?pB øÿÿÿ ? &B AXB ¯E AoE ôÿÿÿ?pF @ F AaF èÿÿÿ?pF A !F ¡F yF pG  SL0f‹j= freeG  =pH A£H WH dostatÜQ > A~@pathpQ @ ~@dpQ @ aV   >pV  pW  T¯W A pW   TpX O¯X AoX TpY R pY  TpZ @pZ 4OpZ øÿÿÿ?~?tp\  üÿÿÿ?p\ R p\  Sp\ >ùD p\  S\ =p\ üÿÿÿ? p\ @ &\ AX\ ;dstatÜd >Apd @ ph   h (A ph Q ph Q „h  „h  ~@qidph @ h   ph @ h   pi  Spi  Spi @pi Si >pj @ j (A pj Ppj P pj @ ‡j Q‡j   Qpk A£k £k ~>dopenÜo >Apo @~=serialdebugpo =pt  t (A pt Q pt Q „t  „t  pt @ t A pt T pt T t   t   pu 4Vpu øÿÿÿ?W~ Œ /seria-x ;> l, opene-x ;> d data px Apx Spx >ûDpx S~=fprintx =Wy v<&{ AO{ †<-{ ;> serial, -{ ;> opened cp{ Ap{ Sp{ >Dp{ S{ =-| ; > tl l8 ip| øÿÿÿ?p| Sp| >$Dp| S~>serialctl| >W} v<&}  AO} <&}  AO} wfilldirÜ„ >A~@tabp„ @p„ @ p† @ † (A p† Pp† P ~@ip†  @ p†   ¯† A ‡†  ‡†   p†  Tp†   Tp‡ U p‡  Tpˆ T ˆ €A&ˆ AOˆ ªdirgenÜ >Ap @ C’  &“  AU“ µp• Sp•   S• >p– A£– £– ~>dreadÜž >dApž @ p©   © A~?qa© Øÿÿÿ?p© A !© ¡© y© pª @ ª (A pª Q pª Q „ª  „ª  pª   ª A pª T pª T ª   ª   ~? pathpª  ôÿÿÿ ?p« @p« 4O p¬  Ôÿÿÿ?p¬ P~?!serp¬ Ðÿÿÿ!?p® ÿA p®  Sp® A p®  SL;ø„="emallocz® "=~?#bufp® ìÿÿÿ#?p¯ ÿA p¯  Sp¯ A p¯  S¯ "=~?$errp¯ èÿÿÿ$?p° Ðÿÿÿ!?p° SL+l=%qlock° %=Wð ÍD p³  $Sp³ A(SLøHj=)usbdirread³ )=p³  '@W´ ë 1serial-¸ ;0> : readin-¸ ;8> g from dp¸ Ap¸ Sp¸ >*Dp¸ S¸ =WÝ  ata tim~?*rcount&Ý øÿÿÿ*?APÝ ED pÝ  S~=+strstrÝ +=&Ý AXÝ  ed outs-½ ;P> erial: r-½ ;X> eading: p½ Ap½ Sp½ >ODp½ Sp½  '@p½ S½ =&¿  '@AS¿ 3 %ld coup¿ >eDp¿ SL¼ì?;=._assert¿ .=pÀ Ðÿÿÿ!?pÀ DO&À AOÀ E nt > 0%pÍ èÿÿÿ$?pÍ SpÍ ÿApÍ SpÍ >oDpÍ SÍ =~>1errrun$31CÎ 1>pÏ ApÏ S~=sleepÏ =~>good$31&Ð >ASÐ d<&Ð 1>'AQÐ e r%s: li-Ó ;x> ne %s is-Ó ;€> gone: %pÓ ApÓ SpÓ >rDpÓ SLzaò=argv0pÓ =pÓ SpÓ Ôÿÿÿ? Ó ApÓ  SÓ =~>.string-Õ ;ˆ> r seria-Õ ;> l line gpÕ >‹DpÕ SL¼ì?;=threadexitsallÕ =WÕ xCÙ >&Û -=AUÛ …<&Ü =AOÜ …<-Ü ;˜> oneseri-Ü ; > al: read-Ü ;¨> : %s %ldpÜ ApÜ SpÜ >œDpÜ SpÜ èÿÿÿ$?pÜ SpÜ øÿÿÿ*?pÜ  SÜ =WÜ <&ß =AOß ‘<-ß ;°> serial-ß ;¸> : read f-ß ;À> rom bulk-ß ;È> %ld, %1pß Apß Spß >²Dpß Spß øÿÿÿ*?pß Spß èÿÿÿ$?pß  Sß =&à øÿÿÿ*?APà ¡<&á =AOá œ<-á ;Ð> 0.10s s-á ;Ø> erial: n-á ;à> eed to r-á ;è> ecover, -á ;ð> data rea-á ;ø> d %ld %rpá Apá Spá >×Dpá Spá  '@pá Sá =pã Ðÿÿÿ!?pã Spã èÿÿÿ$?pã S~=serialrecoverã =&å =AOå ª<-å ;> serial-å ;> : read f-å ;> rom bulkpå Apå Spå >Dpå Spå øÿÿÿ*?på Så =pæ øÿÿÿ*?pæ  '@Wç ë altwriteÜø  > A~@ ppø  @ pþ Q W ó %ld ti- ; > med out~? nw& üÿÿÿ ?AP òD p  S +=p tÿÿÿ!? p  @ & AX ó serial: - ;0> need to - ;8> recover,- ;@> status - ;H> in write- ;P> %d %r p Ap Sp >(Dp Sp üÿÿÿ ?p S =a xÿÿÿ$?p Sp €Ap Sp >XDp S =p  @p Op Sa xÿÿÿ$?p S =p üÿÿÿ ?£ £ ~>dwriteÜ >$A~@fsp @ p 4Q ~?pp  ôÿÿÿ?p P  (A p Q p Q „  „  ~@fidp @  A p T p T       p  üÿÿÿ ?p! ðÿÿÿ!?p! S! %=p!  '@ W6 p$  '@W% I&* AP* sopenepsÜ< >A~@pp@ @p@ OpA üÿÿÿ!?pA O pA  S~@epinpA @ pA  SLøW V=openepA =pA @ pA  QpB  Q&B AXB ¢<-C ;X> %rseria-C ;`> l: opene-C ;h> p %d: %rpC ApC SpC >[DpC SpC @pC S~=fprintC =pD ÿÿÿÿA£D pF üÿÿÿ!? pF P pF  S~@epoutpF @ pF  SF =pF @ pF QpG Q&G AXG º<-H ;p> serial-H ;x> : openep-H ;€> %d: %r pH ApH SpH >rDpH SpH @pH SH =pI @pI  OpI SLM½D=closedevI =pJ ÿÿÿÿA£J -M ;ˆ> timeoutpM  QpM SpM >‰DpM S~= devctlM  =-N ;> 1000ti-N ;˜> meout 10pN @pN OpN SpN >–DpN SN  =pN üÿÿÿ!? pP LQ&P AOP ï 00seria-S ;¨> l: opene-S ;°> p %d: %rpS ApS SpS >£DpS SpS  !@pS SS =pT @pT  OpT ST =pU @pU OpU SU =pV ÿÿÿÿA£V pX QpX SpX ASLûï="opendevdataX "=-Y ;¸> timeoupY @pY OpY SpY >ºDpY SY  =~?#serpY üÿÿÿ#? p\ Q&\ AO\ ö t 1000s-b ;È> erial: o-b ;Ð> pen i/o -b ;Ø> ep data:pb Apb Spb >ÇDpb Sb =pc @pc  Opc Sc =pd @pd Opd Sd =pe üÿÿÿ#?pe LO&e AOe *$findendpointsÜm $>8Aps ÿÿÿÿAps  ps ~@%serpz %@pz Opz Opz 0O~@&ifcpz &@ az  Opz  O z HA~?'epspz èÿÿÿ'?p| A W| A<&‰ -=AO‰ |<-‰ ;à> %r ser-‰ ;è> ial[%d]:-‰ ;ð> ep ids:-‰ ;ø> in %d o-‰ ;> ut %d inp‰ Ap‰ Sp‰ >åDp‰ Sp‰ &@p‰ S~?(epinp‰ øÿÿÿ(?p‰  S~?)epoutp‰ ôÿÿÿ)?p‰ S~?*epintrp‰  ðÿÿÿ*?p‰  S‰ =p‰ ôÿÿÿ)?p‰ øÿÿÿ(?p‰ ðÿÿÿ*? &Š ÿÿÿÿAOŠ €<&Š ÿÿÿÿAXŠ p &@ p %@ & AP › tr %d s- ;> erial: e- ;> p in %s - ; > out %s p Ap Sp >Dp Sp   = Ü A a  Rp dOp Op Sp   = Ü A a  Rp hOp Op  S =p &@ p %@ p‘ LR&‘ AO‘ Â<&’ -=AO’ Â<-’ ;(> serial: -’ ;0> ep intr p’ Ap’ Sp’ >(Dp’ Sp’   =’ Ü A a’  Rp’ `Op’ Op’ S’ =p’ &@ p’ %@ &” -=AQ” Ç<~=+serialdebug&” +=AQ” Ç %s debup•   =• Ü A a•  Rp• dOp• Sp• ><Dp• S•  =-– ;@> g 1debup– &@ =– Ü A p– %@ a–  Qp– hOp– Sp– >DDp– S–  =p– %@ p— LR&— AO— å<-˜ ;H> g 1debup˜ &@ =˜ Ü A a˜  Rp˜ `Op˜ Sp˜ >LDp˜ S˜  =p˜ %@ -™ ;P> g 1debup™ Rp™ Sp™ >TDp™ S™  =p› A£› £› ~>,usageÜ  ,>A-¢ ;X> g 1usag-¢ ;`> e: usb/s-¢ ;h> erial [--¢ ;p> dD] [-m -¢ ;x> mtpt] [-p¢ >\Dp¢ S¢ =p£ ÿÿÿÿA££ ££ ~>-serdevfreeܧ ->A~@.ap© .@~?/serp© üÿÿÿ/?&­ üÿÿÿ/?AX­ ú<£® ~?0ip° Aôÿÿÿ0?W° ÿserialfs~>dwalk-Ä ;8>>D~>dopen-Å ;D>>D~>dread-Æ ;H>>D-Ç ;L>>D~>dstat-È ;P>>D~>serialfsendÜÌ >ApÐ @pÐ 4O pÒ ÌP&Ò AOÒ B.string-è ;€> s srv]pè >‡D pè  ¸ÿÿÿ?rè Q %è  AOè ›L)¡L=abortè =pè A~?.safepè ¨ÿÿÿ?pè ¨ÿÿÿ? pè  S~=atoiè =pè  @ pè ¸ÿÿÿ? pè ¼ÿÿÿ ?Wé ‘<ë ,>£ë wë ²ÿÿÿ?&ë NAOë ”<&ë dAOë ’£î pð 4A pð  Spð A pð  S~=emalloczð =pð  @ pð  Tpð  ñ Apñ   ñ A pñ  AQpñ  A pñ  Opò   ò  Apò   ò $A pò  AQpò  A pò  Opó  Rpô >-D pô  $Tpõ ÿÿÿÿAPRpö  üÿÿÿ/?pö ATR-ø ;ˆ> vid %#06-ø ;> x did %#~?bufaø Æÿÿÿ?pø Spø 2Apø Spø >ˆDpø Spø Tpø Opø  Spø Tpø Opø S~=snprintø =aú Æÿÿÿ? pú  SLz“€8=plmatchú =pú üÿÿÿ/? &ú AXú ô 06xseri- ; > al: no s- ;¨> erial de- ;°> vices fop >œDp S~=werrstr =p ÿÿÿÿA£ p A W p A ! ¡ y p PR&  X 1& AP ><- ;¸> undseri- ;À> al: no e- ;È> ndpoints- ;Ð> found f- ;Ø> or ifc %p >¼Dp Sp Àÿÿÿ0?p S =p ÿÿÿÿA£ p A p  Sp ASLËÖô= chancreate  =p øÿÿÿ1? p ÌPp A p  Sp AS  =p Àÿÿÿ0? p üÿÿÿ/? p øÿÿÿ1? p ÐPW  dserial- ;è> : valid - ;ð> interfac- ;ø> e, calli- ;> ng serinp Ap Sp >âDp S~=$fprint $=p øÿÿÿ1? p  S~>%serinit %>p Àÿÿÿ0? p øÿÿÿ1? & AP x<& #=AO v<- ;> it seri- ;> al: seri- ;> nit: %r p Ap Sp > Dp S $=p ÿÿÿÿA£ & +=AO „<- ; > serial:- ;(> adding - ;0> interfac- ;8> e %d, %pp Ap Sp >!Dp Sp ÈPp Sp   S $=p Àÿÿÿ0? p øÿÿÿ1? p! P&! AO! ž<&" +=AO" ’<-" ;@> serial-" ;H> : HEY! J-" ;P> TAG inte-" ;X> rface %dp" Ap" Sp" >BDp" Sp"  Sp"   S" $=p" Àÿÿÿ0? p" øÿÿÿ1? -# ;`> %p jtap#   # Ap# Sp# (Ap# Sp# >eDp# Sp# ¼ÿÿÿ ?p#  Sp#  S# =W# ¶<&%  AX% «<-& ;h> g%d.%dep&   & Ap& Sp& (Ap& Sp& >oDp& Sp& ¼ÿÿÿ ?p&  S& =W& ¶<-( ;p> iaU%dei-( ;x> aU%d.%dp(   ( Ap( Sp( (Ap( Sp( >vDp( Sp( ¼ÿÿÿ ?p(  Sp(  S( =p* Ap* Sp* >€Dp* Sp* øÿÿÿ1? * Ap* S* $=p*  @ p+ øÿÿÿ1?p+  DOp,  SLO‘{Õ=&incref, &=p, øÿÿÿ1?p- HOp. >D p.  hO / Ap/ SLv<&û='usbfsadd/ '=p/ üÿÿÿ/? p/ Àÿÿÿ0? W/ U %s ~=)pformat53 )=A53 +=A~>*sdebug53 *>A~>+dirtab53 +>A~>,errrun$3153 ,>A53 >ˆA~>-good$3153 ->A53 >XAI3 prolific.8 1287570388 0 0 664 17970 ` ~E7»~E.string-¤;> vid %#06-¤;> x did %#~?bufa¤Êÿÿÿ?p¤Sp¤2Ap¤Sp¤>Dp¤Sp¤Pp¤ S~?ipp¤ üÿÿÿ?p¤Pp¤SLD$s5=snprint¤=L½ÕQA=serialdebug&¦=AO¦ <-¦;> 06xseri-¦;> al: %s %p¦Ap¦Sp¦>Dp¦Sa¦Êÿÿÿ?p¦S~@infop¦@p¦ SLJ”§Š= fprint¦ =p§@ p§ Sa§Êÿÿÿ? p§ SLi})ì= strstr§ =p§üÿÿÿ? &§AO§* dumpbufÜ° >Ap´A W´4 s buf[%-µ;(> d]=%#ux pµ>#DpµSpµ S~@ bufpµ @ ~?ipµ üÿÿÿ?sµ RpµSLuˆ‘=printµ=pµüÿÿÿ? Wµ11Dp¶S¶=£¶~>vendorreadܺ>,A~@pp¿@p¿O~?serp¿øÿÿÿ?&Á=AOÁU<-Á;0> seria-Á;8> l: vendo-Á;@> rread va-Á;H> l: 0x%x -Á;P> idx:%d bpÁApÁSpÁ>3DpÁS~@valpÁ@pÁS~@indexpÁ@pÁ SpÁ @pÁSÁ =pÃøÿÿÿ? pÃP pà SpÃÀA pà SpÃA pà SpÃ@ pà  SpÃ@ pà Spà @ pà SpÃA pà SLïûS|=usbcmdÃ=pà &Å=AOÅp<-Å;X> uf:%p s-Å;`> erial: v-Å;h> endorrea-Å;p> d res:%dpÅApÅSpÅ>_DpÅS~?respÅ üÿÿÿ?pÅ SÅ =pÅüÿÿÿ? pÆ £Æ£Æ~>vendorwriteÜÊ>,ApÏ@pÏOpÏøÿÿÿ?&Ñ=AOÑ‚<-Ñ;x> serial-Ñ;€> : vendor-Ñ;ˆ> write va-Ñ;> l: 0x%x -Ñ;˜> idx:%d pÑApÑSpÑ>zDpÑSpÑ@pÑSpÑ@pÑ SÑ =pÒøÿÿÿ? pÒP pÒ SpÒ@A pÒ SpÒA pÒ SpÒ@ pÒ  SpÒ@ pÒ SpÒASpÒASÒ=pÒ &Ô=AOÔ›<-Ô; > serial: -Ô;¨> vendorwr-Ô;°> ite res:pÔApÔSpÔ> DpÔSpÔ üÿÿÿ?pÔ SÔ =pÔüÿÿÿ? pÕ £Õ£Õ~>plmodemctlÜÚ>ApÚ@ pÞP ~@set&à@AXà«pãA£ãpæAxPpçQ&çAXçµWèºpëA£ë£ë~>plgetparamÜï>4Apõ@põOpøO pø Spø¡A pø Spø!A pø SpøA SpøAS~?bufaøùÿÿÿ? pø SpøA pø Sø=pø@ pøôÿÿÿ?súüÿÿÿ? úÿA¬úAsúûÿÿÿ? úÿA ¬úA ‡ú súúÿÿÿ? úÿA ¬úA ‡ú súùÿÿÿ? úÿA ‡ú púpQsýÿÿÿ?&AXè<-;¸> %d warn-;À> ing, sto-;È> p bit se-;Ð> t to 1.5-;Ø> unsuppopApSp>¼DpS =p@ Wñ rtedser- ;è> ial: get- ;ð> param: p Ap Sp >åDp S  =& =AO &=AO <-;ø> serial: -;> getparam-;> res: %dpApSp>øDpSpôÿÿÿ?pS =pôÿÿÿ?££~>plsetparamÜ>4Ap@ pPpðÿÿÿ?ppPoùÿÿÿ?ppPÍAoúÿÿÿ?ppPÍAoûÿÿÿ?ppPÍAoüÿÿÿ?ptP&AX# serial-%;> : setparp%Ap%Sp%>Dp%S% =&&=AO&9p(ðÿÿÿ? p(P p( Sp(!A p( Sp( A p( Sp(A Sp(ASa(ùÿÿÿ? p( Sp(A p( S(=p(@ p(ôÿÿÿ?p* Sp*xPp*S*>p+@p+S+>&-=AO-Y<--; > am: ser--;(> ial: set--;0> param rep-Ap-Sp->%Dp-Sp-ôÿÿÿ?p-S- =p.ôÿÿÿ?£.£.~>revidÜ2>AW=eheuristicidÜB> A~@ csppB @pD DÿA&DAXDy s: %d s-K;@> erial: c-K;H> hip unkn-K;P> own, set-K;X> ting to -K;`> HX versipKApKSpK>?DpKSK =pLA£L£L~>"plinitÜQ">0ApX@pXOpXèÿÿÿ?pY A pY SpYA pY SL;ø„=#emalloczY#=pYèÿÿÿ? pYøÿÿÿ?&Z=AOZ¥<-Z;h> on plinpZApZSpZ>lDpZSZ =pZèÿÿÿ? p\Pp\Op\O~?$cspp\ôÿÿÿ$?p]Pp]O~?%maxpktp]ðÿÿÿ%?p^Pp^Op^ Op`S`>p`èÿÿÿ? p`Q&`AX`¼paèÿÿÿ? paQ&c=AOcÅ<-c;p> it seri-c;x> al: typepcApcSpc>tDpcSpcQpcSc =pe@peSpe„„ApeSpeASpeøÿÿÿ?pe Se>pf@pfSpfApfSpfASf>pg@pgSpg„„ApgSpgASpgøÿÿÿ?pg Sg>ph@phSphƒƒAphSphASphøÿÿÿ?ph Sh>pi@piSpi„„ApiSpiASpiøÿÿÿ?pi Si>pj@pjSpjApjSpjApjSj>pk@pkSpk„„ApkSpkASpkøÿÿÿ?pk Sk>pl@plSplƒƒAplSplASpløÿÿÿ?pl Sl>pn@pnSpnASpnApnSn>po@poSpoApoSpoASo>po@ pqèÿÿÿ?pqO&qAXqWr pv@pvSv>pwèÿÿÿ?pwSL+l=&qunlockw&=pxøÿÿÿ?pxSL0f‹j='freex'=pyÿA py SpyA py Sy#=~?(stpyüÿÿÿ(?pzèÿÿÿ?pzSL+l=)qlockz)=&{=AO{;,statusreaderp>,DpSp@pSp ApSLS]Å)=-proccreate-=p‚A£‚£‚~>.plsetbreak܆.>(Ap†@ pŠ@pŠOp‹O p‹ Sp‹!A p‹ S&‹ AO‹_/plclearpipesÜ/>Ap@ p”R p–Q&–AX–zp˜@p˜Sp˜ Ap˜Sp˜AS˜>W˜­í=0unstallš0=&šAPš‹ %d dis-›;ˆ> k: unsta-›;> ll epoutp›Ap›Sp›>…Dp›S› =pœüÿÿÿ? pœP pœ Spœ@ pœ P pœ SpœASœ0=&œAPœœ<&1=AOœ<-;˜> : %r di-; > sk: unst-;¨> all epinpApSp>žDpS =pžüÿÿÿ? pžP pž Spž@ pžP pž SpžASž0=&žAPž­<&Ÿ1=AOŸ­<-Ÿ;°> : %r di-Ÿ;¸> sk: unst-Ÿ;À> all epin-Ÿ;È> tr: %r pŸApŸSpŸ>¶DpŸSŸ =p¡A£¡£¡~>setctllineÜ¥>(Ap©@p©OpªO pª Spª!A pª Spª"A pª Ssª@ pª  SpªASpªASpªASª=£ª£ª~>composectlܯ>Ap¯@ p±ŒP&±AO±È<†²AlPW²É< ´ýAlPpµœP&µAOµÎ<†¶AlPW¶Ï< ¸þAlP£¸~>plsendlinesܼ>A&À=AOÀÛ<~>.string-À;Ð> serial: -À;Ø> sendline-À;à> s: %#2.2pÀApÀSpÀ>ÐDpÀSpÀ@sÀlOpÀSÀ =pÁ@pÁSÁ>pÁ@ p SsÂlQ p SÂ>p &Ã=AOÃì<-Ã;è> x seria-Ã;ð> l: sendl-Ã;ø> ines respÃApÃSpÃ>ëDpÃSpà Sà =pÄA£Ä£Ä~>plreadstatusÜÈ>TApÏ@pÏO pÑ Àÿÿÿ?pÑ SÑ)=&Ò=AOÒü<-Ò;> : %d se-Ò;> rial: re-Ò;> ading fr-Ò;> om interpÒApÒSpÒ>DpÒSÒ =pÓ@pÓOpÓ O~?dfdpÓøÿÿÿ?pÕÀÿÿÿ?pÕSÕ&=pÖøÿÿÿ? pÖ SaÖÆÿÿÿ? pÖ SpÖ A pÖ SL rupt %r~? erraØÐÿÿÿ ?pØSpØ(ApØSpØ>&DpØS~= snprintØ =pØüÿÿÿ? pØ@ ~= serialdebug&Ù =AOÙ!<-Ù;(> serial:-Ù;0> interru-Ù;8> pt read pÙApÙSpÙ>)DpÙSpÙ S~= fprintÙ =pÙüÿÿÿ? pÙ@ -Û;@> %d %r t-Û;H> imed out&Û APÛ,GD pÛ S~= strstrÛ =pÛüÿÿÿ? pÛ@ &ÛAOÛ- serial:-Ü;X> need to-Ü;`> recover-Ü;h> , status-Ü;p> read %dpÜApÜSpÜ>QDpÜSpÜ SÜ =pÝÀÿÿÿ? pÝ SaÝÐÿÿÿ ? pÝ SLÖ“:=serialrecoverÝ=pÝüÿÿÿ? pÝ@ &ÝAPÝC %r ser-ã;€> ial: rea-ã;ˆ> ding sta-ã;> tus: %rpãApãSpã>}DpãSã =pãüÿÿÿ? Wãx<&ä  AUäo serial: -ñ; > bad stat-ñ;¨> us read pñApñSpñ>˜DpñSpñ Sñ =pñüÿÿÿ? &ò =AOò€<-ò;°> %d seri-ò;¸> al: fini-ò;À> shed rea-ò;È> d from i-ò;Ð> nterruptpòApòSpò>´DpòSpò Sò =póÀÿÿÿ?póSó&=pôA£ô£ôÜø,>A~@upý@ ~?ppþ üÿÿÿ?pþPpþøÿÿÿ?-ÿ;Ø> %d sta-ÿ;à> tusreadepÿ>ÝDpÿSL·áP=threadsetnameÿ=W‘&AU rprocse-;ð> rial: st-;ø> atusread-;> er exitipApSp>îDpS =pøÿÿÿ?pOpSLM½D=closedev=£~>plsetepsÜ > A-;> ng maxp~@pp@p OpSp> DpSL€$ö=devctl=-;> kt 256m-;> axpkt 25p@pOpSp>DpS=pA££L#Âó=plops-;=>"D-;=>D-; =>D-;=>/D-;=>D-;=>D-; =>.D-;=>D-; > 65=0A~=plinfo5=A5>(AIucons.8 1287570388 0 0 664 2009 ` ~E7»~E.string-Ò;> vid %#06-Ò;> x did %#~?bufaÒÊÿÿÿ?pÒSpÒ2ApÒSpÒ>DpÒSpÒPpÒ S~?ippÒ üÿÿÿ?pÒPpÒSLD$s5=snprintÒ=L½ÕQA=serialdebug&Ô=AOÔ <-Ô;> 06xseri-Ô;> al: %s %pÔApÔSpÔ>DpÔSaÔÊÿÿÿ?pÔS~@infopÔ@pÔ SLJ”§Š= fprintÔ =pÕ@ pÕ SaÕÊÿÿÿ? pÕ SLi})ì= strstrÕ =pÕüÿÿÿ? &ÕAOÕ* ucsetepsÜÜ >A~@ ppÜ @ pàR pâÿÿÿÿApRpã  ãA ãA pãAQpãA pã O-ä; > s maxpkpä RpäSpä>#DpäSL€$ö= devctlä =-å;(> t 8maxppå @påOpåSpå>,DpåSå =pæA£æ£æL#Âó=uconsops-ë;=> D-ë;0> kt 85ë=A5ë>8A5ë=0AIëñSpcQpcSc =pe@peSpeusb/lib/usbfs.h 664 0 0 2537 11202312257 11400ustar00syssystypedef struct Usbfs Usbfs; typedef struct Fid Fid; enum { Hdrsize = 128, /* plenty of room for headers */ Msgsize = 8 * 1024, Bufsize = Hdrsize + Msgsize, Namesz = 40, Errmax = 128, ONONE = ~0, /* omode in Fid when not open */ }; struct Fid { int fid; Qid qid; int omode; Fid* next; void* aux; }; struct Usbfs { char name[Namesz]; uvlong qid; Dev* dev; void* aux; int (*walk)(Usbfs *fs, Fid *f, char *name); void (*clone)(Usbfs *fs, Fid *of, Fid *nf); void (*clunk)(Usbfs *fs, Fid *f); int (*open)(Usbfs *fs, Fid *f, int mode); long (*read)(Usbfs *fs, Fid *f, void *data, long count, vlong offset); long (*write)(Usbfs *fs, Fid*f, void *data, long count, vlong offset); int (*stat)(Usbfs *fs, Qid q, Dir *d); void (*end)(Usbfs *fs); }; typedef int (*Dirgen)(Usbfs*, Qid, int, Dir*, void*); long usbreadbuf(void *data, long count, vlong offset, void *buf, long n); void usbfsadd(Usbfs *dfs); void usbfsdel(Usbfs *dfs); int usbdirread(Usbfs*f, Qid q, char *data, long cnt, vlong off, Dirgen gen, void *arg); void usbfsinit(char* srv, char *mnt, Usbfs *f, int flag); void usbfsdirdump(void); extern char Enotfound[]; extern char Etoosmall[]; extern char Eio[]; extern char Eperm[]; extern char Ebadcall[]; extern char Ebadfid[]; extern char Einuse[]; extern char Eisopen[]; extern char Ebadctl[]; extern Usbfs usbdirfs; extern int usbfsdebug; @ pŠ@pŠOp‹O p‹ Sp‹!A p‹ S&‹ AO‹_ serial:-Ü;X> need to-Ü;`> recover-Ü;h> , status-Ü;p> read %dpÜApÜSpÜ>QDpÜusb/print/mkfile 664 0 0 346 11202312257 11641ustar00syssys #include #include #include "usb.h" enum { Qdir = 0, Qctl, Qraw, Qdata, Qmax, }; int findendpoints(Dev *dev, int devid) { Ep *ep; Dev *d; Usbdev *ud; int i, epout; epout = -1; ud = dev->usb; for(i = 0; i < nelem(ud->ep); i++){ if((ep = ud->ep[i]) == nil) break; if(ep->iface->csp != 0x020107) continue; if(ep->type == Ebulk && (ep->dir == Eboth || ep->dir == Eout)) if(epout == -1) epout = ep->id; } dprint(2, "print: ep ids: out %d\n", epout); if(epout == -1) return -1; d = openep(dev, epout); if(d == nil){ fprint(2, "print: openep %d: %r\n", epout); return -1; } opendevdata(d, OWRITE); if(d->dfd < 0){ fprint(2, "print: open i/o ep data: %r\n"); closedev(d); return -1; } dprint(2, "print: ep out %s\n", d->dir); if(usbdebug > 1) devctl(d, "debug 1"); devctl(d, "name lp%d", devid); return 0; } static int usage(void) { werrstr("usage: usb/print [-N id]"); return -1; } int printmain(Dev *dev, int argc, char **argv) { int devid; devid = dev->id; ARGBEGIN{ case 'N': devid = atoi(EARGF(usage())); break; default: return usage(); }ARGEND if(argc != 0) return usage(); if(findendpoints(dev, devid) < 0){ werrstr("print: endpoints not found"); return -1; } return 0; } E.string-Ò;> vid %#06-Ò;> x did %#~?bufaÒÊÿÿÿ?pÒSpÒ2ApÒSpÒ>DpÒSpÒPpÒ S~?ippÒ üÿÿÿ?pusb/probe 775 0 0 633 11326125204 10350ustar00syssys#!/bin/rc # usb/probe [-h] - list all usb devices, including hubs rfork e test -e /dev/usb || bind -a '#u' /dev || { echo no '#u/usb' >[1=2] exit nousb } filter = cat if (~ $1 -h) filter = (grep -v ' (root)?hub ') awk 'BEGIN { ep = "" } $1 ~ /ep[0-9]+\.0/ && $2 == "enabled" && $NF ~ /busy|idle/ { ep=$1 next } { if(ep != ""){ printf "%s %s\n", ep, $0 ep = "" } } ' /dev/usb/ctl | $filter exit '' usb/serial/ 775 0 0 0 11457773434 106335ustar00syssysusb/serial/ftdi.c 664 0 0 45760 11457541721 11751ustar00syssys/* Future Technology Devices International serial ports */ #include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "ftdi.h" /* * BUG: This keeps growing, there has to be a better way, but without * devices to try it... We can probably simply look for FTDI in the * string, or use regular expressions somehow. */ Cinfo ftinfo[] = { { FTVid, FTACTZWAVEDid }, { FTSheevaVid, FTSheevaDid }, { FTVid, FTOpenRDUltDid}, { FTVid, FTIRTRANSDid }, { FTVid, FTIPLUSDid }, { FTVid, FTSIODid }, { FTVid, FT8U232AMDid }, { FTVid, FT8U232AMALTDid }, { FTVid, FT8U2232CDid }, { FTVid, FTRELAISDid }, { INTERBIOMVid, INTERBIOMIOBRDDid }, { INTERBIOMVid, INTERBIOMMINIIOBRDDid }, { FTVid, FTXF632Did }, { FTVid, FTXF634Did }, { FTVid, FTXF547Did }, { FTVid, FTXF633Did }, { FTVid, FTXF631Did }, { FTVid, FTXF635Did }, { FTVid, FTXF640Did }, { FTVid, FTXF642Did }, { FTVid, FTDSS20Did }, { FTNFRICVid, FTNFRICDid }, { FTVid, FTVNHCPCUSBDDid }, { FTVid, FTMTXORB0Did }, { FTVid, FTMTXORB1Did }, { FTVid, FTMTXORB2Did }, { FTVid, FTMTXORB3Did }, { FTVid, FTMTXORB4Did }, { FTVid, FTMTXORB5Did }, { FTVid, FTMTXORB6Did }, { FTVid, FTPERLEULTRAPORTDid }, { FTVid, FTPIEGROUPDid }, { SEALEVELVid, SEALEVEL2101Did }, { SEALEVELVid, SEALEVEL2102Did }, { SEALEVELVid, SEALEVEL2103Did }, { SEALEVELVid, SEALEVEL2104Did }, { SEALEVELVid, SEALEVEL22011Did }, { SEALEVELVid, SEALEVEL22012Did }, { SEALEVELVid, SEALEVEL22021Did }, { SEALEVELVid, SEALEVEL22022Did }, { SEALEVELVid, SEALEVEL22031Did }, { SEALEVELVid, SEALEVEL22032Did }, { SEALEVELVid, SEALEVEL24011Did }, { SEALEVELVid, SEALEVEL24012Did }, { SEALEVELVid, SEALEVEL24013Did }, { SEALEVELVid, SEALEVEL24014Did }, { SEALEVELVid, SEALEVEL24021Did }, { SEALEVELVid, SEALEVEL24022Did }, { SEALEVELVid, SEALEVEL24023Did }, { SEALEVELVid, SEALEVEL24024Did }, { SEALEVELVid, SEALEVEL24031Did }, { SEALEVELVid, SEALEVEL24032Did }, { SEALEVELVid, SEALEVEL24033Did }, { SEALEVELVid, SEALEVEL24034Did }, { SEALEVELVid, SEALEVEL28011Did }, { SEALEVELVid, SEALEVEL28012Did }, { SEALEVELVid, SEALEVEL28013Did }, { SEALEVELVid, SEALEVEL28014Did }, { SEALEVELVid, SEALEVEL28015Did }, { SEALEVELVid, SEALEVEL28016Did }, { SEALEVELVid, SEALEVEL28017Did }, { SEALEVELVid, SEALEVEL28018Did }, { SEALEVELVid, SEALEVEL28021Did }, { SEALEVELVid, SEALEVEL28022Did }, { SEALEVELVid, SEALEVEL28023Did }, { SEALEVELVid, SEALEVEL28024Did }, { SEALEVELVid, SEALEVEL28025Did }, { SEALEVELVid, SEALEVEL28026Did }, { SEALEVELVid, SEALEVEL28027Did }, { SEALEVELVid, SEALEVEL28028Did }, { SEALEVELVid, SEALEVEL28031Did }, { SEALEVELVid, SEALEVEL28032Did }, { SEALEVELVid, SEALEVEL28033Did }, { SEALEVELVid, SEALEVEL28034Did }, { SEALEVELVid, SEALEVEL28035Did }, { SEALEVELVid, SEALEVEL28036Did }, { SEALEVELVid, SEALEVEL28037Did }, { SEALEVELVid, SEALEVEL28038Did }, { IDTECHVid, IDTECHIDT1221UDid }, { OCTVid, OCTUS101Did }, { FTVid, FTHETIRA1Did }, /* special quirk div = 240 baud = B38400 rtscts = 1 */ { FTVid, FTUSBUIRTDid }, /* special quirk div = 77, baud = B38400 */ { FTVid, PROTEGOSPECIAL1 }, { FTVid, PROTEGOR2X0 }, { FTVid, PROTEGOSPECIAL3 }, { FTVid, PROTEGOSPECIAL4 }, { FTVid, FTGUDEADSE808Did }, { FTVid, FTGUDEADSE809Did }, { FTVid, FTGUDEADSE80ADid }, { FTVid, FTGUDEADSE80BDid }, { FTVid, FTGUDEADSE80CDid }, { FTVid, FTGUDEADSE80DDid }, { FTVid, FTGUDEADSE80EDid }, { FTVid, FTGUDEADSE80FDid }, { FTVid, FTGUDEADSE888Did }, { FTVid, FTGUDEADSE889Did }, { FTVid, FTGUDEADSE88ADid }, { FTVid, FTGUDEADSE88BDid }, { FTVid, FTGUDEADSE88CDid }, { FTVid, FTGUDEADSE88DDid }, { FTVid, FTGUDEADSE88EDid }, { FTVid, FTGUDEADSE88FDid }, { FTVid, FTELVUO100Did }, { FTVid, FTELVUM100Did }, { FTVid, FTELVUR100Did }, { FTVid, FTELVALC8500Did }, { FTVid, FTPYRAMIDDid }, { FTVid, FTELVFHZ1000PCDid }, { FTVid, FTELVCLI7000Did }, { FTVid, FTELVPPS7330Did }, { FTVid, FTELVTFM100Did }, { FTVid, FTELVUDF77Did }, { FTVid, FTELVUIO88Did }, { FTVid, FTELVUAD8Did }, { FTVid, FTELVUDA7Did }, { FTVid, FTELVUSI2Did }, { FTVid, FTELVT1100Did }, { FTVid, FTELVPCD200Did }, { FTVid, FTELVULA200Did }, { FTVid, FTELVCSI8Did }, { FTVid, FTELVEM1000DLDid }, { FTVid, FTELVPCK100Did }, { FTVid, FTELVRFP500Did }, { FTVid, FTELVFS20SIGDid }, { FTVid, FTELVWS300PCDid }, { FTVid, FTELVFHZ1300PCDid }, { FTVid, FTELVWS500Did }, { FTVid, LINXSDMUSBQSSDid }, { FTVid, LINXMASTERDEVEL2Did }, { FTVid, LINXFUTURE0Did }, { FTVid, LINXFUTURE1Did }, { FTVid, LINXFUTURE2Did }, { FTVid, FTCCSICDU200Did }, { FTVid, FTCCSICDU401Did }, { FTVid, INSIDEACCESSO }, { INTREDidVid, INTREDidVALUECANDid }, { INTREDidVid, INTREDidNEOVIDid }, { FALCOMVid, FALCOMTWISTDid }, { FALCOMVid, FALCOMSAMBADid }, { FTVid, FTSUUNTOSPORTSDid }, { FTVid, FTRMCANVIEWDid }, { BANDBVid, BANDBUSOTL4Did }, { BANDBVid, BANDBUSTL4Did }, { BANDBVid, BANDBUSO9ML2Did }, { FTVid, EVERECOPROCDSDid }, { FTVid, FT4NGALAXYDE0Did }, { FTVid, FT4NGALAXYDE1Did }, { FTVid, FT4NGALAXYDE2Did }, { FTVid, XSENSCONVERTER0Did }, { FTVid, XSENSCONVERTER1Did }, { FTVid, XSENSCONVERTER2Did }, { FTVid, XSENSCONVERTER3Did }, { FTVid, XSENSCONVERTER4Did }, { FTVid, XSENSCONVERTER5Did }, { FTVid, XSENSCONVERTER6Did }, { FTVid, XSENSCONVERTER7Did }, { MOBILITYVid, MOBILITYUSBSERIALDid }, { FTVid, FTACTIVEROBOTSDid }, { FTVid, FTMHAMKWDid }, { FTVid, FTMHAMYSDid }, { FTVid, FTMHAMY6Did }, { FTVid, FTMHAMY8Did }, { FTVid, FTMHAMICDid }, { FTVid, FTMHAMDB9Did }, { FTVid, FTMHAMRS232Did }, { FTVid, FTMHAMY9Did }, { FTVid, FTTERATRONIKVCPDid }, { FTVid, FTTERATRONIKD2XXDid }, { EVOLUTIONVid, EVOLUTIONER1Did }, { FTVid, FTARTEMISDid }, { FTVid, FTATIKATK16Did }, { FTVid, FTATIKATK16CDid }, { FTVid, FTATIKATK16HRDid }, { FTVid, FTATIKATK16HRCDid }, { KOBILVid, KOBILCONVB1Did }, { KOBILVid, KOBILCONVKAANDid }, { POSIFLEXVid, POSIFLEXPP7000Did }, { FTVid, FTTTUSBDid }, { FTVid, FTECLOCOM1WIREDid }, { FTVid, FTWESTREXMODEL777Did }, { FTVid, FTWESTREXMODEL8900FDid }, { FTVid, FTPCDJDAC2Did }, { FTVid, FTRRCIRKITSLOCOBUFFERDid }, { FTVid, FTASKRDR400Did }, { ICOMID1Vid, ICOMID1Did }, { PAPOUCHVid, PAPOUCHTMUDid }, { FTVid, FTACGHFDUALDid }, { FT8U232AMDid, FT4232HDid }, { 0, 0 }, }; enum { Packsz = 64, /* default size */ Maxpacksz = 512, Bufsiz = 4 * 1024, }; static int ftdiread(Serialport *p, int val, int index, int req, uchar *buf) { int res; Serial *ser; ser = p->s; if(req != FTGETE2READ) index |= p->interfc + 1; dsprint(2, "serial: ftdiread %#p [%d] req: %#x val: %#x idx:%d buf:%p\n", p, p->interfc, req, val, index, buf); res = usbcmd(ser->dev, Rd2h | Rftdireq | Rdev, req, val, index, buf, 1); dsprint(2, "serial: ftdiread res:%d\n", res); return res; } static int ftdiwrite(Serialport *p, int val, int index, int req) { int res; Serial *ser; ser = p->s; index |= p->interfc + 1; dsprint(2, "serial: ftdiwrite %#p [%d] req: %#x val: %#x idx:%d\n", p, p->interfc, req, val, index); res = usbcmd(ser->dev, Rh2d | Rftdireq | Rdev, req, val, index, nil, 0); dsprint(2, "serial: ftdiwrite res:%d\n", res); return res; } static int ftmodemctl(Serialport *p, int set) { if(set == 0){ p->mctl = 0; ftdiwrite(p, 0, 0, FTSETMODEMCTRL); return 0; } p->mctl = 1; ftdiwrite(p, 0, FTRTSCTSHS, FTSETFLOWCTRL); return 0; } static ushort ft232ambaudbase2div(int baud, int base) { int divisor3; ushort divisor; divisor3 = (base / 2) / baud; if((divisor3 & 7) == 7) divisor3++; /* round x.7/8 up to x+1 */ divisor = divisor3 >> 3; divisor3 &= 7; if(divisor3 == 1) divisor |= 0xc000; /* 0.125 */ else if(divisor3 >= 4) divisor |= 0x4000; /* 0.5 */ else if(divisor3 != 0) divisor |= 0x8000; /* 0.25 */ if( divisor == 1) divisor = 0; /* special case for maximum baud rate */ return divisor; } enum{ ClockNew = 48000000, ClockOld = 12000000 / 16, HetiraDiv = 240, UirtDiv = 77, }; static ushort ft232ambaud2div(int baud) { return ft232ambaudbase2div(baud, ClockNew); } static ulong divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7}; static ulong ft232bmbaudbase2div(int baud, int base) { int divisor3; u32int divisor; divisor3 = (base / 2) / baud; divisor = divisor3 >> 3 | divfrac[divisor3 & 7] << 14; /* Deal with special cases for highest baud rates. */ if( divisor == 1) divisor = 0; /* 1.0 */ else if( divisor == 0x4001) divisor = 1; /* 1.5 */ return divisor; } static ulong ft232bmbaud2div (int baud) { return ft232bmbaudbase2div (baud, ClockNew); } static int customdiv(Serial *ser) { if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did) return HetiraDiv; else if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTUSBUIRTDid) return UirtDiv; fprint(2, "serial: weird custom divisor\n"); return 0; /* shouldn't happen, break as much as I can */ } static ulong ftbaudcalcdiv(Serial *ser, int baud) { int cusdiv; ulong divval; if(baud == 38400 && (cusdiv = customdiv(ser)) != 0) baud = ser->baudbase / cusdiv; if(baud == 0) baud = 9600; switch(ser->type) { case SIO: switch(baud) { case 300: divval = FTb300; break; case 600: divval = FTb600; break; case 1200: divval = FTb1200; break; case 2400: divval = FTb2400; break; case 4800: divval = FTb4800; break; case 9600: divval = FTb9600; break; case 19200: divval = FTb19200; break; case 38400: divval = FTb38400; break; case 57600: divval = FTb57600; break; case 115200: divval = FTb115200; break; default: divval = FTb9600; break; } break; case FT8U232AM: if(baud <= 3000000) divval = ft232ambaud2div(baud); else divval = ft232ambaud2div(9600); break; case FT232BM: case FT2232C: case FTKINDR: case FT2232H: case FT4232H: if(baud <= 3000000) divval = ft232bmbaud2div(baud); else divval = ft232bmbaud2div(9600); break; default: divval = ft232bmbaud2div(9600); break; } return divval; } static int ftsetparam(Serialport *p) { int res; ushort val; ulong bauddiv; val = 0; if(p->stop == 1) val |= FTSETDATASTOPBITS1; else if(p->stop == 2) val |= FTSETDATASTOPBITS2; else if(p->stop == 15) val |= FTSETDATASTOPBITS15; switch(p->parity){ case 0: val |= FTSETDATAParNONE; break; case 1: val |= FTSETDATAParODD; break; case 2: val |= FTSETDATAParEVEN; break; case 3: val |= FTSETDATAParMARK; break; case 4: val |= FTSETDATAParSPACE; break; }; dsprint(2, "serial: setparam\n"); res = ftdiwrite(p, val, 0, FTSETDATA); if(res < 0) return res; res = ftmodemctl(p, p->mctl); if(res < 0) return res; bauddiv = ftbaudcalcdiv(p->s, p->baud); res = ftdiwrite(p, bauddiv, (bauddiv>>16) & 1, FTSETBaudRate); dsprint(2, "serial: setparam res: %d\n", res); return res; } /* ser locked */ static void ftgettype(Serial *ser) { int i, outhdrsz, dno, pksz; ulong baudbase; Conf *cnf; pksz = Packsz; /* Assume it is not the original SIO device for now. */ baudbase = ClockNew / 2; outhdrsz = 0; dno = ser->dev->usb->dno; cnf = ser->dev->usb->conf[0]; ser->nifcs = 0; for(i = 0; i < Niface; i++) if(cnf->iface[i] != nil) ser->nifcs++; if(ser->nifcs > 1) { /* * Multiple interfaces. default assume FT2232C, */ if(dno == 0x500) ser->type = FT2232C; else if(dno == 0x600) ser->type = FTKINDR; else if(dno == 0x700){ ser->type = FT2232H; pksz = Maxpacksz; } else if(dno == 0x800){ ser->type = FT4232H; pksz = Maxpacksz; } else ser->type = FT2232C; ser->jtag = 0; /* * BM-type devices have a bug where dno gets set * to 0x200 when serial is 0. */ if(dno < 0x500) fprint(2, "serial: warning: dno %d too low for " "multi-interface device\n", dno); } else if(dno < 0x200) { /* Old device. Assume it is the original SIO. */ ser->type = SIO; baudbase = ClockOld/16; outhdrsz = 1; } else if(dno < 0x400) /* * Assume its an FT8U232AM (or FT8U245AM) * (It might be a BM because of the iSerialNumber bug, * but it will still work as an AM device.) */ ser->type = FT8U232AM; else /* Assume it is an FT232BM (or FT245BM) */ ser->type = FT232BM; ser->maxrtrans = ser->maxwtrans = pksz; ser->baudbase = baudbase; ser->outhdrsz = outhdrsz; ser->inhdrsz = 2; dsprint (2, "serial: detected type: %#x\n", ser->type); } int ftmatch(Serial *ser, char *info) { Cinfo *ip; char buf[50]; for(ip = ftinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s\n", buf, info); if(strstr(info, buf) != nil){ if(ser != nil){ qlock(ser); ftgettype(ser); qunlock(ser); } return 0; } } return -1; } static int ftuseinhdr(Serialport *p, uchar *b) { if(b[0] & FTICTS) p->cts = 1; else p->cts = 0; if(b[0] & FTIDSR) p->dsr = 1; else p->dsr = 0; if(b[0] & FTIRI) p->ring = 1; else p->ring = 0; if(b[0] & FTIRLSD) p->rlsd = 1; else p->rlsd = 0; if(b[1] & FTIOE) p->novererr++; if(b[1] & FTIPE) p->nparityerr++; if(b[1] & FTIFE) p->nframeerr++; if(b[1] & FTIBI) p->nbreakerr++; return 0; } static int ftsetouthdr(Serialport *p, uchar *b, int len) { if(p->s->outhdrsz != 0) b[0] = FTOPORT | (FTOLENMSK & len); return p->s->outhdrsz; } static int wait4data(Serialport *p, uchar *data, int count) { int d; Serial *ser; ser = p->s; qunlock(ser); d = sendul(p->w4data, 1); qlock(ser); if(d <= 0) return -1; if(p->ndata >= count) p->ndata -= count; else{ count = p->ndata; p->ndata = 0; } assert(count >= 0); assert(p->ndata >= 0); memmove(data, p->data, count); if(p->ndata != 0) memmove(p->data, p->data+count, p->ndata); recvul(p->gotdata); return count; } static int wait4write(Serialport *p, uchar *data, int count) { int off, fd; uchar *b; Serial *ser; ser = p->s; b = emallocz(count+ser->outhdrsz, 1); off = ftsetouthdr(p, b, count); memmove(b+off, data, count); fd = p->epout->dfd; qunlock(ser); count = write(fd, b, count+off); qlock(ser); free(b); return count; } typedef struct Packser Packser; struct Packser{ int nb; uchar b[Bufsiz]; }; typedef struct Areader Areader; struct Areader{ Serialport *p; Channel *c; }; static void shutdownchan(Channel *c) { Packser *bp; while((bp=nbrecvp(c)) != nil) free(bp); chanfree(c); } int cpdata(Serial *ser, Serialport *port, uchar *out, uchar *in, int sz) { int i, ncp, ntotcp, pksz; pksz = ser->maxrtrans; ntotcp = 0; for(i = 0; i < sz; i+= pksz){ ftuseinhdr(port, in + i); if(sz - i > pksz) ncp = pksz - ser->inhdrsz; else ncp = sz - i - ser->inhdrsz; memmove(out, in + i + ser->inhdrsz, ncp); out += ncp; ntotcp += ncp; } return ntotcp; } static void epreader(void *u) { int dfd, rcount, cl; char err[40]; Areader *a; Channel *c; Packser *pk; Serial *ser; Serialport *p; threadsetname("epreader proc"); a = u; p = a->p; ser = p->s; c = a->c; free(a); qlock(ser); dfd = p->epin->dfd; qunlock(ser); pk = nil; do { if (pk == nil) pk = emallocz(sizeof(Packser), 1); 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) continue; if(rcount >= ser->inhdrsz){ rcount = cpdata(ser, p, pk->b, pk->b, rcount); if(rcount != 0){ pk->nb = rcount; cl = sendp(c, pk); if(cl < 0){ /* * if it was a time-out, I don't want * to give back an error. */ rcount = 0; break; } }else free(pk); pk = nil; } } while(rcount >= 0 || (rcount < 0 && strstr(err, "timed out") != nil)); if(rcount < 0) fprint(2, "%s: error reading %s: %r\n", argv0, p->fs.name); free(pk); nbsendp(c, nil); if(p->w4data != nil) chanclose(p->w4data); if(p->gotdata != nil) chanclose(p->gotdata); devctl(ser->dev, "detach"); closedev(ser->dev); usbfsdel(&p->fs); } static void statusreader(void *u) { Areader *a; Channel *c; Packser *pk; Serialport *p; Serial *ser; int cl; p = u; ser = p->s; threadsetname("statusreader thread"); /* big buffering, fewer bytes lost */ c = chancreate(sizeof(Packser *), 128); a = emallocz(sizeof(Areader), 1); a->p = p; a->c = c; incref(ser->dev); proccreate(epreader, a, 16*1024); while((pk = recvp(c)) != nil){ memmove(p->data, pk->b, pk->nb); p->ndata = pk->nb; free(pk); dsprint(2, "serial: status reader %d \n", p->ndata); /* consume it all */ while(p->ndata != 0){ dsprint(2, "serial: status reader to consume: %d\n", p->ndata); cl = recvul(p->w4data); if(cl < 0) break; cl = sendul(p->gotdata, 1); if(cl < 0) break; } } shutdownchan(c); devctl(ser->dev, "detach"); closedev(ser->dev); usbfsdel(&p->fs); } static int ftreset(Serial *ser) { Serialport *p; int i; p = ser->p; for(i = 0; i < Maxifc; i++) if(!p[i].isjtag && p[i].s != nil) ftdiwrite(&p[i], FTRESETCTLVAL, 0, FTRESET); return 0; } static int ftinit(Serialport *p) { Serial *ser; uint timerval; int res; ser = p->s; if(p->isjtag){ res = ftdiread(p, LTGETMASK, PITA, FTSETLATENCYTIMER, (uchar *)&timerval); if(res < 0) // dunno return -1; print("pre-set: latency is %d\n", timerval); ftdiwrite(p, (FTDEFAULT<<8)|LTSETMASK, PITA, FTSETLATENCYTIMER); res = ftdiread(p, LTGETMASK, PITA, FTSETLATENCYTIMER, (uchar *)&timerval); if(res < 0) // dunno return -1; print("post-set: latency is %d\n", timerval); ftdiwrite(p, BMBM|BMMASK, PITA, FTSETBITMODE); return 0; } incref(ser->dev); threadcreate(statusreader, p, 8*1024); return 0; } static int ftsetbreak(Serialport *p, int val) { return ftdiwrite(p, (val != 0? FTSETBREAK: 0), 0, FTSETDATA); } static int ftclearpipes(Serialport *p) { /* maybe can be done in one... */ ftdiwrite(p, FTRESETCTLVALPURGETX, 0, FTRESET); ftdiwrite(p, FTRESETCTLVALPURGERX, 0, FTRESET); return 0; } static int setctlline(Serialport *p, uchar val) { return ftdiwrite(p, val | (val << 8), 0, FTSETMODEMCTRL); } static void updatectlst(Serialport *p, int val) { if(p->rts) p->ctlstate |= val; else p->ctlstate &= ~val; } static int setctl(Serialport *p) { int res; Serial *ser; ser = p->s; if(ser->dev->usb->vid == FTVid && ser->dev->usb->did == FTHETIRA1Did){ fprint(2, "serial: cannot set lines for this device\n"); updatectlst(p, CtlRTS|CtlDTR); p->rts = p->dtr = 1; return -1; } /* NB: you can not set DTR and RTS with one control message */ updatectlst(p, CtlRTS); res = setctlline(p, (CtlRTS<<8)|p->ctlstate); if(res < 0) return res; updatectlst(p, CtlDTR); res = setctlline(p, (CtlDTR<<8)|p->ctlstate); if(res < 0) return res; return 0; } static int ftsendlines(Serialport *p) { int res; dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate); res = setctl(p); dsprint(2, "serial: sendlines res: %d\n", res); return 0; } static int ftseteps(Serialport *p) { char *s; Serial *ser; ser = p->s; s = smprint("maxpkt %d", ser->maxrtrans); devctl(p->epin, s); free(s); s = smprint("maxpkt %d", ser->maxwtrans); devctl(p->epout, s); free(s); return 0; } Serialops ftops = { .init = ftinit, .seteps = ftseteps, .setparam = ftsetparam, .clearpipes = ftclearpipes, .reset = ftreset, .sendlines = ftsendlines, .modemctl = ftmodemctl, .setbreak = ftsetbreak, .wait4data = wait4data, .wait4write = wait4write, }; 0; break; cusb/serial/ftdi.h 664 0 0 41017 11457541550 11745ustar00syssysenum { /* used by devices which don't provide their own Vid */ FTVid = 0x0403, FTSheevaVid = 0x9E88, FTSheevaDid = 0x9E8F, FTOpenRDUltDid = 0x9E90, FTSIODid = 0x8372, /* Product Id SIO appl'n of 8U100AX */ FT8U232AMDid = 0x6001, /* Similar device to SIO above */ FT8U232AMALTDid = 0x6006, /* FT's alternate Did for above*/ FT8U2232CDid = 0x6010, /* Dual channel device */ FTRELAISDid = 0xFA10, /* Relais device */ /* NF reader */ FTNFRICVid = 0x0DCD, FTNFRICDid = 0x0001, FTACTZWAVEDid = 0xF2D0, /* www.irtrans.de device */ /* * ACT Solutions HomePro ZWave interface * http://www.act-solutions.com/HomePro.htm) */ FTIRTRANSDid = 0xFC60, /* * www.thoughttechnology.com/ TT-USB */ FTTTUSBDid = 0xFF20, /* iPlus device */ FTIPLUSDid = 0xD070, /* www.crystalfontz.com devices */ FTXF632Did = 0xFC08, /* 632: 16x2 Character Display */ FTXF634Did = 0xFC09, /* 634: 20x4 Character Display */ FTXF547Did = 0xFC0A, /* 547: Two line Display */ FTXF633Did = 0xFC0B, /* 633: 16x2 Character Display with Keys */ FTXF631Did = 0xFC0C, /* 631: 20x2 Character Display */ FTXF635Did = 0xFC0D, /* 635: 20x4 Character Display */ FTXF640Did = 0xFC0E, /* 640: Two line Display */ FTXF642Did = 0xFC0F, /* 642: Two line Display */ /* * Video Networks Limited / Homechoice in the UK * use an ftdi-based device for their 1Mb broadband */ FTVNHCPCUSBDDid = 0xfe38, /* * PCDJ use ftdi based dj-controllers * DAC-2 device http://www.pcdjhardware.com/DAC2.asp */ FTPCDJDAC2Did = 0xFA88, /* * Matrix Orbital LCD displays, * which are the FT232BM (similar to the 8U232AM) */ FTMTXORB0Did = 0xFA00, FTMTXORB1Did = 0xFA01, FTMTXORB2Did = 0xFA02, FTMTXORB3Did = 0xFA03, FTMTXORB4Did = 0xFA04, FTMTXORB5Did = 0xFA05, FTMTXORB6Did = 0xFA06, /* Interbiometrics USB I/O Board */ INTERBIOMVid = 0x1209, INTERBIOMIOBRDDid = 0x1002, INTERBIOMMINIIOBRDDid = 0x1006, /* * The following are the values for the Perle Systems * UltraPort USB serial converters */ FTPERLEULTRAPORTDid = 0xF0C0, /* * Sealevel SeaLINK+ adapters. */ SEALEVELVid = 0x0c52, SEALEVEL2101Did = 0x2101, /* SeaLINK+232 (2101/2105) */ SEALEVEL2102Did = 0x2102, /* SeaLINK+485 (2102) */ SEALEVEL2103Did = 0x2103, /* SeaLINK+232I (2103) */ SEALEVEL2104Did = 0x2104, /* SeaLINK+485I (2104) */ SEALEVEL22011Did = 0x2211, /* SeaPORT+2/232 (2201) Port 1 */ SEALEVEL22012Did = 0x2221, /* SeaPORT+2/232 (2201) Port 2 */ SEALEVEL22021Did = 0x2212, /* SeaPORT+2/485 (2202) Port 1 */ SEALEVEL22022Did = 0x2222, /* SeaPORT+2/485 (2202) Port 2 */ SEALEVEL22031Did = 0x2213, /* SeaPORT+2 (2203) Port 1 */ SEALEVEL22032Did = 0x2223, /* SeaPORT+2 (2203) Port 2 */ SEALEVEL24011Did = 0x2411, /* SeaPORT+4/232 (2401) Port 1 */ SEALEVEL24012Did = 0x2421, /* SeaPORT+4/232 (2401) Port 2 */ SEALEVEL24013Did = 0x2431, /* SeaPORT+4/232 (2401) Port 3 */ SEALEVEL24014Did = 0x2441, /* SeaPORT+4/232 (2401) Port 4 */ SEALEVEL24021Did = 0x2412, /* SeaPORT+4/485 (2402) Port 1 */ SEALEVEL24022Did = 0x2422, /* SeaPORT+4/485 (2402) Port 2 */ SEALEVEL24023Did = 0x2432, /* SeaPORT+4/485 (2402) Port 3 */ SEALEVEL24024Did = 0x2442, /* SeaPORT+4/485 (2402) Port 4 */ SEALEVEL24031Did = 0x2413, /* SeaPORT+4 (2403) Port 1 */ SEALEVEL24032Did = 0x2423, /* SeaPORT+4 (2403) Port 2 */ SEALEVEL24033Did = 0x2433, /* SeaPORT+4 (2403) Port 3 */ SEALEVEL24034Did = 0x2443, /* SeaPORT+4 (2403) Port 4 */ SEALEVEL28011Did = 0x2811, /* SeaLINK+8/232 (2801) Port 1 */ SEALEVEL28012Did = 0x2821, /* SeaLINK+8/232 (2801) Port 2 */ SEALEVEL28013Did = 0x2831, /* SeaLINK+8/232 (2801) Port 3 */ SEALEVEL28014Did = 0x2841, /* SeaLINK+8/232 (2801) Port 4 */ SEALEVEL28015Did = 0x2851, /* SeaLINK+8/232 (2801) Port 5 */ SEALEVEL28016Did = 0x2861, /* SeaLINK+8/232 (2801) Port 6 */ SEALEVEL28017Did = 0x2871, /* SeaLINK+8/232 (2801) Port 7 */ SEALEVEL28018Did = 0x2881, /* SeaLINK+8/232 (2801) Port 8 */ SEALEVEL28021Did = 0x2812, /* SeaLINK+8/485 (2802) Port 1 */ SEALEVEL28022Did = 0x2822, /* SeaLINK+8/485 (2802) Port 2 */ SEALEVEL28023Did = 0x2832, /* SeaLINK+8/485 (2802) Port 3 */ SEALEVEL28024Did = 0x2842, /* SeaLINK+8/485 (2802) Port 4 */ SEALEVEL28025Did = 0x2852, /* SeaLINK+8/485 (2802) Port 5 */ SEALEVEL28026Did = 0x2862, /* SeaLINK+8/485 (2802) Port 6 */ SEALEVEL28027Did = 0x2872, /* SeaLINK+8/485 (2802) Port 7 */ SEALEVEL28028Did = 0x2882, /* SeaLINK+8/485 (2802) Port 8 */ SEALEVEL28031Did = 0x2813, /* SeaLINK+8 (2803) Port 1 */ SEALEVEL28032Did = 0x2823, /* SeaLINK+8 (2803) Port 2 */ SEALEVEL28033Did = 0x2833, /* SeaLINK+8 (2803) Port 3 */ SEALEVEL28034Did = 0x2843, /* SeaLINK+8 (2803) Port 4 */ SEALEVEL28035Did = 0x2853, /* SeaLINK+8 (2803) Port 5 */ SEALEVEL28036Did = 0x2863, /* SeaLINK+8 (2803) Port 6 */ SEALEVEL28037Did = 0x2873, /* SeaLINK+8 (2803) Port 7 */ SEALEVEL28038Did = 0x2883, /* SeaLINK+8 (2803) Port 8 */ /* KOBIL Vendor ID chipcard terminals */ KOBILVid = 0x0d46, KOBILCONVB1Did = 0x2020, /* KOBIL Konverter for B1 */ KOBILCONVKAANDid = 0x2021, /* KOBILKonverter for KAAN */ /* Icom ID-1 digital transceiver */ ICOMID1Vid = 0x0C26, ICOMID1Did = 0x0004, FTASKRDR400Did = 0xC991, /* ASK RDR 400 series card reader */ FTDSS20Did = 0xFC82, /* DSS-20 Sync Station for Sony Ericsson P800 */ /* * Home Electronics (www.home-electro.com) USB gadgets */ FTHETIRA1Did = 0xFA78, /* Tira-1 IR transceiver */ /* * An infrared receiver and transmitter using the 8U232AM chip * http://www.usbuirt.com */ FTUSBUIRTDid = 0xF850, FTELVUR100Did = 0xFB58, /* USB-RS232-Umsetzer (UR 100) */ FTELVUM100Did = 0xFB5A, /* USB-Modul UM 100 */ FTELVUO100Did = 0xFB5B, /* USB-Modul UO 100 */ FTELVALC8500Did = 0xF06E, /* ALC 8500 Expert */ FTELVCLI7000Did = 0xFB59, /* Computer-Light-Interface */ FTELVPPS7330Did = 0xFB5C, /* Processor-Power-Supply (PPS 7330) */ FTELVTFM100Did = 0xFB5D, /* Temperartur-Feuchte Messgeraet (TFM 100) */ FTELVUDF77Did = 0xFB5E, /* USB DCF Funkurh (UDF 77) */ FTELVUIO88Did = 0xFB5F, /* USB-I/O Interface (UIO 88) */ FTELVUAD8Did = 0xF068, /* USB-AD-Wandler (UAD 8) */ FTELVUDA7Did = 0xF069, /* USB-DA-Wandler (UDA 7) */ FTELVUSI2Did = 0xF06A, /* USB-Schrittmotoren-Interface (USI 2) */ FTELVT1100Did = 0xF06B, /* Thermometer (T 1100) */ FTELVPCD200Did = 0xF06C, /* PC-Datenlogger (PCD 200) */ FTELVULA200Did = 0xF06D, /* USB-LCD-Ansteuerung (ULA 200) */ FTELVFHZ1000PCDid= 0xF06F, /* FHZ 1000 PC */ FTELVCSI8Did = 0xE0F0, /* Computer-Schalt-Interface (CSI 8) */ FTELVEM1000DLDid= 0xE0F1, /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */ FTELVPCK100Did = 0xE0F2, /* PC-Kabeltester (PCK 100) */ FTELVRFP500Did = 0xE0F3, /* HF-Leistungsmesser (RFP 500) */ FTELVFS20SIGDid = 0xE0F4, /* Signalgeber (FS 20 SIG) */ FTELVWS300PCDid = 0xE0F6, /* PC-Wetterstation (WS 300 PC) */ FTELVFHZ1300PCDid= 0xE0E8, /* FHZ 1300 PC */ FTELVWS500Did = 0xE0E9, /* PC-Wetterstation (WS 500) */ /* * Definitions for ID TECH (http://www.idt-net.com) devices */ IDTECHVid = 0x0ACD, /* ID TECH Vendor ID */ IDTECHIDT1221UDid= 0x0300, /* IDT1221U USB to RS-232 */ /* * Definitions for Omnidirectional Control Technology, Inc. devices */ OCTVid = 0x0B39, /* OCT vendor ID */ /* * Note: OCT US101 is also rebadged as Dick Smith Electronics * (NZ) XH6381, Dick Smith Electronics (Aus) XH6451, and SIIG * Inc. model US2308 hardware version 1. */ OCTUS101Did = 0x0421, /* OCT US101 USB to RS-232 */ /* * infrared receiver for access control with IR tags */ FTPIEGROUPDid = 0xF208, /* * Definitions for Artemis astronomical USB based cameras * http://www.artemisccd.co.uk/ */ FTARTEMISDid = 0xDF28, /* All Artemis Cameras */ FTATIKATK16Did = 0xDF30, /* ATIK ATK-16 Grayscale Camera */ FTATIKATK16CDid = 0xDF32, /* ATIK ATK-16C Colour Camera */ FTATIKATK16HRDid= 0xDF31, /* ATIK ATK-16HR Grayscale */ FTATIKATK16HRCDid= 0xDF33, /* ATIK ATK-16HRC Colour Camera */ /* * Protego products */ PROTEGOSPECIAL1 = 0xFC70, /* special/unknown device */ PROTEGOR2X0 = 0xFC71, /* R200-USB TRNG unit (R210, R220, and R230) */ PROTEGOSPECIAL3 = 0xFC72, /* special/unknown device */ PROTEGOSPECIAL4 = 0xFC73, /* special/unknown device */ /* * Gude Analog- und Digitalsysteme GmbH */ FTGUDEADSE808Did = 0xE808, FTGUDEADSE809Did = 0xE809, FTGUDEADSE80ADid = 0xE80A, FTGUDEADSE80BDid = 0xE80B, FTGUDEADSE80CDid = 0xE80C, FTGUDEADSE80DDid = 0xE80D, FTGUDEADSE80EDid = 0xE80E, FTGUDEADSE80FDid = 0xE80F, FTGUDEADSE888Did = 0xE888, /* Expert ISDN Control USB */ FTGUDEADSE889Did = 0xE889, /* USB RS-232 OptoBridge */ FTGUDEADSE88ADid = 0xE88A, FTGUDEADSE88BDid = 0xE88B, FTGUDEADSE88CDid = 0xE88C, FTGUDEADSE88DDid = 0xE88D, FTGUDEADSE88EDid = 0xE88E, FTGUDEADSE88FDid = 0xE88F, /* * Linx Technologies */ LINXSDMUSBQSSDid= 0xF448, /* Linx SDM-USB-QS-S */ LINXMASTERDEVEL2Did= 0xF449, /* Linx Master Development.0 */ LINXFUTURE0Did = 0xF44A, /* Linx future device */ LINXFUTURE1Did = 0xF44B, /* Linx future device */ LINXFUTURE2Did = 0xF44C, /* Linx future device */ /* * CCS Inc. ICDU/ICDU40 - the FT232BM used in a in-circuit-debugger * unit for PIC16's/PIC18's */ FTCCSICDU200Did = 0xF9D0, FTCCSICDU401Did = 0xF9D1, /* Inside Accesso contactless reader (http://www.insidefr.com) */ INSIDEACCESSO = 0xFAD0, /* * Intrepid Control Systems (http://www.intrepidcs.com/) * ValueCAN and NeoVI */ INTREDidVid = 0x093C, INTREDidVALUECANDid= 0x0601, INTREDidNEOVIDid= 0x0701, /* * Falcom Wireless Communications GmbH */ FALCOMVid = 0x0F94, FALCOMTWISTDid = 0x0001, /* Falcom Twist USB GPRS modem */ FALCOMSAMBADid = 0x0005, /* Falcom Samba USB GPRS modem */ /* * SUUNTO */ FTSUUNTOSPORTSDid= 0xF680, /* Suunto Sports instrument */ /* * B&B Electronics */ BANDBVid = 0x0856, /* B&B Electronics Vendor ID */ BANDBUSOTL4Did = 0xAC01, /* USOTL4 Isolated RS-485 */ BANDBUSTL4Did = 0xAC02, /* USTL4 RS-485 Converter */ BANDBUSO9ML2Did = 0xAC03, /* USO9ML2 Isolated RS-232 */ /* * RM Michaelides CANview USB (http://www.rmcan.com) * CAN fieldbus interface adapter */ FTRMCANVIEWDid = 0xfd60, /* * EVER Eco Pro UPS (http://www.ever.com.pl/) */ EVERECOPROCDSDid = 0xe520, /* RS-232 converter */ /* * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485, * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices */ FT4NGALAXYDE0Did = 0x8372, FT4NGALAXYDE1Did = 0xF3C0, FT4NGALAXYDE2Did = 0xF3C1, /* * Mobility Electronics products. */ MOBILITYVid = 0x1342, MOBILITYUSBSERIALDid= 0x0202, /* EasiDock USB 200 serial */ /* * microHAM product IDs (http://www.microham.com) */ FTMHAMKWDid = 0xEEE8, /* USB-KW interface */ FTMHAMYSDid = 0xEEE9, /* USB-YS interface */ FTMHAMY6Did = 0xEEEA, /* USB-Y6 interface */ FTMHAMY8Did = 0xEEEB, /* USB-Y8 interface */ FTMHAMICDid = 0xEEEC, /* USB-IC interface */ FTMHAMDB9Did = 0xEEED, /* USB-DB9 interface */ FTMHAMRS232Did = 0xEEEE, /* USB-RS232 interface */ FTMHAMY9Did = 0xEEEF, /* USB-Y9 interface */ /* * Active Robots product ids. */ FTACTIVEROBOTSDid = 0xE548, /* USB comms board */ XSENSCONVERTER0Did = 0xD388, XSENSCONVERTER1Did = 0xD389, XSENSCONVERTER2Did = 0xD38A, XSENSCONVERTER3Did = 0xD38B, XSENSCONVERTER4Did = 0xD38C, XSENSCONVERTER5Did = 0xD38D, XSENSCONVERTER6Did = 0xD38E, XSENSCONVERTER7Did = 0xD38F, /* * Xsens Technologies BV products (http://www.xsens.com). */ FTTERATRONIKVCPDid = 0xEC88, /* Teratronik device */ FTTERATRONIKD2XXDid = 0xEC89, /* Teratronik device */ /* * Evolution Robotics products (http://www.evolution.com/). */ EVOLUTIONVid = 0xDEEE, EVOLUTIONER1Did = 0x0300, /* ER1 Control Module */ /* Pyramid Computer GmbH */ FTPYRAMIDDid = 0xE6C8, /* Pyramid Appliance Display */ /* * Posiflex inc retail equipment (http://www.posiflex.com.tw) */ POSIFLEXVid = 0x0d3a, POSIFLEXPP7000Did= 0x0300, /* PP-7000II thermal printer */ /* * Westrex International devices */ FTWESTREXMODEL777Did = 0xDC00, /* Model 777 */ FTWESTREXMODEL8900FDid = 0xDC01, /* Model 8900F */ /* * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) */ FTRRCIRKITSLOCOBUFFERDid= 0xc7d0, /* LocoBuffer USB */ FTECLOCOM1WIREDid = 0xEA90, /* COM to 1-Wire USB */ /* * Papouch products (http://www.papouch.com/) */ PAPOUCHVid = 0x5050, PAPOUCHTMUDid = 0x0400, /* TMU USB Thermometer */ /* * ACG Identification Technologies GmbH products http://www.acg.de/ */ FTACGHFDUALDid = 0xDD20, /* HF Dual ISO Reader (RFID) */ /* * new high speed devices */ FT4232HDid = 0x6011, /* FTDI FT4232H based device */ }; /* Commands */ enum { FTRESET = 0, /* Reset the port */ FTSETMODEMCTRL, /* Set the modem control register */ FTSETFLOWCTRL, /* Set flow control register */ FTSETBaudRate, /* Set baud rate */ FTSETDATA, /* Set the parameters, parity */ FTGETMODEMSTATUS, /* Retrieve current value of modem ctl */ FTSETEVENTCHAR, /* Set the event character */ FTSETERRORCHAR, /* Set the error character */ FTSETLATENCYTIMER, /* Set the latency timer */ FTGETLATENCYTIMER, /* Get the latency timer */ FTSETBITMODE, /* Set bigbang mode */ FTGETPINS, /* Read pins state */ FTGETE2READ = 0x90, /* Read an address from EEPROM */ FTSETE2WRITE, /* Write to address on the EEPROM */ FTSETE2ERASE, /* Erase address on the EEPROM */ }; enum { Rftdireq = 1<<6, /* bit for type of request */ }; /* * Commands Data size * Sets have wLength = 0 * Gets have wValue = 0 */ enum { FTGETMODEMSTATUSSZ = 1, FTGETLATENCYTIMERSZ = 0, /* Get the latency timer */ FTGETE2READSZ = 2, /* Read an address */ }; /* * bRequest: FTGETE2READ * wIndex: Address of word to read * Data: Will return a word of data from E2Address */ /* Port Identifier Table */ enum { PITDEFAULT = 0, /* SIOA */ PITA, /* SIOA */ }; /* * bRequest: FTRESET * wValue: Ctl Val * wIndex: Port */ enum { FTRESETCTLVAL = 0, FTRESETCTLVALPURGERX = 1, FTRESETCTLVALPURGETX = 2, }; /* * BmRequestType: SET * bRequest: FTSETBaudRate * wValue: BaudDivisor value - see below * Bits 15 to 0 of the 17-bit divisor are placed in the request value. * Bit 16 is placed in bit 0 of the request index. */ /* chip type */ enum { SIO = 1, FT8U232AM = 2, FT232BM = 3, FT2232C = 4, FTKINDR = 5, FT2232H = 6, FT4232H = 7, }; enum { FTb300 = 0, FTb600 = 1, FTb1200 = 2, FTb2400 = 3, FTb4800 = 4, FTb9600 = 5, FTb19200 = 6, FTb38400 = 7, FTb57600 = 8, FTb115200 = 9, }; /* * bRequest: FTSETDATA * wValue: Data characteristics * wIndex: Port */ enum { FTSETDATAParNONE = 0 << 8, FTSETDATAParODD = 1 << 8, FTSETDATAParEVEN = 2 << 8, FTSETDATAParMARK = 3 << 8, FTSETDATAParSPACE = 4 << 8, FTSETDATASTOPBITS1 = 0 << 11, FTSETDATASTOPBITS15 = 1 << 11, FTSETDATASTOPBITS2 = 2 << 11, FTSETBREAK = 1 << 14, }; /* * bRequest: FTSETMODEMCTRL * wValue: ControlValue (see below) * wIndex: Port */ /* * bRequest: FTSETFLOWCTRL * wValue: Xoff/Xon * wIndex: Protocol/Port - hIndex is protocl / lIndex is port */ enum { FTDISABLEFLOWCTRL= 0, FTRTSCTSHS = 1 << 8, FTDTRDSRHS = 2 << 8, FTXONXOFFHS = 4 << 8, }; /* * bRequest: FTGETLATENCYTIMER * wIndex: Port * wLength: 0 * Data: latency (on return) */ enum { LTGETMASK = 0xa, }; /* * bRequest: FTSETBITMODE * wIndex: Port * wValue: bitbang mode */ enum { BMSERIAL = 0, /* turn off bitbang mode */ BMBM = 1<<8, /* async mode */ BMMPSSE = 2<<8, BMSYNCBB = 4<<8, /* sync bitbang -- 2232x and R-type */ BMMCU = 8<<8, /* MCU Host Bus -- 2232x */ BMOPTO = 0x10<<8, /* opto-isolated<<8, 2232x */ BMCBUS = 0x20<<8, /* CBUS pins of R-type chips */ BMSYNCFF = 0x40<<8, /* Single Channel Sync FIFO, 2232H only */ BMMASK = 0xb }; /* * bRequest: FTSETLATENCYTIMER * wValue: Latency (milliseconds) * wIndex: Port */ enum { FTDEFAULT = 2, LTSETMASK = 0x9, }; /* * BmRequestType: SET * bRequest: FTSETEVENTCHAR * wValue: EventChar * wIndex: Port */ /* * BmRequestType: SET * bRequest: FTSETERRORCHAR * wValue: Error Char * wIndex: Port */ /* * BmRequestType: GET * bRequest: FTGETMODEMSTATUS * wIndex: Port * wLength: 1 * Data: Status */ enum { FTCTSMASK = 0x10, FTDSRMASK = 0x20, FTRIMASK = 0x40, FTRLSDMASK = 0x80, }; enum { /* byte 0 of in data hdr */ FTICTS = 1 << 4, FTIDSR = 1 << 5, FTIRI = 1 << 6, FTIRLSD = 1 << 7, /* receive line signal detect */ /* byte 1 of in data hdr */ FTIDR = 1<<0, /* data ready */ FTIOE = 1<<1, /* overrun error */ FTIPE = 1<<2, /* parity error */ FTIFE = 1<<3, /* framing error */ FTIBI = 1<<4, /* break interrupt */ FTITHRE = 1<<5, /* xmitter holding register */ FTITEMT = 1<<6, /* xmitter empty */ FTIFIFO = 1<<7, /* error in rcv fifo */ /* byte 0 of out data hdr len does not include byte 0 */ FTOLENMSK= 0x3F, FTOPORT = 0x80, /* must be set */ }; extern Serialops ftops; int ftmatch(Serial *ser, char *info); 500) */ FTELVFS20SIGDid = 0xE0F4, /* Signalgeber (FS 20 SIG) */ FTELVWS300PCDid = 0xE0F6, /* PC-Wetterstation (WS 300 PC) */ FTELVFHZ1300PCDid= 0xE0E8, /* FHZ 1300 PC */ FTELVWS500Did = 0xE0E9, /* PC-Wetterstation (WS 500) */ /* * Definitions for ID TECH (http://www.idt-net.com) devices */ IDTECHVid = 0x0ACD, /* ID TECH Vendor ID */ IDTECHIDT1221UDid= 0x0300, /* IDT1221U USB to RS-232 */ /* * Definitions for Omnidirectional Control Technology, Inc. devices */ OCTVid = 0x0usb/serial/main.c 664 0 0 2336 11412732475 11716ustar00syssys#include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "ucons.h" #include "prolific.h" #include "ftdi.h" enum { Arglen = 80, }; typedef struct Parg Parg; /* keep in sync with serial.c */ static void usage(void) { fprint(2, "usage: %s [-dD] [-N nb] [-m mtpt] [-s srv] [dev...]\n", argv0); threadexitsall("usage"); } static int matchserial(char *info, void*) { if(uconsmatch(info) == 0 || plmatch(info) == 0 || ftmatch(nil, info) == 0) return 0; return -1; } void threadmain(int argc, char **argv) { char *mnt, *srv, *as, *ae; char args[Arglen]; mnt = "/dev"; srv = nil; quotefmtinstall(); ae = args + sizeof args; as = seprint(args, ae, "serial"); ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; as = seprint(as, ae, " -d"); break; case 'N': as = seprint(as, ae, " -N %s", EARGF(usage())); break; case 'm': mnt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); break; }ARGEND; rfork(RFNOTEG); fmtinstall('U', Ufmt); threadsetgrp(threadid()); usbfsinit(srv, mnt, &usbdirfs, MAFTER|MCREATE); startdevs(args, argv, argc, matchserial, nil, serialmain); threadexits(nil); } e */ LINXFUTURE1Did = 0xF44B, /* Linx future device */ LINXFUTURE2Did = 0xF44C, /* Linx future device */ /* * CCS Inc. ICDU/ICDU40 - the FT232BM used in a in-circuit-debugger * unit for PIC16's/PIC18's */ FTCCSICDU200Did = 0xF9D0, FTCCSICDU401Did = 0xF9D1, /* Inside Accesso cusb/serial/mkfile 664 0 0 702 11321707426 11770ustar00syssys #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "prolific.h" Cinfo plinfo[] = { { PL2303Vid, PL2303Did }, { PL2303Vid, PL2303DidRSAQ2 }, { PL2303Vid, PL2303DidDCU11 }, { PL2303Vid, PL2303DidRSAQ3 }, { PL2303Vid, PL2303DidPHAROS }, { PL2303Vid, PL2303DidALDIGA }, { PL2303Vid, PL2303DidMMX }, { PL2303Vid, PL2303DidGPRS }, { IODATAVid, IODATADid }, { IODATAVid, IODATADidRSAQ5 }, { ATENVid, ATENDid }, { ATENVid2, ATENDid }, { ELCOMVid, ELCOMDid }, { ELCOMVid, ELCOMDidUCSGT }, { ITEGNOVid, ITEGNODid }, { ITEGNOVid, ITEGNODid2080 }, { MA620Vid, MA620Did }, { RATOCVid, RATOCDid }, { TRIPPVid, TRIPPDid }, { RADIOSHACKVid,RADIOSHACKDid }, { DCU10Vid, DCU10Did }, { SITECOMVid, SITECOMDid }, { ALCATELVid, ALCATELDid }, { SAMSUNGVid, SAMSUNGDid }, { SIEMENSVid, SIEMENSDidSX1 }, { SIEMENSVid, SIEMENSDidX65 }, { SIEMENSVid, SIEMENSDidX75 }, { SIEMENSVid, SIEMENSDidEF81 }, { SYNTECHVid, SYNTECHDid }, { NOKIACA42Vid, NOKIACA42Did }, { CA42CA42Vid, CA42CA42Did }, { SAGEMVid, SAGEMDid }, { LEADTEKVid, LEADTEK9531Did }, { SPEEDDRAGONVid,SPEEDDRAGONDid }, { DATAPILOTU2Vid,DATAPILOTU2Did }, { BELKINVid, BELKINDid }, { ALCORVid, ALCORDid }, { WS002INVid, WS002INDid }, { COREGAVid, COREGADid }, { YCCABLEVid, YCCABLEDid }, { SUPERIALVid, SUPERIALDid }, { HPVid, HPLD220Did }, { 0, 0 }, }; int plmatch(char *info) { Cinfo *ip; char buf[50]; for(ip = plinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s\n", buf, info); if(strstr(info, buf) != nil) return 0; } return -1; } static void statusreader(void *u); static void dumpbuf(uchar *buf, int bufsz) { int i; for(i=0; is; dsprint(2, "serial: vendorread val: 0x%x idx:%d buf:%p\n", val, index, buf); res = usbcmd(ser->dev, Rd2h | Rvendor | Rdev, VendorReadReq, val, index, buf, 1); dsprint(2, "serial: vendorread res:%d\n", res); return res; } static int vendorwrite(Serialport *p, int val, int index) { int res; Serial *ser; ser = p->s; dsprint(2, "serial: vendorwrite val: 0x%x idx:%d\n", val, index); res = usbcmd(ser->dev, Rh2d | Rvendor | Rdev, VendorWriteReq, val, index, nil, 0); dsprint(2, "serial: vendorwrite res:%d\n", res); return res; } /* BUG: I could probably read Dcr0 and set only the bits */ static int plmodemctl(Serialport *p, int set) { Serial *ser; ser = p->s; if(set == 0){ p->mctl = 0; vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init); return 0; } p->mctl = 1; if(ser->type == TypeHX) vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcX); else vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcH); return 0; } static int plgetparam(Serialport *p) { uchar buf[ParamReqSz]; int res; Serial *ser; ser = p->s; res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq, 0, 0, buf, sizeof buf); p->baud = GET4(buf); /* * with the Pl9 interface it is not possible to set `1.5' as stop bits * for the prologic: * 0 is 1 stop bit * 1 is 1.5 stop bits * 2 is 2 stop bits */ if(buf[4] == 1) fprint(2, "warning, stop bit set to 1.5 unsupported"); else if(buf[4] == 0) p->stop = 1; else if(buf[4] == 2) p->stop = 2; p->parity = buf[5]; p->bits = buf[6]; dsprint(2, "serial: getparam: "); if(serialdebug) dumpbuf(buf, sizeof buf); dsprint(2, "serial: getparam res: %d\n", res); return res; } static int plsetparam(Serialport *p) { uchar buf[ParamReqSz]; int res; Serial *ser; ser = p->s; PUT4(buf, p->baud); if(p->stop == 1) buf[4] = 0; else if(p->stop == 2) buf[4] = 2; /* see comment in getparam */ buf[5] = p->parity; buf[6] = p->bits; dsprint(2, "serial: setparam: "); if(serialdebug) dumpbuf(buf, sizeof buf); res = usbcmd(ser->dev, Rh2d | Rclass | Riface, SetLineReq, 0, 0, buf, sizeof buf); plmodemctl(p, p->mctl); plgetparam(p); /* make sure our state corresponds */ dsprint(2, "serial: setparam res: %d\n", res); return res; } static int revid(ulong devno) { switch(devno){ case RevH: return TypeH; case RevX: case RevHX: case Rev1: return TypeHX; default: return TypeUnk; } } /* linux driver says the release id is not always right */ static int heuristicid(ulong csp, ulong maxpkt) { if(Class(csp) == 0x02) return TypeH; else if(maxpkt == 0x40) return TypeHX; else if(Class(csp) == 0x00 || Class(csp) == 0xFF) return TypeH; else{ fprint(2, "serial: chip unknown, setting to HX version\n"); return TypeHX; } } static int plinit(Serialport *p) { char *st; uchar *buf; ulong csp, maxpkt, dno; Serial *ser; ser = p->s; buf = emallocz(VendorReqSz, 1); dsprint(2, "plinit\n"); csp = ser->dev->usb->csp; maxpkt = ser->dev->maxpkt; dno = ser->dev->usb->dno; if((ser->type = revid(dno)) == TypeUnk) ser->type = heuristicid(csp, maxpkt); dsprint(2, "serial: type %d\n", ser->type); vendorread(p, 0x8484, 0, buf); vendorwrite(p, 0x0404, 0); vendorread(p, 0x8484, 0, buf); vendorread(p, 0x8383, 0, buf); vendorread(p, 0x8484, 0, buf); vendorwrite(p, 0x0404, 1); vendorread(p, 0x8484, 0, buf); vendorread(p, 0x8383, 0, buf); vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init); vendorwrite(p, Dcr1Idx|DcrSet, Dcr1Init); if(ser->type == TypeHX) vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitX); else vendorwrite(p, Dcr2Idx|DcrSet, Dcr2InitH); plgetparam(p); qunlock(ser); free(buf); st = emallocz(255, 1); qlock(ser); if(serialdebug) serdumpst(p, st, 255); dsprint(2, st); free(st); /* p gets freed by closedev, the process has a reference */ incref(ser->dev); proccreate(statusreader, p, 8*1024); return 0; } static int plsetbreak(Serialport *p, int val) { Serial *ser; ser = p->s; return usbcmd(ser->dev, Rh2d | Rclass | Riface, (val != 0? BreakOn: BreakOff), val, 0, nil, 0); } static int plclearpipes(Serialport *p) { Serial *ser; ser = p->s; if(ser->type == TypeHX){ vendorwrite(p, PipeDSRst, 0); vendorwrite(p, PipeUSRst, 0); }else{ if(unstall(ser->dev, p->epout, Eout) < 0) dprint(2, "disk: unstall epout: %r\n"); if(unstall(ser->dev, p->epin, Ein) < 0) dprint(2, "disk: unstall epin: %r\n"); if(unstall(ser->dev, p->epintr, Ein) < 0) dprint(2, "disk: unstall epintr: %r\n"); } return 0; } static int setctlline(Serialport *p, uchar val) { Serial *ser; ser = p->s; return usbcmd(ser->dev, Rh2d | Rclass | Riface, SetCtlReq, val, 0, nil, 0); } static void composectl(Serialport *p) { if(p->rts) p->ctlstate |= CtlRTS; else p->ctlstate &= ~CtlRTS; if(p->dtr) p->ctlstate |= CtlDTR; else p->ctlstate &= ~CtlDTR; } static int plsendlines(Serialport *p) { int res; dsprint(2, "serial: sendlines: %#2.2x\n", p->ctlstate); composectl(p); res = setctlline(p, p->ctlstate); dsprint(2, "serial: sendlines res: %d\n", res); return 0; } static int plreadstatus(Serialport *p) { int nr, dfd; char err[40]; uchar buf[VendorReqSz]; Serial *ser; ser = p->s; qlock(ser); dsprint(2, "serial: reading from interrupt\n"); dfd = p->epintr->dfd; qunlock(ser); nr = read(dfd, buf, sizeof buf); qlock(ser); snprint(err, sizeof err, "%r"); dsprint(2, "serial: interrupt read %d %r\n", nr); 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){ qunlock(ser); return -1; } } if(nr < 0) dsprint(2, "serial: reading status: %r"); else if(nr >= sizeof buf - 1){ p->dcd = buf[8] & DcdStatus; p->dsr = buf[8] & DsrStatus; p->cts = buf[8] & BreakerrStatus; p->ring = buf[8] & RingStatus; p->cts = buf[8] & CtsStatus; if(buf[8] & FrerrStatus) p->nframeerr++; if(buf[8] & ParerrStatus) p->nparityerr++; if(buf[8] & OvererrStatus) p->novererr++; } else dsprint(2, "serial: bad status read %d\n", nr); dsprint(2, "serial: finished read from interrupt %d\n", nr); qunlock(ser); return 0; } static void statusreader(void *u) { Serialport *p; Serial *ser; p = u; ser = p->s; threadsetname("statusreaderproc"); while(plreadstatus(p) >= 0) ; fprint(2, "serial: statusreader exiting\n"); closedev(ser->dev); } /* * Maximum number of bytes transferred per frame * The output buffer size cannot be increased due to the size encoding */ static int plseteps(Serialport *p) { devctl(p->epin, "maxpkt 256"); devctl(p->epout, "maxpkt 256"); return 0; } Serialops plops = { .init = plinit, .getparam = plgetparam, .setparam = plsetparam, .clearpipes = plclearpipes, .sendlines = plsendlines, .modemctl = plmodemctl, .setbreak = plsetbreak, .seteps = plseteps, }; 664 0 0 702 11321707426 11770ustar00syssysusb/serial/prolific.h 664 0 0 6117 11321707416 12603ustar00syssysenum { /* flavours of the device */ TypeH, TypeHX, TypeUnk, RevH = 0x0202, RevX = 0x0300, RevHX = 0x0400, Rev1 = 0x0001, /* usbcmd parameters */ SetLineReq = 0x20, SetCtlReq = 0x22, BreakReq = 0x23, BreakOn = 0xffff, BreakOff = 0x0000, GetLineReq = 0x21, VendorWriteReq = 0x01, /* BUG: is this a standard request? */ VendorReadReq = 0x01, ParamReqSz = 7, VendorReqSz = 10, /* status read from interrupt endpoint */ DcdStatus = 0x01, DsrStatus = 0x02, BreakerrStatus = 0x04, RingStatus = 0x08, FrerrStatus = 0x10, ParerrStatus = 0x20, OvererrStatus = 0x40, CtsStatus = 0x80, DcrGet = 0x80, DcrSet = 0x00, Dcr0Idx = 0x00, Dcr0Init = 0x0001, Dcr0HwFcH = 0x0040, Dcr0HwFcX = 0x0060, Dcr1Idx = 0x01, Dcr1Init = 0x0000, Dcr1InitH = 0x0080, Dcr1InitX = 0x0000, Dcr2Idx = 0x02, Dcr2InitH = 0x0024, Dcr2InitX = 0x0044, PipeDSRst = 0x08, PipeUSRst = 0x09, }; enum { PL2303Vid = 0x067b, PL2303Did = 0x2303, PL2303DidRSAQ2 = 0x04bb, PL2303DidDCU11 = 0x1234, PL2303DidPHAROS = 0xaaa0, PL2303DidRSAQ3 = 0xaaa2, PL2303DidALDIGA = 0x0611, PL2303DidMMX = 0x0612, PL2303DidGPRS = 0x0609, ATENVid = 0x0557, ATENVid2 = 0x0547, ATENDid = 0x2008, IODATAVid = 0x04bb, IODATADid = 0x0a03, IODATADidRSAQ5 = 0x0a0e, ELCOMVid = 0x056e, ELCOMDid = 0x5003, ELCOMDidUCSGT = 0x5004, ITEGNOVid = 0x0eba, ITEGNODid = 0x1080, ITEGNODid2080 = 0x2080, MA620Vid = 0x0df7, MA620Did = 0x0620, RATOCVid = 0x0584, RATOCDid = 0xb000, TRIPPVid = 0x2478, TRIPPDid = 0x2008, RADIOSHACKVid = 0x1453, RADIOSHACKDid = 0x4026, DCU10Vid = 0x0731, DCU10Did = 0x0528, SITECOMVid = 0x6189, SITECOMDid = 0x2068, /* Alcatel OT535/735 USB cable */ ALCATELVid = 0x11f7, ALCATELDid = 0x02df, /* Samsung I330 phone cradle */ SAMSUNGVid = 0x04e8, SAMSUNGDid = 0x8001, SIEMENSVid = 0x11f5, SIEMENSDidSX1 = 0x0001, SIEMENSDidX65 = 0x0003, SIEMENSDidX75 = 0x0004, SIEMENSDidEF81 = 0x0005, SYNTECHVid = 0x0745, SYNTECHDid = 0x0001, /* Nokia CA-42 Cable */ NOKIACA42Vid = 0x078b, NOKIACA42Did = 0x1234, /* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ CA42CA42Vid = 0x10b5, CA42CA42Did = 0xac70, SAGEMVid = 0x079b, SAGEMDid = 0x0027, /* Leadtek GPS 9531 (ID 0413:2101) */ LEADTEKVid = 0x0413, LEADTEK9531Did = 0x2101, /* USB GSM cable from Speed Dragon Multimedia, Ltd */ SPEEDDRAGONVid = 0x0e55, SPEEDDRAGONDid = 0x110b, /* DATAPILOT Universal-2 Phone Cable */ BELKINVid = 0x050d, BELKINDid = 0x0257, /* Belkin "F5U257" Serial Adapter */ DATAPILOTU2Vid = 0x0731, DATAPILOTU2Did = 0x2003, ALCORVid = 0x058F, ALCORDid = 0x9720, /* Willcom WS002IN Data Driver (by NetIndex Inc.) */, WS002INVid = 0x11f6, WS002INDid = 0x2001, /* Corega CG-USBRS232R Serial Adapter */, COREGAVid = 0x07aa, COREGADid = 0x002a, /* Y.C. Cable U.S.A., Inc - USB to RS-232 */, YCCABLEVid = 0x05ad, YCCABLEDid = 0x0fba, /* "Superial" USB - Serial */, SUPERIALVid = 0x5372, SUPERIALDid = 0x2303, /* Hewlett-Packard LD220-HP POS Pole Display */, HPVid = 0x03f0, HPLD220Did = 0x3524, }; extern Serialops plops; int plmatch(char *info); (set == 0){ p->mctl = 0; vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init); return 0; } p->mctl = 1; if(ser->type == TypeHX) vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcX); else vendorwrite(p, Dcr0Idx|DcrSet, Dcr0Init|Dcr0HwFcH); return 0; } static int plgetparam(Serialport *p) { uchar buf[ParamReqSz]; int res; Serial *ser; ser = p->s; res = usbcmd(ser->dev, Rd2h | Rclass | Riface, GetLineReq, 0, 0, buf, sizusb/serial/serial.c 664 0 0 37244 11457526130 12275ustar00syssys/* * This part takes care of locking except for initialization and * other threads created by the hw dep. drivers. */ #include #include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "prolific.h" #include "ucons.h" #include "ftdi.h" int serialdebug; enum { /* Qids. Maintain order (relative to dirtabs structs) */ Qroot = 0, Qctl, Qdata, Qmax, }; typedef struct Dirtab Dirtab; struct Dirtab { char *name; int mode; }; static Dirtab dirtab[] = { [Qroot] "/", DMDIR|0555, [Qdata] "eiaU", 0660, [Qctl] "eiaUctl", 0664, }; static int sdebug; static void serialfatal(Serial *ser) { Serialport *p; int i; dsprint(2, "serial: fatal error, detaching\n"); devctl(ser->dev, "detach"); for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; if(p->isjtag) continue; usbfsdel(&p->fs); if(p->w4data != nil) chanclose(p->w4data); if(p->gotdata != nil) chanclose(p->gotdata); if(p->readc) chanclose(p->readc); } } /* I sleep with the lock... only way to drain in general */ static void serialdrain(Serialport *p) { Serial *ser; uint baud, pipesize; ser = p->s; baud = p->baud; if(p->baud == ~0) return; if(ser->maxwtrans < 256) pipesize = 256; else pipesize = ser->maxwtrans; /* wait for the at least 256-byte pipe to clear */ sleep(10 + pipesize/((1 + baud)*1000)); if(ser->clearpipes != nil) ser->clearpipes(p); } /* BUG: separate reset per port */ int serialreset(Serial *ser) { Serialport *p; int i; /* cmd for reset */ for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; if(p->isjtag) continue; serialdrain(p); } if(ser->reset != nil) ser->reset(ser); return 0; } /* call this if something goes wrong */ int serialrecover(Serial *ser, char *err) { if(strstr(err, "detached") != nil) return -1; if(ser->recover > 1) serialfatal(ser); ser->recover++; if(serialreset(ser) < 0) return -1; ser->recover = 0; return 0; } static int serialctl(Serialport *p, char *cmd) { Serial *ser; int c, i, n, nf, nop, nw, par, drain, set, lines; char *f[16]; uchar x; ser = p->s; drain = set = lines = 0; nf = tokenize(cmd, f, nelem(f)); for(i = 0; i < nf; i++){ if(strncmp(f[i], "break", 5) == 0){ if(ser->setbreak != nil) ser->setbreak(p, 1); continue; } nop = 0; n = atoi(f[i]+1); c = *f[i]; if (isascii(c) && isupper(c)) c = tolower(c); switch(c){ case 'b': drain++; p->baud = n; set++; break; case 'c': p->dcd = n; // lines++; ++nop; break; case 'd': p->dtr = n; lines++; break; case 'e': p->dsr = n; // lines++; ++nop; break; case 'f': /* flush the pipes */ drain++; break; case 'h': /* hangup?? */ p->rts = p->dtr = 0; lines++; fprint(2, "serial: %c, unsure ctl\n", c); break; case 'i': ++nop; break; case 'k': drain++; ser->setbreak(p, 1); sleep(n); ser->setbreak(p, 0); break; case 'l': drain++; p->bits = n; set++; break; case 'm': drain++; if(ser->modemctl != nil) ser->modemctl(p, n); if(n == 0) p->cts = 0; break; case 'n': p->blocked = n; ++nop; break; case 'p': /* extended... */ if(strlen(f[i]) != 2) return -1; drain++; par = f[i][1]; if(par == 'n') p->parity = 0; else if(par == 'o') p->parity = 1; else if(par == 'e') p->parity = 2; else if(par == 'm') /* mark parity */ p->parity = 3; else if(par == 's') /* space parity */ p->parity = 4; else return -1; set++; break; case 'q': // drain++; p->limit = n; ++nop; break; case 'r': drain++; p->rts = n; lines++; break; case 's': drain++; p->stop = n; set++; break; case 'w': /* ?? how do I put this */ p->timer = n * 100000LL; ++nop; break; case 'x': if(n == 0) x = CTLS; else x = CTLQ; if(ser->wait4write != nil) nw = ser->wait4write(p, &x, 1); else nw = write(p->epout->dfd, &x, 1); if(nw != 1){ serialrecover(ser, ""); return -1; } break; } /* * don't print. the condition is harmless and the print * splatters all over the display. */ USED(nop); if (0 && nop) fprint(2, "serial: %c, unsupported nop ctl\n", c); } if(drain) serialdrain(p); if(lines && !set){ if(ser->sendlines != nil && ser->sendlines(p) < 0) return -1; } else if(set){ if(ser->setparam != nil && ser->setparam(p) < 0) return -1; } return 0; } char *pformat = "noems"; char * serdumpst(Serialport *p, char *buf, int bufsz) { char *e, *s; Serial *ser; ser = p->s; e = buf + bufsz; s = seprint(buf, e, "b%d ", p->baud); s = seprint(s, e, "c%d ", p->dcd); /* unimplemented */ s = seprint(s, e, "d%d ", p->dtr); s = seprint(s, e, "e%d ", p->dsr); /* unimplemented */ s = seprint(s, e, "l%d ", p->bits); s = seprint(s, e, "m%d ", p->mctl); if(p->parity >= 0 || p->parity < strlen(pformat)) s = seprint(s, e, "p%c ", pformat[p->parity]); else s = seprint(s, e, "p%c ", '?'); s = seprint(s, e, "r%d ", p->rts); s = seprint(s, e, "s%d ", p->stop); s = seprint(s, e, "i%d ", p->fifo); s = seprint(s, e, "\ndev(%d) ", 0); s = seprint(s, e, "type(%d) ", ser->type); s = seprint(s, e, "framing(%d) ", p->nframeerr); s = seprint(s, e, "overruns(%d) ", p->novererr); s = seprint(s, e, "berr(%d) ", p->nbreakerr); s = seprint(s, e, " serr(%d)\n", p->nparityerr); return s; } static int serinit(Serialport *p) { int res; res = 0; Serial *ser; ser = p->s; if(ser->init != nil) res = ser->init(p); if(ser->getparam != nil) ser->getparam(p); p->nframeerr = p->nparityerr = p->nbreakerr = p->novererr = 0; return res; } static int dwalk(Usbfs *fs, Fid *fid, char *name) { int i; char *dname; Qid qid; Serialport *p; qid = fid->qid; if((qid.type & QTDIR) == 0){ werrstr("walk in non-directory"); return -1; } if(strcmp(name, "..") == 0){ /* must be /eiaU%d; i.e. our root dir. */ fid->qid.path = Qroot | fs->qid; fid->qid.vers = 0; fid->qid.type = QTDIR; return 0; } p = fs->aux; for(i = 1; i < nelem(dirtab); i++){ dname = smprint(dirtab[i].name, p->fs.name); if(strcmp(name, dname) == 0){ qid.path = i | fs->qid; qid.vers = 0; qid.type = dirtab[i].mode >> 24; fid->qid = qid; free(dname); return 0; } else free(dname); } werrstr(Enotfound); return -1; } static void dostat(Usbfs *fs, int path, Dir *d) { Dirtab *t; Serialport *p; t = &dirtab[path]; d->qid.path = path; d->qid.type = t->mode >> 24; d->mode = t->mode; p = fs->aux; if(strcmp(t->name, "/") == 0) d->name = t->name; else snprint(d->name, Namesz, t->name, p->fs.name); d->length = 0; } static int dstat(Usbfs *fs, Qid qid, Dir *d) { int path; path = qid.path & ~fs->qid; dostat(fs, path, d); d->qid.path |= fs->qid; return 0; } static int dopen(Usbfs *fs, Fid *fid, int) { ulong path; Serialport *p; path = fid->qid.path & ~fs->qid; p = fs->aux; switch(path){ /* BUG: unneeded? */ case Qdata: dsprint(2, "serial, opened data\n"); break; case Qctl: dsprint(2, "serial, opened ctl\n"); serialctl(p, "l8 i1"); /* default line parameters */ break; } return 0; } static void filldir(Usbfs *fs, Dir *d, Dirtab *tab, int i) { d->qid.path = i | fs->qid; d->mode = tab->mode; if((d->mode & DMDIR) != 0) d->qid.type = QTDIR; else d->qid.type = QTFILE; d->name = tab->name; } static int dirgen(Usbfs *fs, Qid, int i, Dir *d, void *) { i++; /* skip root */ if(i >= nelem(dirtab)) return -1; filldir(fs, d, &dirtab[i], i); return 0; } enum { Serbufsize = 255, }; static long dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) { int dfd; long rcount; ulong path; char *e, *buf, *err; /* change */ Qid q; Serialport *p; Serial *ser; static int errrun, good; q = fid->qid; path = fid->qid.path & ~fs->qid; p = fs->aux; ser = p->s; buf = emallocz(Serbufsize, 1); err = emallocz(Serbufsize, 1); qlock(ser); switch(path){ case Qroot: count = usbdirread(fs, q, data, count, offset, dirgen, nil); break; case Qdata: if(count > ser->maxread) count = ser->maxread; dsprint(2, "serial: reading from data\n"); do { err[0] = 0; dfd = p->epin->dfd; if(usbdebug >= 3) dsprint(2, "serial: reading: %ld\n", count); assert(count > 0); if(ser->wait4data != nil) rcount = ser->wait4data(p, data, count); else{ qunlock(ser); rcount = read(dfd, data, count); qlock(ser); } /* * if we encounter a long run of continuous read * errors, do something drastic so that our caller * doesn't just spin its wheels forever. */ if(rcount < 0) { snprint(err, Serbufsize, "%r"); ++errrun; sleep(20); if (good > 0 && errrun > 10000) { /* the line has been dropped; give up */ qunlock(ser); fprint(2, "%s: line %s is gone: %r\n", argv0, p->fs.name); threadexitsall("serial line gone"); } } else { errrun = 0; good++; } if(usbdebug >= 3) dsprint(2, "serial: read: %s %ld\n", err, rcount); } while(rcount < 0 && strstr(err, "timed out") != nil); dsprint(2, "serial: read from bulk %ld, %10.10s\n", rcount, err); if(rcount < 0){ dsprint(2, "serial: need to recover, data read %ld %r\n", count); serialrecover(ser, err); } dsprint(2, "serial: read from bulk %ld\n", rcount); count = rcount; break; case Qctl: if(offset != 0) count = 0; else { e = serdumpst(p, buf, Serbufsize); count = usbreadbuf(data, count, 0, buf, e - buf); } break; } qunlock(ser); free(err); free(buf); return count; } static long altwrite(Serialport *p, uchar *buf, long count) { int nw, dfd; char err[128]; Serial *ser; ser = p->s; do{ if(ser->wait4write != nil) /* unlocked inside later */ nw = ser->wait4write(p, buf, count); else{ dfd = p->epout->dfd; qunlock(ser); nw = write(dfd, buf, count); qlock(ser); } rerrstr(err, sizeof err); } while(nw < 0 && strstr(err, "timed out") != nil); if(nw != count){ dsprint(2, "serial: need to recover, status in write %d %r\n", nw); snprint(err, sizeof err, "%r"); serialrecover(p->s, err); } return nw; } static long dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong) { ulong path; char *cmd; Serialport *p; Serial *ser; p = fs->aux; ser = p->s; path = fid->qid.path & ~fs->qid; qlock(ser); switch(path){ case Qdata: count = altwrite(p, (uchar *)buf, count); break; case Qctl: cmd = emallocz(count+1, 1); memmove(cmd, buf, count); cmd[count] = 0; if(serialctl(p, cmd) < 0){ qunlock(ser); werrstr(Ebadctl); free(cmd); return -1; } free(cmd); break; default: qunlock(ser); werrstr(Eperm); return -1; } qunlock(ser); return count; } static int openeps(Serialport *p, int epin, int epout, int epintr) { Serial *ser; ser = p->s; p->epin = openep(ser->dev, epin); if(p->epin == nil){ fprint(2, "serial: openep %d: %r\n", epin); return -1; } p->epout = openep(ser->dev, epout); if(p->epout == nil){ fprint(2, "serial: openep %d: %r\n", epout); closedev(p->epin); return -1; } devctl(p->epin, "timeout 1000"); devctl(p->epout, "timeout 1000"); if(ser->hasepintr){ p->epintr = openep(ser->dev, epintr); if(p->epintr == nil){ fprint(2, "serial: openep %d: %r\n", epintr); closedev(p->epin); closedev(p->epout); return -1; } opendevdata(p->epintr, OREAD); devctl(p->epintr, "timeout 1000"); } if(ser->seteps!= nil) ser->seteps(p); opendevdata(p->epin, OREAD); opendevdata(p->epout, OWRITE); if(p->epin->dfd < 0 ||p->epout->dfd < 0 || (ser->hasepintr && p->epintr->dfd < 0)){ fprint(2, "serial: open i/o ep data: %r\n"); closedev(p->epin); closedev(p->epout); if(ser->hasepintr) closedev(p->epintr); return -1; } return 0; } static int findendpoints(Serial *ser, int ifc) { int i, epin, epout, epintr; Ep *ep, **eps; ///Usbdev *ud; epintr = epin = epout = -1; //ud = ser->dev->usb; /* * interfc 0 means start from the start which is equiv to * iterate through endpoints probably, could be done better */ eps = ser->dev->usb->conf[0]->iface[ifc]->ep; for(i = 0; i < Niface; i++){ if((ep = eps[i]) == nil) continue; if(ser->hasepintr && ep->type == Eintr && ep->dir == Ein && epintr == -1) epintr = ep->id; if(ep->type == Ebulk){ if(ep->dir == Ein && epin == -1) epin = ep->id; if(ep->dir == Eout && epout == -1) epout = ep->id; } } dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr); if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1)) return -1; if(openeps(&ser->p[ifc], epin, epout, epintr) < 0) return -1; dprint(2, "serial: ep in %s out %s\n", ser->p[ifc].epin->dir, ser->p[ifc].epout->dir); if(ser->hasepintr) dprint(2, "serial: ep intr %s\n", ser->p[ifc].epintr->dir); if(usbdebug > 1 || serialdebug > 2){ devctl(ser->p[ifc].epin, "debug 1"); devctl(ser->p[ifc].epout, "debug 1"); if(ser->hasepintr) devctl(ser->p[ifc].epintr, "debug 1"); devctl(ser->dev, "debug 1"); } return 0; } /* keep in sync with main.c */ static int usage(void) { werrstr("usage: usb/serial [-dD] [-m mtpt] [-s srv]"); return -1; } static void serdevfree(void *a) { Serial *ser = a; Serialport *p; int i; if(ser == nil) return; for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; if(ser->hasepintr) closedev(p->epintr); closedev(p->epin); closedev(p->epout); p->epintr = p->epin = p->epout = nil; if(p->w4data != nil) chanfree(p->w4data); if(p->gotdata != nil) chanfree(p->gotdata); if(p->readc) chanfree(p->readc); } free(ser); } static Usbfs serialfs = { .walk = dwalk, .open = dopen, .read = dread, .write= dwrite, .stat = dstat, }; static void serialfsend(Usbfs *fs) { Serialport *p; p = fs->aux; if(p->w4data != nil) chanclose(p->w4data); if(p->gotdata != nil) chanclose(p->gotdata); if(p->readc) chanclose(p->readc); } int serialmain(Dev *dev, int argc, char* argv[]) { Serial *ser; Serialport *p; char buf[50]; int i, devid; devid = dev->id; ARGBEGIN{ case 'd': serialdebug++; break; case 'N': devid = atoi(EARGF(usage())); break; default: return usage(); }ARGEND if(argc != 0) return usage(); ser = dev->aux = emallocz(sizeof(Serial), 1); ser->maxrtrans = ser->maxwtrans = sizeof ser->p[0].data; ser->maxread = ser->maxwrite = sizeof ser->p[0].data; ser->dev = dev; dev->free = serdevfree; ser->jtag = -1; ser->nifcs = 1; snprint(buf, sizeof buf, "vid %#06x did %#06x", dev->usb->vid, dev->usb->did); if(plmatch(buf) == 0){ ser->hasepintr = 1; ser->Serialops = plops; } else if(uconsmatch(buf) == 0) ser->Serialops = uconsops; else if(ftmatch(ser, buf) == 0) ser->Serialops = ftops; else { werrstr("serial: no serial devices found"); return -1; } for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; p->interfc = i; p->s = ser; p->fs = serialfs; if(i == ser->jtag){ p->isjtag++; } if(findendpoints(ser, i) < 0){ werrstr("serial: no endpoints found for ifc %d", i); return -1; } p->w4data = chancreate(sizeof(ulong), 0); p->gotdata = chancreate(sizeof(ulong), 0); } qlock(ser); serialreset(ser); for(i = 0; i < ser->nifcs; i++){ p = &ser->p[i]; dprint(2, "serial: valid interface, calling serinit\n"); if(serinit(p) < 0){ dprint(2, "serial: serinit: %r\n"); return -1; } dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p); if(p->isjtag){ dsprint(2, "serial: HEY! JTAG interface %d %p\n", i, p); snprint(p->fs.name, sizeof p->fs.name, "jtag%d.%d", devid, i); } else { if(i == 0) snprint(p->fs.name, sizeof p->fs.name, "eiaU%d", devid); else snprint(p->fs.name, sizeof p->fs.name, "eiaU%d.%d", devid, i); } fprint(2, "%s\n", p->fs.name); p->fs.dev = dev; incref(dev); p->fs.aux = p; p->fs.end = serialfsend; usbfsadd(&p->fs); } qunlock(ser); return 0; } d qid; Serialport *p; qid = fid->qid; if((qid.type & QTDIR) == 0){ werrstr("walk in non-directory"); return -1; } if(strcmp(name, "..") == 0){ /* must be /eiaU%d; i.e. our root dir. */ fid->qid.path = Qroot | fs->qid; fid->qid.vers = 0; fid->qid.type = QTDIR; return 0; } p = fs->aux; for(i = 1; i < nelem(dirtab); i++){ usb/serial/serial.h 664 0 0 4576 11406000273 12251ustar00syssystypedef struct Serial Serial; typedef struct Serialops Serialops; typedef struct Serialport Serialport; struct Serialops { int (*seteps)(Serialport*); int (*init)(Serialport*); int (*getparam)(Serialport*); int (*setparam)(Serialport*); int (*clearpipes)(Serialport*); int (*reset)(Serial*); int (*sendlines)(Serialport*); int (*modemctl)(Serialport*, int); int (*setbreak)(Serialport*, int); int (*readstatus)(Serialport*); int (*wait4data)(Serialport*, uchar *, int); int (*wait4write)(Serialport*, uchar *, int); }; enum { DataBufSz = 8*1024, Maxifc = 16, }; struct Serialport { Serial *s; /* device we belong to */ int isjtag; Dev *epintr; /* may not exist */ Dev *epin; Dev *epout; Usbfs fs; uchar ctlstate; /* serial parameters */ uint baud; int stop; int mctl; int parity; int bits; int fifo; int limit; int rts; int cts; int dsr; int dcd; int dtr; int rlsd; vlong timer; int blocked; /* for sw flow ctl. BUG: not implemented yet */ int nbreakerr; int ring; int nframeerr; int nparityerr; int novererr; int enabled; int interfc; /* interfc on the device for ftdi */ Channel *w4data; Channel *gotdata; Channel *readc; /* to uncouple reads, only used in ftdi... */ int ndata; uchar data[DataBufSz]; }; struct Serial { QLock; Dev *dev; /* usb device*/ int type; /* serial model subtype */ int recover; /* # of non-fatal recovery tries */ Serialops; int hasepintr; int jtag; /* index of jtag interface, -1 none */ int nifcs; /* # of serial interfaces, including JTAG */ Serialport p[Maxifc]; int maxrtrans; int maxwtrans; int maxread; int maxwrite; int inhdrsz; int outhdrsz; int baudbase; /* for special baud base settings, see ftdi */ }; enum { /* soft flow control chars */ CTLS = 023, CTLQ = 021, CtlDTR = 1, CtlRTS = 2, }; /* * !hget http://lxr.linux.no/source/drivers/usb/serial/pl2303.h|htmlfmt * !hget http://lxr.linux.no/source/drivers/usb/serial/pl2303.c|htmlfmt */ int serialmain(Dev *d, int argc, char *argv[]); typedef struct Cinfo Cinfo; struct Cinfo { int vid; /* usb vendor id */ int did; /* usb device/product id */ int cid; /* controller id assigned by us */ }; extern Cinfo plinfo[]; extern Cinfo uconsinfo[]; extern int serialdebug; #define dsprint if(serialdebug)fprint int serialrecover(Serial *ser, char *err); int serialreset(Serial *ser); char *serdumpst(Serialport *p, char *buf, int bufsz); d\n", err, rcount); } while(rcount < 0 && strstr(err, "timed out") != nil); dsprint(2, "serial: read from bulk %ld, %10.10s\nusb/serial/ucons.c 664 0 0 1356 11406000266 12107ustar00syssys#include #include #include #include "usb.h" #include "usbfs.h" #include "serial.h" #include "ucons.h" Cinfo uconsinfo[] = { { Net20DCVid, Net20DCDid }, { 0, 0 }, }; int uconsmatch(char *info) { Cinfo *ip; char buf[50]; for(ip = uconsinfo; ip->vid != 0; ip++){ snprint(buf, sizeof buf, "vid %#06x did %#06x", ip->vid, ip->did); dsprint(2, "serial: %s %s\n", buf, info); if(strstr(info, buf) != nil) return 0; } return -1; } static int ucseteps(Serialport *p) { Serial *ser; ser = p->s; p->baud = ~0; /* not real port */ ser->maxrtrans = ser->maxwtrans = 8; devctl(p->epin, "maxpkt 8"); devctl(p->epout, "maxpkt 8"); return 0; } /* all nops */ Serialops uconsops = { .seteps = ucseteps, }; ite(p, (uchar *)buf, count); break; case Qctl: cmd = emallocz(count+1, 1); memmove(cmd, buf, count); cmd[count] = 0; if(serialctl(p, cmd) < 0){ qunlock(ser); werrstr(Ebadctl); free(cmd); return -1; } free(cmd); break; default: qunlock(ser); usb/serial/ucons.h 664 0 0 214 11237633253 12076ustar00syssys enum { Net20DCVid = 0x0525, /* Ajays usb debug cable */ Net20DCDid = 0x127a, }; int uconsmatch(char *info); extern Serialops uconsops; usb/usbd/ 775 0 0 0 11457773434 103115ustar00syssysusb/usbd/dev.c 664 0 0 13456 11412732143 11243ustar00syssys/* * Framework for USB devices. * Some of them may be embedded into usbd and some of * them may exist as /bin/usb/* binaries on their own. * * When embedded, devmain() is given a ref of an already * configured and open Dev. If devmain() * does not fail it should release this ref when done and * use incref to add further refs to it. */ #include #include #include #include "usb.h" #include "usbd.h" static Lock masklck; extern Devtab devtab[]; static char* cputype; int getdevnb(uvlong *maskp) { int i; lock(&masklck); for(i = 0; i < 8 * sizeof *maskp; i++) if((*maskp & (1ULL<= 0) *maskp &= ~(1ULL<csps); i++) if((csp=dt->csps[i]) != 0) if(csp == dcsp) return 1; else if((csp&DCL) && (csp&~DCL) == Class(dcsp)) return 1; return 0; } static int devmatch(Devtab *dt, Usbdev *d) { int i; int c; Conf *cp; if(dt->vid != -1 && d->vid != dt->vid) return 0; if(dt->did != -1 && d->did != dt->did) return 0; if(cspmatch(dt, d->csp)) return 1; for(c = 0; c < Nconf; c++) if((cp=d->conf[c]) != nil) for(i = 0; i < Niface; i++) if(cp->iface[i] != nil) if(cspmatch(dt, cp->iface[i]->csp)) return 1; return 0; } /* We can't use procexec to execute drivers, because * procexec mounts #| at /mnt/temp and we do *not* * have /mnt/temp at boot time. * Instead, we use access to guess if we can execute the file. * and reply as procexec. Be careful that the child inherits * all the shared state of the thread library. It should run unnoticed. */ static void xexec(Channel *c, char *nm, char *args[]) { int pid; if(access(nm, AEXEC) == 0){ pid = rfork(RFFDG|RFREND|RFPROC); switch(pid){ case 0: exec(nm, args); _exits("exec"); case -1: break; default: sendul(c, pid); threadexits(nil); } } } typedef struct Sarg Sarg; struct Sarg{ Port *pp; Devtab* dt; Channel*rc; char fname[80]; char args[128]; char *argv[40]; }; static void startdevproc(void *a) { Sarg *sa = a; Dev *d; Devtab *dt; int argc; char *args, *argse, **argv; char *fname; threadsetgrp(threadid()); d = sa->pp->dev; dt = sa->dt; args = sa->args; argse = sa->args + sizeof sa->args; argv = sa->argv; fname = sa->fname; sa->pp->devmaskp = &dt->devmask; sa->pp->devnb = getdevnb(&dt->devmask); if(sa->pp->devnb < 0){ sa->pp->devmaskp = nil; sa->pp->devnb = 0; }else args = seprint(args, argse, "-N %d", sa->pp->devnb); if(dt->args != nil) seprint(args, argse, " %s", dt->args); args = sa->args; dprint(2, "%s: start: %s %s\n", argv0, dt->name, args); argv[0] = dt->name; argc = 1; if(args[0] != 0) argc += tokenize(args, argv+1, nelem(sa->argv)-2); argv[argc] = nil; if(dt->init == nil){ if(d->dfd > 0 ){ close(d->dfd); d->dfd = -1; } rfork(RFCFDG); open("/dev/null", OREAD); open("/dev/cons", OWRITE); open("/dev/cons", OWRITE); xexec(sa->rc, argv[0], argv); snprint(fname, sizeof(sa->fname), "/bin/usb/%s", dt->name); xexec(sa->rc, fname, argv); snprint(fname, sizeof(sa->fname), "/boot/%s", dt->name); xexec(sa->rc, fname, argv); if(cputype == nil) cputype = getenv("cputype"); if(cputype != nil){ snprint(fname, sizeof(sa->fname), "/%s/bin/%s", cputype, dt->name); argv[0] = fname; xexec(sa->rc, fname, argv); } fprint(2, "%s: %s: not found. can't exec\n", argv0, dt->name); sendul(sa->rc, -1); threadexits("exec"); }else{ sa->pp->dev = opendev(d->dir); sendul(sa->rc, 0); if(dt->init(d, argc, argv) < 0) fprint(2, "%s: %s: %r\n", argv0, dt->name); closedev(d); free(sa); } threadexits(nil); } static void writeinfo(Dev *d) { char buf[128]; char *s; char *se; Usbdev *ud; Conf *c; Iface *ifc; int i, j; ud = d->usb; s = buf; se = buf+sizeof(buf); s = seprint(s, se, "info %s csp %#08ulx", classname(ud->class), ud->csp); for(i = 0; i < ud->nconf; i++){ c = ud->conf[i]; if(c == nil) break; for(j = 0; j < nelem(c->iface); j++){ ifc = c->iface[j]; if(ifc == nil) break; if(ifc->csp != ud->csp) s = seprint(s, se, " csp %#08ulx", ifc->csp); } } s = seprint(s, se, " vid %06#x did %06#x", ud->vid, ud->did); seprint(s, se, " %q %q", ud->vendor, ud->product); devctl(d, "%s", buf); } int startdev(Port *pp) { Dev *d; Usbdev *ud; Devtab *dt; Sarg *sa; Channel *rc; d = pp->dev; assert(d); ud = d->usb; assert(ud != nil); writeinfo(d); if(ud->class == Clhub){ /* * Hubs are handled directly by this process avoiding * concurrent operation so that at most one device * has the config address in use. * We cancel kernel debug for these eps. too chatty. */ pp->hub = newhub(d->dir, d); if(pp->hub == nil) fprint(2, "%s: %s: %r\n", argv0, d->dir); else fprint(2, "usb/hub... "); if(usbdebug > 1) devctl(d, "debug 0"); /* polled hubs are chatty */ return pp->hub == nil ? -1 : 0; } for(dt = devtab; dt->name != nil; dt++) if(devmatch(dt, ud)) break; /* * From here on the device is for the driver. * When we return pp->dev contains a Dev just for us * with only the ctl open. Both devs are released on the last closedev: * driver's upon I/O errors and ours upon port dettach. */ if(dt->name == nil){ dprint(2, "%s: no configured entry for %s (csp %#08lx)\n", argv0, d->dir, ud->csp); close(d->dfd); d->dfd = -1; return 0; } sa = emallocz(sizeof(Sarg), 1); sa->pp = pp; sa->dt = dt; rc = sa->rc = chancreate(sizeof(ulong), 1); procrfork(startdevproc, sa, Stack, RFNOTEG); if(recvul(rc) != 0) free(sa); chanfree(rc); fprint(2, "usb/%s... ", dt->name); sleep(Spawndelay); /* in case we re-spawn too fast */ return 0; } http://lxr.linux.no/source/drivers/usb/serial/pl2303.h|htmlfmt * !hget http://lxr.linux.no/source/drivers/usb/serial/pl2303.c|htmlfmt */ int serialmain(Dev *d, int argc, char *argv[]); typedef struct Cinfo usb/usbd/mkdev 775 0 0 3442 11457437633 11346ustar00syssys#!/bin/rc rfork e DB=usbdb HDR=../lib/usb.h subs=`{ grep '^ Cl.*' $HDR | sed -e 's/.*Cl([a-z]+)[ ]+=[ ]+([0-9]+).*/-e s.\1,.\2,./' | tr A-Z a-z } cat< #include #include #include "usb.h" #include "usbd.h" EOF awk ' /^#|^$/ { next } collect && /^[^ \t]/{ collect = 0; } $0 ~ /^(embed|auto)/{ section = $0; collect = 1; next; } collect { if(section ~ "embed"){ printf("extern int %smain(Dev*, int, char**);\n", $1); } } ' $DB cat < i) args = args " " $j; else args = $j } for(i = 2; i <= NF; i++){ if($i ~ "^csp="){ ncsp++; sub("csp=", "", $i); printf("%s, ", $i); } else if($i ~ "^subclass="){ ncsp++; sub("subclass=", "", $i); printf("DSC|%s, ", $i); } else if($i ~ "^class="){ ncsp++; sub("class=", "", $i); printf("DCL|%s, ", $i); } else if($i ~ "^proto="){ ncsp++; sub("proto=", "", $i); printf("DPT|%s, ", $i); } else if($i ~ "^vid="){ sub("vid=", "", $i); vid=$i } else if($i ~ "did="){ sub("did=", "", $i); did=$i } } for(i = ncsp; i < 4; i++) printf("0, "); printf("}, %s, %s, \"%s\"},\n", vid, did, args); } ' $DB | sed $subs cat <$target usb/usbd/usbd.c 664 0 0 44370 11412732116 11421ustar00syssys#include #include #include #include #include "usb.h" #include "usbfs.h" #include "usbd.h" static Channel *portc; static int win; static int verbose; int mainstacksize = Stack; static Hub *hubs; static int nhubs; static int mustdump; static int pollms = Pollms; static char *dsname[] = { "disabled", "attached", "configed" }; static int hubfeature(Hub *h, int port, int f, int on) { int cmd; if(on) cmd = Rsetfeature; else cmd = Rclearfeature; return usbcmd(h->dev, Rh2d|Rclass|Rother, cmd, f, port, nil, 0); } /* * This may be used to detect overcurrent on the hub */ static void checkhubstatus(Hub *h) { uchar buf[4]; int sts; if(h->isroot) /* not for root hubs */ return; if(usbcmd(h->dev, Rd2h|Rclass|Rdev, Rgetstatus, 0, 0, buf, 4) < 0){ dprint(2, "%s: get hub status: %r\n", h->dev->dir); return; } sts = GET2(buf); dprint(2, "hub %s: status %#ux\n", h->dev->dir, sts); } static int confighub(Hub *h) { int type; uchar buf[128]; /* room for extra descriptors */ int i; Usbdev *d; DHub *dd; Port *pp; int nr; int nmap; uchar *PortPwrCtrlMask; int offset; int mask; d = h->dev->usb; for(i = 0; i < nelem(d->ddesc); i++) if(d->ddesc[i] == nil) break; else if(d->ddesc[i]->data.bDescriptorType == Dhub){ dd = (DHub*)&d->ddesc[i]->data; nr = Dhublen; goto Config; } type = Rd2h|Rclass|Rdev; nr = usbcmd(h->dev, type, Rgetdesc, Dhub<<8|0, 0, buf, sizeof buf); if(nr < Dhublen){ dprint(2, "%s: %s: getdesc hub: %r\n", argv0, h->dev->dir); return -1; } dd = (DHub*)buf; Config: h->nport = dd->bNbrPorts; nmap = 1 + h->nport/8; if(nr < 7 + 2*nmap){ fprint(2, "%s: %s: descr. too small\n", argv0, h->dev->dir); return -1; } h->port = emallocz((h->nport+1)*sizeof(Port), 1); h->pwrms = dd->bPwrOn2PwrGood*2; if(h->pwrms < Powerdelay) h->pwrms = Powerdelay; h->maxcurrent = dd->bHubContrCurrent; h->pwrmode = dd->wHubCharacteristics[0] & 3; h->compound = (dd->wHubCharacteristics[0] & (1<<2))!=0; h->leds = (dd->wHubCharacteristics[0] & (1<<7)) != 0; PortPwrCtrlMask = dd->DeviceRemovable + nmap; for(i = 1; i <= h->nport; i++){ pp = &h->port[i]; offset = i/8; mask = 1<<(i%8); pp->removable = (dd->DeviceRemovable[offset] & mask) != 0; pp->pwrctl = (PortPwrCtrlMask[offset] & mask) != 0; } return 0; } static void configroothub(Hub *h) { Dev *d; char buf[128]; char *p; int nr; d = h->dev; h->nport = 2; h->maxpkt = 8; seek(d->cfd, 0, 0); nr = read(d->cfd, buf, sizeof(buf)-1); if(nr < 0) goto Done; buf[nr] = 0; p = strstr(buf, "ports "); if(p == nil) fprint(2, "%s: %s: no port information\n", argv0, d->dir); else h->nport = atoi(p+6); p = strstr(buf, "maxpkt "); if(p == nil) fprint(2, "%s: %s: no maxpkt information\n", argv0, d->dir); else h->maxpkt = atoi(p+7); Done: h->port = emallocz((h->nport+1)*sizeof(Port), 1); dprint(2, "%s: %s: ports %d maxpkt %d\n", argv0, d->dir, h->nport, h->maxpkt); } Hub* newhub(char *fn, Dev *d) { Hub *h; int i; Usbdev *ud; h = emallocz(sizeof(Hub), 1); h->isroot = (d == nil); if(h->isroot){ h->dev = opendev(fn); if(h->dev == nil){ fprint(2, "%s: opendev: %s: %r", argv0, fn); goto Fail; } if(opendevdata(h->dev, ORDWR) < 0){ fprint(2, "%s: opendevdata: %s: %r\n", argv0, fn); goto Fail; } configroothub(h); /* never fails */ }else{ h->dev = d; if(confighub(h) < 0){ fprint(2, "%s: %s: config: %r\n", argv0, fn); goto Fail; } } if(h->dev == nil){ fprint(2, "%s: opendev: %s: %r\n", argv0, fn); goto Fail; } devctl(h->dev, "hub"); ud = h->dev->usb; if(h->isroot) devctl(h->dev, "info roothub csp %#08ux ports %d", 0x000009, h->nport); else{ devctl(h->dev, "info hub csp %#08ulx ports %d %q %q", ud->csp, h->nport, ud->vendor, ud->product); for(i = 1; i <= h->nport; i++) if(hubfeature(h, i, Fportpower, 1) < 0) fprint(2, "%s: %s: power: %r\n", argv0, fn); sleep(h->pwrms); for(i = 1; i <= h->nport; i++) if(h->leds != 0) hubfeature(h, i, Fportindicator, 1); } h->next = hubs; hubs = h; nhubs++; dprint(2, "%s: hub %#p allocated:", argv0, h); dprint(2, " ports %d pwrms %d max curr %d pwrm %d cmp %d leds %d\n", h->nport, h->pwrms, h->maxcurrent, h->pwrmode, h->compound, h->leds); incref(h->dev); return h; Fail: if(d != nil) devctl(d, "detach"); free(h->port); free(h); dprint(2, "%s: hub %#p failed to start:", argv0, h); return nil; } static void portdetach(Hub *h, int p); /* * If during enumeration we get an I/O error the hub is gone or * in pretty bad shape. Because of retries of failed usb commands * (and the sleeps they include) it can take a while to detach all * ports for the hub. This detaches all ports and makes the hub void. * The parent hub will detect a detach (probably right now) and * close it later. */ static void hubfail(Hub *h) { int i; for(i = 1; i <= h->nport; i++) portdetach(h, i); h->failed = 1; } static void closehub(Hub *h) { Hub **hl; dprint(2, "%s: closing hub %#p\n", argv0, h); for(hl = &hubs; *hl != nil; hl = &(*hl)->next) if(*hl == h) break; if(*hl == nil) sysfatal("closehub: no hub"); *hl = h->next; nhubs--; hubfail(h); /* detach all ports */ free(h->port); assert(h->dev != nil); devctl(h->dev, "detach"); closedev(h->dev); free(h); } static int portstatus(Hub *h, int p) { Dev *d; uchar buf[4]; int t; int sts; int dbg; dbg = usbdebug; if(dbg != 0 && dbg < 4) usbdebug = 1; /* do not be too chatty */ d = h->dev; t = Rd2h|Rclass|Rother; if(usbcmd(d, t, Rgetstatus, 0, p, buf, sizeof(buf)) < 0) sts = -1; else sts = GET2(buf); usbdebug = dbg; return sts; } static char* stsstr(int sts) { static char s[80]; char *e; e = s; if(sts&PSsuspend) *e++ = 'z'; if(sts&PSreset) *e++ = 'r'; if(sts&PSslow) *e++ = 'l'; if(sts&PShigh) *e++ = 'h'; if(sts&PSchange) *e++ = 'c'; if(sts&PSenable) *e++ = 'e'; if(sts&PSstatuschg) *e++ = 's'; if(sts&PSpresent) *e++ = 'p'; if(e == s) *e++ = '-'; *e = 0; return s; } static int getmaxpkt(Dev *d, int islow) { uchar buf[64]; /* More room to try to get device-specific descriptors */ DDev *dd; dd = (DDev*)buf; if(islow) dd->bMaxPacketSize0 = 8; else dd->bMaxPacketSize0 = 64; if(usbcmd(d, Rd2h|Rstd|Rdev, Rgetdesc, Ddev<<8|0, 0, buf, sizeof(buf)) < 0) return -1; return dd->bMaxPacketSize0; } /* * BUG: does not consider max. power avail. */ static Dev* portattach(Hub *h, int p, int sts) { Dev *d; Port *pp; Dev *nd; char fname[80]; char buf[40]; char *sp; int mp; int nr; d = h->dev; pp = &h->port[p]; nd = nil; pp->state = Pattached; dprint(2, "%s: %s: port %d attach sts %#ux\n", argv0, d->dir, p, sts); sleep(Connectdelay); if(hubfeature(h, p, Fportenable, 1) < 0) dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); sleep(Enabledelay); if(hubfeature(h, p, Fportreset, 1) < 0){ dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); goto Fail; } sleep(Resetdelay); sts = portstatus(h, p); if(sts < 0) goto Fail; if((sts & PSenable) == 0){ dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); hubfeature(h, p, Fportenable, 1); sts = portstatus(h, p); if((sts & PSenable) == 0) goto Fail; } sp = "full"; if(sts & PSslow) sp = "low"; if(sts & PShigh) sp = "high"; dprint(2, "%s: %s: port %d: attached status %#ux\n", argv0, d->dir, p, sts); if(devctl(d, "newdev %s %d", sp, p) < 0){ fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p); goto Fail; } seek(d->cfd, 0, 0); nr = read(d->cfd, buf, sizeof(buf)-1); if(nr == 0){ fprint(2, "%s: %s: port %d: newdev: eof\n", argv0, d->dir, p); goto Fail; } if(nr < 0){ fprint(2, "%s: %s: port %d: newdev: %r\n", argv0, d->dir, p); goto Fail; } buf[nr] = 0; snprint(fname, sizeof(fname), "/dev/usb/%s", buf); nd = opendev(fname); if(nd == nil){ fprint(2, "%s: %s: port %d: opendev: %r\n", argv0, d->dir, p); goto Fail; } if(usbdebug > 2) devctl(nd, "debug 1"); if(opendevdata(nd, ORDWR) < 0){ fprint(2, "%s: %s: opendevdata: %r\n", argv0, nd->dir); goto Fail; } if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){ dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p); goto Fail; } if(devctl(nd, "address") < 0){ dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p); goto Fail; } mp=getmaxpkt(nd, strcmp(sp, "low") == 0); if(mp < 0){ dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p); goto Fail; }else{ dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp); devctl(nd, "maxpkt %d", mp); } if((sts & PSslow) != 0 && strcmp(sp, "full") == 0) dprint(2, "%s: %s: port %d: %s is full speed when port is low\n", argv0, d->dir, p, nd->dir); if(configdev(nd) < 0){ dprint(2, "%s: %s: port %d: configdev: %r\n", argv0, d->dir, p); goto Fail; } /* * We always set conf #1. BUG. */ if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){ dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p); unstall(nd, nd, Eout); if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0) goto Fail; } dprint(2, "%s: %U", argv0, nd); pp->state = Pconfiged; dprint(2, "%s: %s: port %d: configed: %s\n", argv0, d->dir, p, nd->dir); return pp->dev = nd; Fail: pp->state = Pdisabled; pp->sts = 0; if(pp->hub != nil) pp->hub = nil; /* hub closed by enumhub */ hubfeature(h, p, Fportenable, 0); if(nd != nil) devctl(nd, "detach"); closedev(nd); return nil; } static void portdetach(Hub *h, int p) { Dev *d; Port *pp; extern void usbfsgone(char*); d = h->dev; pp = &h->port[p]; /* * Clear present, so that we detect an attach on reconnects. */ pp->sts &= ~(PSpresent|PSenable); if(pp->state == Pdisabled) return; pp->state = Pdisabled; dprint(2, "%s: %s: port %d: detached\n", argv0, d->dir, p); if(pp->hub != nil){ closehub(pp->hub); pp->hub = nil; } if(pp->devmaskp != nil) putdevnb(pp->devmaskp, pp->devnb); pp->devmaskp = nil; if(pp->dev != nil){ devctl(pp->dev, "detach"); usbfsgone(pp->dev->dir); closedev(pp->dev); pp->dev = nil; } } /* * The next two functions are included to * perform a port reset asked for by someone (usually a driver). * This must be done while no other device is in using the * configuration address and with care to keep the old address. * To keep drivers decoupled from usbd they write the reset request * to the #u/usb/epN.0/ctl file and then exit. * This is unfortunate because usbd must now poll twice as much. * * An alternative to this reset process would be for the driver to detach * the device. The next function could see that, issue a port reset, and * then restart the driver once to see if it's a temporary error. * * The real fix would be to use interrupt endpoints for non-root hubs * (would probably make some hubs fail) and add an events file to * the kernel to report events to usbd. This is a severe change not * yet implemented. */ static int portresetwanted(Hub *h, int p) { char buf[5]; Port *pp; Dev *nd; pp = &h->port[p]; nd = pp->dev; if(nd != nil && nd->cfd >= 0 && pread(nd->cfd, buf, 5, 0LL) == 5) return strncmp(buf, "reset", 5) == 0; else return 0; } static void portreset(Hub *h, int p) { int sts; Dev *d, *nd; Port *pp; d = h->dev; pp = &h->port[p]; nd = pp->dev; dprint(2, "%s: %s: port %d: resetting\n", argv0, d->dir, p); if(hubfeature(h, p, Fportreset, 1) < 0){ dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); goto Fail; } sleep(Resetdelay); sts = portstatus(h, p); if(sts < 0) goto Fail; if((sts & PSenable) == 0){ dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); hubfeature(h, p, Fportenable, 1); sts = portstatus(h, p); if((sts & PSenable) == 0) goto Fail; } nd = pp->dev; opendevdata(nd, ORDWR); if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetaddress, nd->id, 0, nil, 0) < 0){ dprint(2, "%s: %s: port %d: setaddress: %r\n", argv0, d->dir, p); goto Fail; } if(devctl(nd, "address") < 0){ dprint(2, "%s: %s: port %d: set address: %r\n", argv0, d->dir, p); goto Fail; } if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0){ dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p); unstall(nd, nd, Eout); if(usbcmd(nd, Rh2d|Rstd|Rdev, Rsetconf, 1, 0, nil, 0) < 0) goto Fail; } if(nd->dfd >= 0) close(nd->dfd); return; Fail: pp->state = Pdisabled; pp->sts = 0; if(pp->hub != nil) pp->hub = nil; /* hub closed by enumhub */ hubfeature(h, p, Fportenable, 0); if(nd != nil) devctl(nd, "detach"); closedev(nd); } static int portgone(Port *pp, int sts) { if(sts < 0) return 1; /* * If it was enabled and it's not now then it may be reconnect. * We pretend it's gone and later we'll see it as attached. */ if((pp->sts & PSenable) != 0 && (sts & PSenable) == 0) return 1; return (pp->sts & PSpresent) != 0 && (sts & PSpresent) == 0; } static int enumhub(Hub *h, int p) { int sts; Dev *d; Port *pp; int onhubs; if(h->failed) return 0; d = h->dev; if(usbdebug > 3) fprint(2, "%s: %s: port %d enumhub\n", argv0, d->dir, p); sts = portstatus(h, p); if(sts < 0){ hubfail(h); /* avoid delays on detachment */ return -1; } pp = &h->port[p]; onhubs = nhubs; if((sts & PSsuspend) != 0){ if(hubfeature(h, p, Fportenable, 1) < 0) dprint(2, "%s: %s: port %d: enable: %r\n", argv0, d->dir, p); sleep(Enabledelay); sts = portstatus(h, p); fprint(2, "%s: %s: port %d: resumed (sts %#ux)\n", argv0, d->dir, p, sts); } if((pp->sts & PSpresent) == 0 && (sts & PSpresent) != 0){ if(portattach(h, p, sts) != nil) if(startdev(pp) < 0) portdetach(h, p); }else if(portgone(pp, sts)) portdetach(h, p); else if(portresetwanted(h, p)) portreset(h, p); else if(pp->sts != sts){ dprint(2, "%s: %s port %d: sts %s %#x ->", argv0, d->dir, p, stsstr(pp->sts), pp->sts); dprint(2, " %s %#x\n",stsstr(sts), sts); } pp->sts = sts; if(onhubs != nhubs) return -1; return 0; } static void dump(void) { Hub *h; int i; mustdump = 0; for(h = hubs; h != nil; h = h->next) for(i = 1; i <= h->nport; i++) fprint(2, "%s: hub %#p %s port %d: %U", argv0, h, h->dev->dir, i, h->port[i].dev); usbfsdirdump(); } static void work(void *a) { Channel *portc; char *fn; Hub *h; int i; portc = a; hubs = nil; /* * Receive requests for root hubs */ while((fn = recvp(portc)) != nil){ dprint(2, "%s: %s starting\n", argv0, fn); h = newhub(fn, nil); if(h == nil) fprint(2, "%s: %s: newhub failed: %r\n", argv0, fn); free(fn); } /* * Enumerate (and acknowledge after first enumeration). * Do NOT perform enumeration concurrently for the same * controller. new devices attached respond to a default * address (0) after reset, thus enumeration has to work * one device at a time at least before addresses have been * assigned. * Do not use hub interrupt endpoint because we * have to poll the root hub(s) in any case. */ for(;;){ Again: for(h = hubs; h != nil; h = h->next) for(i = 1; i <= h->nport; i++) if(enumhub(h, i) < 0){ /* changes in hub list; repeat */ goto Again; } if(portc != nil){ sendp(portc, nil); portc = nil; } sleep(pollms); if(mustdump) dump(); } } static int cfswalk(Usbfs*, Fid *, char *) { werrstr(Enotfound); return -1; } static int cfsopen(Usbfs*, Fid *, int) { return 0; } static long cfsread(Usbfs*, Fid *, void *, long , vlong ) { return 0; } static void setdrvargs(char *name, char *args) { Devtab *dt; extern Devtab devtab[]; for(dt = devtab; dt->name != nil; dt++) if(strstr(dt->name, name) != nil) dt->args = estrdup(args); } static long cfswrite(Usbfs*, Fid *, void *data, long cnt, vlong ) { char buf[80]; char *toks[4]; if(cnt > sizeof(buf)) cnt = sizeof(buf) - 1; strncpy(buf, data, cnt); buf[cnt] = 0; if(cnt > 0 && buf[cnt-1] == '\n') buf[cnt-1] = 0; if(strncmp(buf, "dump", 4) == 0){ mustdump = 1; return cnt; } if(strncmp(buf, "reset", 5) == 0){ werrstr("reset not implemented"); return -1; } if(tokenize(buf, toks, nelem(toks)) != 2){ werrstr("usage: debug|fsdebug n"); return -1; } if(strcmp(toks[0], "debug") == 0) usbdebug = atoi(toks[1]); else if(strcmp(toks[0], "fsdebug") == 0) usbfsdebug = atoi(toks[1]); else if(strcmp(toks[0], "kbargs") == 0) setdrvargs("kb", toks[1]); else if(strcmp(toks[0], "diskargs") == 0) setdrvargs("disk", toks[1]); else{ werrstr("unkown ctl '%s'", buf); return -1; } fprint(2, "%s: debug %d fsdebug %d\n", argv0, usbdebug, usbfsdebug); return cnt; } static int cfsstat(Usbfs* fs, Qid qid, Dir *d) { d->qid = qid; d->qid.path |= fs->qid; d->qid.type = 0; d->qid.vers = 0; d->name = "usbdctl"; d->length = 0; d->mode = 0664; return 0; } static Usbfs ctlfs = { .walk = cfswalk, .open = cfsopen, .read = cfsread, .write = cfswrite, .stat = cfsstat }; static void args(void) { char *s; s = getenv("usbdebug"); if(s != nil) usbdebug = atoi(s); free(s); s = getenv("usbfsdebug"); if(s != nil) usbfsdebug = atoi(s); free(s); s = getenv("kbargs"); if(s != nil) setdrvargs("kb", s); free(s); s = getenv("diskargs"); if(s != nil) setdrvargs("disk", s); free(s); } static void usage(void) { fprint(2, "usage: %s [-Dd] [-s srv] [-m mnt] [dev...]\n", argv0); threadexitsall("usage"); } extern void usbfsexits(int); void threadmain(int argc, char **argv) { int i; Dir *d; int fd; int nd; char *err; char *srv; char *mnt; srv = "usb"; mnt = "/dev"; ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; break; case 's': srv = EARGF(usage()); break; case 'i': pollms = atoi(EARGF(usage())); break; case 'm': mnt = EARGF(usage()); break; default: usage(); }ARGEND; if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) sysfatal("#u: %r"); args(); fmtinstall('U', Ufmt); quotefmtinstall(); rfork(RFNOTEG); portc = chancreate(sizeof(char *), 0); if(portc == nil) sysfatal("chancreate"); proccreate(work, portc, Stack); if(argc == 0){ fd = open("/dev/usb", OREAD); if(fd < 0) sysfatal("/dev/usb: %r"); nd = dirreadall(fd, &d); close(fd); if(nd < 2) sysfatal("/dev/usb: no hubs"); for(i = 0; i < nd; i++) if(strcmp(d[i].name, "ctl") != 0) sendp(portc, smprint("/dev/usb/%s", d[i].name)); free(d); }else for(i = 0; i < argc; i++) sendp(portc, strdup(argv[i])); sendp(portc, nil); err = recvp(portc); chanfree(portc); usbfsexits(0); usbfsinit(srv, mnt, &usbdirfs, MAFTER); snprint(ctlfs.name, sizeof(ctlfs.name), "usbdctl"); usbfsadd(&ctlfs); threadexits(err); } if(mp < 0){ dprint(2, "%s: %s: port %d: getmaxpkt: %r\n", argv0, d->dir, p); goto Fail; }else{ dprint(2, "%s; %s: port %d: maxpkt %d\n", argv0, d->dir, p, mp); devctl(nd, "maxpkt %d", mp); } if((sts & PSslow) != 0 && strcmp(sp, "full") == 0) dprint(usb/usbd/usbd.h 664 0 0 5660 11412732103 11401ustar00syssystypedef struct Hub Hub; typedef struct Port Port; typedef struct DHub DHub; typedef struct Devtab Devtab; typedef struct Usbfs Usbfs; enum { Stack = 32*1024, Dhub = 0x29, /* hub descriptor type */ Dhublen = 9, /* hub descriptor length */ /* hub class feature selectors */ Fhublocalpower = 0, Fhubovercurrent = 1, Fportconnection = 0, Fportenable = 1, Fportsuspend = 2, Fportovercurrent = 3, Fportreset = 4, Fportpower = 8, Fportlowspeed = 9, Fcportconnection = 16, Fcportenable = 17, Fcportsuspend = 18, Fcportovercurrent= 19, Fcportreset = 20, Fportindicator = 22, /* Port status and status change bits * Constants at /sys/src/9/pc/usb.h starting with HP- * must have the same values or root hubs won't work. */ PSpresent = 0x0001, PSenable = 0x0002, PSsuspend = 0x0004, PSovercurrent = 0x0008, PSreset = 0x0010, PSpower = 0x0100, PSslow = 0x0200, PShigh = 0x0400, PSstatuschg = 0x10000, /* PSpresent changed */ PSchange = 0x20000, /* PSenable changed */ /* port/device state */ Pdisabled = 0, /* must be 0 */ Pattached, Pconfiged, /* Delays, timeouts (ms) */ Spawndelay = 1000, /* how often may we re-spawn a driver */ Connectdelay = 1000, /* how much to wait after a connect */ Resetdelay = 20, /* how much to wait after a reset */ Enabledelay = 20, /* how much to wait after an enable */ Powerdelay = 100, /* after powering up ports */ Pollms = 250, /* port poll interval */ Chgdelay = 100, /* waiting for port become stable */ Chgtmout = 1000, /* ...but at most this much */ /* * device tab for embedded usb drivers. */ DCL = 0x01000000, /* csp identifies just class */ DSC = 0x02000000, /* csp identifies just subclass */ DPT = 0x04000000, /* csp identifies just proto */ }; struct Hub { uchar pwrmode; uchar compound; uchar pwrms; /* time to wait in ms */ uchar maxcurrent; /* after powering port*/ int leds; /* has port indicators? */ int maxpkt; uchar nport; Port *port; int failed; /* I/O error while enumerating */ int isroot; /* set if root hub */ Dev *dev; /* for this hub */ Hub *next; /* in list of hubs */ }; struct Port { int state; /* state of the device */ int sts; /* old port status */ uchar removable; uchar pwrctl; Dev *dev; /* attached device (if non-nil) */ Hub *hub; /* non-nil if hub attached */ int devnb; /* device number */ uvlong *devmaskp; /* ptr to dev mask */ }; /* USB HUB descriptor */ struct DHub { uchar bLength; uchar bDescriptorType; uchar bNbrPorts; uchar wHubCharacteristics[2]; uchar bPwrOn2PwrGood; uchar bHubContrCurrent; uchar DeviceRemovable[1]; /* variable length */ }; struct Devtab { char *name; int (*init)(Dev*, int, char**); /* nil if external */ int csps[4]; int vid; int did; char *args; uvlong devmask; }; Hub* newhub(char *fn, Dev *d); int startdev(Port *pp); int getdevnb(uvlong *maskp); void putdevnb(uvlong *maskp, int nb); void threadmain(int argc, char **argv); extern Usbfs usbdfsops; 0){ dprint(2, "%s: %s: port %d: setconf: %r\n", argv0, d->dir, p); unstall(nusb/usbd/usbdb 664 0 0 620 11457525244 11303ustar00syssys# only kb, disk, and ether are prepared for embedding. # others are not yet converted to sit in the usbd device driver library embed kb csp=0x010103 csp=0x020103 args= disk class=storage args= # ether class=255 csp=0x00ffff args= # serial class=255 csp=0xffffff vid=0x0403 did=0x9e90 args= # wifi class=0 csp=0 vid=0x0bda did=0x8192 args= # wifi class=0 csp=0 vid=0x148f did=0x2870 args= auto