summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function/uvc_configfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function/uvc_configfs.c')
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c189
1 files changed, 79 insertions, 110 deletions
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 77d64031aa9c..e5a6b6e36b3d 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -10,17 +10,14 @@
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
*/
-#include <linux/sort.h>
-
-#include "u_uvc.h"
#include "uvc_configfs.h"
+#include <linux/sort.h>
+
/* -----------------------------------------------------------------------------
* Global Utility Structures and Macros
*/
-#define UVCG_STREAMING_CONTROL_SIZE 1
-
#define UVC_ATTR(prefix, cname, aname) \
static struct configfs_attribute prefix##attr_##cname = { \
.ca_name = __stringify(aname), \
@@ -49,12 +46,6 @@ static int uvcg_config_compare_u32(const void *l, const void *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,
- func_inst.group);
-}
-
struct uvcg_config_group_type {
struct config_item_type type;
const char *name;
@@ -125,19 +116,6 @@ static void uvcg_config_remove_children(struct config_group *group)
* control/header
*/
-DECLARE_UVC_HEADER_DESCRIPTOR(1);
-
-struct uvcg_control_header {
- struct config_item item;
- struct UVC_HEADER_DESCRIPTOR(1) desc;
- unsigned linked;
-};
-
-static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
-{
- return container_of(item, struct uvcg_control_header, item);
-}
-
#define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit) \
static ssize_t uvcg_control_header_##cname##_show( \
struct config_item *item, char *page) \
@@ -769,24 +747,6 @@ static const char * const uvcg_format_names[] = {
"mjpeg",
};
-enum uvcg_format_type {
- UVCG_UNCOMPRESSED = 0,
- UVCG_MJPEG,
-};
-
-struct uvcg_format {
- struct config_group group;
- enum uvcg_format_type type;
- unsigned linked;
- unsigned num_frames;
- __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
-};
-
-static struct uvcg_format *to_uvcg_format(struct config_item *item)
-{
- return container_of(to_config_group(item), struct uvcg_format, group);
-}
-
static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
{
struct f_uvc_opts *opts;
@@ -845,29 +805,11 @@ end:
return ret;
}
-struct uvcg_format_ptr {
- struct uvcg_format *fmt;
- struct list_head entry;
-};
-
/* -----------------------------------------------------------------------------
* streaming/header/<NAME>
* streaming/header
*/
-struct uvcg_streaming_header {
- struct config_item item;
- struct uvc_input_header_descriptor desc;
- unsigned linked;
- struct list_head formats;
- unsigned num_fmt;
-};
-
-static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
-{
- return container_of(item, struct uvcg_streaming_header, item);
-}
-
static void uvcg_format_set_indices(struct config_group *fmt);
static int uvcg_streaming_header_allow_link(struct config_item *src,
@@ -1059,31 +1001,6 @@ static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = {
* streaming/<mode>/<format>/<NAME>
*/
-struct uvcg_frame {
- struct config_item item;
- enum uvcg_format_type fmt_type;
- 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_max_video_frame_buffer_size;
- u32 dw_default_frame_interval;
- u8 b_frame_interval_type;
- } __attribute__((packed)) frame;
- u32 *dw_frame_interval;
-};
-
-static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
-{
- return container_of(item, struct uvcg_frame, item);
-}
-
#define UVCG_FRAME_ATTR(cname, aname, bits) \
static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
{ \
@@ -1345,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)
@@ -1375,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);
@@ -1388,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);
@@ -1420,18 +1358,6 @@ static void uvcg_format_set_indices(struct config_group *fmt)
* streaming/uncompressed/<NAME>
*/
-struct uvcg_uncompressed {
- struct uvcg_format fmt;
- struct uvc_format_uncompressed desc;
-};
-
-static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
-{
- return container_of(
- container_of(to_config_group(item), struct uvcg_format, group),
- struct uvcg_uncompressed, fmt);
-}
-
static struct configfs_group_operations uvcg_uncompressed_group_ops = {
.make_item = uvcg_frame_make,
.drop_item = uvcg_frame_drop,
@@ -1565,6 +1491,12 @@ uvcg_uncompressed_##cname##_store(struct config_item *item, \
if (ret) \
goto end; \
\
+ /* index values in uvc are never 0 */ \
+ if (!num) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ \
u->desc.aname = num; \
ret = len; \
end: \
@@ -1645,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);
@@ -1669,18 +1602,6 @@ static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = {
* streaming/mjpeg/<NAME>
*/
-struct uvcg_mjpeg {
- struct uvcg_format fmt;
- struct uvc_format_mjpeg desc;
-};
-
-static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
-{
- return container_of(
- container_of(to_config_group(item), struct uvcg_format, group),
- struct uvcg_mjpeg, fmt);
-}
-
static struct configfs_group_operations uvcg_mjpeg_group_ops = {
.make_item = uvcg_frame_make,
.drop_item = uvcg_frame_drop,
@@ -1758,6 +1679,12 @@ uvcg_mjpeg_##cname##_store(struct config_item *item, \
if (ret) \
goto end; \
\
+ /* index values in uvc are never 0 */ \
+ if (!num) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ \
u->desc.aname = num; \
ret = len; \
end: \
@@ -1831,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);
@@ -2425,10 +2353,51 @@ UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
#undef UVCG_OPTS_ATTR
+#define UVCG_OPTS_STRING_ATTR(cname, aname) \
+static ssize_t f_uvc_opts_string_##cname##_show(struct config_item *item,\
+ char *page) \
+{ \
+ struct f_uvc_opts *opts = to_f_uvc_opts(item); \
+ int result; \
+ \
+ mutex_lock(&opts->lock); \
+ result = snprintf(page, sizeof(opts->aname), "%s", opts->aname);\
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
+ const char *page, size_t len) \
+{ \
+ struct f_uvc_opts *opts = to_f_uvc_opts(item); \
+ int ret = 0; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = snprintf(opts->aname, min(sizeof(opts->aname), len), \
+ "%s", page); \
+ \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+UVC_ATTR(f_uvc_opts_string_, cname, aname)
+
+UVCG_OPTS_STRING_ATTR(function_name, function_name);
+
+#undef UVCG_OPTS_STRING_ATTR
+
static struct configfs_attribute *uvc_attrs[] = {
&f_uvc_opts_attr_streaming_interval,
&f_uvc_opts_attr_streaming_maxpacket,
&f_uvc_opts_attr_streaming_maxburst,
+ &f_uvc_opts_string_attr_function_name,
NULL,
};