From 4f2a365e20831076816b8672735118f654ccfcd8 Mon Sep 17 00:00:00 2001
From: Michael Drake <michael.drake@codethink.co.uk>
Date: Thu, 7 Jun 2018 12:41:16 +0100
Subject: [PATCH 7/9] lsusb: Add support for descriptor extensions.
These allow descriptors with common fields at the start, one of
which common fields specifies a field whos value determines which
of a set of descriptor extensions should be used to render the
remainder of the descriptor.
Signed-off-by: Michael Drake <michael.drake@codethink.co.uk>
---
desc-defs.c | 11 ++++++++++-
desc-defs.h | 39 ++++++++++++++++++++++++++++++++++++++-
desc-dump.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 93 insertions(+), 9 deletions(-)
diff --git a/desc-defs.c b/desc-defs.c
index 4c374e0..60cc603 100644
--- a/desc-defs.c
+++ b/desc-defs.c
@@ -2,7 +2,7 @@
/*
* USB descriptor definitions
*
- * Copyright (C) 2017 Michael Drake <michael.drake@codethink.co.uk>
+ * Copyright (C) 2017-2018 Michael Drake <michael.drake@codethink.co.uk>
*/
#include "config.h"
@@ -441,6 +441,15 @@ static const struct desc desc_audio_2_ac_processing_unit[] = {
{ .field = NULL }
};
+/**
+ * Undefined descriptor
+ *
+ * Ensures remaining data is dumped as garbage at end of descriptor.
+ */
+const struct desc desc_undefined[] = {
+ { .field = NULL }
+};
+
/** UAC3: 4.5.2.10 Processing Unit Descriptor; Table 4-38. */
static const struct desc desc_audio_3_ac_processing_unit[] = {
{ .field = "bUnitID", .size = 1, .type = DESC_NUMBER },
diff --git a/desc-defs.h b/desc-defs.h
index 99d5caa..aa695e4 100644
--- a/desc-defs.h
+++ b/desc-defs.h
@@ -2,7 +2,7 @@
/*
* USB descriptor definitions
*
- * Copyright (C) 2017 Michael Drake <michael.drake@codethink.co.uk>
+ * Copyright (C) 2017-2018 Michael Drake <michael.drake@codethink.co.uk>
*/
#ifndef _DESC_DEFS_H
@@ -33,6 +33,7 @@ enum desc_type {
DESC_TERMINAL_STR, /**< Audio terminal string. */
DESC_BITMAP_STRINGS, /**< Bitfield with string per bit. */
DESC_NUMBER_STRINGS, /**< Use for enum-style value to string. */
+ DESC_EXTENSION, /**< Various possible descriptor extensions. */
DESC_SNOWFLAKE, /**< Value with custom annotation callback function. */
};
@@ -95,6 +96,39 @@ struct desc {
* Must be a '\0' terminated string.
*/
const char *number_postfix;
+ /**
+ * Corresponds to type DESC_EXTENSION.
+ *
+ * This allows the value of this field to be processed by
+ * another descriptor definition. The definition used to
+ * process the value of this field can be controlled by
+ * the value of another field.
+ */
+ struct {
+ /**
+ * Name of field specifying descriptor type to select.
+ */
+ const char *type_field;
+ /**
+ * Array of descriptor definitions and their
+ * associated types values. Array must be terminated
+ * by entry with NULL `desc` member.
+ */
+ const struct desc_ext {
+ /**
+ * Array of descriptor field definitions.
+ * Terminated by entry with NULL `field` member.
+ */
+ const struct desc *desc;
+ /**
+ * Type value for this descriptor definition.
+ * If it matches the type read from the
+ * field `type_field`, then this descriptor
+ * definition will be used to decode this value.
+ */
+ unsigned int type;
+ } *d;
+ } extension;
/**
* Corresponds to type DESC_SNOWFLAKE.
*
@@ -116,6 +150,9 @@ struct desc {
/* ---------------------------------------------------------------------- */
+/* Undefined descriptor */
+extern const struct desc desc_undefined[];
+
/* Audio Control (AC) descriptor definitions */
extern const struct desc * const desc_audio_ac_header[3];
extern const struct desc * const desc_audio_ac_effect_unit[3];
diff --git a/desc-dump.c b/desc-dump.c
index 2f92768..19d2cc7 100644
--- a/desc-dump.c
+++ b/desc-dump.c
@@ -211,8 +211,10 @@ static void number_renderer(
*
* \param[in] dev LibUSB device handle.
* \param[in] current Descriptor definition field to render.
- * \param[in] current_size Descriptor definition field to render.
+ * \param[in] current_size Size of value to render.
* \param[in] buf Byte array containing the descriptor date to dump.
+ * \param[in] buf_len Byte length of `buf`.
+ * \param[in] desc First field in the descriptor definition.
* \param[in] indent Current indent level.
* \param[in] offset Offset to current value in `buf`.
*/
@@ -221,6 +223,8 @@ static void value_renderer(
const struct desc *current,
unsigned int current_size,
const unsigned char *buf,
+ unsigned int buf_len,
+ const struct desc *desc,
unsigned int indent,
size_t offset)
{
@@ -312,6 +316,31 @@ static void value_renderer(
printf(" %s\n", names_audioterminal(
get_n_bytes_as_ull(buf, offset, current_size)));
break;
+ case DESC_EXTENSION: {
+ unsigned int type = get_value_from_field(buf, desc,
+ current->extension.type_field);
+ const struct desc *ext_desc;
+ const struct desc_ext *ext;
+
+ /* Lookup the extention descriptor definitions to use, */
+ for (ext = current->extension.d; ext->desc != NULL; ext++) {
+ if (ext->type == type) {
+ ext_desc = ext->desc;
+ break;
+ }
+ }
+
+ /* If the type didn't match a known type, use the
+ * undefined descriptor. */
+ if (ext->desc == NULL) {
+ ext_desc = desc_undefined;
+ }
+
+ desc_dump(dev, ext_desc, buf + offset,
+ buf_len - offset, indent);
+
+ break;
+ }
case DESC_SNOWFLAKE:
number_renderer(buf, size_chars, offset, current_size);
current->snowflake(
@@ -537,14 +566,23 @@ void desc_dump(
}
/* Dump the field name */
- field_render(entry, entries, field_len,
- current, indent);
+ if (current->type != DESC_EXTENSION) {
+ field_render(entry, entries, field_len,
+ current, indent);
+ }
/* Dump the value */
- value_renderer(dev, current, current_size, buf,
- indent, offset);
- /* Advance offset in buffer */
- offset += current_size;
+ value_renderer(dev, current, current_size, buf, buf_len,
+ desc, indent, offset);
+
+ if (current->type == DESC_EXTENSION) {
+ /* A desc extension consumes all remaining
+ * value buffer. */
+ offset = buf_len;
+ } else {
+ /* Advance offset in buffer */
+ offset += current_size;
+ }
}
}
--
2.14.4