diff options
author | alfred <alfred@FreeBSD.org> | 2009-07-30 00:17:08 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2009-07-30 00:17:08 +0000 |
commit | fd0357779de667d9b21a36be3bb5ad95bfdde4c7 (patch) | |
tree | 027588bd546e41b529edad6060d343f79edb317f | |
parent | 0f210d639a8b58ebb9aa016f3ec10e676cc16f04 (diff) | |
download | FreeBSD-src-fd0357779de667d9b21a36be3bb5ad95bfdde4c7.zip FreeBSD-src-fd0357779de667d9b21a36be3bb5ad95bfdde4c7.tar.gz |
USB CORE - Improve HID parsing
See PR description for more info. Patch is
implemented differently than suggested, but
having the same result.
PR: usb/137188
Submitted by: hps
Approved by: re
-rw-r--r-- | sys/dev/usb/usb_hid.c | 64 |
1 files changed, 61 insertions, 3 deletions
diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c index 220ffa2..b9d61c9 100644 --- a/sys/dev/usb/usb_hid.c +++ b/sys/dev/usb/usb_hid.c @@ -78,11 +78,19 @@ static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize); #define MAXUSAGE 64 #define MAXPUSH 4 +#define MAXID 16 + +struct hid_pos_data { + int32_t rid; + uint32_t pos; +}; + struct hid_data { const uint8_t *start; const uint8_t *end; const uint8_t *p; struct hid_item cur[MAXPUSH]; + struct hid_pos_data last_pos[MAXID]; int32_t usages_min[MAXUSAGE]; int32_t usages_max[MAXUSAGE]; int32_t usage_last; /* last seen usage */ @@ -119,6 +127,58 @@ hid_clear_local(struct hid_item *c) c->set_delimiter = 0; } +static void +hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) +{ + uint8_t i; + + /* check for same report ID - optimise */ + + if (c->report_ID == next_rID) + return; + + /* save current position for current rID */ + + if (c->report_ID == 0) { + i = 0; + } else { + for (i = 1; i != MAXID; i++) { + if (s->last_pos[i].rid == c->report_ID) + break; + if (s->last_pos[i].rid == 0) + break; + } + } + if (i != MAXID) { + s->last_pos[i].rid = c->report_ID; + s->last_pos[i].pos = c->loc.pos; + } + + /* store next report ID */ + + c->report_ID = next_rID; + + /* lookup last position for next rID */ + + if (next_rID == 0) { + i = 0; + } else { + for (i = 1; i != MAXID; i++) { + if (s->last_pos[i].rid == next_rID) + break; + if (s->last_pos[i].rid == 0) + break; + } + } + if (i != MAXID) { + s->last_pos[i].rid = next_rID; + c->loc.pos = s->last_pos[i].pos; + } else { + DPRINTF("Out of RID entries, position is set to zero!\n"); + c->loc.pos = 0; + } +} + /*------------------------------------------------------------------------* * hid_start_parse *------------------------------------------------------------------------*/ @@ -373,9 +433,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h) s->loc_size = dval & mask; break; case 8: - c->report_ID = dval; - /* new report - reset position */ - c->loc.pos = 0; + hid_switch_rid(s, c, dval); break; case 9: /* mask because value is unsigned */ |