source: rtems-libbsd/freebsd/sys/dev/usb/usb_hid.c @ 8e65e1b

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 8e65e1b was 8e65e1b, checked in by Sebastian Huber <sebastian.huber@…>, on 08/23/16 at 13:51:45

usb: Update to FreeBSD trunk 2016-08-23

FreeBSD trunk, 2016-08-23, 9fe7c416e6abb28b1398fd3e5687099846800cfd.

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