dp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00043 #include <stdio.h>
00044 #include <str_error.h>
00045 #include <errno.h>
00046 #include <assert.h>
00047 #include <bool.h>
00048 #include <usb/dev/dp.h>
00049 #include <usb/descriptor.h>
00050 
00051 #define NESTING(parentname, childname) \
00052         { \
00053                 .child = USB_DESCTYPE_##childname, \
00054                 .parent = USB_DESCTYPE_##parentname, \
00055         }
00056 #define LAST_NESTING { -1, -1 }
00057 
00059 usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
00060         NESTING(CONFIGURATION, INTERFACE),
00061         NESTING(INTERFACE, ENDPOINT),
00062         NESTING(INTERFACE, HUB),
00063         NESTING(INTERFACE, HID),
00064         NESTING(HID, HID_REPORT),
00065         LAST_NESTING
00066 };
00067 
00068 #undef NESTING
00069 #undef LAST_NESTING
00070 
00077 static bool is_valid_descriptor_pointer(usb_dp_parser_data_t *data,
00078     uint8_t *ptr)
00079 {
00080         if (ptr == NULL) {
00081                 return false;
00082         }
00083 
00084         if (ptr < data->data) {
00085                 return false;
00086         }
00087 
00088         if ((size_t)(ptr - data->data) >= data->size) {
00089                 return false;
00090         }
00091 
00092         return true;
00093 }
00094 
00102 static uint8_t *get_next_descriptor(usb_dp_parser_data_t *data,
00103     uint8_t *current)
00104 {
00105         assert(is_valid_descriptor_pointer(data, current));
00106 
00107         uint8_t current_length = *current;
00108         uint8_t *next = current + current_length;
00109 
00110         if (!is_valid_descriptor_pointer(data, next)) {
00111                 return NULL;
00112         }
00113 
00114         return next;
00115 }
00116 
00126 static int get_descriptor_type(usb_dp_parser_data_t *data, uint8_t *start)
00127 {
00128         if (start == NULL) {
00129                 return -1;
00130         }
00131 
00132         start++;
00133         if (!is_valid_descriptor_pointer(data, start)) {
00134                 return -1;
00135         } else {
00136                 return (int) (*start);
00137         }
00138 }
00139 
00147 static bool is_nested_descriptor_type(usb_dp_parser_t *parser,
00148     int child, int parent)
00149 {
00150         usb_dp_descriptor_nesting_t *nesting = parser->nesting;
00151         while ((nesting->child > 0) && (nesting->parent > 0)) {
00152                 if ((nesting->child == child) && (nesting->parent == parent)) {
00153                         return true;
00154                 }
00155                 nesting++;
00156         }
00157         return false;
00158 }
00159 
00168 static bool is_nested_descriptor(usb_dp_parser_t *parser,
00169     usb_dp_parser_data_t *data, uint8_t *child, uint8_t *parent)
00170 {
00171         return is_nested_descriptor_type(parser,
00172             get_descriptor_type(data, child),
00173             get_descriptor_type(data, parent));
00174 }
00175 
00185 uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *parser,
00186     usb_dp_parser_data_t *data, uint8_t *parent)
00187 {
00188         if (!is_valid_descriptor_pointer(data, parent)) {
00189                 return NULL;
00190         }
00191 
00192         uint8_t *next = get_next_descriptor(data, parent);
00193         if (next == NULL) {
00194                 return NULL;
00195         }
00196 
00197         if (is_nested_descriptor(parser, data, next, parent)) {
00198                 return next;
00199         } else {
00200                 return NULL;
00201         }
00202 }
00203 
00213 static uint8_t *skip_nested_descriptors(usb_dp_parser_t *parser,
00214     usb_dp_parser_data_t *data, uint8_t *parent)
00215 {
00216         uint8_t *child = usb_dp_get_nested_descriptor(parser, data, parent);
00217         if (child == NULL) {
00218                 return get_next_descriptor(data, parent);
00219         }
00220         uint8_t *next_child = skip_nested_descriptors(parser, data, child);
00221         while (is_nested_descriptor(parser, data, next_child, parent)) {
00222                 next_child = skip_nested_descriptors(parser, data, next_child);
00223         }
00224 
00225         return next_child;
00226 }
00227 
00238 uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *parser,
00239     usb_dp_parser_data_t *data, uint8_t *parent, uint8_t *sibling)
00240 {
00241         if (!is_valid_descriptor_pointer(data, parent)
00242             || !is_valid_descriptor_pointer(data, sibling)) {
00243                 return NULL;
00244         }
00245 
00246         uint8_t *possible_sibling = skip_nested_descriptors(parser, data, sibling);
00247         if (possible_sibling == NULL) {
00248                 return NULL;
00249         }
00250 
00251         int parent_type = get_descriptor_type(data, parent);
00252         int possible_sibling_type = get_descriptor_type(data, possible_sibling);
00253         if (is_nested_descriptor_type(parser, possible_sibling_type, parent_type)) {
00254                 return possible_sibling;
00255         } else {
00256                 return NULL;
00257         }
00258 }
00259 
00271 static void usb_dp_browse_simple_internal(usb_dp_parser_t *parser,
00272     usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
00273     void (*callback)(uint8_t *, size_t, void *), void *arg)
00274 {
00275         if (root == NULL) {
00276                 return;
00277         }
00278         callback(root, depth, arg);
00279         uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
00280         do {
00281                 usb_dp_browse_simple_internal(parser, data, child, depth + 1,
00282                     callback, arg);
00283                 child = usb_dp_get_sibling_descriptor(parser, data,
00284                     root, child);
00285         } while (child != NULL);
00286 }
00287 
00302 void usb_dp_walk_simple(uint8_t *descriptors, size_t descriptors_size,
00303     usb_dp_descriptor_nesting_t *descriptor_nesting,
00304     void (*callback)(uint8_t *, size_t, void *), void *arg)
00305 {
00306         if ((descriptors == NULL) || (descriptors_size == 0)
00307             || (descriptor_nesting == NULL) || (callback == NULL)) {
00308                 return;
00309         }
00310 
00311         usb_dp_parser_data_t data = {
00312                 .data = descriptors,
00313                 .size = descriptors_size,
00314                 .arg = NULL
00315         };
00316 
00317         usb_dp_parser_t parser = {
00318                 .nesting = descriptor_nesting
00319         };
00320 
00321         usb_dp_browse_simple_internal(&parser, &data, descriptors,
00322             0, callback, arg);
00323 }
00324 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7