00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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