usb_hid.c revision 194228
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: head/sys/dev/usb/usb_hid.c 194228 2009-06-15 01:02:43Z thompsa $");
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/usbhid.h>
47
48#define	USB_DEBUG_VAR usb_debug
49
50#include <dev/usb/usb_core.h>
51#include <dev/usb/usb_debug.h>
52#include <dev/usb/usb_parse.h>
53#include <dev/usb/usb_process.h>
54#include <dev/usb/usb_device.h>
55#include <dev/usb/usb_request.h>
56#include <dev/usb/usb_hid.h>
57
58static void hid_clear_local(struct hid_item *);
59static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
60
61#define	MAXUSAGE 64
62#define	MAXPUSH 4
63struct hid_data {
64	const uint8_t *start;
65	const uint8_t *end;
66	const uint8_t *p;
67	struct hid_item cur[MAXPUSH];
68	int32_t	usages_min[MAXUSAGE];
69	int32_t	usages_max[MAXUSAGE];
70	int32_t usage_last;	/* last seen usage */
71	uint32_t loc_size;	/* last seen size */
72	uint32_t loc_count;	/* last seen count */
73	uint8_t	kindset;	/* we have 5 kinds so 8 bits are enough */
74	uint8_t	pushlevel;	/* current pushlevel */
75	uint8_t	ncount;		/* end usage item count */
76	uint8_t icount;		/* current usage item count */
77	uint8_t	nusage;		/* end "usages_min/max" index */
78	uint8_t	iusage;		/* current "usages_min/max" index */
79	uint8_t ousage;		/* current "usages_min/max" offset */
80	uint8_t	susage;		/* usage set flags */
81};
82
83/*------------------------------------------------------------------------*
84 *	hid_clear_local
85 *------------------------------------------------------------------------*/
86static void
87hid_clear_local(struct hid_item *c)
88{
89
90	c->loc.count = 0;
91	c->loc.size = 0;
92	c->usage = 0;
93	c->usage_minimum = 0;
94	c->usage_maximum = 0;
95	c->designator_index = 0;
96	c->designator_minimum = 0;
97	c->designator_maximum = 0;
98	c->string_index = 0;
99	c->string_minimum = 0;
100	c->string_maximum = 0;
101	c->set_delimiter = 0;
102}
103
104/*------------------------------------------------------------------------*
105 *	hid_start_parse
106 *------------------------------------------------------------------------*/
107struct hid_data *
108hid_start_parse(const void *d, usb_size_t len, int kindset)
109{
110	struct hid_data *s;
111
112	if ((kindset-1) & kindset) {
113		DPRINTFN(0, "Only one bit can be "
114		    "set in the kindset\n");
115		return (NULL);
116	}
117
118	s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
119	s->start = s->p = d;
120	s->end = ((const uint8_t *)d) + len;
121	s->kindset = kindset;
122	return (s);
123}
124
125/*------------------------------------------------------------------------*
126 *	hid_end_parse
127 *------------------------------------------------------------------------*/
128void
129hid_end_parse(struct hid_data *s)
130{
131	if (s == NULL)
132		return;
133
134	free(s, M_TEMP);
135}
136
137/*------------------------------------------------------------------------*
138 *	get byte from HID descriptor
139 *------------------------------------------------------------------------*/
140static uint8_t
141hid_get_byte(struct hid_data *s, const uint16_t wSize)
142{
143	const uint8_t *ptr;
144	uint8_t retval;
145
146	ptr = s->p;
147
148	/* check if end is reached */
149	if (ptr == s->end)
150		return (0);
151
152	/* read out a byte */
153	retval = *ptr;
154
155	/* check if data pointer can be advanced by "wSize" bytes */
156	if ((s->end - ptr) < wSize)
157		ptr = s->end;
158	else
159		ptr += wSize;
160
161	/* update pointer */
162	s->p = ptr;
163
164	return (retval);
165}
166
167/*------------------------------------------------------------------------*
168 *	hid_get_item
169 *------------------------------------------------------------------------*/
170int
171hid_get_item(struct hid_data *s, struct hid_item *h)
172{
173	struct hid_item *c;
174	unsigned int bTag, bType, bSize;
175	uint32_t oldpos;
176	int32_t mask;
177	int32_t dval;
178
179	if (s == NULL)
180		return (0);
181
182	c = &s->cur[s->pushlevel];
183
184 top:
185	/* check if there is an array of items */
186	if (s->icount < s->ncount) {
187		/* get current usage */
188		if (s->iusage < s->nusage) {
189			dval = s->usages_min[s->iusage] + s->ousage;
190			c->usage = dval;
191			s->usage_last = dval;
192			if (dval == s->usages_max[s->iusage]) {
193				s->iusage ++;
194				s->ousage = 0;
195			} else {
196				s->ousage ++;
197			}
198		} else {
199			DPRINTFN(1, "Using last usage\n");
200			dval = s->usage_last;
201		}
202		s->icount ++;
203		/*
204		 * Only copy HID item, increment position and return
205		 * if correct kindset!
206		 */
207		if (s->kindset & (1 << c->kind)) {
208			*h = *c;
209			DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
210			    h->loc.size, h->loc.count);
211			c->loc.pos += c->loc.size * c->loc.count;
212			return (1);
213		}
214	}
215
216	/* reset state variables */
217	s->icount = 0;
218	s->ncount = 0;
219	s->iusage = 0;
220	s->nusage = 0;
221	s->susage = 0;
222	s->ousage = 0;
223	hid_clear_local(c);
224
225	/* get next item */
226	while (s->p != s->end) {
227
228		bSize = hid_get_byte(s, 1);
229		if (bSize == 0xfe) {
230			/* long item */
231			bSize = hid_get_byte(s, 1);
232			bSize |= hid_get_byte(s, 1) << 8;
233			bTag = hid_get_byte(s, 1);
234			bType = 0xff;	/* XXX what should it be */
235		} else {
236			/* short item */
237			bTag = bSize >> 4;
238			bType = (bSize >> 2) & 3;
239			bSize &= 3;
240			if (bSize == 3)
241				bSize = 4;
242		}
243		switch (bSize) {
244		case 0:
245			dval = 0;
246			mask = 0;
247			break;
248		case 1:
249			dval = (int8_t)hid_get_byte(s, 1);
250			mask = 0xFF;
251			break;
252		case 2:
253			dval = hid_get_byte(s, 1);
254			dval |= hid_get_byte(s, 1) << 8;
255			dval = (int16_t)dval;
256			mask = 0xFFFF;
257			break;
258		case 4:
259			dval = hid_get_byte(s, 1);
260			dval |= hid_get_byte(s, 1) << 8;
261			dval |= hid_get_byte(s, 1) << 16;
262			dval |= hid_get_byte(s, 1) << 24;
263			mask = 0xFFFFFFFF;
264			break;
265		default:
266			dval = hid_get_byte(s, bSize);
267			DPRINTFN(0, "bad length %u (data=0x%02x)\n",
268			    bSize, dval);
269			continue;
270		}
271
272		switch (bType) {
273		case 0:		/* Main */
274			switch (bTag) {
275			case 8:	/* Input */
276				c->kind = hid_input;
277				c->flags = dval;
278		ret:
279				c->loc.count = s->loc_count;
280				c->loc.size = s->loc_size;
281
282				if (c->flags & HIO_VARIABLE) {
283					/* range check usage count */
284					if (c->loc.count > 255) {
285						DPRINTFN(0, "Number of "
286						    "items truncated to 255\n");
287						s->ncount = 255;
288					} else
289						s->ncount = c->loc.count;
290
291					/*
292					 * The "top" loop will return
293					 * one and one item:
294					 */
295					c->loc.count = 1;
296				} else {
297					s->ncount = 1;
298				}
299				goto top;
300
301			case 9:	/* Output */
302				c->kind = hid_output;
303				c->flags = dval;
304				goto ret;
305			case 10:	/* Collection */
306				c->kind = hid_collection;
307				c->collection = dval;
308				c->collevel++;
309				c->usage = s->usage_last;
310				*h = *c;
311				return (1);
312			case 11:	/* Feature */
313				c->kind = hid_feature;
314				c->flags = dval;
315				goto ret;
316			case 12:	/* End collection */
317				c->kind = hid_endcollection;
318				if (c->collevel == 0) {
319					DPRINTFN(0, "invalid end collection\n");
320					return (0);
321				}
322				c->collevel--;
323				*h = *c;
324				return (1);
325			default:
326				DPRINTFN(0, "Main bTag=%d\n", bTag);
327				break;
328			}
329			break;
330		case 1:		/* Global */
331			switch (bTag) {
332			case 0:
333				c->_usage_page = dval << 16;
334				break;
335			case 1:
336				c->logical_minimum = dval;
337				break;
338			case 2:
339				c->logical_maximum = dval;
340				break;
341			case 3:
342				c->physical_minimum = dval;
343				break;
344			case 4:
345				c->physical_maximum = dval;
346				break;
347			case 5:
348				c->unit_exponent = dval;
349				break;
350			case 6:
351				c->unit = dval;
352				break;
353			case 7:
354				/* mask because value is unsigned */
355				s->loc_size = dval & mask;
356				break;
357			case 8:
358				c->report_ID = dval;
359				/* new report - reset position */
360				c->loc.pos = 0;
361				break;
362			case 9:
363				/* mask because value is unsigned */
364				s->loc_count = dval & mask;
365				break;
366			case 10:	/* Push */
367				s->pushlevel ++;
368				if (s->pushlevel < MAXPUSH) {
369					s->cur[s->pushlevel] = *c;
370					/* store size and count */
371					c->loc.size = s->loc_size;
372					c->loc.count = s->loc_count;
373					/* update current item pointer */
374					c = &s->cur[s->pushlevel];
375				} else {
376					DPRINTFN(0, "Cannot push "
377					    "item @ %d!\n", s->pushlevel);
378				}
379				break;
380			case 11:	/* Pop */
381				s->pushlevel --;
382				if (s->pushlevel < MAXPUSH) {
383					/* preserve position */
384					oldpos = c->loc.pos;
385					c = &s->cur[s->pushlevel];
386					/* restore size and count */
387					s->loc_size = c->loc.size;
388					s->loc_count = c->loc.count;
389					/* set default item location */
390					c->loc.pos = oldpos;
391					c->loc.size = 0;
392					c->loc.count = 0;
393				} else {
394					DPRINTFN(0, "Cannot pop "
395					    "item @ %d!\n", s->pushlevel);
396				}
397				break;
398			default:
399				DPRINTFN(0, "Global bTag=%d\n", bTag);
400				break;
401			}
402			break;
403		case 2:		/* Local */
404			switch (bTag) {
405			case 0:
406				if (bSize != 4)
407					dval = (dval & mask) | c->_usage_page;
408
409				/* set last usage, in case of a collection */
410				s->usage_last = dval;
411
412				if (s->nusage < MAXUSAGE) {
413					s->usages_min[s->nusage] = dval;
414					s->usages_max[s->nusage] = dval;
415					s->nusage ++;
416				} else {
417					DPRINTFN(0, "max usage reached!\n");
418				}
419
420				/* clear any pending usage sets */
421				s->susage = 0;
422				break;
423			case 1:
424				s->susage |= 1;
425
426				if (bSize != 4)
427					dval = (dval & mask) | c->_usage_page;
428				c->usage_minimum = dval;
429
430				goto check_set;
431			case 2:
432				s->susage |= 2;
433
434				if (bSize != 4)
435					dval = (dval & mask) | c->_usage_page;
436				c->usage_maximum = dval;
437
438			check_set:
439				if (s->susage != 3)
440					break;
441
442				/* sanity check */
443				if ((s->nusage < MAXUSAGE) &&
444				    (c->usage_minimum <= c->usage_maximum)) {
445					/* add usage range */
446					s->usages_min[s->nusage] =
447					    c->usage_minimum;
448					s->usages_max[s->nusage] =
449					    c->usage_maximum;
450					s->nusage ++;
451				} else {
452					DPRINTFN(0, "Usage set dropped!\n");
453				}
454				s->susage = 0;
455				break;
456			case 3:
457				c->designator_index = dval;
458				break;
459			case 4:
460				c->designator_minimum = dval;
461				break;
462			case 5:
463				c->designator_maximum = dval;
464				break;
465			case 7:
466				c->string_index = dval;
467				break;
468			case 8:
469				c->string_minimum = dval;
470				break;
471			case 9:
472				c->string_maximum = dval;
473				break;
474			case 10:
475				c->set_delimiter = dval;
476				break;
477			default:
478				DPRINTFN(0, "Local bTag=%d\n", bTag);
479				break;
480			}
481			break;
482		default:
483			DPRINTFN(0, "default bType=%d\n", bType);
484			break;
485		}
486	}
487	return (0);
488}
489
490/*------------------------------------------------------------------------*
491 *	hid_report_size
492 *------------------------------------------------------------------------*/
493int
494hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
495{
496	struct hid_data *d;
497	struct hid_item h;
498	uint32_t temp;
499	uint32_t hpos;
500	uint32_t lpos;
501	uint8_t any_id;
502
503	any_id = 0;
504	hpos = 0;
505	lpos = 0xFFFFFFFF;
506
507	for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
508		if (h.kind == k) {
509			/* check for ID-byte presense */
510			if ((h.report_ID != 0) && !any_id) {
511				if (id != NULL)
512					*id = h.report_ID;
513				any_id = 1;
514			}
515			/* compute minimum */
516			if (lpos > h.loc.pos)
517				lpos = h.loc.pos;
518			/* compute end position */
519			temp = h.loc.pos + (h.loc.size * h.loc.count);
520			/* compute maximum */
521			if (hpos < temp)
522				hpos = temp;
523		}
524	}
525	hid_end_parse(d);
526
527	/* safety check - can happen in case of currupt descriptors */
528	if (lpos > hpos)
529		temp = 0;
530	else
531		temp = hpos - lpos;
532
533	/* check for ID byte */
534	if (any_id)
535		temp += 8;
536	else if (id != NULL)
537		*id = 0;
538
539	/* return length in bytes rounded up */
540	return ((temp + 7) / 8);
541}
542
543/*------------------------------------------------------------------------*
544 *	hid_locate
545 *------------------------------------------------------------------------*/
546int
547hid_locate(const void *desc, usb_size_t size, uint32_t u, enum hid_kind k,
548    uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
549{
550	struct hid_data *d;
551	struct hid_item h;
552
553	for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
554		if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
555			if (index--)
556				continue;
557			if (loc != NULL)
558				*loc = h.loc;
559			if (flags != NULL)
560				*flags = h.flags;
561			if (id != NULL)
562				*id = h.report_ID;
563			hid_end_parse(d);
564			return (1);
565		}
566	}
567	if (loc != NULL)
568		loc->size = 0;
569	if (flags != NULL)
570		*flags = 0;
571	if (id != NULL)
572		*id = 0;
573	hid_end_parse(d);
574	return (0);
575}
576
577/*------------------------------------------------------------------------*
578 *	hid_get_data
579 *------------------------------------------------------------------------*/
580uint32_t
581hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
582{
583	uint32_t hpos = loc->pos;
584	uint32_t hsize = loc->size;
585	uint32_t data;
586	uint32_t rpos;
587	uint8_t n;
588
589	DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
590
591	/* Range check and limit */
592	if (hsize == 0)
593		return (0);
594	if (hsize > 32)
595		hsize = 32;
596
597	/* Get data in a safe way */
598	data = 0;
599	rpos = (hpos / 8);
600	n = (hsize + 7) / 8;
601	rpos += n;
602	while (n--) {
603		rpos--;
604		if (rpos < len)
605			data |= buf[rpos] << (8 * n);
606	}
607
608	/* Correctly shift down data */
609	data = (data >> (hpos % 8));
610
611	/* Mask and sign extend in one */
612	n = 32 - hsize;
613	data = ((int32_t)data << n) >> n;
614
615	DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
616	    loc->pos, loc->size, (long)data);
617	return (data);
618}
619
620/*------------------------------------------------------------------------*
621 *	hid_is_collection
622 *------------------------------------------------------------------------*/
623int
624hid_is_collection(const void *desc, usb_size_t size, uint32_t usage)
625{
626	struct hid_data *hd;
627	struct hid_item hi;
628	int err;
629
630	hd = hid_start_parse(desc, size, hid_input);
631	if (hd == NULL)
632		return (0);
633
634	while ((err = hid_get_item(hd, &hi))) {
635		 if (hi.kind == hid_collection &&
636		     hi.usage == usage)
637			break;
638	}
639	hid_end_parse(hd);
640	return (err);
641}
642
643/*------------------------------------------------------------------------*
644 *	hid_get_descriptor_from_usb
645 *
646 * This function will search for a HID descriptor between two USB
647 * interface descriptors.
648 *
649 * Return values:
650 * NULL: No more HID descriptors.
651 * Else: Pointer to HID descriptor.
652 *------------------------------------------------------------------------*/
653struct usb_hid_descriptor *
654hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
655    struct usb_interface_descriptor *id)
656{
657	struct usb_descriptor *desc = (void *)id;
658
659	if (desc == NULL) {
660		return (NULL);
661	}
662	while ((desc = usb_desc_foreach(cd, desc))) {
663		if ((desc->bDescriptorType == UDESC_HID) &&
664		    (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
665			return (void *)desc;
666		}
667		if (desc->bDescriptorType == UDESC_INTERFACE) {
668			break;
669		}
670	}
671	return (NULL);
672}
673
674/*------------------------------------------------------------------------*
675 *	usbd_req_get_hid_desc
676 *
677 * This function will read out an USB report descriptor from the USB
678 * device.
679 *
680 * Return values:
681 * NULL: Failure.
682 * Else: Success. The pointer should eventually be passed to free().
683 *------------------------------------------------------------------------*/
684usb_error_t
685usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
686    void **descp, uint16_t *sizep,
687    struct malloc_type *mem, uint8_t iface_index)
688{
689	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
690	struct usb_hid_descriptor *hid;
691	usb_error_t err;
692
693	if ((iface == NULL) || (iface->idesc == NULL)) {
694		return (USB_ERR_INVAL);
695	}
696	hid = hid_get_descriptor_from_usb
697	    (usbd_get_config_descriptor(udev), iface->idesc);
698
699	if (hid == NULL) {
700		return (USB_ERR_IOERROR);
701	}
702	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
703	if (*sizep == 0) {
704		return (USB_ERR_IOERROR);
705	}
706	if (mtx)
707		mtx_unlock(mtx);
708
709	*descp = malloc(*sizep, mem, M_ZERO | M_WAITOK);
710
711	if (mtx)
712		mtx_lock(mtx);
713
714	if (*descp == NULL) {
715		return (USB_ERR_NOMEM);
716	}
717	err = usbd_req_get_report_descriptor
718	    (udev, mtx, *descp, *sizep, iface_index);
719
720	if (err) {
721		free(*descp, mem);
722		*descp = NULL;
723		return (err);
724	}
725	return (USB_ERR_NORMAL_COMPLETION);
726}
727