usb: gadget: uvc: track frames in format entries
authorMichael Grzeschik <m.grzeschik@pengutronix.de>
Thu, 21 Apr 2022 21:14:25 +0000 (23:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 May 2022 20:10:36 +0000 (22:10 +0200)
Just like the header is tracking the formats in a linked list, in this
patch we track the frames in a linked list of the formats. It
simplifies the parsing of the configfs structure.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20220421211427.3400834-6-m.grzeschik@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/gadget/function/uvc_configfs.h

index e979a1b..e5a6b6e 100644 (file)
@@ -1262,6 +1262,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
        struct uvcg_format *fmt;
        struct f_uvc_opts *opts;
        struct config_item *opts_item;
+       struct uvcg_frame_ptr *frame_ptr;
 
        h = kzalloc(sizeof(*h), GFP_KERNEL);
        if (!h)
@@ -1292,6 +1293,16 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
                kfree(h);
                return ERR_PTR(-EINVAL);
        }
+
+       frame_ptr = kzalloc(sizeof(*frame_ptr), GFP_KERNEL);
+       if (!frame_ptr) {
+               mutex_unlock(&opts->lock);
+               kfree(h);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       frame_ptr->frm = h;
+       list_add_tail(&frame_ptr->entry, &fmt->frames);
        ++fmt->num_frames;
        mutex_unlock(&opts->lock);
 
@@ -1305,13 +1316,23 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item
        struct uvcg_format *fmt;
        struct f_uvc_opts *opts;
        struct config_item *opts_item;
+       struct uvcg_frame *target_frm = NULL;
+       struct uvcg_frame_ptr *frame_ptr, *tmp;
 
        opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
        opts = to_f_uvc_opts(opts_item);
 
        mutex_lock(&opts->lock);
+       target_frm = container_of(item, struct uvcg_frame, item);
        fmt = to_uvcg_format(&group->cg_item);
-       --fmt->num_frames;
+
+       list_for_each_entry_safe(frame_ptr, tmp, &fmt->frames, entry)
+               if (frame_ptr->frm == target_frm) {
+                       list_del(&frame_ptr->entry);
+                       kfree(frame_ptr);
+                       --fmt->num_frames;
+                       break;
+               }
        mutex_unlock(&opts->lock);
 
        config_item_put(item);
@@ -1556,6 +1577,7 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
        h->desc.bmInterfaceFlags        = 0;
        h->desc.bCopyProtect            = 0;
 
+       INIT_LIST_HEAD(&h->fmt.frames);
        h->fmt.type = UVCG_UNCOMPRESSED;
        config_group_init_type_name(&h->fmt.group, name,
                                    &uvcg_uncompressed_type);
@@ -1736,6 +1758,7 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
        h->desc.bmInterfaceFlags        = 0;
        h->desc.bCopyProtect            = 0;
 
+       INIT_LIST_HEAD(&h->fmt.frames);
        h->fmt.type = UVCG_MJPEG;
        config_group_init_type_name(&h->fmt.group, name,
                                    &uvcg_mjpeg_type);
index 1ec8529..ad2ec8c 100644 (file)
@@ -46,6 +46,7 @@ struct uvcg_format {
        struct config_group     group;
        enum uvcg_format_type   type;
        unsigned                linked;
+       struct list_head        frames;
        unsigned                num_frames;
        __u8                    bmaControls[UVCG_STREAMING_CONTROL_SIZE];
 };
@@ -73,6 +74,11 @@ static inline struct uvcg_streaming_header *to_uvcg_streaming_header(struct conf
        return container_of(item, struct uvcg_streaming_header, item);
 }
 
+struct uvcg_frame_ptr {
+       struct uvcg_frame       *frm;
+       struct list_head        entry;
+};
+
 struct uvcg_frame {
        struct config_item      item;
        enum uvcg_format_type   fmt_type;