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 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 /* TODO check report id, when it does appear (not all devices) */ 56 int 57 parsereportdesc(HidRepTempl *temp, uchar *repdesc, int repsz) 58 { 59 int i, j, l, n, isptr, hasxy, hasbut, nk; 60 int ks[MaxVals]; 61 HidInterface *ifs; 62 63 ifs = temp->ifcs; 64 isptr = 0; 65 hasxy = hasbut = 0; 66 n = 0; 67 nk = 0; 68 memset(ifs, 0, sizeof *ifs * MaxIfc); 69 for(i = 0; i < repsz / 2; i += 2){ 70 if(n == MaxIfc || repdesc[i] == HidEnd) 71 break; 72 73 switch(repdesc[i]){ 74 case HidTypeUsg: 75 switch(repdesc[i+1]){ 76 case HidX: 77 hasxy++; 78 ks[nk++] = KindX; 79 break; 80 case HidY: 81 hasxy++; 82 ks[nk++] = KindY; 83 break; 84 case HidWheel: 85 ks[nk++] = KindWheel; 86 break; 87 case HidPtr: 88 isptr++; 89 break; 90 } 91 break; 92 case HidTypeUsgPg: 93 switch(repdesc[i+1]){ 94 case HidPgButts: 95 hasbut++; 96 ks[nk++] = KindButtons; 97 break; 98 } 99 break; 100 case HidTypeRepSz: 101 ifs[n].nbits = repdesc[i+1]; 102 break; 103 case HidTypeCnt: 104 ifs[n].count = repdesc[i+1]; 105 break; 106 case HidInput: 107 for(j = 0; j <nk; j++) 108 ifs[n].kind[j] = ks[j]; 109 if(nk < ifs[n].count) 110 for(l = j; l <ifs[n].count; l++) 111 ifs[n].kind[l] = ks[j-1]; 112 n++; 113 nk = 0; 114 break; 115 } 116 } 117 temp->nifcs = n; 118 if(isptr && hasxy && hasbut) 119 return 0; 120 fprint(2, "bad report: isptr %d, hasxy %d, hasbut %d\n", 121 isptr, hasxy, hasbut); 122 return -1; 123 } 124 125 int 126 parsereport(HidRepTempl *templ, Chain *rep) 127 { 128 int i, j, k, ifssz; 129 ulong u; 130 uchar *p; 131 HidInterface *ifs; 132 133 ifssz = templ->nifcs; 134 ifs = templ->ifcs; 135 for(i = 0; i < ifssz; i++) 136 for(j = 0; j < ifs[i].count; j++){ 137 if(ifs[i].nbits > 8 * sizeof ifs[i].v[0]){ 138 fprint(2, "ptr: bad bits in parsereport"); 139 return -1; 140 } 141 u =0; 142 getbits(&u, rep, ifs[i].nbits); 143 p = (uchar *)&u; 144 /* le to host */ 145 ifs[i].v[j] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]<<0; 146 k = ifs[i].kind[j]; 147 if(k == KindX || k == KindY || k == KindWheel){ 148 /* propagate sign */ 149 if(ifs[i].v[j] & (1 << (ifs[i].nbits - 1))) 150 ifs[i].v[j] |= ~MSK(ifs[i].nbits); 151 } 152 } 153 return 0; 154 } 155 156 /* TODO: fmt representation */ 157 void 158 dumpreport(HidRepTempl *templ) 159 { 160 int i, j, ifssz; 161 HidInterface *ifs; 162 163 ifssz = templ->nifcs; 164 ifs = templ->ifcs; 165 for(i = 0; i < ifssz; i++){ 166 fprint(2, "\tcount %#ux", ifs[i].count); 167 fprint(2, " nbits %d ", ifs[i].nbits); 168 fprint(2, "\n"); 169 for(j = 0; j < ifs[i].count; j++){ 170 fprint(2, "\t\tkind %#ux ", ifs[i].kind[j]); 171 fprint(2, "v %#lux\n", ifs[i].v[j]); 172 } 173 fprint(2, "\n"); 174 } 175 fprint(2, "\n"); 176 } 177 178 /* could cache indices after parsing the descriptor */ 179 int 180 hidifcval(HidRepTempl *templ, int kind, int n) 181 { 182 int i, j, ifssz; 183 HidInterface *ifs; 184 185 ifssz = templ->nifcs; 186 ifs = templ->ifcs; 187 assert(n <= nelem(ifs[i].v)); 188 for(i = 0; i < ifssz; i++) 189 for(j = 0; j < ifs[i].count; j++) 190 if(ifs[i].kind[j] == kind && n-- == 0) 191 return (int)ifs[i].v[j]; 192 return 0; /* least damage (no buttons, no movement) */ 193 } 194