HelenOS sources
This source file includes following definitions.
- is_valid_descriptor_pointer
- get_next_descriptor
- get_descriptor_type
- is_nested_descriptor_type
- is_nested_descriptor
- usb_dp_get_nested_descriptor
- skip_nested_descriptors
- usb_dp_get_sibling_descriptor
- usb_dp_browse_simple_internal
- usb_dp_walk_simple
#include <usb/dev/dp.h>
#include <usb/descriptor.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define NESTING(parentname, childname) \
{ \
.child = USB_DESCTYPE_##childname, \
.parent = USB_DESCTYPE_##parentname, \
}
#define LAST_NESTING { -1, -1 }
const usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
NESTING(CONFIGURATION, INTERFACE),
NESTING(INTERFACE, ENDPOINT),
NESTING(ENDPOINT, SSPEED_EP_COMPANION),
NESTING(INTERFACE, HUB),
NESTING(INTERFACE, HID),
NESTING(HID, HID_REPORT),
LAST_NESTING
};
#undef NESTING
#undef LAST_NESTING
static bool is_valid_descriptor_pointer(const usb_dp_parser_data_t *data,
const uint8_t *ptr)
{
if (ptr == NULL) {
return false;
}
if (ptr < data->data) {
return false;
}
if ((size_t)(ptr - data->data) >= data->size) {
return false;
}
return true;
}
static const uint8_t *get_next_descriptor(const usb_dp_parser_data_t *data,
const uint8_t *current)
{
assert(is_valid_descriptor_pointer(data, current));
const uint8_t current_length = *current;
const uint8_t *next = current + current_length;
if (!is_valid_descriptor_pointer(data, next)) {
return NULL;
}
return next;
}
static int get_descriptor_type(const usb_dp_parser_data_t *data,
const uint8_t *start)
{
if (start == NULL) {
return -1;
}
start++;
if (!is_valid_descriptor_pointer(data, start)) {
return -1;
} else {
return (int) (*start);
}
}
static bool is_nested_descriptor_type(const usb_dp_parser_t *parser,
int child, int parent)
{
const usb_dp_descriptor_nesting_t *nesting = parser->nesting;
while ((nesting->child > 0) && (nesting->parent > 0)) {
if ((nesting->child == child) && (nesting->parent == parent)) {
return true;
}
nesting++;
}
return false;
}
static bool is_nested_descriptor(const usb_dp_parser_t *parser,
const usb_dp_parser_data_t *data, const uint8_t *child, const uint8_t *parent)
{
return is_nested_descriptor_type(parser,
get_descriptor_type(data, child),
get_descriptor_type(data, parent));
}
const uint8_t *usb_dp_get_nested_descriptor(const usb_dp_parser_t *parser,
const usb_dp_parser_data_t *data, const uint8_t *parent)
{
if (!is_valid_descriptor_pointer(data, parent)) {
return NULL;
}
const uint8_t *next = get_next_descriptor(data, parent);
if (next == NULL) {
return NULL;
}
if (is_nested_descriptor(parser, data, next, parent)) {
return next;
} else {
return NULL;
}
}
static const uint8_t *skip_nested_descriptors(const usb_dp_parser_t *parser,
const usb_dp_parser_data_t *data, const uint8_t *parent)
{
const uint8_t *child =
usb_dp_get_nested_descriptor(parser, data, parent);
if (child == NULL) {
return get_next_descriptor(data, parent);
}
const uint8_t *next_child =
skip_nested_descriptors(parser, data, child);
while (is_nested_descriptor(parser, data, next_child, parent)) {
next_child = skip_nested_descriptors(parser, data, next_child);
}
return next_child;
}
const uint8_t *usb_dp_get_sibling_descriptor(
const usb_dp_parser_t *parser, const usb_dp_parser_data_t *data,
const uint8_t *parent, const uint8_t *sibling)
{
if (!is_valid_descriptor_pointer(data, parent) ||
!is_valid_descriptor_pointer(data, sibling)) {
return NULL;
}
const uint8_t *possible_sibling =
skip_nested_descriptors(parser, data, sibling);
if (possible_sibling == NULL) {
return NULL;
}
int parent_type = get_descriptor_type(data, parent);
int possible_sibling_type = get_descriptor_type(data, possible_sibling);
if (is_nested_descriptor_type(parser,
possible_sibling_type, parent_type)) {
return possible_sibling;
} else {
return NULL;
}
}
static void usb_dp_browse_simple_internal(const usb_dp_parser_t *parser,
const usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
void (*callback)(const uint8_t *, size_t, void *), void *arg)
{
if (root == NULL) {
return;
}
callback(root, depth, arg);
const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
do {
usb_dp_browse_simple_internal(parser, data, child, depth + 1,
callback, arg);
child = usb_dp_get_sibling_descriptor(parser, data,
root, child);
} while (child != NULL);
}
void usb_dp_walk_simple(const uint8_t *descriptors, size_t descriptors_size,
const usb_dp_descriptor_nesting_t *descriptor_nesting,
walk_callback_t callback, void *arg)
{
if ((descriptors == NULL) || (descriptors_size == 0) ||
(descriptor_nesting == NULL) || (callback == NULL)) {
return;
}
const usb_dp_parser_data_t data = {
.data = descriptors,
.size = descriptors_size,
.arg = NULL
};
const usb_dp_parser_t parser = {
.nesting = descriptor_nesting
};
usb_dp_browse_simple_internal(&parser, &data, descriptors,
0, callback, arg);
}
HelenOS homepage, sources at GitHub