TABs -> spaces
[metze/wireshark/wip.git] / epan / dissectors / packet-usb-hid.c
1 /* packet-usb-hid.c
2  *
3  * $Id$
4  *
5  * USB HID dissector
6  * By Adam Nielsen <a.nielsen@shikadi.net> 2009
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23
24 #include "config.h"
25
26 #include <glib.h>
27 #include <epan/packet.h>
28 #include <string.h>
29 #include "packet-usb.h"
30 #include "packet-usb-hid.h"
31
32 /* protocols and header fields */
33 static int proto_usb_hid = -1;
34 static int hf_usb_hid_item_bSize = -1;
35 static int hf_usb_hid_item_bType = -1;
36 static int hf_usb_hid_mainitem_bTag = -1;
37 static int hf_usb_hid_globalitem_bTag = -1;
38 static int hf_usb_hid_localitem_bTag = -1;
39 static int hf_usb_hid_longitem_bTag = -1;
40 static int hf_usb_hid_item_bDataSize = -1;
41 static int hf_usb_hid_item_bLongItemTag = -1;
42 static int hf_usb_hid_item_unk_data = -1;
43
44 static int hf_usb_hid_mainitem_bit0 = -1;
45 static int hf_usb_hid_mainitem_bit1 = -1;
46 static int hf_usb_hid_mainitem_bit2 = -1;
47 static int hf_usb_hid_mainitem_bit3 = -1;
48 static int hf_usb_hid_mainitem_bit4 = -1;
49 static int hf_usb_hid_mainitem_bit5 = -1;
50 static int hf_usb_hid_mainitem_bit6 = -1;
51 static int hf_usb_hid_mainitem_bit7 = -1;
52 static int hf_usb_hid_mainitem_bit7_input = -1;
53 static int hf_usb_hid_mainitem_bit8 = -1;
54 static int hf_usb_hid_mainitem_colltype = -1;
55
56 static int hf_usb_hid_globalitem_usage = -1;
57 static int hf_usb_hid_globalitem_log_min = -1;
58 static int hf_usb_hid_globalitem_log_max = -1;
59 static int hf_usb_hid_globalitem_phy_min = -1;
60 static int hf_usb_hid_globalitem_phy_max = -1;
61 static int hf_usb_hid_globalitem_unit_exp = -1;
62 static int hf_usb_hid_globalitem_unit_sys = -1;
63 static int hf_usb_hid_globalitem_unit_len = -1;
64 static int hf_usb_hid_globalitem_unit_mass = -1;
65 static int hf_usb_hid_globalitem_unit_time = -1;
66 static int hf_usb_hid_globalitem_unit_temp = -1;
67 static int hf_usb_hid_globalitem_unit_current = -1;
68 static int hf_usb_hid_globalitem_unit_brightness = -1;
69 static int hf_usb_hid_globalitem_report_size = -1;
70 static int hf_usb_hid_globalitem_report_id = -1;
71 static int hf_usb_hid_globalitem_report_count = -1;
72 static int hf_usb_hid_globalitem_push = -1;
73 static int hf_usb_hid_globalitem_pop = -1;
74
75 static int hf_usb_hid_localitem_usage = -1;
76 static int hf_usb_hid_localitem_usage_min = -1;
77 /* static int hf_usb_hid_localitem_usage_max = -1; */
78 static int hf_usb_hid_localitem_desig_index = -1;
79 static int hf_usb_hid_localitem_desig_min = -1;
80 static int hf_usb_hid_localitem_desig_max = -1;
81 static int hf_usb_hid_localitem_string_index = -1;
82 static int hf_usb_hid_localitem_string_min = -1;
83 static int hf_usb_hid_localitem_string_max = -1;
84 static int hf_usb_hid_localitem_delimiter = -1;
85
86 static gint ett_usb_hid_report = -1;
87 static gint ett_usb_hid_item_header = -1;
88 static gint ett_usb_hid_wValue = -1;
89
90 static int hf_usb_hid_request = -1;
91 static int hf_usb_hid_value = -1;
92 static int hf_usb_hid_index = -1;
93 static int hf_usb_hid_length = -1;
94 static int hf_usb_hid_report_type = -1;
95 static int hf_usb_hid_report_id = -1;
96 static int hf_usb_hid_duration = -1;
97 static int hf_usb_hid_zero = -1;
98
99 static const true_false_string tfs_mainitem_bit0 = {"Data", "Constant"};
100 static const true_false_string tfs_mainitem_bit1 = {"Array", "Variable"};
101 static const true_false_string tfs_mainitem_bit2 = {"Absolute", "Relative"};
102 static const true_false_string tfs_mainitem_bit3 = {"No wrap", "Wrap"};
103 static const true_false_string tfs_mainitem_bit4 = {"Linear", "Nonlinear"};
104 static const true_false_string tfs_mainitem_bit5 = {"Preferred state", "No preferred state"};
105 static const true_false_string tfs_mainitem_bit6 = {"No null position", "Null state"};
106 static const true_false_string tfs_mainitem_bit7 = {"Non-volatile", "Volatile"};
107 static const true_false_string tfs_mainitem_bit8 = {"Bit field", "Buffered bytes"};
108
109
110 struct usb_hid_global_state {
111     unsigned int usage_page;
112 };
113
114 #define USBHID_SIZE_MASK  0x03
115 #define USBHID_TYPE_MASK  0x0C
116 #define USBHID_TAG_MASK   0xF0
117
118 static const value_string usb_hid_item_bSize_vals[] = {
119     {0, "0 bytes"},
120     {1, "1 byte"},
121     {2, "2 bytes"},
122     {3, "4 bytes"},
123     {0, NULL}
124 };
125
126 #define USBHID_ITEMTYPE_MAIN    0
127 #define USBHID_ITEMTYPE_GLOBAL  1
128 #define USBHID_ITEMTYPE_LOCAL   2
129 #define USBHID_ITEMTYPE_LONG    3
130 static const value_string usb_hid_item_bType_vals[] = {
131     {USBHID_ITEMTYPE_MAIN,   "Main"},
132     {USBHID_ITEMTYPE_GLOBAL, "Global"},
133     {USBHID_ITEMTYPE_LOCAL,  "Local"},
134     {USBHID_ITEMTYPE_LONG,   "Long item"},
135     {0, NULL}
136 };
137
138 #define USBHID_MAINITEM_TAG_INPUT           8
139 #define USBHID_MAINITEM_TAG_OUTPUT          9
140 #define USBHID_MAINITEM_TAG_FEATURE        11
141 #define USBHID_MAINITEM_TAG_COLLECTION     10
142 #define USBHID_MAINITEM_TAG_ENDCOLLECTION  12
143 static const value_string usb_hid_mainitem_bTag_vals[] = {
144     {USBHID_MAINITEM_TAG_INPUT,         "Input"},
145     {USBHID_MAINITEM_TAG_OUTPUT,        "Output"},
146     {USBHID_MAINITEM_TAG_FEATURE,       "Feature"},
147     {USBHID_MAINITEM_TAG_COLLECTION,    "Collection"},
148     {USBHID_MAINITEM_TAG_ENDCOLLECTION, "End collection"},
149     {0, NULL}
150 };
151 #define USBHID_GLOBALITEM_TAG_USAGE_PAGE    0
152 #define USBHID_GLOBALITEM_TAG_LOG_MIN       1
153 #define USBHID_GLOBALITEM_TAG_LOG_MAX       2
154 #define USBHID_GLOBALITEM_TAG_PHY_MIN       3
155 #define USBHID_GLOBALITEM_TAG_PHY_MAX       4
156 #define USBHID_GLOBALITEM_TAG_UNIT_EXP      5
157 #define USBHID_GLOBALITEM_TAG_UNIT          6
158 #define USBHID_GLOBALITEM_TAG_REPORT_SIZE   7
159 #define USBHID_GLOBALITEM_TAG_REPORT_ID     8
160 #define USBHID_GLOBALITEM_TAG_REPORT_COUNT  9
161 #define USBHID_GLOBALITEM_TAG_PUSH         10
162 #define USBHID_GLOBALITEM_TAG_POP          11
163 static const value_string usb_hid_globalitem_bTag_vals[] = {
164     {USBHID_GLOBALITEM_TAG_USAGE_PAGE,   "Usage"},
165     {USBHID_GLOBALITEM_TAG_LOG_MIN,      "Logical minimum"},
166     {USBHID_GLOBALITEM_TAG_LOG_MAX,      "Logical maximum"},
167     {USBHID_GLOBALITEM_TAG_PHY_MIN,      "Physical minimum"},
168     {USBHID_GLOBALITEM_TAG_PHY_MAX,      "Physical maximum"},
169     {USBHID_GLOBALITEM_TAG_UNIT_EXP,     "Unit exponent"},
170     {USBHID_GLOBALITEM_TAG_UNIT,         "Units"},
171     {USBHID_GLOBALITEM_TAG_REPORT_SIZE,  "Report size"},
172     {USBHID_GLOBALITEM_TAG_REPORT_ID,    "Report ID"},
173     {USBHID_GLOBALITEM_TAG_REPORT_COUNT, "Report count"},
174     {USBHID_GLOBALITEM_TAG_PUSH,         "Push"},
175     {USBHID_GLOBALITEM_TAG_POP,          "Pop"},
176     {12, "[Reserved]"},
177     {13, "[Reserved]"},
178     {14, "[Reserved]"},
179     {15, "[Reserved]"},
180     {0, NULL}
181 };
182 #define USBHID_LOCALITEM_TAG_USAGE_PAGE     0
183 #define USBHID_LOCALITEM_TAG_USAGE_MIN      1
184 #define USBHID_LOCALITEM_TAG_USAGE_MAX      2
185 #define USBHID_LOCALITEM_TAG_DESIG_INDEX    3
186 #define USBHID_LOCALITEM_TAG_DESIG_MIN      4
187 #define USBHID_LOCALITEM_TAG_DESIG_MAX      5
188 /* No 6 in spec */
189 #define USBHID_LOCALITEM_TAG_STRING_INDEX   7
190 #define USBHID_LOCALITEM_TAG_STRING_MIN     8
191 #define USBHID_LOCALITEM_TAG_STRING_MAX     9
192 #define USBHID_LOCALITEM_TAG_DELIMITER     10 /* Also listed as reserved in spec! */
193 static const value_string usb_hid_localitem_bTag_vals[] = {
194     {USBHID_LOCALITEM_TAG_USAGE_PAGE,   "Usage"},
195     {USBHID_LOCALITEM_TAG_USAGE_MIN,    "Usage minimum"},
196     {USBHID_LOCALITEM_TAG_USAGE_MAX,    "Usage maximum"},
197     {USBHID_LOCALITEM_TAG_DESIG_INDEX,  "Designator index"},
198     {USBHID_LOCALITEM_TAG_DESIG_MIN,    "Designator minimum"},
199     {USBHID_LOCALITEM_TAG_DESIG_MAX,    "Designator maximum"},
200     {USBHID_LOCALITEM_TAG_STRING_INDEX, "String index"},
201     {USBHID_LOCALITEM_TAG_STRING_MIN,   "String minimum"},
202     {USBHID_LOCALITEM_TAG_STRING_MAX,   "String maximum"},
203     {USBHID_LOCALITEM_TAG_DELIMITER,    "Delimiter"},
204     {11, "[Reserved]"},
205     {12, "[Reserved]"},
206     {13, "[Reserved]"},
207     {14, "[Reserved]"},
208     {15, "[Reserved]"},
209     {0, NULL}
210 };
211 static const value_string usb_hid_longitem_bTag_vals[] = {
212     {15, "Long item"},
213     {0, NULL}
214 };
215
216 static const range_string usb_hid_mainitem_colltype_vals[] = {
217     {0x00, 0x00, "Physical"},
218     {0x01, 0x01, "Application"},
219     {0x02, 0x02, "Logical"},
220     {0x03, 0x03, "Report"},
221     {0x04, 0x04, "Named array"},
222     {0x05, 0x05, "Usage switch"},
223     {0x06, 0x06, "Usage modifier"},
224     {0x07, 0x7F, "[Reserved]"},
225     {0x80, 0xFF, "[Vendor-defined]"},
226     {0, 0, NULL}
227 };
228
229 static const value_string usb_hid_globalitem_unit_exp_vals[] = {
230     {0x0, "n^0"},
231     {0x1, "n^1"},
232     {0x2, "n^2"},
233     {0x3, "n^3"},
234     {0x4, "n^4"},
235     {0x5, "n^5"},
236     {0x6, "n^6"},
237     {0x7, "n^7"},
238     {0x8, "n^-8"},
239     {0x9, "n^-7"},
240     {0xA, "n^-6"},
241     {0xB, "n^-5"},
242     {0xC, "n^-4"},
243     {0xD, "n^-3"},
244     {0xE, "n^-2"},
245     {0xF, "n^-1"},
246     {0, NULL}
247 };
248 static const range_string usb_hid_item_usage_vals[] = {
249     {0x00, 0x00, "Undefined"},
250     {0x01, 0x01, "Generic desktop controls"},
251     {0x02, 0x02, "Simulation controls"},
252     {0x03, 0x03, "VR controls"},
253     {0x04, 0x04, "Sport controls"},
254     {0x05, 0x05, "Game controls"},
255     {0x06, 0x06, "Generic device controls"},
256     {0x07, 0x07, "Keyboard/keypad"},
257     {0x08, 0x08, "LEDs"},
258     {0x09, 0x09, "Button"},
259     {0x0A, 0x0A, "Ordinal"},
260     {0x0B, 0x0B, "Telephony"},
261     {0x0C, 0x0C, "Consumer"},
262     {0x0D, 0x0D, "Digitizer"},
263     {0x0E, 0x0E, "[Reserved]"},
264     {0x0F, 0x0F, "Physical Interface Device (PID) page"},
265     {0x10, 0x10, "Unicode"},
266     {0x11, 0x13, "[Reserved]"},
267     {0x14, 0x14, "Alphanumeric display"},
268     {0x15, 0x3F, "[Reserved]"},
269     {0x40, 0x40, "Medical instruments"},
270     {0x41, 0x7F, "[Reserved]"},
271     {0x80, 0x83, "Monitor page"},
272     {0x84, 0x87, "Power page"},
273     {0x88, 0x8B, "[Reserved]"},
274     {0x8C, 0x8C, "Bar code scanner page"},
275     {0x8D, 0x8D, "Scale page"},
276     {0x8E, 0x8E, "Magnetic Stripe Reading (MSR) devices"},
277     {0x8F, 0x8F, "[Reserved Point of Sale page]"},
278     {0x90, 0x90, "Camera control page"},
279     {0x91, 0x91, "Arcade page"},
280     {0x92, 0xFEFF, "[Reserved]"},
281     {0xFF00, 0xFFFF, "[Vendor-defined]"},
282     {0, 0, NULL}
283 };
284
285 /* Dissector for the data in a HID main report. */
286 static int
287 dissect_usb_hid_report_mainitem_data(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, unsigned int bSize, unsigned int bTag)
288 {
289     switch (bTag) {
290         case USBHID_MAINITEM_TAG_INPUT:
291         case USBHID_MAINITEM_TAG_OUTPUT:
292         case USBHID_MAINITEM_TAG_FEATURE:
293             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit0, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
294             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit1, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
295             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit2, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
296             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit3, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
297             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit4, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
298             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit5, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
299             proto_tree_add_item(tree, hf_usb_hid_mainitem_bit6, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
300             if (bTag == USBHID_MAINITEM_TAG_INPUT) {
301                 proto_tree_add_item(tree, hf_usb_hid_mainitem_bit7_input, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
302             } else {
303                 proto_tree_add_item(tree, hf_usb_hid_mainitem_bit7, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
304             }
305             if (bSize > 1) {
306                 proto_tree_add_item(tree, hf_usb_hid_mainitem_bit8, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
307             } else {
308                 proto_tree_add_text(tree, tvb, offset, 0, "Bits or bytes: Buffered bytes (default, no second byte present)");
309             }
310             break;
311         case USBHID_MAINITEM_TAG_COLLECTION:
312             proto_tree_add_item(tree, hf_usb_hid_mainitem_colltype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
313             break;
314         case USBHID_MAINITEM_TAG_ENDCOLLECTION:
315             /* No item data */
316             break;
317         default:
318             proto_tree_add_item(tree, hf_usb_hid_item_unk_data, tvb, offset, bSize, ENC_NA);
319             break;
320     }
321     offset += bSize;
322     return offset;
323 }
324
325 /* Dissector for the data in a HID main report. */
326 static int
327 dissect_usb_hid_report_globalitem_data(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, unsigned int bSize, unsigned int bTag, struct usb_hid_global_state *global)
328 {
329     switch (bTag) {
330         case USBHID_GLOBALITEM_TAG_USAGE_PAGE:
331             switch (bSize) {
332                 case 1: global->usage_page = tvb_get_guint8(tvb, offset); break;
333                 case 2: global->usage_page = tvb_get_letohs(tvb, offset); break;
334                 case 3: global->usage_page = tvb_get_letoh24(tvb, offset); break;
335                 case 4: global->usage_page = tvb_get_letohl(tvb, offset); break;
336                 default: global->usage_page = 0; break;
337             }
338             proto_tree_add_item(tree, hf_usb_hid_globalitem_usage, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
339             break;
340         case USBHID_GLOBALITEM_TAG_LOG_MIN:
341             proto_tree_add_item(tree, hf_usb_hid_globalitem_log_min, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
342             break;
343         case USBHID_GLOBALITEM_TAG_LOG_MAX:
344             proto_tree_add_item(tree, hf_usb_hid_globalitem_log_max, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
345             break;
346         case USBHID_GLOBALITEM_TAG_PHY_MIN:
347             proto_tree_add_item(tree, hf_usb_hid_globalitem_phy_min, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
348             break;
349         case USBHID_GLOBALITEM_TAG_PHY_MAX:
350             proto_tree_add_item(tree, hf_usb_hid_globalitem_phy_max, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
351             break;
352         case USBHID_GLOBALITEM_TAG_UNIT_EXP:
353             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_exp, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
354             break;
355         case USBHID_GLOBALITEM_TAG_UNIT:
356             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_sys, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
357             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_len, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
358             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_mass, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
359             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_time, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
360             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_temp, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
361             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_current, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
362             proto_tree_add_item(tree, hf_usb_hid_globalitem_unit_brightness, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
363             break;
364         case USBHID_GLOBALITEM_TAG_REPORT_SIZE:
365             proto_tree_add_item(tree, hf_usb_hid_globalitem_report_size, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
366             break;
367         case USBHID_GLOBALITEM_TAG_REPORT_ID:
368             proto_tree_add_item(tree, hf_usb_hid_globalitem_report_id, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
369             break;
370         case USBHID_GLOBALITEM_TAG_REPORT_COUNT:
371             proto_tree_add_item(tree, hf_usb_hid_globalitem_report_count, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
372             break;
373         case USBHID_GLOBALITEM_TAG_PUSH:
374             proto_tree_add_item(tree, hf_usb_hid_globalitem_push, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
375             break;
376         case USBHID_GLOBALITEM_TAG_POP:
377             proto_tree_add_item(tree, hf_usb_hid_globalitem_pop, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
378             break;
379         default:
380             proto_tree_add_item(tree, hf_usb_hid_item_unk_data, tvb, offset, bSize, ENC_NA);
381             break;
382     }
383     offset += bSize;
384     return offset;
385 }
386
387 /* Dissector for the data in a HID main report. */
388 static int
389 dissect_usb_hid_report_localitem_data(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, unsigned int bSize, unsigned int bTag, struct usb_hid_global_state *global)
390 {
391     unsigned int usage_page = 0xffffffff; /* in case bSize == 0 */
392
393     switch (bTag) {
394         case USBHID_LOCALITEM_TAG_USAGE_PAGE:
395             if (bSize > 2) {
396                 /* Full page ID */
397                 proto_tree_add_item(tree, hf_usb_hid_localitem_usage, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
398             } else {
399                 /* Only lower few bits given, need to combine with last global ID */
400                 if (bSize == 1)
401                     usage_page = (global->usage_page & 0xFFFFFF00) | tvb_get_guint8(tvb, offset);
402                 else if (bSize == 2)
403                     usage_page = (global->usage_page & 0xFFFF0000) | tvb_get_ntohs(tvb, offset);
404                 proto_tree_add_text(tree, tvb, offset, bSize, "Usage: %s (0x%08x)",
405                     rval_to_str(usage_page, usb_hid_item_usage_vals, "[Unknown page!]"),
406                     usage_page);
407             }
408             break;
409         case USBHID_LOCALITEM_TAG_USAGE_MIN:
410             proto_tree_add_item(tree, hf_usb_hid_localitem_usage_min, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
411             break;
412         case USBHID_LOCALITEM_TAG_USAGE_MAX:
413             proto_tree_add_item(tree, hf_usb_hid_localitem_usage, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
414             break;
415         case USBHID_LOCALITEM_TAG_DESIG_INDEX:
416             proto_tree_add_item(tree, hf_usb_hid_localitem_desig_index, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
417             break;
418         case USBHID_LOCALITEM_TAG_DESIG_MIN:
419             proto_tree_add_item(tree, hf_usb_hid_localitem_desig_min, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
420             break;
421         case USBHID_LOCALITEM_TAG_DESIG_MAX:
422             proto_tree_add_item(tree, hf_usb_hid_localitem_desig_max, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
423             break;
424         case USBHID_LOCALITEM_TAG_STRING_INDEX:
425             proto_tree_add_item(tree, hf_usb_hid_localitem_string_index, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
426             break;
427         case USBHID_LOCALITEM_TAG_STRING_MIN:
428             proto_tree_add_item(tree, hf_usb_hid_localitem_string_min, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
429             break;
430         case USBHID_LOCALITEM_TAG_STRING_MAX:
431             proto_tree_add_item(tree, hf_usb_hid_localitem_string_max, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
432             break;
433         case USBHID_LOCALITEM_TAG_DELIMITER:
434             proto_tree_add_item(tree, hf_usb_hid_localitem_delimiter, tvb, offset, bSize, ENC_LITTLE_ENDIAN);
435             break;
436         default:
437             proto_tree_add_item(tree, hf_usb_hid_item_unk_data, tvb, offset, bSize, ENC_NA);
438             break;
439     }
440     offset += bSize;
441     return offset;
442 }
443
444 /* Dissector for individual HID report items.  Recursive. */
445 static int
446 dissect_usb_hid_report_item(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_, const struct usb_hid_global_state *global)
447 {
448     proto_item *item=NULL, *subitem=NULL;
449     proto_tree *tree=NULL, *subtree=NULL;
450     int old_offset;
451     unsigned int tmp;
452     unsigned int bSize, bType, bTag;
453     const value_string *usb_hid_cur_bTag_vals;
454     int hf_usb_hid_curitem_bTag;
455     struct usb_hid_global_state cur_global;
456     memcpy(&cur_global, global, sizeof(struct usb_hid_global_state));
457
458     while (tvb_reported_length_remaining(tvb, offset) > 0)
459     {
460         old_offset=offset;
461
462         tmp = tvb_get_guint8(tvb, offset);
463         bSize = tmp & USBHID_SIZE_MASK;
464         if (bSize == 3) bSize++; /* 3 == four bytes */
465         bType = (tmp & USBHID_TYPE_MASK) >> 2;
466         bTag = (tmp & USBHID_TAG_MASK) >> 4;
467
468         switch (bType) {
469             case USBHID_ITEMTYPE_MAIN:
470                 hf_usb_hid_curitem_bTag = hf_usb_hid_mainitem_bTag;
471                 usb_hid_cur_bTag_vals = usb_hid_mainitem_bTag_vals;
472                 break;
473             case USBHID_ITEMTYPE_GLOBAL:
474                 hf_usb_hid_curitem_bTag = hf_usb_hid_globalitem_bTag;
475                 usb_hid_cur_bTag_vals = usb_hid_globalitem_bTag_vals;
476                 break;
477             case USBHID_ITEMTYPE_LOCAL:
478                 hf_usb_hid_curitem_bTag = hf_usb_hid_localitem_bTag;
479                 usb_hid_cur_bTag_vals = usb_hid_localitem_bTag_vals;
480                 break;
481             default: /* Only USBHID_ITEMTYPE_LONG, but keep compiler happy */
482                 hf_usb_hid_curitem_bTag = hf_usb_hid_longitem_bTag;
483                 usb_hid_cur_bTag_vals = usb_hid_longitem_bTag_vals;
484                 break;
485         }
486
487         subitem = proto_tree_add_text(parent_tree, tvb, offset, bSize + 1, "%s item (%s)",
488             val_to_str(bType, usb_hid_item_bType_vals, "Unknown/%u"),
489             val_to_str(bTag, usb_hid_cur_bTag_vals, "Unknown/%u tag")
490         );
491         subtree = proto_item_add_subtree(subitem, ett_usb_hid_item_header);
492
493         item = proto_tree_add_text(subtree, tvb, offset, 1, "Header");
494         tree = proto_item_add_subtree(item, ett_usb_hid_item_header);
495         proto_tree_add_item(tree, hf_usb_hid_item_bSize, tvb, offset,   1, ENC_LITTLE_ENDIAN);
496         proto_tree_add_item(tree, hf_usb_hid_item_bType, tvb, offset,   1, ENC_LITTLE_ENDIAN);
497         proto_tree_add_item(tree, hf_usb_hid_curitem_bTag, tvb, offset, 1, ENC_LITTLE_ENDIAN);
498         offset++;
499         if ((bType == 3) && (bTag == 16)) {
500             /* Long item */
501             bSize = tvb_get_guint8(tvb, offset);
502             proto_tree_add_item(subtree, hf_usb_hid_item_bDataSize, tvb, offset, 1, ENC_LITTLE_ENDIAN);
503             offset++;
504             proto_tree_add_item(subtree, hf_usb_hid_item_bLongItemTag, tvb, offset, 1, ENC_LITTLE_ENDIAN);
505             offset++;
506             proto_tree_add_item(subtree, hf_usb_hid_item_unk_data, tvb, offset, bSize, ENC_NA);
507             offset += bSize;
508         } else {
509             /* Short item */
510             switch (bType) {
511                 case USBHID_ITEMTYPE_MAIN:
512                     offset = dissect_usb_hid_report_mainitem_data(pinfo, subtree, tvb, offset, bSize, bTag);
513                     break;
514                 case USBHID_ITEMTYPE_GLOBAL:
515                     offset = dissect_usb_hid_report_globalitem_data(pinfo, subtree, tvb, offset, bSize, bTag, &cur_global);
516                     break;
517                 case USBHID_ITEMTYPE_LOCAL:
518                     offset = dissect_usb_hid_report_localitem_data(pinfo, subtree, tvb, offset, bSize, bTag, &cur_global);
519                     break;
520                 default: /* Only USBHID_ITEMTYPE_LONG, but keep compiler happy */
521                     proto_tree_add_item(subtree, hf_usb_hid_item_unk_data, tvb, offset, bSize, ENC_NA);
522                     offset += bSize;
523                     break;
524             }
525         }
526
527         if (bType == USBHID_ITEMTYPE_MAIN) {
528             if (bTag == USBHID_MAINITEM_TAG_COLLECTION) {
529                 /* Begin collection, nest following elements under us */
530                 offset = dissect_usb_hid_report_item(pinfo, subtree, tvb, offset, usb_trans_info, usb_conv_info, &cur_global);
531                 proto_item_set_len(subitem, offset-old_offset);
532             } else if (bTag == USBHID_MAINITEM_TAG_ENDCOLLECTION) {
533                 /* End collection, break out to parent tree item */
534                 break;
535             }
536         }
537     }
538     return offset;
539 }
540
541 /* Dissector for HID "GET DESCRIPTOR" subtype. */
542 int
543 dissect_usb_hid_get_report_descriptor(packet_info *pinfo _U_, proto_tree *parent_tree, tvbuff_t *tvb, int offset, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
544 {
545     proto_item *item=NULL;
546     proto_tree *tree=NULL;
547     int old_offset=offset;
548     struct usb_hid_global_state initial_global;
549     memset(&initial_global, 0, sizeof(struct usb_hid_global_state));
550
551     if (parent_tree) {
552         item = proto_tree_add_protocol_format(parent_tree, proto_usb_hid, tvb, offset,
553                               -1, "HID Report");
554         tree = proto_item_add_subtree(item, ett_usb_hid_report);
555         offset = dissect_usb_hid_report_item(pinfo, tree, tvb, offset, usb_trans_info, usb_conv_info, &initial_global);
556
557         proto_item_set_len(item, offset-old_offset);
558     }
559
560     return offset;
561 }
562
563 /* Dissector for HID GET_REPORT request. See USBHID 1.11, Chapter 7.2.1 Get_Report Request */
564 static void
565 dissect_usb_hid_get_report(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
566 {
567     proto_item *item = NULL;
568     proto_tree *subtree = NULL;
569
570     if (is_request) {
571         item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
572         subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
573
574         /* Report Type in the high byte, Report ID in the low byte */
575         proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
576         offset++;
577         proto_tree_add_item(subtree, hf_usb_hid_report_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
578         offset++;
579
580         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
581         offset += 2;
582
583         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
584         /*offset += 2;*/
585     } else {
586     }
587 }
588
589 /* Dissector for HID SET_REPORT request. See USBHID 1.11, Chapter 7.2.2 Set_Report Request */
590 static void
591 dissect_usb_hid_set_report(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
592 {
593     proto_item *item = NULL;
594     proto_tree *subtree = NULL;
595
596     if (is_request) {
597         item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
598         subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
599
600         proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
601         offset++;
602         proto_tree_add_item(subtree, hf_usb_hid_report_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
603         offset++;
604
605         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
606         offset += 2;
607
608         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
609         /*offset += 2;*/
610     } else {
611     }
612 }
613
614
615 /* Dissector for HID GET_IDLE request. See USBHID 1.11, Chapter 7.2.3 Get_Idle Request */
616 static void
617 dissect_usb_hid_get_idle(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
618 {
619     proto_item *item = NULL;
620     proto_tree *subtree = NULL;
621
622     if (is_request) {
623         item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
624         subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
625
626         proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
627         offset++;
628         proto_tree_add_item(subtree, hf_usb_hid_zero, tvb, offset, 1, ENC_LITTLE_ENDIAN);
629         offset++;
630
631         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
632         offset += 2;
633
634         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
635         /*offset += 2;*/
636     } else {
637     }
638 }
639
640 /* Dissector for HID SET_IDLE request. See USBHID 1.11, Chapter 7.2.4 Set_Idle Request */
641 static void
642 dissect_usb_hid_set_idle(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
643 {
644     proto_item *item = NULL;
645     proto_tree *subtree = NULL;
646
647     if (is_request) {
648         item = proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
649         subtree = proto_item_add_subtree(item, ett_usb_hid_wValue);
650
651         /* Duration in the high byte, Report ID in the low byte */
652         proto_tree_add_item(subtree, hf_usb_hid_report_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
653         offset++;
654         proto_tree_add_item(subtree, hf_usb_hid_duration, tvb, offset, 1, ENC_LITTLE_ENDIAN);
655         offset++;
656
657         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
658         offset += 2;
659
660         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
661         /*offset += 2;*/
662     } else {
663     }
664 }
665
666 /* Dissector for HID GET_PROTOCOL request. See USBHID 1.11, Chapter 7.2.5 Get_Protocol Request */
667 static void
668 dissect_usb_hid_get_protocol(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
669 {
670     if (is_request) {
671         proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
672         offset += 2;
673
674         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
675         offset += 2;
676
677         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
678         /*offset += 2;*/
679     } else {
680     }
681 }
682
683 /* Dissector for HID SET_PROTOCOL request. See USBHID 1.11, Chapter 7.2.6 Set_Protocol Request */
684 static void
685 dissect_usb_hid_set_protocol(packet_info *pinfo _U_, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info _U_, usb_conv_info_t *usb_conv_info _U_)
686 {
687     if (is_request) {
688         proto_tree_add_item(tree, hf_usb_hid_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
689         offset += 2;
690
691         proto_tree_add_item(tree, hf_usb_hid_index, tvb, offset, 2, ENC_LITTLE_ENDIAN);
692         offset += 2;
693
694         proto_tree_add_item(tree, hf_usb_hid_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
695         /*offset += 2;*/
696     } else {
697     }
698 }
699
700
701 typedef void (*usb_setup_dissector)(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gboolean is_request, usb_trans_info_t *usb_trans_info, usb_conv_info_t *usb_conv_info);
702
703 typedef struct _usb_setup_dissector_table_t {
704     guint8 request;
705     usb_setup_dissector dissector;
706 } usb_setup_dissector_table_t;
707
708
709 /* USBHID 1.11, Chapter 7.2 Class-Specific Requests */
710 #define USB_HID_SETUP_GET_REPORT      0x01
711 #define USB_HID_SETUP_GET_IDLE        0x02
712 #define USB_HID_SETUP_GET_PROTOCOL    0x03
713 /* 0x04..0x08: Reserved */
714 #define USB_HID_SETUP_SET_REPORT      0x09
715 #define USB_HID_SETUP_SET_IDLE        0x0A
716 #define USB_HID_SETUP_SET_PROTOCOL    0x0B
717
718 static const usb_setup_dissector_table_t setup_dissectors[] = {
719     { USB_HID_SETUP_GET_REPORT,   dissect_usb_hid_get_report },
720     { USB_HID_SETUP_GET_IDLE,     dissect_usb_hid_get_idle },
721     { USB_HID_SETUP_GET_PROTOCOL, dissect_usb_hid_get_protocol },
722     { USB_HID_SETUP_SET_REPORT,   dissect_usb_hid_set_report },
723     { USB_HID_SETUP_SET_IDLE,     dissect_usb_hid_set_idle },
724     { USB_HID_SETUP_SET_PROTOCOL, dissect_usb_hid_set_protocol },
725     { 0, NULL }
726 };
727
728 static const value_string setup_request_names_vals[] = {
729     { USB_HID_SETUP_GET_REPORT,   "GET_REPORT" },
730     { USB_HID_SETUP_GET_IDLE,     "GET_IDLE" },
731     { USB_HID_SETUP_GET_PROTOCOL, "GET_PROTOCOL" },
732     { USB_HID_SETUP_SET_REPORT,   "SET_REPORT" },
733     { USB_HID_SETUP_SET_IDLE,     "SET_IDLE" },
734     { USB_HID_SETUP_SET_PROTOCOL, "SET_PROTOCOL" },
735     { 0, NULL }
736 };
737
738 static const value_string usb_hid_report_type_vals[] = {
739     { 1, "Input" },
740     { 2, "Output" },
741     { 3, "Feature" },
742     { 0, NULL }
743 };
744
745 /* Dissector for HID class-specific control request as defined in
746  * USBHID 1.11, Chapter 7.2.
747  * Returns TRUE if a class specific dissector was found
748  * and FALSE otherwise.
749  */
750 static gint
751 dissect_usb_hid_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
752 {
753     gboolean is_request;
754     usb_conv_info_t *usb_conv_info;
755     usb_trans_info_t *usb_trans_info;
756     int offset = 0;
757     usb_setup_dissector dissector;
758     const usb_setup_dissector_table_t *tmp;
759
760     is_request = (pinfo->srcport==NO_ENDPOINT);
761
762     usb_conv_info = (usb_conv_info_t *)pinfo->usb_conv_info;
763     usb_trans_info = usb_conv_info->usb_trans_info;
764
765     /* See if we can find a class specific dissector for this request */
766     dissector = NULL;
767
768     /* Check valid values for bmRequestType. See Chapter 7.2 in USBHID 1.11 */
769     if ((usb_trans_info->setup.requesttype & 0x7F) ==
770         ((RQT_SETUP_TYPE_CLASS << 5) | RQT_SETUP_RECIPIENT_INTERFACE)) {
771         for (tmp = setup_dissectors; tmp->dissector; tmp++) {
772             if (tmp->request == usb_trans_info->setup.request) {
773                 dissector = tmp->dissector;
774                 break;
775             }
776         }
777     }
778     /* No, we could not find any class specific dissector for this request
779      * return FALSE and let USB try any of the standard requests.
780      */
781     if (!dissector) {
782         return FALSE;
783     }
784
785     col_set_str(pinfo->cinfo, COL_PROTOCOL, "USBHID");
786
787     col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
788     val_to_str(usb_trans_info->setup.request, setup_request_names_vals, "Unknown type %x"),
789         is_request ? "Request" : "Response");
790
791     if (is_request) {
792         proto_tree_add_item(tree, hf_usb_hid_request, tvb, offset, 1, ENC_LITTLE_ENDIAN);
793         offset += 1;
794     }
795
796     dissector(pinfo, tree, tvb, offset, is_request, usb_trans_info, usb_conv_info);
797     return TRUE;
798 }
799
800 void
801 proto_register_usb_hid(void)
802 {
803     static hf_register_info hf[] = {
804         { &hf_usb_hid_item_bSize,
805             { "bSize", "usbhid.item.bSize", FT_UINT8, BASE_DEC,
806                 VALS(usb_hid_item_bSize_vals), USBHID_SIZE_MASK, NULL, HFILL }},
807
808         { &hf_usb_hid_item_bType,
809             { "bType", "usbhid.item.bType", FT_UINT8, BASE_DEC,
810                 VALS(usb_hid_item_bType_vals), USBHID_TYPE_MASK, NULL, HFILL }},
811
812         { &hf_usb_hid_mainitem_bTag,
813             { "bTag", "usbhid.item.bTag", FT_UINT8, BASE_HEX,
814                 VALS(usb_hid_mainitem_bTag_vals), USBHID_TAG_MASK, NULL, HFILL }},
815
816         { &hf_usb_hid_globalitem_bTag,
817             { "bTag", "usbhid.item.bTag", FT_UINT8, BASE_HEX,
818                 VALS(usb_hid_globalitem_bTag_vals), USBHID_TAG_MASK, NULL, HFILL }},
819
820         { &hf_usb_hid_localitem_bTag,
821             { "bTag", "usbhid.item.bTag", FT_UINT8, BASE_HEX,
822                 VALS(usb_hid_localitem_bTag_vals), USBHID_TAG_MASK, NULL, HFILL }},
823
824         { &hf_usb_hid_longitem_bTag,
825             { "bTag", "usbhid.item.bTag", FT_UINT8, BASE_HEX,
826                 VALS(usb_hid_longitem_bTag_vals), USBHID_TAG_MASK, NULL, HFILL }},
827
828         { &hf_usb_hid_item_bDataSize,
829             { "bDataSize", "usbhid.item.bDataSize", FT_UINT8, BASE_DEC,
830                 NULL, 0, NULL, HFILL }},
831
832         { &hf_usb_hid_item_bLongItemTag,
833             { "bTag", "usbhid.item.bLongItemTag", FT_UINT8, BASE_HEX,
834                 NULL, 0, NULL, HFILL }},
835
836         /* Main-report item data */
837
838         { &hf_usb_hid_mainitem_bit0,
839             { "Data/constant", "usbhid.item.main.readonly", FT_BOOLEAN, 9,
840                 TFS(&tfs_mainitem_bit0), 1<<0, NULL, HFILL }},
841
842         { &hf_usb_hid_mainitem_bit1,
843             { "Data type", "usbhid.item.main.variable", FT_BOOLEAN, 9,
844                 TFS(&tfs_mainitem_bit1), 1<<1, NULL, HFILL }},
845
846         { &hf_usb_hid_mainitem_bit2,
847             { "Coordinates", "usbhid.item.main.relative", FT_BOOLEAN, 9,
848                 TFS(&tfs_mainitem_bit2), 1<<2, NULL, HFILL }},
849
850         { &hf_usb_hid_mainitem_bit3,
851             { "Min/max wraparound", "usbhid.item.main.wrap", FT_BOOLEAN, 9,
852                 TFS(&tfs_mainitem_bit3), 1<<3, NULL, HFILL }},
853
854         { &hf_usb_hid_mainitem_bit4,
855             { "Physical relationship to data", "usbhid.item.main.nonlinear", FT_BOOLEAN, 9,
856                 TFS(&tfs_mainitem_bit4), 1<<4, NULL, HFILL }},
857
858         { &hf_usb_hid_mainitem_bit5,
859             { "Preferred state", "usbhid.item.main.no_preferred_state", FT_BOOLEAN, 9,
860                 TFS(&tfs_mainitem_bit5), 1<<5, NULL, HFILL }},
861
862         { &hf_usb_hid_mainitem_bit6,
863             { "Has null position", "usbhid.item.main.nullstate", FT_BOOLEAN, 9,
864                 TFS(&tfs_mainitem_bit6), 1<<6, NULL, HFILL }},
865
866         { &hf_usb_hid_mainitem_bit7,
867             { "(Non)-volatile", "usbhid.item.main.volatile", FT_BOOLEAN, 9,
868                 TFS(&tfs_mainitem_bit7), 1<<7, NULL, HFILL }},
869
870         { &hf_usb_hid_mainitem_bit7_input,
871             { "[Reserved]", "usbhid.item.main.volatile", FT_BOOLEAN, 9,
872                 NULL, 1<<7, NULL, HFILL }},
873
874         { &hf_usb_hid_mainitem_bit8,
875             { "Bits or bytes", "usbhid.item.main.buffered_bytes", FT_BOOLEAN, 9,
876                 TFS(&tfs_mainitem_bit8), 1<<8, NULL, HFILL }},
877
878         { &hf_usb_hid_mainitem_colltype,
879             { "Collection type", "usbhid.item.main.colltype", FT_UINT8, BASE_RANGE_STRING|BASE_HEX,
880                 RVALS(usb_hid_mainitem_colltype_vals), 0, NULL, HFILL }},
881
882         /* Global-report item data */
883
884         { &hf_usb_hid_globalitem_usage,
885             { "Usage page", "usbhid.item.global.usage", FT_UINT8, BASE_RANGE_STRING|BASE_HEX,
886                 RVALS(usb_hid_item_usage_vals), 0, NULL, HFILL }},
887
888         { &hf_usb_hid_globalitem_log_min,
889             { "Logical minimum", "usbhid.item.global.log_min", FT_UINT8, BASE_DEC,
890                 NULL, 0, NULL, HFILL }},
891
892         { &hf_usb_hid_globalitem_log_max,
893             { "Logical maximum", "usbhid.item.global.log_max", FT_UINT8, BASE_DEC,
894                 NULL, 0, NULL, HFILL }},
895
896         { &hf_usb_hid_globalitem_phy_min,
897             { "Physical minimum", "usbhid.item.global.phy_min", FT_UINT8, BASE_DEC,
898                 NULL, 0, NULL, HFILL }},
899
900         { &hf_usb_hid_globalitem_phy_max,
901             { "Physical maximum", "usbhid.item.global.phy_max", FT_UINT8, BASE_DEC,
902                 NULL, 0, NULL, HFILL }},
903
904         { &hf_usb_hid_globalitem_unit_exp,
905             { "Unit exponent", "usbhid.item.global.unit_exp", FT_UINT8, BASE_DEC,
906                 NULL, 0, NULL, HFILL }},
907
908         { &hf_usb_hid_globalitem_unit_sys,
909             { "System", "usbhid.item.global.unit.system", FT_UINT32, BASE_HEX,
910                 VALS(usb_hid_globalitem_unit_exp_vals), 0x0000000F, NULL, HFILL }},
911
912         { &hf_usb_hid_globalitem_unit_len,
913             { "Length", "usbhid.item.global.unit.length", FT_UINT32, BASE_HEX,
914                 VALS(usb_hid_globalitem_unit_exp_vals), 0x000000F0, NULL, HFILL }},
915
916         { &hf_usb_hid_globalitem_unit_mass,
917             { "Mass", "usbhid.item.global.unit.mass", FT_UINT32, BASE_HEX,
918                 VALS(usb_hid_globalitem_unit_exp_vals), 0x00000F00, NULL, HFILL }},
919
920         { &hf_usb_hid_globalitem_unit_time,
921             { "Time", "usbhid.item.global.unit.time", FT_UINT32, BASE_HEX,
922                 VALS(usb_hid_globalitem_unit_exp_vals), 0x0000F000, NULL, HFILL }},
923
924         { &hf_usb_hid_globalitem_unit_temp,
925             { "Temperature", "usbhid.item.global.unit.temperature", FT_UINT32, BASE_HEX,
926                 VALS(usb_hid_globalitem_unit_exp_vals), 0x000F0000, NULL, HFILL }},
927
928         { &hf_usb_hid_globalitem_unit_current,
929             { "Current", "usbhid.item.global.unit.current", FT_UINT32, BASE_HEX,
930                 VALS(usb_hid_globalitem_unit_exp_vals), 0x00F00000, NULL, HFILL }},
931
932         { &hf_usb_hid_globalitem_unit_brightness,
933             { "Luminous intensity", "usbhid.item.global.unit.brightness", FT_UINT32, BASE_HEX,
934                 VALS(usb_hid_globalitem_unit_exp_vals), 0x0F000000, NULL, HFILL }},
935
936         { &hf_usb_hid_globalitem_report_size,
937             { "Report size", "usbhid.item.global.report_size", FT_UINT8, BASE_DEC,
938                 NULL, 0, NULL, HFILL }},
939
940         { &hf_usb_hid_globalitem_report_id,
941             { "Report ID", "usbhid.item.global.report_id", FT_UINT8, BASE_HEX,
942                 NULL, 0, NULL, HFILL }},
943
944         { &hf_usb_hid_globalitem_report_count,
945             { "Report count", "usbhid.item.global.report_count", FT_UINT8, BASE_DEC,
946                 NULL, 0, NULL, HFILL }},
947
948         { &hf_usb_hid_globalitem_push,
949             { "Push", "usbhid.item.global.push", FT_UINT8, BASE_HEX,
950                 NULL, 0, NULL, HFILL }},
951
952         { &hf_usb_hid_globalitem_pop,
953             { "Pop", "usbhid.item.global.pop", FT_UINT8, BASE_HEX,
954                 NULL, 0, NULL, HFILL }},
955
956         /* Local-report item data */
957
958         { &hf_usb_hid_localitem_usage,
959             { "Usage", "usbhid.item.local.usage", FT_UINT8, BASE_RANGE_STRING|BASE_HEX,
960                 RVALS(usb_hid_item_usage_vals), 0, NULL, HFILL }},
961
962         { &hf_usb_hid_localitem_usage_min,
963             { "Usage minimum", "usbhid.item.local.usage_min", FT_UINT8, BASE_HEX,
964                 NULL, 0, NULL, HFILL }},
965
966 #if 0
967         { &hf_usb_hid_localitem_usage_max,
968             { "Usage maximum", "usbhid.item.local.usage_max", FT_UINT8, BASE_HEX,
969                 NULL, 0, NULL, HFILL }},
970 #endif
971
972         { &hf_usb_hid_localitem_desig_index,
973             { "Designator index", "usbhid.item.local.desig_index", FT_UINT8, BASE_HEX,
974                 NULL, 0, NULL, HFILL }},
975
976         { &hf_usb_hid_localitem_desig_min,
977             { "Designator minimum", "usbhid.item.local.desig_min", FT_UINT8, BASE_HEX,
978                 NULL, 0, NULL, HFILL }},
979
980         { &hf_usb_hid_localitem_desig_max,
981             { "Designator maximum", "usbhid.item.local.desig_max", FT_UINT8, BASE_HEX,
982                 NULL, 0, NULL, HFILL }},
983
984         { &hf_usb_hid_localitem_string_index,
985             { "String index", "usbhid.item.local.string_index", FT_UINT8, BASE_HEX,
986                 NULL, 0, NULL, HFILL }},
987
988         { &hf_usb_hid_localitem_string_min,
989             { "String minimum", "usbhid.item.local.string_min", FT_UINT8, BASE_HEX,
990                 NULL, 0, NULL, HFILL }},
991
992         { &hf_usb_hid_localitem_string_max,
993             { "String maximum", "usbhid.item.local.string_max", FT_UINT8, BASE_HEX,
994                 NULL, 0, NULL, HFILL }},
995
996         { &hf_usb_hid_localitem_delimiter,
997             { "Delimiter", "usbhid.item.local.delimiter", FT_UINT8, BASE_HEX,
998                 NULL, 0, NULL, HFILL }},
999
1000
1001         { &hf_usb_hid_item_unk_data,
1002             { "Item data", "usbhid.item.data", FT_BYTES, BASE_NONE,
1003                 NULL, 0, NULL, HFILL }},
1004
1005         /* USB HID specific requests */
1006         { &hf_usb_hid_request,
1007         { "bRequest", "usbhid.setup.bRequest", FT_UINT8, BASE_HEX, VALS(setup_request_names_vals), 0x0,
1008           NULL, HFILL }},
1009
1010         { &hf_usb_hid_value,
1011         { "wValue", "usbhid.setup.wValue", FT_UINT16, BASE_HEX, NULL, 0x0,
1012           NULL, HFILL }},
1013
1014         { &hf_usb_hid_index,
1015         { "wIndex", "usbhid.setup.wIndex", FT_UINT16, BASE_DEC, NULL, 0x0,
1016           NULL, HFILL }},
1017
1018         { &hf_usb_hid_length,
1019         { "wLength", "usbhid.setup.wLength", FT_UINT16, BASE_DEC, NULL, 0x0,
1020           NULL, HFILL }},
1021
1022         { &hf_usb_hid_report_type,
1023         { "ReportType", "usbhid.setup.ReportType", FT_UINT8, BASE_DEC,
1024           VALS(usb_hid_report_type_vals), 0x0,
1025           NULL, HFILL }},
1026
1027         { &hf_usb_hid_report_id,
1028         { "ReportID", "usbhid.setup.ReportID", FT_UINT8, BASE_DEC, NULL, 0x0,
1029           NULL, HFILL }},
1030
1031         { &hf_usb_hid_duration,
1032         { "Duration", "usbhid.setup.Duration", FT_UINT8, BASE_DEC, NULL, 0x0,
1033           NULL, HFILL }},
1034
1035         { &hf_usb_hid_zero,
1036         { "(zero)", "usbhid.setup.zero", FT_UINT8, BASE_DEC, NULL, 0x0,
1037           NULL, HFILL }}
1038
1039     };
1040
1041     static gint *usb_hid_subtrees[] = {
1042         &ett_usb_hid_report,
1043         &ett_usb_hid_item_header,
1044         &ett_usb_hid_wValue
1045     };
1046
1047     proto_usb_hid = proto_register_protocol("USB HID", "USBHID", "usbhid");
1048     proto_register_field_array(proto_usb_hid, hf, array_length(hf));
1049     proto_register_subtree_array(usb_hid_subtrees, array_length(usb_hid_subtrees));
1050 }
1051
1052 void
1053 proto_reg_handoff_usb_hid(void) {
1054     dissector_handle_t usb_hid_control_handle;
1055
1056     usb_hid_control_handle = new_create_dissector_handle(dissect_usb_hid_control, proto_usb_hid);
1057     dissector_add_uint("usb.control", IF_CLASS_HID, usb_hid_control_handle);
1058 }
1059
1060 /*
1061  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1062  *
1063  * Local variables:
1064  * c-basic-offset: 4
1065  * tab-width: 8
1066  * indent-tabs-mode: nil
1067  * End:
1068  *
1069  * vi: set shiftwidth=4 tabstop=8 expandtab:
1070  * :indentSize=4:tabSize=8:noTabs=true:
1071  */