]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
usb: gadget: f_midi: allow customizing the USB MIDI interface string through configfs
authorVictor Krawiec <victor.krawiec@arturia.com>
Tue, 9 Dec 2025 16:40:06 +0000 (17:40 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Dec 2025 13:43:01 +0000 (14:43 +0100)
When using f_midi from configfs the USB MIDI interface string is hardcoded
to 'MIDI function'.

This USB string descriptor is used by some third-party OS or software to
display the name of the MIDI device

Since we add an additional string option a new macro block was created to
factorize declarations

Signed-off-by: Victor Krawiec <victor.krawiec@arturia.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251209164006.143219-1-victor.krawiec@arturia.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/configfs-usb-gadget-midi
Documentation/usb/gadget-testing.rst
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/u_midi.h

index 07389cddd51a3d833bab0370529504d9c57763ff..d6bd67bb91fc09b5d0ded7b3b2dec451ea5cb3a4 100644 (file)
@@ -4,11 +4,12 @@ KernelVersion:        3.19
 Description:
                The attributes:
 
-               ==========      ====================================
-               index           index value for the USB MIDI adapter
-               id              ID string for the USB MIDI adapter
-               buflen          MIDI buffer length
-               qlen            USB read request queue length
-               in_ports        number of MIDI input ports
-               out_ports       number of MIDI output ports
-               ==========      ====================================
+               ================        ====================================
+               index                   index value for the USB MIDI adapter
+               id                      ID string for the USB MIDI adapter
+               buflen                  MIDI buffer length
+               qlen                    USB read request queue length
+               in_ports                number of MIDI input ports
+               out_ports               number of MIDI output ports
+               interface_string        USB AudioControl interface string
+               ================        ====================================
index 5f90af1fb5732180d0a9fe34846583eb04588837..01a128d664cb1114c4c3c3efd62b54216c2124b5 100644 (file)
@@ -368,14 +368,15 @@ Function-specific configfs interface
 The function name to use when creating the function directory is "midi".
 The MIDI function provides these attributes in its function directory:
 
-       =============== ====================================
-       buflen          MIDI buffer length
-       id              ID string for the USB MIDI adapter
-       in_ports        number of MIDI input ports
-       index           index value for the USB MIDI adapter
-       out_ports       number of MIDI output ports
-       qlen            USB read request queue length
-       =============== ====================================
+       ================ ====================================
+       buflen           MIDI buffer length
+       id               ID string for the USB MIDI adapter
+       in_ports         number of MIDI input ports
+       index            index value for the USB MIDI adapter
+       out_ports        number of MIDI output ports
+       qlen             USB read request queue length
+       interface_string USB AudioControl interface string
+       ================ ====================================
 
 Testing the MIDI function
 -------------------------
index da82598fcef8a814bee0052d8dc14375bc9e515b..ad679a6ecac188e058d22ab6057d89eb7c3c5a7c 100644 (file)
@@ -875,6 +875,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_composite_dev *cdev = c->cdev;
        struct f_midi *midi = func_to_midi(f);
        struct usb_string *us;
+       struct f_midi_opts *opts;
        int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0;
 
        midi->gadget = cdev->gadget;
@@ -883,6 +884,10 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
        if (status < 0)
                goto fail_register;
 
+       opts = container_of(f->fi, struct f_midi_opts, func_inst);
+       if (opts->interface_string)
+               midi_string_defs[STRING_FUNC_IDX].s = opts->interface_string;
+
        /* maybe allocate device-global string ID */
        us = usb_gstrings_attach(c->cdev, midi_strings,
                                 ARRAY_SIZE(midi_string_defs));
@@ -1178,59 +1183,60 @@ end:                                                                    \
                                                                        \
 CONFIGFS_ATTR(f_midi_opts_, name);
 
+#define F_MIDI_OPT_STRING(name)                                                \
+static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \
+{                                                                      \
+       struct f_midi_opts *opts = to_f_midi_opts(item);                \
+       ssize_t result;                                                 \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       if (opts->name) {                                               \
+               result = strscpy(page, opts->name, PAGE_SIZE);          \
+       } else {                                                        \
+               page[0] = 0;                                            \
+               result = 0;                                             \
+       }                                                               \
+                                                                       \
+       mutex_unlock(&opts->lock);                                      \
+                                                                       \
+       return result;                                                  \
+}                                                                      \
+                                                                       \
+static ssize_t f_midi_opts_##name##_store(struct config_item *item,    \
+                                        const char *page, size_t len)  \
+{                                                                      \
+       struct f_midi_opts *opts = to_f_midi_opts(item);                \
+       int ret;                                                        \
+       char *c;                                                        \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       if (opts->refcnt > 1) {                                         \
+               ret = -EBUSY;                                           \
+               goto end;                                               \
+       }                                                               \
+                                                                       \
+       c = kstrndup(page, len, GFP_KERNEL);                            \
+       if (!c) {                                                       \
+               ret = -ENOMEM;                                          \
+               goto end;                                               \
+       }                                                               \
+       kfree(opts->name);                                              \
+       opts->name = c;                                                 \
+       ret = len;                                                      \
+end:                                                                   \
+       mutex_unlock(&opts->lock);                                      \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+CONFIGFS_ATTR(f_midi_opts_, name)
+
 F_MIDI_OPT_SIGNED(index, true, SNDRV_CARDS);
 F_MIDI_OPT(buflen, false, 0);
 F_MIDI_OPT(qlen, false, 0);
 F_MIDI_OPT(in_ports, true, MAX_PORTS);
 F_MIDI_OPT(out_ports, true, MAX_PORTS);
-
-static ssize_t f_midi_opts_id_show(struct config_item *item, char *page)
-{
-       struct f_midi_opts *opts = to_f_midi_opts(item);
-       ssize_t result;
-
-       mutex_lock(&opts->lock);
-       if (opts->id) {
-               result = strscpy(page, opts->id, PAGE_SIZE);
-       } else {
-               page[0] = 0;
-               result = 0;
-       }
-
-       mutex_unlock(&opts->lock);
-
-       return result;
-}
-
-static ssize_t f_midi_opts_id_store(struct config_item *item,
-                                   const char *page, size_t len)
-{
-       struct f_midi_opts *opts = to_f_midi_opts(item);
-       int ret;
-       char *c;
-
-       mutex_lock(&opts->lock);
-       if (opts->refcnt > 1) {
-               ret = -EBUSY;
-               goto end;
-       }
-
-       c = kstrndup(page, len, GFP_KERNEL);
-       if (!c) {
-               ret = -ENOMEM;
-               goto end;
-       }
-       if (opts->id_allocated)
-               kfree(opts->id);
-       opts->id = c;
-       opts->id_allocated = true;
-       ret = len;
-end:
-       mutex_unlock(&opts->lock);
-       return ret;
-}
-
-CONFIGFS_ATTR(f_midi_opts_, id);
+F_MIDI_OPT_STRING(id);
+F_MIDI_OPT_STRING(interface_string);
 
 static struct configfs_attribute *midi_attrs[] = {
        &f_midi_opts_attr_index,
@@ -1239,6 +1245,7 @@ static struct configfs_attribute *midi_attrs[] = {
        &f_midi_opts_attr_in_ports,
        &f_midi_opts_attr_out_ports,
        &f_midi_opts_attr_id,
+       &f_midi_opts_attr_interface_string,
        NULL,
 };
 
@@ -1262,8 +1269,8 @@ static void f_midi_free_inst(struct usb_function_instance *f)
        mutex_unlock(&opts->lock);
 
        if (free) {
-               if (opts->id_allocated)
-                       kfree(opts->id);
+               kfree(opts->id);
+               kfree(opts->interface_string);
                kfree(opts);
        }
 }
@@ -1279,7 +1286,8 @@ static struct usb_function_instance *f_midi_alloc_inst(void)
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = f_midi_free_inst;
        opts->index = SNDRV_DEFAULT_IDX1;
-       opts->id = SNDRV_DEFAULT_STR1;
+       opts->id = NULL;
+       opts->interface_string = NULL;
        opts->buflen = 512;
        opts->qlen = 32;
        opts->in_ports = 1;
index 2e400b495cb85727f1b5dbdafa7d60bf7ac72084..41cb8aa73f09bd545df2759117620e1f6cd17b23 100644 (file)
@@ -19,7 +19,7 @@ struct f_midi_opts {
        struct usb_function_instance    func_inst;
        int                             index;
        char                            *id;
-       bool                            id_allocated;
+       char                            *interface_string;
        unsigned int                    in_ports;
        unsigned int                    out_ports;
        unsigned int                    buflen;