208 lines
6.2 KiB
Diff
208 lines
6.2 KiB
Diff
|
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
|
||
|
|