1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "usb.h" 5 #include "hid.h" 6 7 /* 8 * Rough hid descriptor parsing and interpretation for mice 9 * 10 * Chain and its operations build the infrastructure needed 11 * to manipulate non-aligned fields, which do appear (sigh!). 12 */ 13 14 /* Get, at most, 8 bits*/ 15 static uchar 16 get8bits(Chain *ch, int nbits) 17 { 18 int b, nbyb, nbib, nlb; 19 uchar low, high; 20 21 b = ch->b + nbits - 1; 22 nbib = ch->b % 8; 23 nbyb = ch->b / 8; 24 nlb = 8 - nbib; 25 if(nlb > nbits) 26 nlb = nbits; 27 28 low = MSK(nlb) & (ch->buf[nbyb] >> nbib); 29 if(IsCut(ch->b, b)) 30 high = (ch->buf[nbyb + 1] & MSK(nbib)) << nlb; 31 else 32 high = 0; 33 ch->b += nbits; 34 return MSK(nbits)&(high | low); 35 } 36 37 static void 38 getbits(void *p, Chain *ch, int nbits) 39 { 40 int nby, nbi, i; 41 uchar *vp; 42 43 assert(ch->e >= ch->b); 44 nby = nbits / 8; 45 nbi = nbits % 8; 46 47 vp = p; 48 for(i = 0; i < nby; i++) 49 *vp++ = get8bits(ch, 8); 50 51 if(nbi != 0) 52 *vp = get8bits(ch, nbi); 53 } 54 55 int 56 parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz) 57 { 58 int i, j, l, n, isptr, hasxy, hasbut, nk, ncoll, dsize; 59 uchar ks[MaxVals+1]; 60 HidInterface *ifs; 61 62 ifs = temp->ifcs; 63 isptr = 0; 64 hasxy = hasbut = 0; 65 ncoll = 0; 66 n = 0; 67 nk = 0; 68 memset(ifs, 0, sizeof *ifs * MaxIfc); 69 for(i = 0; i < repsz; i += dsize+1){ 70 dsize = (1 << (repdesc[i] & 03)) >> 1; 71 if(nk > MaxVals){ 72 fprint(2, "bad report: too many input types\n"); 73 return -1; 74 } 75 if(n == MaxIfc) 76 break; 77 if(repdesc[i] == HidEnd){ 78 ncoll--; 79 if(ncoll == 0) 80 break; 81 } 82 83 switch(repdesc[i]){ 84 case HidReportId: 85 switch(repdesc[i+1]){ 86 case HidReportIdPtr: 87 temp->id = repdesc[i+1]; 88 break; 89 default: 90 fprint(2, "report type %#ux bad\n", 91 repdesc[i+1]); 92 return -1; 93 } 94 break; 95 case HidTypeUsg: 96 switch(repdesc[i+1]){ 97 case HidX: 98 hasxy++; 99 ks[nk++] = KindX; 100 break; 101 case HidY: 102 hasxy++; 103 ks[nk++] = KindY; 104 break; 105 case HidZ: 106 ks[nk++] = KindPad; 107 break; 108 case HidWheel: 109 ks[nk++] = KindWheel; 110 break; 111 case HidPtr: 112 isptr++; 113 break; 114 } 115 break; 116 case HidTypeUsgPg: 117 switch(repdesc[i+1]){ 118 case HidPgButts: 119 hasbut++; 120 ks[nk++] = KindButtons; 121 break; 122 } 123 break; 124 case HidTypeRepSz: 125 ifs[n].nbits = repdesc[i+1]; 126 break; 127 case HidTypeCnt: 128 ifs[n].count = repdesc[i+1]; 129 break; 130 case HidInput: 131 if(ifs[n].count > MaxVals){ 132 fprint(2, "bad report: input count too big\n"); 133 return -1; 134 } 135 for(j = 0; j <nk; j++) 136 ifs[n].kind[j] = ks[j]; 137 if(nk != 0 && nk < ifs[n].count) 138 for(l = j; l <ifs[n].count; l++) 139 ifs[n].kind[l] = ks[j-1]; 140 n++; 141 if(n < MaxIfc){ 142 ifs[n].count = ifs[n-1].count; /* inherit values */ 143 ifs[n].nbits = ifs[n-1].nbits; 144 if(ifs[n].nbits == 0) 145 ifs[n].nbits = 1; 146 } 147 nk = 0; 148 break; 149 case HidCollection: 150 ncoll++; 151 break; 152 } 153 } 154 temp->nifcs = n; 155 for(i = 0; i < n; i++) 156 temp->sz += temp->ifcs[i].nbits * temp->ifcs[i].count; 157 temp->sz = (temp->sz + 7) / 8; 158 159 if(isptr && hasxy && hasbut) 160 return 0; 161 fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n", 162 isptr, hasxy, hasbut); 163 return -1; 164 } 165 166 int 167 parsereport(HidRepTempl *templ, Chain *rep) 168 { 169 int i, j, k, ifssz; 170 ulong u; 171 uchar *p; 172 HidInterface *ifs; 173 174 ifssz = templ->nifcs; 175 ifs = templ->ifcs; 176 for(i = 0; i < ifssz; i++) 177 for(j = 0; j < ifs[i].count; j++){ 178 if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){ 179 fprint(2, "ptr: bad bits in parsereport"); 180 return -1; 181 } 182 u =0; 183 getbits(&u, rep, ifs[i].nbits); 184 p = (uchar *)&u; 185 /* le to host */ 186 ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0; 187 k = ifs[i].kind[j]; 188 if(k == KindX || k == KindY || k == KindWheel){ 189 /* propagate sign */ 190 if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1))) 191 ifs[i].v[j] |= ~MSK(ifs[i].nbits); 192 } 193 } 194 return 0; 195 } 196 197 /* TODO: fmt representation */ 198 void 199 dumpreport(HidRepTempl *templ) 200 { 201 int i, j, ifssz; 202 HidInterface *ifs; 203 204 ifssz = templ->nifcs; 205 ifs = templ->ifcs; 206 for(i = 0; i < ifssz; i++){ 207 fprint(2, "\tcount %#ux", ifs[i].count); 208 fprint(2, " nbits %d ", ifs[i].nbits); 209 fprint(2, "\n"); 210 for(j = 0; j < ifs[i].count; j++){ 211 fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]); 212 fprint(2, "v %#lux\n", ifs[i].v[j]); 213 } 214 fprint(2, "\n"); 215 } 216 fprint(2, "\n"); 217 } 218 219 /* could precalculate indices after parsing the descriptor */ 220 int 221 hidifcval(HidRepTempl *templ, int kind, int n) 222 { 223 int i, j, ifssz; 224 HidInterface *ifs; 225 226 ifssz = templ->nifcs; 227 ifs = templ->ifcs; 228 assert(n <= nelem(ifs[i].v)); 229 for(i = 0; i < ifssz; i++) 230 for(j = 0; j < ifs[i].count; j++) 231 if(ifs[i].kind[j] == kind && n-- == 0) 232 return (int)ifs[i].v[j]; 233 return 0; /* least damage (no buttons, no movement) */ 234 } 235