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

usb: gadget: uvc: configfs: Add frame-based frame format support

Add support for frame-based frame format, which can be used to support
multiple formats like H264 or H265, in addition to MJPEG and YUV frames.

The frame-based format is set to H264 by default, but it can be updated
to other formats by modifying the GUID through the guid configfs
attribute. Different structures are used for all three formats, as
H264 has a different structure compared to MJPEG and uncompressed
formats. These structures will be passed to the frame make function
based on the active format, using a common frame structure with
additional parameters needed only for frame-based formats. These
parameters are handled at runtime in the UVC driver.

Signed-off-by: Akash Kumar <quic_akakum@quicinc.com>
Link: https://lore.kernel.org/r/20240927152138.31416-1-quic_akakum@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Akash Kumar and committed by
Greg Kroah-Hartman
7b5a5895 e1b2772e

+485 -12
+64
Documentation/ABI/testing/configfs-usb-gadget-uvc
··· 342 342 support 343 343 ========================= ===================================== 344 344 345 + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased 346 + Date: Sept 2024 347 + KernelVersion: 5.15 348 + Description: Framebased format descriptors 349 + 350 + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name 351 + Date: Sept 2024 352 + KernelVersion: 5.15 353 + Description: Specific framebased format descriptors 354 + 355 + ================== ======================================= 356 + bFormatIndex unique id for this format descriptor; 357 + only defined after parent header is 358 + linked into the streaming class; 359 + read-only 360 + bmaControls this format's data for bmaControls in 361 + the streaming header 362 + bmInterlaceFlags specifies interlace information, 363 + read-only 364 + bAspectRatioY the X dimension of the picture aspect 365 + ratio, read-only 366 + bAspectRatioX the Y dimension of the picture aspect 367 + ratio, read-only 368 + bDefaultFrameIndex optimum frame index for this stream 369 + bBitsPerPixel number of bits per pixel used to 370 + specify color in the decoded video 371 + frame 372 + guidFormat globally unique id used to identify 373 + stream-encoding format 374 + ================== ======================================= 375 + 376 + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name/name 377 + Date: Sept 2024 378 + KernelVersion: 5.15 379 + Description: Specific framebased frame descriptors 380 + 381 + ========================= ===================================== 382 + bFrameIndex unique id for this framedescriptor; 383 + only defined after parent format is 384 + linked into the streaming header; 385 + read-only 386 + dwFrameInterval indicates how frame interval can be 387 + programmed; a number of values 388 + separated by newline can be specified 389 + dwDefaultFrameInterval the frame interval the device would 390 + like to use as default 391 + dwBytesPerLine Specifies the number of bytes per line 392 + of video for packed fixed frame size 393 + formats, allowing the receiver to 394 + perform stride alignment of the video. 395 + If the bVariableSize value (above) is 396 + TRUE (1), or if the format does not 397 + permit such alignment, this value shall 398 + be set to zero (0). 399 + dwMaxBitRate the maximum bit rate at the shortest 400 + frame interval in bps 401 + dwMinBitRate the minimum bit rate at the longest 402 + frame interval in bps 403 + wHeight height of decoded bitmap frame in px 404 + wWidth width of decoded bitmam frame in px 405 + bmCapabilities still image support, fixed frame-rate 406 + support 407 + ========================= ===================================== 408 + 345 409 What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header 346 410 Date: Dec 2014 347 411 KernelVersion: 4.0
+337 -11
drivers/usb/gadget/function/uvc_configfs.c
··· 1566 1566 /* ----------------------------------------------------------------------------- 1567 1567 * streaming/uncompressed 1568 1568 * streaming/mjpeg 1569 + * streaming/framebased 1569 1570 */ 1570 1571 1571 1572 static const char * const uvcg_format_names[] = { 1572 1573 "uncompressed", 1573 1574 "mjpeg", 1575 + "framebased", 1574 1576 }; 1575 1577 1576 1578 static struct uvcg_color_matching * ··· 1779 1777 target_fmt = container_of(to_config_group(target), struct uvcg_format, 1780 1778 group); 1781 1779 1780 + if (!target_fmt) 1781 + goto out; 1782 + 1782 1783 uvcg_format_set_indices(to_config_group(target)); 1783 1784 1784 1785 format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); ··· 1821 1816 target_fmt = container_of(to_config_group(target), struct uvcg_format, 1822 1817 group); 1823 1818 1819 + if (!target_fmt) 1820 + goto out; 1821 + 1824 1822 list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry) 1825 1823 if (format_ptr->fmt == target_fmt) { 1826 1824 list_del(&format_ptr->entry); ··· 1834 1826 1835 1827 --target_fmt->linked; 1836 1828 1829 + out: 1837 1830 mutex_unlock(&opts->lock); 1838 1831 mutex_unlock(su_mutex); 1839 1832 } ··· 2031 2022 UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); 2032 2023 UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); 2033 2024 UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); 2025 + UVCG_FRAME_ATTR(dw_bytes_perline, dwBytesPerLine, 32); 2034 2026 2035 2027 #undef UVCG_FRAME_ATTR 2036 2028 ··· 2045 2035 int result, i; 2046 2036 char *pg = page; 2047 2037 2048 - mutex_lock(su_mutex); /* for navigating configfs hierarchy */ 2038 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ 2049 2039 2050 2040 opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent; 2051 2041 opts = to_f_uvc_opts(opts_item); ··· 2115 2105 2116 2106 UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); 2117 2107 2118 - static struct configfs_attribute *uvcg_frame_attrs[] = { 2108 + static struct configfs_attribute *uvcg_frame_attrs1[] = { 2119 2109 &uvcg_frame_attr_b_frame_index, 2120 2110 &uvcg_frame_attr_bm_capabilities, 2121 2111 &uvcg_frame_attr_w_width, ··· 2128 2118 NULL, 2129 2119 }; 2130 2120 2131 - static const struct config_item_type uvcg_frame_type = { 2121 + static struct configfs_attribute *uvcg_frame_attrs2[] = { 2122 + &uvcg_frame_attr_b_frame_index, 2123 + &uvcg_frame_attr_bm_capabilities, 2124 + &uvcg_frame_attr_w_width, 2125 + &uvcg_frame_attr_w_height, 2126 + &uvcg_frame_attr_dw_min_bit_rate, 2127 + &uvcg_frame_attr_dw_max_bit_rate, 2128 + &uvcg_frame_attr_dw_default_frame_interval, 2129 + &uvcg_frame_attr_dw_frame_interval, 2130 + &uvcg_frame_attr_dw_bytes_perline, 2131 + NULL, 2132 + }; 2133 + 2134 + static const struct config_item_type uvcg_frame_type1 = { 2132 2135 .ct_item_ops = &uvcg_config_item_ops, 2133 - .ct_attrs = uvcg_frame_attrs, 2136 + .ct_attrs = uvcg_frame_attrs1, 2134 2137 .ct_owner = THIS_MODULE, 2138 + }; 2139 + 2140 + static const struct config_item_type uvcg_frame_type2 = { 2141 + .ct_item_ops = &uvcg_config_item_ops, 2142 + .ct_attrs = uvcg_frame_attrs2, 2143 + .ct_owner = THIS_MODULE, 2135 2144 }; 2136 2145 2137 2146 static struct config_item *uvcg_frame_make(struct config_group *group, ··· 2174 2145 h->frame.dw_max_bit_rate = 55296000; 2175 2146 h->frame.dw_max_video_frame_buffer_size = 460800; 2176 2147 h->frame.dw_default_frame_interval = 666666; 2148 + h->frame.dw_bytes_perline = 0; 2177 2149 2178 2150 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; 2179 2151 opts = to_f_uvc_opts(opts_item); ··· 2187 2157 } else if (fmt->type == UVCG_MJPEG) { 2188 2158 h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG; 2189 2159 h->fmt_type = UVCG_MJPEG; 2160 + } else if (fmt->type == UVCG_FRAMEBASED) { 2161 + h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED; 2162 + h->fmt_type = UVCG_FRAMEBASED; 2190 2163 } else { 2191 2164 mutex_unlock(&opts->lock); 2192 2165 kfree(h); ··· 2208 2175 ++fmt->num_frames; 2209 2176 mutex_unlock(&opts->lock); 2210 2177 2211 - config_item_init_type_name(&h->item, name, &uvcg_frame_type); 2178 + if (fmt->type == UVCG_FRAMEBASED) 2179 + config_item_init_type_name(&h->item, name, &uvcg_frame_type2); 2180 + else 2181 + config_item_init_type_name(&h->item, name, &uvcg_frame_type1); 2212 2182 2213 2183 return &h->item; 2214 2184 } ··· 2250 2214 2251 2215 list_for_each_entry(ci, &fmt->cg_children, ci_entry) { 2252 2216 struct uvcg_frame *frm; 2253 - 2254 - if (ci->ci_type != &uvcg_frame_type) 2255 - continue; 2256 2217 2257 2218 frm = to_uvcg_frame(ci); 2258 2219 frm->frame.b_frame_index = i++; ··· 2711 2678 }; 2712 2679 2713 2680 /* ----------------------------------------------------------------------------- 2681 + * streaming/framebased/<NAME> 2682 + */ 2683 + 2684 + static struct configfs_group_operations uvcg_framebased_group_ops = { 2685 + .make_item = uvcg_frame_make, 2686 + .drop_item = uvcg_frame_drop, 2687 + }; 2688 + 2689 + #define UVCG_FRAMEBASED_ATTR_RO(cname, aname, bits) \ 2690 + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ 2691 + char *page) \ 2692 + { \ 2693 + struct uvcg_framebased *u = to_uvcg_framebased(item); \ 2694 + struct f_uvc_opts *opts; \ 2695 + struct config_item *opts_item; \ 2696 + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ 2697 + int result; \ 2698 + \ 2699 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ 2700 + \ 2701 + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ 2702 + opts = to_f_uvc_opts(opts_item); \ 2703 + \ 2704 + mutex_lock(&opts->lock); \ 2705 + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ 2706 + mutex_unlock(&opts->lock); \ 2707 + \ 2708 + mutex_unlock(su_mutex); \ 2709 + return result; \ 2710 + } \ 2711 + \ 2712 + UVC_ATTR_RO(uvcg_framebased_, cname, aname) 2713 + 2714 + #define UVCG_FRAMEBASED_ATTR(cname, aname, bits) \ 2715 + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ 2716 + char *page) \ 2717 + { \ 2718 + struct uvcg_framebased *u = to_uvcg_framebased(item); \ 2719 + struct f_uvc_opts *opts; \ 2720 + struct config_item *opts_item; \ 2721 + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ 2722 + int result; \ 2723 + \ 2724 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ 2725 + \ 2726 + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ 2727 + opts = to_f_uvc_opts(opts_item); \ 2728 + \ 2729 + mutex_lock(&opts->lock); \ 2730 + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ 2731 + mutex_unlock(&opts->lock); \ 2732 + \ 2733 + mutex_unlock(su_mutex); \ 2734 + return result; \ 2735 + } \ 2736 + \ 2737 + static ssize_t \ 2738 + uvcg_framebased_##cname##_store(struct config_item *item, \ 2739 + const char *page, size_t len) \ 2740 + { \ 2741 + struct uvcg_framebased *u = to_uvcg_framebased(item); \ 2742 + struct f_uvc_opts *opts; \ 2743 + struct config_item *opts_item; \ 2744 + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ 2745 + int ret; \ 2746 + u8 num; \ 2747 + \ 2748 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ 2749 + \ 2750 + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ 2751 + opts = to_f_uvc_opts(opts_item); \ 2752 + \ 2753 + mutex_lock(&opts->lock); \ 2754 + if (u->fmt.linked || opts->refcnt) { \ 2755 + ret = -EBUSY; \ 2756 + goto end; \ 2757 + } \ 2758 + \ 2759 + ret = kstrtou8(page, 0, &num); \ 2760 + if (ret) \ 2761 + goto end; \ 2762 + \ 2763 + if (num > 255) { \ 2764 + ret = -EINVAL; \ 2765 + goto end; \ 2766 + } \ 2767 + u->desc.aname = num; \ 2768 + ret = len; \ 2769 + end: \ 2770 + mutex_unlock(&opts->lock); \ 2771 + mutex_unlock(su_mutex); \ 2772 + return ret; \ 2773 + } \ 2774 + \ 2775 + UVC_ATTR(uvcg_framebased_, cname, aname) 2776 + 2777 + UVCG_FRAMEBASED_ATTR_RO(b_format_index, bFormatIndex, 8); 2778 + UVCG_FRAMEBASED_ATTR_RO(b_bits_per_pixel, bBitsPerPixel, 8); 2779 + UVCG_FRAMEBASED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); 2780 + UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); 2781 + UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); 2782 + UVCG_FRAMEBASED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); 2783 + 2784 + #undef UVCG_FRAMEBASED_ATTR 2785 + #undef UVCG_FRAMEBASED_ATTR_RO 2786 + 2787 + static ssize_t uvcg_framebased_guid_format_show(struct config_item *item, 2788 + char *page) 2789 + { 2790 + struct uvcg_framebased *ch = to_uvcg_framebased(item); 2791 + struct f_uvc_opts *opts; 2792 + struct config_item *opts_item; 2793 + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; 2794 + 2795 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ 2796 + 2797 + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; 2798 + opts = to_f_uvc_opts(opts_item); 2799 + 2800 + mutex_lock(&opts->lock); 2801 + memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat)); 2802 + mutex_unlock(&opts->lock); 2803 + 2804 + mutex_unlock(su_mutex); 2805 + 2806 + return sizeof(ch->desc.guidFormat); 2807 + } 2808 + 2809 + static ssize_t uvcg_framebased_guid_format_store(struct config_item *item, 2810 + const char *page, size_t len) 2811 + { 2812 + struct uvcg_framebased *ch = to_uvcg_framebased(item); 2813 + struct f_uvc_opts *opts; 2814 + struct config_item *opts_item; 2815 + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; 2816 + int ret; 2817 + 2818 + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ 2819 + 2820 + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; 2821 + opts = to_f_uvc_opts(opts_item); 2822 + 2823 + mutex_lock(&opts->lock); 2824 + if (ch->fmt.linked || opts->refcnt) { 2825 + ret = -EBUSY; 2826 + goto end; 2827 + } 2828 + 2829 + memcpy(ch->desc.guidFormat, page, 2830 + min(sizeof(ch->desc.guidFormat), len)); 2831 + ret = sizeof(ch->desc.guidFormat); 2832 + 2833 + end: 2834 + mutex_unlock(&opts->lock); 2835 + mutex_unlock(su_mutex); 2836 + return ret; 2837 + } 2838 + 2839 + UVC_ATTR(uvcg_framebased_, guid_format, guidFormat); 2840 + 2841 + static inline ssize_t 2842 + uvcg_framebased_bma_controls_show(struct config_item *item, char *page) 2843 + { 2844 + struct uvcg_framebased *u = to_uvcg_framebased(item); 2845 + 2846 + return uvcg_format_bma_controls_show(&u->fmt, page); 2847 + } 2848 + 2849 + static inline ssize_t 2850 + uvcg_framebased_bma_controls_store(struct config_item *item, 2851 + const char *page, size_t len) 2852 + { 2853 + struct uvcg_framebased *u = to_uvcg_framebased(item); 2854 + 2855 + return uvcg_format_bma_controls_store(&u->fmt, page, len); 2856 + } 2857 + 2858 + UVC_ATTR(uvcg_framebased_, bma_controls, bmaControls); 2859 + 2860 + static struct configfs_attribute *uvcg_framebased_attrs[] = { 2861 + &uvcg_framebased_attr_b_format_index, 2862 + &uvcg_framebased_attr_b_default_frame_index, 2863 + &uvcg_framebased_attr_b_bits_per_pixel, 2864 + &uvcg_framebased_attr_b_aspect_ratio_x, 2865 + &uvcg_framebased_attr_b_aspect_ratio_y, 2866 + &uvcg_framebased_attr_bm_interface_flags, 2867 + &uvcg_framebased_attr_bma_controls, 2868 + &uvcg_framebased_attr_guid_format, 2869 + NULL, 2870 + }; 2871 + 2872 + static const struct config_item_type uvcg_framebased_type = { 2873 + .ct_item_ops = &uvcg_config_item_ops, 2874 + .ct_group_ops = &uvcg_framebased_group_ops, 2875 + .ct_attrs = uvcg_framebased_attrs, 2876 + .ct_owner = THIS_MODULE, 2877 + }; 2878 + 2879 + static struct config_group *uvcg_framebased_make(struct config_group *group, 2880 + const char *name) 2881 + { 2882 + static char guid[] = { /*Declear frame based as H264 format*/ 2883 + 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 2884 + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 2885 + }; 2886 + struct uvcg_framebased *h; 2887 + 2888 + h = kzalloc(sizeof(*h), GFP_KERNEL); 2889 + if (!h) 2890 + return ERR_PTR(-ENOMEM); 2891 + 2892 + h->desc.bLength = UVC_DT_FORMAT_FRAMEBASED_SIZE; 2893 + h->desc.bDescriptorType = USB_DT_CS_INTERFACE; 2894 + h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED; 2895 + memcpy(h->desc.guidFormat, guid, sizeof(guid)); 2896 + h->desc.bBitsPerPixel = 0; 2897 + h->desc.bDefaultFrameIndex = 1; 2898 + h->desc.bAspectRatioX = 0; 2899 + h->desc.bAspectRatioY = 0; 2900 + h->desc.bmInterfaceFlags = 0; 2901 + h->desc.bCopyProtect = 0; 2902 + h->desc.bVariableSize = 1; 2903 + 2904 + INIT_LIST_HEAD(&h->fmt.frames); 2905 + h->fmt.type = UVCG_FRAMEBASED; 2906 + config_group_init_type_name(&h->fmt.group, name, 2907 + &uvcg_framebased_type); 2908 + 2909 + return &h->fmt.group; 2910 + } 2911 + 2912 + static struct configfs_group_operations uvcg_framebased_grp_ops = { 2913 + .make_group = uvcg_framebased_make, 2914 + }; 2915 + 2916 + static const struct uvcg_config_group_type uvcg_framebased_grp_type = { 2917 + .type = { 2918 + .ct_item_ops = &uvcg_config_item_ops, 2919 + .ct_group_ops = &uvcg_framebased_grp_ops, 2920 + .ct_owner = THIS_MODULE, 2921 + }, 2922 + .name = "framebased", 2923 + }; 2924 + 2925 + /* ----------------------------------------------------------------------------- 2714 2926 * streaming/color_matching/default 2715 2927 */ 2716 2928 ··· 3190 2912 if (ret) 3191 2913 return ret; 3192 2914 grp = &f->fmt->group; 2915 + j = 0; 3193 2916 list_for_each_entry(item, &grp->cg_children, ci_entry) { 3194 2917 frm = to_uvcg_frame(item); 3195 2918 ret = fun(frm, priv2, priv3, j++, UVCG_FRAME); ··· 3244 2965 container_of(fmt, struct uvcg_mjpeg, fmt); 3245 2966 3246 2967 *size += sizeof(m->desc); 2968 + } else if (fmt->type == UVCG_FRAMEBASED) { 2969 + struct uvcg_framebased *f = 2970 + container_of(fmt, struct uvcg_framebased, fmt); 2971 + 2972 + *size += sizeof(f->desc); 3247 2973 } else { 3248 2974 return -EINVAL; 3249 2975 } ··· 3259 2975 int sz = sizeof(frm->dw_frame_interval); 3260 2976 3261 2977 *size += sizeof(frm->frame); 2978 + /* 2979 + * framebased has duplicate member with uncompressed and 2980 + * mjpeg, so minus it 2981 + */ 2982 + *size -= sizeof(u32); 3262 2983 *size += frm->frame.b_frame_interval_type * sz; 3263 2984 } 3264 2985 break; ··· 3276 2987 } 3277 2988 3278 2989 ++*count; 2990 + 2991 + return 0; 2992 + } 2993 + 2994 + static int __uvcg_copy_framebased_desc(void *dest, struct uvcg_frame *frm, 2995 + int sz) 2996 + { 2997 + struct uvc_frame_framebased *desc = dest; 2998 + 2999 + desc->bLength = frm->frame.b_length; 3000 + desc->bDescriptorType = frm->frame.b_descriptor_type; 3001 + desc->bDescriptorSubType = frm->frame.b_descriptor_subtype; 3002 + desc->bFrameIndex = frm->frame.b_frame_index; 3003 + desc->bmCapabilities = frm->frame.bm_capabilities; 3004 + desc->wWidth = frm->frame.w_width; 3005 + desc->wHeight = frm->frame.w_height; 3006 + desc->dwMinBitRate = frm->frame.dw_min_bit_rate; 3007 + desc->dwMaxBitRate = frm->frame.dw_max_bit_rate; 3008 + desc->dwDefaultFrameInterval = frm->frame.dw_default_frame_interval; 3009 + desc->bFrameIntervalType = frm->frame.b_frame_interval_type; 3010 + desc->dwBytesPerLine = frm->frame.dw_bytes_perline; 3279 3011 3280 3012 return 0; 3281 3013 } ··· 3355 3045 m->desc.bNumFrameDescriptors = fmt->num_frames; 3356 3046 memcpy(*dest, &m->desc, sizeof(m->desc)); 3357 3047 *dest += sizeof(m->desc); 3048 + } else if (fmt->type == UVCG_FRAMEBASED) { 3049 + struct uvcg_framebased *f = 3050 + container_of(fmt, struct uvcg_framebased, 3051 + fmt); 3052 + 3053 + f->desc.bFormatIndex = n + 1; 3054 + f->desc.bNumFrameDescriptors = fmt->num_frames; 3055 + memcpy(*dest, &f->desc, sizeof(f->desc)); 3056 + *dest += sizeof(f->desc); 3358 3057 } else { 3359 3058 return -EINVAL; 3360 3059 } ··· 3373 3054 struct uvcg_frame *frm = priv1; 3374 3055 struct uvc_descriptor_header *h = *dest; 3375 3056 3376 - sz = sizeof(frm->frame); 3377 - memcpy(*dest, &frm->frame, sz); 3057 + sz = sizeof(frm->frame) - 4; 3058 + if (frm->fmt_type != UVCG_FRAMEBASED) 3059 + memcpy(*dest, &frm->frame, sz); 3060 + else 3061 + __uvcg_copy_framebased_desc(*dest, frm, sz); 3378 3062 *dest += sz; 3379 3063 sz = frm->frame.b_frame_interval_type * 3380 3064 sizeof(*frm->dw_frame_interval); ··· 3388 3066 frm->frame.b_frame_interval_type); 3389 3067 else if (frm->fmt_type == UVCG_MJPEG) 3390 3068 h->bLength = UVC_DT_FRAME_MJPEG_SIZE( 3391 - frm->frame.b_frame_interval_type); 3069 + frm->frame.b_frame_interval_type); 3070 + else if (frm->fmt_type == UVCG_FRAMEBASED) 3071 + h->bLength = UVC_DT_FRAME_FRAMEBASED_SIZE( 3072 + frm->frame.b_frame_interval_type); 3392 3073 } 3393 3074 break; 3394 3075 case UVCG_COLOR_MATCHING: { ··· 3610 3285 &uvcg_streaming_header_grp_type, 3611 3286 &uvcg_uncompressed_grp_type, 3612 3287 &uvcg_mjpeg_grp_type, 3288 + &uvcg_framebased_grp_type, 3613 3289 &uvcg_color_matching_grp_type, 3614 3290 &uvcg_streaming_class_grp_type, 3615 3291 NULL,
+16
drivers/usb/gadget/function/uvc_configfs.h
··· 49 49 enum uvcg_format_type { 50 50 UVCG_UNCOMPRESSED = 0, 51 51 UVCG_MJPEG, 52 + UVCG_FRAMEBASED, 52 53 }; 53 54 54 55 struct uvcg_format { ··· 106 105 u32 dw_max_video_frame_buffer_size; 107 106 u32 dw_default_frame_interval; 108 107 u8 b_frame_interval_type; 108 + u32 dw_bytes_perline; 109 109 } __attribute__((packed)) frame; 110 110 u32 *dw_frame_interval; 111 111 }; ··· 142 140 static inline struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item) 143 141 { 144 142 return container_of(to_uvcg_format(item), struct uvcg_mjpeg, fmt); 143 + } 144 + 145 + /* ----------------------------------------------------------------------------- 146 + * streaming/framebased/<NAME> 147 + */ 148 + 149 + struct uvcg_framebased { 150 + struct uvcg_format fmt; 151 + struct uvc_format_framebased desc; 152 + }; 153 + 154 + static inline struct uvcg_framebased *to_uvcg_framebased(struct config_item *item) 155 + { 156 + return container_of(to_uvcg_format(item), struct uvcg_framebased, fmt); 145 157 } 146 158 147 159 /* -----------------------------------------------------------------------------
+10 -1
drivers/usb/gadget/function/uvc_v4l2.c
··· 31 31 { 32 32 char guid[16] = UVC_GUID_FORMAT_MJPEG; 33 33 const struct uvc_format_desc *format; 34 - struct uvcg_uncompressed *unc; 35 34 36 35 if (uformat->type == UVCG_UNCOMPRESSED) { 36 + struct uvcg_uncompressed *unc; 37 + 37 38 unc = to_uvcg_uncompressed(&uformat->group.cg_item); 39 + if (!unc) 40 + return ERR_PTR(-EINVAL); 41 + 42 + memcpy(guid, unc->desc.guidFormat, sizeof(guid)); 43 + } else if (uformat->type == UVCG_FRAMEBASED) { 44 + struct uvcg_framebased *unc; 45 + 46 + unc = to_uvcg_framebased(&uformat->group.cg_item); 38 47 if (!unc) 39 48 return ERR_PTR(-EINVAL); 40 49
+58
include/uapi/linux/usb/video.h
··· 597 597 __le32 dwFrameInterval[n]; \ 598 598 } __attribute__ ((packed)) 599 599 600 + /* Frame Based Payload - 3.1.1. Frame Based Video Format Descriptor */ 601 + struct uvc_format_framebased { 602 + __u8 bLength; 603 + __u8 bDescriptorType; 604 + __u8 bDescriptorSubType; 605 + __u8 bFormatIndex; 606 + __u8 bNumFrameDescriptors; 607 + __u8 guidFormat[16]; 608 + __u8 bBitsPerPixel; 609 + __u8 bDefaultFrameIndex; 610 + __u8 bAspectRatioX; 611 + __u8 bAspectRatioY; 612 + __u8 bmInterfaceFlags; 613 + __u8 bCopyProtect; 614 + __u8 bVariableSize; 615 + } __attribute__((__packed__)); 616 + 617 + #define UVC_DT_FORMAT_FRAMEBASED_SIZE 28 618 + 619 + /* Frame Based Payload - 3.1.2. Frame Based Video Frame Descriptor */ 620 + struct uvc_frame_framebased { 621 + __u8 bLength; 622 + __u8 bDescriptorType; 623 + __u8 bDescriptorSubType; 624 + __u8 bFrameIndex; 625 + __u8 bmCapabilities; 626 + __u16 wWidth; 627 + __u16 wHeight; 628 + __u32 dwMinBitRate; 629 + __u32 dwMaxBitRate; 630 + __u32 dwDefaultFrameInterval; 631 + __u8 bFrameIntervalType; 632 + __u32 dwBytesPerLine; 633 + __u32 dwFrameInterval[]; 634 + } __attribute__((__packed__)); 635 + 636 + #define UVC_DT_FRAME_FRAMEBASED_SIZE(n) (26+4*(n)) 637 + 638 + #define UVC_FRAME_FRAMEBASED(n) \ 639 + uvc_frame_framebased_##n 640 + 641 + #define DECLARE_UVC_FRAME_FRAMEBASED(n) \ 642 + struct UVC_FRAME_FRAMEBASED(n) { \ 643 + __u8 bLength; \ 644 + __u8 bDescriptorType; \ 645 + __u8 bDescriptorSubType; \ 646 + __u8 bFrameIndex; \ 647 + __u8 bmCapabilities; \ 648 + __u16 wWidth; \ 649 + __u16 wHeight; \ 650 + __u32 dwMinBitRate; \ 651 + __u32 dwMaxBitRate; \ 652 + __u32 dwDefaultFrameInterval; \ 653 + __u8 bFrameIntervalType; \ 654 + __u32 dwBytesPerLine; \ 655 + __u32 dwFrameInterval[n]; \ 656 + } __attribute__ ((packed)) 657 + 600 658 #endif /* __LINUX_USB_VIDEO_H */ 601 659