1/*
2 * \brief This file contains class specific functions for human interface
3 *        devices such as keyboard and mouse
4 *
5 *        USB Device Class 0x03
6 * ===========================================================================
7 */
8
9/*
10 * Copyright (c) 2007-2013 ETH Zurich.
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
16 */
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <barrelfish/barrelfish.h>
22
23#include <usb/usb.h>
24#include <usb/usb_request.h>
25#include <usb/usb_device.h>
26#include <usb/usb_parse.h>
27#include <usb/class/usb_hid.h>
28
29/**
30 * \brief   clears out the local data of a HID item descriptor
31 */
32static void usb_hid_item_clear_local(struct usb_hid_item *c)
33{
34    c->loc.count = 0;
35    c->loc.size = 0;
36    c->usage = 0;
37    c->usage_minimum = 0;
38    c->usage_maximum = 0;
39    c->designator_index = 0;
40    c->designator_minimum = 0;
41    c->designator_maximum = 0;
42    c->string_index = 0;
43    c->string_minimum = 0;
44    c->string_maximum = 0;
45    c->set_delimiter = 0;
46}
47
48/**
49 * \brief this function switches the report ID of an hid item with the
50 *        new value
51 *
52 * \param s the current HID data
53 * \param c the current HID item
54 * \param next_rID the report id to set
55 */
56static void usb_hid_switch_reportid(struct usb_hid_data *s,
57        struct usb_hid_item *c, int32_t next_rID)
58{
59    uint8_t i;
60
61    /* check for same report ID - optimize */
62
63    if (c->report_ID == next_rID)
64        return;
65
66    /* save current position for current rID */
67
68    if (c->report_ID == 0) {
69        i = 0;
70    } else {
71        for (i = 1; i != USB_HID_MAXID; i++) {
72            if (s->last_pos[i].rid == c->report_ID)
73                break;
74            if (s->last_pos[i].rid == 0)
75                break;
76        }
77    }
78    if (i != USB_HID_MAXID) {
79        s->last_pos[i].rid = c->report_ID;
80        s->last_pos[i].position = c->loc.position;
81    }
82
83    /* store next report ID */
84
85    c->report_ID = next_rID;
86
87    /* lookup last position for next rID */
88
89    if (next_rID == 0) {
90        i = 0;
91    } else {
92        for (i = 1; i != USB_HID_MAXID; i++) {
93            if (s->last_pos[i].rid == next_rID)
94                break;
95            if (s->last_pos[i].rid == 0)
96                break;
97        }
98    }
99    if (i != USB_HID_MAXID) {
100        s->last_pos[i].rid = next_rID;
101        c->loc.position = s->last_pos[i].position;
102    } else {
103        debug_printf("Out of RID entries, position is set to zero!\n");
104        c->loc.position = 0;
105    }
106}
107
108/**
109 * \brief   allocates a new usb_hid_data structure for parsing the USB HID
110 *          reports
111 *
112 * \param   d       initial data pointer
113 * \param   len     length of the data
114 * \param   kindset the kindset
115 *
116 * \return  pointer to the usb_hid_data structure on sucess
117 *          NULL on failure
118 */
119struct usb_hid_data *usb_hid_start_parse(const void *d, uint32_t len,
120        int32_t kindset)
121{
122    struct usb_hid_data *s;
123
124    if ((kindset - 1) & kindset) {
125        debug_printf("WARNING: Only one bit can be set in the kindset\n");
126        return (NULL);
127    }
128
129    s = malloc(sizeof(*s));
130    memset(s, 0, sizeof(*s));
131    s->start = s->p = d;
132    s->end = ((const uint8_t *) d) + len;
133    s->kindset = kindset;
134    return (s);
135}
136
137/**
138 * \brief   frees up the usb_hid_data structure from parsiDPRINTFNng the report
139 *          descriptor
140 *
141 * \param   s   the usb_hid_data structure to be freed
142 */
143void usb_hid_end_parse(struct usb_hid_data *s)
144{
145    if (s == NULL)
146        return;
147
148    free(s);
149}
150
151/**
152 * \brief   gets the next byte when parsing the USB HID report descriptor
153 *
154 * \param   s       pointer to the parsing state
155 * \param   wSize   bytes to advance the data pointer
156 *
157 * \return  the next byte on success
158 *          0 on failure
159 */
160static uint8_t usb_hid_get_byte(struct usb_hid_data *s, const uint16_t wSize)
161{
162    const uint8_t *ptr;
163    uint8_t retval;
164
165    ptr = s->p;
166
167    /* check if end is reached */
168    if (ptr == s->end)
169        return (0);
170
171    /* read out a byte */
172    retval = *ptr;
173
174    /* check if data pointer can be advanced by "wSize" bytes */
175    if ((s->end - ptr) < wSize)
176        ptr = s->end;
177    else
178        ptr += wSize;
179
180    /* update pointer */
181    s->p = ptr;
182
183    return (retval);
184}
185
186/**
187 * \brief   this function gets the the next usb_hid_item from the report
188 *          descriptor according to the current parsing state
189 *
190 * \param   s   the current parsing state
191 * \param   h   pointer where to store the returned data
192 *
193 * \return  0: on failure
194 *          1: on success
195 */
196int32_t usb_hid_get_item(struct usb_hid_data *s, struct usb_hid_item *h)
197{
198    struct usb_hid_item *c;
199    uint32_t bTag, bType, bSize;
200    uint32_t oldpos;
201    int32_t mask;
202    int32_t dval;
203
204    if (s == NULL)
205        return (0);
206
207    c = &s->cur[s->pushlevel];
208
209    top:
210    /* check if there is an array of items */
211    if (s->icount < s->ncount) {
212        /* get current usage */
213        if (s->iusage < s->nusage) {
214            dval = s->usages_min[s->iusage] + s->ousage;
215            c->usage = dval;
216            s->usage_last = dval;
217            if (dval == s->usages_max[s->iusage]) {
218                s->iusage++;
219                s->ousage = 0;
220            } else {
221                s->ousage++;
222            }
223        } else {
224            dval = s->usage_last;
225        }
226        s->icount++;
227        /*
228         * Only copy HID item, increment position and return
229         * if correct kindset!
230         */
231        if (s->kindset & (1 << c->kind)) {
232            *h = *c;
233            c->loc.position += c->loc.size * c->loc.count;
234            return (1);
235        }
236    }
237
238    /* reset state variables */
239    s->icount = 0;
240    s->ncount = 0;
241    s->iusage = 0;
242    s->nusage = 0;
243    s->susage = 0;
244    s->ousage = 0;
245    usb_hid_item_clear_local(c);
246
247    /* get next item */
248    while (s->p != s->end) {
249
250        bSize = usb_hid_get_byte(s, 1);
251        if (bSize == 0xfe) {
252            /* long item */
253            bSize = usb_hid_get_byte(s, 1);
254            bSize |= usb_hid_get_byte(s, 1) << 8;
255            bTag = usb_hid_get_byte(s, 1);
256            bType = 0xff; /* XXX what should it be */
257        } else {
258            /* short item */
259            bTag = bSize >> 4;
260            bType = (bSize >> 2) & 3;
261            bSize &= 3;
262            if (bSize == 3)
263                bSize = 4;
264        }
265        switch (bSize) {
266            case 0:
267                dval = 0;
268                mask = 0;
269                break;
270            case 1:
271                dval = (int8_t) usb_hid_get_byte(s, 1);
272                mask = 0xFF;
273                break;
274            case 2:
275                dval = usb_hid_get_byte(s, 1);
276                dval |= usb_hid_get_byte(s, 1) << 8;
277                dval = (int16_t) dval;
278                mask = 0xFFFF;
279                break;
280            case 4:
281                dval = usb_hid_get_byte(s, 1);
282                dval |= usb_hid_get_byte(s, 1) << 8;
283                dval |= usb_hid_get_byte(s, 1) << 16;
284                dval |= usb_hid_get_byte(s, 1) << 24;
285                mask = 0xFFFFFFFF;
286                break;
287            default:
288                dval = usb_hid_get_byte(s, bSize);
289                USB_DEBUG("bad length %"PRIu32" (data=0x%02"PRId32")\n", bSize, dval);
290                continue;
291        }
292
293        switch (bType) {
294            case 0: /* Main */
295                switch (bTag) {
296                    case 8: /* Input */
297                        c->kind = USB_HID_KIND_INPUT;
298                        c->flags = dval;
299                        ret: c->loc.count = s->loc_count;
300                        c->loc.size = s->loc_size;
301
302                        if (c->flags & USB_HID_IO_VARIABLE) {
303                            /* range check usage count */
304                            if (c->loc.count > 255) {
305                                USB_DEBUG("Number of "
306                                "items truncated to 255\n");
307                                s->ncount = 255;
308                            } else
309                                s->ncount = c->loc.count;
310
311                            /*
312                             * The "top" loop will return
313                             * one and one item:
314                             */
315                            c->loc.count = 1;
316                        } else {
317                            s->ncount = 1;
318                        }
319                        goto top;
320
321                    case 9: /* Output */
322                        c->kind = USB_HID_KIND_OUTPUT;
323                        c->flags = dval;
324                        goto ret;
325                    case 10: /* Collection */
326                        c->kind = USB_HID_KIND_COLLECTION;
327                        c->collection = dval;
328                        c->collevel++;
329                        c->usage = s->usage_last;
330                        *h = *c;
331                        return (1);
332                    case 11: /* Feature */
333                        c->kind = USB_HID_KIND_FEATURE;
334                        c->flags = dval;
335                        goto ret;
336                    case 12: /* End collection */
337                        c->kind = USB_HID_KIND_ENDCOLLECTION;
338                        if (c->collevel == 0) {
339                            USB_DEBUG("invalid end collection\n");
340                            return (0);
341                        }
342                        c->collevel--;
343                        *h = *c;
344                        return (1);
345                    default:
346                        /* noop */
347                        break;
348                }
349                break;
350            case 1: /* Global */
351                switch (bTag) {
352                    case 0:
353                        c->_usage_page = dval << 16;
354                        break;
355                    case 1:
356                        c->logical_minimum = dval;
357                        break;
358                    case 2:
359                        c->logical_maximum = dval;
360                        break;
361                    case 3:
362                        c->physical_minimum = dval;
363                        break;
364                    case 4:
365                        c->physical_maximum = dval;
366                        break;
367                    case 5:
368                        c->unit_exponent = dval;
369                        break;
370                    case 6:
371                        c->unit = dval;
372                        break;
373                    case 7:
374                        /* mask because value is unsigned */
375                        s->loc_size = dval & mask;
376                        break;
377                    case 8:
378                        usb_hid_switch_reportid(s, c, dval);
379                        break;
380                    case 9:
381                        /* mask because value is unsigned */
382                        s->loc_count = dval & mask;
383                        break;
384                    case 10: /* Push */
385                        s->pushlevel++;
386                        if (s->pushlevel < USB_HID_MAXPUSH) {
387                            s->cur[s->pushlevel] = *c;
388                            /* store size and count */
389                            c->loc.size = s->loc_size;
390                            c->loc.count = s->loc_count;
391                            /* update current item pointer */
392                            c = &s->cur[s->pushlevel];
393                        } else {
394                            USB_DEBUG("Cannot push "
395                            "item @ %d\n", s->pushlevel);
396                        }
397                        break;
398                    case 11: /* Pop */
399                        s->pushlevel--;
400                        if (s->pushlevel < USB_HID_MAXPUSH) {
401                            /* preserve position */
402                            oldpos = c->loc.position;
403                            c = &s->cur[s->pushlevel];
404                            /* restore size and count */
405                            s->loc_size = c->loc.size;
406                            s->loc_count = c->loc.count;
407                            /* set default item location */
408                            c->loc.position = oldpos;
409                            c->loc.size = 0;
410                            c->loc.count = 0;
411                        } else {
412                            USB_DEBUG("Cannot pop "
413                            "item @ %d\n", s->pushlevel);
414                        }
415                        break;
416                    default:
417                        /* noop */
418                        break;
419                }
420                break;
421            case 2: /* Local */
422                switch (bTag) {
423                    case 0:
424                        if (bSize != 4)
425                            dval = (dval & mask) | c->_usage_page;
426
427                        /* set last usage, in case of a collection */
428                        s->usage_last = dval;
429
430                        if (s->nusage < USB_HID_MAXUSAGE) {
431                            s->usages_min[s->nusage] = dval;
432                            s->usages_max[s->nusage] = dval;
433                            s->nusage++;
434                        } else {
435                            USB_DEBUG("max usage reached\n");
436                        }
437
438                        /* clear any pending usage sets */
439                        s->susage = 0;
440                        break;
441                    case 1:
442                        s->susage |= 1;
443
444                        if (bSize != 4)
445                            dval = (dval & mask) | c->_usage_page;
446                        c->usage_minimum = dval;
447
448                        goto check_set;
449                    case 2:
450                        s->susage |= 2;
451
452                        if (bSize != 4)
453                            dval = (dval & mask) | c->_usage_page;
454                        c->usage_maximum = dval;
455
456                        check_set: if (s->susage != 3)
457                            break;
458
459                        /* sanity check */
460                        if ((s->nusage < USB_HID_MAXUSAGE)
461                                && (c->usage_minimum <= c->usage_maximum)) {
462                            /* add usage range */
463                            s->usages_min[s->nusage] = c->usage_minimum;
464                            s->usages_max[s->nusage] = c->usage_maximum;
465                            s->nusage++;
466                        } else {
467                            USB_DEBUG("Usage set dropped\n");
468                        }
469                        s->susage = 0;
470                        break;
471                    case 3:
472                        c->designator_index = dval;
473                        break;
474                    case 4:
475                        c->designator_minimum = dval;
476                        break;
477                    case 5:
478                        c->designator_maximum = dval;
479                        break;
480                    case 7:
481                        c->string_index = dval;
482                        break;
483                    case 8:
484                        c->string_minimum = dval;
485                        break;
486                    case 9:
487                        c->string_maximum = dval;
488                        break;
489                    case 10:
490                        c->set_delimiter = dval;
491                        break;
492                    default:
493                        /* noop */
494                        break;
495                }
496                break;
497            default:
498                /* noop */
499                break;
500        }
501    }
502    return (0);
503}
504
505/**
506 * \brief       calculates the size of the USB HID report descriptor
507 *
508 * \param buf   pointer to the buffer containing the data to parse
509 * \param len   the length of the data in the buffer
510 * \param k     the kind of the report descriptor we want to get the size of
511 * \param id    the id of the descriptor we want to get
512 *
513 * \return      the length of the report in bytes
514 */
515int32_t usb_hid_report_size(const void *buf, uint32_t len, enum usb_hid_kind k,
516        uint8_t *id)
517{
518    struct usb_hid_data *d;
519    struct usb_hid_item h;
520    uint32_t temp;
521    uint32_t hpos;
522    uint32_t lpos;
523    uint8_t any_id;
524
525    any_id = 0;
526    hpos = 0;
527    lpos = 0xFFFFFFFF;
528
529    for (d = usb_hid_start_parse(buf, len, 1 << k); usb_hid_get_item(d, &h);) {
530        if (h.kind == k) {
531            /* check for ID-byte presence */
532            if ((h.report_ID != 0) && !any_id) {
533                if (id != NULL)
534                    *id = h.report_ID;
535                any_id = 1;
536            }
537            /* compute minimum */
538            if (lpos > h.loc.position)
539                lpos = h.loc.position;
540            /* compute end position */
541            temp = h.loc.position + (h.loc.size * h.loc.count);
542            /* compute maximum */
543            if (hpos < temp)
544                hpos = temp;
545        }
546    }
547    usb_hid_end_parse(d);
548
549    /* safety check - can happen in case of currupt descriptors */
550    if (lpos > hpos)
551        temp = 0;
552    else
553        temp = hpos - lpos;
554
555    /* check for ID byte */
556    if (any_id)
557        temp += 8;
558    else if (id != NULL)
559        *id = 0;
560
561    /* return length in bytes rounded up */
562    return ((temp + 7) / 8);
563}
564
565/**
566 * \brief
567 *
568 * \param desc  the pointer to the report descriptor descriptor
569 * \param size  the size of the descriptor
570 * \param u     the usage
571 * \param k     the kind of the report item we want to locate
572 * \param index the index of the report with kind k we want to locate
573 * \param loc   the returned location
574 * \param flags the returned flags
575 * \param id    the returned id
576 *
577 * \return  0: there is no matching element
578 *          Else: there is a matching element found at location loc
579 */
580int32_t usb_hid_locate(const void *desc, uint32_t size, uint32_t usage,
581        enum usb_hid_kind k, uint8_t repindex, struct usb_hid_location *loc,
582        uint32_t *flags, uint8_t *id)
583{
584    struct usb_hid_data *d;
585    struct usb_hid_item h;
586
587    d = usb_hid_start_parse(desc, size, 1 << k);
588
589    while (usb_hid_get_item(d, &h)) {
590        if (h.kind == k && !(h.flags & USB_HID_IO_CONST) && h.usage == usage) {
591            if (repindex--)
592                continue;
593            if (loc != NULL)
594                *loc = h.loc;
595            if (flags != NULL)
596                *flags = h.flags;
597            if (id != NULL)
598                *id = h.report_ID;
599            usb_hid_end_parse(d);
600            return (1);
601        }
602    }
603    if (loc != NULL)
604        loc->size = 0;
605    if (flags != NULL)
606        *flags = 0;
607    if (id != NULL)
608        *id = 0;
609    usb_hid_end_parse(d);
610    return (0);
611}
612
613/**
614 * \brief generic function that gets data out of some
615 *
616 * \param buf       buffer containing the data
617 * \param len       the length of the data in the buffer
618 * \param loc       the location we want to extract
619 * \param is_signed the returned data is signed or not
620 *
621 * \return  0: on failure
622 *          data: on success
623 */
624static uint32_t usb_hid_get_data_generic(const uint8_t *buf, uint32_t len,
625        struct usb_hid_location *loc, int32_t is_signed)
626{
627    uint32_t hpos = loc->position;
628    uint32_t hsize = loc->size;
629    uint32_t data;
630    uint32_t rpos;
631    uint8_t n;
632
633    /* Range check and limit */
634    if (hsize == 0)
635        return (0);
636    if (hsize > 32)
637        hsize = 32;
638
639    /* Get data in a safe way */
640    data = 0;
641    rpos = (hpos / 8);
642    n = (hsize + 7) / 8;
643    rpos += n;
644
645    while (n--) {
646        rpos--;
647        if (rpos < len) {
648            data |= buf[rpos] << (8 * n);
649        }
650    }
651
652    /* Correctly shift down data */
653    data = (data >> (hpos % 8));
654    n = 32 - hsize;
655
656    /* Mask and sign extend in one */
657    if (is_signed != 0) {
658        data = (int32_t) ((int32_t) data << n) >> n;
659    } else {
660        data = (uint32_t) ((uint32_t) data << n) >> n;
661    }
662
663    USB_DEBUG_HID("Get data generic: pos=%u, size=%u, data=%x\n", hpos, hsize, data);
664
665    return (data);
666}
667
668/**
669 * \brief   wrapper function for getting the data ouf of a report
670 *          the data returned is signed
671 *
672 * \param buf       buffer containing the data
673 * \param len       the length of the data in the buffer
674 * \param loc       the location we want to extract
675 *
676 * \return  0: on failure
677 *          data: on sucess
678 */
679int32_t usb_hid_get_data(const uint8_t *buf, uint32_t len,
680        struct usb_hid_location *loc)
681{
682    return (usb_hid_get_data_generic(buf, len, loc, 1));
683}
684
685/**
686 * \brief   wrapper function for getting the data ouf of a report
687 *          the data returned is unsigned
688 *
689 * \param buf       buffer containing the data
690 * \param len       the length of the data in the buffer
691 * \param loc       the location we want to extract
692 *
693 * \return  0: on failure
694 *          data: on sucess
695 */uint32_t usb_hid_get_data_unsigned(const uint8_t *buf, uint32_t len,
696        struct usb_hid_location *loc)
697{
698    return (usb_hid_get_data_generic(buf, len, loc, 0));
699}
700
701/*
702 * \brief inserts a data value into the report descriptor
703 *
704 * \param buf   buffer containing the report descriptor
705 * \param len   the length of the data in the buffer
706 * \param loc   the location to put in the value
707 * \param value the value to put into the report
708 */
709void usb_hid_put_data_unsigned(uint8_t *buf, uint32_t len,
710        struct usb_hid_location *loc, uint32_t value)
711{
712    uint32_t hpos = loc->position;
713    uint32_t hsize = loc->size;
714    uint64_t data;
715    uint64_t mask;
716    uint32_t rpos;
717    uint8_t n;
718
719    /* Range check and limit */
720    if (hsize == 0)
721        return;
722    if (hsize > 32)
723        hsize = 32;
724
725    /* Put data in a safe way */
726    rpos = (hpos / 8);
727    n = (hsize + 7) / 8;
728    data = ((uint64_t) value) << (hpos % 8);
729    mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
730    rpos += n;
731    while (n--) {
732        rpos--;
733        if (rpos < len) {
734            buf[rpos] &= ~(mask >> (8 * n));
735            buf[rpos] |= (data >> (8 * n));
736        }
737    }
738}
739
740/*
741 * \brief checks if the HID device is a collection or a single function device
742 *
743 * \param desc  the descriptor to analyize
744 * \param size  the size of the descriptor to analize
745 * \param usage the usage of the device
746 *
747 * \return 1: the device is a collection
748 *         0: the device is not a collection
749 */
750int32_t usb_hid_is_collection(const void *desc, uint32_t size, uint32_t usage)
751{
752    struct usb_hid_data *hd;
753    struct usb_hid_item hi;
754    int32_t err;
755
756    hd = usb_hid_start_parse(desc, size, USB_HID_KIND_INPUT);
757    if (hd == NULL)
758        return (0);
759
760    while ((err = usb_hid_get_item(hd, &hi))) {
761        if (hi.kind == USB_HID_KIND_COLLECTION && hi.usage == usage)
762            break;
763    }
764    usb_hid_end_parse(hd);
765    return (err);
766}
767
768/**
769 * \brief search for a hid descriptor in a config descriptor between two
770 *        interface descriptors
771 *
772 *
773 * \param cd the config descriptor to search
774 * \param id the interface descriptor to start searching
775 *
776 * \return  usb_hid_descriptor on success
777 *          NULL if there are moer HID descriptors
778 */
779struct usb_hid_descriptor *usb_hid_get_descriptor_from_usb(
780        struct usb_config_descriptor *cd, struct usb_interface_descriptor *id)
781{
782    struct usb_descriptor *desc = (void *) id;
783
784    if (desc == NULL) {
785        return (NULL);
786    }
787
788    while ((desc = usb_parse_next_descriptor(cd, desc))) {
789        if ((desc->bDescriptorType == USB_DESCRIPTOR_TYPE_HID)
790                && (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
791            return ((void *) desc);
792        }
793        if (desc->bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) {
794            break;
795        }
796    }
797    return (NULL);
798}
799
800/*
801 * \brief get the HID descriptor from the usb device using a USB request
802 *
803 * \param ret_desc the returned descriptor
804 * \param ret_size the returned size of the descriptor
805 * \param iface the interface number to get the idescriptor of
806 */
807usb_error_t usb_hid_get_hid_descriptor(struct usb_hid_descriptor **ret_desc,
808        uint16_t *ret_size, uint8_t iface)
809{
810    struct usb_hid_descriptor *hid;
811
812    struct usb_config_descriptor *cfg_desc = usb_device_get_cfg_desc();
813
814    hid = usb_hid_get_descriptor_from_usb(cfg_desc,
815            (struct usb_interface_descriptor *) (cfg_desc + 1));
816
817    if (hid == NULL) {
818        return (USB_ERR_IOERROR);
819    }
820
821    *ret_size = USB_HID_DTYPE_GET_LEN(hid->descriptors);
822
823    if (*ret_size == 0) {
824        return (USB_ERR_IOERROR);
825    }
826
827    if (*ret_desc == NULL) {
828        return (USB_ERR_NOMEM);
829    }
830
831    usb_error_t err = usb_hid_get_report_descriptor(ret_desc, *ret_size, iface);
832
833    if (err) {
834        *ret_desc = NULL;
835        return (err);
836    }
837
838    return (USB_ERR_OK);
839}
840
841/**
842 * \brief gets the report descriptor from the HID device
843 *
844 * \param d pointer to the report descriptror
845 * \param size the expected size of the report descriptor
846 * \param iface the interface we want to get the report of
847 */
848usb_error_t usb_hid_get_report_descriptor(struct usb_hid_descriptor **d,
849        uint16_t size, uint8_t iface)
850{
851    if (d == NULL) {
852        return (USB_ERR_INVAL);
853    }
854    struct usb_device_request req;
855    req.bType.direction = USB_REQUEST_READ;
856    req.bType.recipient = USB_REQUEST_RECIPIENT_INTERFACE;
857    req.bType.type = USB_REQUEST_TYPE_STANDARD;
858    req.bRequest = USB_HID_REQUEST_GET_DESCRIPTOR;
859    req.wValue = USB_DESCRIPTOR_TYPE_REPORT << 8;
860    req.wIndex = iface;
861    req.wLength = size;
862
863    uint16_t ret_data_length;
864
865    usb_error_t err = usb_do_request_read(&req, &ret_data_length, (void **) d);
866
867    if (err != USB_ERR_OK) {
868        *d = NULL;
869    }
870
871    if (ret_data_length != size) {
872        USB_DEBUG("WARNING: got wrong data size. \n");
873        free(*d);
874        *d = NULL;
875        err = USB_ERR_IOERROR;
876    }
877
878    return (err);
879
880}
881
882/**
883 * \brief this function sets the idlerate of the HID device
884 *
885 * \param iface the interface to set the idle rate for
886 * \param duration the interval in 2 ms setps
887 * \param id the id of the report
888 */
889usb_error_t usb_hid_set_idle(uint8_t iface, uint8_t duration, uint8_t id)
890{
891    struct usb_device_request req;
892
893    req.bRequest = USB_HID_REQUEST_SET_IDLE;
894    req.bType.direction = USB_REQUEST_WRITE;
895    req.bType.recipient = USB_REQUEST_RECIPIENT_INTERFACE;
896    req.bType.type = USB_REQUEST_TYPE_CLASS;
897
898    req.wValue = (duration << 8) | id;
899    req.wIndex = iface;
900    req.wLength = 0;
901
902    return (usb_do_request(&req));
903}
904