usb: gadget: f_uac2: allow changing terminal types through configfs
authorJames Gruber <jimmyjgruber@gmail.com>
Thu, 14 Sep 2023 22:27:46 +0000 (15:27 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Oct 2023 07:35:43 +0000 (09:35 +0200)
Add "c_terminal_type" and "p_terminal_type" configfs entries
in order to allow the user to change the capture and playback terminal
type codes.

These fields affect the type of audio device that Windows detects, so
being able to modify this is useful when it would be advantageous for
a gadget to be detected as something other than a generic
speaker/microphone.

The fields default to microphone for the capture type field and speaker
for the playback type field as was the case before.

Signed-off-by: James Gruber <jimmyjgruber@gmail.com>
Link: https://lore.kernel.org/r/20230914222746.155126-1-jimmyjgruber@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/configfs-usb-gadget-uac2
Documentation/usb/gadget-testing.rst
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/u_uac2.h

index 3371c39f651db5c698f40da037bb35a9eca75978..a2bf4fd82a5b7c3ec512256a39ae72dc8995f844 100644 (file)
@@ -35,4 +35,6 @@ Description:
                req_number              the number of pre-allocated requests
                                        for both capture and playback
                function_name           name of the interface
+               c_terminal_type         code of the capture terminal type
+               p_terminal_type         code of the playback terminal type
                =====================   =======================================
index 394cd226bfaeb489aa0f42414f9fbcb5210272ef..29072c166d236a25e175df3f1677b607a4449013 100644 (file)
@@ -755,6 +755,8 @@ The uac2 function provides these attributes in its function directory:
        req_number       the number of pre-allocated request for both capture
                         and playback
        function_name    name of the interface
+       c_terminal_type  code of the capture terminal type
+       p_terminal_type  code of the playback terminal type
        ================ ====================================================
 
 The attributes have sane default values.
index 0219cd79493a73714b95f5c1156f5ff9c6216f77..f9a0f07a7476be709adf2736f1ff72ca8a1e2257 100644 (file)
@@ -212,7 +212,7 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
 
        .bDescriptorSubtype = UAC_INPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
+       /* .wTerminalType = DYNAMIC */
        .bAssocTerminal = 0,
        /* .bCSourceID = DYNAMIC */
        .iChannelNames = 0,
@@ -240,7 +240,7 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
 
        .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
+       /* .wTerminalType = DYNAMIC */
        .bAssocTerminal = 0,
        /* .bSourceID = DYNAMIC */
        /* .bCSourceID = DYNAMIC */
@@ -977,6 +977,9 @@ static void setup_descriptor(struct f_uac2_opts *opts)
                iad_desc.bInterfaceCount++;
        }
 
+       io_in_it_desc.wTerminalType = cpu_to_le16(opts->c_terminal_type);
+       io_out_ot_desc.wTerminalType = cpu_to_le16(opts->p_terminal_type);
+
        setup_headers(opts, fs_audio_desc, USB_SPEED_FULL);
        setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH);
        setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER);
@@ -2095,6 +2098,9 @@ UAC2_ATTRIBUTE(s16, c_volume_res);
 UAC2_ATTRIBUTE(u32, fb_max);
 UAC2_ATTRIBUTE_STRING(function_name);
 
+UAC2_ATTRIBUTE(s16, p_terminal_type);
+UAC2_ATTRIBUTE(s16, c_terminal_type);
+
 static struct configfs_attribute *f_uac2_attrs[] = {
        &f_uac2_opts_attr_p_chmask,
        &f_uac2_opts_attr_p_srate,
@@ -2122,6 +2128,9 @@ static struct configfs_attribute *f_uac2_attrs[] = {
 
        &f_uac2_opts_attr_function_name,
 
+       &f_uac2_opts_attr_p_terminal_type,
+       &f_uac2_opts_attr_c_terminal_type,
+
        NULL,
 };
 
@@ -2180,6 +2189,9 @@ static struct usb_function_instance *afunc_alloc_inst(void)
 
        snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
 
+       opts->p_terminal_type = UAC2_DEF_P_TERM_TYPE;
+       opts->c_terminal_type = UAC2_DEF_C_TERM_TYPE;
+
        return &opts->func_inst;
 }
 
index 0510c9bad58dbd8851eca814eca76a071b27e775..5e81bdd6c5fbab1075704cb4cb0cdfe4d58c86b2 100644 (file)
 #define UAC2_DEF_REQ_NUM 2
 #define UAC2_DEF_INT_REQ_NUM   10
 
+#define UAC2_DEF_P_TERM_TYPE 0x301
+       /* UAC_OUTPUT_TERMINAL_SPEAKER */
+#define UAC2_DEF_C_TERM_TYPE 0x201
+       /* UAC_INPUT_TERMINAL_MICROPHONE*/
+
 struct f_uac2_opts {
        struct usb_function_instance    func_inst;
        int                             p_chmask;
@@ -65,6 +70,9 @@ struct f_uac2_opts {
 
        char                    function_name[32];
 
+       s16                             p_terminal_type;
+       s16                             c_terminal_type;
+
        struct mutex                    lock;
        int                             refcnt;
 };