Skip to content

Commit 1dde8e2

Browse files
tmon-nordicdleach02
authored andcommitted
usb: device_next: uac2: Generate Feature Unit descriptor
Rework NUM_SPATIAL_LOCATIONS() to evaluate to integer literal to allow using it with LISTIFY() macro. This is necessary because Feature Unit do not operate on channel clusters but rather on logical channels. Track back Output Terminal channel cluster to appropriate entity. This is necessary because Feature Unit does not repeat the channel cluster information. Signed-off-by: Tomasz Moń <[email protected]>
1 parent 3ca52a0 commit 1dde8e2

File tree

1 file changed

+130
-9
lines changed

1 file changed

+130
-9
lines changed

subsys/usb/device_next/class/usbd_uac2_macros.h

Lines changed: 130 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@
108108
#define EXT_FORMAT_TYPE_II 130
109109
#define EXT_FORMAT_TYPE_III 131
110110

111+
/* Convert 0 to empty and everything else to itself */
112+
#define EMPTY_ON_ZERO(value) COND_CODE_0(value, (), (value))
113+
111114
/* Automatically assign Entity IDs based on entities order in devicetree */
112115
#define ENTITY_ID(e) UTIL_INC(DT_NODE_CHILD_IDX(e))
113116

@@ -168,12 +171,26 @@
168171
* control is present but read-only and 0b11 when control can be programmed by
169172
* host. Value 0b10 is not allowed by the specification.
170173
*/
171-
#define CONTROL_BITS(entity, control_name, bitshift) \
174+
#define CONTROL_NOT_PRESENT 0x0
175+
#define CONTROL_READ_ONLY 0x1
176+
#define CONTROL_HOST_PROGRAMMABLE 0x3
177+
178+
#define CONTROL_TOKEN(entity, control_name) \
172179
COND_CODE_1(DT_NODE_HAS_PROP(entity, control_name), \
173-
(COND_CODE_0(DT_ENUM_IDX(entity, control_name), \
174-
((0x1 << bitshift)) /* read-only */, \
175-
((0x3 << bitshift)) /* host-programmable */)), \
176-
((0x0 << bitshift)) /* control not present */)
180+
(DT_STRING_UPPER_TOKEN(entity, control_name)), \
181+
(NOT_PRESENT))
182+
183+
#define CONTROL_BITS(entity, control_name, bitshift) \
184+
(UTIL_CAT(CONTROL_, CONTROL_TOKEN(entity, control_name)) << bitshift)
185+
186+
#define CONTROL_TOKEN_BY_IDX(entity, control_name, idx) \
187+
COND_CODE_1(DT_PROP_HAS_IDX(entity, control_name, idx), \
188+
(DT_STRING_UPPER_TOKEN_BY_IDX(entity, control_name, idx)), \
189+
(NOT_PRESENT))
190+
191+
#define CONTROL_BITS_BY_IDX(entity, control_name, idx, bitshift) \
192+
(UTIL_CAT(CONTROL_, CONTROL_TOKEN_BY_IDX(entity, control_name, idx)) \
193+
<< bitshift)
177194

178195
#define CLOCK_SOURCE_CONTROLS(entity) \
179196
CONTROL_BITS(entity, frequency_control, 0) | \
@@ -194,6 +211,23 @@
194211
CONTROL_BITS(entity, underflow_control, 6) | \
195212
CONTROL_BITS(entity, overflow_control, 8)
196213

214+
#define FEATURE_UNIT_CHANNEL_CONTROLS(entity, ch) \
215+
CONTROL_BITS_BY_IDX(entity, mute_control, ch, 0) | \
216+
CONTROL_BITS_BY_IDX(entity, volume_control, ch, 2) | \
217+
CONTROL_BITS_BY_IDX(entity, bass_control, ch, 4) | \
218+
CONTROL_BITS_BY_IDX(entity, mid_control, ch, 6) | \
219+
CONTROL_BITS_BY_IDX(entity, treble_control, ch, 8) | \
220+
CONTROL_BITS_BY_IDX(entity, graphic_equalizer_control, ch, 10) | \
221+
CONTROL_BITS_BY_IDX(entity, automatic_gain_control, ch, 12) | \
222+
CONTROL_BITS_BY_IDX(entity, delay_control, ch, 14) | \
223+
CONTROL_BITS_BY_IDX(entity, bass_boost_control, ch, 16) | \
224+
CONTROL_BITS_BY_IDX(entity, loudness_control, ch, 18) | \
225+
CONTROL_BITS_BY_IDX(entity, input_gain_control, ch, 20) | \
226+
CONTROL_BITS_BY_IDX(entity, input_gain_pad_control, ch, 22) | \
227+
CONTROL_BITS_BY_IDX(entity, phase_inverter_control, ch, 24) | \
228+
CONTROL_BITS_BY_IDX(entity, underflow_control, ch, 26) | \
229+
CONTROL_BITS_BY_IDX(entity, overflow_control, ch, 28)
230+
197231
#define AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node) \
198232
CONTROL_BITS(node, pitch_control, 0) | \
199233
CONTROL_BITS(node, data_overrun_control, 2) | \
@@ -233,10 +267,24 @@
233267

234268
#define SPATIAL_LOCATIONS_U32(entity) \
235269
(FOR_EACH_IDX(ARRAY_BIT, (|), SPATIAL_LOCATIONS_ARRAY(entity)))
236-
#define NUM_SPATIAL_LOCATIONS(entity) \
237-
(FOR_EACH(IDENTITY, (+), SPATIAL_LOCATIONS_ARRAY(entity)))
270+
#define NUM_SPATIAL_LOCATIONS(entity) \
271+
NUM_VA_ARGS(LIST_DROP_EMPTY( \
272+
FOR_EACH(EMPTY_ON_ZERO, (,), SPATIAL_LOCATIONS_ARRAY(entity)) \
273+
))
238274
#define SPATIAL_LOCATIONS(entity) U32_LE(SPATIAL_LOCATIONS_U32(entity))
239275

276+
#define FEATURE_UNIT_NUM_CHANNELS(entity) \
277+
NUM_SPATIAL_LOCATIONS(DT_PHANDLE_BY_IDX(entity, data_source, 0))
278+
279+
#define FEATURE_UNIT_CONTROLS_BY_IDX(i, entity) \
280+
U32_LE(FEATURE_UNIT_CHANNEL_CONTROLS(entity, i))
281+
282+
#define FEATURE_UNIT_CONTROLS_ARRAYS(entity) \
283+
LISTIFY(UTIL_INC(FEATURE_UNIT_NUM_CHANNELS(entity)), \
284+
FEATURE_UNIT_CONTROLS_BY_IDX, (,), entity)
285+
286+
#define FEATURE_UNIT_DESCRIPTOR_LENGTH(entity) \
287+
(6 + (FEATURE_UNIT_NUM_CHANNELS(entity) + 1) * 4)
240288

241289
/* 4.7.2.1 Clock Source Descriptor */
242290
#define CLOCK_SOURCE_DESCRIPTOR(entity) \
@@ -277,6 +325,16 @@
277325
U16_LE(OUTPUT_TERMINAL_CONTROLS(entity)), /* bmControls */ \
278326
0x00, /* iTerminal */
279327

328+
/* 4.7.2.8 Feature Unit Descriptor */
329+
#define FEATURE_UNIT_DESCRIPTOR(entity) \
330+
FEATURE_UNIT_DESCRIPTOR_LENGTH(entity), /* bLength */ \
331+
CS_INTERFACE, /* bDescriptorType */ \
332+
AC_DESCRIPTOR_FEATURE_UNIT, /* bDescriptorSubtype */\
333+
ENTITY_ID(entity), /* bUnitID */ \
334+
CONNECTED_ENTITY_ID(entity, data_source), /* bSourceID */ \
335+
FEATURE_UNIT_CONTROLS_ARRAYS(entity), /* bmaControls 0..ch */ \
336+
0x00, /* iFeature */
337+
280338
#define ENTITY_HEADER(entity) \
281339
IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), ( \
282340
CLOCK_SOURCE_DESCRIPTOR(entity) \
@@ -286,6 +344,9 @@
286344
)) \
287345
IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal), ( \
288346
OUTPUT_TERMINAL_DESCRIPTOR(entity) \
347+
)) \
348+
IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_feature_unit), ( \
349+
FEATURE_UNIT_DESCRIPTOR(entity) \
289350
))
290351

291352
#define ENTITY_HEADER_ARRAYS(entity) \
@@ -318,6 +379,23 @@
318379
(FORMAT_TYPE_I), (FORMAT_TYPE_IV))
319380
#define AUDIO_STREAMING_FORMATS(node) U32_LE(0x00000001)
320381

382+
#define FEATURE_UNIT_CHANNEL_CLUSTER(node) \
383+
IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, data_source), \
384+
zephyr_uac2_input_terminal), ( \
385+
DT_PROP(node, data_source) \
386+
))
387+
388+
/* Track back Output Terminal data source to entity that has channel cluster */
389+
#define OUTPUT_TERMINAL_CHANNEL_CLUSTER(node) \
390+
IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, data_source), \
391+
zephyr_uac2_input_terminal), ( \
392+
DT_PROP(node, data_source) \
393+
)) \
394+
IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, data_source), \
395+
zephyr_uac2_feature_unit), ( \
396+
FEATURE_UNIT_CHANNEL_CLUSTER(DT_PROP(node, data_source))\
397+
))
398+
321399
/* If AudioStreaming is linked to input terminal, obtain the channel cluster
322400
* configuration from the linked terminal. Otherwise (it has to be connected
323401
* to output terminal) obtain the channel cluster configuration from data source
@@ -329,8 +407,8 @@
329407
DT_PROP(node, linked_terminal) \
330408
)) \
331409
IF_ENABLED(DT_NODE_HAS_COMPAT(DT_PROP(node, linked_terminal), \
332-
zephyr_uac2_output_terminal), ( \
333-
DT_PROP(DT_PROP(node, linked_terminal), data_source) \
410+
zephyr_uac2_output_terminal), (OUTPUT_TERMINAL_CHANNEL_CLUSTER( \
411+
DT_PROP(node, linked_terminal)) \
334412
))
335413

336414
#define AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node) \
@@ -928,6 +1006,42 @@
9281006
DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal), \
9291007
zephyr_uac2_input_terminal))
9301008

1009+
#define VALIDATE_OUTPUT_TERMINAL_DATA_SOURCE(entity) \
1010+
UTIL_OR(DT_NODE_HAS_COMPAT(DT_PROP(entity, data_source), \
1011+
zephyr_uac2_input_terminal), \
1012+
DT_NODE_HAS_COMPAT(DT_PROP(entity, data_source), \
1013+
zephyr_uac2_feature_unit))
1014+
1015+
#define VALIDATE_FEATURE_UNIT_DATA_SOURCE(entity) \
1016+
DT_NODE_HAS_COMPAT(DT_PROP(entity, data_source), \
1017+
zephyr_uac2_input_terminal)
1018+
1019+
#define BUILD_ASSERT_FEATURE_UNIT_CONTROL(fu, control) \
1020+
BUILD_ASSERT(UTIL_OR(UTIL_NOT(DT_NODE_HAS_PROP(fu, control)), \
1021+
DT_PROP_LEN(fu, control) <= 1 + FEATURE_UNIT_NUM_CHANNELS(fu)), \
1022+
"Feature Unit " DT_NODE_PATH(fu) " has " \
1023+
STRINGIFY(FEATURE_UNIT_NUM_CHANNELS(fu)) " logical channel(s) " \
1024+
"but its property " #control " has " \
1025+
STRINGIFY(DT_PROP_LEN(fu, control)) " values" \
1026+
);
1027+
1028+
#define BUILD_ASSERT_FEATURE_UNIT_CONTROLS_LENGTH(entity) \
1029+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, mute_control) \
1030+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, volume_control) \
1031+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, bass_control) \
1032+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, mid_control) \
1033+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, treble_control) \
1034+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, graphic_equalizer_control) \
1035+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, automatic_gain_control) \
1036+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, delay_control) \
1037+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, bass_boost_control) \
1038+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, loudness_control) \
1039+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, input_gain_control) \
1040+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, input_gain_pad_control) \
1041+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, phase_inverter_control) \
1042+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, underflow_control) \
1043+
BUILD_ASSERT_FEATURE_UNIT_CONTROL(entity, overflow_control)
1044+
9311045
#define NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) UTIL_OR( \
9321046
UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I), \
9331047
IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_III)), \
@@ -973,6 +1087,13 @@
9731087
IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_output_terminal), ( \
9741088
BUILD_ASSERT(VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(node), \
9751089
"Terminals associations must be Input<->Output"); \
1090+
BUILD_ASSERT(VALIDATE_OUTPUT_TERMINAL_DATA_SOURCE(node), \
1091+
"Unsupported Output Terminal data source"); \
1092+
)) \
1093+
IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_feature_unit), ( \
1094+
BUILD_ASSERT(VALIDATE_FEATURE_UNIT_DATA_SOURCE(node), \
1095+
"Unsupported Feature Unit data source"); \
1096+
BUILD_ASSERT_FEATURE_UNIT_CONTROLS_LENGTH(node); \
9761097
)) \
9771098
IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \
9781099
BUILD_ASSERT(VALIDATE_LINKED_TERMINAL(node), \

0 commit comments

Comments
 (0)