1906943f9SDavid du Colombier typedef struct Altc Altc; 2906943f9SDavid du Colombier typedef struct Conf Conf; 3906943f9SDavid du Colombier typedef struct DConf DConf; 4906943f9SDavid du Colombier typedef struct DDesc DDesc; 5906943f9SDavid du Colombier typedef struct DDev DDev; 6906943f9SDavid du Colombier typedef struct DEp DEp; 7906943f9SDavid du Colombier typedef struct DIface DIface; 8906943f9SDavid du Colombier typedef struct Desc Desc; 9906943f9SDavid du Colombier typedef struct Dev Dev; 10906943f9SDavid du Colombier typedef struct Ep Ep; 11906943f9SDavid du Colombier typedef struct Iface Iface; 12906943f9SDavid du Colombier typedef struct Usbdev Usbdev; 137f0337cdSDavid du Colombier 1416146bc9SDavid du Colombier enum { 1517a7aae3SDavid du Colombier /* fundamental constants */ 1617a7aae3SDavid du Colombier Nep = 16, /* max. endpoints per usb device & per interface */ 1717a7aae3SDavid du Colombier 1816146bc9SDavid du Colombier /* tunable parameters */ 1916146bc9SDavid du Colombier Nconf = 16, /* max. configurations per usb device */ 2017a7aae3SDavid du Colombier Nddesc = 8*Nep, /* max. device-specific descriptors per usb device */ 2116146bc9SDavid du Colombier Niface = 16, /* max. interfaces per configuration */ 2239dc1420SDavid du Colombier Naltc = 16, /* max. alt configurations per interface */ 2316146bc9SDavid du Colombier Uctries = 4, /* no. of tries for usbcmd */ 24906943f9SDavid du Colombier Ucdelay = 50, /* delay before retrying */ 251b3e7169SDavid du Colombier 26906943f9SDavid du Colombier /* request type */ 27906943f9SDavid du Colombier Rh2d = 0<<7, /* host to device */ 28906943f9SDavid du Colombier Rd2h = 1<<7, /* device to host */ 29906943f9SDavid du Colombier 30906943f9SDavid du Colombier Rstd = 0<<5, /* types */ 317f0337cdSDavid du Colombier Rclass = 1<<5, 327f0337cdSDavid du Colombier Rvendor = 2<<5, 331b3e7169SDavid du Colombier 34906943f9SDavid du Colombier Rdev = 0, /* recipients */ 35906943f9SDavid du Colombier Riface = 1, 36906943f9SDavid du Colombier Rep = 2, /* endpoint */ 377f0337cdSDavid du Colombier Rother = 3, 387f0337cdSDavid du Colombier 397f0337cdSDavid du Colombier /* standard requests */ 40906943f9SDavid du Colombier Rgetstatus = 0, 41906943f9SDavid du Colombier Rclearfeature = 1, 42906943f9SDavid du Colombier Rsetfeature = 3, 43906943f9SDavid du Colombier Rsetaddress = 5, 44906943f9SDavid du Colombier Rgetdesc = 6, 45906943f9SDavid du Colombier Rsetdesc = 7, 46906943f9SDavid du Colombier Rgetconf = 8, 47906943f9SDavid du Colombier Rsetconf = 9, 48906943f9SDavid du Colombier Rgetiface = 10, 49906943f9SDavid du Colombier Rsetiface = 11, 50906943f9SDavid du Colombier Rsynchframe = 12, 517f0337cdSDavid du Colombier 52906943f9SDavid du Colombier Rgetcur = 0x81, 53906943f9SDavid du Colombier Rgetmin = 0x82, 54906943f9SDavid du Colombier Rgetmax = 0x83, 55906943f9SDavid du Colombier Rgetres = 0x84, 56906943f9SDavid du Colombier Rsetcur = 0x01, 57906943f9SDavid du Colombier Rsetmin = 0x02, 58906943f9SDavid du Colombier Rsetmax = 0x03, 59906943f9SDavid du Colombier Rsetres = 0x04, 607f0337cdSDavid du Colombier 61906943f9SDavid du Colombier /* dev classes */ 62906943f9SDavid du Colombier Clnone = 0, /* not in usb */ 63906943f9SDavid du Colombier Claudio = 1, 64906943f9SDavid du Colombier Clcomms = 2, 65906943f9SDavid du Colombier Clhid = 3, 66906943f9SDavid du Colombier Clprinter = 7, 67906943f9SDavid du Colombier Clstorage = 8, 68906943f9SDavid du Colombier Clhub = 9, 69906943f9SDavid du Colombier Cldata = 10, 70906943f9SDavid du Colombier 71906943f9SDavid du Colombier /* standard descriptor sizes */ 72906943f9SDavid du Colombier Ddevlen = 18, 73906943f9SDavid du Colombier Dconflen = 9, 74906943f9SDavid du Colombier Difacelen = 9, 75906943f9SDavid du Colombier Deplen = 7, 767f0337cdSDavid du Colombier 777f0337cdSDavid du Colombier /* descriptor types */ 78906943f9SDavid du Colombier Ddev = 1, 79906943f9SDavid du Colombier Dconf = 2, 80906943f9SDavid du Colombier Dstr = 3, 81906943f9SDavid du Colombier Diface = 4, 82906943f9SDavid du Colombier Dep = 5, 83906943f9SDavid du Colombier Dreport = 0x22, 84906943f9SDavid du Colombier Dfunction = 0x24, 85906943f9SDavid du Colombier Dphysical = 0x23, 867f0337cdSDavid du Colombier 877f0337cdSDavid du Colombier /* feature selectors */ 88906943f9SDavid du Colombier Fdevremotewakeup = 1, 89906943f9SDavid du Colombier Fhalt = 0, 90906943f9SDavid du Colombier 91906943f9SDavid du Colombier /* device state */ 92906943f9SDavid du Colombier Detached = 0, 93906943f9SDavid du Colombier Attached, 94906943f9SDavid du Colombier Enabled, 95906943f9SDavid du Colombier Assigned, 96906943f9SDavid du Colombier Configured, 97906943f9SDavid du Colombier 98906943f9SDavid du Colombier /* endpoint direction */ 99906943f9SDavid du Colombier Ein = 0, 100906943f9SDavid du Colombier Eout, 101906943f9SDavid du Colombier Eboth, 102906943f9SDavid du Colombier 103906943f9SDavid du Colombier /* endpoint type */ 104906943f9SDavid du Colombier Econtrol = 0, 105906943f9SDavid du Colombier Eiso = 1, 106906943f9SDavid du Colombier Ebulk = 2, 107906943f9SDavid du Colombier Eintr = 3, 108906943f9SDavid du Colombier 109906943f9SDavid du Colombier /* endpoint isotype */ 110906943f9SDavid du Colombier Eunknown = 0, 111906943f9SDavid du Colombier Easync = 1, 112906943f9SDavid du Colombier Eadapt = 2, 113906943f9SDavid du Colombier Esync = 3, 114906943f9SDavid du Colombier 115906943f9SDavid du Colombier /* config attrib */ 116906943f9SDavid du Colombier Cbuspowered = 1<<7, 117906943f9SDavid du Colombier Cselfpowered = 1<<6, 118906943f9SDavid du Colombier Cremotewakeup = 1<<5, 1197f0337cdSDavid du Colombier 1207f0337cdSDavid du Colombier /* report types */ 1217f0337cdSDavid du Colombier Tmtype = 3<<2, 1227f0337cdSDavid du Colombier Tmitem = 0xF0, 1237f0337cdSDavid du Colombier Tmain = 0<<2, 1247f0337cdSDavid du Colombier Tinput = 0x80, 1257f0337cdSDavid du Colombier Toutput = 0x90, 1267f0337cdSDavid du Colombier Tfeature = 0xB0, 1277f0337cdSDavid du Colombier Tcoll = 0xA0, 1287f0337cdSDavid du Colombier Tecoll = 0xC0, 1297f0337cdSDavid du Colombier Tglobal = 1<<2, 1307f0337cdSDavid du Colombier Tusagepage = 0x00, 1317f0337cdSDavid du Colombier Tlmin = 0x10, 1327f0337cdSDavid du Colombier Tlmax = 0x20, 1337f0337cdSDavid du Colombier Tpmin = 0x30, 1347f0337cdSDavid du Colombier Tpmax = 0x40, 1357f0337cdSDavid du Colombier Tunitexp = 0x50, 1367f0337cdSDavid du Colombier Tunit = 0x60, 1377f0337cdSDavid du Colombier Trepsize = 0x70, 1387f0337cdSDavid du Colombier TrepID = 0x80, 1397f0337cdSDavid du Colombier Trepcount = 0x90, 1407f0337cdSDavid du Colombier Tpush = 0xA0, 1417f0337cdSDavid du Colombier Tpop = 0xB0, 1427f0337cdSDavid du Colombier Tlocal = 2<<2, 1437f0337cdSDavid du Colombier Tusage = 0x00, 1447f0337cdSDavid du Colombier Tumin = 0x10, 1457f0337cdSDavid du Colombier Tumax = 0x20, 1467f0337cdSDavid du Colombier Tdindex = 0x30, 1477f0337cdSDavid du Colombier Tdmin = 0x40, 1487f0337cdSDavid du Colombier Tdmax = 0x50, 1497f0337cdSDavid du Colombier Tsindex = 0x70, 1507f0337cdSDavid du Colombier Tsmin = 0x80, 1517f0337cdSDavid du Colombier Tsmax = 0x90, 1527f0337cdSDavid du Colombier Tsetdelim = 0xA0, 1537f0337cdSDavid du Colombier Treserved = 3<<2, 1547f0337cdSDavid du Colombier Tlong = 0xFE, 1557f0337cdSDavid du Colombier 1567f0337cdSDavid du Colombier }; 1577f0337cdSDavid du Colombier 158906943f9SDavid du Colombier /* 159906943f9SDavid du Colombier * Usb device (when used for ep0s) or endpoint. 160906943f9SDavid du Colombier * RC: One ref because of existing, another one per ogoing I/O. 161906943f9SDavid du Colombier * per-driver resources (including FS if any) are released by aux 162906943f9SDavid du Colombier * once the last ref is gone. This may include other Devs using 163906943f9SDavid du Colombier * to access endpoints for actual I/O. 164906943f9SDavid du Colombier */ 165906943f9SDavid du Colombier struct Dev 1667f0337cdSDavid du Colombier { 167906943f9SDavid du Colombier Ref; 168906943f9SDavid du Colombier char* dir; /* path for the endpoint dir */ 169906943f9SDavid du Colombier int id; /* usb id for device or ep. number */ 170906943f9SDavid du Colombier int dfd; /* descriptor for the data file */ 171906943f9SDavid du Colombier int cfd; /* descriptor for the control file */ 172906943f9SDavid du Colombier int maxpkt; /* cached from usb description */ 173906943f9SDavid du Colombier Ref nerrs; /* number of errors in requests */ 174906943f9SDavid du Colombier Usbdev* usb; /* USB description */ 175906943f9SDavid du Colombier void* aux; /* for the device driver */ 176906943f9SDavid du Colombier void (*free)(void*); /* idem. to release aux */ 1777f0337cdSDavid du Colombier }; 1787f0337cdSDavid du Colombier 179906943f9SDavid du Colombier /* 180906943f9SDavid du Colombier * device description as reported by USB (unpacked). 181906943f9SDavid du Colombier */ 182906943f9SDavid du Colombier struct Usbdev 1837f0337cdSDavid du Colombier { 184906943f9SDavid du Colombier ulong csp; /* USB class/subclass/proto */ 185906943f9SDavid du Colombier int vid; /* vendor id */ 186906943f9SDavid du Colombier int did; /* product (device) id */ 187*80e9508eSDavid du Colombier int dno; /* device release number */ 188906943f9SDavid du Colombier char* vendor; 189906943f9SDavid du Colombier char* product; 190906943f9SDavid du Colombier char* serial; 191906943f9SDavid du Colombier int vsid; 192906943f9SDavid du Colombier int psid; 193906943f9SDavid du Colombier int ssid; 194906943f9SDavid du Colombier int class; /* from descriptor */ 195906943f9SDavid du Colombier int nconf; /* from descriptor */ 196906943f9SDavid du Colombier Conf* conf[Nconf]; /* configurations */ 197906943f9SDavid du Colombier Ep* ep[Nep]; /* all endpoints in device */ 198906943f9SDavid du Colombier Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */ 199906943f9SDavid du Colombier }; 200906943f9SDavid du Colombier 201906943f9SDavid du Colombier struct Ep 202906943f9SDavid du Colombier { 203906943f9SDavid du Colombier uchar addr; /* endpt address, 0-15 (|0x80 if Ein) */ 20415174232SDavid du Colombier uchar dir; /* direction, Ein/Eout */ 20515174232SDavid du Colombier uchar type; /* Econtrol, Eiso, Ebulk, Eintr */ 20615174232SDavid du Colombier uchar isotype; /* Eunknown, Easync, Eadapt, Esync */ 2077f0337cdSDavid du Colombier int id; 208906943f9SDavid du Colombier int maxpkt; /* max. packet size */ 209906943f9SDavid du Colombier int ntds; /* nb. of Tds per µframe */ 210906943f9SDavid du Colombier Conf* conf; /* the endpoint belongs to */ 211906943f9SDavid du Colombier Iface* iface; /* the endpoint belongs to */ 2127f0337cdSDavid du Colombier }; 2137f0337cdSDavid du Colombier 214906943f9SDavid du Colombier struct Altc 2157f0337cdSDavid du Colombier { 2167f0337cdSDavid du Colombier int attrib; 2177f0337cdSDavid du Colombier int interval; 218906943f9SDavid du Colombier void* aux; /* for the driver program */ 2197f0337cdSDavid du Colombier }; 2207f0337cdSDavid du Colombier 221906943f9SDavid du Colombier struct Iface 2227f0337cdSDavid du Colombier { 223906943f9SDavid du Colombier int id; /* interface number */ 2247f0337cdSDavid du Colombier ulong csp; /* USB class/subclass/proto */ 225906943f9SDavid du Colombier Altc* altc[Naltc]; 226906943f9SDavid du Colombier Ep* ep[Nep]; 227906943f9SDavid du Colombier void* aux; /* for the driver program */ 2287f0337cdSDavid du Colombier }; 2297f0337cdSDavid du Colombier 230906943f9SDavid du Colombier struct Conf 2317f0337cdSDavid du Colombier { 2327f0337cdSDavid du Colombier int cval; /* value for set configuration */ 2337f0337cdSDavid du Colombier int attrib; 234906943f9SDavid du Colombier int milliamps; /* maximum power in this config. */ 23516146bc9SDavid du Colombier Iface* iface[Niface]; 2367f0337cdSDavid du Colombier }; 2377f0337cdSDavid du Colombier 238906943f9SDavid du Colombier /* 239906943f9SDavid du Colombier * Device-specific descriptors. 240906943f9SDavid du Colombier * They show up mixed with other descriptors 241906943f9SDavid du Colombier * within a configuration. 242906943f9SDavid du Colombier * These are unknown to the library but handed to the driver. 243906943f9SDavid du Colombier */ 24442704577SDavid du Colombier struct DDesc 24542704577SDavid du Colombier { 24642704577SDavid du Colombier uchar bLength; 24742704577SDavid du Colombier uchar bDescriptorType; 24842704577SDavid du Colombier uchar bbytes[1]; 24942704577SDavid du Colombier /* extra bytes allocated here to keep the rest of it */ 25042704577SDavid du Colombier }; 25142704577SDavid du Colombier 252906943f9SDavid du Colombier struct Desc 2537f0337cdSDavid du Colombier { 254906943f9SDavid du Colombier Conf* conf; /* where this descriptor was read */ 255906943f9SDavid du Colombier Iface* iface; /* last iface before desc in conf. */ 256906943f9SDavid du Colombier Ep* ep; /* last endpt before desc in conf. */ 257906943f9SDavid du Colombier Altc* altc; /* last alt.c. before desc in conf. */ 258906943f9SDavid du Colombier DDesc data; /* unparsed standard USB descriptor */ 2599a747e4fSDavid du Colombier }; 2609a747e4fSDavid du Colombier 2617f0337cdSDavid du Colombier /* 2627f0337cdSDavid du Colombier * layout of standard descriptor types 2637f0337cdSDavid du Colombier */ 264906943f9SDavid du Colombier struct DDev 2657f0337cdSDavid du Colombier { 266906943f9SDavid du Colombier uchar bLength; 267906943f9SDavid du Colombier uchar bDescriptorType; 268906943f9SDavid du Colombier uchar bcdUSB[2]; 269906943f9SDavid du Colombier uchar bDevClass; 270906943f9SDavid du Colombier uchar bDevSubClass; 271906943f9SDavid du Colombier uchar bDevProtocol; 272906943f9SDavid du Colombier uchar bMaxPacketSize0; 273906943f9SDavid du Colombier uchar idVendor[2]; 274906943f9SDavid du Colombier uchar idProduct[2]; 275906943f9SDavid du Colombier uchar bcdDev[2]; 276906943f9SDavid du Colombier uchar iManufacturer; 277906943f9SDavid du Colombier uchar iProduct; 278906943f9SDavid du Colombier uchar iSerialNumber; 279906943f9SDavid du Colombier uchar bNumConfigurations; 2807f0337cdSDavid du Colombier }; 2817f0337cdSDavid du Colombier 282906943f9SDavid du Colombier struct DConf 2837f0337cdSDavid du Colombier { 284906943f9SDavid du Colombier uchar bLength; 285906943f9SDavid du Colombier uchar bDescriptorType; 286906943f9SDavid du Colombier uchar wTotalLength[2]; 287906943f9SDavid du Colombier uchar bNumInterfaces; 288906943f9SDavid du Colombier uchar bConfigurationValue; 289906943f9SDavid du Colombier uchar iConfiguration; 290906943f9SDavid du Colombier uchar bmAttributes; 291906943f9SDavid du Colombier uchar MaxPower; 292906943f9SDavid du Colombier }; 293906943f9SDavid du Colombier 294906943f9SDavid du Colombier struct DIface 295906943f9SDavid du Colombier { 296906943f9SDavid du Colombier uchar bLength; 297906943f9SDavid du Colombier uchar bDescriptorType; 298906943f9SDavid du Colombier uchar bInterfaceNumber; 299906943f9SDavid du Colombier uchar bAlternateSetting; 300906943f9SDavid du Colombier uchar bNumEndpoints; 301906943f9SDavid du Colombier uchar bInterfaceClass; 302906943f9SDavid du Colombier uchar bInterfaceSubClass; 303906943f9SDavid du Colombier uchar bInterfaceProtocol; 304906943f9SDavid du Colombier uchar iInterface; 305906943f9SDavid du Colombier }; 306906943f9SDavid du Colombier 307906943f9SDavid du Colombier struct DEp 308906943f9SDavid du Colombier { 309906943f9SDavid du Colombier uchar bLength; 310906943f9SDavid du Colombier uchar bDescriptorType; 311906943f9SDavid du Colombier uchar bEndpointAddress; 312906943f9SDavid du Colombier uchar bmAttributes; 313906943f9SDavid du Colombier uchar wMaxPacketSize[2]; 314906943f9SDavid du Colombier uchar bInterval; 315906943f9SDavid du Colombier }; 3167f0337cdSDavid du Colombier 3179a747e4fSDavid du Colombier #define Class(csp) ((csp) & 0xff) 3189a747e4fSDavid du Colombier #define Subclass(csp) (((csp)>>8) & 0xff) 3199a747e4fSDavid du Colombier #define Proto(csp) (((csp)>>16) & 0xff) 32016146bc9SDavid du Colombier #define CSP(c, s, p) ((c) | (s)<<8 | (p)<<16) 32116146bc9SDavid du Colombier 32216146bc9SDavid du Colombier #define GET2(p) (((p)[1] & 0xFF)<<8 | ((p)[0] & 0xFF)) 32316146bc9SDavid du Colombier #define PUT2(p,v) {(p)[0] = (v); (p)[1] = (v)>>8;} 32416146bc9SDavid du Colombier #define GET4(p) (((p)[3]&0xFF)<<24 | ((p)[2]&0xFF)<<16 | \ 32516146bc9SDavid du Colombier ((p)[1]&0xFF)<<8 | ((p)[0]&0xFF)) 32616146bc9SDavid du Colombier #define PUT4(p,v) {(p)[0] = (v); (p)[1] = (v)>>8; \ 32716146bc9SDavid du Colombier (p)[2] = (v)>>16; (p)[3] = (v)>>24;} 32816146bc9SDavid du Colombier 329906943f9SDavid du Colombier #define dprint if(usbdebug)fprint 330906943f9SDavid du Colombier #define ddprint if(usbdebug > 1)fprint 3319a747e4fSDavid du Colombier 332906943f9SDavid du Colombier #pragma varargck type "U" Dev* 333906943f9SDavid du Colombier #pragma varargck argpos devctl 2 3349a747e4fSDavid du Colombier 335906943f9SDavid du Colombier int Ufmt(Fmt *f); 336906943f9SDavid du Colombier char* classname(int c); 337906943f9SDavid du Colombier void closedev(Dev *d); 338906943f9SDavid du Colombier int configdev(Dev *d); 339906943f9SDavid du Colombier int devctl(Dev *dev, char *fmt, ...); 340906943f9SDavid du Colombier void* emallocz(ulong size, int zero); 341906943f9SDavid du Colombier char* estrdup(char *s); 342906943f9SDavid du Colombier int matchdevcsp(char *info, void *a); 343906943f9SDavid du Colombier int finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs); 344906943f9SDavid du Colombier char* hexstr(void *a, int n); 345906943f9SDavid du Colombier int loaddevconf(Dev *d, int n); 346906943f9SDavid du Colombier int loaddevdesc(Dev *d); 347906943f9SDavid du Colombier char* loaddevstr(Dev *d, int sid); 348906943f9SDavid du Colombier Dev* opendev(char *fn); 349906943f9SDavid du Colombier int opendevdata(Dev *d, int mode); 350906943f9SDavid du Colombier Dev* openep(Dev *d, int id); 351906943f9SDavid du Colombier int parseconf(Usbdev *d, Conf *c, uchar *b, int n); 352906943f9SDavid du Colombier int parsedesc(Usbdev *d, Conf *c, uchar *b, int n); 353906943f9SDavid du Colombier int parsedev(Dev *xd, uchar *b, int n); 354906943f9SDavid du Colombier void startdevs(char *args, char *argv[], int argc, int (*mf)(char*,void*), void*ma, int (*df)(Dev*,int,char**)); 355906943f9SDavid du Colombier int unstall(Dev *dev, Dev *ep, int dir); 356906943f9SDavid du Colombier int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count); 3577f0337cdSDavid du Colombier 358906943f9SDavid du Colombier 359906943f9SDavid du Colombier extern int usbdebug; /* more messages for bigger values */ 360906943f9SDavid du Colombier 361906943f9SDavid du Colombier 362