112bd3c8bSSascha Wildner /* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */
212bd3c8bSSascha Wildner
312bd3c8bSSascha Wildner /*
412bd3c8bSSascha Wildner * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
512bd3c8bSSascha Wildner * All rights reserved.
612bd3c8bSSascha Wildner *
712bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without
812bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions
912bd3c8bSSascha Wildner * are met:
1012bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright
1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer.
1212bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
1312bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the
1412bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution.
1512bd3c8bSSascha Wildner *
1612bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1712bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1812bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1912bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2012bd3c8bSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2112bd3c8bSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2212bd3c8bSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2312bd3c8bSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2412bd3c8bSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2512bd3c8bSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2612bd3c8bSSascha Wildner * SUCH DAMAGE.
27*ee284e10SSascha Wildner *
28*ee284e10SSascha Wildner * $FreeBSD: head/lib/libusbhid/parse.c 240762 2012-09-20 18:56:27Z mav $
2912bd3c8bSSascha Wildner */
3012bd3c8bSSascha Wildner
3112bd3c8bSSascha Wildner #include <assert.h>
3212bd3c8bSSascha Wildner #include <stdlib.h>
3312bd3c8bSSascha Wildner #include <string.h>
3412bd3c8bSSascha Wildner #include <sys/time.h>
3512bd3c8bSSascha Wildner
363186c89eSSascha Wildner #include <bus/u4b/usb.h>
373186c89eSSascha Wildner #include <bus/u4b/usbhid.h>
3812bd3c8bSSascha Wildner
3912bd3c8bSSascha Wildner #include "usbhid.h"
4012bd3c8bSSascha Wildner #include "usbvar.h"
4112bd3c8bSSascha Wildner
4212bd3c8bSSascha Wildner #define MAXUSAGE 100
4312bd3c8bSSascha Wildner #define MAXPUSH 4
4412bd3c8bSSascha Wildner #define MAXID 64
4512bd3c8bSSascha Wildner #define ITEMTYPES 3
4612bd3c8bSSascha Wildner
4712bd3c8bSSascha Wildner struct hid_pos_data {
4812bd3c8bSSascha Wildner int32_t rid;
4912bd3c8bSSascha Wildner uint32_t pos[ITEMTYPES];
5012bd3c8bSSascha Wildner };
5112bd3c8bSSascha Wildner
5212bd3c8bSSascha Wildner struct hid_data {
5312bd3c8bSSascha Wildner const uint8_t *start;
5412bd3c8bSSascha Wildner const uint8_t *end;
5512bd3c8bSSascha Wildner const uint8_t *p;
5612bd3c8bSSascha Wildner struct hid_item cur[MAXPUSH];
5712bd3c8bSSascha Wildner struct hid_pos_data last_pos[MAXID];
5812bd3c8bSSascha Wildner uint32_t pos[ITEMTYPES];
5912bd3c8bSSascha Wildner int32_t usages_min[MAXUSAGE];
6012bd3c8bSSascha Wildner int32_t usages_max[MAXUSAGE];
6112bd3c8bSSascha Wildner int32_t usage_last; /* last seen usage */
6212bd3c8bSSascha Wildner uint32_t loc_size; /* last seen size */
6312bd3c8bSSascha Wildner uint32_t loc_count; /* last seen count */
6412bd3c8bSSascha Wildner uint8_t kindset; /* we have 5 kinds so 8 bits are enough */
6512bd3c8bSSascha Wildner uint8_t pushlevel; /* current pushlevel */
6612bd3c8bSSascha Wildner uint8_t ncount; /* end usage item count */
6712bd3c8bSSascha Wildner uint8_t icount; /* current usage item count */
6812bd3c8bSSascha Wildner uint8_t nusage; /* end "usages_min/max" index */
6912bd3c8bSSascha Wildner uint8_t iusage; /* current "usages_min/max" index */
7012bd3c8bSSascha Wildner uint8_t ousage; /* current "usages_min/max" offset */
7112bd3c8bSSascha Wildner uint8_t susage; /* usage set flags */
72*ee284e10SSascha Wildner int32_t reportid; /* requested report ID */
7312bd3c8bSSascha Wildner };
7412bd3c8bSSascha Wildner
7512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
7612bd3c8bSSascha Wildner * hid_clear_local
7712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
7812bd3c8bSSascha Wildner static void
hid_clear_local(hid_item_t * c)7912bd3c8bSSascha Wildner hid_clear_local(hid_item_t *c)
8012bd3c8bSSascha Wildner {
8112bd3c8bSSascha Wildner
8212bd3c8bSSascha Wildner c->usage = 0;
8312bd3c8bSSascha Wildner c->usage_minimum = 0;
8412bd3c8bSSascha Wildner c->usage_maximum = 0;
8512bd3c8bSSascha Wildner c->designator_index = 0;
8612bd3c8bSSascha Wildner c->designator_minimum = 0;
8712bd3c8bSSascha Wildner c->designator_maximum = 0;
8812bd3c8bSSascha Wildner c->string_index = 0;
8912bd3c8bSSascha Wildner c->string_minimum = 0;
9012bd3c8bSSascha Wildner c->string_maximum = 0;
9112bd3c8bSSascha Wildner c->set_delimiter = 0;
9212bd3c8bSSascha Wildner }
9312bd3c8bSSascha Wildner
9412bd3c8bSSascha Wildner static void
hid_switch_rid(struct hid_data * s,struct hid_item * c,int32_t next_rID)9512bd3c8bSSascha Wildner hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
9612bd3c8bSSascha Wildner {
9712bd3c8bSSascha Wildner uint8_t i, j;
9812bd3c8bSSascha Wildner
9912bd3c8bSSascha Wildner /* check for same report ID - optimise */
10012bd3c8bSSascha Wildner
10112bd3c8bSSascha Wildner if (c->report_ID == next_rID)
10212bd3c8bSSascha Wildner return;
10312bd3c8bSSascha Wildner
10412bd3c8bSSascha Wildner /* save current position for current rID */
10512bd3c8bSSascha Wildner
10612bd3c8bSSascha Wildner if (c->report_ID == 0) {
10712bd3c8bSSascha Wildner i = 0;
10812bd3c8bSSascha Wildner } else {
10912bd3c8bSSascha Wildner for (i = 1; i != MAXID; i++) {
11012bd3c8bSSascha Wildner if (s->last_pos[i].rid == c->report_ID)
11112bd3c8bSSascha Wildner break;
11212bd3c8bSSascha Wildner if (s->last_pos[i].rid == 0)
11312bd3c8bSSascha Wildner break;
11412bd3c8bSSascha Wildner }
11512bd3c8bSSascha Wildner }
11612bd3c8bSSascha Wildner if (i != MAXID) {
11712bd3c8bSSascha Wildner s->last_pos[i].rid = c->report_ID;
11812bd3c8bSSascha Wildner for (j = 0; j < ITEMTYPES; j++)
11912bd3c8bSSascha Wildner s->last_pos[i].pos[j] = s->pos[j];
12012bd3c8bSSascha Wildner }
12112bd3c8bSSascha Wildner
12212bd3c8bSSascha Wildner /* store next report ID */
12312bd3c8bSSascha Wildner
12412bd3c8bSSascha Wildner c->report_ID = next_rID;
12512bd3c8bSSascha Wildner
12612bd3c8bSSascha Wildner /* lookup last position for next rID */
12712bd3c8bSSascha Wildner
12812bd3c8bSSascha Wildner if (next_rID == 0) {
12912bd3c8bSSascha Wildner i = 0;
13012bd3c8bSSascha Wildner } else {
13112bd3c8bSSascha Wildner for (i = 1; i != MAXID; i++) {
13212bd3c8bSSascha Wildner if (s->last_pos[i].rid == next_rID)
13312bd3c8bSSascha Wildner break;
13412bd3c8bSSascha Wildner if (s->last_pos[i].rid == 0)
13512bd3c8bSSascha Wildner break;
13612bd3c8bSSascha Wildner }
13712bd3c8bSSascha Wildner }
13812bd3c8bSSascha Wildner if (i != MAXID) {
13912bd3c8bSSascha Wildner s->last_pos[i].rid = next_rID;
14012bd3c8bSSascha Wildner for (j = 0; j < ITEMTYPES; j++)
14112bd3c8bSSascha Wildner s->pos[j] = s->last_pos[i].pos[j];
14212bd3c8bSSascha Wildner } else {
14312bd3c8bSSascha Wildner for (j = 0; j < ITEMTYPES; j++)
14412bd3c8bSSascha Wildner s->pos[j] = 0; /* Out of RID entries. */
14512bd3c8bSSascha Wildner }
14612bd3c8bSSascha Wildner }
14712bd3c8bSSascha Wildner
14812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
14912bd3c8bSSascha Wildner * hid_start_parse
15012bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
15112bd3c8bSSascha Wildner hid_data_t
hid_start_parse(report_desc_t d,int kindset,int id)152*ee284e10SSascha Wildner hid_start_parse(report_desc_t d, int kindset, int id)
15312bd3c8bSSascha Wildner {
15412bd3c8bSSascha Wildner struct hid_data *s;
15512bd3c8bSSascha Wildner
15612bd3c8bSSascha Wildner s = malloc(sizeof *s);
15712bd3c8bSSascha Wildner memset(s, 0, sizeof *s);
15812bd3c8bSSascha Wildner s->start = s->p = d->data;
15912bd3c8bSSascha Wildner s->end = d->data + d->size;
16012bd3c8bSSascha Wildner s->kindset = kindset;
161*ee284e10SSascha Wildner s->reportid = id;
16212bd3c8bSSascha Wildner return (s);
16312bd3c8bSSascha Wildner }
16412bd3c8bSSascha Wildner
16512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
16612bd3c8bSSascha Wildner * hid_end_parse
16712bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
16812bd3c8bSSascha Wildner void
hid_end_parse(hid_data_t s)16912bd3c8bSSascha Wildner hid_end_parse(hid_data_t s)
17012bd3c8bSSascha Wildner {
17112bd3c8bSSascha Wildner
17212bd3c8bSSascha Wildner if (s == NULL)
17312bd3c8bSSascha Wildner return;
17412bd3c8bSSascha Wildner
17512bd3c8bSSascha Wildner free(s);
17612bd3c8bSSascha Wildner }
17712bd3c8bSSascha Wildner
17812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
17912bd3c8bSSascha Wildner * get byte from HID descriptor
18012bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
18112bd3c8bSSascha Wildner static uint8_t
hid_get_byte(struct hid_data * s,const uint16_t wSize)18212bd3c8bSSascha Wildner hid_get_byte(struct hid_data *s, const uint16_t wSize)
18312bd3c8bSSascha Wildner {
18412bd3c8bSSascha Wildner const uint8_t *ptr;
18512bd3c8bSSascha Wildner uint8_t retval;
18612bd3c8bSSascha Wildner
18712bd3c8bSSascha Wildner ptr = s->p;
18812bd3c8bSSascha Wildner
18912bd3c8bSSascha Wildner /* check if end is reached */
19012bd3c8bSSascha Wildner if (ptr == s->end)
19112bd3c8bSSascha Wildner return (0);
19212bd3c8bSSascha Wildner
19312bd3c8bSSascha Wildner /* read out a byte */
19412bd3c8bSSascha Wildner retval = *ptr;
19512bd3c8bSSascha Wildner
19612bd3c8bSSascha Wildner /* check if data pointer can be advanced by "wSize" bytes */
19712bd3c8bSSascha Wildner if ((s->end - ptr) < wSize)
19812bd3c8bSSascha Wildner ptr = s->end;
19912bd3c8bSSascha Wildner else
20012bd3c8bSSascha Wildner ptr += wSize;
20112bd3c8bSSascha Wildner
20212bd3c8bSSascha Wildner /* update pointer */
20312bd3c8bSSascha Wildner s->p = ptr;
20412bd3c8bSSascha Wildner
20512bd3c8bSSascha Wildner return (retval);
20612bd3c8bSSascha Wildner }
20712bd3c8bSSascha Wildner
20812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
20912bd3c8bSSascha Wildner * hid_get_item
21012bd3c8bSSascha Wildner *------------------------------------------------------------------------*/
211*ee284e10SSascha Wildner static int
hid_get_item_raw(hid_data_t s,hid_item_t * h)212*ee284e10SSascha Wildner hid_get_item_raw(hid_data_t s, hid_item_t *h)
21312bd3c8bSSascha Wildner {
21412bd3c8bSSascha Wildner hid_item_t *c;
21512bd3c8bSSascha Wildner unsigned int bTag, bType, bSize;
21612bd3c8bSSascha Wildner int32_t mask;
21712bd3c8bSSascha Wildner int32_t dval;
21812bd3c8bSSascha Wildner
21912bd3c8bSSascha Wildner if (s == NULL)
22012bd3c8bSSascha Wildner return (0);
22112bd3c8bSSascha Wildner
22212bd3c8bSSascha Wildner c = &s->cur[s->pushlevel];
22312bd3c8bSSascha Wildner
22412bd3c8bSSascha Wildner top:
22512bd3c8bSSascha Wildner /* check if there is an array of items */
22612bd3c8bSSascha Wildner if (s->icount < s->ncount) {
22712bd3c8bSSascha Wildner /* get current usage */
22812bd3c8bSSascha Wildner if (s->iusage < s->nusage) {
22912bd3c8bSSascha Wildner dval = s->usages_min[s->iusage] + s->ousage;
23012bd3c8bSSascha Wildner c->usage = dval;
23112bd3c8bSSascha Wildner s->usage_last = dval;
23212bd3c8bSSascha Wildner if (dval == s->usages_max[s->iusage]) {
23312bd3c8bSSascha Wildner s->iusage ++;
23412bd3c8bSSascha Wildner s->ousage = 0;
23512bd3c8bSSascha Wildner } else {
23612bd3c8bSSascha Wildner s->ousage ++;
23712bd3c8bSSascha Wildner }
23812bd3c8bSSascha Wildner } else {
23912bd3c8bSSascha Wildner /* Using last usage */
24012bd3c8bSSascha Wildner dval = s->usage_last;
24112bd3c8bSSascha Wildner }
24212bd3c8bSSascha Wildner s->icount ++;
24312bd3c8bSSascha Wildner /*
24412bd3c8bSSascha Wildner * Only copy HID item, increment position and return
24512bd3c8bSSascha Wildner * if correct kindset!
24612bd3c8bSSascha Wildner */
24712bd3c8bSSascha Wildner if (s->kindset & (1 << c->kind)) {
24812bd3c8bSSascha Wildner *h = *c;
24912bd3c8bSSascha Wildner h->pos = s->pos[c->kind];
25012bd3c8bSSascha Wildner s->pos[c->kind] += c->report_size * c->report_count;
25112bd3c8bSSascha Wildner return (1);
25212bd3c8bSSascha Wildner }
25312bd3c8bSSascha Wildner }
25412bd3c8bSSascha Wildner
25512bd3c8bSSascha Wildner /* reset state variables */
25612bd3c8bSSascha Wildner s->icount = 0;
25712bd3c8bSSascha Wildner s->ncount = 0;
25812bd3c8bSSascha Wildner s->iusage = 0;
25912bd3c8bSSascha Wildner s->nusage = 0;
26012bd3c8bSSascha Wildner s->susage = 0;
26112bd3c8bSSascha Wildner s->ousage = 0;
26212bd3c8bSSascha Wildner hid_clear_local(c);
26312bd3c8bSSascha Wildner
26412bd3c8bSSascha Wildner /* get next item */
26512bd3c8bSSascha Wildner while (s->p != s->end) {
26612bd3c8bSSascha Wildner
26712bd3c8bSSascha Wildner bSize = hid_get_byte(s, 1);
26812bd3c8bSSascha Wildner if (bSize == 0xfe) {
26912bd3c8bSSascha Wildner /* long item */
27012bd3c8bSSascha Wildner bSize = hid_get_byte(s, 1);
27112bd3c8bSSascha Wildner bSize |= hid_get_byte(s, 1) << 8;
27212bd3c8bSSascha Wildner bTag = hid_get_byte(s, 1);
27312bd3c8bSSascha Wildner bType = 0xff; /* XXX what should it be */
27412bd3c8bSSascha Wildner } else {
27512bd3c8bSSascha Wildner /* short item */
27612bd3c8bSSascha Wildner bTag = bSize >> 4;
27712bd3c8bSSascha Wildner bType = (bSize >> 2) & 3;
27812bd3c8bSSascha Wildner bSize &= 3;
27912bd3c8bSSascha Wildner if (bSize == 3)
28012bd3c8bSSascha Wildner bSize = 4;
28112bd3c8bSSascha Wildner }
28212bd3c8bSSascha Wildner
28312bd3c8bSSascha Wildner switch(bSize) {
28412bd3c8bSSascha Wildner case 0:
28512bd3c8bSSascha Wildner dval = 0;
28612bd3c8bSSascha Wildner mask = 0;
28712bd3c8bSSascha Wildner break;
28812bd3c8bSSascha Wildner case 1:
28912bd3c8bSSascha Wildner dval = (int8_t)hid_get_byte(s, 1);
29012bd3c8bSSascha Wildner mask = 0xFF;
29112bd3c8bSSascha Wildner break;
29212bd3c8bSSascha Wildner case 2:
29312bd3c8bSSascha Wildner dval = hid_get_byte(s, 1);
29412bd3c8bSSascha Wildner dval |= hid_get_byte(s, 1) << 8;
29512bd3c8bSSascha Wildner dval = (int16_t)dval;
29612bd3c8bSSascha Wildner mask = 0xFFFF;
29712bd3c8bSSascha Wildner break;
29812bd3c8bSSascha Wildner case 4:
29912bd3c8bSSascha Wildner dval = hid_get_byte(s, 1);
30012bd3c8bSSascha Wildner dval |= hid_get_byte(s, 1) << 8;
30112bd3c8bSSascha Wildner dval |= hid_get_byte(s, 1) << 16;
30212bd3c8bSSascha Wildner dval |= hid_get_byte(s, 1) << 24;
30312bd3c8bSSascha Wildner mask = 0xFFFFFFFF;
30412bd3c8bSSascha Wildner break;
30512bd3c8bSSascha Wildner default:
30612bd3c8bSSascha Wildner dval = hid_get_byte(s, bSize);
30712bd3c8bSSascha Wildner continue;
30812bd3c8bSSascha Wildner }
30912bd3c8bSSascha Wildner
31012bd3c8bSSascha Wildner switch (bType) {
31112bd3c8bSSascha Wildner case 0: /* Main */
31212bd3c8bSSascha Wildner switch (bTag) {
31312bd3c8bSSascha Wildner case 8: /* Input */
31412bd3c8bSSascha Wildner c->kind = hid_input;
31512bd3c8bSSascha Wildner c->flags = dval;
31612bd3c8bSSascha Wildner ret:
31712bd3c8bSSascha Wildner c->report_count = s->loc_count;
31812bd3c8bSSascha Wildner c->report_size = s->loc_size;
31912bd3c8bSSascha Wildner
32012bd3c8bSSascha Wildner if (c->flags & HIO_VARIABLE) {
32112bd3c8bSSascha Wildner /* range check usage count */
32212bd3c8bSSascha Wildner if (c->report_count > 255) {
32312bd3c8bSSascha Wildner s->ncount = 255;
32412bd3c8bSSascha Wildner } else
32512bd3c8bSSascha Wildner s->ncount = c->report_count;
32612bd3c8bSSascha Wildner
32712bd3c8bSSascha Wildner /*
32812bd3c8bSSascha Wildner * The "top" loop will return
32912bd3c8bSSascha Wildner * one and one item:
33012bd3c8bSSascha Wildner */
33112bd3c8bSSascha Wildner c->report_count = 1;
33212bd3c8bSSascha Wildner c->usage_minimum = 0;
33312bd3c8bSSascha Wildner c->usage_maximum = 0;
33412bd3c8bSSascha Wildner } else {
33512bd3c8bSSascha Wildner s->ncount = 1;
33612bd3c8bSSascha Wildner }
33712bd3c8bSSascha Wildner goto top;
33812bd3c8bSSascha Wildner
33912bd3c8bSSascha Wildner case 9: /* Output */
34012bd3c8bSSascha Wildner c->kind = hid_output;
34112bd3c8bSSascha Wildner c->flags = dval;
34212bd3c8bSSascha Wildner goto ret;
34312bd3c8bSSascha Wildner case 10: /* Collection */
34412bd3c8bSSascha Wildner c->kind = hid_collection;
34512bd3c8bSSascha Wildner c->collection = dval;
34612bd3c8bSSascha Wildner c->collevel++;
34712bd3c8bSSascha Wildner c->usage = s->usage_last;
34812bd3c8bSSascha Wildner *h = *c;
34912bd3c8bSSascha Wildner return (1);
35012bd3c8bSSascha Wildner case 11: /* Feature */
35112bd3c8bSSascha Wildner c->kind = hid_feature;
35212bd3c8bSSascha Wildner c->flags = dval;
35312bd3c8bSSascha Wildner goto ret;
35412bd3c8bSSascha Wildner case 12: /* End collection */
35512bd3c8bSSascha Wildner c->kind = hid_endcollection;
35612bd3c8bSSascha Wildner if (c->collevel == 0) {
35712bd3c8bSSascha Wildner /* Invalid end collection. */
35812bd3c8bSSascha Wildner return (0);
35912bd3c8bSSascha Wildner }
36012bd3c8bSSascha Wildner c->collevel--;
36112bd3c8bSSascha Wildner *h = *c;
36212bd3c8bSSascha Wildner return (1);
36312bd3c8bSSascha Wildner default:
36412bd3c8bSSascha Wildner break;
36512bd3c8bSSascha Wildner }
36612bd3c8bSSascha Wildner break;
36712bd3c8bSSascha Wildner
36812bd3c8bSSascha Wildner case 1: /* Global */
36912bd3c8bSSascha Wildner switch (bTag) {
37012bd3c8bSSascha Wildner case 0:
37112bd3c8bSSascha Wildner c->_usage_page = dval << 16;
37212bd3c8bSSascha Wildner break;
37312bd3c8bSSascha Wildner case 1:
37412bd3c8bSSascha Wildner c->logical_minimum = dval;
37512bd3c8bSSascha Wildner break;
37612bd3c8bSSascha Wildner case 2:
37712bd3c8bSSascha Wildner c->logical_maximum = dval;
37812bd3c8bSSascha Wildner break;
37912bd3c8bSSascha Wildner case 3:
38012bd3c8bSSascha Wildner c->physical_minimum = dval;
38112bd3c8bSSascha Wildner break;
38212bd3c8bSSascha Wildner case 4:
38312bd3c8bSSascha Wildner c->physical_maximum = dval;
38412bd3c8bSSascha Wildner break;
38512bd3c8bSSascha Wildner case 5:
38612bd3c8bSSascha Wildner c->unit_exponent = dval;
38712bd3c8bSSascha Wildner break;
38812bd3c8bSSascha Wildner case 6:
38912bd3c8bSSascha Wildner c->unit = dval;
39012bd3c8bSSascha Wildner break;
39112bd3c8bSSascha Wildner case 7:
39212bd3c8bSSascha Wildner /* mask because value is unsigned */
39312bd3c8bSSascha Wildner s->loc_size = dval & mask;
39412bd3c8bSSascha Wildner break;
39512bd3c8bSSascha Wildner case 8:
396*ee284e10SSascha Wildner hid_switch_rid(s, c, dval & mask);
39712bd3c8bSSascha Wildner break;
39812bd3c8bSSascha Wildner case 9:
39912bd3c8bSSascha Wildner /* mask because value is unsigned */
40012bd3c8bSSascha Wildner s->loc_count = dval & mask;
40112bd3c8bSSascha Wildner break;
40212bd3c8bSSascha Wildner case 10: /* Push */
40312bd3c8bSSascha Wildner s->pushlevel ++;
40412bd3c8bSSascha Wildner if (s->pushlevel < MAXPUSH) {
40512bd3c8bSSascha Wildner s->cur[s->pushlevel] = *c;
40612bd3c8bSSascha Wildner /* store size and count */
40712bd3c8bSSascha Wildner c->report_size = s->loc_size;
40812bd3c8bSSascha Wildner c->report_count = s->loc_count;
40912bd3c8bSSascha Wildner /* update current item pointer */
41012bd3c8bSSascha Wildner c = &s->cur[s->pushlevel];
41112bd3c8bSSascha Wildner }
41212bd3c8bSSascha Wildner break;
41312bd3c8bSSascha Wildner case 11: /* Pop */
41412bd3c8bSSascha Wildner s->pushlevel --;
41512bd3c8bSSascha Wildner if (s->pushlevel < MAXPUSH) {
41612bd3c8bSSascha Wildner c = &s->cur[s->pushlevel];
41712bd3c8bSSascha Wildner /* restore size and count */
41812bd3c8bSSascha Wildner s->loc_size = c->report_size;
41912bd3c8bSSascha Wildner s->loc_count = c->report_count;
42012bd3c8bSSascha Wildner c->report_size = 0;
42112bd3c8bSSascha Wildner c->report_count = 0;
42212bd3c8bSSascha Wildner }
42312bd3c8bSSascha Wildner break;
42412bd3c8bSSascha Wildner default:
42512bd3c8bSSascha Wildner break;
42612bd3c8bSSascha Wildner }
42712bd3c8bSSascha Wildner break;
42812bd3c8bSSascha Wildner case 2: /* Local */
42912bd3c8bSSascha Wildner switch (bTag) {
43012bd3c8bSSascha Wildner case 0:
43112bd3c8bSSascha Wildner if (bSize != 4)
43212bd3c8bSSascha Wildner dval = (dval & mask) | c->_usage_page;
43312bd3c8bSSascha Wildner
43412bd3c8bSSascha Wildner /* set last usage, in case of a collection */
43512bd3c8bSSascha Wildner s->usage_last = dval;
43612bd3c8bSSascha Wildner
43712bd3c8bSSascha Wildner if (s->nusage < MAXUSAGE) {
43812bd3c8bSSascha Wildner s->usages_min[s->nusage] = dval;
43912bd3c8bSSascha Wildner s->usages_max[s->nusage] = dval;
44012bd3c8bSSascha Wildner s->nusage ++;
44112bd3c8bSSascha Wildner }
44212bd3c8bSSascha Wildner /* else XXX */
44312bd3c8bSSascha Wildner
44412bd3c8bSSascha Wildner /* clear any pending usage sets */
44512bd3c8bSSascha Wildner s->susage = 0;
44612bd3c8bSSascha Wildner break;
44712bd3c8bSSascha Wildner case 1:
44812bd3c8bSSascha Wildner s->susage |= 1;
44912bd3c8bSSascha Wildner
45012bd3c8bSSascha Wildner if (bSize != 4)
45112bd3c8bSSascha Wildner dval = (dval & mask) | c->_usage_page;
45212bd3c8bSSascha Wildner c->usage_minimum = dval;
45312bd3c8bSSascha Wildner
45412bd3c8bSSascha Wildner goto check_set;
45512bd3c8bSSascha Wildner case 2:
45612bd3c8bSSascha Wildner s->susage |= 2;
45712bd3c8bSSascha Wildner
45812bd3c8bSSascha Wildner if (bSize != 4)
45912bd3c8bSSascha Wildner dval = (dval & mask) | c->_usage_page;
46012bd3c8bSSascha Wildner c->usage_maximum = dval;
46112bd3c8bSSascha Wildner
46212bd3c8bSSascha Wildner check_set:
46312bd3c8bSSascha Wildner if (s->susage != 3)
46412bd3c8bSSascha Wildner break;
46512bd3c8bSSascha Wildner
46612bd3c8bSSascha Wildner /* sanity check */
46712bd3c8bSSascha Wildner if ((s->nusage < MAXUSAGE) &&
46812bd3c8bSSascha Wildner (c->usage_minimum <= c->usage_maximum)) {
46912bd3c8bSSascha Wildner /* add usage range */
47012bd3c8bSSascha Wildner s->usages_min[s->nusage] =
47112bd3c8bSSascha Wildner c->usage_minimum;
47212bd3c8bSSascha Wildner s->usages_max[s->nusage] =
47312bd3c8bSSascha Wildner c->usage_maximum;
47412bd3c8bSSascha Wildner s->nusage ++;
47512bd3c8bSSascha Wildner }
47612bd3c8bSSascha Wildner /* else XXX */
47712bd3c8bSSascha Wildner
47812bd3c8bSSascha Wildner s->susage = 0;
47912bd3c8bSSascha Wildner break;
48012bd3c8bSSascha Wildner case 3:
48112bd3c8bSSascha Wildner c->designator_index = dval;
48212bd3c8bSSascha Wildner break;
48312bd3c8bSSascha Wildner case 4:
48412bd3c8bSSascha Wildner c->designator_minimum = dval;
48512bd3c8bSSascha Wildner break;
48612bd3c8bSSascha Wildner case 5:
48712bd3c8bSSascha Wildner c->designator_maximum = dval;
48812bd3c8bSSascha Wildner break;
48912bd3c8bSSascha Wildner case 7:
49012bd3c8bSSascha Wildner c->string_index = dval;
49112bd3c8bSSascha Wildner break;
49212bd3c8bSSascha Wildner case 8:
49312bd3c8bSSascha Wildner c->string_minimum = dval;
49412bd3c8bSSascha Wildner break;
49512bd3c8bSSascha Wildner case 9:
49612bd3c8bSSascha Wildner c->string_maximum = dval;
49712bd3c8bSSascha Wildner break;
49812bd3c8bSSascha Wildner case 10:
49912bd3c8bSSascha Wildner c->set_delimiter = dval;
50012bd3c8bSSascha Wildner break;
50112bd3c8bSSascha Wildner default:
50212bd3c8bSSascha Wildner break;
50312bd3c8bSSascha Wildner }
50412bd3c8bSSascha Wildner break;
50512bd3c8bSSascha Wildner default:
50612bd3c8bSSascha Wildner break;
50712bd3c8bSSascha Wildner }
50812bd3c8bSSascha Wildner }
50912bd3c8bSSascha Wildner return (0);
51012bd3c8bSSascha Wildner }
51112bd3c8bSSascha Wildner
51212bd3c8bSSascha Wildner int
hid_get_item(hid_data_t s,hid_item_t * h)513*ee284e10SSascha Wildner hid_get_item(hid_data_t s, hid_item_t *h)
514*ee284e10SSascha Wildner {
515*ee284e10SSascha Wildner int r;
516*ee284e10SSascha Wildner
517*ee284e10SSascha Wildner for (;;) {
518*ee284e10SSascha Wildner r = hid_get_item_raw(s, h);
519*ee284e10SSascha Wildner if (r <= 0 || s->reportid == -1 || h->report_ID == s->reportid)
520*ee284e10SSascha Wildner break;
521*ee284e10SSascha Wildner }
522*ee284e10SSascha Wildner return (r);
523*ee284e10SSascha Wildner }
524*ee284e10SSascha Wildner
525*ee284e10SSascha Wildner int
hid_report_size(report_desc_t r,enum hid_kind k,int id)52612bd3c8bSSascha Wildner hid_report_size(report_desc_t r, enum hid_kind k, int id)
52712bd3c8bSSascha Wildner {
52812bd3c8bSSascha Wildner struct hid_data *d;
52912bd3c8bSSascha Wildner struct hid_item h;
53012bd3c8bSSascha Wildner uint32_t temp;
53112bd3c8bSSascha Wildner uint32_t hpos;
53212bd3c8bSSascha Wildner uint32_t lpos;
53312bd3c8bSSascha Wildner int report_id = 0;
53412bd3c8bSSascha Wildner
53512bd3c8bSSascha Wildner hpos = 0;
53612bd3c8bSSascha Wildner lpos = 0xFFFFFFFF;
53712bd3c8bSSascha Wildner
53812bd3c8bSSascha Wildner memset(&h, 0, sizeof h);
53912bd3c8bSSascha Wildner for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) {
540*ee284e10SSascha Wildner if (h.kind == k) {
54112bd3c8bSSascha Wildner /* compute minimum */
54212bd3c8bSSascha Wildner if (lpos > h.pos)
54312bd3c8bSSascha Wildner lpos = h.pos;
54412bd3c8bSSascha Wildner /* compute end position */
54512bd3c8bSSascha Wildner temp = h.pos + (h.report_size * h.report_count);
54612bd3c8bSSascha Wildner /* compute maximum */
54712bd3c8bSSascha Wildner if (hpos < temp)
54812bd3c8bSSascha Wildner hpos = temp;
54912bd3c8bSSascha Wildner if (h.report_ID != 0)
55012bd3c8bSSascha Wildner report_id = 1;
55112bd3c8bSSascha Wildner }
55212bd3c8bSSascha Wildner }
55312bd3c8bSSascha Wildner hid_end_parse(d);
55412bd3c8bSSascha Wildner
55512bd3c8bSSascha Wildner /* safety check - can happen in case of currupt descriptors */
55612bd3c8bSSascha Wildner if (lpos > hpos)
55712bd3c8bSSascha Wildner temp = 0;
55812bd3c8bSSascha Wildner else
55912bd3c8bSSascha Wildner temp = hpos - lpos;
56012bd3c8bSSascha Wildner
56112bd3c8bSSascha Wildner /* return length in bytes rounded up */
56212bd3c8bSSascha Wildner return ((temp + 7) / 8 + report_id);
56312bd3c8bSSascha Wildner }
56412bd3c8bSSascha Wildner
56512bd3c8bSSascha Wildner int
hid_locate(report_desc_t desc,unsigned int u,enum hid_kind k,hid_item_t * h,int id)56612bd3c8bSSascha Wildner hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
56712bd3c8bSSascha Wildner hid_item_t *h, int id)
56812bd3c8bSSascha Wildner {
56912bd3c8bSSascha Wildner struct hid_data *d;
57012bd3c8bSSascha Wildner
57112bd3c8bSSascha Wildner for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) {
57212bd3c8bSSascha Wildner if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
57312bd3c8bSSascha Wildner hid_end_parse(d);
57412bd3c8bSSascha Wildner return (1);
57512bd3c8bSSascha Wildner }
57612bd3c8bSSascha Wildner }
57712bd3c8bSSascha Wildner hid_end_parse(d);
57812bd3c8bSSascha Wildner h->report_size = 0;
57912bd3c8bSSascha Wildner return (0);
58012bd3c8bSSascha Wildner }
581