| From 8ac8e5b604be4c8691bbe259f0410fe5dd50df90 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 2 Sep 2018 19:46:03 -0400 |
| Subject: usb: gadget: uvc: configfs: Sort frame intervals upon writing |
| |
| From: Paul Elder <paul.elder@ideasonboard.com> |
| |
| [ Upstream commit 89969a842e72b1b653140a4bbddd927b242736d0 ] |
| |
| There is an issue where the host is unable to tell the gadget what frame |
| rate it wants if the dwFrameIntervals in the interface descriptors are |
| not in ascending order. This means that when instantiating a uvc gadget |
| via configfs the user must make sure the dwFrameIntervals are in |
| ascending order. |
| |
| Instead of silently failing the breaking of this rule, we sort the |
| dwFrameIntervals upon writing to configfs. |
| |
| Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> |
| Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/usb/gadget/function/uvc_configfs.c | 13 +++++++++++++ |
| 1 file changed, 13 insertions(+) |
| |
| diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c |
| index 9478a7cdb1433..2e4c0391b5836 100644 |
| --- a/drivers/usb/gadget/function/uvc_configfs.c |
| +++ b/drivers/usb/gadget/function/uvc_configfs.c |
| @@ -9,6 +9,9 @@ |
| * |
| * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
| */ |
| + |
| +#include <linux/sort.h> |
| + |
| #include "u_uvc.h" |
| #include "uvc_configfs.h" |
| |
| @@ -31,6 +34,14 @@ static struct configfs_attribute prefix##attr_##cname = { \ |
| .show = prefix##cname##_show, \ |
| } |
| |
| +static int uvcg_config_compare_u32(const void *l, const void *r) |
| +{ |
| + u32 li = *(const u32 *)l; |
| + u32 ri = *(const u32 *)r; |
| + |
| + return li < ri ? -1 : li == ri ? 0 : 1; |
| +} |
| + |
| static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item) |
| { |
| return container_of(to_config_group(item), struct f_uvc_opts, |
| @@ -1134,6 +1145,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, |
| kfree(ch->dw_frame_interval); |
| ch->dw_frame_interval = frm_intrv; |
| ch->frame.b_frame_interval_type = n; |
| + sort(ch->dw_frame_interval, n, sizeof(*ch->dw_frame_interval), |
| + uvcg_config_compare_u32, NULL); |
| ret = len; |
| |
| end: |
| -- |
| 2.20.1 |
| |