henesyinit from p9fd787fda5 years agoHistory
288 lines · 6.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include "usb.h"#include "usbproto.h" static int	loadconfig(Device *d, int n);static int	checkep(Dalt*, Endpt*);static void	adddesc(Ddesc*, uchar*);static void	dumplangids(Device*); intdescribedevice(Device *d){	int i, nr;	DDevice *dd;	uchar buf[1023]; 	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (DEVICE<<8)|0, 0, buf, sizeof(buf));	if(nr < 0) {		werrstr("describedevice: %r");		return -1;	}	if(nr < DDEVLEN) {		werrstr("describedevice: short device descriptor (%d < %d)", nr, DDEVLEN);		return -1;	}	dd = (DDevice*)buf;	if(dd->bDescriptorType != DEVICE || dd->bLength < DDEVLEN) {		werrstr("describedevice: bogus device descriptor");		return -1;	}	d->vers = GET2(dd->bcdUSB);	d->csp = CSP(dd->bDeviceClass, dd->bDeviceSubClass, dd->bDeviceProtocol);	d->max0 = dd->bMaxPacketSize0;	d->vid = GET2(dd->idVendor);	d->did = GET2(dd->idProduct);	d->release = GET2(dd->bcdDevice);	d->manufacturer = dd->iManufacturer;	d->product = dd->iProduct;	d->serial = dd->iSerialNumber;	d->nconf = dd->bNumConfigurations; 	/* read all configurations */	if(d->config != nil)		free(d->config);	d->config = emallocz(d->nconf*sizeof(Dconf), 1);	for(i = 0; i < d->nconf; i++)		if(loadconfig(d, i) < 0)			return -1;	return 0;} static uchar type[] ={	[0]	Econtrol,	[1]	Eiso,	[2]	Ebulk,	[3]	Eintr,}; static uchar isotype[] ={	[0]	Eunknown,	[1]	Easync,	[2]	Eadapt,	[3]	Esync,}; static intloadconfig(Device *d, int n){	int i, nr;	Dconf *c;	Dinf *intf;	Endpt *ep;	DConfig *dc;	Ddesc *desc;	DInterface *di;	Dalt *alt, **alttail;	DEndpoint *dep;	uchar buf[1023], *p, *ebuf; 	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (CONFIGURATION<<8)|n, 0, buf, sizeof(buf));	if(nr < 0) {		werrstr("loadconfig: %r");		return -1;	}	if(nr < DCONFLEN) {		werrstr("loadconfig: short configuration descriptor (%d < %d)", nr, 2);		return -1;	}	dc = (DConfig*)buf;	if(dc->bDescriptorType != CONFIGURATION || dc->bLength < DCONFLEN) {		werrstr("describedevice: bogus configuration descriptor");		return -1;	}	if(GET2(dc->wTotalLength) != nr) {		werrstr("describedevice: configuration descriptor length mismatch");		return -1;	}	c = &d->config[n];	c->d = d;	c->x = n;	c->nif = dc->bNumInterfaces;	c->cval = dc->bConfigurationValue;	c->config = dc->iConfiguration;	c->attrib = dc->bmAttributes;	c->milliamps = dc->MaxPower*2;		/* 2mA units */ 	c->iface = emallocz(c->nif*sizeof(Dinf), 1);	for(i = 0; i < c->nif; i++) {		intf = &c->iface[i];		intf->d = d;		intf->conf = c;		intf->x = i;	}	alttail = emallocz(c->nif*sizeof(Dalt*), 1);	alt = nil;	ep = nil; 	p = buf+dc->bLength;	ebuf = buf+nr;	while(p < ebuf) {		if(p+p[0] > ebuf) {			werrstr("truncated descriptor in loadconfig");			goto error;		}		switch(p[1]) {		case DEVICE:		case CONFIGURATION:			werrstr("illegal descriptor in loadconfig: %x", p[1]);			goto error;		case INTERFACE:			if(checkep(alt, ep) < 0)				goto error;			di = (DInterface*)p;			i = di->bInterfaceNumber;			if(i >= c->nif) {				werrstr("interface number out of bounds");				goto error;			}			intf = &c->iface[i];			alt = mallocz(sizeof(Dalt), 1);			alt->intf = intf;			alt->alt = di->bAlternateSetting;			alt->npt = di->bNumEndpoints;			alt->ep = emallocz(alt->npt*sizeof(Endpt), 1);			alt->next = nil;			if(alttail[i] == nil) {				intf->alt = alt;				intf->csp = CSP(di->bInterfaceClass, di->bInterfaceSubClass, di->bInterfaceProtocol);				intf->interface = di->iInterface;			}			else				alttail[i]->next = alt;			alttail[i] = alt;			ep = nil;			break;		case ENDPOINT:			if(alt == nil) {				werrstr("endpoint descriptor without interface");				goto error;			}			if(ep == nil)				ep = &alt->ep[0];			else {				ep++;				if(ep - alt->ep > alt->npt) {					werrstr("too many endpoints for interface");					goto error;				}			}			dep = (DEndpoint*)p;			ep->addr = dep->bEndpointAddress & 0x0f;			ep->dir = (dep->bEndpointAddress & 0x80) ? Ein : Eout;			ep->type = type[dep->bmAttributes & 0x03];			ep->isotype = isotype[(dep->bmAttributes>>2) & 0x03];			ep->maxpkt = GET2(dep->wMaxPacketSize);			ep->pollms = dep->bInterval;			break;		default:			if(alt == nil)				desc = &c->desc;			else if(ep == nil)				desc = &alt->desc;			else				desc = &ep->desc;			adddesc(desc, p);		}		p += p[0];	}	free(alttail);	return checkep(alt, ep); error:	free(alttail);	return -1;} static intcheckep(Dalt *alt, Endpt *ep){	int nep; 	if(alt == nil)		return 0;	if(ep == nil)		nep = 0;	else		nep = ep-alt->ep+1;	if(nep != alt->npt) {		werrstr("incorrect number of endpoint descriptors %d != %d", nep, alt->npt);		return -1;	}	return 0;} static voidadddesc(Ddesc *desc, uchar *p){	int len; 	len = p[0];	desc->data = realloc(desc->data, desc->bytes+len);	memmove(desc->data+desc->bytes, p, len);	desc->bytes += len;	desc->ndesc++;} static voiddumplangids(Device *d){	int nr, i;	uchar buf[1023]; 	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (STRING<<8)|0, 0, buf, sizeof(buf)-2);	if(nr < 0) {		fprint(2, "dumplangids: %r\n");		return;	}	if(nr < 2 || buf[0] != nr || buf[1] != STRING) {		fprint(2, "dumplangids: bogus descriptor\n");		return;	}	for(i = 1; i < nr/2; i++)		fprint(2, "%d\n", GET2(&buf[i*2]));} voidloadstr(Device *d, int i, int langid){	int nr;	uchar buf[256+2]; 	if(i == 0 || d->strings[i] != nil)		return;	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (STRING<<8)|i, langid, buf, sizeof(buf)-2);	if(nr < 0) {		d->strings[i] = smprint("loadstr(%d): %r", i);		return;	}	if(nr < 2 || buf[0] != nr || buf[1] != STRING) {		d->strings[i] = smprint("loadstr(%d): bogus string", i);		return;	}	buf[nr] = 0;	buf[nr+1] = 0;	d->strings[i] = smprint("%S", (ushort*)(buf+2));} voidloadstrings(Device *d, int langid){	int i, j;	Dconf *c; 	loadstr(d, d->manufacturer, langid);	loadstr(d, d->product, langid);	loadstr(d, d->serial, langid); 	for(i = 0; i < d->nconf; i++) {		c = &d->config[i];		loadstr(d, c->config, langid);		for(j = 0; j < c->nif; j++)			loadstr(d, c->iface[j].interface, langid);	}}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t