source: mainline/uspace/lib/usbhid/src/hidpath.c

Last change on this file was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 10.6 KB
RevLine 
[9d05599]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
[160b75e]29/** @addtogroup libusbhid
[9d05599]30 * @{
31 */
32/** @file
33 * HID report descriptor and report data parser implementation.
34 */
[faa44e58]35#include <usb/hid/hidparser.h>
[9d05599]36#include <errno.h>
37#include <stdio.h>
38#include <mem.h>
[38d150e]39#include <stdlib.h>
[9d05599]40#include <usb/debug.h>
41#include <assert.h>
42
[5499a8b]43/**
44 * Compares two usages if they are same or not or one of the usages is not
45 * set.
46 *
47 * @param usage1
48 * @param usage2
49 * @return boolean
50 */
51#define USB_HID_SAME_USAGE(usage1, usage2) \
52 ((usage1 == usage2) || (usage1 == 0) || (usage2 == 0))
[9d05599]53
[5499a8b]54/**
55 * Compares two usage pages if they are same or not or one of them is not set.
56 *
57 * @param page1
58 * @param page2
59 * @return boolean
60 */
61#define USB_HID_SAME_USAGE_PAGE(page1, page2) \
62 ((page1 == page2) || (page1 == 0) || (page2 == 0))
[3a6e423]63
[9d05599]64/**
65 * Appends one item (couple of usage_path and usage) into the usage path
66 * structure
67 *
68 * @param usage_path Usage path structure
69 * @param usage_page Usage page constant
70 * @param usage Usage constant
71 * @return Error code
72 */
[ae3a941]73errno_t usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path,
74 int32_t usage_page, int32_t usage)
75{
76 usb_hid_report_usage_path_t *item =
77 malloc(sizeof(usb_hid_report_usage_path_t));
[9d05599]78
[4bb7ffe]79 if (item == NULL) {
[9d05599]80 return ENOMEM;
81 }
[b72efe8]82 link_initialize(&item->rpath_items_link);
[9d05599]83
84 item->usage = usage;
85 item->usage_page = usage_page;
86 item->flags = 0;
[ae3a941]87
[b72efe8]88 list_append (&item->rpath_items_link, &usage_path->items);
[9d05599]89 usage_path->depth++;
90 return EOK;
91}
92
93/**
94 * Removes last item from the usage path structure
[ae3a941]95 * @param usage_path
[9d05599]96 * @return void
97 */
98void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
99{
[b72efe8]100 link_t *item_link;
[9d05599]101 usb_hid_report_usage_path_t *item;
[ae3a941]102
103 if (!list_empty(&usage_path->items)) {
[b72efe8]104 item_link = list_last(&usage_path->items);
105 item = list_get_instance(item_link,
106 usb_hid_report_usage_path_t, rpath_items_link);
107 list_remove(item_link);
[9d05599]108 usage_path->depth--;
109 free(item);
110 }
111}
112
113/**
114 * Nulls last item of the usage path structure.
115 *
116 * @param usage_path
117 * @return void
118 */
119void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
120{
121 usb_hid_report_usage_path_t *item;
[ae3a941]122
123 if (!list_empty(&usage_path->items)) {
[b72efe8]124 item = list_get_instance(list_last(&usage_path->items),
[ae3a941]125 usb_hid_report_usage_path_t, rpath_items_link);
[5499a8b]126
[9d05599]127 memset(item, 0, sizeof(usb_hid_report_usage_path_t));
128 }
129}
130
131/**
132 * Modifies last item of usage path structure by given usage page or usage
133 *
134 * @param usage_path Opaque usage path structure
135 * @param tag Class of currently processed tag (Usage page tag falls into Global
136 * class but Usage tag into the Local)
137 * @param data Value of the processed tag
138 * @return void
139 */
[ae3a941]140void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path,
141 int32_t tag, int32_t data)
[9d05599]142{
143 usb_hid_report_usage_path_t *item;
[ae3a941]144
145 if (!list_empty(&usage_path->items)) {
[b72efe8]146 item = list_get_instance(list_last(&usage_path->items),
[1433ecda]147 usb_hid_report_usage_path_t, rpath_items_link);
[9d05599]148
[ae3a941]149 switch (tag) {
150 case USB_HID_TAG_CLASS_GLOBAL:
151 item->usage_page = data;
152 break;
153 case USB_HID_TAG_CLASS_LOCAL:
154 item->usage = data;
155 break;
[9d05599]156 }
157 }
158}
159
160void usb_hid_print_usage_path(usb_hid_report_path_t *path)
161{
[a1732929]162 usb_log_debug("USAGE_PATH FOR RId(%d):", path->report_id);
163 usb_log_debug("\tLENGTH: %d", path->depth);
[9d05599]164
[feeac0d]165 list_foreach(path->items, rpath_items_link,
166 usb_hid_report_usage_path_t, path_item) {
[5499a8b]167
[a1732929]168 usb_log_debug("\tUSAGE_PAGE: %X", path_item->usage_page);
169 usb_log_debug("\tUSAGE: %X", path_item->usage);
170 usb_log_debug("\tFLAGS: %d", path_item->flags);
[9d05599]171 }
172}
173
[e141281]174/** Compare two usage paths structures
[9d05599]175 *
[e141281]176 * @param report_path Usage path structure to compare with @path
177 * @param path Usage patrh structure to compare
178 * @param flags Flags determining the mode of comparison
[9d05599]179 *
[3ca4ae9]180 * @return 0 if both paths are identical, non zero number otherwise
[e141281]181 *
[9d05599]182 */
[e141281]183int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
184 usb_hid_report_path_t *path, int flags)
[9d05599]185{
186 usb_hid_report_usage_path_t *report_item;
187 usb_hid_report_usage_path_t *path_item;
[ae3a941]188
[9d05599]189 link_t *report_link;
190 link_t *path_link;
[ae3a941]191
[9d05599]192 int only_page;
[ae3a941]193
[e141281]194 if (report_path->report_id != path->report_id) {
195 if (path->report_id != 0) {
[dcb7d7cd]196 return 1;
197 }
[9d05599]198 }
[ae3a941]199
[5f7b75a]200 // Empty path match all others
[e141281]201 if (path->depth == 0) {
[3ca4ae9]202 return 0;
[9d05599]203 }
[ae3a941]204
[e141281]205 if ((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0) {
[9d05599]206 flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY;
207 }
[ae3a941]208
[e141281]209 switch (flags) {
[f3b39b4]210 case USB_HID_PATH_COMPARE_ANYWHERE:
[6ff23ff]211 /*
212 * Path is somewhere in report_path
213 */
[e141281]214 if (path->depth != 1) {
[f3b39b4]215 return 1;
216 }
[ae3a941]217
[b72efe8]218 path_link = list_first(&path->items);
219 path_item = list_get_instance(path_link,
[e141281]220 usb_hid_report_usage_path_t, rpath_items_link);
[ae3a941]221
[feeac0d]222 list_foreach(report_path->items, rpath_items_link,
223 usb_hid_report_usage_path_t, report_item) {
[07525cd]224 if (USB_HID_SAME_USAGE_PAGE(report_item->usage_page,
[e141281]225 path_item->usage_page)) {
[ae3a941]226
[07525cd]227 if (only_page == 0) {
228 if (USB_HID_SAME_USAGE(report_item->usage,
229 path_item->usage))
[3ca4ae9]230 return 0;
[e141281]231 } else {
[3ca4ae9]232 return 0;
[f3b39b4]233 }
[5f7b75a]234 }
[f3b39b4]235 }
[ae3a941]236
[f3b39b4]237 return 1;
[ae3a941]238
[f3b39b4]239 case USB_HID_PATH_COMPARE_STRICT:
[6ff23ff]240 /*
241 * The paths must be identical
242 */
[e141281]243 if (report_path->depth != path->depth) {
[5f7b75a]244 return 1;
[f3b39b4]245 }
[dc12262]246 /* Fallthrough */
[ae3a941]247
[f3b39b4]248 case USB_HID_PATH_COMPARE_BEGIN:
[6ff23ff]249 /*
250 * Path is prefix of the report_path
251 */
[b72efe8]252 report_link = report_path->items.head.next;
253 path_link = path->items.head.next;
[ae3a941]254
[07525cd]255 while ((report_link != &report_path->items.head) &&
256 (path_link != &path->items.head)) {
[ae3a941]257
[e141281]258 report_item = list_get_instance(report_link,
[07525cd]259 usb_hid_report_usage_path_t, rpath_items_link);
[ae3a941]260
[f3b39b4]261 path_item = list_get_instance(path_link,
[e141281]262 usb_hid_report_usage_path_t, rpath_items_link);
[ae3a941]263
[e141281]264 if (!USB_HID_SAME_USAGE_PAGE(report_item->usage_page,
265 path_item->usage_page) || ((only_page == 0) &&
266 !USB_HID_SAME_USAGE(report_item->usage,
[07525cd]267 path_item->usage))) {
[f3b39b4]268 return 1;
[feeac0d]269 } else {
[f3b39b4]270 report_link = report_link->next;
[feeac0d]271 path_link = path_link->next;
[f3b39b4]272 }
[b72efe8]273 }
[ae3a941]274
[e141281]275 if ((((flags & USB_HID_PATH_COMPARE_BEGIN) != 0) &&
276 (path_link == &path->items.head)) ||
277 ((report_link == &report_path->items.head) &&
[07525cd]278 (path_link == &path->items.head))) {
[3ca4ae9]279 return 0;
[07525cd]280 } else {
[f3b39b4]281 return 1;
[07525cd]282 }
[f3b39b4]283 break;
[ae3a941]284
[f3b39b4]285 case USB_HID_PATH_COMPARE_END:
[6ff23ff]286 /*
287 * Path is suffix of report_path
288 */
[b72efe8]289 report_link = report_path->items.head.prev;
290 path_link = path->items.head.prev;
[ae3a941]291
[e141281]292 if (list_empty(&path->items)) {
[3ca4ae9]293 return 0;
[f3b39b4]294 }
[ae3a941]295
[e141281]296 while ((report_link != &report_path->items.head) &&
[1433ecda]297 (path_link != &path->items.head)) {
[b72efe8]298 report_item = list_get_instance(report_link,
[e141281]299 usb_hid_report_usage_path_t, rpath_items_link);
[ae3a941]300
[e141281]301 path_item = list_get_instance(path_link,
302 usb_hid_report_usage_path_t, rpath_items_link);
[ae3a941]303
[e141281]304 if (!USB_HID_SAME_USAGE_PAGE(report_item->usage_page,
305 path_item->usage_page) || ((only_page == 0) &&
306 !USB_HID_SAME_USAGE(report_item->usage,
307 path_item->usage))) {
308 return 1;
[f3b39b4]309 } else {
310 report_link = report_link->prev;
[e141281]311 path_link = path_link->prev;
[f3b39b4]312 }
313 }
[ae3a941]314
[e141281]315 if (path_link == &path->items.head) {
[3ca4ae9]316 return 0;
[e141281]317 } else {
[f3b39b4]318 return 1;
[e141281]319 }
[f3b39b4]320 break;
[ae3a941]321
[f3b39b4]322 default:
[3ca4ae9]323 return -1;
[9d05599]324 }
325}
326
327/**
328 * Allocates and initializes new usage path structure.
329 *
330 * @return Initialized usage path structure
331 */
332usb_hid_report_path_t *usb_hid_report_path(void)
333{
334 usb_hid_report_path_t *path;
335 path = malloc(sizeof(usb_hid_report_path_t));
[ae3a941]336 if (path == NULL) {
[9d05599]337 return NULL;
[1433ecda]338 } else {
[9d05599]339 path->depth = 0;
340 path->report_id = 0;
[b72efe8]341 link_initialize(&path->cpath_link);
342 list_initialize(&path->items);
[9d05599]343 return path;
344 }
345}
346
347/**
348 * Releases given usage path structure.
349 *
350 * @param path usage path structure to release
351 * @return void
352 */
353void usb_hid_report_path_free(usb_hid_report_path_t *path)
354{
[0cda600]355 if (path == NULL)
356 return;
[ae3a941]357 while (!list_empty(&path->items)) {
[9d05599]358 usb_hid_report_remove_last_item(path);
359 }
360
[b72efe8]361 assert_link_not_used(&path->cpath_link);
[9d05599]362 free(path);
363}
364
365/**
366 * Clone content of given usage path to the new one
367 *
368 * @param usage_path Usage path structure to clone
369 * @return New copy of given usage path structure
370 */
[5499a8b]371usb_hid_report_path_t *usb_hid_report_path_clone(
[ae3a941]372 usb_hid_report_path_t *usage_path)
[9d05599]373{
374 usb_hid_report_usage_path_t *new_path_item;
375 usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
376
[ae3a941]377 if (new_usage_path == NULL) {
[9d05599]378 return NULL;
379 }
380
381 new_usage_path->report_id = usage_path->report_id;
[ae3a941]382
383 if (list_empty(&usage_path->items)) {
[9d05599]384 return new_usage_path;
385 }
386
[feeac0d]387 list_foreach(usage_path->items, rpath_items_link,
388 usb_hid_report_usage_path_t, path_item) {
[f3b39b4]389
[9d05599]390 new_path_item = malloc(sizeof(usb_hid_report_usage_path_t));
[ae3a941]391 if (new_path_item == NULL) {
[9d05599]392 return NULL;
393 }
[ae3a941]394
[b72efe8]395 link_initialize(&new_path_item->rpath_items_link);
[9d05599]396 new_path_item->usage_page = path_item->usage_page;
[ae3a941]397 new_path_item->usage = path_item->usage;
398 new_path_item->flags = path_item->flags;
399
[b72efe8]400 list_append(&new_path_item->rpath_items_link,
401 &new_usage_path->items);
[9d05599]402 new_usage_path->depth++;
403 }
404
405 return new_usage_path;
406}
407
408/**
409 * Sets report id in usage path structure
410 *
411 * @param path Usage path structure
412 * @param report_id Report id to set
413 * @return Error code
414 */
[ae3a941]415errno_t usb_hid_report_path_set_report_id(usb_hid_report_path_t *path,
416 uint8_t report_id)
[9d05599]417{
[ae3a941]418 if (path == NULL) {
[9d05599]419 return EINVAL;
420 }
421
422 path->report_id = report_id;
423 return EOK;
424}
425
426/**
427 * @}
428 */
Note: See TracBrowser for help on using the repository browser.