source: mainline/uspace/lib/usb/src/hidpath.c@ 5f7b75a

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

BEGIN and ANYWHERE options added to usage path comparison

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