firmware/br-ext-chip-goke/board/gk7205v200/kernel/patches/00_drivers-usb-gadget-funct...

843 lines
26 KiB
Diff

--- linux-4.9.37/drivers/usb/gadget/function/uvc_configfs.c 2017-07-12 16:42:41.000000000 +0300
+++ linux-4.9.y/drivers/usb/gadget/function/uvc_configfs.c 2021-06-07 13:01:34.000000000 +0300
@@ -254,7 +254,49 @@
return result;
}
-UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
+static ssize_t uvcg_default_processing_bm_controls_store(
+ struct config_item *item, const char *page, size_t len)
+{
+ struct uvcg_default_processing *dp = to_uvcg_default_processing(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
+ struct uvc_processing_unit_descriptor *pd;
+ int ret, i;
+ const char *pg = page;
+ /* sign, base 2 representation, newline, terminator */
+ char buf[1 + sizeof(u8) * 8 + 1 + 1];
+ int idx;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ pd = &opts->uvc_processing;
+
+ idx = 0;
+ while (pg - page < len) {
+ i = 0;
+ while (i < sizeof(buf) && (pg - page < len) &&
+ *pg != '\0' && *pg != '\n')
+ buf[i++] = *pg++;
+ while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
+ ++pg;
+ buf[i] = '\0';
+ ret = kstrtou8(buf, 0, &pd->bmControls[idx++]);
+ if (ret < 0)
+ goto end;
+ if (idx >= pd->bControlSize)
+ break;
+ }
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_processing_attrs[] = {
&uvcg_default_processing_attr_b_unit_id,
@@ -281,6 +323,110 @@
.ct_owner = THIS_MODULE,
};
+/* control/extension/default */
+static struct uvcg_default_extension {
+ struct config_group group;
+} uvcg_default_extension;
+
+static inline struct uvcg_default_extension
+*to_uvcg_default_extension(struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct uvcg_default_extension, group);
+}
+
+#define UVCG_DEFAULT_EXTENSION_ATTR(cname, aname, conv) \
+static ssize_t uvcg_default_extension_##cname##_show( \
+ struct config_item *item, char *page) \
+{ \
+ struct uvcg_default_extension *dp = to_uvcg_default_extension(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \
+ struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) *ed; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ ed = &opts->uvc_extension; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(ed->aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+UVC_ATTR_RO(uvcg_default_extension_, cname, aname)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_EXTENSION_ATTR(b_unit_id, bUnitID, identity_conv);
+UVCG_DEFAULT_EXTENSION_ATTR(b_num_input_pins, bNrInPins, identity_conv);
+UVCG_DEFAULT_EXTENSION_ATTR(i_extension, iExtension, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_EXTENSION_ATTR
+
+static ssize_t uvcg_default_extension_bm_controls_show(
+ struct config_item *item, char *page)
+{
+ struct uvcg_default_extension *dp = to_uvcg_default_extension(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
+ struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) *ed;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ ed = &opts->uvc_extension;
+
+ mutex_lock(&opts->lock);
+ for (result = 0, i = 0; i < ed->bControlSize; ++i) {
+ result += sprintf(pg, "%d\n", ed->bmControls[i]);
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+UVC_ATTR_RO(uvcg_default_extension_, bm_controls, bmControls);
+
+static struct configfs_attribute *uvcg_default_extension_attrs[] = {
+ &uvcg_default_extension_attr_b_unit_id,
+ &uvcg_default_extension_attr_b_num_input_pins,
+ &uvcg_default_extension_attr_bm_controls,
+ &uvcg_default_extension_attr_i_extension,
+ NULL,
+};
+
+static struct config_item_type uvcg_default_extension_type = {
+ .ct_attrs = uvcg_default_extension_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* struct uvcg_extension {}; */
+
+/* control/extension */
+static struct uvcg_extension_grp {
+ struct config_group group;
+} uvcg_extension_grp;
+
+static struct config_item_type uvcg_extension_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
/* control/terminal/camera/default */
static struct uvcg_default_camera {
struct config_group group;
@@ -368,7 +514,50 @@
return result;
}
-UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
+static ssize_t uvcg_default_camera_bm_controls_store(
+ struct config_item *item, const char *page, size_t len)
+{
+ struct uvcg_default_camera *dc = to_uvcg_default_camera(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
+ struct uvc_camera_terminal_descriptor *cd;
+ int ret, i;
+ const char *pg = page;
+ /* sign, base 2 representation, newline, terminator */
+ char buf[1 + sizeof(u8) * 8 + 1 + 1];
+ int idx;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->
+ ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ cd = &opts->uvc_camera_terminal;
+
+ idx = 0;
+ while (pg - page < len) {
+ i = 0;
+ while (i < sizeof(buf) && (pg - page < len) &&
+ *pg != '\0' && *pg != '\n')
+ buf[i++] = *pg++;
+ while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
+ ++pg;
+ buf[i] = '\0';
+ ret = kstrtou8(buf, 0, &cd->bmControls[idx++]);
+ if (ret < 0)
+ goto end;
+ if (idx >= cd->bControlSize)
+ break;
+ }
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_camera_attrs[] = {
&uvcg_default_camera_attr_b_terminal_id,
@@ -626,14 +815,21 @@
struct config_group group;
} uvcg_mjpeg_grp;
+/* streaming/frame_based */
+static struct uvcg_frame_based_format_grp {
+ struct config_group group;
+} uvcg_frame_based_format_grp;
+
static struct config_item *fmt_parent[] = {
&uvcg_uncompressed_grp.group.cg_item,
&uvcg_mjpeg_grp.group.cg_item,
+ &uvcg_frame_based_format_grp.group.cg_item,
};
enum uvcg_format_type {
UVCG_UNCOMPRESSED = 0,
UVCG_MJPEG,
+ UVCG_FRAME_FRAME_BASED,
};
struct uvcg_format {
@@ -1203,6 +1399,7 @@
return ERR_PTR(-EINVAL);
}
++fmt->num_frames;
+ h->frame.b_frame_index = fmt->num_frames;
mutex_unlock(&opts->lock);
config_item_init_type_name(&h->item, name, &uvcg_frame_type);
@@ -1227,6 +1424,263 @@
mutex_unlock(&opts->lock);
}
+struct uvcg_frame_based_frame {
+ struct {
+ u8 b_length;
+ u8 b_descriptor_type;
+ u8 b_descriptor_subtype;
+ u8 b_frame_index;
+ u8 bm_capabilities;
+ u16 w_width;
+ u16 w_height;
+ u32 dw_min_bit_rate;
+ u32 dw_max_bit_rate;
+ u32 dw_default_frame_interval;
+ u8 b_frame_interval_type;
+ u32 dw_bytes_per_line;
+ } __attribute__((packed)) frame;
+ u32 *dw_frame_interval;
+ enum uvcg_format_type fmt_type;
+ struct config_item item;
+};
+
+static struct uvcg_frame_based_frame *to_uvcg_frame_based_frame(struct config_item *item)
+{
+ return container_of(item, struct uvcg_frame_based_frame, item);
+}
+
+#define UVCG_FRAME_BASED_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
+static ssize_t uvcg_frame_based_frame_##cname##_show(struct config_item *item, char *page)\
+{ \
+ struct uvcg_frame_based_frame *f = to_uvcg_frame_based_frame(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t uvcg_frame_based_frame_##cname##_store(struct config_item *item, \
+ const char *page, size_t len)\
+{ \
+ struct uvcg_frame_based_frame *f = to_uvcg_frame_based_frame(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct uvcg_format *fmt; \
+ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+ int ret; \
+ u##bits num; \
+ \
+ ret = kstrtou##bits(page, 0, &num); \
+ if (ret) \
+ return ret; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ fmt = to_uvcg_format(f->item.ci_parent); \
+ \
+ mutex_lock(&opts->lock); \
+ if (fmt->linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ f->frame.cname = to_little_endian(num); \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+UVC_ATTR(uvcg_frame_based_frame_, cname, aname);
+
+#define noop_conversion(x) (x)
+
+UVCG_FRAME_BASED_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
+ noop_conversion, 8);
+UVCG_FRAME_BASED_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_BASED_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_BASED_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_BASED_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_BASED_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
+ le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_BASED_FRAME_ATTR(dw_bytes_per_line, dwBytesPerLine,
+ le32_to_cpu, cpu_to_le32, 32);
+
+#undef noop_conversion
+
+#undef UVCG_FRAME_BASED_FRAME_ATTR
+
+static ssize_t uvcg_frame_based_frame_dw_frame_interval_show(struct config_item *item,
+ char *page)
+{
+ struct uvcg_frame_based_frame *frm = to_uvcg_frame_based_frame(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
+ result += sprintf(pg, "%d\n",
+ le32_to_cpu(frm->dw_frame_interval[i]));
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+ return result;
+}
+
+static ssize_t uvcg_frame_based_frame_dw_frame_interval_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct uvcg_frame_based_frame *ch = to_uvcg_frame_based_frame(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct uvcg_format *fmt;
+ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;
+ int ret = 0, n = 0;
+ u32 *frm_intrv, *tmp;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->item.ci_parent->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ fmt = to_uvcg_format(ch->item.ci_parent);
+
+ mutex_lock(&opts->lock);
+ if (fmt->linked || opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
+ if (ret)
+ goto end;
+
+ tmp = frm_intrv = kcalloc(n, sizeof(u32), GFP_KERNEL);
+ if (!frm_intrv) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
+ if (ret) {
+ kfree(frm_intrv);
+ goto end;
+ }
+
+ kfree(ch->dw_frame_interval);
+ ch->dw_frame_interval = frm_intrv;
+ ch->frame.b_frame_interval_type = n;
+ ret = len;
+
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVC_ATTR(uvcg_frame_based_frame_, dw_frame_interval, dwFrameInterval);
+
+static struct configfs_attribute *uvcg_frame_based_frame_attrs[] = {
+ &uvcg_frame_based_frame_attr_bm_capabilities,
+ &uvcg_frame_based_frame_attr_w_width,
+ &uvcg_frame_based_frame_attr_w_height,
+ &uvcg_frame_based_frame_attr_dw_min_bit_rate,
+ &uvcg_frame_based_frame_attr_dw_max_bit_rate,
+ &uvcg_frame_based_frame_attr_dw_default_frame_interval,
+ &uvcg_frame_based_frame_attr_dw_frame_interval,
+ &uvcg_frame_based_frame_attr_dw_bytes_per_line,
+ NULL,
+};
+
+static struct config_item_type uvcg_frame_based_frame_type = {
+ .ct_attrs = uvcg_frame_based_frame_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *uvcg_frame_based_frame_make(struct config_group *group,
+ const char *name)
+{
+ struct uvcg_frame_based_frame *h;
+ struct uvcg_format *fmt;
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
+ h->frame.b_frame_index = 1;
+ h->frame.w_width = cpu_to_le16(640);
+ h->frame.w_height = cpu_to_le16(360);
+ h->frame.dw_min_bit_rate = cpu_to_le32(18432000);
+ h->frame.dw_max_bit_rate = cpu_to_le32(55296000);
+ h->frame.dw_default_frame_interval = cpu_to_le32(333333);
+ h->frame.dw_bytes_per_line = cpu_to_le32(0);
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ fmt = to_uvcg_format(&group->cg_item);
+ if (fmt->type == UVCG_FRAME_FRAME_BASED) {
+ h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED;
+ h->fmt_type = UVCG_FRAME_FRAME_BASED;
+ } else {
+ mutex_unlock(&opts->lock);
+ kfree(h);
+ return ERR_PTR(-EINVAL);
+ }
+ ++fmt->num_frames;
+ h->frame.b_frame_index = fmt->num_frames;
+ mutex_unlock(&opts->lock);
+
+ config_item_init_type_name(&h->item, name, &uvcg_frame_based_frame_type);
+
+ return &h->item;
+}
+
+static void uvcg_frame_based_frame_drop(struct config_group *group, struct config_item *item)
+{
+ struct uvcg_frame_based_frame *h = to_uvcg_frame_based_frame(item);
+ struct uvcg_format *fmt;
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ fmt = to_uvcg_format(&group->cg_item);
+ --fmt->num_frames;
+ kfree(h);
+ mutex_unlock(&opts->lock);
+}
+
/* streaming/uncompressed/<NAME> */
struct uvcg_uncompressed {
struct uvcg_format fmt;
@@ -1438,10 +1892,17 @@
static struct config_group *uvcg_uncompressed_make(struct config_group *group,
const char *name)
{
+#ifndef CONFIG_GOKE_MC
static char guid[] = {
'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
};
+#else
+ static char guid[] = {
+ 'N', 'V', '2', '1', 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+ };
+#endif
struct uvcg_uncompressed *h;
h = kzalloc(sizeof(*h), GFP_KERNEL);
@@ -1452,7 +1913,11 @@
h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
h->desc.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED;
memcpy(h->desc.guidFormat, guid, sizeof(guid));
+#ifndef CONFIG_GOKE_MC
h->desc.bBitsPerPixel = 16;
+#else
+ h->desc.bBitsPerPixel = 12;
+#endif
h->desc.bDefaultFrameIndex = 1;
h->desc.bAspectRatioX = 0;
h->desc.bAspectRatioY = 0;
@@ -1678,6 +2143,205 @@
.ct_owner = THIS_MODULE,
};
+/* streaming/frame_based<NAME> */
+struct uvcg_frame_based_format {
+ struct uvcg_format fmt;
+ struct uvc_frame_based_format_desc desc;
+};
+
+static struct uvcg_frame_based_format *to_uvcg_frame_based_format(struct config_item *item)
+{
+ return container_of(
+ container_of(to_config_group(item), struct uvcg_format, group),
+ struct uvcg_frame_based_format, fmt);
+}
+
+static struct configfs_group_operations uvcg_frame_based_format_group_ops = {
+ .make_item = uvcg_frame_based_frame_make,
+ .drop_item = uvcg_frame_based_frame_drop,
+};
+
+#define UVCG_FRAME_BASED_FORMAT_ATTR_RO(cname, aname, conv) \
+static ssize_t uvcg_frame_based_format_##cname##_show(struct config_item *item, char *page)\
+{ \
+ struct uvcg_frame_based_format *u = to_uvcg_frame_based_format(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+UVC_ATTR_RO(uvcg_frame_based_format_, cname, aname)
+
+#define UVCG_FRAME_BASED_FORMAT_ATTR(cname, aname, conv) \
+static ssize_t uvcg_frame_based_format_##cname##_show(struct config_item *item, char *page)\
+{ \
+ struct uvcg_frame_based_format *u = to_uvcg_frame_based_format(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t \
+uvcg_frame_based_format_##cname##_store(struct config_item *item, \
+ const char *page, size_t len) \
+{ \
+ struct uvcg_frame_based_format *u = to_uvcg_frame_based_format(item); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int ret; \
+ u8 num; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ if (u->fmt.linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou8(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > 255) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ u->desc.aname = num; \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+UVC_ATTR(uvcg_frame_based_format_, cname, aname)
+
+#define identity_conv(x) (x)
+
+UVCG_FRAME_BASED_FORMAT_ATTR(b_default_frame_index, bDefaultFrameIndex,
+ identity_conv);
+UVCG_FRAME_BASED_FORMAT_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
+UVCG_FRAME_BASED_FORMAT_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
+UVCG_FRAME_BASED_FORMAT_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_FRAME_BASED_FORMAT_ATTR
+#undef UVCG_FRAME_BASED_FORMAT_ATTR_RO
+
+static inline ssize_t
+uvcg_frame_based_format_bma_controls_show(struct config_item *item, char *page)
+{
+ struct uvcg_frame_based_format *u = to_uvcg_frame_based_format(item);
+ return uvcg_format_bma_controls_show(&u->fmt, page);
+}
+
+static inline ssize_t
+uvcg_frame_based_format_bma_controls_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct uvcg_frame_based_format *u = to_uvcg_frame_based_format(item);
+ return uvcg_format_bma_controls_store(&u->fmt, page, len);
+}
+
+UVC_ATTR(uvcg_frame_based_format_, bma_controls, bmaControls);
+
+static struct configfs_attribute *uvcg_frame_based_format_attrs[] = {
+ &uvcg_frame_based_format_attr_b_default_frame_index,
+ &uvcg_frame_based_format_attr_b_aspect_ratio_x,
+ &uvcg_frame_based_format_attr_b_aspect_ratio_y,
+ &uvcg_frame_based_format_attr_bm_interface_flags,
+ &uvcg_frame_based_format_attr_bma_controls,
+ NULL,
+};
+
+static struct config_item_type uvcg_frame_based_format_type = {
+ .ct_group_ops = &uvcg_frame_based_format_group_ops,
+ .ct_attrs = uvcg_frame_based_format_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_frame_based_format_make(struct config_group *group,
+ const char *name)
+{
+ static char guid[] = { /*Declear frame frame based as H264*/
+ 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+ };
+ struct uvcg_frame_based_format *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->desc.bLength = UVC_DT_FRAME_BASED_FORMAT_SIZE;
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED;
+ memcpy(h->desc.guidFormat, guid, sizeof(guid));
+ h->desc.bBitsPerPixel = 16;
+ h->desc.bDefaultFrameIndex = 1;
+ h->desc.bAspectRatioX = 0;
+ h->desc.bAspectRatioY = 0;
+ h->desc.bmInterfaceFlags = 0;
+ h->desc.bCopyProtect = 0;
+ h->desc.bVariableSize = 1;
+
+ h->fmt.type = UVCG_FRAME_FRAME_BASED;
+ config_group_init_type_name(&h->fmt.group, name,
+ &uvcg_frame_based_format_type);
+
+ return &h->fmt.group;
+}
+
+static void uvcg_frame_based_format_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct uvcg_frame_based_format *h = to_uvcg_frame_based_format(item);
+
+ kfree(h);
+}
+
+static struct configfs_group_operations uvcg_frame_based_format_grp_ops = {
+ .make_group = uvcg_frame_based_format_make,
+ .drop_item = uvcg_frame_based_format_drop,
+};
+
+static struct config_item_type uvcg_frame_based_format_grp_type = {
+ .ct_group_ops = &uvcg_frame_based_format_grp_ops,
+ .ct_owner = THIS_MODULE,
+};
+
/* streaming/color_matching/default */
static struct uvcg_default_color_matching {
struct config_group group;
@@ -1873,6 +2537,11 @@
container_of(fmt, struct uvcg_mjpeg, fmt);
*size += sizeof(m->desc);
+ } else if (fmt->type == UVCG_FRAME_FRAME_BASED) {
+ struct uvcg_frame_based_format *h =
+ container_of(fmt, struct uvcg_frame_based_format, fmt);
+
+ *size += sizeof(h->desc);
} else {
return -EINVAL;
}
@@ -1881,7 +2550,14 @@
case UVCG_FRAME: {
struct uvcg_frame *frm = priv1;
int sz = sizeof(frm->dw_frame_interval);
+ if (frm->frame.b_descriptor_subtype == UVC_VS_FRAME_FRAME_BASED) {
+ struct uvcg_frame_based_frame *fb_frm = priv1;
+ *size += sizeof(fb_frm->frame);
+ *size += fb_frm->frame.b_frame_interval_type * sizeof(fb_frm->dw_frame_interval);
+ ++*count;
+ return 0;
+ }
*size += sizeof(frm->frame);
*size += frm->frame.b_frame_interval_type * sz;
}
@@ -1949,6 +2625,15 @@
*dest += sizeof(m->desc);
mjp->bNumFrameDescriptors = fmt->num_frames;
mjp->bFormatIndex = n + 1;
+ } else if (fmt->type == UVCG_FRAME_FRAME_BASED) {
+ struct uvc_frame_based_format_desc *ffb = *dest;
+ struct uvcg_frame_based_format *h =
+ container_of(fmt, struct uvcg_frame_based_format, fmt);
+
+ memcpy(*dest, &h->desc, sizeof(h->desc));
+ *dest += sizeof(h->desc);
+ ffb->bNumFrameDescriptors = fmt->num_frames;
+ ffb->bFormatIndex = n + 1;
} else {
return -EINVAL;
}
@@ -1958,6 +2643,19 @@
struct uvcg_frame *frm = priv1;
struct uvc_descriptor_header *h = *dest;
+ if (frm->frame.b_descriptor_subtype == UVC_VS_FRAME_FRAME_BASED) {
+ struct uvcg_frame_based_frame *fb_frm = priv1;
+ sz = sizeof(fb_frm->frame);
+ memcpy(*dest, &fb_frm->frame, sz);
+ *dest += sz;
+ sz = fb_frm->frame.b_frame_interval_type *
+ sizeof(*fb_frm->dw_frame_interval);
+ memcpy(*dest, fb_frm->dw_frame_interval, sz);
+ *dest += sz;
+ h->bLength = UVC_DT_FRAME_BASED_FRAME_SIZE(
+ fb_frm->frame.b_frame_interval_type);
+ return 0;
+ }
sz = sizeof(frm->frame);
memcpy(*dest, &frm->frame, sz);
*dest += sz;
@@ -2224,6 +2922,13 @@
configfs_add_default_group(&uvcg_default_processing.group,
&uvcg_processing_grp.group);
+ config_group_init_type_name(&uvcg_default_extension.group,
+ "default", &uvcg_default_extension_type);
+ config_group_init_type_name(&uvcg_extension_grp.group,
+ "extension", &uvcg_extension_grp_type);
+ configfs_add_default_group(&uvcg_default_extension.group,
+ &uvcg_extension_grp.group);
+
config_group_init_type_name(&uvcg_default_camera.group,
"default", &uvcg_default_camera_type);
config_group_init_type_name(&uvcg_camera_grp.group,
@@ -2278,6 +2983,9 @@
config_group_init_type_name(&uvcg_mjpeg_grp.group,
"mjpeg",
&uvcg_mjpeg_grp_type);
+ config_group_init_type_name(&uvcg_frame_based_format_grp.group,
+ "framebased",
+ &uvcg_frame_based_format_grp_type);
config_group_init_type_name(&uvcg_default_color_matching.group,
"default",
&uvcg_default_color_matching_type);
@@ -2310,6 +3018,8 @@
&uvcg_streaming_grp.group);
configfs_add_default_group(&uvcg_mjpeg_grp.group,
&uvcg_streaming_grp.group);
+ configfs_add_default_group(&uvcg_frame_based_format_grp.group,
+ &uvcg_streaming_grp.group);
configfs_add_default_group(&uvcg_color_matching_grp.group,
&uvcg_streaming_grp.group);
configfs_add_default_group(&uvcg_streaming_class_grp.group,