Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <thread.h>
4
#include <bio.h>
5
#include "usb.h"
6
 
7
int
8
parsedev(Dev *xd, uchar *b, int n)
9
{
10
	Usbdev *d;
11
	DDev *dd;
12
	char *hd;
13
 
14
	d = xd->usb;
15
	assert(d != nil);
16
	dd = (DDev*)b;
17
	if(usbdebug>1){
18
		hd = hexstr(b, Ddevlen);
19
		fprint(2, "%s: parsedev %s: %s\n", argv0, xd->dir, hd);
20
		free(hd);
21
	}
22
	if(dd->bLength < Ddevlen){
23
		werrstr("short dev descr. (%d < %d)", dd->bLength, Ddevlen);
24
		return -1;
25
	}
26
	if(dd->bDescriptorType != Ddev){
27
		werrstr("%d is not a dev descriptor", dd->bDescriptorType);
28
		return -1;
29
	}
30
	d->csp = CSP(dd->bDevClass, dd->bDevSubClass, dd->bDevProtocol);
31
	d->ep[0]->maxpkt = xd->maxpkt = dd->bMaxPacketSize0;
32
	d->class = dd->bDevClass;
33
	d->nconf = dd->bNumConfigurations;
34
	if(d->nconf == 0)
35
		dprint(2, "%s: %s: no configurations\n", argv0, xd->dir);
36
	d->vid = GET2(dd->idVendor);
37
	d->did = GET2(dd->idProduct);
38
	d->dno = GET2(dd->bcdDev);
39
	d->vsid = dd->iManufacturer;
40
	d->psid = dd->iProduct;
41
	d->ssid = dd->iSerialNumber;
42
	if(n > Ddevlen && usbdebug>1)
43
		fprint(2, "%s: %s: parsedev: %d bytes left",
44
			argv0, xd->dir, n - Ddevlen);
45
	return Ddevlen;
46
}
47
 
48
static int
49
parseiface(Usbdev *d, Conf *c, uchar *b, int n, Iface **ipp, Altc **app)
50
{
51
	int class, subclass, proto;
52
	int ifid, altid;
53
	DIface *dip;
54
	Iface *ip;
55
 
56
	assert(d != nil && c != nil);
57
	if(n < Difacelen){
58
		werrstr("short interface descriptor");
59
		return -1;
60
	}
61
	dip = (DIface *)b;
62
	ifid = dip->bInterfaceNumber;
63
	if(ifid < 0 || ifid >= nelem(c->iface)){
64
		werrstr("bad interface number %d", ifid);
65
		return -1;
66
	}
67
	if(c->iface[ifid] == nil)
68
		c->iface[ifid] = emallocz(sizeof(Iface), 1);
69
	ip = c->iface[ifid];
70
	class = dip->bInterfaceClass;
71
	subclass = dip->bInterfaceSubClass;
72
	proto = dip->bInterfaceProtocol;
73
	ip->csp = CSP(class, subclass, proto);
74
	if(d->csp == 0)				/* use csp from 1st iface */
75
		d->csp = ip->csp;		/* if device has none */
76
	if(d->class == 0)
77
		d->class = class;
78
	ip->id = ifid;
79
	if(c == d->conf[0] && ifid == 0)	/* ep0 was already there */
80
		d->ep[0]->iface = ip;
81
	altid = dip->bAlternateSetting;
82
	if(altid < 0 || altid >= nelem(ip->altc)){
83
		werrstr("bad alternate conf. number %d", altid);
84
		return -1;
85
	}
86
	if(ip->altc[altid] == nil)
87
		ip->altc[altid] = emallocz(sizeof(Altc), 1);
88
	*ipp = ip;
89
	*app = ip->altc[altid];
90
	return Difacelen;
91
}
92
 
93
extern Ep* mkep(Usbdev *, int);
94
 
95
static int
96
parseendpt(Usbdev *d, Conf *c, Iface *ip, Altc *altc, uchar *b, int n, Ep **epp)
97
{
98
	int i, dir, epid;
99
	Ep *ep;
100
	DEp *dep;
101
 
102
	assert(d != nil && c != nil && ip != nil && altc != nil);
103
	if(n < Deplen){
104
		werrstr("short endpoint descriptor");
105
		return -1;
106
	}
107
	dep = (DEp *)b;
108
	altc->attrib = dep->bmAttributes;	/* here? */
109
	altc->interval = dep->bInterval;
110
 
111
	epid = dep->bEndpointAddress & 0xF;
112
	assert(epid < nelem(d->ep));
113
	if(dep->bEndpointAddress & 0x80)
114
		dir = Ein;
115
	else
116
		dir = Eout;
117
	ep = d->ep[epid];
118
	if(ep == nil){
119
		ep = mkep(d, epid);
120
		ep->dir = dir;
121
	}else if((ep->addr & 0x80) != (dep->bEndpointAddress & 0x80))
122
		ep->dir = Eboth;
123
	ep->maxpkt = GET2(dep->wMaxPacketSize);
124
	ep->ntds = 1 + ((ep->maxpkt >> 11) & 3);
125
	ep->maxpkt &= 0x7FF;
126
	ep->addr = dep->bEndpointAddress;
127
	ep->type = dep->bmAttributes & 0x03;
128
	ep->isotype = (dep->bmAttributes>>2) & 0x03;
129
	ep->conf = c;
130
	ep->iface = ip;
131
	for(i = 0; i < nelem(ip->ep); i++)
132
		if(ip->ep[i] == nil)
133
			break;
134
	if(i == nelem(ip->ep)){
135
		werrstr("parseendpt: bug: too many end points on interface "
136
			"with csp %#lux", ip->csp);
137
		fprint(2, "%s: %r\n", argv0);
138
		return -1;
139
	}
140
	*epp = ip->ep[i] = ep;
141
	return Dep;
142
}
143
 
144
static char*
145
dname(int dtype)
146
{
147
	switch(dtype){
148
	case Ddev:	return "device";
149
	case Dconf: 	return "config";
150
	case Dstr: 	return "string";
151
	case Diface:	return "interface";
152
	case Dep:	return "endpoint";
153
	case Dreport:	return "report";
154
	case Dphysical:	return "phys";
155
	default:	return "desc";
156
	}
157
}
158
 
159
int
160
parsedesc(Usbdev *d, Conf *c, uchar *b, int n)
161
{
162
	int	len, nd, tot;
163
	Iface	*ip;
164
	Ep 	*ep;
165
	Altc	*altc;
166
	char	*hd;
167
 
168
	assert(d != nil && c != nil);
169
	tot = 0;
170
	ip = nil;
171
	ep = nil;
172
	altc = nil;
173
	for(nd = 0; nd < nelem(d->ddesc); nd++)
174
		if(d->ddesc[nd] == nil)
175
			break;
176
 
177
	while(n > 2 && b[0] != 0 && b[0] <= n){
178
		len = b[0];
179
		if(usbdebug>1){
180
			hd = hexstr(b, len);
181
			fprint(2, "%s:\t\tparsedesc %s %x[%d] %s\n",
182
				argv0, dname(b[1]), b[1], b[0], hd);
183
			free(hd);
184
		}
185
		switch(b[1]){
186
		case Ddev:
187
		case Dconf:
188
			werrstr("unexpected descriptor %d", b[1]);
189
			ddprint(2, "%s\tparsedesc: %r", argv0);
190
			break;
191
		case Diface:
192
			if(parseiface(d, c, b, n, &ip, &altc) < 0){
193
				ddprint(2, "%s\tparsedesc: %r\n", argv0);
194
				return -1;
195
			}
196
			break;
197
		case Dep:
198
			if(ip == nil || altc == nil){
199
				werrstr("unexpected endpoint descriptor");
200
				break;
201
			}
202
			if(parseendpt(d, c, ip, altc, b, n, &ep) < 0){
203
				ddprint(2, "%s\tparsedesc: %r\n", argv0);
204
				return -1;
205
			}
206
			break;
207
		default:
208
			if(nd == nelem(d->ddesc)){
209
				fprint(2, "%s: parsedesc: too many "
210
					"device-specific descriptors for device"
211
					" %s %s\n",
212
					argv0, d->vendor, d->product);
213
				break;
214
			}
215
			d->ddesc[nd] = emallocz(sizeof(Desc)+b[0], 0);
216
			d->ddesc[nd]->iface = ip;
217
			d->ddesc[nd]->ep = ep;
218
			d->ddesc[nd]->altc = altc;
219
			d->ddesc[nd]->conf = c;
220
			memmove(&d->ddesc[nd]->data, b, len);
221
			++nd;
222
		}
223
		n -= len;
224
		b += len;
225
		tot += len;
226
	}
227
	return tot;
228
}
229
 
230
int
231
parseconf(Usbdev *d, Conf *c, uchar *b, int n)
232
{
233
	DConf* dc;
234
	int	l;
235
	int	nr;
236
	char	*hd;
237
 
238
	assert(d != nil && c != nil);
239
	dc = (DConf*)b;
240
	if(usbdebug>1){
241
		hd = hexstr(b, Dconflen);
242
		fprint(2, "%s:\tparseconf  %s\n", argv0, hd);
243
		free(hd);
244
	}
245
	if(dc->bLength < Dconflen){
246
		werrstr("short configuration descriptor");
247
		return -1;
248
	}
249
	if(dc->bDescriptorType != Dconf){
250
		werrstr("not a configuration descriptor");
251
		return -1;
252
	}
253
	c->cval = dc->bConfigurationValue;
254
	c->attrib = dc->bmAttributes;
255
	c->milliamps = dc->MaxPower*2;
256
	l = GET2(dc->wTotalLength);
257
	if(n < l){
258
		werrstr("truncated configuration info");
259
		return -1;
260
	}
261
	n -= Dconflen;
262
	b += Dconflen;
263
	nr = 0;
264
	if(n > 0 && (nr=parsedesc(d, c, b, n)) < 0)
265
		return -1;
266
	n -= nr;
267
	if(n > 0 && usbdebug>1)
268
		fprint(2, "%s:\tparseconf: %d bytes left\n", argv0, n);
269
	return l;
270
}