source: mainline/uspace/lib/usb/src/hidpath.c@ 3a6e423

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3a6e423 was 3a6e423, checked in by Matej Klonfar <maklf@…>, 14 years ago

Parsing of usages in case of array items repaired

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 * Copyright (c) 2011 Matej Klonfar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusb
30 * @{
31 */
32/** @file
33 * HID report descriptor and report data parser implementation.
34 */
35#include <usb/classes/hidparser.h>
36#include <errno.h>
37#include <stdio.h>
38#include <malloc.h>
39#include <mem.h>
40#include <usb/debug.h>
41#include <assert.h>
42
43
44#define USB_HID_SAME_USAGE(usage1, usage2) ((usage1 == usage2) || (usage1 == 0) || (usage2 == 0))
45#define USB_HID_SAME_USAGE_PAGE(page1, page2) ((page1 == page2) || (page1 == 0) || (page2 == 0))
46
47/**
48 * Appends one item (couple of usage_path and usage) into the usage path
49 * structure
50 *
51 * @param usage_path Usage path structure
52 * @param usage_page Usage page constant
53 * @param usage Usage constant
54 * @return Error code
55 */
56int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path,
57 int32_t usage_page, int32_t usage)
58{
59 usb_hid_report_usage_path_t *item;
60
61 if(!(item=malloc(sizeof(usb_hid_report_usage_path_t)))) {
62 return ENOMEM;
63 }
64 list_initialize(&item->link);
65
66 item->usage = usage;
67 item->usage_page = usage_page;
68 item->flags = 0;
69
70 list_append (&item->link, &usage_path->head);
71 usage_path->depth++;
72 return EOK;
73}
74
75/**
76 * Removes last item from the usage path structure
77 * @param usage_path
78 * @return void
79 */
80void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
81{
82 usb_hid_report_usage_path_t *item;
83
84 if(!list_empty(&usage_path->head)){
85 item = list_get_instance(usage_path->head.prev,
86 usb_hid_report_usage_path_t, link);
87 list_remove(usage_path->head.prev);
88 usage_path->depth--;
89 free(item);
90 }
91}
92
93/**
94 * Nulls last item of the usage path structure.
95 *
96 * @param usage_path
97 * @return void
98 */
99void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
100{
101 usb_hid_report_usage_path_t *item;
102
103 if(!list_empty(&usage_path->head)){
104 item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
105 memset(item, 0, sizeof(usb_hid_report_usage_path_t));
106 }
107}
108
109/**
110 * Modifies last item of usage path structure by given usage page or usage
111 *
112 * @param usage_path Opaque usage path structure
113 * @param tag Class of currently processed tag (Usage page tag falls into Global
114 * class but Usage tag into the Local)
115 * @param data Value of the processed tag
116 * @return void
117 */
118void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path,
119 int32_t tag, int32_t data)
120{
121 usb_hid_report_usage_path_t *item;
122
123 if(!list_empty(&usage_path->head)){
124 item = list_get_instance(usage_path->head.prev,
125 usb_hid_report_usage_path_t, link);
126
127 switch(tag) {
128 case USB_HID_TAG_CLASS_GLOBAL:
129 item->usage_page = data;
130 break;
131 case USB_HID_TAG_CLASS_LOCAL:
132 item->usage = data;
133 break;
134 }
135 }
136
137}
138
139
140void usb_hid_print_usage_path(usb_hid_report_path_t *path)
141{
142 usb_log_debug("USAGE_PATH FOR RId(%d):\n", path->report_id);
143 usb_log_debug("\tLENGTH: %d\n", path->depth);
144
145 link_t *item = path->head.next;
146 usb_hid_report_usage_path_t *path_item;
147 while(item != &path->head) {
148
149 path_item = list_get_instance(item, usb_hid_report_usage_path_t, link);
150 usb_log_debug("\tUSAGE_PAGE: %X\n", path_item->usage_page);
151 usb_log_debug("\tUSAGE: %X\n", path_item->usage);
152 usb_log_debug("\tFLAGS: %d\n", path_item->flags);
153
154 item = item->next;
155 }
156}
157
158/**
159 * Compares two usage paths structures
160 *
161 *
162 * @param report_path usage path structure to compare with @path
163 * @param path usage patrh structure to compare
164 * @param flags Flags determining the mode of comparison
165 * @return EOK if both paths are identical, non zero number otherwise
166 */
167int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
168 usb_hid_report_path_t *path,
169 int flags)
170{
171 usb_hid_report_usage_path_t *report_item;
172 usb_hid_report_usage_path_t *path_item;
173
174 link_t *report_link;
175 link_t *path_link;
176
177 int only_page;
178
179 if(report_path->report_id != path->report_id) {
180 return 1;
181 }
182
183 // Empty path match all others
184 if(path->depth == 0){
185 return EOK;
186 }
187
188
189 if((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0){
190 flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY;
191 }
192
193 switch(flags){
194 /* path is somewhere in report_path */
195 case USB_HID_PATH_COMPARE_ANYWHERE:
196 if(path->depth != 1){
197 return 1;
198 }
199
200 // projit skrz cestu a kdyz nekde sedi tak vratim EOK
201 // dojduli az za konec tak nnesedi
202 report_link = report_path->head.next;
203 path_link = path->head.next;
204 path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
205
206 while(report_link != &report_path->head) {
207 report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
208 if(USB_HID_SAME_USAGE_PAGE(report_item->usage_page, path_item->usage_page)){
209 if(only_page == 0){
210 if(USB_HID_SAME_USAGE(report_item->usage, path_item->usage)) {
211 return EOK;
212 }
213 }
214 else {
215 return EOK;
216 }
217 }
218
219 report_link = report_link->next;
220 }
221
222 return 1;
223 break;
224 /* the paths must be identical */
225 case USB_HID_PATH_COMPARE_STRICT:
226 if(report_path->depth != path->depth){
227 return 1;
228 }
229
230 /* path is prefix of the report_path */
231 case USB_HID_PATH_COMPARE_BEGIN:
232
233 report_link = report_path->head.next;
234 path_link = path->head.next;
235
236 while((report_link != &report_path->head) &&
237 (path_link != &path->head)) {
238
239 report_item = list_get_instance(report_link,
240 usb_hid_report_usage_path_t,
241 link);
242
243 path_item = list_get_instance(path_link,
244 usb_hid_report_usage_path_t,
245 link);
246
247 if(!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, path_item->usage_page) ||
248 ((only_page == 0) &&
249 !USB_HID_SAME_USAGE(report_item->usage, path_item->usage))) {
250
251 return 1;
252 } else {
253 report_link = report_link->next;
254 path_link = path_link->next;
255 }
256
257 }
258
259 if((((flags & USB_HID_PATH_COMPARE_BEGIN) != 0) && (path_link == &path->head)) ||
260 ((report_link == &report_path->head) && (path_link == &path->head))) {
261 return EOK;
262 }
263 else {
264 return 1;
265 }
266 break;
267
268 /* path is suffix of report_path */
269 case USB_HID_PATH_COMPARE_END:
270
271 report_link = report_path->head.prev;
272 path_link = path->head.prev;
273
274 if(list_empty(&path->head)){
275 return EOK;
276 }
277
278 while((report_link != &report_path->head) &&
279 (path_link != &path->head)) {
280
281 report_item = list_get_instance(report_link,
282 usb_hid_report_usage_path_t,
283 link);
284 path_item = list_get_instance(path_link,
285 usb_hid_report_usage_path_t,
286 link);
287
288 if(!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, path_item->usage_page) ||
289 ((only_page == 0) &&
290 !USB_HID_SAME_USAGE(report_item->usage, path_item->usage))) {
291 return 1;
292 } else {
293 report_link = report_link->prev;
294 path_link = path_link->prev;
295 }
296
297 }
298
299 if(path_link == &path->head) {
300 return EOK;
301 }
302 else {
303 return 1;
304 }
305
306 break;
307
308 default:
309 return EINVAL;
310 }
311}
312
313/**
314 * Allocates and initializes new usage path structure.
315 *
316 * @return Initialized usage path structure
317 */
318usb_hid_report_path_t *usb_hid_report_path(void)
319{
320 usb_hid_report_path_t *path;
321 path = malloc(sizeof(usb_hid_report_path_t));
322 if(path == NULL){
323 return NULL;
324 }
325 else {
326 path->depth = 0;
327 path->report_id = 0;
328 list_initialize(&path->link);
329 list_initialize(&path->head);
330 return path;
331 }
332}
333
334/**
335 * Releases given usage path structure.
336 *
337 * @param path usage path structure to release
338 * @return void
339 */
340void usb_hid_report_path_free(usb_hid_report_path_t *path)
341{
342 while(!list_empty(&path->head)){
343 usb_hid_report_remove_last_item(path);
344 }
345
346 list_remove(&path->link);
347 free(path);
348}
349
350
351/**
352 * Clone content of given usage path to the new one
353 *
354 * @param usage_path Usage path structure to clone
355 * @return New copy of given usage path structure
356 */
357usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path)
358{
359 link_t *path_link;
360 usb_hid_report_usage_path_t *path_item;
361 usb_hid_report_usage_path_t *new_path_item;
362 usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
363
364 if(new_usage_path == NULL){
365 return NULL;
366 }
367
368 new_usage_path->report_id = usage_path->report_id;
369
370 if(list_empty(&usage_path->head)){
371 return new_usage_path;
372 }
373
374 path_link = usage_path->head.next;
375 while(path_link != &usage_path->head) {
376 path_item = list_get_instance(path_link, usb_hid_report_usage_path_t,
377 link);
378 new_path_item = malloc(sizeof(usb_hid_report_usage_path_t));
379 if(new_path_item == NULL) {
380 return NULL;
381 }
382
383 list_initialize (&new_path_item->link);
384 new_path_item->usage_page = path_item->usage_page;
385 new_path_item->usage = path_item->usage;
386 new_path_item->flags = path_item->flags;
387
388 list_append(&new_path_item->link, &new_usage_path->head);
389 new_usage_path->depth++;
390
391 path_link = path_link->next;
392 }
393
394 return new_usage_path;
395}
396
397
398/**
399 * Sets report id in usage path structure
400 *
401 * @param path Usage path structure
402 * @param report_id Report id to set
403 * @return Error code
404 */
405int usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, uint8_t report_id)
406{
407 if(path == NULL){
408 return EINVAL;
409 }
410
411 path->report_id = report_id;
412 return EOK;
413}
414
415/**
416 * @}
417 */
Note: See TracBrowser for help on using the repository browser.