243 lines · 5.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <thread.h>#include "usb.h"#include "hid.h" /* * Rough hid descriptor parsing and interpretation for mice * * Chain and its operations build the infrastructure needed * to manipulate non-aligned fields, which do appear (sigh!). */ /* Get, at most, 8 bits*/static ucharget8bits(Chain *ch, int nbits){	int b, nbyb, nbib, nlb;	uchar low, high; 	b = ch->b + nbits - 1;	nbib = ch->b % 8;	nbyb = ch->b / 8;	nlb = 8 - nbib;	if(nlb > nbits)		nlb = nbits; 	low = MSK(nlb) & (ch->buf[nbyb] >> nbib);	if(IsCut(ch->b, b))		high = (ch->buf[nbyb + 1] & MSK(nbib)) << nlb;	else		high = 0;	ch->b += nbits;	return MSK(nbits)&(high | low);} static voidgetbits(void *p, Chain *ch, int nbits){	int nby, nbi, i;	uchar *vp; 	assert(ch->e >= ch->b);	nby = nbits / 8;	nbi = nbits % 8; 	vp = p;	for(i = 0; i < nby; i++)		*vp++ = get8bits(ch, 8); 	if(nbi != 0)		*vp = get8bits(ch, nbi);} intparsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz){	int i, j, l, n, isptr, hasxy, hasbut, nk, ncoll, dsize;	uchar ks[MaxVals+1];	HidInterface *ifs; 	ifs = temp->ifcs;	isptr = 0;	hasxy = hasbut = 0;	ncoll = 0;	n = 0;	nk = 0;	memset(ifs, 0, sizeof *ifs * MaxIfc);	for(i = 0; i < repsz; i += dsize+1){		dsize = (1 << (repdesc[i] & 03)) >> 1;		if(nk > MaxVals){			fprint(2, "bad report: too many input types\n");			return -1;		}		if(n == MaxIfc)			break;		if(repdesc[i] == HidEnd){			ncoll--;			if(ncoll == 0)				break;		} 		switch(repdesc[i]){		case HidReportId:			switch(repdesc[i+1]){			case HidReportIdPtr:				temp->id = repdesc[i+1];				break;			default:				fprint(2, "report type %#ux bad\n",					repdesc[i+1]);				return -1;			}			break;		case HidTypeUsg:			switch(repdesc[i+1]){			case HidX:				hasxy++;				ks[nk++] = KindX;				break;			case HidY:				hasxy++;				ks[nk++] = KindY;				break;			case HidZ:				ks[nk++] = KindPad;				break;			case HidWheel:				ks[nk++] = KindWheel;				break;			case HidPtr:				isptr++;				break;			}			break;		case HidTypeUsgPg:			switch(repdesc[i+1]){			case HidPgButts:				hasbut++;				ks[nk++] = KindButtons;				break;			}			break;		case HidTypeRepSz:			ifs[n].nbits = repdesc[i+1];			break;		case HidTypeCnt:			ifs[n].count = repdesc[i+1];			break;		case HidInput:			if(ifs[n].count > MaxVals){				fprint(2, "bad report: input count too big\n");				return -1;			}			for(j = 0; j <nk; j++)				ifs[n].kind[j] = ks[j];			if(nk != 0 && nk < ifs[n].count)				for(l = j; l <ifs[n].count; l++)					ifs[n].kind[l] = ks[j-1];			n++;			if(n < MaxIfc){				ifs[n].count = ifs[n-1].count;	/* inherit values */				ifs[n].nbits = ifs[n-1].nbits;				if(ifs[n].nbits == 0)					ifs[n].nbits = 1;			}			nk = 0;			break;		case HidCollection:			ncoll++;			break;		}	}	temp->nifcs = n;	for(i = 0; i < n; i++)		temp->sz += temp->ifcs[i].nbits * temp->ifcs[i].count;	temp->sz = (temp->sz + 7) / 8;		if(isptr && hasxy && hasbut)		return 0;	fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n",		isptr, hasxy, hasbut);	return -1;} intparsereport(HidRepTempl *templ, Chain *rep){	int i, j, k, ifssz;	ulong u;	uchar *p;	HidInterface *ifs; 	ifssz = templ->nifcs;	ifs = templ->ifcs;	for(i = 0; i < ifssz; i++)		for(j = 0; j < ifs[i].count; j++){			if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){				fprint(2, "ptr: bad bits in parsereport");				return -1;			}			u =0;			getbits(&u, rep, ifs[i].nbits);			p = (uchar *)&u;			/* le to host */			ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0;			k = ifs[i].kind[j];			if(k == KindX || k == KindY || k == KindWheel){				/* propagate sign */				if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1)))					ifs[i].v[j] |= ~MSK(ifs[i].nbits);			}		}	return 0;} /* TODO: fmt representation */voiddumpreport(HidRepTempl *templ){	int i, j, ifssz;	HidInterface *ifs; 	ifssz = templ->nifcs;	ifs = templ->ifcs;	for(i = 0; i < ifssz; i++){		fprint(2, "\tcount %#ux", ifs[i].count);		fprint(2, " nbits %d ", ifs[i].nbits);		fprint(2, "\n");		for(j = 0; j < ifs[i].count; j++){			fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]);			fprint(2, "v %#lux\n", ifs[i].v[j]);		}		fprint(2, "\n");	}	fprint(2, "\n");} /* could precalculate indices after parsing the descriptor */inthidifcval(HidRepTempl *templ, int kind, int n){	int i, j, ifssz;	HidInterface *ifs; 	ifssz = templ->nifcs;	ifs = templ->ifcs;	assert(n <= nelem(ifs[i].v));	for(i = 0; i < ifssz; i++)		for(j = 0; j < ifs[i].count; j++)			if(ifs[i].kind[j] == kind && n-- == 0)				return (int)ifs[i].v[j];	return 0;		/* least damage (no buttons, no movement) */}