xref: /freebsd/sys/dev/usb/usb_hid.c (revision 3a3f90c6c3cc3124c6f4df8a11b57c8a36a2d13c)
1 /*	$NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $	*/
2 
3 
4 #include <sys/cdefs.h>
5 __FBSDID("$FreeBSD$");
6 /*-
7  * Copyright (c) 1998 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Lennart Augustsson (lennart@augustsson.net) at
12  * Carlstedt Research & Technology.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *        This product includes software developed by the NetBSD
25  *        Foundation, Inc. and its contributors.
26  * 4. Neither the name of The NetBSD Foundation nor the names of its
27  *    contributors may be used to endorse or promote products derived
28  *    from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usb_mfunc.h>
45 #include <dev/usb/usb_error.h>
46 #include <dev/usb/usb_defs.h>
47 #include <dev/usb/usbhid.h>
48 
49 #define	USB_DEBUG_VAR usb2_debug
50 
51 #include <dev/usb/usb_core.h>
52 #include <dev/usb/usb_debug.h>
53 #include <dev/usb/usb_parse.h>
54 #include <dev/usb/usb_process.h>
55 #include <dev/usb/usb_device.h>
56 #include <dev/usb/usb_request.h>
57 #include <dev/usb/usb_hid.h>
58 
59 static void hid_clear_local(struct hid_item *);
60 
61 #define	MAXUSAGE 100
62 struct hid_data {
63 	const uint8_t *start;
64 	const uint8_t *end;
65 	const uint8_t *p;
66 	struct hid_item cur;
67 	int32_t	usages[MAXUSAGE];
68 	int	nu;
69 	int	minset;
70 	int	multi;
71 	int	multimax;
72 	int	kindset;
73 };
74 
75 /*------------------------------------------------------------------------*
76  *	hid_clear_local
77  *------------------------------------------------------------------------*/
78 static void
79 hid_clear_local(struct hid_item *c)
80 {
81 
82 	c->usage = 0;
83 	c->usage_minimum = 0;
84 	c->usage_maximum = 0;
85 	c->designator_index = 0;
86 	c->designator_minimum = 0;
87 	c->designator_maximum = 0;
88 	c->string_index = 0;
89 	c->string_minimum = 0;
90 	c->string_maximum = 0;
91 	c->set_delimiter = 0;
92 }
93 
94 /*------------------------------------------------------------------------*
95  *	hid_start_parse
96  *------------------------------------------------------------------------*/
97 struct hid_data *
98 hid_start_parse(const void *d, int len, int kindset)
99 {
100 	struct hid_data *s;
101 
102 	s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
103 	s->start = s->p = d;
104 	s->end = ((const uint8_t *)d) + len;
105 	s->kindset = kindset;
106 	return (s);
107 }
108 
109 /*------------------------------------------------------------------------*
110  *	hid_end_parse
111  *------------------------------------------------------------------------*/
112 void
113 hid_end_parse(struct hid_data *s)
114 {
115 
116 	while (s->cur.next != NULL) {
117 		struct hid_item *hi = s->cur.next->next;
118 
119 		free(s->cur.next, M_TEMP);
120 		s->cur.next = hi;
121 	}
122 	free(s, M_TEMP);
123 }
124 
125 /*------------------------------------------------------------------------*
126  *	hid_get_item
127  *------------------------------------------------------------------------*/
128 int
129 hid_get_item(struct hid_data *s, struct hid_item *h)
130 {
131 	struct hid_item *c = &s->cur;
132 	unsigned int bTag, bType, bSize;
133 	uint32_t oldpos;
134 	const uint8_t *data;
135 	int32_t dval;
136 	const uint8_t *p;
137 	struct hid_item *hi;
138 	int i;
139 
140 top:
141 	if (s->multimax != 0) {
142 		if (s->multi < s->multimax) {
143 			c->usage = s->usages[MIN(s->multi, s->nu - 1)];
144 			s->multi++;
145 			*h = *c;
146 			c->loc.pos += c->loc.size;
147 			h->next = 0;
148 			return (1);
149 		} else {
150 			c->loc.count = s->multimax;
151 			s->multimax = 0;
152 			s->nu = 0;
153 			hid_clear_local(c);
154 		}
155 	}
156 	for (;;) {
157 		p = s->p;
158 		if (p >= s->end)
159 			return (0);
160 
161 		bSize = *p++;
162 		if (bSize == 0xfe) {
163 			/* long item */
164 			bSize = *p++;
165 			bSize |= *p++ << 8;
166 			bTag = *p++;
167 			data = p;
168 			p += bSize;
169 			bType = 0xff;	/* XXX what should it be */
170 		} else {
171 			/* short item */
172 			bTag = bSize >> 4;
173 			bType = (bSize >> 2) & 3;
174 			bSize &= 3;
175 			if (bSize == 3)
176 				bSize = 4;
177 			data = p;
178 			p += bSize;
179 		}
180 		s->p = p;
181 		switch (bSize) {
182 		case 0:
183 			dval = 0;
184 			break;
185 		case 1:
186 			dval = (int8_t)*data++;
187 			break;
188 		case 2:
189 			dval = *data++;
190 			dval |= *data++ << 8;
191 			dval = (int16_t)dval;
192 			break;
193 		case 4:
194 			dval = *data++;
195 			dval |= *data++ << 8;
196 			dval |= *data++ << 16;
197 			dval |= *data++ << 24;
198 			break;
199 		default:
200 			printf("BAD LENGTH %d\n", bSize);
201 			continue;
202 		}
203 
204 		switch (bType) {
205 		case 0:		/* Main */
206 			switch (bTag) {
207 			case 8:	/* Input */
208 				if (!(s->kindset & (1 << hid_input))) {
209 					if (s->nu > 0)
210 						s->nu--;
211 					continue;
212 				}
213 				c->kind = hid_input;
214 				c->flags = dval;
215 		ret:
216 				if (c->flags & HIO_VARIABLE) {
217 					s->multimax = c->loc.count;
218 					s->multi = 0;
219 					c->loc.count = 1;
220 					if (s->minset) {
221 						for (i = c->usage_minimum;
222 						    i <= c->usage_maximum;
223 						    i++) {
224 							s->usages[s->nu] = i;
225 							if (s->nu < MAXUSAGE - 1)
226 								s->nu++;
227 						}
228 						s->minset = 0;
229 					}
230 					goto top;
231 				} else {
232 					*h = *c;
233 					h->next = 0;
234 					c->loc.pos +=
235 					    c->loc.size * c->loc.count;
236 					hid_clear_local(c);
237 					s->minset = 0;
238 					return (1);
239 				}
240 			case 9:	/* Output */
241 				if (!(s->kindset & (1 << hid_output))) {
242 					if (s->nu > 0)
243 						s->nu--;
244 					continue;
245 				}
246 				c->kind = hid_output;
247 				c->flags = dval;
248 				goto ret;
249 			case 10:	/* Collection */
250 				c->kind = hid_collection;
251 				c->collection = dval;
252 				c->collevel++;
253 				*h = *c;
254 				hid_clear_local(c);
255 				s->nu = 0;
256 				return (1);
257 			case 11:	/* Feature */
258 				if (!(s->kindset & (1 << hid_feature))) {
259 					if (s->nu > 0)
260 						s->nu--;
261 					continue;
262 				}
263 				c->kind = hid_feature;
264 				c->flags = dval;
265 				goto ret;
266 			case 12:	/* End collection */
267 				c->kind = hid_endcollection;
268 				c->collevel--;
269 				*h = *c;
270 				hid_clear_local(c);
271 				s->nu = 0;
272 				return (1);
273 			default:
274 				printf("Main bTag=%d\n", bTag);
275 				break;
276 			}
277 			break;
278 		case 1:		/* Global */
279 			switch (bTag) {
280 			case 0:
281 				c->_usage_page = dval << 16;
282 				break;
283 			case 1:
284 				c->logical_minimum = dval;
285 				break;
286 			case 2:
287 				c->logical_maximum = dval;
288 				break;
289 			case 3:
290 				c->physical_minimum = dval;
291 				break;
292 			case 4:
293 				c->physical_maximum = dval;
294 				break;
295 			case 5:
296 				c->unit_exponent = dval;
297 				break;
298 			case 6:
299 				c->unit = dval;
300 				break;
301 			case 7:
302 				c->loc.size = dval;
303 				break;
304 			case 8:
305 				c->report_ID = dval;
306 				break;
307 			case 9:
308 				c->loc.count = dval;
309 				break;
310 			case 10:	/* Push */
311 				hi = malloc(sizeof *hi, M_TEMP, M_WAITOK);
312 				*hi = s->cur;
313 				c->next = hi;
314 				break;
315 			case 11:	/* Pop */
316 				hi = c->next;
317 				oldpos = c->loc.pos;
318 				s->cur = *hi;
319 				c->loc.pos = oldpos;
320 				free(hi, M_TEMP);
321 				break;
322 			default:
323 				printf("Global bTag=%d\n", bTag);
324 				break;
325 			}
326 			break;
327 		case 2:		/* Local */
328 			switch (bTag) {
329 			case 0:
330 				if (bSize == 1)
331 					dval = c->_usage_page | (dval & 0xff);
332 				else if (bSize == 2)
333 					dval = c->_usage_page | (dval & 0xffff);
334 				c->usage = dval;
335 				if (s->nu < MAXUSAGE)
336 					s->usages[s->nu++] = dval;
337 				/* else XXX */
338 				break;
339 			case 1:
340 				s->minset = 1;
341 				if (bSize == 1)
342 					dval = c->_usage_page | (dval & 0xff);
343 				else if (bSize == 2)
344 					dval = c->_usage_page | (dval & 0xffff);
345 				c->usage_minimum = dval;
346 				break;
347 			case 2:
348 				if (bSize == 1)
349 					dval = c->_usage_page | (dval & 0xff);
350 				else if (bSize == 2)
351 					dval = c->_usage_page | (dval & 0xffff);
352 				c->usage_maximum = dval;
353 				break;
354 			case 3:
355 				c->designator_index = dval;
356 				break;
357 			case 4:
358 				c->designator_minimum = dval;
359 				break;
360 			case 5:
361 				c->designator_maximum = dval;
362 				break;
363 			case 7:
364 				c->string_index = dval;
365 				break;
366 			case 8:
367 				c->string_minimum = dval;
368 				break;
369 			case 9:
370 				c->string_maximum = dval;
371 				break;
372 			case 10:
373 				c->set_delimiter = dval;
374 				break;
375 			default:
376 				printf("Local bTag=%d\n", bTag);
377 				break;
378 			}
379 			break;
380 		default:
381 			printf("default bType=%d\n", bType);
382 			break;
383 		}
384 	}
385 }
386 
387 /*------------------------------------------------------------------------*
388  *	hid_report_size
389  *------------------------------------------------------------------------*/
390 int
391 hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t *idp)
392 {
393 	struct hid_data *d;
394 	struct hid_item h;
395 	int hi, lo, size, id;
396 
397 	id = 0;
398 	hi = lo = -1;
399 	for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);)
400 		if (h.kind == k) {
401 			if (h.report_ID != 0 && !id)
402 				id = h.report_ID;
403 			if (h.report_ID == id) {
404 				if (lo < 0)
405 					lo = h.loc.pos;
406 				hi = h.loc.pos + h.loc.size * h.loc.count;
407 			}
408 		}
409 	hid_end_parse(d);
410 	size = hi - lo;
411 	if (id != 0) {
412 		size += 8;
413 		*idp = id;		/* XXX wrong */
414 	} else
415 		*idp = 0;
416 	return ((size + 7) / 8);
417 }
418 
419 /*------------------------------------------------------------------------*
420  *	hid_locate
421  *------------------------------------------------------------------------*/
422 int
423 hid_locate(const void *desc, int size, uint32_t u, enum hid_kind k,
424     struct hid_location *loc, uint32_t *flags)
425 {
426 	struct hid_data *d;
427 	struct hid_item h;
428 
429 	for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
430 		if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
431 			if (loc != NULL)
432 				*loc = h.loc;
433 			if (flags != NULL)
434 				*flags = h.flags;
435 			hid_end_parse(d);
436 			return (1);
437 		}
438 	}
439 	hid_end_parse(d);
440 	loc->size = 0;
441 	return (0);
442 }
443 
444 /*------------------------------------------------------------------------*
445  *	hid_get_data
446  *------------------------------------------------------------------------*/
447 uint32_t
448 hid_get_data(const uint8_t *buf, uint32_t len, struct hid_location *loc)
449 {
450 	uint32_t hpos = loc->pos;
451 	uint32_t hsize = loc->size;
452 	uint32_t data;
453 	int i, s, t;
454 
455 	DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
456 
457 	if (hsize == 0)
458 		return (0);
459 
460 	data = 0;
461 	s = hpos / 8;
462 	for (i = hpos; i < (hpos + hsize); i += 8) {
463 		t = (i / 8);
464 		if (t < len) {
465 			data |= buf[t] << ((t - s) * 8);
466 		}
467 	}
468 	data >>= hpos % 8;
469 	data &= (1 << hsize) - 1;
470 	hsize = 32 - hsize;
471 	/* Sign extend */
472 	data = ((int32_t)data << hsize) >> hsize;
473 	DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
474 	    loc->pos, loc->size, (long)data);
475 	return (data);
476 }
477 
478 /*------------------------------------------------------------------------*
479  *	hid_is_collection
480  *------------------------------------------------------------------------*/
481 int
482 hid_is_collection(const void *desc, int size, uint32_t usage)
483 {
484 	struct hid_data *hd;
485 	struct hid_item hi;
486 	int err;
487 
488 	hd = hid_start_parse(desc, size, hid_input);
489 	if (hd == NULL)
490 		return (0);
491 
492 	err = hid_get_item(hd, &hi) &&
493 	    hi.kind == hid_collection &&
494 	    hi.usage == usage;
495 	hid_end_parse(hd);
496 	return (err);
497 }
498 
499 /*------------------------------------------------------------------------*
500  *	hid_get_descriptor_from_usb
501  *
502  * This function will search for a HID descriptor between two USB
503  * interface descriptors.
504  *
505  * Return values:
506  * NULL: No more HID descriptors.
507  * Else: Pointer to HID descriptor.
508  *------------------------------------------------------------------------*/
509 struct usb2_hid_descriptor *
510 hid_get_descriptor_from_usb(struct usb2_config_descriptor *cd,
511     struct usb2_interface_descriptor *id)
512 {
513 	struct usb2_descriptor *desc = (void *)id;
514 
515 	if (desc == NULL) {
516 		return (NULL);
517 	}
518 	while ((desc = usb2_desc_foreach(cd, desc))) {
519 		if ((desc->bDescriptorType == UDESC_HID) &&
520 		    (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
521 			return (void *)desc;
522 		}
523 		if (desc->bDescriptorType == UDESC_INTERFACE) {
524 			break;
525 		}
526 	}
527 	return (NULL);
528 }
529 
530 /*------------------------------------------------------------------------*
531  *	usb2_req_get_hid_desc
532  *
533  * This function will read out an USB report descriptor from the USB
534  * device.
535  *
536  * Return values:
537  * NULL: Failure.
538  * Else: Success. The pointer should eventually be passed to free().
539  *------------------------------------------------------------------------*/
540 usb2_error_t
541 usb2_req_get_hid_desc(struct usb2_device *udev, struct mtx *mtx,
542     void **descp, uint16_t *sizep,
543     usb2_malloc_type mem, uint8_t iface_index)
544 {
545 	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
546 	struct usb2_hid_descriptor *hid;
547 	usb2_error_t err;
548 
549 	if ((iface == NULL) || (iface->idesc == NULL)) {
550 		return (USB_ERR_INVAL);
551 	}
552 	hid = hid_get_descriptor_from_usb
553 	    (usb2_get_config_descriptor(udev), iface->idesc);
554 
555 	if (hid == NULL) {
556 		return (USB_ERR_IOERROR);
557 	}
558 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
559 	if (*sizep == 0) {
560 		return (USB_ERR_IOERROR);
561 	}
562 	if (mtx)
563 		mtx_unlock(mtx);
564 
565 	*descp = malloc(*sizep, mem, M_ZERO | M_WAITOK);
566 
567 	if (mtx)
568 		mtx_lock(mtx);
569 
570 	if (*descp == NULL) {
571 		return (USB_ERR_NOMEM);
572 	}
573 	err = usb2_req_get_report_descriptor
574 	    (udev, mtx, *descp, *sizep, iface_index);
575 
576 	if (err) {
577 		free(*descp, mem);
578 		*descp = NULL;
579 		return (err);
580 	}
581 	return (USB_ERR_NORMAL_COMPLETION);
582 }
583