source: rtems-libbsd/freebsd/sys/dev/usb/usb_hid.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

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