From 571e148aaec20c26c308d6611cdb1f34ec81ff1e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 26 May 2018 20:58:19 +0300 Subject: configfs: Refactor ConfigFS parsing code Move all attribute parsing to a top-level configfs_parse_uvc() function, and split control and streaming interface attributes to two separate helper functions. In addition to making the code more structured, it will also allow supporting multiple streaming interfaces in a single UVC function in the future. The uvc_function_config structure is similarly reorganized in a hierarchical representation of the configuration. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- configfs.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++------------- configfs.h | 53 +++++++++++++++++++++++------ uvc-gadget.c | 4 +-- 3 files changed, 128 insertions(+), 37 deletions(-) diff --git a/configfs.c b/configfs.c index 3b98f55..38954d5 100644 --- a/configfs.c +++ b/configfs.c @@ -199,12 +199,21 @@ static char *udc_find_video_device(const char *udc, const char *function) */ static const struct uvc_function_config g_webcam_config = { - .control_interface = 0, - .streaming_interface = 1, - - .streaming_interval = 1, - .streaming_maxburst = 0, - .streaming_maxpacket = 1024, + .control = { + .intf = { + .bInterfaceNumber = 0, + }, + }, + .streaming = { + .intf = { + .bInterfaceNumber = 1, + }, + .ep = { + .bInterval = 1, + .bMaxBurst = 0, + .wMaxPacketSize = 1024, + }, + }, }; static int parse_legacy_g_webcam(const char *udc, @@ -269,16 +278,74 @@ void configfs_free_uvc_function(struct uvc_function_config *fc) free(fc); } -static int configfs_parse_interfaces(const char *fpath, - struct uvc_function_config *fc) +#define configfs_parse_child(parent, child, cfg, parse) \ +({ \ + char *__path; \ + int __ret; \ + \ + __path = path_join((parent), (child)); \ + if (__path) { \ + __ret = parse(__path, (cfg)); \ + free(__path); \ + } else { \ + __ret = -ENOMEM; \ + } \ + \ + __ret; \ +}) + +static int configfs_parse_interface(const char *path, + struct uvc_function_config_interface *cfg) { int ret; - ret = attribute_read_uint(fpath, "control/bInterfaceNumber", - &fc->control_interface); + ret = attribute_read_uint(path, "bInterfaceNumber", + &cfg->bInterfaceNumber); + + return ret; +} + +static int configfs_parse_control(const char *path, + struct uvc_function_config_control *cfg) +{ + int ret; + + ret = configfs_parse_interface(path, &cfg->intf); + + return ret; +} + +static int configfs_parse_streaming(const char *path, + struct uvc_function_config_streaming *cfg) +{ + int ret; + + ret = configfs_parse_interface(path, &cfg->intf); + + return ret; +} + +static int configfs_parse_uvc(const char *fpath, + struct uvc_function_config *fc) +{ + int ret = 0; - ret = ret ? : attribute_read_uint(fpath, "streaming/bInterfaceNumber", - &fc->streaming_interface); + ret = ret ? : configfs_parse_child(fpath, "control", &fc->control, + configfs_parse_control); + ret = ret ? : configfs_parse_child(fpath, "streaming", &fc->streaming, + configfs_parse_streaming); + + /* + * These parameters should be part of the streaming interface in + * ConfigFS, but for legacy reasons they are located directly in the + * function directory. + */ + ret = ret ? : attribute_read_uint(fpath, "streaming_interval", + &fc->streaming.ep.bInterval); + ret = ret ? : attribute_read_uint(fpath, "streaming_maxburst", + &fc->streaming.ep.bMaxBurst); + ret = ret ? : attribute_read_uint(fpath, "streaming_maxpacket", + &fc->streaming.ep.wMaxPacketSize); return ret; } @@ -337,21 +404,14 @@ struct uvc_function_config *configfs_parse_uvc_function(const char *function) fc->udc = attribute_read_str(fpath, "../../UDC"); fc->video = udc_find_video_device(fc->udc, function); - if (!fc->video) + if (!fc->video) { ret = -ENODEV; + goto done; + } - /* Identify interface numbers. */ - ret = ret ? : configfs_parse_interfaces(fpath, fc); - - ret = ret ? : attribute_read_uint(fpath, "streaming_interval", - &fc->streaming_interval); - - ret = ret ? : attribute_read_uint(fpath, "streaming_maxburst", - &fc->streaming_maxburst); - - ret = ret ? : attribute_read_uint(fpath, "streaming_maxpacket", - &fc->streaming_maxpacket); + ret = configfs_parse_uvc(fpath, fc); +done: if (ret) { configfs_free_uvc_function(fc); fc = NULL; diff --git a/configfs.h b/configfs.h index b5c7480..9f7f377 100644 --- a/configfs.h +++ b/configfs.h @@ -10,26 +10,57 @@ #ifndef __CONFIGFS_H__ #define __CONFIGFS_H__ +/* + * struct uvc_function_config_endpoint - Endpoint parameters + * @bInterval: Transfer interval (interrupt and isochronous only) + * @bMaxBurst: Transfer burst size (super-speed only) + * @wMaxPacketSize: Maximum packet size (including the multiplier) + */ +struct uvc_function_config_endpoint { + unsigned int bInterval; + unsigned int bMaxBurst; + unsigned int wMaxPacketSize; +}; + +/* + * struct uvc_function_config_interface - Interface parameters + * @bInterfaceNumber: Interface number + */ +struct uvc_function_config_interface { + unsigned int bInterfaceNumber; +}; + +/* + * struct uvc_function_config_control - Control interface parameters + * @intf: Generic interface parameters + */ +struct uvc_function_config_control { + struct uvc_function_config_interface intf; +}; + +/* + * struct uvc_function_config_streaming - Streaming interface parameters + * @intf: Generic interface parameters + * @ep: Endpoint parameters + */ +struct uvc_function_config_streaming { + struct uvc_function_config_interface intf; + struct uvc_function_config_endpoint ep; +}; + /* * struct uvc_function_config - UVC function configuration parameters * @video: Full path to the video device node * @udc: UDC name - * @control_interface: Control interface number - * @streaming_interface: Streaming interface number - * @streaming_interval: Isochronous interval for the streaming endpoint - * @streaming_maxburts: Isochronous maximum burst for the streaming endpoint - * @streaming_maxpacket: Isochronous maximum packets for the streaming endpoint + * @control: Control interface configuration + * @streaming: Streaming interface configuration */ struct uvc_function_config { char *video; char *udc; - unsigned int control_interface; - unsigned int streaming_interface; - - unsigned int streaming_interval; - unsigned int streaming_maxburst; - unsigned int streaming_maxpacket; + struct uvc_function_config_control control; + struct uvc_function_config_streaming streaming; }; struct uvc_function_config *configfs_parse_uvc_function(const char *function); diff --git a/uvc-gadget.c b/uvc-gadget.c index 96f9996..57dc097 100644 --- a/uvc-gadget.c +++ b/uvc-gadget.c @@ -414,9 +414,9 @@ uvc_events_process_class(struct uvc_device *dev, if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE) return; - if (interface == dev->fc->control_interface) + if (interface == dev->fc->control.intf.bInterfaceNumber) uvc_events_process_control(dev, ctrl->bRequest, ctrl->wValue >> 8, resp); - else if (interface == dev->fc->streaming_interface) + else if (interface == dev->fc->streaming.intf.bInterfaceNumber) uvc_events_process_streaming(dev, ctrl->bRequest, ctrl->wValue >> 8, resp); } -- cgit v1.2.3