Merge branch 'vendor/BINUTILS225'
[dragonfly.git] / sys / bus / u4b / usb_hid.c
1 /* $FreeBSD: head/sys/dev/usb/usb_hid.c 246122 2013-01-30 15:26:04Z hselasky $ */
2 /*      $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $   */
3
4
5 /*-
6  * Copyright (c) 1998 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Lennart Augustsson (lennart@augustsson.net) at
11  * Carlstedt Research & Technology.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/stdint.h>
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/types.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/bus.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/condvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/unistd.h>
48 #include <sys/callout.h>
49 #include <sys/malloc.h>
50 #include <sys/priv.h>
51
52 #include <bus/u4b/usb.h>
53 #include <bus/u4b/usbdi.h>
54 #include <bus/u4b/usbdi_util.h>
55 #include <bus/u4b/usbhid.h>
56
57 #define USB_DEBUG_VAR usb_debug
58
59 #include <bus/u4b/usb_core.h>
60 #include <bus/u4b/usb_debug.h>
61 #include <bus/u4b/usb_process.h>
62 #include <bus/u4b/usb_device.h>
63 #include <bus/u4b/usb_request.h>
64
65 static void hid_clear_local(struct hid_item *);
66 static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
67
68 #define MAXUSAGE 64
69 #define MAXPUSH 4
70 #define MAXID 16
71
72 struct hid_pos_data {
73         int32_t rid;
74         uint32_t pos;
75 };
76
77 struct hid_data {
78         const uint8_t *start;
79         const uint8_t *end;
80         const uint8_t *p;
81         struct hid_item cur[MAXPUSH];
82         struct hid_pos_data last_pos[MAXID];
83         int32_t usages_min[MAXUSAGE];
84         int32_t usages_max[MAXUSAGE];
85         int32_t usage_last;     /* last seen usage */
86         uint32_t loc_size;      /* last seen size */
87         uint32_t loc_count;     /* last seen count */
88         uint8_t kindset;        /* we have 5 kinds so 8 bits are enough */
89         uint8_t pushlevel;      /* current pushlevel */
90         uint8_t ncount;         /* end usage item count */
91         uint8_t icount;         /* current usage item count */
92         uint8_t nusage;         /* end "usages_min/max" index */
93         uint8_t iusage;         /* current "usages_min/max" index */
94         uint8_t ousage;         /* current "usages_min/max" offset */
95         uint8_t susage;         /* usage set flags */
96 };
97
98 /*------------------------------------------------------------------------*
99  *      hid_clear_local
100  *------------------------------------------------------------------------*/
101 static void
102 hid_clear_local(struct hid_item *c)
103 {
104
105         c->loc.count = 0;
106         c->loc.size = 0;
107         c->usage = 0;
108         c->usage_minimum = 0;
109         c->usage_maximum = 0;
110         c->designator_index = 0;
111         c->designator_minimum = 0;
112         c->designator_maximum = 0;
113         c->string_index = 0;
114         c->string_minimum = 0;
115         c->string_maximum = 0;
116         c->set_delimiter = 0;
117 }
118
119 static void
120 hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
121 {
122         uint8_t i;
123
124         /* check for same report ID - optimise */
125
126         if (c->report_ID == next_rID)
127                 return;
128
129         /* save current position for current rID */
130
131         if (c->report_ID == 0) {
132                 i = 0;
133         } else {
134                 for (i = 1; i != MAXID; i++) {
135                         if (s->last_pos[i].rid == c->report_ID)
136                                 break;
137                         if (s->last_pos[i].rid == 0)
138                                 break;
139                 }
140         }
141         if (i != MAXID) {
142                 s->last_pos[i].rid = c->report_ID;
143                 s->last_pos[i].pos = c->loc.pos;
144         }
145
146         /* store next report ID */
147
148         c->report_ID = next_rID;
149
150         /* lookup last position for next rID */
151
152         if (next_rID == 0) {
153                 i = 0;
154         } else {
155                 for (i = 1; i != MAXID; i++) {
156                         if (s->last_pos[i].rid == next_rID)
157                                 break;
158                         if (s->last_pos[i].rid == 0)
159                                 break;
160                 }
161         }
162         if (i != MAXID) {
163                 s->last_pos[i].rid = next_rID;
164                 c->loc.pos = s->last_pos[i].pos;
165         } else {
166                 DPRINTF("Out of RID entries, position is set to zero!\n");
167                 c->loc.pos = 0;
168         }
169 }
170
171 /*------------------------------------------------------------------------*
172  *      hid_start_parse
173  *------------------------------------------------------------------------*/
174 struct hid_data *
175 hid_start_parse(const void *d, usb_size_t len, int kindset)
176 {
177         struct hid_data *s;
178
179         if ((kindset-1) & kindset) {
180                 DPRINTFN(0, "Only one bit can be "
181                     "set in the kindset\n");
182                 return (NULL);
183         }
184
185         s = kmalloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
186         s->start = s->p = d;
187         s->end = ((const uint8_t *)d) + len;
188         s->kindset = kindset;
189         return (s);
190 }
191
192 /*------------------------------------------------------------------------*
193  *      hid_end_parse
194  *------------------------------------------------------------------------*/
195 void
196 hid_end_parse(struct hid_data *s)
197 {
198         if (s == NULL)
199                 return;
200
201         kfree(s, M_TEMP);
202 }
203
204 /*------------------------------------------------------------------------*
205  *      get byte from HID descriptor
206  *------------------------------------------------------------------------*/
207 static uint8_t
208 hid_get_byte(struct hid_data *s, const uint16_t wSize)
209 {
210         const uint8_t *ptr;
211         uint8_t retval;
212
213         ptr = s->p;
214
215         /* check if end is reached */
216         if (ptr == s->end)
217                 return (0);
218
219         /* read out a byte */
220         retval = *ptr;
221
222         /* check if data pointer can be advanced by "wSize" bytes */
223         if ((s->end - ptr) < wSize)
224                 ptr = s->end;
225         else
226                 ptr += wSize;
227
228         /* update pointer */
229         s->p = ptr;
230
231         return (retval);
232 }
233
234 /*------------------------------------------------------------------------*
235  *      hid_get_item
236  *------------------------------------------------------------------------*/
237 int
238 hid_get_item(struct hid_data *s, struct hid_item *h)
239 {
240         struct hid_item *c;
241         unsigned int bTag, bType, bSize;
242         uint32_t oldpos;
243         int32_t mask;
244         int32_t dval;
245
246         if (s == NULL)
247                 return (0);
248
249         c = &s->cur[s->pushlevel];
250
251  top:
252         /* check if there is an array of items */
253         if (s->icount < s->ncount) {
254                 /* get current usage */
255                 if (s->iusage < s->nusage) {
256                         dval = s->usages_min[s->iusage] + s->ousage;
257                         c->usage = dval;
258                         s->usage_last = dval;
259                         if (dval == s->usages_max[s->iusage]) {
260                                 s->iusage ++;
261                                 s->ousage = 0;
262                         } else {
263                                 s->ousage ++;
264                         }
265                 } else {
266                         DPRINTFN(1, "Using last usage\n");
267                         dval = s->usage_last;
268                 }
269                 s->icount ++;
270                 /* 
271                  * Only copy HID item, increment position and return
272                  * if correct kindset!
273                  */
274                 if (s->kindset & (1 << c->kind)) {
275                         *h = *c;
276                         DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
277                             h->loc.size, h->loc.count);
278                         c->loc.pos += c->loc.size * c->loc.count;
279                         return (1);
280                 }
281         }
282
283         /* reset state variables */
284         s->icount = 0;
285         s->ncount = 0;
286         s->iusage = 0;
287         s->nusage = 0;
288         s->susage = 0;
289         s->ousage = 0;
290         hid_clear_local(c);
291
292         /* get next item */
293         while (s->p != s->end) {
294
295                 bSize = hid_get_byte(s, 1);
296                 if (bSize == 0xfe) {
297                         /* long item */
298                         bSize = hid_get_byte(s, 1);
299                         bSize |= hid_get_byte(s, 1) << 8;
300                         bTag = hid_get_byte(s, 1);
301                         bType = 0xff;   /* XXX what should it be */
302                 } else {
303                         /* short item */
304                         bTag = bSize >> 4;
305                         bType = (bSize >> 2) & 3;
306                         bSize &= 3;
307                         if (bSize == 3)
308                                 bSize = 4;
309                 }
310                 switch (bSize) {
311                 case 0:
312                         dval = 0;
313                         mask = 0;
314                         break;
315                 case 1:
316                         dval = (int8_t)hid_get_byte(s, 1);
317                         mask = 0xFF;
318                         break;
319                 case 2:
320                         dval = hid_get_byte(s, 1);
321                         dval |= hid_get_byte(s, 1) << 8;
322                         dval = (int16_t)dval;
323                         mask = 0xFFFF;
324                         break;
325                 case 4:
326                         dval = hid_get_byte(s, 1);
327                         dval |= hid_get_byte(s, 1) << 8;
328                         dval |= hid_get_byte(s, 1) << 16;
329                         dval |= hid_get_byte(s, 1) << 24;
330                         mask = 0xFFFFFFFF;
331                         break;
332                 default:
333                         dval = hid_get_byte(s, bSize);
334                         DPRINTFN(0, "bad length %u (data=0x%02x)\n",
335                             bSize, dval);
336                         continue;
337                 }
338
339                 switch (bType) {
340                 case 0:         /* Main */
341                         switch (bTag) {
342                         case 8: /* Input */
343                                 c->kind = hid_input;
344                                 c->flags = dval;
345                 ret:
346                                 c->loc.count = s->loc_count;
347                                 c->loc.size = s->loc_size;
348
349                                 if (c->flags & HIO_VARIABLE) {
350                                         /* range check usage count */
351                                         if (c->loc.count > 255) {
352                                                 DPRINTFN(0, "Number of "
353                                                     "items truncated to 255\n");
354                                                 s->ncount = 255;
355                                         } else
356                                                 s->ncount = c->loc.count;
357
358                                         /* 
359                                          * The "top" loop will return
360                                          * one and one item:
361                                          */
362                                         c->loc.count = 1;
363                                 } else {
364                                         s->ncount = 1;
365                                 }
366                                 goto top;
367
368                         case 9: /* Output */
369                                 c->kind = hid_output;
370                                 c->flags = dval;
371                                 goto ret;
372                         case 10:        /* Collection */
373                                 c->kind = hid_collection;
374                                 c->collection = dval;
375                                 c->collevel++;
376                                 c->usage = s->usage_last;
377                                 *h = *c;
378                                 return (1);
379                         case 11:        /* Feature */
380                                 c->kind = hid_feature;
381                                 c->flags = dval;
382                                 goto ret;
383                         case 12:        /* End collection */
384                                 c->kind = hid_endcollection;
385                                 if (c->collevel == 0) {
386                                         DPRINTFN(0, "invalid end collection\n");
387                                         return (0);
388                                 }
389                                 c->collevel--;
390                                 *h = *c;
391                                 return (1);
392                         default:
393                                 DPRINTFN(0, "Main bTag=%d\n", bTag);
394                                 break;
395                         }
396                         break;
397                 case 1:         /* Global */
398                         switch (bTag) {
399                         case 0:
400                                 c->_usage_page = dval << 16;
401                                 break;
402                         case 1:
403                                 c->logical_minimum = dval;
404                                 break;
405                         case 2:
406                                 c->logical_maximum = dval;
407                                 break;
408                         case 3:
409                                 c->physical_minimum = dval;
410                                 break;
411                         case 4:
412                                 c->physical_maximum = dval;
413                                 break;
414                         case 5:
415                                 c->unit_exponent = dval;
416                                 break;
417                         case 6:
418                                 c->unit = dval;
419                                 break;
420                         case 7:
421                                 /* mask because value is unsigned */
422                                 s->loc_size = dval & mask;
423                                 break;
424                         case 8:
425                                 hid_switch_rid(s, c, dval & mask);
426                                 break;
427                         case 9:
428                                 /* mask because value is unsigned */
429                                 s->loc_count = dval & mask;
430                                 break;
431                         case 10:        /* Push */
432                                 s->pushlevel ++;
433                                 if (s->pushlevel < MAXPUSH) {
434                                         s->cur[s->pushlevel] = *c;
435                                         /* store size and count */
436                                         c->loc.size = s->loc_size;
437                                         c->loc.count = s->loc_count;
438                                         /* update current item pointer */
439                                         c = &s->cur[s->pushlevel];
440                                 } else {
441                                         DPRINTFN(0, "Cannot push "
442                                             "item @ %d\n", s->pushlevel);
443                                 }
444                                 break;
445                         case 11:        /* Pop */
446                                 s->pushlevel --;
447                                 if (s->pushlevel < MAXPUSH) {
448                                         /* preserve position */
449                                         oldpos = c->loc.pos;
450                                         c = &s->cur[s->pushlevel];
451                                         /* restore size and count */
452                                         s->loc_size = c->loc.size;
453                                         s->loc_count = c->loc.count;
454                                         /* set default item location */
455                                         c->loc.pos = oldpos;
456                                         c->loc.size = 0;
457                                         c->loc.count = 0;
458                                 } else {
459                                         DPRINTFN(0, "Cannot pop "
460                                             "item @ %d\n", s->pushlevel);
461                                 }
462                                 break;
463                         default:
464                                 DPRINTFN(0, "Global bTag=%d\n", bTag);
465                                 break;
466                         }
467                         break;
468                 case 2:         /* Local */
469                         switch (bTag) {
470                         case 0:
471                                 if (bSize != 4)
472                                         dval = (dval & mask) | c->_usage_page;
473
474                                 /* set last usage, in case of a collection */
475                                 s->usage_last = dval;
476
477                                 if (s->nusage < MAXUSAGE) {
478                                         s->usages_min[s->nusage] = dval;
479                                         s->usages_max[s->nusage] = dval;
480                                         s->nusage ++;
481                                 } else {
482                                         DPRINTFN(0, "max usage reached\n");
483                                 }
484
485                                 /* clear any pending usage sets */
486                                 s->susage = 0;
487                                 break;
488                         case 1:
489                                 s->susage |= 1;
490
491                                 if (bSize != 4)
492                                         dval = (dval & mask) | c->_usage_page;
493                                 c->usage_minimum = dval;
494
495                                 goto check_set;
496                         case 2:
497                                 s->susage |= 2;
498
499                                 if (bSize != 4)
500                                         dval = (dval & mask) | c->_usage_page;
501                                 c->usage_maximum = dval;
502
503                         check_set:
504                                 if (s->susage != 3)
505                                         break;
506
507                                 /* sanity check */
508                                 if ((s->nusage < MAXUSAGE) &&
509                                     (c->usage_minimum <= c->usage_maximum)) {
510                                         /* add usage range */
511                                         s->usages_min[s->nusage] = 
512                                             c->usage_minimum;
513                                         s->usages_max[s->nusage] = 
514                                             c->usage_maximum;
515                                         s->nusage ++;
516                                 } else {
517                                         DPRINTFN(0, "Usage set dropped\n");
518                                 }
519                                 s->susage = 0;
520                                 break;
521                         case 3:
522                                 c->designator_index = dval;
523                                 break;
524                         case 4:
525                                 c->designator_minimum = dval;
526                                 break;
527                         case 5:
528                                 c->designator_maximum = dval;
529                                 break;
530                         case 7:
531                                 c->string_index = dval;
532                                 break;
533                         case 8:
534                                 c->string_minimum = dval;
535                                 break;
536                         case 9:
537                                 c->string_maximum = dval;
538                                 break;
539                         case 10:
540                                 c->set_delimiter = dval;
541                                 break;
542                         default:
543                                 DPRINTFN(0, "Local bTag=%d\n", bTag);
544                                 break;
545                         }
546                         break;
547                 default:
548                         DPRINTFN(0, "default bType=%d\n", bType);
549                         break;
550                 }
551         }
552         return (0);
553 }
554
555 /*------------------------------------------------------------------------*
556  *      hid_report_size
557  *------------------------------------------------------------------------*/
558 int
559 hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
560 {
561         struct hid_data *d;
562         struct hid_item h;
563         uint32_t temp;
564         uint32_t hpos;
565         uint32_t lpos;
566         uint8_t any_id;
567
568         any_id = 0;
569         hpos = 0;
570         lpos = 0xFFFFFFFF;
571
572         for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
573                 if (h.kind == k) {
574                         /* check for ID-byte presense */
575                         if ((h.report_ID != 0) && !any_id) {
576                                 if (id != NULL)
577                                         *id = h.report_ID;
578                                 any_id = 1;
579                         }
580                         /* compute minimum */
581                         if (lpos > h.loc.pos)
582                                 lpos = h.loc.pos;
583                         /* compute end position */
584                         temp = h.loc.pos + (h.loc.size * h.loc.count);
585                         /* compute maximum */
586                         if (hpos < temp)
587                                 hpos = temp;
588                 }
589         }
590         hid_end_parse(d);
591
592         /* safety check - can happen in case of currupt descriptors */
593         if (lpos > hpos)
594                 temp = 0;
595         else
596                 temp = hpos - lpos;
597
598         /* check for ID byte */
599         if (any_id)
600                 temp += 8;
601         else if (id != NULL)
602                 *id = 0;
603
604         /* return length in bytes rounded up */
605         return ((temp + 7) / 8);
606 }
607
608 /*------------------------------------------------------------------------*
609  *      hid_locate
610  *------------------------------------------------------------------------*/
611 int
612 hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k,
613     uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
614 {
615         struct hid_data *d;
616         struct hid_item h;
617
618         for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
619                 if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
620                         if (index--)
621                                 continue;
622                         if (loc != NULL)
623                                 *loc = h.loc;
624                         if (flags != NULL)
625                                 *flags = h.flags;
626                         if (id != NULL)
627                                 *id = h.report_ID;
628                         hid_end_parse(d);
629                         return (1);
630                 }
631         }
632         if (loc != NULL)
633                 loc->size = 0;
634         if (flags != NULL)
635                 *flags = 0;
636         if (id != NULL)
637                 *id = 0;
638         hid_end_parse(d);
639         return (0);
640 }
641
642 /*------------------------------------------------------------------------*
643  *      hid_get_data
644  *------------------------------------------------------------------------*/
645 static uint32_t
646 hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc,
647     int is_signed)
648 {
649         uint32_t hpos = loc->pos;
650         uint32_t hsize = loc->size;
651         uint32_t data;
652         uint32_t rpos;
653         uint8_t n;
654
655         DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
656
657         /* Range check and limit */
658         if (hsize == 0)
659                 return (0);
660         if (hsize > 32)
661                 hsize = 32;
662
663         /* Get data in a safe way */
664         data = 0;
665         rpos = (hpos / 8);
666         n = (hsize + 7) / 8;
667         rpos += n;
668         while (n--) {
669                 rpos--;
670                 if (rpos < len)
671                         data |= buf[rpos] << (8 * n);
672         }
673
674         /* Correctly shift down data */
675         data = (data >> (hpos % 8));
676         n = 32 - hsize;
677
678         /* Mask and sign extend in one */
679         if (is_signed != 0)
680                 data = (int32_t)((int32_t)data << n) >> n;
681         else
682                 data = (uint32_t)((uint32_t)data << n) >> n;
683
684         DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
685             loc->pos, loc->size, (long)data);
686         return (data);
687 }
688
689 int32_t
690 hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
691 {
692         return (hid_get_data_sub(buf, len, loc, 1));
693 }
694
695 uint32_t
696 hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
697 {
698         return (hid_get_data_sub(buf, len, loc, 0));
699 }
700
701 /*------------------------------------------------------------------------*
702  *      hid_put_data
703  *------------------------------------------------------------------------*/
704 void
705 hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
706     struct hid_location *loc, unsigned int value)
707 {
708         uint32_t hpos = loc->pos;
709         uint32_t hsize = loc->size;
710         uint64_t data;
711         uint64_t mask;
712         uint32_t rpos;
713         uint8_t n;
714
715         DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
716
717         /* Range check and limit */
718         if (hsize == 0)
719                 return;
720         if (hsize > 32)
721                 hsize = 32;
722
723         /* Put data in a safe way */
724         rpos = (hpos / 8);
725         n = (hsize + 7) / 8;
726         data = ((uint64_t)value) << (hpos % 8);
727         mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
728         rpos += n;
729         while (n--) {
730                 rpos--;
731                 if (rpos < len) {
732                         buf[rpos] &= ~(mask >> (8 * n));
733                         buf[rpos] |= (data >> (8 * n));
734                 }
735         }
736 }
737
738 /*------------------------------------------------------------------------*
739  *      hid_is_collection
740  *------------------------------------------------------------------------*/
741 int
742 hid_is_collection(const void *desc, usb_size_t size, int32_t usage)
743 {
744         struct hid_data *hd;
745         struct hid_item hi;
746         int err;
747
748         hd = hid_start_parse(desc, size, hid_input);
749         if (hd == NULL)
750                 return (0);
751
752         while ((err = hid_get_item(hd, &hi))) {
753                  if (hi.kind == hid_collection &&
754                      hi.usage == usage)
755                         break;
756         }
757         hid_end_parse(hd);
758         return (err);
759 }
760
761 /*------------------------------------------------------------------------*
762  *      hid_get_descriptor_from_usb
763  *
764  * This function will search for a HID descriptor between two USB
765  * interface descriptors.
766  *
767  * Return values:
768  * NULL: No more HID descriptors.
769  * Else: Pointer to HID descriptor.
770  *------------------------------------------------------------------------*/
771 struct usb_hid_descriptor *
772 hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
773     struct usb_interface_descriptor *id)
774 {
775         struct usb_descriptor *desc = (void *)id;
776
777         if (desc == NULL) {
778                 return (NULL);
779         }
780         while ((desc = usb_desc_foreach(cd, desc))) {
781                 if ((desc->bDescriptorType == UDESC_HID) &&
782                     (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
783                         return (void *)desc;
784                 }
785                 if (desc->bDescriptorType == UDESC_INTERFACE) {
786                         break;
787                 }
788         }
789         return (NULL);
790 }
791
792 /*------------------------------------------------------------------------*
793  *      usbd_req_get_hid_desc
794  *
795  * This function will read out an USB report descriptor from the USB
796  * device.
797  *
798  * Return values:
799  * NULL: Failure.
800  * Else: Success. The pointer should eventually be passed to free().
801  *------------------------------------------------------------------------*/
802 usb_error_t
803 usbd_req_get_hid_desc(struct usb_device *udev, struct lock *lock,
804     void **descp, uint16_t *sizep,
805     struct malloc_type *mem, uint8_t iface_index)
806 {
807         struct usb_interface *iface = usbd_get_iface(udev, iface_index);
808         struct usb_hid_descriptor *hid;
809         usb_error_t err;
810
811         if ((iface == NULL) || (iface->idesc == NULL)) {
812                 return (USB_ERR_INVAL);
813         }
814         hid = hid_get_descriptor_from_usb
815             (usbd_get_config_descriptor(udev), iface->idesc);
816
817         if (hid == NULL) {
818                 return (USB_ERR_IOERROR);
819         }
820         *sizep = UGETW(hid->descrs[0].wDescriptorLength);
821         if (*sizep == 0) {
822                 return (USB_ERR_IOERROR);
823         }
824         if (lock)
825                 lockmgr(lock, LK_RELEASE);
826
827         *descp = kmalloc(*sizep, mem, M_ZERO | M_WAITOK);
828
829         if (lock)
830                 lockmgr(lock, LK_EXCLUSIVE);
831
832         if (*descp == NULL) {
833                 return (USB_ERR_NOMEM);
834         }
835         err = usbd_req_get_report_descriptor
836             (udev, lock, *descp, *sizep, iface_index);
837
838         if (err) {
839                 kfree(*descp, mem);
840                 *descp = NULL;
841                 return (err);
842         }
843         return (USB_ERR_NORMAL_COMPLETION);
844 }
845
846 /*------------------------------------------------------------------------*
847  *      hid_is_mouse
848  *
849  * This function will decide if a USB descriptor belongs to a USB mouse.
850  *
851  * Return values:
852  * Zero: Not a USB mouse.
853  * Else: Is a USB mouse.
854  *------------------------------------------------------------------------*/
855 int
856 hid_is_mouse(const void *d_ptr, uint16_t d_len)
857 {
858         struct hid_data *hd;
859         struct hid_item hi;
860         int mdepth;
861         int found;
862
863         hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
864         if (hd == NULL)
865                 return (0);
866
867         mdepth = 0;
868         found = 0;
869
870         while (hid_get_item(hd, &hi)) {
871                 switch (hi.kind) {
872                 case hid_collection:
873                         if (mdepth != 0)
874                                 mdepth++;
875                         else if (hi.collection == 1 &&
876                              hi.usage ==
877                               HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
878                                 mdepth++;
879                         break;
880                 case hid_endcollection:
881                         if (mdepth != 0)
882                                 mdepth--;
883                         break;
884                 case hid_input:
885                         if (mdepth == 0)
886                                 break;
887                         if (hi.usage ==
888                              HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
889                             (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
890                                 found++;
891                         if (hi.usage ==
892                              HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
893                             (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
894                                 found++;
895                         break;
896                 default:
897                         break;
898                 }
899         }
900         hid_end_parse(hd);
901         return (found);
902 }
903
904 /*------------------------------------------------------------------------*
905  *      hid_is_keyboard
906  *
907  * This function will decide if a USB descriptor belongs to a USB keyboard.
908  *
909  * Return values:
910  * Zero: Not a USB keyboard.
911  * Else: Is a USB keyboard.
912  *------------------------------------------------------------------------*/
913 int
914 hid_is_keyboard(const void *d_ptr, uint16_t d_len)
915 {
916         if (hid_is_collection(d_ptr, d_len,
917             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
918                 return (1);
919         return (0);
920 }