nusb: implement aijus stable uniqueue device names

instead of naming devices by ther dynamically assigned device address,
we hash device uniqueue fields from the device descriptor and produce
a 5 digit hex string that will identify the device across machines.

when there is a collision (less than 1% chance with 100 devices),
usbd will append the device address to the name to make it uniqueue
for this machine.

the hname is passed to drivers in the devid argument, which now has
the form addr:hname, where the colon and hname can be omited (for backwards
compatibility).

when the new behaviour isnt desired, nousbhname= environment variable
can be defined giving the old behaviour.
This commit is contained in:
cinap_lenrek 2014-06-28 18:09:43 +02:00
parent d8c75e45de
commit 4275c49e72
19 changed files with 182 additions and 63 deletions

View file

@ -7,22 +7,25 @@ if(! bind -a '#u' /dev)
@{ @{
rfork ne rfork ne
fn attach { fn attach {
id=$1
if(~ $#* 5 && ! test -e /env/nousbhname)
id=$1:$5
switch($4){ switch($4){
case *01 case *01
nusb/audio $1 nusb/audio $id
case *02 case *02
# serial and ethernet # serial and ethernet
nusb/serial $1 nusb/serial $id
# handled /sys/src/9/boot/nusbrc # handled /sys/src/9/boot/nusbrc
# nusb/ether $1 # nusb/ether $id
case *03 case *03
# handled /sys/src/9/boot/nusbrc # handled /sys/src/9/boot/nusbrc
# nusb/kb $1 # nusb/kb $id
case *08 case *08
# handled /sys/src/9/boot/nusbrc # handled /sys/src/9/boot/nusbrc
# nusb/disk $1 # nusb/disk $id
case *10106 case 010106
nusb/ptp $1 nusb/ptp $id
} }
} }
fn detach { fn detach {

View file

@ -28,6 +28,7 @@ struct Dev {
Usbdev* usb; /* USB description */ Usbdev* usb; /* USB description */
void* aux; /* for the device driver */ void* aux; /* for the device driver */
void (*free)(void*); /* idem. to release aux */ void (*free)(void*); /* idem. to release aux */
char* hname; /* hash name, uniqueue for device */
}; };
.sp 0.3v .sp 0.3v
struct Usbdev { struct Usbdev {
@ -119,7 +120,7 @@ Dev* openep(Dev *d, int id);
int unstall(Dev *dev, Dev *ep, int dir); int unstall(Dev *dev, Dev *ep, int dir);
int usbcmd(Dev *d, int type, int req, int usbcmd(Dev *d, int type, int req,
int value, int index, uchar *data, int count); int value, int index, uchar *data, int count);
Dev* getdev(int id); Dev* getdev(char *devid);
.sp 0.3v .sp 0.3v
extern int usbdebug; /* more messages for bigger values */ extern int usbdebug; /* more messages for bigger values */
.EE .EE

View file

@ -88,23 +88,41 @@ attachment. It provides a filesystem with the file
.B usbevent .B usbevent
(usually seen as (usually seen as
.BR /dev/usbevent ) .BR /dev/usbevent )
which, when read, returns a 5 column, space separated line of which, when read, returns a 6 column, space separated line of
text, one for each event. The columns are: text, one for each event. The columns are:
.B attach .B attach
or or
.B detach .B detach
.I devid followed by
.I addr
.I vid .I vid
.I did .I did
.I csp
and and
.I csp . .I hname .
All but The
.I devid .I addr
are formatted as 4 digit hexadecimal. This file is read by is the decimal device address assigned.
.I Vid
and
.I did
are formatted as 4 digit hexadecimal.
.I Csp
is the device class, subclass, protocol indentifier
formatd as 6 digit hexadecimal.
.I Usbd
assigns a stable device uniqueue name based on the
device descriptor for
.I hname .
This information is read by
.IR nusbrc (8) .IR nusbrc (8)
and the and the
.I addr
and
.I hname
are passed to a suitable driver as
.I devid .I devid
is passed to a suitable driver. in the form \fIaddr\fB:\fIhname
.SS Keyboards and mice .SS Keyboards and mice
.I Kb .I Kb
supports USB keyboards and mice either as separate USB devices supports USB keyboards and mice either as separate USB devices
@ -123,13 +141,10 @@ configures and manages USB mass storage devices. It
provides a file system (usually seen under provides a file system (usually seen under
.BR /dev ) .BR /dev )
that includes one directory per storage device, named that includes one directory per storage device, named
.BI sdU N . M .BI sdU N [. M ]
in correspondence with the usb device number and the storage in correspondence with the usb device uniqueue name
unit number (or LUN). and the storage unit number (or LUN). The LUN is omited
For example, LUN number 2 on for single lun devices.
.B /dev/usb/ep3.0
can be accessed through
.BR /dev/sdU3.2 .
.PP .PP
The storage device directory contains the usual files The storage device directory contains the usual files
served by served by
@ -183,7 +198,7 @@ provides a file system (usually seen under
that includes one directory per USB serial port, named that includes one directory per USB serial port, named
.BI eiaU N .BI eiaU N
or or
.BI eiaU N . M. .BI eiaU N [. M ].
In this directory there are two files, In this directory there are two files,
.BR eiaU , .BR eiaU ,
similar to similar to

View file

@ -15,9 +15,21 @@ or
.IR cpurc (8)), .IR cpurc (8)),
.I nusbrc .I nusbrc
handles the startup and shutdown of usb drivers on physical handles the startup and shutdown of usb drivers on physical
device attach and detach events. device attach and detach events by reading
.B /dev/usbevent
file.
.SH SOURCE .SH SOURCE
.B /rc/bin/nusbrc .B /rc/bin/nusbrc
.B /sys/src/9/boot/nusbrc .B /sys/src/9/boot/nusbrc
.SH "SEE ALSO" .SH "SEE ALSO"
.IR nusb (4) .IR nusb (4)
.SH BUGS
Usb devices appear as files under
.B /dev
and
.B /shr
identified by the devices uniqueue name assigned by usbd.
When the environment variable
.I nousbhname
is defined, devies are named by ther dynamically assigned
usb device address instead. This emulates the old behaviour.

View file

@ -812,6 +812,11 @@ It is not on by default because it causes problems on some laptops.
.SS \fLusbwait=\fIvalue\fP .SS \fLusbwait=\fIvalue\fP
This changes the sleep time from the default 2 to value in cases of This changes the sleep time from the default 2 to value in cases of
USB devices taking a long time to come online. USB devices taking a long time to come online.
.SS \fLnousbhname=\fP
When defined,
.IR nusbrc (8)
will use the dynamically assigned usb device address to name
usb devices instead of the device uniqueue name.
.SS VIDEO .SS VIDEO
.SS \fLmonitor=\fIvalue\fP .SS \fLmonitor=\fIvalue\fP
.SS \fLvgasize=\fIvalue\fP .SS \fLvgasize=\fIvalue\fP

View file

@ -11,29 +11,33 @@ if(! nusb/usbd)
@{ @{
rfork ne rfork ne
fn attach { fn attach {
id=$1
if(~ $#* 5 && ! test -e /env/nousbhname)
id=$1:$5
switch($2$3){ switch($2$3){
case 0b957720 0b95772a 0db0a877 13b10018 15577720 20013c05 07d13c05 05ac1402 case 0b957720 0b95772a 0db0a877 13b10018 15577720 20013c05 07d13c05 05ac1402
nusb/ether -t a88772 $etherargs $1 nusb/ether -t a88772 $etherargs $id
case 0b951780 14eaab11 17370039 0411006e 050d5055 case 0b951780 14eaab11 17370039 0411006e 050d5055
nusb/ether -t a88178 $etherargs $1 nusb/ether -t a88178 $etherargs $id
case 2001abc1 case 2001abc1
nusb/ether -t aue $etherargs $1 nusb/ether -t aue $etherargs $id
case 0bda8150 case 0bda8150
nusb/ether -t url $etherargs $1 nusb/ether -t url $etherargs $id
case 18d14ee3 0bb40003 case 18d14ee3 0bb40003
nusb/ether -t rndis $etherargs $1 nusb/ether -t rndis $etherargs $id
case * case *
switch($4){ switch($4){
case *03 case *03
nusb/kb $1 nusb/kb $id
case *02 case *02
# CDC ethernet # CDC ethernet
nusb/ether $etherargs $1 nusb/ether $etherargs $id
case *08 case *08
if(nusb/disk $1) {@{ if(nusb/disk $id) {@{
rfork ne rfork ne
cd '#σ/usb' cd '#σ/usb'
for(dev in sdU^$1.*) if(test -d $dev) { devs=sdU^($1 $5)
for(dev in $devs $devs.*) if(test -d $dev) {
diskparts $dev diskparts $dev
for(part in $dev/dos* $dev/9fat) if(test -r $part) { for(part in $dev/dos* $dev/9fat) if(test -r $part) {
mkdir -m 0700 '#σc/'^$dev || exit mkdir -m 0700 '#σc/'^$dev || exit
@ -45,12 +49,13 @@ if(! nusb/usbd)
}&} }&}
case * case *
if(~ $2 0424) if(~ $2 0424)
nusb/ether -t smsc $etherargs $1 nusb/ether -t smsc $etherargs $id
} }
} }
} }
fn detach { fn detach {
rm -rf '#σc/usb/'^$1.* '#σc/sdU'^$1.* '#σc/usbnet/'^$1.* devs='#σc/sdU'^($1 $5)
rm -rf '#σc/usb/'^$1.* '#σc/usbnet/'^$1.* $devs $devs.*
} }
rc < '#σ/usb/usbevent' & rc < '#σ/usb/usbevent' &
} }

View file

@ -184,7 +184,7 @@ main(int argc, char *argv[])
if(argc == 0) if(argc == 0)
usage(); usage();
if((d = getdev(atoi(*argv))) == nil) if((d = getdev(*argv)) == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
audiodev = d; audiodev = d;

View file

@ -1042,7 +1042,7 @@ main(int argc, char **argv)
if(argc != 1) if(argc != 1)
usage(); usage();
dev = getdev(atoi(*argv)); dev = getdev(*argv);
if(dev == nil) if(dev == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
ums = dev->aux = emallocz(sizeof(Ums), 1); ums = dev->aux = emallocz(sizeof(Ums), 1);
@ -1062,7 +1062,10 @@ main(int argc, char **argv)
for(i = 0; i <= ums->maxlun; i++){ for(i = 0; i <= ums->maxlun; i++){
lun = &ums->lun[i]; lun = &ums->lun[i];
snprint(lun->name, sizeof(lun->name), "sdU%d.%d", dev->id, i); if(ums->maxlun > 0)
snprint(lun->name, sizeof(lun->name), "sdU%s.%d", dev->hname, i);
else
snprint(lun->name, sizeof(lun->name), "sdU%s", dev->hname);
makeparts(lun); makeparts(lun);
} }
snprint(buf, sizeof buf, "%d.disk", dev->id); snprint(buf, sizeof buf, "%d.disk", dev->id);

View file

@ -819,7 +819,7 @@ threadmain(int argc, char **argv)
if(argc != 1) if(argc != 1)
usage(); usage();
if((d = getdev(atoi(*argv))) == nil) if((d = getdev(*argv)) == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
if(findendpoints(d, &ei, &eo) < 0) if(findendpoints(d, &ei, &eo) < 0)
sysfatal("no endpoints found"); sysfatal("no endpoints found");
@ -847,7 +847,7 @@ threadmain(int argc, char **argv)
atnotify(inote, 1); atnotify(inote, 1);
time0 = time(0); time0 = time(0);
tab[Qiface].name = smprint("etherU%d", d->id); tab[Qiface].name = smprint("etherU%s", d->hname);
snprint(s, sizeof(s), "%d.ether", d->id); snprint(s, sizeof(s), "%d.ether", d->id);
closedev(d); closedev(d);
threadpostsharesrv(&fs, nil, "usbnet", s); threadpostsharesrv(&fs, nil, "usbnet", s);

View file

@ -410,7 +410,7 @@ threadmain(int argc, char* argv[])
}ARGEND; }ARGEND;
if(argc != 1) if(argc != 1)
usage(); usage();
d = getdev(atoi(*argv)); d = getdev(*argv);
if(d == nil) if(d == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
ud = d->usb; ud = d->usb;

View file

@ -794,7 +794,7 @@ threadmain(int argc, char* argv[])
}ARGEND; }ARGEND;
if(argc != 1) if(argc != 1)
usage(); usage();
d = getdev(atoi(*argv)); d = getdev(*argv);
if(d == nil) if(d == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
ud = d->usb; ud = d->usb;

View file

@ -121,6 +121,7 @@ opendev(char *fn)
free(d); free(d);
return nil; return nil;
} }
d->hname = nil;
dprint(2, "%s: opendev %#p %s\n", argv0, d, fn); dprint(2, "%s: opendev %#p %s\n", argv0, d, fn);
return d; return d;
} }
@ -323,6 +324,8 @@ closedev(Dev *d)
d->cfd = d->dfd = -1; d->cfd = d->dfd = -1;
free(d->dir); free(d->dir);
d->dir = nil; d->dir = nil;
free(d->hname);
d->hname = nil;
ud = d->usb; ud = d->usb;
d->usb = nil; d->usb = nil;
if(ud != nil){ if(ud != nil){
@ -509,12 +512,26 @@ devctl(Dev *dev, char *fmt, ...)
} }
Dev * Dev *
getdev(int id) getdev(char *devid)
{ {
char buf[40], *p;
Dev *d; Dev *d;
char buf[40];
if(devid[0] == '/' || devid[0] == '#'){
snprint(buf, sizeof buf, "/dev/usb/ep%d.0", id); snprint(buf, sizeof buf, "%s", devid);
p = strrchr(buf, '/');
if(p != nil){
p = strrchr(buf, ':');
if(p != nil)
*p = 0;
}
} else {
p = nil;
snprint(buf, sizeof buf, "/dev/usb/ep%ld.0", strtol(devid, &p, 10));
if(*p != ':')
p = nil;
}
d = opendev(buf); d = opendev(buf);
if(d == nil) if(d == nil)
return nil; return nil;
@ -522,5 +539,12 @@ getdev(int id)
closedev(d); closedev(d);
return nil; return nil;
} }
if(p == nil){
snprint(buf, sizeof buf, ":%d", d->id);
p = buf;
}
d->hname = strdup(p+1);
return d; return d;
} }

View file

@ -174,6 +174,7 @@ struct Dev
Usbdev* usb; /* USB description */ Usbdev* usb; /* USB description */
void* aux; /* for the device driver */ void* aux; /* for the device driver */
void (*free)(void*); /* idem. to release aux */ void (*free)(void*); /* idem. to release aux */
char* hname; /* hash name, uniqueue for device */
}; };
/* /*
@ -351,7 +352,7 @@ int parsedesc(Usbdev *d, Conf *c, uchar *b, int n);
int parsedev(Dev *xd, uchar *b, int n); int parsedev(Dev *xd, uchar *b, int n);
int unstall(Dev *dev, Dev *ep, int dir); int unstall(Dev *dev, Dev *ep, int dir);
int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count); int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count);
Dev* getdev(int id); Dev* getdev(char *devid);
extern int usbdebug; /* more messages for bigger values */ extern int usbdebug; /* more messages for bigger values */

View file

@ -1011,7 +1011,7 @@ threadmain(int argc, char **argv)
if(argc == 0) if(argc == 0)
usage(); usage();
if((d = getdev(atoi(*argv))) == nil) if((d = getdev(*argv)) == nil)
sysfatal("opendev: %r"); sysfatal("opendev: %r");
if(findendpoints(d, &epin, &epout, &epint) < 0) if(findendpoints(d, &epin, &epout, &epint) < 0)
sysfatal("findendpoints: %r"); sysfatal("findendpoints: %r");
@ -1037,7 +1037,7 @@ threadmain(int argc, char **argv)
time0 = time(0); time0 = time(0);
snprint(name, sizeof name, "sdU%d", d->id); snprint(name, sizeof name, "sdU%s", d->hname);
snprint(desc, sizeof desc, "%d.ptp", d->id); snprint(desc, sizeof desc, "%d.ptp", d->id);
threadpostsharesrv(&fs, nil, name, desc); threadpostsharesrv(&fs, nil, name, desc);

View file

@ -810,7 +810,7 @@ threadmain(int argc, char* argv[])
}ARGEND }ARGEND
if(argc != 1) if(argc != 1)
usage(); usage();
dev = getdev(atoi(*argv)); dev = getdev(*argv);
if(dev == nil) if(dev == nil)
sysfatal("getdev: %r"); sysfatal("getdev: %r");
@ -859,17 +859,10 @@ threadmain(int argc, char* argv[])
} }
dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p); dsprint(2, "serial: adding interface %d, %p\n", p->interfc, p);
if(p->isjtag){ if(ser->nifcs == 1)
snprint(p->name, sizeof p->name, "jtag"); snprint(p->name, sizeof p->name, "%s%s", p->isjtag ? "jtag" : "eiaU", dev->hname);
dsprint(2, "serial: JTAG interface %d %p\n", i, p); else
snprint(p->name, sizeof p->name, "jtag%d.%d", dev->id, i); snprint(p->name, sizeof p->name, "%s%s.%d", p->isjtag ? "jtag" : "eiaU", dev->hname, i);
} else {
snprint(p->name, sizeof p->name, "eiaU");
if(i == 0)
snprint(p->name, sizeof p->name, "eiaU%d", dev->id);
else
snprint(p->name, sizeof p->name, "eiaU%d.%d", dev->id, i);
}
fprint(2, "%s...", p->name); fprint(2, "%s...", p->name);
incref(dev); incref(dev);
p->readrend.l = &p->readq; p->readrend.l = &p->readq;

View file

@ -2,3 +2,4 @@ int attachdev(Port*);
void detachdev(Port*); void detachdev(Port*);
void work(void); void work(void);
Hub* newhub(char *, Dev *); Hub* newhub(char *, Dev *);
void hname(char *);

View file

@ -0,0 +1,17 @@
#include <u.h>
#include <libc.h>
#include <mp.h>
#include <libsec.h>
void
hname(char *buf)
{
uchar d[SHA1dlen];
u32int x;
int n;
n = strlen(buf);
sha1((uchar*)buf, n, d, nil);
x = d[0] | d[1]<<8 | d[2]<<16;
snprint(buf, n+1, "%.5ux", x & 0xfffff);
}

View file

@ -3,6 +3,7 @@
OFILES=\ OFILES=\
usbd.$O\ usbd.$O\
hub.$O\ hub.$O\
hname.$O\
HFILES=\ HFILES=\
dat.h\ dat.h\

View file

@ -221,8 +221,10 @@ static char *
formatdev(Dev *d, int type) formatdev(Dev *d, int type)
{ {
Usbdev *u = d->usb; Usbdev *u = d->usb;
return smprint("%s %d %.4x %.4x %.6lx %s\n",
return smprint("%s %d %.4x %.4x %.8lx\n", type ? "detach" : "attach", d->id, u->vid, u->did, u->csp); type ? "detach" : "attach",
d->id, u->vid, u->did, u->csp,
d->hname != nil ? d->hname : "");
} }
static void static void
@ -335,6 +337,39 @@ Srv usbdsrv = {
.destroyfid = usbddestroyfid, .destroyfid = usbddestroyfid,
}; };
static void
assignhname(Dev *dev)
{
extern Hub *hubs;
char buf[64];
Usbdev *ud;
Hub *h;
int i;
ud = dev->usb;
/* build string of device uniqueue stuff */
snprint(buf, sizeof(buf), "%.4x%.4x%.4x%.6lx%s",
ud->vid, ud->did, ud->dno, ud->csp, ud->serial);
hname(buf);
/* check for collisions */
for(h = hubs; h != nil; h = h->next){
for(i = 1; i <= h->nport; i++){
if(h->port[i].dev == nil)
continue;
if(h->port[i].dev->hname == nil || h->port[i].dev == dev)
continue;
if(strcmp(h->port[i].dev->hname, buf) == 0){
dev->hname = smprint("%s%d", buf, dev->id);
return;
}
}
}
dev->hname = strdup(buf);
}
int int
attachdev(Port *p) attachdev(Port *p)
{ {
@ -355,6 +390,9 @@ attachdev(Port *p)
/* close control endpoint so driver can open it */ /* close control endpoint so driver can open it */
close(d->dfd); close(d->dfd);
d->dfd = -1; d->dfd = -1;
/* assign stable name based on device descriptor */
assignhname(d);
pushevent(d, formatdev(d, 0)); pushevent(d, formatdev(d, 0));
return 0; return 0;