nusb: Fix handling of interface altsetting.
The altsetting was handled only for a single endpoint (per interface number), but has to be handled for each endpoint (per interface *AND* altsetting number). A multi function device (like a disk) can have multiple interfaces, all with the same interface number but varying altsetting numbers and each of these interfaces would list distict endpoint configurations. Multiple interfaces can even share some endpoints (they use the same endpoint addresses), but we still have to duplicate them for each interface+altsetting number (as they'r part of actually distict interfaces with distict endpoint configurations). It is also important to *NOT* make endpoints bi-directional (dir == Eboth) when only one direction is used in a interface/altsetting and the other direction in another. This was the case for nusb/disk with some seagate drive where endpoints where shared between the UAS and usb storage class interface (but with distict altsettings). The duplicate endpoints (as in using the same endpoint address) are chained together by a next pointer and the head is stored in Usbdev.ep[addr], where addr is the endpoint address. These Ep structures will have distinct endpoint numbers Ep.id (when they have conflicting types), but all will share the endpoint address (lower 4 bits of the endpoint number). The consequence is that all of the endpoints configuration (attributes, interval) is now stored in the Ep struct and no more Altc struct is present. A pointer to the Ep struct has to be passed to openep() for it to configure the endpoint. For the Iface struct, we will now create multiple of them: one for each interface *AND* altsetting nunber, chained together on a next pointer and the head being stored in conf->iface[ifaceid]. -- cinap
This commit is contained in:
parent
14bb9734a6
commit
065d601916
16 changed files with 370 additions and 387 deletions
|
@ -24,14 +24,17 @@ struct Dev {
|
||||||
int id; /* usb id for device or ep. number */
|
int id; /* usb id for device or ep. number */
|
||||||
int dfd; /* descriptor for the data file */
|
int dfd; /* descriptor for the data file */
|
||||||
int cfd; /* descriptor for the control file */
|
int cfd; /* descriptor for the control file */
|
||||||
|
int isusb3; /* this is a usb3 device */
|
||||||
|
int depth; /* hub depth for usb3 hubs */
|
||||||
int maxpkt; /* cached from usb description */
|
int maxpkt; /* cached from usb description */
|
||||||
Usbdev* usb; /* USB description */
|
Usbdev* usb; /* USB description */
|
||||||
|
Ep* ep; /* endpoint from epopen() */
|
||||||
void* aux; /* for the device driver */
|
void* aux; /* for the device driver */
|
||||||
void (*free)(void*); /* idem. to release aux */
|
|
||||||
char* hname; /* hash name, unique for device */
|
char* hname; /* hash name, unique for device */
|
||||||
};
|
};
|
||||||
.sp 0.3v
|
.sp 0.3v
|
||||||
struct Usbdev {
|
struct Usbdev {
|
||||||
|
int ver; /* usb version */
|
||||||
ulong csp; /* USB class/subclass/proto */
|
ulong csp; /* USB class/subclass/proto */
|
||||||
int vid; /* vendor id */
|
int vid; /* vendor id */
|
||||||
int did; /* product (device) id */
|
int did; /* product (device) id */
|
||||||
|
@ -39,36 +42,42 @@ struct Usbdev {
|
||||||
char* vendor;
|
char* vendor;
|
||||||
char* product;
|
char* product;
|
||||||
char* serial;
|
char* serial;
|
||||||
int ls; /* low speed */
|
int vsid;
|
||||||
|
int psid;
|
||||||
|
int ssid;
|
||||||
int class; /* from descriptor */
|
int class; /* from descriptor */
|
||||||
int nconf; /* from descriptor */
|
int nconf; /* from descriptor */
|
||||||
Conf* conf[Nconf]; /* configurations */
|
Conf* conf[Nconf]; /* configurations */
|
||||||
Ep* ep[Nep]; /* all endpoints in device */
|
Ep* ep[Epmax+1]; /* all endpoints in device (chained), indexed by address */
|
||||||
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
|
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
|
||||||
};
|
};
|
||||||
.sp 0.3v
|
.sp 0.3v
|
||||||
struct Ep {
|
struct Ep {
|
||||||
uchar addr; /* endpt address */
|
|
||||||
uchar dir; /* direction, Ein/Eout */
|
|
||||||
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
|
|
||||||
uchar isotype; /* Eunknown, Easync, Eadapt, Esync */
|
|
||||||
int id;
|
|
||||||
int maxpkt; /* max. packet size */
|
|
||||||
Conf* conf; /* the endpoint belongs to */
|
|
||||||
Iface* iface; /* the endpoint belongs to */
|
Iface* iface; /* the endpoint belongs to */
|
||||||
};
|
Conf* conf; /* the endpoint belongs to */
|
||||||
.sp 0.3v
|
|
||||||
struct Altc {
|
int id; /* endpoint number: (id & Epmax) == endpoint address */
|
||||||
|
uchar dir; /* direction, Ein/Eout/Eboth */
|
||||||
|
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
|
||||||
|
|
||||||
int attrib;
|
int attrib;
|
||||||
int interval;
|
int pollival;
|
||||||
|
int maxpkt; /* max. packet size */
|
||||||
|
int ntds; /* nb. of Tds per µframe */
|
||||||
|
|
||||||
|
/* chain of endpoints with same address (used in different interfaces/altsettings) */
|
||||||
|
Ep* next;
|
||||||
|
|
||||||
void* aux; /* for the driver program */
|
void* aux; /* for the driver program */
|
||||||
};
|
};
|
||||||
.sp 0.3v
|
.sp 0.3v
|
||||||
struct Iface {
|
struct Iface {
|
||||||
int id; /* interface number */
|
int id; /* interface number */
|
||||||
|
int alt; /* altsetting for this interface */
|
||||||
ulong csp; /* USB class/subclass/proto */
|
ulong csp; /* USB class/subclass/proto */
|
||||||
Altc* altc[Naltc];
|
Iface* next; /* chain of interfaces of different altsettings */
|
||||||
Ep* ep[Nep];
|
Ep* ep[Nep]; /* consecutive array of endpoints in this interface (not including ep0) */
|
||||||
|
|
||||||
void* aux; /* for the driver program */
|
void* aux; /* for the driver program */
|
||||||
};
|
};
|
||||||
.sp 0.3v
|
.sp 0.3v
|
||||||
|
@ -83,7 +92,6 @@ struct Desc {
|
||||||
Conf* conf; /* where this descriptor was read */
|
Conf* conf; /* where this descriptor was read */
|
||||||
Iface* iface; /* last iface before desc in conf. */
|
Iface* iface; /* last iface before desc in conf. */
|
||||||
Ep* ep; /* last endpt 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 */
|
DDesc data; /* unparsed standard USB descriptor */
|
||||||
};
|
};
|
||||||
.sp 0.3v
|
.sp 0.3v
|
||||||
|
@ -116,7 +124,7 @@ char* hexstr(void *a, int n);
|
||||||
char* loaddevstr(Dev *d, int sid);
|
char* loaddevstr(Dev *d, int sid);
|
||||||
Dev* opendev(char *fn);
|
Dev* opendev(char *fn);
|
||||||
int opendevdata(Dev *d, int mode);
|
int opendevdata(Dev *d, int mode);
|
||||||
Dev* openep(Dev *d, int id);
|
Dev* openep(Dev *d, Ep *e);
|
||||||
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);
|
||||||
|
@ -160,11 +168,7 @@ to add references and
|
||||||
to drop references (and release resources when the last one vanishes).
|
to drop references (and release resources when the last one vanishes).
|
||||||
As an aid to the driver, the field
|
As an aid to the driver, the field
|
||||||
.B aux
|
.B aux
|
||||||
may keep driver-specific data and the function
|
may keep driver-specific data.
|
||||||
.B free
|
|
||||||
will be called (if not null) to release the
|
|
||||||
.B aux
|
|
||||||
structure when the reference count goes down to zero.
|
|
||||||
.PP
|
.PP
|
||||||
.I Dev.dir
|
.I Dev.dir
|
||||||
holds the path for the endpoint's directory.
|
holds the path for the endpoint's directory.
|
||||||
|
@ -173,6 +177,9 @@ The field
|
||||||
.B id
|
.B id
|
||||||
keeps the device number for setup endpoints and the endpoint number
|
keeps the device number for setup endpoints and the endpoint number
|
||||||
for all other endpoints.
|
for all other endpoints.
|
||||||
|
The endpoint number identifies
|
||||||
|
.I devusb
|
||||||
|
endpoint and is unique within a device.
|
||||||
For example, it would be
|
For example, it would be
|
||||||
.B 3
|
.B 3
|
||||||
for
|
for
|
||||||
|
@ -185,6 +192,12 @@ It is easy to remember this because the former is created to operate
|
||||||
on the device, while the later has been created as a particular endpoint
|
on the device, while the later has been created as a particular endpoint
|
||||||
to perform I/O.
|
to perform I/O.
|
||||||
.PP
|
.PP
|
||||||
|
The field
|
||||||
|
.B ep
|
||||||
|
holds the endpoint structure that was passed in
|
||||||
|
.I epopen
|
||||||
|
which gives easy access to the endpoint configuration.
|
||||||
|
.PP
|
||||||
Fields
|
Fields
|
||||||
.B dfd
|
.B dfd
|
||||||
and
|
and
|
||||||
|
|
|
@ -40,15 +40,15 @@ parsedescr(Desc *dd)
|
||||||
uchar *b;
|
uchar *b;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(dd == nil || dd->iface == nil || dd->altc == nil)
|
if(dd == nil || dd->iface == nil)
|
||||||
return;
|
return;
|
||||||
if(Subclass(dd->iface->csp) != 2)
|
if(Subclass(dd->iface->csp) != 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
c = dd->altc->aux;
|
c = dd->iface->aux;
|
||||||
if(c == nil){
|
if(c == nil){
|
||||||
c = mallocz(sizeof(*c), 1);
|
c = mallocz(sizeof(*c), 1);
|
||||||
dd->altc->aux = c;
|
dd->iface->aux = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
b = (uchar*)&dd->data;
|
b = (uchar*)&dd->data;
|
||||||
|
@ -87,15 +87,12 @@ parsedescr(Desc *dd)
|
||||||
Dev*
|
Dev*
|
||||||
setupep(Dev *d, Ep *e, int speed)
|
setupep(Dev *d, Ep *e, int speed)
|
||||||
{
|
{
|
||||||
Altc *x;
|
|
||||||
Aconf *c;
|
Aconf *c;
|
||||||
Range *f;
|
Range *f;
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(e->iface->altc); i++){
|
for(;e != nil; e = e->next){
|
||||||
if((x = e->iface->altc[i]) == nil)
|
c = e->iface->aux;
|
||||||
continue;
|
if(c == nil)
|
||||||
if((c = x->aux) == nil)
|
|
||||||
continue;
|
continue;
|
||||||
for(f = c->freq; f != nil; f = f->next)
|
for(f = c->freq; f != nil; f = f->next)
|
||||||
if(speed >= f->min && speed <= f->max)
|
if(speed >= f->min && speed <= f->max)
|
||||||
|
@ -105,7 +102,7 @@ setupep(Dev *d, Ep *e, int speed)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
Foundaltc:
|
Foundaltc:
|
||||||
if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, i, e->iface->id, nil, 0) < 0){
|
if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, e->iface->alt, e->iface->id, nil, 0) < 0){
|
||||||
werrstr("set altc: %r");
|
werrstr("set altc: %r");
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -116,15 +113,14 @@ Foundaltc:
|
||||||
b[0] = speed;
|
b[0] = speed;
|
||||||
b[1] = speed >> 8;
|
b[1] = speed >> 8;
|
||||||
b[2] = speed >> 16;
|
b[2] = speed >> 16;
|
||||||
if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, e->addr, b, 3) < 0)
|
if(usbcmd(d, Rh2d|Rclass|Rep, Rsetcur, 0x100, (e->type==Ein?0x80:0)|(e->id&Epmax), b, 3) < 0)
|
||||||
fprint(2, "warning: set freq: %r\n");
|
fprint(2, "warning: set freq: %r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if((d = openep(d, e->id)) == nil){
|
if((d = openep(d, e)) == nil){
|
||||||
werrstr("openep: %r");
|
werrstr("openep: %r");
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
devctl(d, "pollival %d", x->interval);
|
|
||||||
devctl(d, "samplesz %d", audiochan*audiores/8);
|
devctl(d, "samplesz %d", audiochan*audiores/8);
|
||||||
devctl(d, "sampledelay %d", audiodelay);
|
devctl(d, "sampledelay %d", audiodelay);
|
||||||
devctl(d, "hz %d", speed);
|
devctl(d, "hz %d", speed);
|
||||||
|
@ -224,7 +220,7 @@ main(int argc, char *argv[])
|
||||||
parsedescr(d->usb->ddesc[i]);
|
parsedescr(d->usb->ddesc[i]);
|
||||||
for(i = 0; i < nelem(d->usb->ep); i++){
|
for(i = 0; i < nelem(d->usb->ep); i++){
|
||||||
e = d->usb->ep[i];
|
e = d->usb->ep[i];
|
||||||
if(e != nil && e->type == Eiso && e->iface != nil && e->iface->csp == CSP(Claudio, 2, 0)){
|
if(e != nil && e->type == Eiso && e->iface->csp == CSP(Claudio, 2, 0)){
|
||||||
switch(e->dir){
|
switch(e->dir){
|
||||||
case Ein:
|
case Ein:
|
||||||
if(audioepin != nil)
|
if(audioepin != nil)
|
||||||
|
|
|
@ -248,11 +248,10 @@ frameinterval(Cam *c, VSUncompressedFrame *f, double t)
|
||||||
val = max;
|
val = max;
|
||||||
else{
|
else{
|
||||||
val = floor((t - min) / step) * step + min;
|
val = floor((t - min) / step) * step + min;
|
||||||
if(t >= val + step / 2.0)
|
|
||||||
t += step;
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
mini = -1;
|
mini = -1;
|
||||||
|
minδ = 0;
|
||||||
for(i = 0; i < f->bFrameIntervalType; i++){
|
for(i = 0; i < f->bFrameIntervalType; i++){
|
||||||
δ = fabs(((u32int)GET4(f->dwFrameInterval[i])) - t);
|
δ = fabs(((u32int)GET4(f->dwFrameInterval[i])) - t);
|
||||||
if(mini < 0 || δ < minδ){
|
if(mini < 0 || δ < minδ){
|
||||||
|
|
|
@ -197,43 +197,41 @@ cvtproc(void *v)
|
||||||
qunlock(&c->qulock);
|
qunlock(&c->qulock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Altc *
|
static Ep*
|
||||||
selaltc(Cam *c, ProbeControl *pc)
|
selaltc(Cam *c, ProbeControl *pc, Ep *ep)
|
||||||
{
|
{
|
||||||
int k;
|
|
||||||
uvlong bw, bw1, minbw;
|
uvlong bw, bw1, minbw;
|
||||||
int mink;
|
|
||||||
Format *fo;
|
Format *fo;
|
||||||
VSUncompressedFrame *f;
|
VSUncompressedFrame *f;
|
||||||
Iface *iface;
|
Ep *mink;
|
||||||
Altc *altc;
|
|
||||||
|
|
||||||
if(getframedesc(c, pc->bFormatIndex, pc->bFrameIndex, &fo, &f) < 0){
|
if(getframedesc(c, pc->bFormatIndex, pc->bFrameIndex, &fo, &f) < 0){
|
||||||
werrstr("selaltc: PROBE_CONTROL returned invalid bFormatIndex,bFrameIndex=%d,%d", pc->bFormatIndex, pc->bFrameIndex);
|
werrstr("selaltc: PROBE_CONTROL returned invalid bFormatIndex,bFrameIndex=%d,%d", pc->bFormatIndex, pc->bFrameIndex);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
mink = nil;
|
||||||
|
minbw = ~0ULL;
|
||||||
bw = (uvlong)GET2(f->wWidth) * GET2(f->wHeight) * fo->desc->bBitsPerPixel * 10e6 / GET4(c->pc.dwFrameInterval);
|
bw = (uvlong)GET2(f->wWidth) * GET2(f->wHeight) * fo->desc->bBitsPerPixel * 10e6 / GET4(c->pc.dwFrameInterval);
|
||||||
iface = c->iface;
|
for(;ep != nil; ep = ep->next){
|
||||||
mink = -1;
|
if(ep->iface->id != c->iface->id)
|
||||||
for(k = 0; k < nelem(iface->altc); k++){
|
continue;
|
||||||
altc = iface->altc[k];
|
bw1 = ep->maxpkt * ep->ntds * 8 * 1000 * 8;
|
||||||
if(altc == nil) continue;
|
if(bw1 >= bw) {
|
||||||
bw1 = altc->maxpkt * altc->ntds * 8 * 1000 * 8;
|
if(mink == nil || bw1 < minbw){
|
||||||
if(bw1 < bw) continue;
|
minbw = bw1;
|
||||||
if(mink < 0 || bw1 < minbw){
|
mink = ep;
|
||||||
minbw = bw1;
|
}
|
||||||
mink = k;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mink < 0){
|
if(mink == nil){
|
||||||
werrstr("device does not have enough bandwidth (need %lld bit/s)", bw);
|
werrstr("device does not have enough bandwidth (need %lld bit/s)", bw);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
if(usbcmd(c->dev, 0x01, Rsetiface, mink, iface->id, nil, 0) < 0){
|
if(usbcmd(c->dev, 0x01, Rsetiface, mink->iface->alt, mink->iface->id, nil, 0) < 0){
|
||||||
werrstr("selaltc: SET_INTERFACE(%d, %d): %r", iface->id, mink);
|
werrstr("selaltc: SET_INTERFACE(%d, %d): %r", ep->iface->id, ep->iface->alt);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
return iface->altc[mink];
|
return mink;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -261,8 +259,7 @@ int
|
||||||
videoopen(Cam *c, int fr)
|
videoopen(Cam *c, int fr)
|
||||||
{
|
{
|
||||||
Dev *d;
|
Dev *d;
|
||||||
Altc *altc;
|
Ep *e;
|
||||||
Dev *ep;
|
|
||||||
Format *f;
|
Format *f;
|
||||||
|
|
||||||
qlock(&c->qulock);
|
qlock(&c->qulock);
|
||||||
|
@ -282,24 +279,20 @@ err:
|
||||||
if(usbcmd(d, 0x21, SET_CUR, VS_PROBE_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < sizeof(ProbeControl)) goto err;
|
if(usbcmd(d, 0x21, SET_CUR, VS_PROBE_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < sizeof(ProbeControl)) goto err;
|
||||||
if(usbcmd(d, 0xA1, GET_CUR, VS_PROBE_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < 0) goto err;
|
if(usbcmd(d, 0xA1, GET_CUR, VS_PROBE_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < 0) goto err;
|
||||||
if(usbcmd(d, 0x21, SET_CUR, VS_COMMIT_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < sizeof(ProbeControl)) goto err;
|
if(usbcmd(d, 0x21, SET_CUR, VS_COMMIT_CONTROL << 8, c->iface->id, (uchar *) &c->pc, sizeof(ProbeControl)) < sizeof(ProbeControl)) goto err;
|
||||||
altc = selaltc(c, &c->pc);
|
e = selaltc(c, &c->pc, d->usb->ep[c->hdr->bEndpointAddress & Epmax]);
|
||||||
if(altc == nil)
|
if(e == nil)
|
||||||
goto err;
|
goto err;
|
||||||
ep = openep(d, c->hdr->bEndpointAddress & 0x7f);
|
c->ep = openep(d, e);
|
||||||
if(ep == nil){
|
if(c->ep == nil){
|
||||||
usbcmd(d, 0x01, Rsetiface, 0, c->iface->id, nil, 0);
|
usbcmd(d, 0x01, Rsetiface, 0, c->iface->id, nil, 0);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
devctl(ep, "pollival %d", altc->interval);
|
devctl(c->ep, "uframes 1");
|
||||||
devctl(ep, "uframes 1");
|
if(opendevdata(c->ep, OREAD) < 0){
|
||||||
devctl(ep, "ntds %d", altc->ntds);
|
|
||||||
devctl(ep, "maxpkt %d", altc->maxpkt);
|
|
||||||
if(opendevdata(ep, OREAD) < 0){
|
|
||||||
usbcmd(d, 0x01, Rsetiface, 0, c->iface->id, nil, 0);
|
usbcmd(d, 0x01, Rsetiface, 0, c->iface->id, nil, 0);
|
||||||
closedev(ep);
|
closedev(c->ep);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
c->ep = ep;
|
|
||||||
mkframes(c);
|
mkframes(c);
|
||||||
c->active = 1;
|
c->active = 1;
|
||||||
c->framemode = fr;
|
c->framemode = fr;
|
||||||
|
|
|
@ -386,7 +386,6 @@ umsinit(void)
|
||||||
}
|
}
|
||||||
if(some == 0){
|
if(some == 0){
|
||||||
dprint(2, "disk: all luns failed\n");
|
dprint(2, "disk: all luns failed\n");
|
||||||
devctl(dev, "detach");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -950,46 +949,61 @@ dwrite(Req *req)
|
||||||
int
|
int
|
||||||
findendpoints(Ums *ums)
|
findendpoints(Ums *ums)
|
||||||
{
|
{
|
||||||
Ep *ep;
|
Ep *ep, *ein, *eout;
|
||||||
Usbdev *ud;
|
Usbdev *ud;
|
||||||
ulong csp, sc;
|
ulong csp;
|
||||||
int i, epin, epout;
|
int i;
|
||||||
|
|
||||||
epin = epout = -1;
|
|
||||||
ud = dev->usb;
|
ud = dev->usb;
|
||||||
|
|
||||||
|
ein = eout = nil;
|
||||||
for(i = 0; i < nelem(ud->ep); i++){
|
for(i = 0; i < nelem(ud->ep); i++){
|
||||||
if((ep = ud->ep[i]) == nil)
|
if((ep = ud->ep[i]) == nil)
|
||||||
continue;
|
continue;
|
||||||
csp = ep->iface->csp;
|
csp = ep->iface->csp;
|
||||||
sc = Subclass(csp);
|
if(Class(csp) != Clstorage || Proto(csp) != Protobulk || ep->type != Ebulk)
|
||||||
if(!(Class(csp) == Clstorage && (Proto(csp) == Protobulk || Proto(csp) == Protouas)))
|
|
||||||
continue;
|
continue;
|
||||||
if(sc != Subatapi && sc != Sub8070 && sc != Subscsi)
|
if(ep->dir == Eboth || ep->dir == Ein)
|
||||||
fprint(2, "disk: subclass %#ulx not supported. trying anyway\n", sc);
|
if(ein == nil)
|
||||||
if(ep->type == Ebulk){
|
ein = ep;
|
||||||
if(ep->dir == Eboth || ep->dir == Ein)
|
if(ep->dir == Eboth || ep->dir == Eout)
|
||||||
if(epin == -1)
|
if(eout == nil)
|
||||||
epin = ep->id;
|
eout = ep;
|
||||||
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(ein != nil && eout != nil)
|
||||||
if(epin == -1 || epout == -1)
|
goto Found;
|
||||||
|
|
||||||
|
/* try UAS protocol */
|
||||||
|
ein = eout = nil;
|
||||||
|
for(i = 0; i < nelem(ud->ep); i++){
|
||||||
|
if((ep = ud->ep[i]) == nil)
|
||||||
|
continue;
|
||||||
|
csp = ep->iface->csp;
|
||||||
|
if(Class(csp) != Clstorage || Proto(csp) != Protouas || ep->type != Ebulk)
|
||||||
|
continue;
|
||||||
|
if(ep->dir == Eboth || ep->dir == Ein)
|
||||||
|
if(ein == nil)
|
||||||
|
ein = ep;
|
||||||
|
if(ep->dir == Eboth || ep->dir == Eout)
|
||||||
|
if(eout == nil)
|
||||||
|
eout = ep;
|
||||||
|
}
|
||||||
|
if(ein == nil || eout == nil)
|
||||||
return -1;
|
return -1;
|
||||||
ums->epin = openep(dev, epin);
|
Found:
|
||||||
|
dprint(2, "disk: ep ids: in %d out %d\n", ein->id, eout->id);
|
||||||
|
ums->epin = openep(dev, ein);
|
||||||
if(ums->epin == nil){
|
if(ums->epin == nil){
|
||||||
fprint(2, "disk: openep %d: %r\n", epin);
|
fprint(2, "disk: openep %d: %r\n", ein->id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(epout == epin){
|
if(ein == eout){
|
||||||
incref(ums->epin);
|
incref(ums->epin);
|
||||||
ums->epout = ums->epin;
|
ums->epout = ums->epin;
|
||||||
}else
|
}else
|
||||||
ums->epout = openep(dev, epout);
|
ums->epout = openep(dev, eout);
|
||||||
if(ums->epout == nil){
|
if(ums->epout == nil){
|
||||||
fprint(2, "disk: openep %d: %r\n", epout);
|
fprint(2, "disk: openep %d: %r\n", eout->id);
|
||||||
closedev(ums->epin);
|
closedev(ums->epin);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1064,6 +1078,7 @@ main(int argc, char **argv)
|
||||||
case 'd':
|
case 'd':
|
||||||
scsidebug(diskdebug);
|
scsidebug(diskdebug);
|
||||||
diskdebug++;
|
diskdebug++;
|
||||||
|
usbdebug++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
|
|
@ -586,55 +586,49 @@ fsdestroyfid(Fid *fid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
static int
|
||||||
ifaceinit(Dev *d, Iface *ifc, int *ei, int *eo)
|
ifaceinit(Dev *d, Iface *iface, Ep **ein, Ep **eout)
|
||||||
{
|
{
|
||||||
int i, epin, epout;
|
|
||||||
Ep *ep;
|
Ep *ep;
|
||||||
|
int i;
|
||||||
|
|
||||||
if(ifc == nil)
|
if(iface == nil)
|
||||||
return -1;
|
return -1;
|
||||||
|
*ein = *eout = nil;
|
||||||
epin = epout = -1;
|
for(i = 0; i < nelem(iface->ep); i++){
|
||||||
for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++)
|
ep = iface->ep[i];
|
||||||
if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){
|
if(ep == nil)
|
||||||
if(ep->dir == Eboth || ep->dir == Ein)
|
break;
|
||||||
if(epin == -1)
|
if(ep->type != Ebulk)
|
||||||
epin = ep->id;
|
continue;
|
||||||
if(ep->dir == Eboth || ep->dir == Eout)
|
if(ep->dir == Eboth || ep->dir == Ein){
|
||||||
if(epout == -1)
|
if(*ein == nil)
|
||||||
epout = ep->id;
|
*ein = ep;
|
||||||
}
|
}
|
||||||
if(epin == -1 || epout == -1)
|
if(ep->dir == Eboth || ep->dir == Eout){
|
||||||
return -1;
|
if(*eout == nil)
|
||||||
|
*eout = ep;
|
||||||
for(i = 0; i < nelem(ifc->altc); i++)
|
}
|
||||||
if(ifc->altc[i] != nil)
|
if(*ein != nil && *eout != nil)
|
||||||
setalt(d, ifc->id, i);
|
goto Found;
|
||||||
|
}
|
||||||
*ei = epin;
|
return -1;
|
||||||
*eo = epout;
|
Found:
|
||||||
|
if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, iface->alt, iface->id, nil, 0) < 0)
|
||||||
|
dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, iface->id, iface->alt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
findendpoints(Dev *d, int *ei, int *eo)
|
findendpoints(Dev *d, Ep **ein, Ep **eout)
|
||||||
{
|
{
|
||||||
int i, j, ctlid, datid;
|
int i, j, ctlid, datid;
|
||||||
Iface *ctlif, *datif;
|
Iface *iface, *ctlif, *datif;
|
||||||
Usbdev *ud;
|
Usbdev *ud;
|
||||||
Desc *desc;
|
Desc *desc;
|
||||||
Conf *c;
|
Conf *c;
|
||||||
|
|
||||||
ud = d->usb;
|
ud = d->usb;
|
||||||
*ei = *eo = -1;
|
|
||||||
|
|
||||||
/* look for union descriptor with ethernet ctrl interface */
|
/* look for union descriptor with ethernet ctrl interface */
|
||||||
for(i = 0; i < nelem(ud->ddesc); i++){
|
for(i = 0; i < nelem(ud->ddesc); i++){
|
||||||
|
@ -651,16 +645,15 @@ findendpoints(Dev *d, int *ei, int *eo)
|
||||||
|
|
||||||
ctlif = datif = nil;
|
ctlif = datif = nil;
|
||||||
for(j = 0; j < nelem(c->iface); j++){
|
for(j = 0; j < nelem(c->iface); j++){
|
||||||
if(c->iface[j] == nil)
|
for(iface = c->iface[j]; iface != nil; iface = iface->next){
|
||||||
continue;
|
if(iface->id == ctlid)
|
||||||
if(c->iface[j]->id == ctlid)
|
ctlif = iface;
|
||||||
ctlif = c->iface[j];
|
if(iface->id == datid)
|
||||||
if(c->iface[j]->id == datid)
|
datif = iface;
|
||||||
datif = c->iface[j];
|
}
|
||||||
|
|
||||||
if(datif != nil && ctlif != nil){
|
if(datif != nil && ctlif != nil){
|
||||||
if(Subclass(ctlif->csp) == Scether)
|
if(Subclass(ctlif->csp) == Scether)
|
||||||
if(ifaceinit(d, datif, ei, eo) != -1)
|
if(ifaceinit(d, datif, ein, eout) != -1)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -668,11 +661,18 @@ findendpoints(Dev *d, int *ei, int *eo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try any other one that seems to be ok */
|
/* try any other one that seems to be ok */
|
||||||
for(i = 0; i < nelem(ud->conf); i++)
|
for(i = 0; i < nelem(ud->conf); i++){
|
||||||
if((c = ud->conf[i]) != nil)
|
if((c = ud->conf[i]) != nil){
|
||||||
for(j = 0; j < nelem(c->iface); j++)
|
for(j = 0; j < nelem(c->iface); j++){
|
||||||
if(ifaceinit(d,c->iface[j],ei,eo) != -1)
|
for(datif = c->iface[j]; datif != nil; datif = datif->next){
|
||||||
return 0;
|
if(ifaceinit(d, datif, ein, eout) != -1)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ein = *eout = nil;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -909,7 +909,8 @@ void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char s[64], *t;
|
char s[64], *t;
|
||||||
int et, ei, eo;
|
int et;
|
||||||
|
Ep *ein, *eout;
|
||||||
|
|
||||||
fmtinstall('E', eipfmt);
|
fmtinstall('E', eipfmt);
|
||||||
|
|
||||||
|
@ -948,7 +949,8 @@ threadmain(int argc, char **argv)
|
||||||
|
|
||||||
if((epctl = getdev(*argv)) == nil)
|
if((epctl = getdev(*argv)) == nil)
|
||||||
sysfatal("getdev: %r");
|
sysfatal("getdev: %r");
|
||||||
if(findendpoints(epctl, &ei, &eo) < 0)
|
|
||||||
|
if(findendpoints(epctl, &ein, &eout) < 0)
|
||||||
sysfatal("no endpoints found");
|
sysfatal("no endpoints found");
|
||||||
|
|
||||||
werrstr("");
|
werrstr("");
|
||||||
|
@ -957,14 +959,14 @@ threadmain(int argc, char **argv)
|
||||||
if(epreceive == nil || eptransmit == nil)
|
if(epreceive == nil || eptransmit == nil)
|
||||||
sysfatal("bug in init");
|
sysfatal("bug in init");
|
||||||
|
|
||||||
if((epin = openep(epctl, ei)) == nil)
|
if((epin = openep(epctl, ein)) == nil)
|
||||||
sysfatal("openep: %r");
|
sysfatal("openep: %r");
|
||||||
if(ei == eo){
|
if(ein == eout){
|
||||||
incref(epin);
|
incref(epin);
|
||||||
epout = epin;
|
epout = epin;
|
||||||
opendevdata(epin, ORDWR);
|
opendevdata(epin, ORDWR);
|
||||||
} else {
|
} else {
|
||||||
if((epout = openep(epctl, eo)) == nil)
|
if((epout = openep(epctl, eout)) == nil)
|
||||||
sysfatal("openep: %r");
|
sysfatal("openep: %r");
|
||||||
opendevdata(epin, OREAD);
|
opendevdata(epin, OREAD);
|
||||||
opendevdata(epout, OWRITE);
|
opendevdata(epout, OWRITE);
|
||||||
|
|
|
@ -199,13 +199,12 @@ repparse(uchar *d, uchar *e,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setproto(KDev *f, int eid)
|
setproto(KDev *f, Iface *iface)
|
||||||
{
|
{
|
||||||
int id, proto;
|
int proto;
|
||||||
|
|
||||||
proto = Bootproto;
|
proto = Bootproto;
|
||||||
id = f->dev->usb->ep[eid]->iface->id;
|
f->nrep = usbcmd(f->dev, Rd2h|Rstd|Riface, Rgetdesc, Dreport<<8, iface->id,
|
||||||
f->nrep = usbcmd(f->dev, Rd2h|Rstd|Riface, Rgetdesc, Dreport<<8, id,
|
|
||||||
f->rep, sizeof(f->rep));
|
f->rep, sizeof(f->rep));
|
||||||
if(f->nrep > 0){
|
if(f->nrep > 0){
|
||||||
if(debug){
|
if(debug){
|
||||||
|
@ -227,10 +226,10 @@ setproto(KDev *f, int eid)
|
||||||
* if a HID's subclass code is 1 (boot mode), it will support
|
* if a HID's subclass code is 1 (boot mode), it will support
|
||||||
* setproto, otherwise it is not guaranteed to.
|
* setproto, otherwise it is not guaranteed to.
|
||||||
*/
|
*/
|
||||||
if(Subclass(f->dev->usb->ep[eid]->iface->csp) != 1)
|
if(Subclass(iface->csp) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return usbcmd(f->dev, Rh2d|Rclass|Riface, Setproto, proto, id, nil, 0);
|
return usbcmd(f->dev, Rh2d|Rclass|Riface, Setproto, proto, iface->id, nil, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -387,11 +386,11 @@ kbstart(Dev *d, Ep *ep, void (*f)(void*))
|
||||||
kd = emallocz(sizeof(KDev), 1);
|
kd = emallocz(sizeof(KDev), 1);
|
||||||
incref(d);
|
incref(d);
|
||||||
kd->dev = d;
|
kd->dev = d;
|
||||||
if(setproto(kd, ep->id) < 0){
|
if(setproto(kd, ep->iface) < 0){
|
||||||
fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
|
fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
kd->ep = openep(kd->dev, ep->id);
|
kd->ep = openep(kd->dev, ep);
|
||||||
if(kd->ep == nil){
|
if(kd->ep == nil){
|
||||||
fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
|
fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
|
||||||
goto Err;
|
goto Err;
|
||||||
|
|
|
@ -323,12 +323,10 @@ repparse(uchar *d, uchar *e,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setproto(Hiddev *f, int eid)
|
setproto(Hiddev *f, Iface *iface)
|
||||||
{
|
{
|
||||||
int proto;
|
int proto;
|
||||||
Iface *iface;
|
|
||||||
|
|
||||||
iface = f->dev->usb->ep[eid]->iface;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DWC OTG controller misses some split transaction inputs.
|
* DWC OTG controller misses some split transaction inputs.
|
||||||
|
@ -433,7 +431,7 @@ hdrecover(Hiddev *f)
|
||||||
qlock(&l);
|
qlock(&l);
|
||||||
}
|
}
|
||||||
Resetdone:
|
Resetdone:
|
||||||
if(setproto(f, f->ep->id) < 0){
|
if(setproto(f, f->ep->ep->iface) < 0){
|
||||||
rerrstr(err, sizeof(err));
|
rerrstr(err, sizeof(err));
|
||||||
qunlock(&l);
|
qunlock(&l);
|
||||||
hdfatal(f, err);
|
hdfatal(f, err);
|
||||||
|
@ -883,11 +881,11 @@ hdsetup(Dev *d, Ep *ep)
|
||||||
f->kinfd = -1;
|
f->kinfd = -1;
|
||||||
incref(d);
|
incref(d);
|
||||||
f->dev = d;
|
f->dev = d;
|
||||||
if(setproto(f, ep->id) < 0){
|
if(setproto(f, ep->iface) < 0){
|
||||||
fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
|
fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir);
|
||||||
goto Err;
|
goto Err;
|
||||||
}
|
}
|
||||||
f->ep = openep(f->dev, ep->id);
|
f->ep = openep(f->dev, ep);
|
||||||
if(f->ep == nil){
|
if(f->ep == nil){
|
||||||
fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
|
fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id);
|
||||||
goto Err;
|
goto Err;
|
||||||
|
|
|
@ -24,63 +24,47 @@ nameid(char *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
Dev*
|
Dev*
|
||||||
openep(Dev *d, int id)
|
openep(Dev *d, Ep *ep)
|
||||||
{
|
{
|
||||||
char *mode; /* How many modes? */
|
char *mode; /* How many modes? */
|
||||||
Ep *ep;
|
|
||||||
Altc *ac;
|
|
||||||
Dev *epd;
|
Dev *epd;
|
||||||
Usbdev *ud;
|
|
||||||
char name[40];
|
char name[40];
|
||||||
|
|
||||||
if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
|
|
||||||
return nil;
|
|
||||||
if(d->cfd < 0 || d->usb == nil){
|
if(d->cfd < 0 || d->usb == nil){
|
||||||
werrstr("device not configured");
|
werrstr("device not configured");
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
ud = d->usb;
|
snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, ep->id);
|
||||||
if(id < 0 || id >= nelem(ud->ep) || ud->ep[id] == nil){
|
|
||||||
werrstr("bad enpoint number");
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
ep = ud->ep[id];
|
|
||||||
snprint(name, sizeof(name), "/dev/usb/ep%d.%d", d->id, id);
|
|
||||||
if(access(name, AEXIST) == 0){
|
if(access(name, AEXIST) == 0){
|
||||||
dprint(2, "%s: %s already exists; trying to open\n", argv0, name);
|
dprint(2, "%s: %s already exists; trying to open\n", argv0, name);
|
||||||
epd = opendev(name);
|
epd = opendev(name);
|
||||||
if(epd != nil){
|
} else {
|
||||||
epd->id = id;
|
mode = "rw";
|
||||||
epd->maxpkt = ep->maxpkt; /* guess */
|
if(ep->dir == Ein)
|
||||||
|
mode = "r";
|
||||||
|
if(ep->dir == Eout)
|
||||||
|
mode = "w";
|
||||||
|
if(devctl(d, "new %d %d %s", ep->id, ep->type, mode) < 0){
|
||||||
|
dprint(2, "%s: %s: new: %r\n", argv0, d->dir);
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
return epd;
|
epd = opendev(name);
|
||||||
}
|
}
|
||||||
mode = "rw";
|
|
||||||
if(ep->dir == Ein)
|
|
||||||
mode = "r";
|
|
||||||
if(ep->dir == Eout)
|
|
||||||
mode = "w";
|
|
||||||
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)
|
if(epd == nil)
|
||||||
return nil;
|
return nil;
|
||||||
epd->id = id;
|
epd->ep = ep;
|
||||||
|
epd->id = ep->id;
|
||||||
if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0)
|
if(devctl(epd, "maxpkt %d", ep->maxpkt) < 0)
|
||||||
fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir);
|
fprint(2, "%s: %s: openep: maxpkt: %r\n", argv0, epd->dir);
|
||||||
else
|
else
|
||||||
dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt);
|
dprint(2, "%s: %s: maxpkt %d\n", argv0, epd->dir, ep->maxpkt);
|
||||||
epd->maxpkt = ep->maxpkt;
|
epd->maxpkt = ep->maxpkt;
|
||||||
ac = ep->iface->altc[0];
|
|
||||||
if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0)
|
if(ep->ntds > 1 && devctl(epd, "ntds %d", ep->ntds) < 0)
|
||||||
fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir);
|
fprint(2, "%s: %s: openep: ntds: %r\n", argv0, epd->dir);
|
||||||
else
|
else
|
||||||
dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds);
|
dprint(2, "%s: %s: ntds %d\n", argv0, epd->dir, ep->ntds);
|
||||||
|
if((ep->type == Eintr || ep->type == Eiso) && ep->pollival != 0)
|
||||||
if(ac != nil && (ep->type == Eintr || ep->type == Eiso) && ac->interval != 0)
|
if(devctl(epd, "pollival %d", ep->pollival) < 0)
|
||||||
if(devctl(epd, "pollival %d", ac->interval) < 0)
|
|
||||||
fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir);
|
fprint(2, "%s: %s: openep: pollival: %r\n", argv0, epd->dir);
|
||||||
return epd;
|
return epd;
|
||||||
}
|
}
|
||||||
|
@ -91,8 +75,6 @@ opendev(char *fn)
|
||||||
Dev *d;
|
Dev *d;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0)
|
|
||||||
return nil;
|
|
||||||
d = emallocz(sizeof(Dev), 1);
|
d = emallocz(sizeof(Dev), 1);
|
||||||
incref(d);
|
incref(d);
|
||||||
|
|
||||||
|
@ -109,6 +91,7 @@ opendev(char *fn)
|
||||||
strcpy(d->dir+l, "/ctl");
|
strcpy(d->dir+l, "/ctl");
|
||||||
d->cfd = open(d->dir, ORDWR|OCEXEC);
|
d->cfd = open(d->dir, ORDWR|OCEXEC);
|
||||||
d->dir[l] = 0;
|
d->dir[l] = 0;
|
||||||
|
d->ep = nil;
|
||||||
d->id = nameid(fn);
|
d->id = nameid(fn);
|
||||||
if(d->cfd < 0){
|
if(d->cfd < 0){
|
||||||
werrstr("can't open endpoint %s: %r", d->dir);
|
werrstr("can't open endpoint %s: %r", d->dir);
|
||||||
|
@ -173,8 +156,13 @@ mkep(Usbdev *d, int id)
|
||||||
{
|
{
|
||||||
Ep *ep;
|
Ep *ep;
|
||||||
|
|
||||||
d->ep[id] = ep = emallocz(sizeof(Ep), 1);
|
ep = emallocz(sizeof(Ep), 1);
|
||||||
ep->id = id;
|
ep->id = id;
|
||||||
|
|
||||||
|
id &= Epmax;
|
||||||
|
ep->next = d->ep[id];
|
||||||
|
d->ep[id] = ep;
|
||||||
|
|
||||||
return ep;
|
return ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +246,7 @@ loaddevdesc(Dev *d)
|
||||||
ep0->dir = Eboth;
|
ep0->dir = Eboth;
|
||||||
ep0->type = Econtrol;
|
ep0->type = Econtrol;
|
||||||
ep0->maxpkt = d->maxpkt = 8; /* a default */
|
ep0->maxpkt = d->maxpkt = 8; /* a default */
|
||||||
|
d->ep = ep0;
|
||||||
nr = parsedev(d, buf, nr);
|
nr = parsedev(d, buf, nr);
|
||||||
if(nr >= 0){
|
if(nr >= 0){
|
||||||
d->usb->vendor = loaddevstr(d, d->usb->vsid);
|
d->usb->vendor = loaddevstr(d, d->usb->vsid);
|
||||||
|
@ -289,17 +278,17 @@ configdev(Dev *d)
|
||||||
static void
|
static void
|
||||||
closeconf(Conf *c)
|
closeconf(Conf *c)
|
||||||
{
|
{
|
||||||
|
Iface *f;
|
||||||
int i;
|
int i;
|
||||||
int a;
|
|
||||||
|
|
||||||
if(c == nil)
|
if(c == nil)
|
||||||
return;
|
return;
|
||||||
for(i = 0; i < nelem(c->iface); i++)
|
for(i = 0; i < nelem(c->iface); i++){
|
||||||
if(c->iface[i] != nil){
|
while((f = c->iface[i]) != nil) {
|
||||||
for(a = 0; a < nelem(c->iface[i]->altc); a++)
|
c->iface[i] = f->next;
|
||||||
free(c->iface[i]->altc[a]);
|
free(f);
|
||||||
free(c->iface[i]);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +296,7 @@ void
|
||||||
closedev(Dev *d)
|
closedev(Dev *d)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
Ep *ep;
|
||||||
Usbdev *ud;
|
Usbdev *ud;
|
||||||
|
|
||||||
if(d==nil || decref(d) != 0)
|
if(d==nil || decref(d) != 0)
|
||||||
|
@ -327,11 +317,14 @@ closedev(Dev *d)
|
||||||
free(ud->vendor);
|
free(ud->vendor);
|
||||||
free(ud->product);
|
free(ud->product);
|
||||||
free(ud->serial);
|
free(ud->serial);
|
||||||
for(i = 0; i < nelem(ud->ep); i++)
|
for(i = 0; i < nelem(ud->ep); i++){
|
||||||
free(ud->ep[i]);
|
while((ep = ud->ep[i]) != nil){
|
||||||
|
ud->ep[i] = ep->next;
|
||||||
|
free(ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
for(i = 0; i < nelem(ud->ddesc); i++)
|
for(i = 0; i < nelem(ud->ddesc); i++)
|
||||||
free(ud->ddesc[i]);
|
free(ud->ddesc[i]);
|
||||||
|
|
||||||
for(i = 0; i < nelem(ud->conf); i++)
|
for(i = 0; i < nelem(ud->conf); i++)
|
||||||
closeconf(ud->conf[i]);
|
closeconf(ud->conf[i]);
|
||||||
free(ud);
|
free(ud);
|
||||||
|
|
|
@ -52,24 +52,12 @@ static void
|
||||||
fmtprintiface(Fmt *f, Iface *i)
|
fmtprintiface(Fmt *f, Iface *i)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
Altc *a;
|
|
||||||
Ep *ep;
|
Ep *ep;
|
||||||
char *eds, *ets;
|
char *eds, *ets;
|
||||||
|
|
||||||
fmtprint(f, "\t\tiface csp %s.%uld.%uld\n",
|
fmtprint(f, "\t\tiface csp %s.%uld.%uld alt %d\n",
|
||||||
classname(Class(i->csp)), Subclass(i->csp), Proto(i->csp));
|
classname(Class(i->csp)), Subclass(i->csp), Proto(i->csp), i->alt);
|
||||||
for(j = 0; j < Naltc; j++){
|
for(j = 0; j < nelem(i->ep); j++){
|
||||||
a=i->altc[j];
|
|
||||||
if(a == nil)
|
|
||||||
break;
|
|
||||||
fmtprint(f, "\t\t alt %d attr %d ival %d",
|
|
||||||
j, a->attrib, a->interval);
|
|
||||||
if(a->aux != nil)
|
|
||||||
fmtprint(f, " devspec %p\n", a->aux);
|
|
||||||
else
|
|
||||||
fmtprint(f, "\n");
|
|
||||||
}
|
|
||||||
for(j = 0; j < Nep; j++){
|
|
||||||
ep = i->ep[j];
|
ep = i->ep[j];
|
||||||
if(ep == nil)
|
if(ep == nil)
|
||||||
break;
|
break;
|
||||||
|
@ -79,9 +67,9 @@ fmtprintiface(Fmt *f, Iface *i)
|
||||||
if(ep->type <= nelem(etype))
|
if(ep->type <= nelem(etype))
|
||||||
ets = etype[ep->type];
|
ets = etype[ep->type];
|
||||||
fmtprint(f, "\t\t ep id %d addr %d dir %s type %s"
|
fmtprint(f, "\t\t ep id %d addr %d dir %s type %s"
|
||||||
" itype %d maxpkt %d ntds %d\n",
|
" attrib %x maxpkt %d ntds %d pollival %d\n",
|
||||||
ep->id, ep->addr, eds, ets, ep->isotype,
|
ep->id, ep->id & Epmax, eds, ets, ep->attrib,
|
||||||
ep->maxpkt, ep->ntds);
|
ep->maxpkt, ep->ntds, ep->pollival);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,16 +78,16 @@ fmtprintconf(Fmt *f, Usbdev *d, int ci)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Conf *c;
|
Conf *c;
|
||||||
|
Iface *fc;
|
||||||
char *hd;
|
char *hd;
|
||||||
|
|
||||||
c = d->conf[ci];
|
c = d->conf[ci];
|
||||||
fmtprint(f, "\tconf: cval %d attrib %x %d mA\n",
|
fmtprint(f, "\tconf: cval %d attrib %x %d mA\n",
|
||||||
c->cval, c->attrib, c->milliamps);
|
c->cval, c->attrib, c->milliamps);
|
||||||
for(i = 0; i < Niface; i++)
|
for(i = 0; i < Niface; i++){
|
||||||
if(c->iface[i] == nil)
|
for(fc = c->iface[i]; fc != nil; fc = fc->next)
|
||||||
break;
|
fmtprintiface(f, fc);
|
||||||
else
|
}
|
||||||
fmtprintiface(f, c->iface[i]);
|
|
||||||
for(i = 0; i < Nddesc; i++)
|
for(i = 0; i < Nddesc; i++)
|
||||||
if(d->ddesc[i] == nil)
|
if(d->ddesc[i] == nil)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,7 +11,6 @@ parsedev(Dev *xd, uchar *b, int n)
|
||||||
char *hd;
|
char *hd;
|
||||||
|
|
||||||
d = xd->usb;
|
d = xd->usb;
|
||||||
assert(d != nil);
|
|
||||||
dd = (DDev*)b;
|
dd = (DDev*)b;
|
||||||
if(usbdebug>1){
|
if(usbdebug>1){
|
||||||
hd = hexstr(b, Ddevlen);
|
hd = hexstr(b, Ddevlen);
|
||||||
|
@ -50,62 +49,59 @@ parsedev(Dev *xd, uchar *b, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp, Altc **app)
|
parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp)
|
||||||
{
|
{
|
||||||
int class, subclass, proto;
|
int class, subclass, proto, alt, id;
|
||||||
int ifid, altid;
|
ulong csp;
|
||||||
DIface *dip;
|
DIface *dip;
|
||||||
Iface *ip;
|
Iface *ip;
|
||||||
|
|
||||||
assert(d != nil && c != nil);
|
|
||||||
if(n < Difacelen){
|
if(n < Difacelen){
|
||||||
werrstr("short interface descriptor");
|
werrstr("short interface descriptor");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dip = (DIface *)b;
|
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;
|
class = dip->bInterfaceClass;
|
||||||
subclass = dip->bInterfaceSubClass;
|
subclass = dip->bInterfaceSubClass;
|
||||||
proto = dip->bInterfaceProtocol;
|
proto = dip->bInterfaceProtocol;
|
||||||
ip->csp = CSP(class, subclass, proto);
|
csp = CSP(class, subclass, proto);
|
||||||
if(ip->csp == 0)
|
if(csp == 0)
|
||||||
ip->csp = d->csp;
|
csp = d->csp;
|
||||||
if(d->csp == 0) /* use csp from 1st iface */
|
|
||||||
d->csp = ip->csp; /* if device has none */
|
|
||||||
if(d->class == 0)
|
if(d->class == 0)
|
||||||
d->class = class;
|
d->class = class;
|
||||||
ip->id = ifid;
|
alt = dip->bAlternateSetting;
|
||||||
if(c == d->conf[0] && ifid == 0) /* ep0 was already there */
|
id = dip->bInterfaceNumber;
|
||||||
d->ep[0]->iface = ip;
|
if(id < 0 || id >= nelem(c->iface)){
|
||||||
altid = dip->bAlternateSetting;
|
werrstr("bad interface number %d", id);
|
||||||
if(altid < 0 || altid >= nelem(ip->altc)){
|
|
||||||
werrstr("bad alternate conf. number %d", altid);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(ip->altc[altid] == nil)
|
for(ip = c->iface[id]; ip != nil; ip = ip->next)
|
||||||
ip->altc[altid] = emallocz(sizeof(Altc), 1);
|
if(ip->csp == csp && ip->alt == alt)
|
||||||
|
goto Found;
|
||||||
|
ip = emallocz(sizeof(Iface), 1);
|
||||||
|
ip->id = id;
|
||||||
|
ip->csp = csp;
|
||||||
|
ip->alt = alt;
|
||||||
|
ip->next = c->iface[id];
|
||||||
|
c->iface[id] = ip;
|
||||||
|
if(d->csp == 0) /* use csp from 1st iface */
|
||||||
|
d->csp = ip->csp; /* if device has none */
|
||||||
|
if(c == d->conf[0] && id == 0) /* ep0 was already there */
|
||||||
|
d->ep[0]->iface = ip;
|
||||||
|
Found:
|
||||||
*ipp = ip;
|
*ipp = ip;
|
||||||
*app = ip->altc[altid];
|
|
||||||
return Difacelen;
|
return Difacelen;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern Ep* mkep(Usbdev *, int);
|
extern Ep* mkep(Usbdev *, int);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp)
|
parseendpt(Usbdev *d, Conf *c, Iface *ip, uchar *b, int n, Ep **epp)
|
||||||
{
|
{
|
||||||
int i, dir, epid, type, addr;
|
int addr, dir, type, id, i;
|
||||||
Ep *ep;
|
|
||||||
DEp *dep;
|
DEp *dep;
|
||||||
|
Ep *ep;
|
||||||
|
|
||||||
assert(d != nil && c != nil && ip != nil && altc != nil);
|
|
||||||
if(n < Deplen){
|
if(n < Deplen){
|
||||||
werrstr("short endpoint descriptor");
|
werrstr("short endpoint descriptor");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -118,54 +114,67 @@ parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp)
|
||||||
dir = Ein;
|
dir = Ein;
|
||||||
else
|
else
|
||||||
dir = Eout;
|
dir = Eout;
|
||||||
epid = addr & 0xF; /* default map to 0..15 */
|
|
||||||
assert(epid < nelem(d->ep));
|
/*
|
||||||
ep = d->ep[epid];
|
* the endpoint id is created once, setting
|
||||||
if(ep == nil){
|
* type and direction, meaning the endpoint's
|
||||||
ep = mkep(d, epid);
|
* id must be unique for (type, dir) relative
|
||||||
ep->dir = dir;
|
* to all other potential endpoints from
|
||||||
}else if((ep->addr & 0x80) != (addr & 0x80)){
|
* interfaces/altsettings on this device.
|
||||||
if(ep->type == type && type != Eiso)
|
*
|
||||||
ep->dir = Eboth;
|
* the low Epmax bits of the id contains the
|
||||||
else {
|
* endpoint address that must be preserved.
|
||||||
/*
|
*/
|
||||||
* resolve conflict when same endpoint number
|
id = addr & Epmax;
|
||||||
* is used for different input and output types.
|
Again:
|
||||||
* map input endpoint to 16..31 and output to 0..15.
|
for(ep = d->ep[id & Epmax]; ep != nil; ep = ep->next){
|
||||||
*/
|
if(ep->id != id)
|
||||||
ep->id = ((ep->addr & 0x80) != 0)<<4 | (ep->addr & 0xF);
|
continue;
|
||||||
d->ep[ep->id] = ep;
|
if(ep->type != type){
|
||||||
epid = ep->id ^ 0x10;
|
id += Epmax+1;
|
||||||
ep = mkep(d, epid);
|
goto Again;
|
||||||
ep->dir = dir;
|
|
||||||
}
|
}
|
||||||
|
if(ep->dir == dir)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* Ein/Eout endpoints from the same
|
||||||
|
* interface/altsetting can be merged
|
||||||
|
* into one. (except for iso).
|
||||||
|
*/
|
||||||
|
if(ep->iface != ip || type == Eiso){
|
||||||
|
id += Epmax+1;
|
||||||
|
goto Again;
|
||||||
|
}
|
||||||
|
dir = Eboth;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ep == nil || ep->iface != ip)
|
||||||
|
ep = mkep(d, id);
|
||||||
|
|
||||||
|
ep->dir = dir;
|
||||||
|
ep->type = type;
|
||||||
|
ep->iface = ip;
|
||||||
|
ep->conf = c;
|
||||||
ep->maxpkt = GET2(dep->wMaxPacketSize);
|
ep->maxpkt = GET2(dep->wMaxPacketSize);
|
||||||
ep->ntds = 1 + ((ep->maxpkt >> 11) & 3);
|
ep->ntds = 1 + ((ep->maxpkt >> 11) & 3);
|
||||||
ep->maxpkt &= 0x7FF;
|
ep->maxpkt &= 0x7FF;
|
||||||
ep->addr = addr;
|
ep->attrib = dep->bmAttributes;
|
||||||
ep->type = type;
|
ep->pollival = dep->bInterval;
|
||||||
ep->isotype = (dep->bmAttributes>>2) & 0x03;
|
|
||||||
ep->isousage = (dep->bmAttributes>>4) & 0x03;
|
for(i = 0; i < nelem(ip->ep); i++){
|
||||||
ep->conf = c;
|
if(ip->ep[i] == nil){
|
||||||
ep->iface = ip;
|
ip->ep[i] = ep;
|
||||||
if(ep->type != Eiso || ep->isousage == Edata || ep->isousage == Eimplicit){
|
break;
|
||||||
altc->attrib = dep->bmAttributes;
|
}
|
||||||
altc->interval = dep->bInterval;
|
if(ip->ep[i] == ep)
|
||||||
altc->maxpkt = ep->maxpkt;
|
|
||||||
altc->ntds = ep->ntds;
|
|
||||||
}
|
|
||||||
for(i = 0; i < nelem(ip->ep); i++)
|
|
||||||
if(ip->ep[i] == nil)
|
|
||||||
break;
|
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;
|
if(i >= nelem(ip->ep))
|
||||||
return Dep;
|
fprint(2, "%s: parseendpt: too many endpoints in interface", argv0);
|
||||||
|
|
||||||
|
*epp = ep;
|
||||||
|
return Deplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
|
@ -189,14 +198,11 @@ parsedesc(Usbdev *d, Conf *c, uchar *b, int n)
|
||||||
int len, nd, tot;
|
int len, nd, tot;
|
||||||
Iface *ip;
|
Iface *ip;
|
||||||
Ep *ep;
|
Ep *ep;
|
||||||
Altc *altc;
|
|
||||||
char *hd;
|
char *hd;
|
||||||
|
|
||||||
assert(d != nil && c != nil);
|
|
||||||
tot = 0;
|
tot = 0;
|
||||||
ip = nil;
|
ip = nil;
|
||||||
ep = nil;
|
ep = nil;
|
||||||
altc = nil;
|
|
||||||
for(nd = 0; nd < nelem(d->ddesc); nd++)
|
for(nd = 0; nd < nelem(d->ddesc); nd++)
|
||||||
if(d->ddesc[nd] == nil)
|
if(d->ddesc[nd] == nil)
|
||||||
break;
|
break;
|
||||||
|
@ -216,23 +222,23 @@ parsedesc(Usbdev *d, Conf *c, uchar *b, int n)
|
||||||
ddprint(2, "%s\tparsedesc: %r", argv0);
|
ddprint(2, "%s\tparsedesc: %r", argv0);
|
||||||
break;
|
break;
|
||||||
case Diface:
|
case Diface:
|
||||||
if(parseiface(d, c, b, n, &ip, &altc) < 0){
|
if(parseiface(d, c, b, n, &ip) < 0){
|
||||||
ddprint(2, "%s\tparsedesc: %r\n", argv0);
|
ddprint(2, "%s\tparsedesc: %r\n", argv0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Dep:
|
case Dep:
|
||||||
if(ip == nil || altc == nil){
|
if(ip == nil){
|
||||||
werrstr("unexpected endpoint descriptor");
|
werrstr("unexpected endpoint descriptor");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){
|
if(parseendpt(d, c, ip, b, n, &ep) < 0){
|
||||||
ddprint(2, "%s\tparsedesc: %r\n", argv0);
|
ddprint(2, "%s\tparsedesc: %r\n", argv0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(nd == nelem(d->ddesc)){
|
if(nd >= nelem(d->ddesc)){
|
||||||
fprint(2, "%s: parsedesc: too many "
|
fprint(2, "%s: parsedesc: too many "
|
||||||
"device-specific descriptors for device"
|
"device-specific descriptors for device"
|
||||||
" %s %s\n",
|
" %s %s\n",
|
||||||
|
@ -242,7 +248,6 @@ parsedesc(Usbdev *d, Conf *c, uchar *b, int n)
|
||||||
d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0);
|
d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0);
|
||||||
d->ddesc[nd]->iface = ip;
|
d->ddesc[nd]->iface = ip;
|
||||||
d->ddesc[nd]->ep = ep;
|
d->ddesc[nd]->ep = ep;
|
||||||
d->ddesc[nd]->altc = altc;
|
|
||||||
d->ddesc[nd]->conf = c;
|
d->ddesc[nd]->conf = c;
|
||||||
memmove(&d->ddesc[nd]->data, b, len);
|
memmove(&d->ddesc[nd]->data, b, len);
|
||||||
++nd;
|
++nd;
|
||||||
|
@ -262,7 +267,6 @@ parseconf(Usbdev *d, Conf *c, uchar *b, int n)
|
||||||
int nr;
|
int nr;
|
||||||
char *hd;
|
char *hd;
|
||||||
|
|
||||||
assert(d != nil && c != nil);
|
|
||||||
dc = (DConf*)b;
|
dc = (DConf*)b;
|
||||||
if(usbdebug>1){
|
if(usbdebug>1){
|
||||||
hd = hexstr(b, Dconflen);
|
hd = hexstr(b, Dconflen);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
typedef struct Altc Altc;
|
|
||||||
typedef struct Conf Conf;
|
typedef struct Conf Conf;
|
||||||
typedef struct DConf DConf;
|
typedef struct DConf DConf;
|
||||||
typedef struct DDesc DDesc;
|
typedef struct DDesc DDesc;
|
||||||
|
@ -12,17 +11,17 @@ typedef struct Iface Iface;
|
||||||
typedef struct Usbdev Usbdev;
|
typedef struct Usbdev Usbdev;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* fundamental constants */
|
|
||||||
Nep = 256, /* max. endpoints per usb device & per interface */
|
|
||||||
|
|
||||||
/* tunable parameters */
|
/* tunable parameters */
|
||||||
|
Nep = 64, /* max. endpoints per interface */
|
||||||
Nconf = 16, /* max. configurations per usb device */
|
Nconf = 16, /* max. configurations per usb device */
|
||||||
Nddesc = 8*Nep, /* max. device-specific descriptors per usb device */
|
Nddesc = 8*Nep, /* max. device-specific descriptors per usb device */
|
||||||
Niface = 16, /* max. interfaces per configuration */
|
Niface = 16, /* max. interfaces per configuration */
|
||||||
Naltc = 256, /* max. alt configurations per interface */
|
|
||||||
Uctries = 4, /* no. of tries for usbcmd */
|
Uctries = 4, /* no. of tries for usbcmd */
|
||||||
Ucdelay = 50, /* delay before retrying */
|
Ucdelay = 50, /* delay before retrying */
|
||||||
|
|
||||||
|
/* fundamental constants */
|
||||||
|
Epmax = 0xF, /* endpoint address mask */
|
||||||
|
|
||||||
/* request type */
|
/* request type */
|
||||||
Rh2d = 0<<7, /* host to device */
|
Rh2d = 0<<7, /* host to device */
|
||||||
Rd2h = 1<<7, /* device to host */
|
Rd2h = 1<<7, /* device to host */
|
||||||
|
@ -110,17 +109,6 @@ enum {
|
||||||
Ebulk = 2,
|
Ebulk = 2,
|
||||||
Eintr = 3,
|
Eintr = 3,
|
||||||
|
|
||||||
/* endpoint isotype */
|
|
||||||
Eunknown = 0,
|
|
||||||
Easync = 1,
|
|
||||||
Eadapt = 2,
|
|
||||||
Esync = 3,
|
|
||||||
|
|
||||||
/* endpoint isousage */
|
|
||||||
Edata = 0,
|
|
||||||
Efeedback = 1,
|
|
||||||
Eimplicit = 2,
|
|
||||||
|
|
||||||
/* config attrib */
|
/* config attrib */
|
||||||
Cbuspowered = 1<<7,
|
Cbuspowered = 1<<7,
|
||||||
Cselfpowered = 1<<6,
|
Cselfpowered = 1<<6,
|
||||||
|
@ -182,6 +170,7 @@ struct Dev
|
||||||
int depth; /* hub depth for usb3 hubs */
|
int depth; /* hub depth for usb3 hubs */
|
||||||
int maxpkt; /* cached from usb description */
|
int maxpkt; /* cached from usb description */
|
||||||
Usbdev* usb; /* USB description */
|
Usbdev* usb; /* USB description */
|
||||||
|
Ep* ep; /* endpoint from epopen() */
|
||||||
void* aux; /* for the device driver */
|
void* aux; /* for the device driver */
|
||||||
char* hname; /* hash name, unique for device */
|
char* hname; /* hash name, unique for device */
|
||||||
};
|
};
|
||||||
|
@ -205,40 +194,38 @@ struct Usbdev
|
||||||
int class; /* from descriptor */
|
int class; /* from descriptor */
|
||||||
int nconf; /* from descriptor */
|
int nconf; /* from descriptor */
|
||||||
Conf* conf[Nconf]; /* configurations */
|
Conf* conf[Nconf]; /* configurations */
|
||||||
Ep* ep[Nep]; /* all endpoints in device */
|
Ep* ep[Epmax+1]; /* all endpoints in device (chained), indexed by address */
|
||||||
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
|
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ep
|
struct Ep
|
||||||
{
|
{
|
||||||
uchar addr; /* endpt address, 0-15 (|0x80 if Ein) */
|
Iface* iface; /* the endpoint belongs to */
|
||||||
uchar dir; /* direction, Ein/Eout */
|
Conf* conf; /* the endpoint belongs to */
|
||||||
|
|
||||||
|
int id; /* endpoint number: (id & Epmax) == endpoint address */
|
||||||
|
uchar dir; /* direction, Ein/Eout/Eboth */
|
||||||
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
|
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
|
||||||
uchar isotype; /* Eunknown, Easync, Eadapt, Esync */
|
|
||||||
uchar isousage; /* Edata, Efeedback, Eimplicit */
|
int attrib;
|
||||||
|
int pollival;
|
||||||
int id;
|
|
||||||
int maxpkt; /* max. packet size */
|
int maxpkt; /* max. packet size */
|
||||||
int ntds; /* nb. of Tds per µframe */
|
int ntds; /* nb. of Tds per µframe */
|
||||||
Conf* conf; /* the endpoint belongs to */
|
|
||||||
Iface* iface; /* the endpoint belongs to */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Altc
|
/* chain of endpoints with same address (used in different interfaces/altsettings) */
|
||||||
{
|
Ep* next;
|
||||||
int attrib;
|
|
||||||
int interval;
|
|
||||||
int maxpkt;
|
|
||||||
int ntds;
|
|
||||||
void* aux; /* for the driver program */
|
void* aux; /* for the driver program */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Iface
|
struct Iface
|
||||||
{
|
{
|
||||||
int id; /* interface number */
|
int id; /* interface number */
|
||||||
|
int alt; /* altsetting for this interface */
|
||||||
ulong csp; /* USB class/subclass/proto */
|
ulong csp; /* USB class/subclass/proto */
|
||||||
Altc* altc[Naltc];
|
Iface* next; /* chain of interfaces of different altsettings */
|
||||||
Ep* ep[Nep];
|
Ep* ep[Nep]; /* consecutive array of endpoints in this interface (not including ep0) */
|
||||||
|
|
||||||
void* aux; /* for the driver program */
|
void* aux; /* for the driver program */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,7 +256,6 @@ struct Desc
|
||||||
Conf* conf; /* where this descriptor was read */
|
Conf* conf; /* where this descriptor was read */
|
||||||
Iface* iface; /* last iface before desc in conf. */
|
Iface* iface; /* last iface before desc in conf. */
|
||||||
Ep* ep; /* last endpt 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 */
|
DDesc data; /* unparsed standard USB descriptor */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -360,7 +346,7 @@ int loaddevdesc(Dev *d);
|
||||||
char* loaddevstr(Dev *d, int sid);
|
char* loaddevstr(Dev *d, int sid);
|
||||||
Dev* opendev(char *fn);
|
Dev* opendev(char *fn);
|
||||||
int opendevdata(Dev *d, int mode);
|
int opendevdata(Dev *d, int mode);
|
||||||
Dev* openep(Dev *d, int id);
|
Dev* openep(Dev *d, Ep *e);
|
||||||
int parseconf(Usbdev *d, Conf *c, uchar *b, int n);
|
int parseconf(Usbdev *d, Conf *c, uchar *b, int n);
|
||||||
int parsedesc(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);
|
int parsedev(Dev *xd, uchar *b, int n);
|
||||||
|
@ -369,5 +355,3 @@ int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int cou
|
||||||
Dev* getdev(char *devid);
|
Dev* getdev(char *devid);
|
||||||
|
|
||||||
extern int usbdebug; /* more messages for bigger values */
|
extern int usbdebug; /* more messages for bigger values */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -958,29 +958,29 @@ fsend(Srv *)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
findendpoints(Dev *d, int *epin, int *epout, int *epint)
|
findendpoints(Dev *d, Ep **epin, Ep **epout, Ep **epint)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
Ep *ep;
|
Ep *ep;
|
||||||
Usbdev *ud;
|
Usbdev *ud;
|
||||||
|
|
||||||
ud = d->usb;
|
ud = d->usb;
|
||||||
*epin = *epout = *epint = -1;
|
*epin = *epout = *epint = nil;
|
||||||
for(i=0; i<nelem(ud->ep); i++){
|
for(i=0; i<nelem(ud->ep); i++){
|
||||||
if((ep = ud->ep[i]) == nil)
|
if((ep = ud->ep[i]) == nil)
|
||||||
continue;
|
continue;
|
||||||
if(ep->type == Eintr && *epint == -1)
|
if(ep->type == Eintr && *epint == nil)
|
||||||
*epint = ep->id;
|
*epint = ep;
|
||||||
if(ep->type != Ebulk)
|
if(ep->type != Ebulk)
|
||||||
continue;
|
continue;
|
||||||
if(ep->dir == Eboth || ep->dir == Ein)
|
if(ep->dir == Eboth || ep->dir == Ein)
|
||||||
if(*epin == -1)
|
if(*epin == nil)
|
||||||
*epin = ep->id;
|
*epin = ep;
|
||||||
if(ep->dir == Eboth || ep->dir == Eout)
|
if(ep->dir == Eboth || ep->dir == Eout)
|
||||||
if(*epout == -1)
|
if(*epout == nil)
|
||||||
*epout = ep->id;
|
*epout = ep;
|
||||||
}
|
}
|
||||||
if(*epin >= 0 && *epout >= 0)
|
if(*epin != nil && *epout != nil)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1009,7 @@ void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char name[64], desc[64];
|
char name[64], desc[64];
|
||||||
int epin, epout, epint;
|
Ep *epin, *epout, *epint;
|
||||||
Dev *d;
|
Dev *d;
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
|
|
|
@ -1385,7 +1385,6 @@ Eagain:
|
||||||
chanclose(p->w4data);
|
chanclose(p->w4data);
|
||||||
if(p->gotdata != nil)
|
if(p->gotdata != nil)
|
||||||
chanclose(p->gotdata);
|
chanclose(p->gotdata);
|
||||||
devctl(ser->dev, "detach");
|
|
||||||
closedev(ser->dev);
|
closedev(ser->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1426,7 +1425,6 @@ statusreader(void *u)
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdownchan(c);
|
shutdownchan(c);
|
||||||
devctl(ser->dev, "detach");
|
|
||||||
closedev(ser->dev);
|
closedev(ser->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,7 @@ serialfatal(Serial *ser)
|
||||||
Serialport *p;
|
Serialport *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dsprint(2, "serial: fatal error, detaching\n");
|
dsprint(2, "serial: fatal error, closing\n");
|
||||||
devctl(ser->dev, "detach");
|
|
||||||
|
|
||||||
for(i = 0; i < ser->nifcs; i++){
|
for(i = 0; i < ser->nifcs; i++){
|
||||||
p = &ser->p[i];
|
p = &ser->p[i];
|
||||||
if(p->w4data != nil)
|
if(p->w4data != nil)
|
||||||
|
@ -564,14 +562,14 @@ dwrite(Req *req)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
openeps(Serialport *p, int epin, int epout, int epintr)
|
openeps(Serialport *p, Ep *epin, Ep *epout, Ep *epintr)
|
||||||
{
|
{
|
||||||
Serial *ser;
|
Serial *ser;
|
||||||
|
|
||||||
ser = p->s;
|
ser = p->s;
|
||||||
p->epin = openep(ser->dev, epin);
|
p->epin = openep(ser->dev, epin);
|
||||||
if(p->epin == nil){
|
if(p->epin == nil){
|
||||||
fprint(2, "serial: openep %d: %r\n", epin);
|
fprint(2, "serial: openep %d: %r\n", epin->id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(epin == epout){
|
if(epin == epout){
|
||||||
|
@ -580,14 +578,14 @@ openeps(Serialport *p, int epin, int epout, int epintr)
|
||||||
} else
|
} else
|
||||||
p->epout = openep(ser->dev, epout);
|
p->epout = openep(ser->dev, epout);
|
||||||
if(p->epout == nil){
|
if(p->epout == nil){
|
||||||
fprint(2, "serial: openep %d: %r\n", epout);
|
fprint(2, "serial: openep %d: %r\n", epout->id);
|
||||||
closedev(p->epin);
|
closedev(p->epin);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(ser->hasepintr){
|
if(ser->hasepintr){
|
||||||
p->epintr = openep(ser->dev, epintr);
|
p->epintr = openep(ser->dev, epintr);
|
||||||
if(p->epintr == nil){
|
if(p->epintr == nil){
|
||||||
fprint(2, "serial: openep %d: %r\n", epintr);
|
fprint(2, "serial: openep %d: %r\n", epintr->id);
|
||||||
closedev(p->epin);
|
closedev(p->epin);
|
||||||
closedev(p->epout);
|
closedev(p->epout);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -619,34 +617,30 @@ openeps(Serialport *p, int epin, int epout, int epintr)
|
||||||
static int
|
static int
|
||||||
findendpoints(Serial *ser, int ifc)
|
findendpoints(Serial *ser, int ifc)
|
||||||
{
|
{
|
||||||
int i, epin, epout, epintr;
|
Ep **eps, *ep, *epin, *epout, *epintr;
|
||||||
Ep *ep, **eps;
|
int i;
|
||||||
|
|
||||||
epintr = epin = epout = -1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* interfc 0 means start from the start which is equiv to
|
* interfc 0 means start from the start which is equiv to
|
||||||
* iterate through endpoints probably, could be done better
|
* iterate through endpoints probably, could be done better
|
||||||
*/
|
*/
|
||||||
eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
|
eps = ser->dev->usb->conf[0]->iface[ifc]->ep;
|
||||||
|
epintr = epin = epout = nil;
|
||||||
for(i = 0; i < Nep; i++){
|
for(i = 0; i < Nep; i++){
|
||||||
if((ep = eps[i]) == nil)
|
if((ep = eps[i]) == nil)
|
||||||
continue;
|
break;
|
||||||
if(ser->hasepintr && ep->type == Eintr &&
|
if(ser->hasepintr && ep->type == Eintr && ep->dir == Ein && epintr == nil)
|
||||||
ep->dir == Ein && epintr == -1)
|
epintr = ep;
|
||||||
epintr = ep->id;
|
|
||||||
if(ep->type == Ebulk){
|
if(ep->type == Ebulk){
|
||||||
if((ep->dir == Ein || ep->dir == Eboth) && epin == -1)
|
if((ep->dir == Ein || ep->dir == Eboth) && epin == nil)
|
||||||
epin = ep->id;
|
epin = ep;
|
||||||
if((ep->dir == Eout || ep->dir == Eboth) && epout == -1)
|
if((ep->dir == Eout || ep->dir == Eboth) && epout == nil)
|
||||||
epout = ep->id;
|
epout = ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin, epout, epintr);
|
if(epin == nil || epout == nil || (ser->hasepintr && epintr == nil))
|
||||||
if(epin == -1 || epout == -1 || (ser->hasepintr && epintr == -1))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
dprint(2, "serial[%d]: ep ids: in %d out %d intr %d\n", ifc, epin->id, epout->id, epintr!=nil?epintr->id:-1);
|
||||||
if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
|
if(openeps(&ser->p[ifc], epin, epout, epintr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -411,11 +411,18 @@ attachdev(Port *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create all endpoint files for default conf #1 */
|
/*
|
||||||
|
* create all endpoint files for default conf #1
|
||||||
|
* but do not create endpoints that have an altsetting.
|
||||||
|
*/
|
||||||
for(id=1; id<nelem(d->usb->ep); id++){
|
for(id=1; id<nelem(d->usb->ep); id++){
|
||||||
Ep *ep = d->usb->ep[id];
|
Ep *ep = d->usb->ep[id];
|
||||||
if(ep != nil && ep->conf != nil && ep->conf->cval == 1){
|
if(ep != nil
|
||||||
Dev *epd = openep(d, id);
|
&& ep->next == nil
|
||||||
|
&& ep->conf != nil
|
||||||
|
&& ep->conf->cval == 1
|
||||||
|
&& ep->iface->alt == 0){
|
||||||
|
Dev *epd = openep(d, ep);
|
||||||
if(epd != nil)
|
if(epd != nil)
|
||||||
closedev(epd);
|
closedev(epd);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue