Commit 755801cb authored by Felipe Balbi's avatar Felipe Balbi

Merge tag 'uvcg-20180925' of git://linuxtv.org/pinchartl/media into testing/next

UVC gadget updates for v4.20

- configfs cleanups, fixes and extensions
- Endianness fixes
- Miscellaneous cleanups
parents 17b57b18 3fb2fd76
...@@ -12,6 +12,10 @@ Date: Dec 2014 ...@@ -12,6 +12,10 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Control descriptors Description: Control descriptors
All attributes read only:
bInterfaceNumber - USB interface number for this
streaming interface
What: /config/usb-gadget/gadget/functions/uvc.name/control/class What: /config/usb-gadget/gadget/functions/uvc.name/control/class
Date: Dec 2014 Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
...@@ -109,6 +113,10 @@ Date: Dec 2014 ...@@ -109,6 +113,10 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Streaming descriptors Description: Streaming descriptors
All attributes read only:
bInterfaceNumber - USB interface number for this
streaming interface
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
Date: Dec 2014 Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
...@@ -160,6 +168,10 @@ Description: Specific MJPEG format descriptors ...@@ -160,6 +168,10 @@ Description: Specific MJPEG format descriptors
All attributes read only, All attributes read only,
except bmaControls and bDefaultFrameIndex: except bmaControls and bDefaultFrameIndex:
bFormatIndex - unique id for this format descriptor;
only defined after parent header is
linked into the streaming class;
read-only
bmaControls - this format's data for bmaControls in bmaControls - this format's data for bmaControls in
the streaming header the streaming header
bmInterfaceFlags - specifies interlace information, bmInterfaceFlags - specifies interlace information,
...@@ -177,6 +189,10 @@ Date: Dec 2014 ...@@ -177,6 +189,10 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Specific MJPEG frame descriptors Description: Specific MJPEG frame descriptors
bFrameIndex - unique id for this framedescriptor;
only defined after parent format is
linked into the streaming header;
read-only
dwFrameInterval - indicates how frame interval can be dwFrameInterval - indicates how frame interval can be
programmed; a number of values programmed; a number of values
separated by newline can be specified separated by newline can be specified
...@@ -204,6 +220,10 @@ Date: Dec 2014 ...@@ -204,6 +220,10 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Specific uncompressed format descriptors Description: Specific uncompressed format descriptors
bFormatIndex - unique id for this format descriptor;
only defined after parent header is
linked into the streaming class;
read-only
bmaControls - this format's data for bmaControls in bmaControls - this format's data for bmaControls in
the streaming header the streaming header
bmInterfaceFlags - specifies interlace information, bmInterfaceFlags - specifies interlace information,
...@@ -224,6 +244,10 @@ Date: Dec 2014 ...@@ -224,6 +244,10 @@ Date: Dec 2014
KernelVersion: 4.0 KernelVersion: 4.0
Description: Specific uncompressed frame descriptors Description: Specific uncompressed frame descriptors
bFrameIndex - unique id for this framedescriptor;
only defined after parent format is
linked into the streaming header;
read-only
dwFrameInterval - indicates how frame interval can be dwFrameInterval - indicates how frame interval can be
programmed; a number of values programmed; a number of values
separated by newline can be specified separated by newline can be specified
......
...@@ -197,12 +197,6 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = { ...@@ -197,12 +197,6 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
NULL, NULL,
}; };
void uvc_set_trace_param(unsigned int trace)
{
uvc_gadget_trace_param = trace;
}
EXPORT_SYMBOL(uvc_set_trace_param);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* Control requests * Control requests
*/ */
...@@ -232,13 +226,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) ...@@ -232,13 +226,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct v4l2_event v4l2_event; struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
/* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n",
* ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue),
* le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength));
*/
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
INFO(f->config->cdev, "invalid request type\n"); uvcg_info(f, "invalid request type\n");
return -EINVAL; return -EINVAL;
} }
...@@ -272,7 +261,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface) ...@@ -272,7 +261,7 @@ uvc_function_get_alt(struct usb_function *f, unsigned interface)
{ {
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); uvcg_info(f, "%s(%u)\n", __func__, interface);
if (interface == uvc->control_intf) if (interface == uvc->control_intf)
return 0; return 0;
...@@ -291,13 +280,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) ...@@ -291,13 +280,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
int ret; int ret;
INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt);
if (interface == uvc->control_intf) { if (interface == uvc->control_intf) {
if (alt) if (alt)
return -EINVAL; return -EINVAL;
INFO(cdev, "reset UVC Control\n"); uvcg_info(f, "reset UVC Control\n");
usb_ep_disable(uvc->control_ep); usb_ep_disable(uvc->control_ep);
if (!uvc->control_ep->desc) if (!uvc->control_ep->desc)
...@@ -348,7 +337,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) ...@@ -348,7 +337,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (!uvc->video.ep) if (!uvc->video.ep)
return -EINVAL; return -EINVAL;
INFO(cdev, "reset UVC\n"); uvcg_info(f, "reset UVC\n");
usb_ep_disable(uvc->video.ep); usb_ep_disable(uvc->video.ep);
ret = config_ep_by_speed(f->config->cdev->gadget, ret = config_ep_by_speed(f->config->cdev->gadget,
...@@ -373,7 +362,7 @@ uvc_function_disable(struct usb_function *f) ...@@ -373,7 +362,7 @@ uvc_function_disable(struct usb_function *f)
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
struct v4l2_event v4l2_event; struct v4l2_event v4l2_event;
INFO(f->config->cdev, "uvc_function_disable\n"); uvcg_info(f, "%s()\n", __func__);
memset(&v4l2_event, 0, sizeof(v4l2_event)); memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_DISCONNECT; v4l2_event.type = UVC_EVENT_DISCONNECT;
...@@ -392,21 +381,19 @@ uvc_function_disable(struct usb_function *f) ...@@ -392,21 +381,19 @@ uvc_function_disable(struct usb_function *f)
void void
uvc_function_connect(struct uvc_device *uvc) uvc_function_connect(struct uvc_device *uvc)
{ {
struct usb_composite_dev *cdev = uvc->func.config->cdev;
int ret; int ret;
if ((ret = usb_function_activate(&uvc->func)) < 0) if ((ret = usb_function_activate(&uvc->func)) < 0)
INFO(cdev, "UVC connect failed with %d\n", ret); uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret);
} }
void void
uvc_function_disconnect(struct uvc_device *uvc) uvc_function_disconnect(struct uvc_device *uvc)
{ {
struct usb_composite_dev *cdev = uvc->func.config->cdev;
int ret; int ret;
if ((ret = usb_function_deactivate(&uvc->func)) < 0) if ((ret = usb_function_deactivate(&uvc->func)) < 0)
INFO(cdev, "UVC disconnect failed with %d\n", ret); uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
...@@ -605,7 +592,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -605,7 +592,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
struct f_uvc_opts *opts; struct f_uvc_opts *opts;
int ret = -EINVAL; int ret = -EINVAL;
INFO(cdev, "uvc_function_bind\n"); uvcg_info(f, "%s()\n", __func__);
opts = fi_to_f_uvc_opts(f->fi); opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters. /* Sanity check the streaming endpoint module parameters.
...@@ -618,8 +605,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -618,8 +605,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
if (opts->streaming_maxburst && if (opts->streaming_maxburst &&
(opts->streaming_maxpacket % 1024) != 0) { (opts->streaming_maxpacket % 1024) != 0) {
opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
INFO(cdev, "overriding streaming_maxpacket to %d\n", uvcg_info(f, "overriding streaming_maxpacket to %d\n",
opts->streaming_maxpacket); opts->streaming_maxpacket);
} }
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the /* Fill in the FS/HS/SS Video Streaming specific descriptors from the
...@@ -658,7 +645,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -658,7 +645,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
/* Allocate endpoints. */ /* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) { if (!ep) {
INFO(cdev, "Unable to allocate control EP\n"); uvcg_info(f, "Unable to allocate control EP\n");
goto error; goto error;
} }
uvc->control_ep = ep; uvc->control_ep = ep;
...@@ -672,7 +659,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -672,7 +659,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
if (!ep) { if (!ep) {
INFO(cdev, "Unable to allocate streaming EP\n"); uvcg_info(f, "Unable to allocate streaming EP\n");
goto error; goto error;
} }
uvc->video.ep = ep; uvc->video.ep = ep;
...@@ -699,12 +686,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -699,12 +686,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_iad.bFirstInterface = ret; uvc_iad.bFirstInterface = ret;
uvc_control_intf.bInterfaceNumber = ret; uvc_control_intf.bInterfaceNumber = ret;
uvc->control_intf = ret; uvc->control_intf = ret;
opts->control_interface = ret;
if ((ret = usb_interface_id(c, f)) < 0) if ((ret = usb_interface_id(c, f)) < 0)
goto error; goto error;
uvc_streaming_intf_alt0.bInterfaceNumber = ret; uvc_streaming_intf_alt0.bInterfaceNumber = ret;
uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret; uvc->streaming_intf = ret;
opts->streaming_interface = ret;
/* Copy descriptors */ /* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
...@@ -743,19 +732,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -743,19 +732,19 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->control_req->context = uvc; uvc->control_req->context = uvc;
if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
printk(KERN_INFO "v4l2_device_register failed\n"); uvcg_err(f, "failed to register V4L2 device\n");
goto error; goto error;
} }
/* Initialise video. */ /* Initialise video. */
ret = uvcg_video_init(&uvc->video); ret = uvcg_video_init(&uvc->video, uvc);
if (ret < 0) if (ret < 0)
goto error; goto error;
/* Register a V4L2 device. */ /* Register a V4L2 device. */
ret = uvc_register_video(uvc); ret = uvc_register_video(uvc);
if (ret < 0) { if (ret < 0) {
printk(KERN_INFO "Unable to register video device\n"); uvcg_err(f, "failed to register video device\n");
goto error; goto error;
} }
...@@ -792,6 +781,7 @@ static struct usb_function_instance *uvc_alloc_inst(void) ...@@ -792,6 +781,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
struct uvc_output_terminal_descriptor *od; struct uvc_output_terminal_descriptor *od;
struct uvc_color_matching_descriptor *md; struct uvc_color_matching_descriptor *md;
struct uvc_descriptor_header **ctl_cls; struct uvc_descriptor_header **ctl_cls;
int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL); opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts) if (!opts)
...@@ -868,7 +858,12 @@ static struct usb_function_instance *uvc_alloc_inst(void) ...@@ -868,7 +858,12 @@ static struct usb_function_instance *uvc_alloc_inst(void)
opts->streaming_interval = 1; opts->streaming_interval = 1;
opts->streaming_maxpacket = 1024; opts->streaming_maxpacket = 1024;
uvcg_attach_configfs(opts); ret = uvcg_attach_configfs(opts);
if (ret < 0) {
kfree(opts);
return ERR_PTR(ret);
}
return &opts->func_inst; return &opts->func_inst;
} }
...@@ -886,7 +881,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) ...@@ -886,7 +881,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
INFO(cdev, "%s\n", __func__); uvcg_info(f, "%s\n", __func__);
device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
video_unregister_device(&uvc->vdev); video_unregister_device(&uvc->vdev);
......
...@@ -25,6 +25,9 @@ struct f_uvc_opts { ...@@ -25,6 +25,9 @@ struct f_uvc_opts {
unsigned int streaming_maxpacket; unsigned int streaming_maxpacket;
unsigned int streaming_maxburst; unsigned int streaming_maxburst;
unsigned int control_interface;
unsigned int streaming_interface;
/* /*
* Control descriptors array pointers for full-/high-speed and * Control descriptors array pointers for full-/high-speed and
* super-speed. They point by default to the uvc_fs_control_cls and * super-speed. They point by default to the uvc_fs_control_cls and
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
struct usb_ep; struct usb_ep;
struct usb_request; struct usb_request;
struct uvc_descriptor_header; struct uvc_descriptor_header;
struct uvc_device;
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Debugging, printing and logging * Debugging, printing and logging
...@@ -51,14 +52,12 @@ extern unsigned int uvc_gadget_trace_param; ...@@ -51,14 +52,12 @@ extern unsigned int uvc_gadget_trace_param;
printk(KERN_DEBUG "uvcvideo: " msg); \ printk(KERN_DEBUG "uvcvideo: " msg); \
} while (0) } while (0)
#define uvc_warn_once(dev, warn, msg...) \ #define uvcg_dbg(f, fmt, args...) \
do { \ dev_dbg(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
if (!test_and_set_bit(warn, &dev->warnings)) \ #define uvcg_info(f, fmt, args...) \
printk(KERN_INFO "uvcvideo: " msg); \ dev_info(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
} while (0) #define uvcg_err(f, fmt, args...) \
dev_err(&(f)->config->cdev->gadget->dev, "%s: " fmt, (f)->name, ##args)
#define uvc_printk(level, msg...) \
printk(level "uvcvideo: " msg)
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Driver specific constants * Driver specific constants
...@@ -73,6 +72,7 @@ extern unsigned int uvc_gadget_trace_param; ...@@ -73,6 +72,7 @@ extern unsigned int uvc_gadget_trace_param;
*/ */
struct uvc_video { struct uvc_video {
struct uvc_device *uvc;
struct usb_ep *ep; struct usb_ep *ep;
/* Frame parameters */ /* Frame parameters */
......
...@@ -9,9 +9,16 @@ ...@@ -9,9 +9,16 @@
* *
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*/ */
#include <linux/sort.h>
#include "u_uvc.h" #include "u_uvc.h"
#include "uvc_configfs.h" #include "uvc_configfs.h"
/* -----------------------------------------------------------------------------
* Global Utility Structures and Macros
*/
#define UVCG_STREAMING_CONTROL_SIZE 1 #define UVCG_STREAMING_CONTROL_SIZE 1
#define UVC_ATTR(prefix, cname, aname) \ #define UVC_ATTR(prefix, cname, aname) \
...@@ -31,13 +38,93 @@ static struct configfs_attribute prefix##attr_##cname = { \ ...@@ -31,13 +38,93 @@ static struct configfs_attribute prefix##attr_##cname = { \
.show = prefix##cname##_show, \ .show = prefix##cname##_show, \
} }
#define le8_to_cpu(x) (x)
#define cpu_to_le8(x) (x)
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) 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, return container_of(to_config_group(item), struct f_uvc_opts,
func_inst.group); func_inst.group);
} }
/* control/header/<NAME> */ struct uvcg_config_group_type {
struct config_item_type type;
const char *name;
const struct uvcg_config_group_type **children;
int (*create_children)(struct config_group *group);
};
static void uvcg_config_item_release(struct config_item *item)
{
struct config_group *group = to_config_group(item);
kfree(group);
}
static struct configfs_item_operations uvcg_config_item_ops = {
.release = uvcg_config_item_release,
};
static int uvcg_config_create_group(struct config_group *parent,
const struct uvcg_config_group_type *type);
static int uvcg_config_create_children(struct config_group *group,
const struct uvcg_config_group_type *type)
{
const struct uvcg_config_group_type **child;
int ret;
if (type->create_children)
return type->create_children(group);
for (child = type->children; child && *child; ++child) {
ret = uvcg_config_create_group(group, *child);
if (ret < 0)
return ret;
}
return 0;
}
static int uvcg_config_create_group(struct config_group *parent,
const struct uvcg_config_group_type *type)
{
struct config_group *group;
group = kzalloc(sizeof(*group), GFP_KERNEL);
if (!group)
return -ENOMEM;
config_group_init_type_name(group, type->name, &type->type);
configfs_add_default_group(group, parent);
return uvcg_config_create_children(group, type);
}
static void uvcg_config_remove_children(struct config_group *group)
{
struct config_group *child, *n;
list_for_each_entry_safe(child, n, &group->default_groups, group_entry) {
list_del(&child->group_entry);
uvcg_config_remove_children(child);
config_item_put(&child->cg_item);
}
}
/* -----------------------------------------------------------------------------
* control/header/<NAME>
* control/header
*/
DECLARE_UVC_HEADER_DESCRIPTOR(1); DECLARE_UVC_HEADER_DESCRIPTOR(1);
struct uvcg_control_header { struct uvcg_control_header {
...@@ -51,9 +138,9 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it ...@@ -51,9 +138,9 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it
return container_of(item, struct uvcg_control_header, item); return container_of(item, struct uvcg_control_header, item);
} }
#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ #define UVCG_CTRL_HDR_ATTR(cname, aname, bits, limit) \
static ssize_t uvcg_control_header_##cname##_show( \ static ssize_t uvcg_control_header_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_control_header *ch = to_uvcg_control_header(item); \ struct uvcg_control_header *ch = to_uvcg_control_header(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
...@@ -67,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \ ...@@ -67,7 +154,7 @@ static ssize_t uvcg_control_header_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(ch->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(ch->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -83,7 +170,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ ...@@ -83,7 +170,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
int ret; \ int ret; \
uxx num; \ u##bits num; \
\ \
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\ \
...@@ -96,7 +183,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ ...@@ -96,7 +183,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
goto end; \ goto end; \
} \ } \
\ \
ret = str2u(page, 0, &num); \ ret = kstrtou##bits(page, 0, &num); \
if (ret) \ if (ret) \
goto end; \ goto end; \
\ \
...@@ -104,7 +191,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \ ...@@ -104,7 +191,7 @@ uvcg_control_header_##cname##_store(struct config_item *item, \
ret = -EINVAL; \ ret = -EINVAL; \
goto end; \ goto end; \
} \ } \
ch->desc.aname = vnoc(num); \ ch->desc.aname = cpu_to_le##bits(num); \
ret = len; \ ret = len; \
end: \ end: \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
...@@ -114,11 +201,9 @@ end: \ ...@@ -114,11 +201,9 @@ end: \
\ \
UVC_ATTR(uvcg_control_header_, cname, aname) UVC_ATTR(uvcg_control_header_, cname, aname)
UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16, UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, 16, 0xffff);
0xffff);
UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32, UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, 32, 0x7fffffff);
u32, cpu_to_le32, 0x7fffffff);
#undef UVCG_CTRL_HDR_ATTR #undef UVCG_CTRL_HDR_ATTR
...@@ -129,6 +214,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = { ...@@ -129,6 +214,7 @@ static struct configfs_attribute *uvcg_control_header_attrs[] = {
}; };
static const struct config_item_type uvcg_control_header_type = { static const struct config_item_type uvcg_control_header_type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_control_header_attrs, .ct_attrs = uvcg_control_header_attrs,
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
...@@ -153,60 +239,42 @@ static struct config_item *uvcg_control_header_make(struct config_group *group, ...@@ -153,60 +239,42 @@ static struct config_item *uvcg_control_header_make(struct config_group *group,
return &h->item; return &h->item;
} }
static void uvcg_control_header_drop(struct config_group *group,
struct config_item *item)
{
struct uvcg_control_header *h = to_uvcg_control_header(item);
kfree(h);
}
/* control/header */
static struct uvcg_control_header_grp {
struct config_group group;
} uvcg_control_header_grp;
static struct configfs_group_operations uvcg_control_header_grp_ops = { static struct configfs_group_operations uvcg_control_header_grp_ops = {
.make_item = uvcg_control_header_make, .make_item = uvcg_control_header_make,
.drop_item = uvcg_control_header_drop,
}; };
static const struct config_item_type uvcg_control_header_grp_type = { static const struct uvcg_config_group_type uvcg_control_header_grp_type = {
.ct_group_ops = &uvcg_control_header_grp_ops, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_control_header_grp_ops,
.ct_owner = THIS_MODULE,
},
.name = "header",
}; };
/* control/processing/default */ /* -----------------------------------------------------------------------------
static struct uvcg_default_processing { * control/processing/default
struct config_group group; */
} uvcg_default_processing;
static inline struct uvcg_default_processing
*to_uvcg_default_processing(struct config_item *item)
{
return container_of(to_config_group(item),
struct uvcg_default_processing, group);
}
#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \ #define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_processing_##cname##_show( \ static ssize_t uvcg_default_processing_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_processing_unit_descriptor *pd; \ struct uvc_processing_unit_descriptor *pd; \
int result; \ int result; \
\ \
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\ \
opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
pd = &opts->uvc_processing; \ pd = &opts->uvc_processing; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(pd->aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(pd->aname)); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -215,37 +283,33 @@ static ssize_t uvcg_default_processing_##cname##_show( \ ...@@ -215,37 +283,33 @@ static ssize_t uvcg_default_processing_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_default_processing_, cname, aname) UVC_ATTR_RO(uvcg_default_processing_, cname, aname)
#define identity_conv(x) (x) UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, 8);
UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, 8);
UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv); UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, 16);
UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv); UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8);
UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
#undef identity_conv
#undef UVCG_DEFAULT_PROCESSING_ATTR #undef UVCG_DEFAULT_PROCESSING_ATTR
static ssize_t uvcg_default_processing_bm_controls_show( static ssize_t uvcg_default_processing_bm_controls_show(
struct config_item *item, char *page) struct config_item *item, char *page)
{ {
struct uvcg_default_processing *dp = to_uvcg_default_processing(item); struct config_group *group = to_config_group(item);
struct f_uvc_opts *opts; struct f_uvc_opts *opts;
struct config_item *opts_item; struct config_item *opts_item;
struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct uvc_processing_unit_descriptor *pd; struct uvc_processing_unit_descriptor *pd;
int result, i; int result, i;
char *pg = page; char *pg = page;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item); opts = to_f_uvc_opts(opts_item);
pd = &opts->uvc_processing; pd = &opts->uvc_processing;
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
for (result = 0, i = 0; i < pd->bControlSize; ++i) { for (result = 0, i = 0; i < pd->bControlSize; ++i) {
result += sprintf(pg, "%d\n", pd->bmControls[i]); result += sprintf(pg, "%u\n", pd->bmControls[i]);
pg = page + result; pg = page + result;
} }
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
...@@ -266,54 +330,55 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = { ...@@ -266,54 +330,55 @@ static struct configfs_attribute *uvcg_default_processing_attrs[] = {
NULL, NULL,
}; };
static const struct config_item_type uvcg_default_processing_type = { static const struct uvcg_config_group_type uvcg_default_processing_type = {
.ct_attrs = uvcg_default_processing_attrs, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_default_processing_attrs,
.ct_owner = THIS_MODULE,
},
.name = "default",
}; };
/* struct uvcg_processing {}; */ /* -----------------------------------------------------------------------------
* control/processing
/* control/processing */ */
static struct uvcg_processing_grp {
struct config_group group;
} uvcg_processing_grp;
static const struct config_item_type uvcg_processing_grp_type = { static const struct uvcg_config_group_type uvcg_processing_grp_type = {
.ct_owner = THIS_MODULE, .type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "processing",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_default_processing_type,
NULL,
},
}; };
/* control/terminal/camera/default */ /* -----------------------------------------------------------------------------
static struct uvcg_default_camera { * control/terminal/camera/default
struct config_group group; */
} uvcg_default_camera;
static inline struct uvcg_default_camera
*to_uvcg_default_camera(struct config_item *item)
{
return container_of(to_config_group(item),
struct uvcg_default_camera, group);
}
#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \ #define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_camera_##cname##_show( \ static ssize_t uvcg_default_camera_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_camera_terminal_descriptor *cd; \ struct uvc_camera_terminal_descriptor *cd; \
int result; \ int result; \
\ \
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\ \
opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \
ci_parent; \ ci_parent; \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_camera_terminal; \ cd = &opts->uvc_camera_terminal; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(cd->aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -323,44 +388,40 @@ static ssize_t uvcg_default_camera_##cname##_show( \ ...@@ -323,44 +388,40 @@ static ssize_t uvcg_default_camera_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_default_camera_, cname, aname) UVC_ATTR_RO(uvcg_default_camera_, cname, aname)
#define identity_conv(x) (x) UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, 8);
UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, 16);
UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv); UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, 8);
UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, 8);
UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin, UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
le16_to_cpu); 16);
UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax, UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
le16_to_cpu); 16);
UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
le16_to_cpu); 16);
#undef identity_conv
#undef UVCG_DEFAULT_CAMERA_ATTR #undef UVCG_DEFAULT_CAMERA_ATTR
static ssize_t uvcg_default_camera_bm_controls_show( static ssize_t uvcg_default_camera_bm_controls_show(
struct config_item *item, char *page) struct config_item *item, char *page)
{ {
struct uvcg_default_camera *dc = to_uvcg_default_camera(item); struct config_group *group = to_config_group(item);
struct f_uvc_opts *opts; struct f_uvc_opts *opts;
struct config_item *opts_item; struct config_item *opts_item;
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct uvc_camera_terminal_descriptor *cd; struct uvc_camera_terminal_descriptor *cd;
int result, i; int result, i;
char *pg = page; char *pg = page;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> opts_item = group->cg_item.ci_parent->ci_parent->ci_parent->
ci_parent; ci_parent;
opts = to_f_uvc_opts(opts_item); opts = to_f_uvc_opts(opts_item);
cd = &opts->uvc_camera_terminal; cd = &opts->uvc_camera_terminal;
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
for (result = 0, i = 0; i < cd->bControlSize; ++i) { for (result = 0, i = 0; i < cd->bControlSize; ++i) {
result += sprintf(pg, "%d\n", cd->bmControls[i]); result += sprintf(pg, "%u\n", cd->bmControls[i]);
pg = page + result; pg = page + result;
} }
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
...@@ -383,54 +444,55 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = { ...@@ -383,54 +444,55 @@ static struct configfs_attribute *uvcg_default_camera_attrs[] = {
NULL, NULL,
}; };
static const struct config_item_type uvcg_default_camera_type = { static const struct uvcg_config_group_type uvcg_default_camera_type = {
.ct_attrs = uvcg_default_camera_attrs, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_default_camera_attrs,
.ct_owner = THIS_MODULE,
},
.name = "default",
}; };
/* struct uvcg_camera {}; */ /* -----------------------------------------------------------------------------
* control/terminal/camera
/* control/terminal/camera */ */
static struct uvcg_camera_grp {
struct config_group group;
} uvcg_camera_grp;
static const struct config_item_type uvcg_camera_grp_type = { static const struct uvcg_config_group_type uvcg_camera_grp_type = {
.ct_owner = THIS_MODULE, .type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "camera",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_default_camera_type,
NULL,
},
}; };
/* control/terminal/output/default */ /* -----------------------------------------------------------------------------
static struct uvcg_default_output { * control/terminal/output/default
struct config_group group; */
} uvcg_default_output;
static inline struct uvcg_default_output
*to_uvcg_default_output(struct config_item *item)
{
return container_of(to_config_group(item),
struct uvcg_default_output, group);
}
#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \ #define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_output_##cname##_show( \ static ssize_t uvcg_default_output_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_default_output *dout = to_uvcg_default_output(item); \ struct config_group *group = to_config_group(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_output_terminal_descriptor *cd; \ struct uvc_output_terminal_descriptor *cd; \
int result; \ int result; \
\ \
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\ \
opts_item = dout->group.cg_item.ci_parent->ci_parent-> \ opts_item = group->cg_item.ci_parent->ci_parent-> \
ci_parent->ci_parent; \ ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_output_terminal; \ cd = &opts->uvc_output_terminal; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(cd->aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -440,15 +502,11 @@ static ssize_t uvcg_default_output_##cname##_show( \ ...@@ -440,15 +502,11 @@ static ssize_t uvcg_default_output_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_default_output_, cname, aname) UVC_ATTR_RO(uvcg_default_output_, cname, aname)
#define identity_conv(x) (x) UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8);
UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16);
UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv); UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8);
UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu); UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8);
UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv); UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8);
UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
#undef identity_conv
#undef UVCG_DEFAULT_OUTPUT_ATTR #undef UVCG_DEFAULT_OUTPUT_ATTR
...@@ -461,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = { ...@@ -461,47 +519,68 @@ static struct configfs_attribute *uvcg_default_output_attrs[] = {
NULL, NULL,
}; };
static const struct config_item_type uvcg_default_output_type = { static const struct uvcg_config_group_type uvcg_default_output_type = {
.ct_attrs = uvcg_default_output_attrs, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_default_output_attrs,
.ct_owner = THIS_MODULE,
},
.name = "default",
}; };
/* struct uvcg_output {}; */ /* -----------------------------------------------------------------------------
* control/terminal/output
/* control/terminal/output */ */
static struct uvcg_output_grp {
struct config_group group;
} uvcg_output_grp;
static const struct config_item_type uvcg_output_grp_type = { static const struct uvcg_config_group_type uvcg_output_grp_type = {
.ct_owner = THIS_MODULE, .type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "output",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_default_output_type,
NULL,
},
}; };
/* control/terminal */ /* -----------------------------------------------------------------------------
static struct uvcg_terminal_grp { * control/terminal
struct config_group group; */
} uvcg_terminal_grp;
static const struct config_item_type uvcg_terminal_grp_type = { static const struct uvcg_config_group_type uvcg_terminal_grp_type = {
.ct_owner = THIS_MODULE, .type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "terminal",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_camera_grp_type,
&uvcg_output_grp_type,
NULL,
},
}; };
/* control/class/{fs} */ /* -----------------------------------------------------------------------------
static struct uvcg_control_class { * control/class/{fs|ss}
struct config_group group; */
} uvcg_control_class_fs, uvcg_control_class_ss;
struct uvcg_control_class_group {
struct config_group group;
const char *name;
};
static inline struct uvc_descriptor_header static inline struct uvc_descriptor_header
**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o) **uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
{ {
struct uvcg_control_class *cl = container_of(to_config_group(i), struct uvcg_control_class_group *group =
struct uvcg_control_class, group); container_of(i, struct uvcg_control_class_group,
group.cg_item);
if (cl == &uvcg_control_class_fs) if (!strcmp(group->name, "fs"))
return o->uvc_fs_control_cls; return o->uvc_fs_control_cls;
if (cl == &uvcg_control_class_ss) if (!strcmp(group->name, "ss"))
return o->uvc_ss_control_cls; return o->uvc_ss_control_cls;
return NULL; return NULL;
...@@ -544,6 +623,7 @@ static int uvcg_control_class_allow_link(struct config_item *src, ...@@ -544,6 +623,7 @@ static int uvcg_control_class_allow_link(struct config_item *src,
unlock: unlock:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
out: out:
config_item_put(header);
mutex_unlock(su_mutex); mutex_unlock(su_mutex);
return ret; return ret;
} }
...@@ -579,10 +659,12 @@ static void uvcg_control_class_drop_link(struct config_item *src, ...@@ -579,10 +659,12 @@ static void uvcg_control_class_drop_link(struct config_item *src,
unlock: unlock:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
out: out:
config_item_put(header);
mutex_unlock(su_mutex); mutex_unlock(su_mutex);
} }
static struct configfs_item_operations uvcg_control_class_item_ops = { static struct configfs_item_operations uvcg_control_class_item_ops = {
.release = uvcg_config_item_release,
.allow_link = uvcg_control_class_allow_link, .allow_link = uvcg_control_class_allow_link,
.drop_link = uvcg_control_class_drop_link, .drop_link = uvcg_control_class_drop_link,
}; };
...@@ -592,37 +674,99 @@ static const struct config_item_type uvcg_control_class_type = { ...@@ -592,37 +674,99 @@ static const struct config_item_type uvcg_control_class_type = {
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
/* control/class */ /* -----------------------------------------------------------------------------
static struct uvcg_control_class_grp { * control/class
struct config_group group; */
} uvcg_control_class_grp;
static int uvcg_control_class_create_children(struct config_group *parent)
{
static const char * const names[] = { "fs", "ss" };
unsigned int i;
static const struct config_item_type uvcg_control_class_grp_type = { for (i = 0; i < ARRAY_SIZE(names); ++i) {
.ct_owner = THIS_MODULE, struct uvcg_control_class_group *group;
group = kzalloc(sizeof(*group), GFP_KERNEL);
if (!group)
return -ENOMEM;
group->name = names[i];
config_group_init_type_name(&group->group, group->name,
&uvcg_control_class_type);
configfs_add_default_group(&group->group, parent);
}
return 0;
}
static const struct uvcg_config_group_type uvcg_control_class_grp_type = {
.type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "class",
.create_children = uvcg_control_class_create_children,
}; };
/* control */ /* -----------------------------------------------------------------------------
static struct uvcg_control_grp { * control
struct config_group group; */
} uvcg_control_grp;
static ssize_t uvcg_default_control_b_interface_number_show(
struct config_item *item, char *page)
{
struct config_group *group = to_config_group(item);
struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct config_item *opts_item;
struct f_uvc_opts *opts;
int result = 0;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
opts_item = item->ci_parent;
opts = to_f_uvc_opts(opts_item);
mutex_lock(&opts->lock);
result += sprintf(page, "%u\n", opts->control_interface);
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
return result;
}
UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber);
static const struct config_item_type uvcg_control_grp_type = { static struct configfs_attribute *uvcg_default_control_attrs[] = {
.ct_owner = THIS_MODULE, &uvcg_default_control_attr_b_interface_number,
NULL,
}; };
/* streaming/uncompressed */ static const struct uvcg_config_group_type uvcg_control_grp_type = {
static struct uvcg_uncompressed_grp { .type = {
struct config_group group; .ct_item_ops = &uvcg_config_item_ops,
} uvcg_uncompressed_grp; .ct_attrs = uvcg_default_control_attrs,
.ct_owner = THIS_MODULE,
},
.name = "control",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_control_header_grp_type,
&uvcg_processing_grp_type,
&uvcg_terminal_grp_type,
&uvcg_control_class_grp_type,
NULL,
},
};
/* streaming/mjpeg */ /* -----------------------------------------------------------------------------
static struct uvcg_mjpeg_grp { * streaming/uncompressed
struct config_group group; * streaming/mjpeg
} uvcg_mjpeg_grp; */
static struct config_item *fmt_parent[] = { static const char * const uvcg_format_names[] = {
&uvcg_uncompressed_grp.group.cg_item, "uncompressed",
&uvcg_mjpeg_grp.group.cg_item, "mjpeg",
}; };
enum uvcg_format_type { enum uvcg_format_type {
...@@ -706,7 +850,11 @@ struct uvcg_format_ptr { ...@@ -706,7 +850,11 @@ struct uvcg_format_ptr {
struct list_head entry; struct list_head entry;
}; };
/* streaming/header/<NAME> */ /* -----------------------------------------------------------------------------
* streaming/header/<NAME>
* streaming/header
*/
struct uvcg_streaming_header { struct uvcg_streaming_header {
struct config_item item; struct config_item item;
struct uvc_input_header_descriptor desc; struct uvc_input_header_descriptor desc;
...@@ -720,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item ...@@ -720,6 +868,8 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item
return container_of(item, struct uvcg_streaming_header, 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, static int uvcg_streaming_header_allow_link(struct config_item *src,
struct config_item *target) struct config_item *target)
{ {
...@@ -744,10 +894,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, ...@@ -744,10 +894,22 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
goto out; goto out;
} }
for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i) /*
if (target->ci_parent == fmt_parent[i]) * Linking is only allowed to direct children of the format nodes
* (streaming/uncompressed or streaming/mjpeg nodes). First check that
* the grand-parent of the target matches the grand-parent of the source
* (the streaming node), and then verify that the target parent is a
* format node.
*/
if (src->ci_parent->ci_parent != target->ci_parent->ci_parent)
goto out;
for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) {
if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i]))
break; break;
if (i == ARRAY_SIZE(fmt_parent)) }
if (i == ARRAY_SIZE(uvcg_format_names))
goto out; goto out;
target_fmt = container_of(to_config_group(target), struct uvcg_format, target_fmt = container_of(to_config_group(target), struct uvcg_format,
...@@ -755,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, ...@@ -755,6 +917,8 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
if (!target_fmt) if (!target_fmt)
goto out; goto out;
uvcg_format_set_indices(to_config_group(target));
format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
if (!format_ptr) { if (!format_ptr) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -764,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, ...@@ -764,6 +928,7 @@ static int uvcg_streaming_header_allow_link(struct config_item *src,
format_ptr->fmt = target_fmt; format_ptr->fmt = target_fmt;
list_add_tail(&format_ptr->entry, &src_hdr->formats); list_add_tail(&format_ptr->entry, &src_hdr->formats);
++src_hdr->num_fmt; ++src_hdr->num_fmt;
++target_fmt->linked;
out: out:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
...@@ -801,19 +966,22 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, ...@@ -801,19 +966,22 @@ static void uvcg_streaming_header_drop_link(struct config_item *src,
break; break;
} }
--target_fmt->linked;
out: out:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
mutex_unlock(su_mutex); mutex_unlock(su_mutex);
} }
static struct configfs_item_operations uvcg_streaming_header_item_ops = { static struct configfs_item_operations uvcg_streaming_header_item_ops = {
.allow_link = uvcg_streaming_header_allow_link, .release = uvcg_config_item_release,
.drop_link = uvcg_streaming_header_drop_link, .allow_link = uvcg_streaming_header_allow_link,
.drop_link = uvcg_streaming_header_drop_link,
}; };
#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \ #define UVCG_STREAMING_HEADER_ATTR(cname, aname, bits) \
static ssize_t uvcg_streaming_header_##cname##_show( \ static ssize_t uvcg_streaming_header_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \ struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
...@@ -827,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ ...@@ -827,7 +995,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(sh->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(sh->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -836,16 +1004,11 @@ static ssize_t uvcg_streaming_header_##cname##_show( \ ...@@ -836,16 +1004,11 @@ static ssize_t uvcg_streaming_header_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_streaming_header_, cname, aname) UVC_ATTR_RO(uvcg_streaming_header_, cname, aname)
#define identity_conv(x) (x) UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, 8);
UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, 8);
UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv); UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, 8);
UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv); UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, 8);
UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod, UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, 8);
identity_conv);
UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
#undef identity_conv
#undef UVCG_STREAMING_HEADER_ATTR #undef UVCG_STREAMING_HEADER_ATTR
...@@ -884,31 +1047,26 @@ static struct config_item ...@@ -884,31 +1047,26 @@ static struct config_item
return &h->item; return &h->item;
} }
static void uvcg_streaming_header_drop(struct config_group *group,
struct config_item *item)
{
struct uvcg_streaming_header *h = to_uvcg_streaming_header(item);
kfree(h);
}
/* streaming/header */
static struct uvcg_streaming_header_grp {
struct config_group group;
} uvcg_streaming_header_grp;
static struct configfs_group_operations uvcg_streaming_header_grp_ops = { static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
.make_item = uvcg_streaming_header_make, .make_item = uvcg_streaming_header_make,
.drop_item = uvcg_streaming_header_drop,
}; };
static const struct config_item_type uvcg_streaming_header_grp_type = { static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = {
.ct_group_ops = &uvcg_streaming_header_grp_ops, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_streaming_header_grp_ops,
.ct_owner = THIS_MODULE,
},
.name = "header",
}; };
/* streaming/<mode>/<format>/<NAME> */ /* -----------------------------------------------------------------------------
* streaming/<mode>/<format>/<NAME>
*/
struct uvcg_frame { struct uvcg_frame {
struct config_item item;
enum uvcg_format_type fmt_type;
struct { struct {
u8 b_length; u8 b_length;
u8 b_descriptor_type; u8 b_descriptor_type;
...@@ -924,8 +1082,6 @@ struct uvcg_frame { ...@@ -924,8 +1082,6 @@ struct uvcg_frame {
u8 b_frame_interval_type; u8 b_frame_interval_type;
} __attribute__((packed)) frame; } __attribute__((packed)) frame;
u32 *dw_frame_interval; u32 *dw_frame_interval;
enum uvcg_format_type fmt_type;
struct config_item item;
}; };
static struct uvcg_frame *to_uvcg_frame(struct config_item *item) static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
...@@ -933,7 +1089,7 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item) ...@@ -933,7 +1089,7 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
return container_of(item, struct uvcg_frame, item); return container_of(item, struct uvcg_frame, item);
} }
#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \ #define UVCG_FRAME_ATTR(cname, aname, bits) \
static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
{ \ { \
struct uvcg_frame *f = to_uvcg_frame(item); \ struct uvcg_frame *f = to_uvcg_frame(item); \
...@@ -948,7 +1104,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\ ...@@ -948,7 +1104,7 @@ static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \ result = sprintf(page, "%u\n", f->frame.cname); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -963,8 +1119,8 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ ...@@ -963,8 +1119,8 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct uvcg_format *fmt; \ struct uvcg_format *fmt; \
struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
typeof(f->frame.cname) num; \
int ret; \ int ret; \
u##bits num; \
\ \
ret = kstrtou##bits(page, 0, &num); \ ret = kstrtou##bits(page, 0, &num); \
if (ret) \ if (ret) \
...@@ -982,7 +1138,7 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \ ...@@ -982,7 +1138,7 @@ static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
goto end; \ goto end; \
} \ } \
\ \
f->frame.cname = to_little_endian(num); \ f->frame.cname = num; \
ret = len; \ ret = len; \
end: \ end: \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
...@@ -992,20 +1148,48 @@ end: \ ...@@ -992,20 +1148,48 @@ end: \
\ \
UVC_ATTR(uvcg_frame_, cname, aname); UVC_ATTR(uvcg_frame_, cname, aname);
#define noop_conversion(x) (x) static ssize_t uvcg_frame_b_frame_index_show(struct config_item *item,
char *page)
{
struct uvcg_frame *f = to_uvcg_frame(item);
struct uvcg_format *fmt;
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct config_item *fmt_item;
struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;
int result;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
fmt_item = f->item.ci_parent;
fmt = to_uvcg_format(fmt_item);
UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion, if (!fmt->linked) {
noop_conversion, 8); result = -EBUSY;
UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16); goto out;
UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16); }
UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
le32_to_cpu, cpu_to_le32, 32);
UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
le32_to_cpu, cpu_to_le32, 32);
#undef noop_conversion opts_item = fmt_item->ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item);
mutex_lock(&opts->lock);
result = sprintf(page, "%u\n", f->frame.b_frame_index);
mutex_unlock(&opts->lock);
out:
mutex_unlock(su_mutex);
return result;
}
UVC_ATTR_RO(uvcg_frame_, b_frame_index, bFrameIndex);
UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, 8);
UVCG_FRAME_ATTR(w_width, wWidth, 16);
UVCG_FRAME_ATTR(w_height, wHeight, 16);
UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32);
UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32);
UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32);
UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32);
#undef UVCG_FRAME_ATTR #undef UVCG_FRAME_ATTR
...@@ -1026,8 +1210,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, ...@@ -1026,8 +1210,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) { for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
result += sprintf(pg, "%d\n", result += sprintf(pg, "%u\n", frm->dw_frame_interval[i]);
le32_to_cpu(frm->dw_frame_interval[i]));
pg = page + result; pg = page + result;
} }
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
...@@ -1052,7 +1235,7 @@ static inline int __uvcg_fill_frm_intrv(char *buf, void *priv) ...@@ -1052,7 +1235,7 @@ static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
return ret; return ret;
interv = priv; interv = priv;
**interv = cpu_to_le32(num); **interv = num;
++*interv; ++*interv;
return 0; return 0;
...@@ -1129,6 +1312,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, ...@@ -1129,6 +1312,8 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
kfree(ch->dw_frame_interval); kfree(ch->dw_frame_interval);
ch->dw_frame_interval = frm_intrv; ch->dw_frame_interval = frm_intrv;
ch->frame.b_frame_interval_type = n; 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; ret = len;
end: end:
...@@ -1140,6 +1325,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, ...@@ -1140,6 +1325,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
static struct configfs_attribute *uvcg_frame_attrs[] = { static struct configfs_attribute *uvcg_frame_attrs[] = {
&uvcg_frame_attr_b_frame_index,
&uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_bm_capabilities,
&uvcg_frame_attr_w_width, &uvcg_frame_attr_w_width,
&uvcg_frame_attr_w_height, &uvcg_frame_attr_w_height,
...@@ -1152,6 +1338,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { ...@@ -1152,6 +1338,7 @@ static struct configfs_attribute *uvcg_frame_attrs[] = {
}; };
static const struct config_item_type uvcg_frame_type = { static const struct config_item_type uvcg_frame_type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_frame_attrs, .ct_attrs = uvcg_frame_attrs,
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
...@@ -1170,12 +1357,12 @@ static struct config_item *uvcg_frame_make(struct config_group *group, ...@@ -1170,12 +1357,12 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
h->frame.b_descriptor_type = USB_DT_CS_INTERFACE; h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
h->frame.b_frame_index = 1; h->frame.b_frame_index = 1;
h->frame.w_width = cpu_to_le16(640); h->frame.w_width = 640;
h->frame.w_height = cpu_to_le16(360); h->frame.w_height = 360;
h->frame.dw_min_bit_rate = cpu_to_le32(18432000); h->frame.dw_min_bit_rate = 18432000;
h->frame.dw_max_bit_rate = cpu_to_le32(55296000); h->frame.dw_max_bit_rate = 55296000;
h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800); h->frame.dw_max_video_frame_buffer_size = 460800;
h->frame.dw_default_frame_interval = cpu_to_le32(666666); h->frame.dw_default_frame_interval = 666666;
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
opts = to_f_uvc_opts(opts_item); opts = to_f_uvc_opts(opts_item);
...@@ -1203,7 +1390,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group, ...@@ -1203,7 +1390,6 @@ static struct config_item *uvcg_frame_make(struct config_group *group,
static void uvcg_frame_drop(struct config_group *group, struct config_item *item) static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
{ {
struct uvcg_frame *h = to_uvcg_frame(item);
struct uvcg_format *fmt; struct uvcg_format *fmt;
struct f_uvc_opts *opts; struct f_uvc_opts *opts;
struct config_item *opts_item; struct config_item *opts_item;
...@@ -1214,11 +1400,31 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item ...@@ -1214,11 +1400,31 @@ static void uvcg_frame_drop(struct config_group *group, struct config_item *item
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
fmt = to_uvcg_format(&group->cg_item); fmt = to_uvcg_format(&group->cg_item);
--fmt->num_frames; --fmt->num_frames;
kfree(h);
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
config_item_put(item);
}
static void uvcg_format_set_indices(struct config_group *fmt)
{
struct config_item *ci;
unsigned int i = 1;
list_for_each_entry(ci, &fmt->cg_children, ci_entry) {
struct uvcg_frame *frm;
if (ci->ci_type != &uvcg_frame_type)
continue;
frm = to_uvcg_frame(ci);
frm->frame.b_frame_index = i++;
}
} }
/* streaming/uncompressed/<NAME> */ /* -----------------------------------------------------------------------------
* streaming/uncompressed/<NAME>
*/
struct uvcg_uncompressed { struct uvcg_uncompressed {
struct uvcg_format fmt; struct uvcg_format fmt;
struct uvc_format_uncompressed desc; struct uvc_format_uncompressed desc;
...@@ -1290,7 +1496,7 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item, ...@@ -1290,7 +1496,7 @@ static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat); UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat);
#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \ #define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, bits) \
static ssize_t uvcg_uncompressed_##cname##_show( \ static ssize_t uvcg_uncompressed_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
...@@ -1306,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ ...@@ -1306,7 +1512,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(u->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -1315,7 +1521,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ ...@@ -1315,7 +1521,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_uncompressed_, cname, aname); UVC_ATTR_RO(uvcg_uncompressed_, cname, aname);
#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \ #define UVCG_UNCOMPRESSED_ATTR(cname, aname, bits) \
static ssize_t uvcg_uncompressed_##cname##_show( \ static ssize_t uvcg_uncompressed_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
...@@ -1331,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \ ...@@ -1331,7 +1537,7 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(u->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -1378,16 +1584,12 @@ end: \ ...@@ -1378,16 +1584,12 @@ end: \
\ \
UVC_ATTR(uvcg_uncompressed_, cname, aname); UVC_ATTR(uvcg_uncompressed_, cname, aname);
#define identity_conv(x) (x) UVCG_UNCOMPRESSED_ATTR_RO(b_format_index, bFormatIndex, 8);
UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, 8);
UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv); UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex, UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
identity_conv); UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
#undef identity_conv
#undef UVCG_UNCOMPRESSED_ATTR #undef UVCG_UNCOMPRESSED_ATTR
#undef UVCG_UNCOMPRESSED_ATTR_RO #undef UVCG_UNCOMPRESSED_ATTR_RO
...@@ -1410,6 +1612,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item, ...@@ -1410,6 +1612,7 @@ uvcg_uncompressed_bma_controls_store(struct config_item *item,
UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls); UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_uncompressed_attrs[] = { static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
&uvcg_uncompressed_attr_b_format_index,
&uvcg_uncompressed_attr_guid_format, &uvcg_uncompressed_attr_guid_format,
&uvcg_uncompressed_attr_b_bits_per_pixel, &uvcg_uncompressed_attr_b_bits_per_pixel,
&uvcg_uncompressed_attr_b_default_frame_index, &uvcg_uncompressed_attr_b_default_frame_index,
...@@ -1421,6 +1624,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = { ...@@ -1421,6 +1624,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
}; };
static const struct config_item_type uvcg_uncompressed_type = { static const struct config_item_type uvcg_uncompressed_type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_uncompressed_group_ops, .ct_group_ops = &uvcg_uncompressed_group_ops,
.ct_attrs = uvcg_uncompressed_attrs, .ct_attrs = uvcg_uncompressed_attrs,
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
...@@ -1457,25 +1661,23 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group, ...@@ -1457,25 +1661,23 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
return &h->fmt.group; return &h->fmt.group;
} }
static void uvcg_uncompressed_drop(struct config_group *group,
struct config_item *item)
{
struct uvcg_uncompressed *h = to_uvcg_uncompressed(item);
kfree(h);
}
static struct configfs_group_operations uvcg_uncompressed_grp_ops = { static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
.make_group = uvcg_uncompressed_make, .make_group = uvcg_uncompressed_make,
.drop_item = uvcg_uncompressed_drop,
}; };
static const struct config_item_type uvcg_uncompressed_grp_type = { static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = {
.ct_group_ops = &uvcg_uncompressed_grp_ops, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_uncompressed_grp_ops,
.ct_owner = THIS_MODULE,
},
.name = "uncompressed",
}; };
/* streaming/mjpeg/<NAME> */ /* -----------------------------------------------------------------------------
* streaming/mjpeg/<NAME>
*/
struct uvcg_mjpeg { struct uvcg_mjpeg {
struct uvcg_format fmt; struct uvcg_format fmt;
struct uvc_format_mjpeg desc; struct uvc_format_mjpeg desc;
...@@ -1493,7 +1695,7 @@ static struct configfs_group_operations uvcg_mjpeg_group_ops = { ...@@ -1493,7 +1695,7 @@ static struct configfs_group_operations uvcg_mjpeg_group_ops = {
.drop_item = uvcg_frame_drop, .drop_item = uvcg_frame_drop,
}; };
#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \ #define UVCG_MJPEG_ATTR_RO(cname, aname, bits) \
static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \ { \
struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
...@@ -1508,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ ...@@ -1508,7 +1710,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(u->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -1517,7 +1719,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ ...@@ -1517,7 +1719,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
\ \
UVC_ATTR_RO(uvcg_mjpeg_, cname, aname) UVC_ATTR_RO(uvcg_mjpeg_, cname, aname)
#define UVCG_MJPEG_ATTR(cname, aname, conv) \ #define UVCG_MJPEG_ATTR(cname, aname, bits) \
static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \ { \
struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
...@@ -1532,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\ ...@@ -1532,7 +1734,7 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(u->desc.aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -1579,16 +1781,12 @@ end: \ ...@@ -1579,16 +1781,12 @@ end: \
\ \
UVC_ATTR(uvcg_mjpeg_, cname, aname) UVC_ATTR(uvcg_mjpeg_, cname, aname)
#define identity_conv(x) (x) UVCG_MJPEG_ATTR_RO(b_format_index, bFormatIndex, 8);
UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, 8);
UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex, UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, 8);
identity_conv); UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8);
UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv); UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8);
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv); UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8);
UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
#undef identity_conv
#undef UVCG_MJPEG_ATTR #undef UVCG_MJPEG_ATTR
#undef UVCG_MJPEG_ATTR_RO #undef UVCG_MJPEG_ATTR_RO
...@@ -1611,6 +1809,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item, ...@@ -1611,6 +1809,7 @@ uvcg_mjpeg_bma_controls_store(struct config_item *item,
UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls); UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_mjpeg_attrs[] = { static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
&uvcg_mjpeg_attr_b_format_index,
&uvcg_mjpeg_attr_b_default_frame_index, &uvcg_mjpeg_attr_b_default_frame_index,
&uvcg_mjpeg_attr_bm_flags, &uvcg_mjpeg_attr_bm_flags,
&uvcg_mjpeg_attr_b_aspect_ratio_x, &uvcg_mjpeg_attr_b_aspect_ratio_x,
...@@ -1621,6 +1820,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = { ...@@ -1621,6 +1820,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
}; };
static const struct config_item_type uvcg_mjpeg_type = { static const struct config_item_type uvcg_mjpeg_type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_mjpeg_group_ops, .ct_group_ops = &uvcg_mjpeg_group_ops,
.ct_attrs = uvcg_mjpeg_attrs, .ct_attrs = uvcg_mjpeg_attrs,
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
...@@ -1651,56 +1851,42 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group, ...@@ -1651,56 +1851,42 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
return &h->fmt.group; return &h->fmt.group;
} }
static void uvcg_mjpeg_drop(struct config_group *group,
struct config_item *item)
{
struct uvcg_mjpeg *h = to_uvcg_mjpeg(item);
kfree(h);
}
static struct configfs_group_operations uvcg_mjpeg_grp_ops = { static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
.make_group = uvcg_mjpeg_make, .make_group = uvcg_mjpeg_make,
.drop_item = uvcg_mjpeg_drop,
}; };
static const struct config_item_type uvcg_mjpeg_grp_type = { static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = {
.ct_group_ops = &uvcg_mjpeg_grp_ops, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_group_ops = &uvcg_mjpeg_grp_ops,
.ct_owner = THIS_MODULE,
},
.name = "mjpeg",
}; };
/* streaming/color_matching/default */ /* -----------------------------------------------------------------------------
static struct uvcg_default_color_matching { * streaming/color_matching/default
struct config_group group; */
} uvcg_default_color_matching;
static inline struct uvcg_default_color_matching
*to_uvcg_default_color_matching(struct config_item *item)
{
return container_of(to_config_group(item),
struct uvcg_default_color_matching, group);
}
#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \ #define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, bits) \
static ssize_t uvcg_default_color_matching_##cname##_show( \ static ssize_t uvcg_default_color_matching_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
struct uvcg_default_color_matching *dc = \ struct config_group *group = to_config_group(item); \
to_uvcg_default_color_matching(item); \
struct f_uvc_opts *opts; \ struct f_uvc_opts *opts; \
struct config_item *opts_item; \ struct config_item *opts_item; \
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
struct uvc_color_matching_descriptor *cd; \ struct uvc_color_matching_descriptor *cd; \
int result; \ int result; \
\ \
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\ \
opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \ opts = to_f_uvc_opts(opts_item); \
cd = &opts->uvc_color_matching; \ cd = &opts->uvc_color_matching; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(cd->aname)); \ result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
mutex_unlock(su_mutex); \ mutex_unlock(su_mutex); \
...@@ -1709,16 +1895,10 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \ ...@@ -1709,16 +1895,10 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \
\ \
UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname) UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
#define identity_conv(x) (x) UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8);
UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
identity_conv);
UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics, UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
bTransferCharacteristics, identity_conv); bTransferCharacteristics, 8);
UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8);
identity_conv);
#undef identity_conv
#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR #undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
...@@ -1729,41 +1909,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = { ...@@ -1729,41 +1909,54 @@ static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
NULL, NULL,
}; };
static const struct config_item_type uvcg_default_color_matching_type = { static const struct uvcg_config_group_type uvcg_default_color_matching_type = {
.ct_attrs = uvcg_default_color_matching_attrs, .type = {
.ct_owner = THIS_MODULE, .ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_default_color_matching_attrs,
.ct_owner = THIS_MODULE,
},
.name = "default",
}; };
/* struct uvcg_color_matching {}; */ /* -----------------------------------------------------------------------------
* streaming/color_matching
/* streaming/color_matching */ */
static struct uvcg_color_matching_grp {
struct config_group group;
} uvcg_color_matching_grp;
static const struct config_item_type uvcg_color_matching_grp_type = { static const struct uvcg_config_group_type uvcg_color_matching_grp_type = {
.ct_owner = THIS_MODULE, .type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "color_matching",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_default_color_matching_type,
NULL,
},
}; };
/* streaming/class/{fs|hs|ss} */ /* -----------------------------------------------------------------------------
static struct uvcg_streaming_class { * streaming/class/{fs|hs|ss}
struct config_group group; */
} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
struct uvcg_streaming_class_group {
struct config_group group;
const char *name;
};
static inline struct uvc_descriptor_header static inline struct uvc_descriptor_header
***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o) ***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
{ {
struct uvcg_streaming_class *cl = container_of(to_config_group(i), struct uvcg_streaming_class_group *group =
struct uvcg_streaming_class, group); container_of(i, struct uvcg_streaming_class_group,
group.cg_item);
if (cl == &uvcg_streaming_class_fs) if (!strcmp(group->name, "fs"))
return &o->uvc_fs_streaming_cls; return &o->uvc_fs_streaming_cls;
if (cl == &uvcg_streaming_class_hs) if (!strcmp(group->name, "hs"))
return &o->uvc_hs_streaming_cls; return &o->uvc_hs_streaming_cls;
if (cl == &uvcg_streaming_class_ss) if (!strcmp(group->name, "ss"))
return &o->uvc_ss_streaming_cls; return &o->uvc_ss_streaming_cls;
return NULL; return NULL;
...@@ -1922,24 +2115,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, ...@@ -1922,24 +2115,22 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
struct uvcg_format *fmt = priv1; struct uvcg_format *fmt = priv1;
if (fmt->type == UVCG_UNCOMPRESSED) { if (fmt->type == UVCG_UNCOMPRESSED) {
struct uvc_format_uncompressed *unc = *dest;
struct uvcg_uncompressed *u = struct uvcg_uncompressed *u =
container_of(fmt, struct uvcg_uncompressed, container_of(fmt, struct uvcg_uncompressed,
fmt); fmt);
u->desc.bFormatIndex = n + 1;
u->desc.bNumFrameDescriptors = fmt->num_frames;
memcpy(*dest, &u->desc, sizeof(u->desc)); memcpy(*dest, &u->desc, sizeof(u->desc));
*dest += sizeof(u->desc); *dest += sizeof(u->desc);
unc->bNumFrameDescriptors = fmt->num_frames;
unc->bFormatIndex = n + 1;
} else if (fmt->type == UVCG_MJPEG) { } else if (fmt->type == UVCG_MJPEG) {
struct uvc_format_mjpeg *mjp = *dest;
struct uvcg_mjpeg *m = struct uvcg_mjpeg *m =
container_of(fmt, struct uvcg_mjpeg, fmt); container_of(fmt, struct uvcg_mjpeg, fmt);
m->desc.bFormatIndex = n + 1;
m->desc.bNumFrameDescriptors = fmt->num_frames;
memcpy(*dest, &m->desc, sizeof(m->desc)); memcpy(*dest, &m->desc, sizeof(m->desc));
*dest += sizeof(m->desc); *dest += sizeof(m->desc);
mjp->bNumFrameDescriptors = fmt->num_frames;
mjp->bFormatIndex = n + 1;
} else { } else {
return -EINVAL; return -EINVAL;
} }
...@@ -2038,6 +2229,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, ...@@ -2038,6 +2229,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src,
unlock: unlock:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
out: out:
config_item_put(header);
mutex_unlock(su_mutex); mutex_unlock(su_mutex);
return ret; return ret;
} }
...@@ -2078,10 +2270,12 @@ static void uvcg_streaming_class_drop_link(struct config_item *src, ...@@ -2078,10 +2270,12 @@ static void uvcg_streaming_class_drop_link(struct config_item *src,
unlock: unlock:
mutex_unlock(&opts->lock); mutex_unlock(&opts->lock);
out: out:
config_item_put(header);
mutex_unlock(su_mutex); mutex_unlock(su_mutex);
} }
static struct configfs_item_operations uvcg_streaming_class_item_ops = { static struct configfs_item_operations uvcg_streaming_class_item_ops = {
.release = uvcg_config_item_release,
.allow_link = uvcg_streaming_class_allow_link, .allow_link = uvcg_streaming_class_allow_link,
.drop_link = uvcg_streaming_class_drop_link, .drop_link = uvcg_streaming_class_drop_link,
}; };
...@@ -2091,36 +2285,109 @@ static const struct config_item_type uvcg_streaming_class_type = { ...@@ -2091,36 +2285,109 @@ static const struct config_item_type uvcg_streaming_class_type = {
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
/* streaming/class */ /* -----------------------------------------------------------------------------
static struct uvcg_streaming_class_grp { * streaming/class
struct config_group group; */
} uvcg_streaming_class_grp;
static int uvcg_streaming_class_create_children(struct config_group *parent)
{
static const char * const names[] = { "fs", "hs", "ss" };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(names); ++i) {
struct uvcg_streaming_class_group *group;
group = kzalloc(sizeof(*group), GFP_KERNEL);
if (!group)
return -ENOMEM;
static const struct config_item_type uvcg_streaming_class_grp_type = { group->name = names[i];
.ct_owner = THIS_MODULE,
config_group_init_type_name(&group->group, group->name,
&uvcg_streaming_class_type);
configfs_add_default_group(&group->group, parent);
}
return 0;
}
static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = {
.type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_owner = THIS_MODULE,
},
.name = "class",
.create_children = uvcg_streaming_class_create_children,
}; };
/* streaming */ /* -----------------------------------------------------------------------------
static struct uvcg_streaming_grp { * streaming
struct config_group group; */
} uvcg_streaming_grp;
static const struct config_item_type uvcg_streaming_grp_type = { static ssize_t uvcg_default_streaming_b_interface_number_show(
.ct_owner = THIS_MODULE, struct config_item *item, char *page)
{
struct config_group *group = to_config_group(item);
struct mutex *su_mutex = &group->cg_subsys->su_mutex;
struct config_item *opts_item;
struct f_uvc_opts *opts;
int result = 0;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
opts_item = item->ci_parent;
opts = to_f_uvc_opts(opts_item);
mutex_lock(&opts->lock);
result += sprintf(page, "%u\n", opts->streaming_interface);
mutex_unlock(&opts->lock);
mutex_unlock(su_mutex);
return result;
}
UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber);
static struct configfs_attribute *uvcg_default_streaming_attrs[] = {
&uvcg_default_streaming_attr_b_interface_number,
NULL,
};
static const struct uvcg_config_group_type uvcg_streaming_grp_type = {
.type = {
.ct_item_ops = &uvcg_config_item_ops,
.ct_attrs = uvcg_default_streaming_attrs,
.ct_owner = THIS_MODULE,
},
.name = "streaming",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_streaming_header_grp_type,
&uvcg_uncompressed_grp_type,
&uvcg_mjpeg_grp_type,
&uvcg_color_matching_grp_type,
&uvcg_streaming_class_grp_type,
NULL,
},
}; };
static void uvc_attr_release(struct config_item *item) /* -----------------------------------------------------------------------------
* UVC function
*/
static void uvc_func_item_release(struct config_item *item)
{ {
struct f_uvc_opts *opts = to_f_uvc_opts(item); struct f_uvc_opts *opts = to_f_uvc_opts(item);
uvcg_config_remove_children(to_config_group(item));
usb_put_function_instance(&opts->func_inst); usb_put_function_instance(&opts->func_inst);
} }
static struct configfs_item_operations uvc_item_ops = { static struct configfs_item_operations uvc_func_item_ops = {
.release = uvc_attr_release, .release = uvc_func_item_release,
}; };
#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \ #define UVCG_OPTS_ATTR(cname, aname, limit) \
static ssize_t f_uvc_opts_##cname##_show( \ static ssize_t f_uvc_opts_##cname##_show( \
struct config_item *item, char *page) \ struct config_item *item, char *page) \
{ \ { \
...@@ -2128,7 +2395,7 @@ static ssize_t f_uvc_opts_##cname##_show( \ ...@@ -2128,7 +2395,7 @@ static ssize_t f_uvc_opts_##cname##_show( \
int result; \ int result; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
result = sprintf(page, "%d\n", conv(opts->cname)); \ result = sprintf(page, "%u\n", opts->cname); \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
\ \
return result; \ return result; \
...@@ -2139,8 +2406,8 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ ...@@ -2139,8 +2406,8 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
const char *page, size_t len) \ const char *page, size_t len) \
{ \ { \
struct f_uvc_opts *opts = to_f_uvc_opts(item); \ struct f_uvc_opts *opts = to_f_uvc_opts(item); \
unsigned int num; \
int ret; \ int ret; \
uxx num; \
\ \
mutex_lock(&opts->lock); \ mutex_lock(&opts->lock); \
if (opts->refcnt) { \ if (opts->refcnt) { \
...@@ -2148,7 +2415,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ ...@@ -2148,7 +2415,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
goto end; \ goto end; \
} \ } \
\ \
ret = str2u(page, 0, &num); \ ret = kstrtouint(page, 0, &num); \
if (ret) \ if (ret) \
goto end; \ goto end; \
\ \
...@@ -2156,7 +2423,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \ ...@@ -2156,7 +2423,7 @@ f_uvc_opts_##cname##_store(struct config_item *item, \
ret = -EINVAL; \ ret = -EINVAL; \
goto end; \ goto end; \
} \ } \
opts->cname = vnoc(num); \ opts->cname = num; \
ret = len; \ ret = len; \
end: \ end: \
mutex_unlock(&opts->lock); \ mutex_unlock(&opts->lock); \
...@@ -2165,16 +2432,9 @@ end: \ ...@@ -2165,16 +2432,9 @@ end: \
\ \
UVC_ATTR(f_uvc_opts_, cname, cname) UVC_ATTR(f_uvc_opts_, cname, cname)
#define identity_conv(x) (x) UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16);
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072);
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
kstrtou8, u8, identity_conv, 16);
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
kstrtou16, u16, le16_to_cpu, 3072);
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
kstrtou8, u8, identity_conv, 15);
#undef identity_conv
#undef UVCG_OPTS_ATTR #undef UVCG_OPTS_ATTR
...@@ -2185,123 +2445,31 @@ static struct configfs_attribute *uvc_attrs[] = { ...@@ -2185,123 +2445,31 @@ static struct configfs_attribute *uvc_attrs[] = {
NULL, NULL,
}; };
static const struct config_item_type uvc_func_type = { static const struct uvcg_config_group_type uvc_func_type = {
.ct_item_ops = &uvc_item_ops, .type = {
.ct_attrs = uvc_attrs, .ct_item_ops = &uvc_func_item_ops,
.ct_owner = THIS_MODULE, .ct_attrs = uvc_attrs,
.ct_owner = THIS_MODULE,
},
.name = "",
.children = (const struct uvcg_config_group_type*[]) {
&uvcg_control_grp_type,
&uvcg_streaming_grp_type,
NULL,
},
}; };
int uvcg_attach_configfs(struct f_uvc_opts *opts) int uvcg_attach_configfs(struct f_uvc_opts *opts)
{ {
config_group_init_type_name(&uvcg_control_header_grp.group, int ret;
"header",
&uvcg_control_header_grp_type);
config_group_init_type_name(&uvcg_default_processing.group,
"default", &uvcg_default_processing_type);
config_group_init_type_name(&uvcg_processing_grp.group,
"processing", &uvcg_processing_grp_type);
configfs_add_default_group(&uvcg_default_processing.group,
&uvcg_processing_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,
"camera", &uvcg_camera_grp_type);
configfs_add_default_group(&uvcg_default_camera.group,
&uvcg_camera_grp.group);
config_group_init_type_name(&uvcg_default_output.group,
"default", &uvcg_default_output_type);
config_group_init_type_name(&uvcg_output_grp.group,
"output", &uvcg_output_grp_type);
configfs_add_default_group(&uvcg_default_output.group,
&uvcg_output_grp.group);
config_group_init_type_name(&uvcg_terminal_grp.group,
"terminal", &uvcg_terminal_grp_type);
configfs_add_default_group(&uvcg_camera_grp.group,
&uvcg_terminal_grp.group);
configfs_add_default_group(&uvcg_output_grp.group,
&uvcg_terminal_grp.group);
config_group_init_type_name(&uvcg_control_class_fs.group,
"fs", &uvcg_control_class_type);
config_group_init_type_name(&uvcg_control_class_ss.group,
"ss", &uvcg_control_class_type);
config_group_init_type_name(&uvcg_control_class_grp.group,
"class",
&uvcg_control_class_grp_type);
configfs_add_default_group(&uvcg_control_class_fs.group,
&uvcg_control_class_grp.group);
configfs_add_default_group(&uvcg_control_class_ss.group,
&uvcg_control_class_grp.group);
config_group_init_type_name(&uvcg_control_grp.group,
"control",
&uvcg_control_grp_type);
configfs_add_default_group(&uvcg_control_header_grp.group,
&uvcg_control_grp.group);
configfs_add_default_group(&uvcg_processing_grp.group,
&uvcg_control_grp.group);
configfs_add_default_group(&uvcg_terminal_grp.group,
&uvcg_control_grp.group);
configfs_add_default_group(&uvcg_control_class_grp.group,
&uvcg_control_grp.group);
config_group_init_type_name(&uvcg_streaming_header_grp.group,
"header",
&uvcg_streaming_header_grp_type);
config_group_init_type_name(&uvcg_uncompressed_grp.group,
"uncompressed",
&uvcg_uncompressed_grp_type);
config_group_init_type_name(&uvcg_mjpeg_grp.group,
"mjpeg",
&uvcg_mjpeg_grp_type);
config_group_init_type_name(&uvcg_default_color_matching.group,
"default",
&uvcg_default_color_matching_type);
config_group_init_type_name(&uvcg_color_matching_grp.group,
"color_matching",
&uvcg_color_matching_grp_type);
configfs_add_default_group(&uvcg_default_color_matching.group,
&uvcg_color_matching_grp.group);
config_group_init_type_name(&uvcg_streaming_class_fs.group,
"fs", &uvcg_streaming_class_type);
config_group_init_type_name(&uvcg_streaming_class_hs.group,
"hs", &uvcg_streaming_class_type);
config_group_init_type_name(&uvcg_streaming_class_ss.group,
"ss", &uvcg_streaming_class_type);
config_group_init_type_name(&uvcg_streaming_class_grp.group,
"class", &uvcg_streaming_class_grp_type);
configfs_add_default_group(&uvcg_streaming_class_fs.group,
&uvcg_streaming_class_grp.group);
configfs_add_default_group(&uvcg_streaming_class_hs.group,
&uvcg_streaming_class_grp.group);
configfs_add_default_group(&uvcg_streaming_class_ss.group,
&uvcg_streaming_class_grp.group);
config_group_init_type_name(&uvcg_streaming_grp.group,
"streaming", &uvcg_streaming_grp_type);
configfs_add_default_group(&uvcg_streaming_header_grp.group,
&uvcg_streaming_grp.group);
configfs_add_default_group(&uvcg_uncompressed_grp.group,
&uvcg_streaming_grp.group);
configfs_add_default_group(&uvcg_mjpeg_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,
&uvcg_streaming_grp.group);
config_group_init_type_name(&opts->func_inst.group,
"",
&uvc_func_type);
configfs_add_default_group(&uvcg_control_grp.group,
&opts->func_inst.group);
configfs_add_default_group(&uvcg_streaming_grp.group,
&opts->func_inst.group);
return 0; config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name,
&uvc_func_type.type);
ret = uvcg_config_create_children(&opts->func_inst.group,
&uvc_func_type);
if (ret < 0)
config_group_put(&opts->func_inst.group);
return ret;
} }
...@@ -115,8 +115,8 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) ...@@ -115,8 +115,8 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
} }
if (i == ARRAY_SIZE(uvc_formats)) { if (i == ARRAY_SIZE(uvc_formats)) {
printk(KERN_INFO "Unsupported format 0x%08x.\n", uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
fmt->fmt.pix.pixelformat); fmt->fmt.pix.pixelformat);
return -EINVAL; return -EINVAL;
} }
......
...@@ -125,6 +125,23 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, ...@@ -125,6 +125,23 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
* Request handling * Request handling
*/ */
static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
{
int ret;
ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
if (ret < 0) {
uvcg_err(&video->uvc->func, "Failed to queue request (%d).\n",
ret);
/* Isochronous endpoints can't be halted. */
if (usb_endpoint_xfer_bulk(video->ep->desc))
usb_ep_set_halt(video->ep);
}
return ret;
}
/* /*
* I somehow feel that synchronisation won't be easy to achieve here. We have * I somehow feel that synchronisation won't be easy to achieve here. We have
* three events that control USB requests submission: * three events that control USB requests submission:
...@@ -169,13 +186,14 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -169,13 +186,14 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
break; break;
case -ESHUTDOWN: /* disconnect from host. */ case -ESHUTDOWN: /* disconnect from host. */
printk(KERN_DEBUG "VS request cancelled.\n"); uvcg_dbg(&video->uvc->func, "VS request cancelled.\n");
uvcg_queue_cancel(queue, 1); uvcg_queue_cancel(queue, 1);
goto requeue; goto requeue;
default: default:
printk(KERN_INFO "VS request completed with status %d.\n", uvcg_info(&video->uvc->func,
req->status); "VS request completed with status %d.\n",
req->status);
uvcg_queue_cancel(queue, 0); uvcg_queue_cancel(queue, 0);
goto requeue; goto requeue;
} }
...@@ -189,14 +207,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -189,14 +207,13 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
video->encode(req, video, buf); video->encode(req, video, buf);
if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { ret = uvcg_video_ep_queue(video, req);
printk(KERN_INFO "Failed to queue request (%d).\n", ret); spin_unlock_irqrestore(&video->queue.irqlock, flags);
usb_ep_set_halt(ep);
spin_unlock_irqrestore(&video->queue.irqlock, flags); if (ret < 0) {
uvcg_queue_cancel(queue, 0); uvcg_queue_cancel(queue, 0);
goto requeue; goto requeue;
} }
spin_unlock_irqrestore(&video->queue.irqlock, flags);
return; return;
...@@ -316,15 +333,13 @@ int uvcg_video_pump(struct uvc_video *video) ...@@ -316,15 +333,13 @@ int uvcg_video_pump(struct uvc_video *video)
video->encode(req, video, buf); video->encode(req, video, buf);
/* Queue the USB request */ /* Queue the USB request */
ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); ret = uvcg_video_ep_queue(video, req);
spin_unlock_irqrestore(&queue->irqlock, flags);
if (ret < 0) { if (ret < 0) {
printk(KERN_INFO "Failed to queue request (%d)\n", ret);
usb_ep_set_halt(video->ep);
spin_unlock_irqrestore(&queue->irqlock, flags);
uvcg_queue_cancel(queue, 0); uvcg_queue_cancel(queue, 0);
break; break;
} }
spin_unlock_irqrestore(&queue->irqlock, flags);
} }
spin_lock_irqsave(&video->req_lock, flags); spin_lock_irqsave(&video->req_lock, flags);
...@@ -342,8 +357,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable) ...@@ -342,8 +357,8 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
int ret; int ret;
if (video->ep == NULL) { if (video->ep == NULL) {
printk(KERN_INFO "Video enable failed, device is " uvcg_info(&video->uvc->func,
"uninitialized.\n"); "Video enable failed, device is uninitialized.\n");
return -ENODEV; return -ENODEV;
} }
...@@ -375,11 +390,12 @@ int uvcg_video_enable(struct uvc_video *video, int enable) ...@@ -375,11 +390,12 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
/* /*
* Initialize the UVC video stream. * Initialize the UVC video stream.
*/ */
int uvcg_video_init(struct uvc_video *video) int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
{ {
INIT_LIST_HEAD(&video->req_free); INIT_LIST_HEAD(&video->req_free);
spin_lock_init(&video->req_lock); spin_lock_init(&video->req_lock);
video->uvc = uvc;
video->fcc = V4L2_PIX_FMT_YUYV; video->fcc = V4L2_PIX_FMT_YUYV;
video->bpp = 16; video->bpp = 16;
video->width = 320; video->width = 320;
......
...@@ -18,6 +18,6 @@ int uvcg_video_pump(struct uvc_video *video); ...@@ -18,6 +18,6 @@ int uvcg_video_pump(struct uvc_video *video);
int uvcg_video_enable(struct uvc_video *video, int enable); int uvcg_video_enable(struct uvc_video *video, int enable);
int uvcg_video_init(struct uvc_video *video); int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc);
#endif /* __UVC_VIDEO_H__ */ #endif /* __UVC_VIDEO_H__ */
...@@ -192,14 +192,14 @@ struct uvc_descriptor_header { ...@@ -192,14 +192,14 @@ struct uvc_descriptor_header {
/* 3.7.2. Video Control Interface Header Descriptor */ /* 3.7.2. Video Control Interface Header Descriptor */
struct uvc_header_descriptor { struct uvc_header_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u16 bcdUVC; __le16 bcdUVC;
__u16 wTotalLength; __le16 wTotalLength;
__u32 dwClockFrequency; __le32 dwClockFrequency;
__u8 bInCollection; __u8 bInCollection;
__u8 baInterfaceNr[]; __u8 baInterfaceNr[];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_HEADER_SIZE(n) (12+(n)) #define UVC_DT_HEADER_SIZE(n) (12+(n))
...@@ -209,57 +209,57 @@ struct uvc_header_descriptor { ...@@ -209,57 +209,57 @@ struct uvc_header_descriptor {
#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ #define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
struct UVC_HEADER_DESCRIPTOR(n) { \ struct UVC_HEADER_DESCRIPTOR(n) { \
__u8 bLength; \ __u8 bLength; \
__u8 bDescriptorType; \ __u8 bDescriptorType; \
__u8 bDescriptorSubType; \ __u8 bDescriptorSubType; \
__u16 bcdUVC; \ __le16 bcdUVC; \
__u16 wTotalLength; \ __le16 wTotalLength; \
__u32 dwClockFrequency; \ __le32 dwClockFrequency; \
__u8 bInCollection; \ __u8 bInCollection; \
__u8 baInterfaceNr[n]; \ __u8 baInterfaceNr[n]; \
} __attribute__ ((packed)) } __attribute__ ((packed))
/* 3.7.2.1. Input Terminal Descriptor */ /* 3.7.2.1. Input Terminal Descriptor */
struct uvc_input_terminal_descriptor { struct uvc_input_terminal_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bTerminalID; __u8 bTerminalID;
__u16 wTerminalType; __le16 wTerminalType;
__u8 bAssocTerminal; __u8 bAssocTerminal;
__u8 iTerminal; __u8 iTerminal;
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_INPUT_TERMINAL_SIZE 8 #define UVC_DT_INPUT_TERMINAL_SIZE 8
/* 3.7.2.2. Output Terminal Descriptor */ /* 3.7.2.2. Output Terminal Descriptor */
struct uvc_output_terminal_descriptor { struct uvc_output_terminal_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bTerminalID; __u8 bTerminalID;
__u16 wTerminalType; __le16 wTerminalType;
__u8 bAssocTerminal; __u8 bAssocTerminal;
__u8 bSourceID; __u8 bSourceID;
__u8 iTerminal; __u8 iTerminal;
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_OUTPUT_TERMINAL_SIZE 9 #define UVC_DT_OUTPUT_TERMINAL_SIZE 9
/* 3.7.2.3. Camera Terminal Descriptor */ /* 3.7.2.3. Camera Terminal Descriptor */
struct uvc_camera_terminal_descriptor { struct uvc_camera_terminal_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bTerminalID; __u8 bTerminalID;
__u16 wTerminalType; __le16 wTerminalType;
__u8 bAssocTerminal; __u8 bAssocTerminal;
__u8 iTerminal; __u8 iTerminal;
__u16 wObjectiveFocalLengthMin; __le16 wObjectiveFocalLengthMin;
__u16 wObjectiveFocalLengthMax; __le16 wObjectiveFocalLengthMax;
__u16 wOcularFocalLength; __le16 wOcularFocalLength;
__u8 bControlSize; __u8 bControlSize;
__u8 bmControls[3]; __u8 bmControls[3];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) #define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
...@@ -293,15 +293,15 @@ struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ ...@@ -293,15 +293,15 @@ struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
/* 3.7.2.5. Processing Unit Descriptor */ /* 3.7.2.5. Processing Unit Descriptor */
struct uvc_processing_unit_descriptor { struct uvc_processing_unit_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bUnitID; __u8 bUnitID;
__u8 bSourceID; __u8 bSourceID;
__u16 wMaxMultiplier; __le16 wMaxMultiplier;
__u8 bControlSize; __u8 bControlSize;
__u8 bmControls[2]; __u8 bmControls[2];
__u8 iProcessing; __u8 iProcessing;
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) #define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
...@@ -343,29 +343,29 @@ struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ ...@@ -343,29 +343,29 @@ struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ /* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
struct uvc_control_endpoint_descriptor { struct uvc_control_endpoint_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u16 wMaxTransferSize; __le16 wMaxTransferSize;
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_CONTROL_ENDPOINT_SIZE 5 #define UVC_DT_CONTROL_ENDPOINT_SIZE 5
/* 3.9.2.1. Input Header Descriptor */ /* 3.9.2.1. Input Header Descriptor */
struct uvc_input_header_descriptor { struct uvc_input_header_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bNumFormats; __u8 bNumFormats;
__u16 wTotalLength; __le16 wTotalLength;
__u8 bEndpointAddress; __u8 bEndpointAddress;
__u8 bmInfo; __u8 bmInfo;
__u8 bTerminalLink; __u8 bTerminalLink;
__u8 bStillCaptureMethod; __u8 bStillCaptureMethod;
__u8 bTriggerSupport; __u8 bTriggerSupport;
__u8 bTriggerUsage; __u8 bTriggerUsage;
__u8 bControlSize; __u8 bControlSize;
__u8 bmaControls[]; __u8 bmaControls[];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) #define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
...@@ -375,32 +375,32 @@ struct uvc_input_header_descriptor { ...@@ -375,32 +375,32 @@ struct uvc_input_header_descriptor {
#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ #define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
__u8 bLength; \ __u8 bLength; \
__u8 bDescriptorType; \ __u8 bDescriptorType; \
__u8 bDescriptorSubType; \ __u8 bDescriptorSubType; \
__u8 bNumFormats; \ __u8 bNumFormats; \
__u16 wTotalLength; \ __le16 wTotalLength; \
__u8 bEndpointAddress; \ __u8 bEndpointAddress; \
__u8 bmInfo; \ __u8 bmInfo; \
__u8 bTerminalLink; \ __u8 bTerminalLink; \
__u8 bStillCaptureMethod; \ __u8 bStillCaptureMethod; \
__u8 bTriggerSupport; \ __u8 bTriggerSupport; \
__u8 bTriggerUsage; \ __u8 bTriggerUsage; \
__u8 bControlSize; \ __u8 bControlSize; \
__u8 bmaControls[p][n]; \ __u8 bmaControls[p][n]; \
} __attribute__ ((packed)) } __attribute__ ((packed))
/* 3.9.2.2. Output Header Descriptor */ /* 3.9.2.2. Output Header Descriptor */
struct uvc_output_header_descriptor { struct uvc_output_header_descriptor {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bNumFormats; __u8 bNumFormats;
__u16 wTotalLength; __le16 wTotalLength;
__u8 bEndpointAddress; __u8 bEndpointAddress;
__u8 bTerminalLink; __u8 bTerminalLink;
__u8 bControlSize; __u8 bControlSize;
__u8 bmaControls[]; __u8 bmaControls[];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) #define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
...@@ -410,15 +410,15 @@ struct uvc_output_header_descriptor { ...@@ -410,15 +410,15 @@ struct uvc_output_header_descriptor {
#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ #define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
__u8 bLength; \ __u8 bLength; \
__u8 bDescriptorType; \ __u8 bDescriptorType; \
__u8 bDescriptorSubType; \ __u8 bDescriptorSubType; \
__u8 bNumFormats; \ __u8 bNumFormats; \
__u16 wTotalLength; \ __le16 wTotalLength; \
__u8 bEndpointAddress; \ __u8 bEndpointAddress; \
__u8 bTerminalLink; \ __u8 bTerminalLink; \
__u8 bControlSize; \ __u8 bControlSize; \
__u8 bmaControls[p][n]; \ __u8 bmaControls[p][n]; \
} __attribute__ ((packed)) } __attribute__ ((packed))
/* 3.9.2.6. Color matching descriptor */ /* 3.9.2.6. Color matching descriptor */
...@@ -473,19 +473,19 @@ struct uvc_format_uncompressed { ...@@ -473,19 +473,19 @@ struct uvc_format_uncompressed {
/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ /* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
struct uvc_frame_uncompressed { struct uvc_frame_uncompressed {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bFrameIndex; __u8 bFrameIndex;
__u8 bmCapabilities; __u8 bmCapabilities;
__u16 wWidth; __le16 wWidth;
__u16 wHeight; __le16 wHeight;
__u32 dwMinBitRate; __le32 dwMinBitRate;
__u32 dwMaxBitRate; __le32 dwMaxBitRate;
__u32 dwMaxVideoFrameBufferSize; __le32 dwMaxVideoFrameBufferSize;
__u32 dwDefaultFrameInterval; __le32 dwDefaultFrameInterval;
__u8 bFrameIntervalType; __u8 bFrameIntervalType;
__u32 dwFrameInterval[]; __le32 dwFrameInterval[];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) #define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
...@@ -495,19 +495,19 @@ struct uvc_frame_uncompressed { ...@@ -495,19 +495,19 @@ struct uvc_frame_uncompressed {
#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ #define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
struct UVC_FRAME_UNCOMPRESSED(n) { \ struct UVC_FRAME_UNCOMPRESSED(n) { \
__u8 bLength; \ __u8 bLength; \
__u8 bDescriptorType; \ __u8 bDescriptorType; \
__u8 bDescriptorSubType; \ __u8 bDescriptorSubType; \
__u8 bFrameIndex; \ __u8 bFrameIndex; \
__u8 bmCapabilities; \ __u8 bmCapabilities; \
__u16 wWidth; \ __le16 wWidth; \
__u16 wHeight; \ __le16 wHeight; \
__u32 dwMinBitRate; \ __le32 dwMinBitRate; \
__u32 dwMaxBitRate; \ __le32 dwMaxBitRate; \
__u32 dwMaxVideoFrameBufferSize; \ __le32 dwMaxVideoFrameBufferSize; \
__u32 dwDefaultFrameInterval; \ __le32 dwDefaultFrameInterval; \
__u8 bFrameIntervalType; \ __u8 bFrameIntervalType; \
__u32 dwFrameInterval[n]; \ __le32 dwFrameInterval[n]; \
} __attribute__ ((packed)) } __attribute__ ((packed))
/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ /* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
...@@ -529,19 +529,19 @@ struct uvc_format_mjpeg { ...@@ -529,19 +529,19 @@ struct uvc_format_mjpeg {
/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ /* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
struct uvc_frame_mjpeg { struct uvc_frame_mjpeg {
__u8 bLength; __u8 bLength;
__u8 bDescriptorType; __u8 bDescriptorType;
__u8 bDescriptorSubType; __u8 bDescriptorSubType;
__u8 bFrameIndex; __u8 bFrameIndex;
__u8 bmCapabilities; __u8 bmCapabilities;
__u16 wWidth; __le16 wWidth;
__u16 wHeight; __le16 wHeight;
__u32 dwMinBitRate; __le32 dwMinBitRate;
__u32 dwMaxBitRate; __le32 dwMaxBitRate;
__u32 dwMaxVideoFrameBufferSize; __le32 dwMaxVideoFrameBufferSize;
__u32 dwDefaultFrameInterval; __le32 dwDefaultFrameInterval;
__u8 bFrameIntervalType; __u8 bFrameIntervalType;
__u32 dwFrameInterval[]; __le32 dwFrameInterval[];
} __attribute__((__packed__)); } __attribute__((__packed__));
#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) #define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
...@@ -551,19 +551,19 @@ struct uvc_frame_mjpeg { ...@@ -551,19 +551,19 @@ struct uvc_frame_mjpeg {
#define DECLARE_UVC_FRAME_MJPEG(n) \ #define DECLARE_UVC_FRAME_MJPEG(n) \
struct UVC_FRAME_MJPEG(n) { \ struct UVC_FRAME_MJPEG(n) { \
__u8 bLength; \ __u8 bLength; \
__u8 bDescriptorType; \ __u8 bDescriptorType; \
__u8 bDescriptorSubType; \ __u8 bDescriptorSubType; \
__u8 bFrameIndex; \ __u8 bFrameIndex; \
__u8 bmCapabilities; \ __u8 bmCapabilities; \
__u16 wWidth; \ __le16 wWidth; \
__u16 wHeight; \ __le16 wHeight; \
__u32 dwMinBitRate; \ __le32 dwMinBitRate; \
__u32 dwMaxBitRate; \ __le32 dwMaxBitRate; \
__u32 dwMaxVideoFrameBufferSize; \ __le32 dwMaxVideoFrameBufferSize; \
__u32 dwDefaultFrameInterval; \ __le32 dwDefaultFrameInterval; \
__u8 bFrameIntervalType; \ __u8 bFrameIntervalType; \
__u32 dwFrameInterval[n]; \ __le32 dwFrameInterval[n]; \
} __attribute__ ((packed)) } __attribute__ ((packed))
#endif /* __LINUX_USB_VIDEO_H */ #endif /* __LINUX_USB_VIDEO_H */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment