|
108 | 108 | #define EXT_FORMAT_TYPE_II 130
|
109 | 109 | #define EXT_FORMAT_TYPE_III 131
|
110 | 110 |
|
| 111 | +/* Convert 0 to empty and everything else to itself */ |
| 112 | +#define EMPTY_ON_ZERO(value) COND_CODE_0(value, (), (value)) |
| 113 | + |
111 | 114 | /* Automatically assign Entity IDs based on entities order in devicetree */
|
112 | 115 | #define ENTITY_ID(e) UTIL_INC(DT_NODE_CHILD_IDX(e))
|
113 | 116 |
|
|
168 | 171 | * control is present but read-only and 0b11 when control can be programmed by
|
169 | 172 | * host. Value 0b10 is not allowed by the specification.
|
170 | 173 | */
|
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) \ |
172 | 179 | 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) |
177 | 194 |
|
178 | 195 | #define CLOCK_SOURCE_CONTROLS(entity) \
|
179 | 196 | CONTROL_BITS(entity, frequency_control, 0) | \
|
|
194 | 211 | CONTROL_BITS(entity, underflow_control, 6) | \
|
195 | 212 | CONTROL_BITS(entity, overflow_control, 8)
|
196 | 213 |
|
| 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 | + |
197 | 231 | #define AUDIO_STREAMING_DATA_ENDPOINT_CONTROLS(node) \
|
198 | 232 | CONTROL_BITS(node, pitch_control, 0) | \
|
199 | 233 | CONTROL_BITS(node, data_overrun_control, 2) | \
|
|
233 | 267 |
|
234 | 268 | #define SPATIAL_LOCATIONS_U32(entity) \
|
235 | 269 | (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 | + )) |
238 | 274 | #define SPATIAL_LOCATIONS(entity) U32_LE(SPATIAL_LOCATIONS_U32(entity))
|
239 | 275 |
|
| 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) |
240 | 288 |
|
241 | 289 | /* 4.7.2.1 Clock Source Descriptor */
|
242 | 290 | #define CLOCK_SOURCE_DESCRIPTOR(entity) \
|
|
277 | 325 | U16_LE(OUTPUT_TERMINAL_CONTROLS(entity)), /* bmControls */ \
|
278 | 326 | 0x00, /* iTerminal */
|
279 | 327 |
|
| 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 | + |
280 | 338 | #define ENTITY_HEADER(entity) \
|
281 | 339 | IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_clock_source), ( \
|
282 | 340 | CLOCK_SOURCE_DESCRIPTOR(entity) \
|
|
286 | 344 | )) \
|
287 | 345 | IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_output_terminal), ( \
|
288 | 346 | OUTPUT_TERMINAL_DESCRIPTOR(entity) \
|
| 347 | + )) \ |
| 348 | + IF_ENABLED(DT_NODE_HAS_COMPAT(entity, zephyr_uac2_feature_unit), ( \ |
| 349 | + FEATURE_UNIT_DESCRIPTOR(entity) \ |
289 | 350 | ))
|
290 | 351 |
|
291 | 352 | #define ENTITY_HEADER_ARRAYS(entity) \
|
|
318 | 379 | (FORMAT_TYPE_I), (FORMAT_TYPE_IV))
|
319 | 380 | #define AUDIO_STREAMING_FORMATS(node) U32_LE(0x00000001)
|
320 | 381 |
|
| 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 | + |
321 | 399 | /* If AudioStreaming is linked to input terminal, obtain the channel cluster
|
322 | 400 | * configuration from the linked terminal. Otherwise (it has to be connected
|
323 | 401 | * to output terminal) obtain the channel cluster configuration from data source
|
|
329 | 407 | DT_PROP(node, linked_terminal) \
|
330 | 408 | )) \
|
331 | 409 | 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)) \ |
334 | 412 | ))
|
335 | 413 |
|
336 | 414 | #define AUDIO_STREAMING_NUM_SPATIAL_LOCATIONS(node) \
|
|
928 | 1006 | DT_NODE_HAS_COMPAT(DT_PROP(entity, assoc_terminal), \
|
929 | 1007 | zephyr_uac2_input_terminal))
|
930 | 1008 |
|
| 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 | + |
931 | 1045 | #define NEEDS_SUBSLOT_SIZE_AND_BIT_RESOLUTION(node) UTIL_OR( \
|
932 | 1046 | UTIL_OR(IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_I), \
|
933 | 1047 | IS_EQ(AUDIO_STREAMING_FORMAT_TYPE(node), FORMAT_TYPE_III)), \
|
|
973 | 1087 | IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_output_terminal), ( \
|
974 | 1088 | BUILD_ASSERT(VALIDATE_OUTPUT_TERMINAL_ASSOCIATION(node), \
|
975 | 1089 | "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); \ |
976 | 1097 | )) \
|
977 | 1098 | IF_ENABLED(DT_NODE_HAS_COMPAT(node, zephyr_uac2_audio_streaming), ( \
|
978 | 1099 | BUILD_ASSERT(VALIDATE_LINKED_TERMINAL(node), \
|
|
0 commit comments