1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
|
typedef struct Altc Altc;
typedef struct Conf Conf;
typedef struct DConf DConf;
typedef struct DDesc DDesc;
typedef struct DDev DDev;
typedef struct DEp DEp;
typedef struct DIface DIface;
typedef struct Desc Desc;
typedef struct Dev Dev;
typedef struct Ep Ep;
typedef struct Iface Iface;
typedef struct Usbdev Usbdev;
enum {
/* fundamental constants */
Nep = 256, /* max. endpoints per usb device & per interface */
/* tunable parameters */
Nconf = 16, /* max. configurations per usb device */
Nddesc = 8*Nep, /* max. device-specific descriptors per usb device */
Niface = 16, /* max. interfaces per configuration */
Naltc = 256, /* max. alt configurations per interface */
Uctries = 4, /* no. of tries for usbcmd */
Ucdelay = 50, /* delay before retrying */
/* request type */
Rh2d = 0<<7, /* host to device */
Rd2h = 1<<7, /* device to host */
Rstd = 0<<5, /* types */
Rclass = 1<<5,
Rvendor = 2<<5,
Rdev = 0, /* recipients */
Riface = 1,
Rep = 2, /* endpoint */
Rother = 3,
/* standard requests */
Rgetstatus = 0,
Rclearfeature = 1,
Rsetfeature = 3,
Rsetaddress = 5,
Rgetdesc = 6,
Rsetdesc = 7,
Rgetconf = 8,
Rsetconf = 9,
Rgetiface = 10,
Rsetiface = 11,
Rsynchframe = 12,
Rgetcur = 0x81,
Rgetmin = 0x82,
Rgetmax = 0x83,
Rgetres = 0x84,
Rsetcur = 0x01,
Rsetmin = 0x02,
Rsetmax = 0x03,
Rsetres = 0x04,
/* dev classes */
Clnone = 0, /* not in usb */
Claudio = 1,
Clcomms = 2,
Clhid = 3,
Clprinter = 7,
Clstorage = 8,
Clhub = 9,
Cldata = 10,
/* standard descriptor sizes */
Ddevlen = 18,
Dconflen = 9,
Difacelen = 9,
Deplen = 7,
/* descriptor types */
Ddev = 1,
Dconf = 2,
Dstr = 3,
Diface = 4,
Dep = 5,
Dreport = 0x22,
Dfunction = 0x24,
Dphysical = 0x23,
/* feature selectors */
Fdevremotewakeup = 1,
Fhalt = 0,
/* device state */
Detached = 0,
Attached,
Enabled,
Assigned,
Configured,
/* endpoint direction */
Ein = 0,
Eout,
Eboth,
/* endpoint type */
Econtrol = 0,
Eiso = 1,
Ebulk = 2,
Eintr = 3,
/* endpoint isotype */
Eunknown = 0,
Easync = 1,
Eadapt = 2,
Esync = 3,
/* config attrib */
Cbuspowered = 1<<7,
Cselfpowered = 1<<6,
Cremotewakeup = 1<<5,
/* report types */
Tmtype = 3<<2,
Tmitem = 0xF0,
Tmain = 0<<2,
Tinput = 0x80,
Toutput = 0x90,
Tfeature = 0xB0,
Tcoll = 0xA0,
Tecoll = 0xC0,
Tglobal = 1<<2,
Tusagepage = 0x00,
Tlmin = 0x10,
Tlmax = 0x20,
Tpmin = 0x30,
Tpmax = 0x40,
Tunitexp = 0x50,
Tunit = 0x60,
Trepsize = 0x70,
TrepID = 0x80,
Trepcount = 0x90,
Tpush = 0xA0,
Tpop = 0xB0,
Tlocal = 2<<2,
Tusage = 0x00,
Tumin = 0x10,
Tumax = 0x20,
Tdindex = 0x30,
Tdmin = 0x40,
Tdmax = 0x50,
Tsindex = 0x70,
Tsmin = 0x80,
Tsmax = 0x90,
Tsetdelim = 0xA0,
Treserved = 3<<2,
Tlong = 0xFE,
};
/*
* Usb device (when used for ep0s) or endpoint.
* RC: One ref because of existing, another one per ogoing I/O.
* per-driver resources (including FS if any) are released by aux
* once the last ref is gone. This may include other Devs using
* to access endpoints for actual I/O.
*/
struct Dev
{
Ref;
char* dir; /* path for the endpoint dir */
int id; /* usb id for device or ep. number */
int dfd; /* descriptor for the data file */
int cfd; /* descriptor for the control file */
int maxpkt; /* cached from usb description */
Ref nerrs; /* number of errors in requests */
Usbdev* usb; /* USB description */
void* aux; /* for the device driver */
void (*free)(void*); /* idem. to release aux */
char* hname; /* hash name, uniqueue for device */
};
/*
* device description as reported by USB (unpacked).
*/
struct Usbdev
{
ulong csp; /* USB class/subclass/proto */
int vid; /* vendor id */
int did; /* product (device) id */
int dno; /* device release number */
char* vendor;
char* product;
char* serial;
int vsid;
int psid;
int ssid;
int class; /* from descriptor */
int nconf; /* from descriptor */
Conf* conf[Nconf]; /* configurations */
Ep* ep[Nep]; /* all endpoints in device */
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
};
struct Ep
{
uchar addr; /* endpt address, 0-15 (|0x80 if Ein) */
uchar dir; /* direction, Ein/Eout */
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
uchar isotype; /* Eunknown, Easync, Eadapt, Esync */
int id;
int maxpkt; /* max. packet size */
int ntds; /* nb. of Tds per µframe */
Conf* conf; /* the endpoint belongs to */
Iface* iface; /* the endpoint belongs to */
};
struct Altc
{
int attrib;
int interval;
void* aux; /* for the driver program */
};
struct Iface
{
int id; /* interface number */
ulong csp; /* USB class/subclass/proto */
Altc* altc[Naltc];
Ep* ep[Nep];
void* aux; /* for the driver program */
};
struct Conf
{
int cval; /* value for set configuration */
int attrib;
int milliamps; /* maximum power in this config. */
Iface* iface[Niface];
};
/*
* Device-specific descriptors.
* They show up mixed with other descriptors
* within a configuration.
* These are unknown to the library but handed to the driver.
*/
struct DDesc
{
uchar bLength;
uchar bDescriptorType;
uchar bbytes[1];
/* extra bytes allocated here to keep the rest of it */
};
struct Desc
{
Conf* conf; /* where this descriptor was read */
Iface* iface; /* last iface before desc in conf. */
Ep* ep; /* last endpt before desc in conf. */
Altc* altc; /* last alt.c. before desc in conf. */
DDesc data; /* unparsed standard USB descriptor */
};
/*
* layout of standard descriptor types
*/
struct DDev
{
uchar bLength;
uchar bDescriptorType;
uchar bcdUSB[2];
uchar bDevClass;
uchar bDevSubClass;
uchar bDevProtocol;
uchar bMaxPacketSize0;
uchar idVendor[2];
uchar idProduct[2];
uchar bcdDev[2];
uchar iManufacturer;
uchar iProduct;
uchar iSerialNumber;
uchar bNumConfigurations;
};
struct DConf
{
uchar bLength;
uchar bDescriptorType;
uchar wTotalLength[2];
uchar bNumInterfaces;
uchar bConfigurationValue;
uchar iConfiguration;
uchar bmAttributes;
uchar MaxPower;
};
struct DIface
{
uchar bLength;
uchar bDescriptorType;
uchar bInterfaceNumber;
uchar bAlternateSetting;
uchar bNumEndpoints;
uchar bInterfaceClass;
uchar bInterfaceSubClass;
uchar bInterfaceProtocol;
uchar iInterface;
};
struct DEp
{
uchar bLength;
uchar bDescriptorType;
uchar bEndpointAddress;
uchar bmAttributes;
uchar wMaxPacketSize[2];
uchar bInterval;
};
#define Class(csp) ((csp) & 0xff)
#define Subclass(csp) (((csp)>>8) & 0xff)
#define Proto(csp) (((csp)>>16) & 0xff)
#define CSP(c, s, p) ((c) | (s)<<8 | (p)<<16)
#define GET2(p) (((p)[1] & 0xFF)<<8 | ((p)[0] & 0xFF))
#define PUT2(p,v) {(p)[0] = (v); (p)[1] = (v)>>8;}
#define GET4(p) (((p)[3]&0xFF)<<24 | ((p)[2]&0xFF)<<16 | \
((p)[1]&0xFF)<<8 | ((p)[0]&0xFF))
#define PUT4(p,v) {(p)[0] = (v); (p)[1] = (v)>>8; \
(p)[2] = (v)>>16; (p)[3] = (v)>>24;}
#define dprint if(usbdebug)fprint
#define ddprint if(usbdebug > 1)fprint
#pragma varargck type "U" Dev*
#pragma varargck argpos devctl 2
int Ufmt(Fmt *f);
char* classname(int c);
void closedev(Dev *d);
int configdev(Dev *d);
int devctl(Dev *dev, char *fmt, ...);
void* emallocz(ulong size, int zero);
char* estrdup(char *s);
char* hexstr(void *a, int n);
int loaddevconf(Dev *d, int n);
int loaddevdesc(Dev *d);
char* loaddevstr(Dev *d, int sid);
Dev* opendev(char *fn);
int opendevdata(Dev *d, int mode);
Dev* openep(Dev *d, int id);
int parseconf(Usbdev *d, Conf *c, uchar *b, int n);
int parsedesc(Usbdev *d, Conf *c, uchar *b, int n);
int parsedev(Dev *xd, uchar *b, int n);
int unstall(Dev *dev, Dev *ep, int dir);
int usbcmd(Dev *d, int type, int req, int value, int index, uchar *data, int count);
Dev* getdev(char *devid);
extern int usbdebug; /* more messages for bigger values */
|