Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: usb-audio: Add support for Processing Units in UAC3

This patch adds support for the Processig Units defined in
the UAC3 spec. The main difference with the previous specs
is the lack of on/off switches in the controls for these
units and the addiction of the new Multi Function Processing
Unit.

The current version of the UAC3 spec doesn't define any
useful controls for the new Multi Function Processing Unit
so no control will get created once this unit is parsed.

Signed-off-by: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Jorge Sanjuan and committed by
Takashi Iwai
0f292f02 4e887af3

+104 -11
+15
include/linux/usb/audio-v3.h
··· 387 387 #define UAC3_CONNECTORS 0x0f 388 388 #define UAC3_POWER_DOMAIN 0x10 389 389 390 + /* A.20 PROCESSING UNIT PROCESS TYPES */ 391 + #define UAC3_PROCESS_UNDEFINED 0x00 392 + #define UAC3_PROCESS_UP_DOWNMIX 0x01 393 + #define UAC3_PROCESS_STEREO_EXTENDER 0x02 394 + #define UAC3_PROCESS_MULTI_FUNCTION 0x03 395 + 390 396 /* A.22 AUDIO CLASS-SPECIFIC REQUEST CODES */ 391 397 /* see audio-v2.h for the rest, which is identical to v2 */ 392 398 #define UAC3_CS_REQ_INTEN 0x04 ··· 411 405 #define UAC3_TE_UNDERFLOW 0x03 412 406 #define UAC3_TE_OVERFLOW 0x04 413 407 #define UAC3_TE_LATENCY 0x05 408 + 409 + /* A.23.10 PROCESSING UNITS CONTROL SELECTROS */ 410 + 411 + /* Up/Down Mixer */ 412 + #define UAC3_UD_MODE_SELECT 0x01 413 + 414 + /* Stereo Extender */ 415 + #define UAC3_EXT_WIDTH_CONTROL 0x01 416 + 414 417 415 418 /* BADD predefined Unit/Terminal values */ 416 419 #define UAC3_BADD_IT_ID1 1 /* Input Terminal ID1: bTerminalID = 1 */
+40 -9
include/uapi/linux/usb/audio.h
··· 390 390 static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc, 391 391 int protocol) 392 392 { 393 - return (protocol == UAC_VERSION_1) ? 394 - desc->baSourceID[desc->bNrInPins + 4] : 395 - 2; /* in UAC2, this value is constant */ 393 + switch (protocol) { 394 + case UAC_VERSION_1: 395 + return desc->baSourceID[desc->bNrInPins + 4]; 396 + case UAC_VERSION_2: 397 + return 2; /* in UAC2, this value is constant */ 398 + case UAC_VERSION_3: 399 + return 4; /* in UAC3, this value is constant */ 400 + default: 401 + return 1; 402 + } 396 403 } 397 404 398 405 static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc, 399 406 int protocol) 400 407 { 401 - return (protocol == UAC_VERSION_1) ? 402 - &desc->baSourceID[desc->bNrInPins + 5] : 403 - &desc->baSourceID[desc->bNrInPins + 6]; 408 + switch (protocol) { 409 + case UAC_VERSION_1: 410 + return &desc->baSourceID[desc->bNrInPins + 5]; 411 + case UAC_VERSION_2: 412 + return &desc->baSourceID[desc->bNrInPins + 6]; 413 + case UAC_VERSION_3: 414 + return &desc->baSourceID[desc->bNrInPins + 2]; 415 + default: 416 + return NULL; 417 + } 404 418 } 405 419 406 420 static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc, 407 421 int protocol) 408 422 { 409 423 __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); 410 - return *(uac_processing_unit_bmControls(desc, protocol) 411 - + control_size); 424 + 425 + switch (protocol) { 426 + case UAC_VERSION_1: 427 + case UAC_VERSION_2: 428 + default: 429 + return *(uac_processing_unit_bmControls(desc, protocol) 430 + + control_size); 431 + case UAC_VERSION_3: 432 + return 0; /* UAC3 does not have this field */ 433 + } 412 434 } 413 435 414 436 static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc, 415 437 int protocol) 416 438 { 417 439 __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); 418 - return uac_processing_unit_bmControls(desc, protocol) 440 + 441 + switch (protocol) { 442 + case UAC_VERSION_1: 443 + case UAC_VERSION_2: 444 + default: 445 + return uac_processing_unit_bmControls(desc, protocol) 419 446 + control_size + 1; 447 + case UAC_VERSION_3: 448 + return uac_processing_unit_bmControls(desc, protocol) 449 + + control_size; 450 + } 420 451 } 421 452 422 453 /* 4.5.2 Class-Specific AS Interface Descriptor */
+49 -2
sound/usb/mixer.c
··· 953 953 954 954 return 0; 955 955 } 956 + case UAC3_PROCESSING_UNIT: { 957 + struct uac_processing_unit_descriptor *d = p1; 958 + 959 + if (!d->bNrInPins) 960 + return -EINVAL; 961 + 962 + /* call recursively to retrieve the channel info */ 963 + err = check_input_term(state, d->baSourceID[0], term); 964 + if (err < 0) 965 + return err; 966 + 967 + term->type = d->bDescriptorSubtype << 16; /* virtual type */ 968 + term->id = id; 969 + term->name = 0; /* TODO: UAC3 Class-specific strings */ 970 + 971 + return 0; 972 + } 956 973 default: 957 974 return -ENODEV; 958 975 } ··· 2197 2180 struct procunit_value_info *values; 2198 2181 }; 2199 2182 2183 + static struct procunit_value_info undefined_proc_info[] = { 2184 + { 0x00, "Control Undefined", 0 }, 2185 + { 0 } 2186 + }; 2187 + 2200 2188 static struct procunit_value_info updown_proc_info[] = { 2201 2189 { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, 2202 2190 { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, ··· 2250 2228 { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, 2251 2229 { 0 }, 2252 2230 }; 2231 + 2232 + static struct procunit_value_info uac3_updown_proc_info[] = { 2233 + { UAC3_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, 2234 + { 0 } 2235 + }; 2236 + static struct procunit_value_info uac3_stereo_ext_proc_info[] = { 2237 + { UAC3_EXT_WIDTH_CONTROL, "Width Control", USB_MIXER_U8 }, 2238 + { 0 } 2239 + }; 2240 + 2241 + static struct procunit_info uac3_procunits[] = { 2242 + { UAC3_PROCESS_UP_DOWNMIX, "Up Down", uac3_updown_proc_info }, 2243 + { UAC3_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", uac3_stereo_ext_proc_info }, 2244 + { UAC3_PROCESS_MULTI_FUNCTION, "Multi-Function", undefined_proc_info }, 2245 + { 0 }, 2246 + }; 2247 + 2253 2248 /* 2254 2249 * predefined data for extension units 2255 2250 */ ··· 2427 2388 static int parse_audio_processing_unit(struct mixer_build *state, int unitid, 2428 2389 void *raw_desc) 2429 2390 { 2430 - return build_audio_procunit(state, unitid, raw_desc, 2431 - procunits, "Processing Unit"); 2391 + switch (state->mixer->protocol) { 2392 + case UAC_VERSION_1: 2393 + case UAC_VERSION_2: 2394 + default: 2395 + return build_audio_procunit(state, unitid, raw_desc, 2396 + procunits, "Processing Unit"); 2397 + case UAC_VERSION_3: 2398 + return build_audio_procunit(state, unitid, raw_desc, 2399 + uac3_procunits, "Processing Unit"); 2400 + } 2432 2401 } 2433 2402 2434 2403 static int parse_audio_extension_unit(struct mixer_build *state, int unitid,