blob: fa8d2e1f54baccce98b4ac6aac3ce85556d753d6 [file] [log] [blame]
Greg Kroah-Hartman5fd54ac2017-11-03 11:28:30 +01001// SPDX-License-Identifier: GPL-2.0
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002/*
3 * uvc_configfs.c
4 *
5 * Configfs support for the uvc function.
6 *
7 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
8 * http://www.samsung.com
9 *
10 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010011 */
12#include "u_uvc.h"
13#include "uvc_configfs.h"
14
Laurent Pinchartf7d81092018-05-24 17:49:34 +030015/* -----------------------------------------------------------------------------
16 * Global Utility Structures and Macros
17 */
18
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010019#define UVCG_STREAMING_CONTROL_SIZE 1
20
Christoph Hellwig76e0da32015-10-03 15:32:39 +020021#define UVC_ATTR(prefix, cname, aname) \
22static struct configfs_attribute prefix##attr_##cname = { \
23 .ca_name = __stringify(aname), \
Mian Yousaf Kaukab27681ab2015-11-28 18:35:44 +010024 .ca_mode = S_IRUGO | S_IWUGO, \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020025 .ca_owner = THIS_MODULE, \
26 .show = prefix##cname##_show, \
27 .store = prefix##cname##_store, \
28}
29
30#define UVC_ATTR_RO(prefix, cname, aname) \
31static struct configfs_attribute prefix##attr_##cname = { \
32 .ca_name = __stringify(aname), \
33 .ca_mode = S_IRUGO, \
34 .ca_owner = THIS_MODULE, \
35 .show = prefix##cname##_show, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010036}
37
Laurent Pinchartc728eff2018-05-23 18:49:43 +030038static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
39{
40 return container_of(to_config_group(item), struct f_uvc_opts,
41 func_inst.group);
42}
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010043
Laurent Pinchartefbf0af2018-05-24 17:49:34 +030044struct uvcg_config_group_type {
45 struct config_item_type type;
46 const char *name;
47 const struct uvcg_config_group_type **children;
48 int (*create_children)(struct config_group *group);
49};
50
51static void uvcg_config_item_release(struct config_item *item)
52{
53 struct config_group *group = to_config_group(item);
54
55 kfree(group);
56}
57
58static struct configfs_item_operations uvcg_config_item_ops = {
59 .release = uvcg_config_item_release,
60};
61
62static int uvcg_config_create_group(struct config_group *parent,
63 const struct uvcg_config_group_type *type);
64
65static int uvcg_config_create_children(struct config_group *group,
66 const struct uvcg_config_group_type *type)
67{
68 const struct uvcg_config_group_type **child;
69 int ret;
70
71 if (type->create_children)
72 return type->create_children(group);
73
74 for (child = type->children; child && *child; ++child) {
75 ret = uvcg_config_create_group(group, *child);
76 if (ret < 0)
77 return ret;
78 }
79
80 return 0;
81}
82
83static int uvcg_config_create_group(struct config_group *parent,
84 const struct uvcg_config_group_type *type)
85{
86 struct config_group *group;
87
88 group = kzalloc(sizeof(*group), GFP_KERNEL);
89 if (!group)
90 return -ENOMEM;
91
92 config_group_init_type_name(group, type->name, &type->type);
93 configfs_add_default_group(group, parent);
94
95 return uvcg_config_create_children(group, type);
96}
97
98static void uvcg_config_remove_children(struct config_group *group)
99{
100 struct config_group *child, *n;
101
102 list_for_each_entry_safe(child, n, &group->default_groups, group_entry) {
103 list_del(&child->group_entry);
104 uvcg_config_remove_children(child);
105 config_item_put(&child->cg_item);
106 }
107}
108
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300109/* -----------------------------------------------------------------------------
110 * control/header/<NAME>
111 * control/header
112 */
113
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100114DECLARE_UVC_HEADER_DESCRIPTOR(1);
115
116struct uvcg_control_header {
117 struct config_item item;
118 struct UVC_HEADER_DESCRIPTOR(1) desc;
119 unsigned linked;
120};
121
kbuild test robotf093a2d2015-01-13 16:55:38 +0800122static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100123{
124 return container_of(item, struct uvcg_control_header, item);
125}
126
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100127#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
128static ssize_t uvcg_control_header_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200129 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100130{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200131 struct uvcg_control_header *ch = to_uvcg_control_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100132 struct f_uvc_opts *opts; \
133 struct config_item *opts_item; \
134 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
135 int result; \
136 \
137 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
138 \
139 opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
140 opts = to_f_uvc_opts(opts_item); \
141 \
142 mutex_lock(&opts->lock); \
143 result = sprintf(page, "%d\n", conv(ch->desc.aname)); \
144 mutex_unlock(&opts->lock); \
145 \
146 mutex_unlock(su_mutex); \
147 return result; \
148} \
149 \
150static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200151uvcg_control_header_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100152 const char *page, size_t len) \
153{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200154 struct uvcg_control_header *ch = to_uvcg_control_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100155 struct f_uvc_opts *opts; \
156 struct config_item *opts_item; \
157 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
158 int ret; \
159 uxx num; \
160 \
161 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
162 \
163 opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
164 opts = to_f_uvc_opts(opts_item); \
165 \
166 mutex_lock(&opts->lock); \
167 if (ch->linked || opts->refcnt) { \
168 ret = -EBUSY; \
169 goto end; \
170 } \
171 \
172 ret = str2u(page, 0, &num); \
173 if (ret) \
174 goto end; \
175 \
176 if (num > limit) { \
177 ret = -EINVAL; \
178 goto end; \
179 } \
180 ch->desc.aname = vnoc(num); \
181 ret = len; \
182end: \
183 mutex_unlock(&opts->lock); \
184 mutex_unlock(su_mutex); \
185 return ret; \
186} \
187 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200188UVC_ATTR(uvcg_control_header_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100189
190UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
191 0xffff);
192
193UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
194 u32, cpu_to_le32, 0x7fffffff);
195
196#undef UVCG_CTRL_HDR_ATTR
197
198static struct configfs_attribute *uvcg_control_header_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200199 &uvcg_control_header_attr_bcd_uvc,
200 &uvcg_control_header_attr_dw_clock_frequency,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100201 NULL,
202};
203
Bhumika Goyal97363902017-10-16 17:18:41 +0200204static const struct config_item_type uvcg_control_header_type = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300205 .ct_item_ops = &uvcg_config_item_ops,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100206 .ct_attrs = uvcg_control_header_attrs,
207 .ct_owner = THIS_MODULE,
208};
209
210static struct config_item *uvcg_control_header_make(struct config_group *group,
211 const char *name)
212{
213 struct uvcg_control_header *h;
214
215 h = kzalloc(sizeof(*h), GFP_KERNEL);
216 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +0300217 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100218
219 h->desc.bLength = UVC_DT_HEADER_SIZE(1);
220 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
221 h->desc.bDescriptorSubType = UVC_VC_HEADER;
222 h->desc.bcdUVC = cpu_to_le16(0x0100);
223 h->desc.dwClockFrequency = cpu_to_le32(48000000);
224
225 config_item_init_type_name(&h->item, name, &uvcg_control_header_type);
226
227 return &h->item;
228}
229
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100230static struct configfs_group_operations uvcg_control_header_grp_ops = {
231 .make_item = uvcg_control_header_make,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100232};
233
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300234static const struct uvcg_config_group_type uvcg_control_header_grp_type = {
235 .type = {
236 .ct_item_ops = &uvcg_config_item_ops,
237 .ct_group_ops = &uvcg_control_header_grp_ops,
238 .ct_owner = THIS_MODULE,
239 },
240 .name = "header",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100241};
242
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300243/* -----------------------------------------------------------------------------
244 * control/processing/default
245 */
246
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100247#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \
248static ssize_t uvcg_default_processing_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200249 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100250{ \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300251 struct config_group *group = to_config_group(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100252 struct f_uvc_opts *opts; \
253 struct config_item *opts_item; \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300254 struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100255 struct uvc_processing_unit_descriptor *pd; \
256 int result; \
257 \
258 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
259 \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300260 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100261 opts = to_f_uvc_opts(opts_item); \
262 pd = &opts->uvc_processing; \
263 \
264 mutex_lock(&opts->lock); \
265 result = sprintf(page, "%d\n", conv(pd->aname)); \
266 mutex_unlock(&opts->lock); \
267 \
268 mutex_unlock(su_mutex); \
269 return result; \
270} \
271 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200272UVC_ATTR_RO(uvcg_default_processing_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100273
274#define identity_conv(x) (x)
275
276UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv);
277UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv);
278UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
279UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
280
281#undef identity_conv
282
283#undef UVCG_DEFAULT_PROCESSING_ATTR
284
285static ssize_t uvcg_default_processing_bm_controls_show(
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200286 struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100287{
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300288 struct config_group *group = to_config_group(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100289 struct f_uvc_opts *opts;
290 struct config_item *opts_item;
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300291 struct mutex *su_mutex = &group->cg_subsys->su_mutex;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100292 struct uvc_processing_unit_descriptor *pd;
293 int result, i;
294 char *pg = page;
295
296 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
297
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300298 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100299 opts = to_f_uvc_opts(opts_item);
300 pd = &opts->uvc_processing;
301
302 mutex_lock(&opts->lock);
303 for (result = 0, i = 0; i < pd->bControlSize; ++i) {
304 result += sprintf(pg, "%d\n", pd->bmControls[i]);
305 pg = page + result;
306 }
307 mutex_unlock(&opts->lock);
308
309 mutex_unlock(su_mutex);
310
311 return result;
312}
313
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200314UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100315
316static struct configfs_attribute *uvcg_default_processing_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200317 &uvcg_default_processing_attr_b_unit_id,
318 &uvcg_default_processing_attr_b_source_id,
319 &uvcg_default_processing_attr_w_max_multiplier,
320 &uvcg_default_processing_attr_bm_controls,
321 &uvcg_default_processing_attr_i_processing,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100322 NULL,
323};
324
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300325static const struct uvcg_config_group_type uvcg_default_processing_type = {
326 .type = {
327 .ct_item_ops = &uvcg_config_item_ops,
328 .ct_attrs = uvcg_default_processing_attrs,
329 .ct_owner = THIS_MODULE,
330 },
331 .name = "default",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100332};
333
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300334/* -----------------------------------------------------------------------------
335 * control/processing
336 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100337
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300338static const struct uvcg_config_group_type uvcg_processing_grp_type = {
339 .type = {
340 .ct_item_ops = &uvcg_config_item_ops,
341 .ct_owner = THIS_MODULE,
342 },
343 .name = "processing",
344 .children = (const struct uvcg_config_group_type*[]) {
345 &uvcg_default_processing_type,
346 NULL,
347 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100348};
349
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300350/* -----------------------------------------------------------------------------
351 * control/terminal/camera/default
352 */
353
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100354#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \
355static ssize_t uvcg_default_camera_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200356 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100357{ \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300358 struct config_group *group = to_config_group(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100359 struct f_uvc_opts *opts; \
360 struct config_item *opts_item; \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300361 struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100362 struct uvc_camera_terminal_descriptor *cd; \
363 int result; \
364 \
365 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
366 \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300367 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100368 ci_parent; \
369 opts = to_f_uvc_opts(opts_item); \
370 cd = &opts->uvc_camera_terminal; \
371 \
372 mutex_lock(&opts->lock); \
373 result = sprintf(page, "%d\n", conv(cd->aname)); \
374 mutex_unlock(&opts->lock); \
375 \
376 mutex_unlock(su_mutex); \
377 \
378 return result; \
379} \
380 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200381UVC_ATTR_RO(uvcg_default_camera_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100382
383#define identity_conv(x) (x)
384
385UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv);
386UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
387UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
388UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
389UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
390 le16_to_cpu);
391UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
392 le16_to_cpu);
393UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
394 le16_to_cpu);
395
396#undef identity_conv
397
398#undef UVCG_DEFAULT_CAMERA_ATTR
399
400static ssize_t uvcg_default_camera_bm_controls_show(
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200401 struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100402{
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300403 struct config_group *group = to_config_group(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100404 struct f_uvc_opts *opts;
405 struct config_item *opts_item;
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300406 struct mutex *su_mutex = &group->cg_subsys->su_mutex;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100407 struct uvc_camera_terminal_descriptor *cd;
408 int result, i;
409 char *pg = page;
410
411 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
412
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300413 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent->
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100414 ci_parent;
415 opts = to_f_uvc_opts(opts_item);
416 cd = &opts->uvc_camera_terminal;
417
418 mutex_lock(&opts->lock);
419 for (result = 0, i = 0; i < cd->bControlSize; ++i) {
420 result += sprintf(pg, "%d\n", cd->bmControls[i]);
421 pg = page + result;
422 }
423 mutex_unlock(&opts->lock);
424
425 mutex_unlock(su_mutex);
426 return result;
427}
428
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200429UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100430
431static struct configfs_attribute *uvcg_default_camera_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200432 &uvcg_default_camera_attr_b_terminal_id,
433 &uvcg_default_camera_attr_w_terminal_type,
434 &uvcg_default_camera_attr_b_assoc_terminal,
435 &uvcg_default_camera_attr_i_terminal,
436 &uvcg_default_camera_attr_w_objective_focal_length_min,
437 &uvcg_default_camera_attr_w_objective_focal_length_max,
438 &uvcg_default_camera_attr_w_ocular_focal_length,
439 &uvcg_default_camera_attr_bm_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100440 NULL,
441};
442
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300443static const struct uvcg_config_group_type uvcg_default_camera_type = {
444 .type = {
445 .ct_item_ops = &uvcg_config_item_ops,
446 .ct_attrs = uvcg_default_camera_attrs,
447 .ct_owner = THIS_MODULE,
448 },
449 .name = "default",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100450};
451
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300452/* -----------------------------------------------------------------------------
453 * control/terminal/camera
454 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100455
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300456static const struct uvcg_config_group_type uvcg_camera_grp_type = {
457 .type = {
458 .ct_item_ops = &uvcg_config_item_ops,
459 .ct_owner = THIS_MODULE,
460 },
461 .name = "camera",
462 .children = (const struct uvcg_config_group_type*[]) {
463 &uvcg_default_camera_type,
464 NULL,
465 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100466};
467
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300468/* -----------------------------------------------------------------------------
469 * control/terminal/output/default
470 */
471
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100472#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \
473static ssize_t uvcg_default_output_##cname##_show( \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300474 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100475{ \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300476 struct config_group *group = to_config_group(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100477 struct f_uvc_opts *opts; \
478 struct config_item *opts_item; \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300479 struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100480 struct uvc_output_terminal_descriptor *cd; \
481 int result; \
482 \
483 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
484 \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +0300485 opts_item = group->cg_item.ci_parent->ci_parent-> \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100486 ci_parent->ci_parent; \
487 opts = to_f_uvc_opts(opts_item); \
488 cd = &opts->uvc_output_terminal; \
489 \
490 mutex_lock(&opts->lock); \
491 result = sprintf(page, "%d\n", conv(cd->aname)); \
492 mutex_unlock(&opts->lock); \
493 \
494 mutex_unlock(su_mutex); \
495 \
496 return result; \
497} \
498 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200499UVC_ATTR_RO(uvcg_default_output_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100500
501#define identity_conv(x) (x)
502
503UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv);
504UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
505UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
506UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
507UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
508
509#undef identity_conv
510
511#undef UVCG_DEFAULT_OUTPUT_ATTR
512
513static struct configfs_attribute *uvcg_default_output_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200514 &uvcg_default_output_attr_b_terminal_id,
515 &uvcg_default_output_attr_w_terminal_type,
516 &uvcg_default_output_attr_b_assoc_terminal,
517 &uvcg_default_output_attr_b_source_id,
518 &uvcg_default_output_attr_i_terminal,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100519 NULL,
520};
521
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300522static const struct uvcg_config_group_type uvcg_default_output_type = {
523 .type = {
524 .ct_item_ops = &uvcg_config_item_ops,
525 .ct_attrs = uvcg_default_output_attrs,
526 .ct_owner = THIS_MODULE,
527 },
528 .name = "default",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100529};
530
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300531/* -----------------------------------------------------------------------------
532 * control/terminal/output
533 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100534
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300535static const struct uvcg_config_group_type uvcg_output_grp_type = {
536 .type = {
537 .ct_item_ops = &uvcg_config_item_ops,
538 .ct_owner = THIS_MODULE,
539 },
540 .name = "output",
541 .children = (const struct uvcg_config_group_type*[]) {
542 &uvcg_default_output_type,
543 NULL,
544 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100545};
546
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300547/* -----------------------------------------------------------------------------
548 * control/terminal
549 */
550
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300551static const struct uvcg_config_group_type uvcg_terminal_grp_type = {
552 .type = {
553 .ct_item_ops = &uvcg_config_item_ops,
554 .ct_owner = THIS_MODULE,
555 },
556 .name = "terminal",
557 .children = (const struct uvcg_config_group_type*[]) {
558 &uvcg_camera_grp_type,
559 &uvcg_output_grp_type,
560 NULL,
561 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100562};
563
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300564/* -----------------------------------------------------------------------------
565 * control/class/{fs|ss}
566 */
567
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300568struct uvcg_control_class_group {
569 struct config_group group;
570 const char *name;
571};
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100572
573static inline struct uvc_descriptor_header
574**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
575{
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300576 struct uvcg_control_class_group *group =
577 container_of(i, struct uvcg_control_class_group,
578 group.cg_item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100579
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300580 if (!strcmp(group->name, "fs"))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100581 return o->uvc_fs_control_cls;
582
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300583 if (!strcmp(group->name, "ss"))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100584 return o->uvc_ss_control_cls;
585
586 return NULL;
587}
588
589static int uvcg_control_class_allow_link(struct config_item *src,
590 struct config_item *target)
591{
592 struct config_item *control, *header;
593 struct f_uvc_opts *opts;
594 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
595 struct uvc_descriptor_header **class_array;
596 struct uvcg_control_header *target_hdr;
597 int ret = -EINVAL;
598
599 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
600
601 control = src->ci_parent->ci_parent;
602 header = config_group_find_item(to_config_group(control), "header");
603 if (!header || target->ci_parent != header)
604 goto out;
605
606 opts = to_f_uvc_opts(control->ci_parent);
607
608 mutex_lock(&opts->lock);
609
610 class_array = uvcg_get_ctl_class_arr(src, opts);
611 if (!class_array)
612 goto unlock;
613 if (opts->refcnt || class_array[0]) {
614 ret = -EBUSY;
615 goto unlock;
616 }
617
618 target_hdr = to_uvcg_control_header(target);
619 ++target_hdr->linked;
620 class_array[0] = (struct uvc_descriptor_header *)&target_hdr->desc;
621 ret = 0;
622
623unlock:
624 mutex_unlock(&opts->lock);
625out:
Laurent Pinchart86f3dae2018-08-02 00:14:00 +0300626 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100627 mutex_unlock(su_mutex);
628 return ret;
629}
630
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100631static void uvcg_control_class_drop_link(struct config_item *src,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100632 struct config_item *target)
633{
634 struct config_item *control, *header;
635 struct f_uvc_opts *opts;
636 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
637 struct uvc_descriptor_header **class_array;
638 struct uvcg_control_header *target_hdr;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100639
640 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
641
642 control = src->ci_parent->ci_parent;
643 header = config_group_find_item(to_config_group(control), "header");
644 if (!header || target->ci_parent != header)
645 goto out;
646
647 opts = to_f_uvc_opts(control->ci_parent);
648
649 mutex_lock(&opts->lock);
650
651 class_array = uvcg_get_ctl_class_arr(src, opts);
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100652 if (!class_array || opts->refcnt)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100653 goto unlock;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100654
655 target_hdr = to_uvcg_control_header(target);
656 --target_hdr->linked;
657 class_array[0] = NULL;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100658
659unlock:
660 mutex_unlock(&opts->lock);
661out:
Laurent Pinchart86f3dae2018-08-02 00:14:00 +0300662 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100663 mutex_unlock(su_mutex);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100664}
665
666static struct configfs_item_operations uvcg_control_class_item_ops = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300667 .release = uvcg_config_item_release,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100668 .allow_link = uvcg_control_class_allow_link,
669 .drop_link = uvcg_control_class_drop_link,
670};
671
Bhumika Goyal97363902017-10-16 17:18:41 +0200672static const struct config_item_type uvcg_control_class_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100673 .ct_item_ops = &uvcg_control_class_item_ops,
674 .ct_owner = THIS_MODULE,
675};
676
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300677/* -----------------------------------------------------------------------------
678 * control/class
679 */
680
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300681static int uvcg_control_class_create_children(struct config_group *parent)
682{
683 static const char * const names[] = { "fs", "ss" };
684 unsigned int i;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100685
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300686 for (i = 0; i < ARRAY_SIZE(names); ++i) {
687 struct uvcg_control_class_group *group;
688
689 group = kzalloc(sizeof(*group), GFP_KERNEL);
690 if (!group)
691 return -ENOMEM;
692
693 group->name = names[i];
694
695 config_group_init_type_name(&group->group, group->name,
696 &uvcg_control_class_type);
697 configfs_add_default_group(&group->group, parent);
698 }
699
700 return 0;
701}
702
703static const struct uvcg_config_group_type uvcg_control_class_grp_type = {
704 .type = {
705 .ct_item_ops = &uvcg_config_item_ops,
706 .ct_owner = THIS_MODULE,
707 },
708 .name = "class",
709 .create_children = uvcg_control_class_create_children,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100710};
711
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300712/* -----------------------------------------------------------------------------
713 * control
714 */
715
Laurent Pinchartbf715442018-05-23 18:47:56 +0300716static ssize_t uvcg_default_control_b_interface_number_show(
717 struct config_item *item, char *page)
718{
719 struct config_group *group = to_config_group(item);
720 struct mutex *su_mutex = &group->cg_subsys->su_mutex;
721 struct config_item *opts_item;
722 struct f_uvc_opts *opts;
723 int result = 0;
724
725 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
726
727 opts_item = item->ci_parent;
728 opts = to_f_uvc_opts(opts_item);
729
730 mutex_lock(&opts->lock);
731 result += sprintf(page, "%u\n", opts->control_interface);
732 mutex_unlock(&opts->lock);
733
734 mutex_unlock(su_mutex);
735
736 return result;
737}
738
739UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber);
740
741static struct configfs_attribute *uvcg_default_control_attrs[] = {
742 &uvcg_default_control_attr_b_interface_number,
743 NULL,
744};
745
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300746static const struct uvcg_config_group_type uvcg_control_grp_type = {
747 .type = {
748 .ct_item_ops = &uvcg_config_item_ops,
Laurent Pinchartbf715442018-05-23 18:47:56 +0300749 .ct_attrs = uvcg_default_control_attrs,
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300750 .ct_owner = THIS_MODULE,
751 },
752 .name = "control",
753 .children = (const struct uvcg_config_group_type*[]) {
754 &uvcg_control_header_grp_type,
755 &uvcg_processing_grp_type,
756 &uvcg_terminal_grp_type,
757 &uvcg_control_class_grp_type,
758 NULL,
759 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100760};
761
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300762/* -----------------------------------------------------------------------------
763 * streaming/uncompressed
764 * streaming/mjpeg
765 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100766
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300767static const char * const uvcg_format_names[] = {
768 "uncompressed",
769 "mjpeg",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100770};
771
772enum uvcg_format_type {
773 UVCG_UNCOMPRESSED = 0,
774 UVCG_MJPEG,
775};
776
777struct uvcg_format {
778 struct config_group group;
779 enum uvcg_format_type type;
780 unsigned linked;
781 unsigned num_frames;
782 __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
783};
784
kbuild test robotf093a2d2015-01-13 16:55:38 +0800785static struct uvcg_format *to_uvcg_format(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100786{
787 return container_of(to_config_group(item), struct uvcg_format, group);
788}
789
790static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
791{
792 struct f_uvc_opts *opts;
793 struct config_item *opts_item;
794 struct mutex *su_mutex = &f->group.cg_subsys->su_mutex;
795 int result, i;
796 char *pg = page;
797
798 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
799
800 opts_item = f->group.cg_item.ci_parent->ci_parent->ci_parent;
801 opts = to_f_uvc_opts(opts_item);
802
803 mutex_lock(&opts->lock);
804 result = sprintf(pg, "0x");
805 pg += result;
806 for (i = 0; i < UVCG_STREAMING_CONTROL_SIZE; ++i) {
807 result += sprintf(pg, "%x\n", f->bmaControls[i]);
808 pg = page + result;
809 }
810 mutex_unlock(&opts->lock);
811
812 mutex_unlock(su_mutex);
813 return result;
814}
815
816static ssize_t uvcg_format_bma_controls_store(struct uvcg_format *ch,
817 const char *page, size_t len)
818{
819 struct f_uvc_opts *opts;
820 struct config_item *opts_item;
821 struct mutex *su_mutex = &ch->group.cg_subsys->su_mutex;
822 int ret = -EINVAL;
823
824 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
825
826 opts_item = ch->group.cg_item.ci_parent->ci_parent->ci_parent;
827 opts = to_f_uvc_opts(opts_item);
828
829 mutex_lock(&opts->lock);
830 if (ch->linked || opts->refcnt) {
831 ret = -EBUSY;
832 goto end;
833 }
834
835 if (len < 4 || *page != '0' ||
836 (*(page + 1) != 'x' && *(page + 1) != 'X'))
837 goto end;
838 ret = hex2bin(ch->bmaControls, page + 2, 1);
839 if (ret < 0)
840 goto end;
841 ret = len;
842end:
843 mutex_unlock(&opts->lock);
844 mutex_unlock(su_mutex);
845 return ret;
846}
847
848struct uvcg_format_ptr {
849 struct uvcg_format *fmt;
850 struct list_head entry;
851};
852
Laurent Pinchartf7d81092018-05-24 17:49:34 +0300853/* -----------------------------------------------------------------------------
854 * streaming/header/<NAME>
855 * streaming/header
856 */
857
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100858struct uvcg_streaming_header {
859 struct config_item item;
860 struct uvc_input_header_descriptor desc;
861 unsigned linked;
862 struct list_head formats;
863 unsigned num_fmt;
864};
865
kbuild test robotf093a2d2015-01-13 16:55:38 +0800866static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100867{
868 return container_of(item, struct uvcg_streaming_header, item);
869}
870
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100871static int uvcg_streaming_header_allow_link(struct config_item *src,
872 struct config_item *target)
873{
874 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
875 struct config_item *opts_item;
876 struct f_uvc_opts *opts;
877 struct uvcg_streaming_header *src_hdr;
878 struct uvcg_format *target_fmt = NULL;
879 struct uvcg_format_ptr *format_ptr;
880 int i, ret = -EINVAL;
881
882 src_hdr = to_uvcg_streaming_header(src);
883 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
884
885 opts_item = src->ci_parent->ci_parent->ci_parent;
886 opts = to_f_uvc_opts(opts_item);
887
888 mutex_lock(&opts->lock);
889
890 if (src_hdr->linked) {
891 ret = -EBUSY;
892 goto out;
893 }
894
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300895 /*
896 * Linking is only allowed to direct children of the format nodes
897 * (streaming/uncompressed or streaming/mjpeg nodes). First check that
898 * the grand-parent of the target matches the grand-parent of the source
899 * (the streaming node), and then verify that the target parent is a
900 * format node.
901 */
902 if (src->ci_parent->ci_parent != target->ci_parent->ci_parent)
903 goto out;
904
905 for (i = 0; i < ARRAY_SIZE(uvcg_format_names); ++i) {
906 if (!strcmp(target->ci_parent->ci_name, uvcg_format_names[i]))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100907 break;
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300908 }
909
910 if (i == ARRAY_SIZE(uvcg_format_names))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100911 goto out;
912
913 target_fmt = container_of(to_config_group(target), struct uvcg_format,
914 group);
915 if (!target_fmt)
916 goto out;
917
918 format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
919 if (!format_ptr) {
Dan Carpenterdf90f832015-01-14 23:59:48 +0300920 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100921 goto out;
922 }
923 ret = 0;
924 format_ptr->fmt = target_fmt;
925 list_add_tail(&format_ptr->entry, &src_hdr->formats);
926 ++src_hdr->num_fmt;
927
928out:
929 mutex_unlock(&opts->lock);
930 mutex_unlock(su_mutex);
931 return ret;
932}
933
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +0100934static void uvcg_streaming_header_drop_link(struct config_item *src,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100935 struct config_item *target)
936{
937 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
938 struct config_item *opts_item;
939 struct f_uvc_opts *opts;
940 struct uvcg_streaming_header *src_hdr;
941 struct uvcg_format *target_fmt = NULL;
942 struct uvcg_format_ptr *format_ptr, *tmp;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100943
944 src_hdr = to_uvcg_streaming_header(src);
945 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
946
947 opts_item = src->ci_parent->ci_parent->ci_parent;
948 opts = to_f_uvc_opts(opts_item);
949
950 mutex_lock(&opts->lock);
951 target_fmt = container_of(to_config_group(target), struct uvcg_format,
952 group);
953 if (!target_fmt)
954 goto out;
955
956 list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
957 if (format_ptr->fmt == target_fmt) {
958 list_del(&format_ptr->entry);
959 kfree(format_ptr);
960 --src_hdr->num_fmt;
961 break;
962 }
963
964out:
965 mutex_unlock(&opts->lock);
966 mutex_unlock(su_mutex);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100967}
968
969static struct configfs_item_operations uvcg_streaming_header_item_ops = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +0300970 .release = uvcg_config_item_release,
971 .allow_link = uvcg_streaming_header_allow_link,
972 .drop_link = uvcg_streaming_header_drop_link,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100973};
974
975#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \
976static ssize_t uvcg_streaming_header_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200977 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100978{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200979 struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100980 struct f_uvc_opts *opts; \
981 struct config_item *opts_item; \
982 struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\
983 int result; \
984 \
985 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
986 \
987 opts_item = sh->item.ci_parent->ci_parent->ci_parent; \
988 opts = to_f_uvc_opts(opts_item); \
989 \
990 mutex_lock(&opts->lock); \
991 result = sprintf(page, "%d\n", conv(sh->desc.aname)); \
992 mutex_unlock(&opts->lock); \
993 \
994 mutex_unlock(su_mutex); \
995 return result; \
996} \
997 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200998UVC_ATTR_RO(uvcg_streaming_header_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100999
1000#define identity_conv(x) (x)
1001
1002UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv);
1003UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv);
1004UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod,
1005 identity_conv);
1006UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
1007UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
1008
1009#undef identity_conv
1010
1011#undef UVCG_STREAMING_HEADER_ATTR
1012
1013static struct configfs_attribute *uvcg_streaming_header_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001014 &uvcg_streaming_header_attr_bm_info,
1015 &uvcg_streaming_header_attr_b_terminal_link,
1016 &uvcg_streaming_header_attr_b_still_capture_method,
1017 &uvcg_streaming_header_attr_b_trigger_support,
1018 &uvcg_streaming_header_attr_b_trigger_usage,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001019 NULL,
1020};
1021
Bhumika Goyal97363902017-10-16 17:18:41 +02001022static const struct config_item_type uvcg_streaming_header_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001023 .ct_item_ops = &uvcg_streaming_header_item_ops,
1024 .ct_attrs = uvcg_streaming_header_attrs,
1025 .ct_owner = THIS_MODULE,
1026};
1027
1028static struct config_item
1029*uvcg_streaming_header_make(struct config_group *group, const char *name)
1030{
1031 struct uvcg_streaming_header *h;
1032
1033 h = kzalloc(sizeof(*h), GFP_KERNEL);
1034 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001035 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001036
1037 INIT_LIST_HEAD(&h->formats);
1038 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
1039 h->desc.bDescriptorSubType = UVC_VS_INPUT_HEADER;
1040 h->desc.bTerminalLink = 3;
1041 h->desc.bControlSize = UVCG_STREAMING_CONTROL_SIZE;
1042
1043 config_item_init_type_name(&h->item, name, &uvcg_streaming_header_type);
1044
1045 return &h->item;
1046}
1047
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001048static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
1049 .make_item = uvcg_streaming_header_make,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001050};
1051
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001052static const struct uvcg_config_group_type uvcg_streaming_header_grp_type = {
1053 .type = {
1054 .ct_item_ops = &uvcg_config_item_ops,
1055 .ct_group_ops = &uvcg_streaming_header_grp_ops,
1056 .ct_owner = THIS_MODULE,
1057 },
1058 .name = "header",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001059};
1060
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001061/* -----------------------------------------------------------------------------
1062 * streaming/<mode>/<format>/<NAME>
1063 */
1064
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001065struct uvcg_frame {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001066 struct config_item item;
1067 enum uvcg_format_type fmt_type;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001068 struct {
1069 u8 b_length;
1070 u8 b_descriptor_type;
1071 u8 b_descriptor_subtype;
1072 u8 b_frame_index;
1073 u8 bm_capabilities;
1074 u16 w_width;
1075 u16 w_height;
1076 u32 dw_min_bit_rate;
1077 u32 dw_max_bit_rate;
1078 u32 dw_max_video_frame_buffer_size;
1079 u32 dw_default_frame_interval;
1080 u8 b_frame_interval_type;
1081 } __attribute__((packed)) frame;
1082 u32 *dw_frame_interval;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001083};
1084
kbuild test robotf093a2d2015-01-13 16:55:38 +08001085static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001086{
1087 return container_of(item, struct uvcg_frame, item);
1088}
1089
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001090#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001091static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001092{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001093 struct uvcg_frame *f = to_uvcg_frame(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001094 struct f_uvc_opts *opts; \
1095 struct config_item *opts_item; \
1096 struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
1097 int result; \
1098 \
1099 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1100 \
1101 opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
1102 opts = to_f_uvc_opts(opts_item); \
1103 \
1104 mutex_lock(&opts->lock); \
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001105 result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001106 mutex_unlock(&opts->lock); \
1107 \
1108 mutex_unlock(su_mutex); \
1109 return result; \
1110} \
1111 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001112static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001113 const char *page, size_t len)\
1114{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001115 struct uvcg_frame *f = to_uvcg_frame(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001116 struct f_uvc_opts *opts; \
1117 struct config_item *opts_item; \
1118 struct uvcg_format *fmt; \
1119 struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
1120 int ret; \
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001121 u##bits num; \
1122 \
1123 ret = kstrtou##bits(page, 0, &num); \
1124 if (ret) \
1125 return ret; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001126 \
1127 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1128 \
1129 opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
1130 opts = to_f_uvc_opts(opts_item); \
1131 fmt = to_uvcg_format(f->item.ci_parent); \
1132 \
1133 mutex_lock(&opts->lock); \
1134 if (fmt->linked || opts->refcnt) { \
1135 ret = -EBUSY; \
1136 goto end; \
1137 } \
1138 \
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001139 f->frame.cname = to_little_endian(num); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001140 ret = len; \
1141end: \
1142 mutex_unlock(&opts->lock); \
1143 mutex_unlock(su_mutex); \
1144 return ret; \
1145} \
1146 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001147UVC_ATTR(uvcg_frame_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001148
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001149#define noop_conversion(x) (x)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001150
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001151UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
1152 noop_conversion, 8);
1153UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
1154UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
1155UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
1156UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001157UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001158 le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001159UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001160 le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001161
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001162#undef noop_conversion
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001163
1164#undef UVCG_FRAME_ATTR
1165
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001166static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001167 char *page)
1168{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001169 struct uvcg_frame *frm = to_uvcg_frame(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001170 struct f_uvc_opts *opts;
1171 struct config_item *opts_item;
1172 struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
1173 int result, i;
1174 char *pg = page;
1175
1176 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1177
1178 opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
1179 opts = to_f_uvc_opts(opts_item);
1180
1181 mutex_lock(&opts->lock);
1182 for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
1183 result += sprintf(pg, "%d\n",
1184 le32_to_cpu(frm->dw_frame_interval[i]));
1185 pg = page + result;
1186 }
1187 mutex_unlock(&opts->lock);
1188
1189 mutex_unlock(su_mutex);
1190 return result;
1191}
1192
1193static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
1194{
1195 ++*((int *)priv);
1196 return 0;
1197}
1198
1199static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
1200{
1201 u32 num, **interv;
1202 int ret;
1203
1204 ret = kstrtou32(buf, 0, &num);
1205 if (ret)
1206 return ret;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001207
1208 interv = priv;
1209 **interv = cpu_to_le32(num);
1210 ++*interv;
1211
1212 return 0;
1213}
1214
1215static int __uvcg_iter_frm_intrv(const char *page, size_t len,
1216 int (*fun)(char *, void *), void *priv)
1217{
1218 /* sign, base 2 representation, newline, terminator */
1219 char buf[1 + sizeof(u32) * 8 + 1 + 1];
1220 const char *pg = page;
1221 int i, ret;
1222
1223 if (!fun)
1224 return -EINVAL;
1225
1226 while (pg - page < len) {
1227 i = 0;
1228 while (i < sizeof(buf) && (pg - page < len) &&
1229 *pg != '\0' && *pg != '\n')
1230 buf[i++] = *pg++;
1231 if (i == sizeof(buf))
1232 return -EINVAL;
1233 while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
1234 ++pg;
1235 buf[i] = '\0';
1236 ret = fun(buf, priv);
1237 if (ret)
1238 return ret;
1239 }
1240
1241 return 0;
1242}
1243
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001244static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001245 const char *page, size_t len)
1246{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001247 struct uvcg_frame *ch = to_uvcg_frame(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001248 struct f_uvc_opts *opts;
1249 struct config_item *opts_item;
1250 struct uvcg_format *fmt;
1251 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;
1252 int ret = 0, n = 0;
1253 u32 *frm_intrv, *tmp;
1254
1255 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1256
1257 opts_item = ch->item.ci_parent->ci_parent->ci_parent->ci_parent;
1258 opts = to_f_uvc_opts(opts_item);
1259 fmt = to_uvcg_format(ch->item.ci_parent);
1260
1261 mutex_lock(&opts->lock);
1262 if (fmt->linked || opts->refcnt) {
1263 ret = -EBUSY;
1264 goto end;
1265 }
1266
1267 ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
1268 if (ret)
1269 goto end;
1270
1271 tmp = frm_intrv = kcalloc(n, sizeof(u32), GFP_KERNEL);
1272 if (!frm_intrv) {
1273 ret = -ENOMEM;
1274 goto end;
1275 }
1276
1277 ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
1278 if (ret) {
1279 kfree(frm_intrv);
1280 goto end;
1281 }
1282
1283 kfree(ch->dw_frame_interval);
1284 ch->dw_frame_interval = frm_intrv;
1285 ch->frame.b_frame_interval_type = n;
1286 ret = len;
1287
1288end:
1289 mutex_unlock(&opts->lock);
1290 mutex_unlock(su_mutex);
1291 return ret;
1292}
1293
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001294UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001295
1296static struct configfs_attribute *uvcg_frame_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001297 &uvcg_frame_attr_bm_capabilities,
1298 &uvcg_frame_attr_w_width,
1299 &uvcg_frame_attr_w_height,
1300 &uvcg_frame_attr_dw_min_bit_rate,
1301 &uvcg_frame_attr_dw_max_bit_rate,
1302 &uvcg_frame_attr_dw_max_video_frame_buffer_size,
1303 &uvcg_frame_attr_dw_default_frame_interval,
1304 &uvcg_frame_attr_dw_frame_interval,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001305 NULL,
1306};
1307
Bhumika Goyal97363902017-10-16 17:18:41 +02001308static const struct config_item_type uvcg_frame_type = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001309 .ct_item_ops = &uvcg_config_item_ops,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001310 .ct_attrs = uvcg_frame_attrs,
1311 .ct_owner = THIS_MODULE,
1312};
1313
1314static struct config_item *uvcg_frame_make(struct config_group *group,
1315 const char *name)
1316{
1317 struct uvcg_frame *h;
1318 struct uvcg_format *fmt;
1319 struct f_uvc_opts *opts;
1320 struct config_item *opts_item;
1321
1322 h = kzalloc(sizeof(*h), GFP_KERNEL);
1323 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001324 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001325
1326 h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
1327 h->frame.b_frame_index = 1;
1328 h->frame.w_width = cpu_to_le16(640);
1329 h->frame.w_height = cpu_to_le16(360);
1330 h->frame.dw_min_bit_rate = cpu_to_le32(18432000);
1331 h->frame.dw_max_bit_rate = cpu_to_le32(55296000);
1332 h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800);
1333 h->frame.dw_default_frame_interval = cpu_to_le32(666666);
1334
1335 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
1336 opts = to_f_uvc_opts(opts_item);
1337
1338 mutex_lock(&opts->lock);
1339 fmt = to_uvcg_format(&group->cg_item);
1340 if (fmt->type == UVCG_UNCOMPRESSED) {
1341 h->frame.b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED;
1342 h->fmt_type = UVCG_UNCOMPRESSED;
1343 } else if (fmt->type == UVCG_MJPEG) {
1344 h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG;
1345 h->fmt_type = UVCG_MJPEG;
1346 } else {
1347 mutex_unlock(&opts->lock);
Dan Carpenterc5b2dc62015-01-15 00:03:08 +03001348 kfree(h);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001349 return ERR_PTR(-EINVAL);
1350 }
1351 ++fmt->num_frames;
1352 mutex_unlock(&opts->lock);
1353
1354 config_item_init_type_name(&h->item, name, &uvcg_frame_type);
1355
1356 return &h->item;
1357}
1358
kbuild test robotf093a2d2015-01-13 16:55:38 +08001359static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001360{
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001361 struct uvcg_format *fmt;
1362 struct f_uvc_opts *opts;
1363 struct config_item *opts_item;
1364
1365 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
1366 opts = to_f_uvc_opts(opts_item);
1367
1368 mutex_lock(&opts->lock);
1369 fmt = to_uvcg_format(&group->cg_item);
1370 --fmt->num_frames;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001371 mutex_unlock(&opts->lock);
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001372
1373 config_item_put(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001374}
1375
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001376/* -----------------------------------------------------------------------------
1377 * streaming/uncompressed/<NAME>
1378 */
1379
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001380struct uvcg_uncompressed {
1381 struct uvcg_format fmt;
1382 struct uvc_format_uncompressed desc;
1383};
1384
kbuild test robotf093a2d2015-01-13 16:55:38 +08001385static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001386{
1387 return container_of(
1388 container_of(to_config_group(item), struct uvcg_format, group),
1389 struct uvcg_uncompressed, fmt);
1390}
1391
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001392static struct configfs_group_operations uvcg_uncompressed_group_ops = {
1393 .make_item = uvcg_frame_make,
1394 .drop_item = uvcg_frame_drop,
1395};
1396
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001397static ssize_t uvcg_uncompressed_guid_format_show(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001398 char *page)
1399{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001400 struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001401 struct f_uvc_opts *opts;
1402 struct config_item *opts_item;
1403 struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
1404
1405 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1406
1407 opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
1408 opts = to_f_uvc_opts(opts_item);
1409
1410 mutex_lock(&opts->lock);
1411 memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat));
1412 mutex_unlock(&opts->lock);
1413
1414 mutex_unlock(su_mutex);
1415
1416 return sizeof(ch->desc.guidFormat);
1417}
1418
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001419static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001420 const char *page, size_t len)
1421{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001422 struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001423 struct f_uvc_opts *opts;
1424 struct config_item *opts_item;
1425 struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
1426 int ret;
1427
1428 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1429
1430 opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
1431 opts = to_f_uvc_opts(opts_item);
1432
1433 mutex_lock(&opts->lock);
1434 if (ch->fmt.linked || opts->refcnt) {
1435 ret = -EBUSY;
1436 goto end;
1437 }
1438
1439 memcpy(ch->desc.guidFormat, page,
1440 min(sizeof(ch->desc.guidFormat), len));
1441 ret = sizeof(ch->desc.guidFormat);
1442
1443end:
1444 mutex_unlock(&opts->lock);
1445 mutex_unlock(su_mutex);
1446 return ret;
1447}
1448
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001449UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001450
1451#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \
1452static ssize_t uvcg_uncompressed_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001453 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001454{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001455 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001456 struct f_uvc_opts *opts; \
1457 struct config_item *opts_item; \
1458 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1459 int result; \
1460 \
1461 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1462 \
1463 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1464 opts = to_f_uvc_opts(opts_item); \
1465 \
1466 mutex_lock(&opts->lock); \
1467 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1468 mutex_unlock(&opts->lock); \
1469 \
1470 mutex_unlock(su_mutex); \
1471 return result; \
1472} \
1473 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001474UVC_ATTR_RO(uvcg_uncompressed_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001475
1476#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \
1477static ssize_t uvcg_uncompressed_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001478 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001479{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001480 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001481 struct f_uvc_opts *opts; \
1482 struct config_item *opts_item; \
1483 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1484 int result; \
1485 \
1486 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1487 \
1488 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1489 opts = to_f_uvc_opts(opts_item); \
1490 \
1491 mutex_lock(&opts->lock); \
1492 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1493 mutex_unlock(&opts->lock); \
1494 \
1495 mutex_unlock(su_mutex); \
1496 return result; \
1497} \
1498 \
1499static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001500uvcg_uncompressed_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001501 const char *page, size_t len) \
1502{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001503 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001504 struct f_uvc_opts *opts; \
1505 struct config_item *opts_item; \
1506 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1507 int ret; \
1508 u8 num; \
1509 \
1510 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1511 \
1512 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1513 opts = to_f_uvc_opts(opts_item); \
1514 \
1515 mutex_lock(&opts->lock); \
1516 if (u->fmt.linked || opts->refcnt) { \
1517 ret = -EBUSY; \
1518 goto end; \
1519 } \
1520 \
1521 ret = kstrtou8(page, 0, &num); \
1522 if (ret) \
1523 goto end; \
1524 \
1525 if (num > 255) { \
1526 ret = -EINVAL; \
1527 goto end; \
1528 } \
1529 u->desc.aname = num; \
1530 ret = len; \
1531end: \
1532 mutex_unlock(&opts->lock); \
1533 mutex_unlock(su_mutex); \
1534 return ret; \
1535} \
1536 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001537UVC_ATTR(uvcg_uncompressed_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001538
1539#define identity_conv(x) (x)
1540
1541UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv);
1542UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex,
1543 identity_conv);
1544UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
1545UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
1546UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
1547
1548#undef identity_conv
1549
1550#undef UVCG_UNCOMPRESSED_ATTR
1551#undef UVCG_UNCOMPRESSED_ATTR_RO
1552
1553static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001554uvcg_uncompressed_bma_controls_show(struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001555{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001556 struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001557 return uvcg_format_bma_controls_show(&unc->fmt, page);
1558}
1559
1560static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001561uvcg_uncompressed_bma_controls_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001562 const char *page, size_t len)
1563{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001564 struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
1565 return uvcg_format_bma_controls_store(&unc->fmt, page, len);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001566}
1567
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001568UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001569
1570static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001571 &uvcg_uncompressed_attr_guid_format,
1572 &uvcg_uncompressed_attr_b_bits_per_pixel,
1573 &uvcg_uncompressed_attr_b_default_frame_index,
1574 &uvcg_uncompressed_attr_b_aspect_ratio_x,
1575 &uvcg_uncompressed_attr_b_aspect_ratio_y,
1576 &uvcg_uncompressed_attr_bm_interface_flags,
1577 &uvcg_uncompressed_attr_bma_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001578 NULL,
1579};
1580
Bhumika Goyal97363902017-10-16 17:18:41 +02001581static const struct config_item_type uvcg_uncompressed_type = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001582 .ct_item_ops = &uvcg_config_item_ops,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001583 .ct_group_ops = &uvcg_uncompressed_group_ops,
1584 .ct_attrs = uvcg_uncompressed_attrs,
1585 .ct_owner = THIS_MODULE,
1586};
1587
1588static struct config_group *uvcg_uncompressed_make(struct config_group *group,
1589 const char *name)
1590{
1591 static char guid[] = {
1592 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
1593 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
1594 };
1595 struct uvcg_uncompressed *h;
1596
1597 h = kzalloc(sizeof(*h), GFP_KERNEL);
1598 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001599 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001600
1601 h->desc.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE;
1602 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
1603 h->desc.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED;
1604 memcpy(h->desc.guidFormat, guid, sizeof(guid));
1605 h->desc.bBitsPerPixel = 16;
1606 h->desc.bDefaultFrameIndex = 1;
1607 h->desc.bAspectRatioX = 0;
1608 h->desc.bAspectRatioY = 0;
1609 h->desc.bmInterfaceFlags = 0;
1610 h->desc.bCopyProtect = 0;
1611
1612 h->fmt.type = UVCG_UNCOMPRESSED;
1613 config_group_init_type_name(&h->fmt.group, name,
1614 &uvcg_uncompressed_type);
1615
1616 return &h->fmt.group;
1617}
1618
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001619static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
1620 .make_group = uvcg_uncompressed_make,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001621};
1622
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001623static const struct uvcg_config_group_type uvcg_uncompressed_grp_type = {
1624 .type = {
1625 .ct_item_ops = &uvcg_config_item_ops,
1626 .ct_group_ops = &uvcg_uncompressed_grp_ops,
1627 .ct_owner = THIS_MODULE,
1628 },
1629 .name = "uncompressed",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001630};
1631
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001632/* -----------------------------------------------------------------------------
1633 * streaming/mjpeg/<NAME>
1634 */
1635
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001636struct uvcg_mjpeg {
1637 struct uvcg_format fmt;
1638 struct uvc_format_mjpeg desc;
1639};
1640
kbuild test robotf093a2d2015-01-13 16:55:38 +08001641static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001642{
1643 return container_of(
1644 container_of(to_config_group(item), struct uvcg_format, group),
1645 struct uvcg_mjpeg, fmt);
1646}
1647
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001648static struct configfs_group_operations uvcg_mjpeg_group_ops = {
1649 .make_item = uvcg_frame_make,
1650 .drop_item = uvcg_frame_drop,
1651};
1652
1653#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001654static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001655{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001656 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001657 struct f_uvc_opts *opts; \
1658 struct config_item *opts_item; \
1659 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1660 int result; \
1661 \
1662 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1663 \
1664 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1665 opts = to_f_uvc_opts(opts_item); \
1666 \
1667 mutex_lock(&opts->lock); \
1668 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1669 mutex_unlock(&opts->lock); \
1670 \
1671 mutex_unlock(su_mutex); \
1672 return result; \
1673} \
1674 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001675UVC_ATTR_RO(uvcg_mjpeg_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001676
1677#define UVCG_MJPEG_ATTR(cname, aname, conv) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001678static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001679{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001680 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001681 struct f_uvc_opts *opts; \
1682 struct config_item *opts_item; \
1683 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1684 int result; \
1685 \
1686 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1687 \
1688 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1689 opts = to_f_uvc_opts(opts_item); \
1690 \
1691 mutex_lock(&opts->lock); \
1692 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1693 mutex_unlock(&opts->lock); \
1694 \
1695 mutex_unlock(su_mutex); \
1696 return result; \
1697} \
1698 \
1699static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001700uvcg_mjpeg_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001701 const char *page, size_t len) \
1702{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001703 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001704 struct f_uvc_opts *opts; \
1705 struct config_item *opts_item; \
1706 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1707 int ret; \
1708 u8 num; \
1709 \
1710 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1711 \
1712 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1713 opts = to_f_uvc_opts(opts_item); \
1714 \
1715 mutex_lock(&opts->lock); \
1716 if (u->fmt.linked || opts->refcnt) { \
1717 ret = -EBUSY; \
1718 goto end; \
1719 } \
1720 \
1721 ret = kstrtou8(page, 0, &num); \
1722 if (ret) \
1723 goto end; \
1724 \
1725 if (num > 255) { \
1726 ret = -EINVAL; \
1727 goto end; \
1728 } \
1729 u->desc.aname = num; \
1730 ret = len; \
1731end: \
1732 mutex_unlock(&opts->lock); \
1733 mutex_unlock(su_mutex); \
1734 return ret; \
1735} \
1736 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001737UVC_ATTR(uvcg_mjpeg_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001738
1739#define identity_conv(x) (x)
1740
1741UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex,
1742 identity_conv);
1743UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv);
1744UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
1745UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
1746UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
1747
1748#undef identity_conv
1749
1750#undef UVCG_MJPEG_ATTR
1751#undef UVCG_MJPEG_ATTR_RO
1752
1753static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001754uvcg_mjpeg_bma_controls_show(struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001755{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001756 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
1757 return uvcg_format_bma_controls_show(&u->fmt, page);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001758}
1759
1760static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001761uvcg_mjpeg_bma_controls_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001762 const char *page, size_t len)
1763{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001764 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
1765 return uvcg_format_bma_controls_store(&u->fmt, page, len);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001766}
1767
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001768UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001769
1770static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001771 &uvcg_mjpeg_attr_b_default_frame_index,
1772 &uvcg_mjpeg_attr_bm_flags,
1773 &uvcg_mjpeg_attr_b_aspect_ratio_x,
1774 &uvcg_mjpeg_attr_b_aspect_ratio_y,
1775 &uvcg_mjpeg_attr_bm_interface_flags,
1776 &uvcg_mjpeg_attr_bma_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001777 NULL,
1778};
1779
Bhumika Goyal97363902017-10-16 17:18:41 +02001780static const struct config_item_type uvcg_mjpeg_type = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001781 .ct_item_ops = &uvcg_config_item_ops,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001782 .ct_group_ops = &uvcg_mjpeg_group_ops,
1783 .ct_attrs = uvcg_mjpeg_attrs,
1784 .ct_owner = THIS_MODULE,
1785};
1786
1787static struct config_group *uvcg_mjpeg_make(struct config_group *group,
1788 const char *name)
1789{
1790 struct uvcg_mjpeg *h;
1791
1792 h = kzalloc(sizeof(*h), GFP_KERNEL);
1793 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001794 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001795
1796 h->desc.bLength = UVC_DT_FORMAT_MJPEG_SIZE;
1797 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
1798 h->desc.bDescriptorSubType = UVC_VS_FORMAT_MJPEG;
1799 h->desc.bDefaultFrameIndex = 1;
1800 h->desc.bAspectRatioX = 0;
1801 h->desc.bAspectRatioY = 0;
1802 h->desc.bmInterfaceFlags = 0;
1803 h->desc.bCopyProtect = 0;
1804
1805 h->fmt.type = UVCG_MJPEG;
1806 config_group_init_type_name(&h->fmt.group, name,
1807 &uvcg_mjpeg_type);
1808
1809 return &h->fmt.group;
1810}
1811
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001812static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
1813 .make_group = uvcg_mjpeg_make,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001814};
1815
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001816static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = {
1817 .type = {
1818 .ct_item_ops = &uvcg_config_item_ops,
1819 .ct_group_ops = &uvcg_mjpeg_grp_ops,
1820 .ct_owner = THIS_MODULE,
1821 },
1822 .name = "mjpeg",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001823};
1824
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001825/* -----------------------------------------------------------------------------
1826 * streaming/color_matching/default
1827 */
1828
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001829#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \
1830static ssize_t uvcg_default_color_matching_##cname##_show( \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +03001831 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001832{ \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +03001833 struct config_group *group = to_config_group(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001834 struct f_uvc_opts *opts; \
1835 struct config_item *opts_item; \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +03001836 struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001837 struct uvc_color_matching_descriptor *cd; \
1838 int result; \
1839 \
1840 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1841 \
Laurent Pinchartb0aa30f2018-05-24 17:49:34 +03001842 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001843 opts = to_f_uvc_opts(opts_item); \
1844 cd = &opts->uvc_color_matching; \
1845 \
1846 mutex_lock(&opts->lock); \
1847 result = sprintf(page, "%d\n", conv(cd->aname)); \
1848 mutex_unlock(&opts->lock); \
1849 \
1850 mutex_unlock(su_mutex); \
1851 return result; \
1852} \
1853 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001854UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001855
1856#define identity_conv(x) (x)
1857
1858UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
1859 identity_conv);
1860UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
1861 bTransferCharacteristics, identity_conv);
1862UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
1863 identity_conv);
1864
1865#undef identity_conv
1866
1867#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
1868
1869static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001870 &uvcg_default_color_matching_attr_b_color_primaries,
1871 &uvcg_default_color_matching_attr_b_transfer_characteristics,
1872 &uvcg_default_color_matching_attr_b_matrix_coefficients,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001873 NULL,
1874};
1875
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001876static const struct uvcg_config_group_type uvcg_default_color_matching_type = {
1877 .type = {
1878 .ct_item_ops = &uvcg_config_item_ops,
1879 .ct_attrs = uvcg_default_color_matching_attrs,
1880 .ct_owner = THIS_MODULE,
1881 },
1882 .name = "default",
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001883};
1884
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001885/* -----------------------------------------------------------------------------
1886 * streaming/color_matching
1887 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001888
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001889static const struct uvcg_config_group_type uvcg_color_matching_grp_type = {
1890 .type = {
1891 .ct_item_ops = &uvcg_config_item_ops,
1892 .ct_owner = THIS_MODULE,
1893 },
1894 .name = "color_matching",
1895 .children = (const struct uvcg_config_group_type*[]) {
1896 &uvcg_default_color_matching_type,
1897 NULL,
1898 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001899};
1900
Laurent Pinchartf7d81092018-05-24 17:49:34 +03001901/* -----------------------------------------------------------------------------
1902 * streaming/class/{fs|hs|ss}
1903 */
1904
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001905struct uvcg_streaming_class_group {
1906 struct config_group group;
1907 const char *name;
1908};
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001909
1910static inline struct uvc_descriptor_header
1911***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
1912{
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001913 struct uvcg_streaming_class_group *group =
1914 container_of(i, struct uvcg_streaming_class_group,
1915 group.cg_item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001916
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001917 if (!strcmp(group->name, "fs"))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001918 return &o->uvc_fs_streaming_cls;
1919
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001920 if (!strcmp(group->name, "hs"))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001921 return &o->uvc_hs_streaming_cls;
1922
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03001923 if (!strcmp(group->name, "ss"))
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001924 return &o->uvc_ss_streaming_cls;
1925
1926 return NULL;
1927}
1928
1929enum uvcg_strm_type {
1930 UVCG_HEADER = 0,
1931 UVCG_FORMAT,
1932 UVCG_FRAME
1933};
1934
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01001935/*
1936 * Iterate over a hierarchy of streaming descriptors' config items.
1937 * The items are created by the user with configfs.
1938 *
1939 * It "processes" the header pointed to by @priv1, then for each format
1940 * that follows the header "processes" the format itself and then for
1941 * each frame inside a format "processes" the frame.
1942 *
1943 * As a "processing" function the @fun is used.
1944 *
1945 * __uvcg_iter_strm_cls() is used in two context: first, to calculate
1946 * the amount of memory needed for an array of streaming descriptors
1947 * and second, to actually fill the array.
1948 *
1949 * @h: streaming header pointer
1950 * @priv2: an "inout" parameter (the caller might want to see the changes to it)
1951 * @priv3: an "inout" parameter (the caller might want to see the changes to it)
1952 * @fun: callback function for processing each level of the hierarchy
1953 */
Andrzej Pietrasiewicz72796832015-01-19 13:52:57 +01001954static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
1955 void *priv2, void *priv3,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001956 int (*fun)(void *, void *, void *, int, enum uvcg_strm_type type))
1957{
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001958 struct uvcg_format_ptr *f;
1959 struct config_group *grp;
1960 struct config_item *item;
1961 struct uvcg_frame *frm;
1962 int ret, i, j;
1963
1964 if (!fun)
1965 return -EINVAL;
1966
1967 i = j = 0;
1968 ret = fun(h, priv2, priv3, 0, UVCG_HEADER);
1969 if (ret)
1970 return ret;
1971 list_for_each_entry(f, &h->formats, entry) {
1972 ret = fun(f->fmt, priv2, priv3, i++, UVCG_FORMAT);
1973 if (ret)
1974 return ret;
1975 grp = &f->fmt->group;
1976 list_for_each_entry(item, &grp->cg_children, ci_entry) {
1977 frm = to_uvcg_frame(item);
1978 ret = fun(frm, priv2, priv3, j++, UVCG_FRAME);
1979 if (ret)
1980 return ret;
1981 }
1982 }
1983
1984 return ret;
1985}
1986
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01001987/*
1988 * Count how many bytes are needed for an array of streaming descriptors.
1989 *
1990 * @priv1: pointer to a header, format or frame
1991 * @priv2: inout parameter, accumulated size of the array
1992 * @priv3: inout parameter, accumulated number of the array elements
1993 * @n: unused, this function's prototype must match @fun in __uvcg_iter_strm_cls
1994 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001995static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
1996 enum uvcg_strm_type type)
1997{
1998 size_t *size = priv2;
1999 size_t *count = priv3;
2000
2001 switch (type) {
2002 case UVCG_HEADER: {
2003 struct uvcg_streaming_header *h = priv1;
2004
2005 *size += sizeof(h->desc);
2006 /* bmaControls */
2007 *size += h->num_fmt * UVCG_STREAMING_CONTROL_SIZE;
2008 }
2009 break;
2010 case UVCG_FORMAT: {
2011 struct uvcg_format *fmt = priv1;
2012
2013 if (fmt->type == UVCG_UNCOMPRESSED) {
2014 struct uvcg_uncompressed *u =
2015 container_of(fmt, struct uvcg_uncompressed,
2016 fmt);
2017
2018 *size += sizeof(u->desc);
2019 } else if (fmt->type == UVCG_MJPEG) {
2020 struct uvcg_mjpeg *m =
2021 container_of(fmt, struct uvcg_mjpeg, fmt);
2022
2023 *size += sizeof(m->desc);
2024 } else {
2025 return -EINVAL;
2026 }
2027 }
2028 break;
2029 case UVCG_FRAME: {
2030 struct uvcg_frame *frm = priv1;
2031 int sz = sizeof(frm->dw_frame_interval);
2032
2033 *size += sizeof(frm->frame);
2034 *size += frm->frame.b_frame_interval_type * sz;
2035 }
2036 break;
2037 }
2038
2039 ++*count;
2040
2041 return 0;
2042}
2043
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01002044/*
2045 * Fill an array of streaming descriptors.
2046 *
2047 * @priv1: pointer to a header, format or frame
2048 * @priv2: inout parameter, pointer into a block of memory
2049 * @priv3: inout parameter, pointer to a 2-dimensional array
2050 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002051static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
2052 enum uvcg_strm_type type)
2053{
2054 void **dest = priv2;
2055 struct uvc_descriptor_header ***array = priv3;
2056 size_t sz;
2057
2058 **array = *dest;
2059 ++*array;
2060
2061 switch (type) {
2062 case UVCG_HEADER: {
2063 struct uvc_input_header_descriptor *ihdr = *dest;
2064 struct uvcg_streaming_header *h = priv1;
2065 struct uvcg_format_ptr *f;
2066
2067 memcpy(*dest, &h->desc, sizeof(h->desc));
2068 *dest += sizeof(h->desc);
2069 sz = UVCG_STREAMING_CONTROL_SIZE;
2070 list_for_each_entry(f, &h->formats, entry) {
2071 memcpy(*dest, f->fmt->bmaControls, sz);
2072 *dest += sz;
2073 }
2074 ihdr->bLength = sizeof(h->desc) + h->num_fmt * sz;
2075 ihdr->bNumFormats = h->num_fmt;
2076 }
2077 break;
2078 case UVCG_FORMAT: {
2079 struct uvcg_format *fmt = priv1;
2080
2081 if (fmt->type == UVCG_UNCOMPRESSED) {
2082 struct uvc_format_uncompressed *unc = *dest;
2083 struct uvcg_uncompressed *u =
2084 container_of(fmt, struct uvcg_uncompressed,
2085 fmt);
2086
2087 memcpy(*dest, &u->desc, sizeof(u->desc));
2088 *dest += sizeof(u->desc);
2089 unc->bNumFrameDescriptors = fmt->num_frames;
2090 unc->bFormatIndex = n + 1;
2091 } else if (fmt->type == UVCG_MJPEG) {
2092 struct uvc_format_mjpeg *mjp = *dest;
2093 struct uvcg_mjpeg *m =
2094 container_of(fmt, struct uvcg_mjpeg, fmt);
2095
2096 memcpy(*dest, &m->desc, sizeof(m->desc));
2097 *dest += sizeof(m->desc);
2098 mjp->bNumFrameDescriptors = fmt->num_frames;
2099 mjp->bFormatIndex = n + 1;
2100 } else {
2101 return -EINVAL;
2102 }
2103 }
2104 break;
2105 case UVCG_FRAME: {
2106 struct uvcg_frame *frm = priv1;
2107 struct uvc_descriptor_header *h = *dest;
2108
2109 sz = sizeof(frm->frame);
2110 memcpy(*dest, &frm->frame, sz);
2111 *dest += sz;
2112 sz = frm->frame.b_frame_interval_type *
2113 sizeof(*frm->dw_frame_interval);
2114 memcpy(*dest, frm->dw_frame_interval, sz);
2115 *dest += sz;
2116 if (frm->fmt_type == UVCG_UNCOMPRESSED)
2117 h->bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(
2118 frm->frame.b_frame_interval_type);
2119 else if (frm->fmt_type == UVCG_MJPEG)
2120 h->bLength = UVC_DT_FRAME_MJPEG_SIZE(
2121 frm->frame.b_frame_interval_type);
2122 }
2123 break;
2124 }
2125
2126 return 0;
2127}
2128
2129static int uvcg_streaming_class_allow_link(struct config_item *src,
2130 struct config_item *target)
2131{
2132 struct config_item *streaming, *header;
2133 struct f_uvc_opts *opts;
2134 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
2135 struct uvc_descriptor_header ***class_array, **cl_arr;
2136 struct uvcg_streaming_header *target_hdr;
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01002137 void *data, *data_save;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002138 size_t size = 0, count = 0;
2139 int ret = -EINVAL;
2140
2141 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
2142
2143 streaming = src->ci_parent->ci_parent;
2144 header = config_group_find_item(to_config_group(streaming), "header");
2145 if (!header || target->ci_parent != header)
2146 goto out;
2147
2148 opts = to_f_uvc_opts(streaming->ci_parent);
2149
2150 mutex_lock(&opts->lock);
2151
2152 class_array = __uvcg_get_stream_class_arr(src, opts);
2153 if (!class_array || *class_array || opts->refcnt) {
2154 ret = -EBUSY;
2155 goto unlock;
2156 }
2157
2158 target_hdr = to_uvcg_streaming_header(target);
2159 ret = __uvcg_iter_strm_cls(target_hdr, &size, &count, __uvcg_cnt_strm);
2160 if (ret)
2161 goto unlock;
2162
2163 count += 2; /* color_matching, NULL */
2164 *class_array = kcalloc(count, sizeof(void *), GFP_KERNEL);
2165 if (!*class_array) {
Dan Carpenterdf90f832015-01-14 23:59:48 +03002166 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002167 goto unlock;
2168 }
2169
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01002170 data = data_save = kzalloc(size, GFP_KERNEL);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002171 if (!data) {
2172 kfree(*class_array);
2173 *class_array = NULL;
Christophe JAILLETbd610c5a2016-07-16 09:04:40 +02002174 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002175 goto unlock;
2176 }
2177 cl_arr = *class_array;
2178 ret = __uvcg_iter_strm_cls(target_hdr, &data, &cl_arr,
2179 __uvcg_fill_strm);
2180 if (ret) {
2181 kfree(*class_array);
2182 *class_array = NULL;
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01002183 /*
2184 * __uvcg_fill_strm() called from __uvcg_iter_stream_cls()
2185 * might have advanced the "data", so use a backup copy
2186 */
2187 kfree(data_save);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002188 goto unlock;
2189 }
2190 *cl_arr = (struct uvc_descriptor_header *)&opts->uvc_color_matching;
2191
2192 ++target_hdr->linked;
2193 ret = 0;
2194
2195unlock:
2196 mutex_unlock(&opts->lock);
2197out:
Laurent Pinchart86f3dae2018-08-02 00:14:00 +03002198 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002199 mutex_unlock(su_mutex);
2200 return ret;
2201}
2202
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +01002203static void uvcg_streaming_class_drop_link(struct config_item *src,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002204 struct config_item *target)
2205{
2206 struct config_item *streaming, *header;
2207 struct f_uvc_opts *opts;
2208 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
2209 struct uvc_descriptor_header ***class_array;
2210 struct uvcg_streaming_header *target_hdr;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002211
2212 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
2213
2214 streaming = src->ci_parent->ci_parent;
2215 header = config_group_find_item(to_config_group(streaming), "header");
2216 if (!header || target->ci_parent != header)
2217 goto out;
2218
2219 opts = to_f_uvc_opts(streaming->ci_parent);
2220
2221 mutex_lock(&opts->lock);
2222
2223 class_array = __uvcg_get_stream_class_arr(src, opts);
2224 if (!class_array || !*class_array)
2225 goto unlock;
2226
Andrzej Pietrasiewicze16769d2016-11-28 13:22:42 +01002227 if (opts->refcnt)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002228 goto unlock;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002229
2230 target_hdr = to_uvcg_streaming_header(target);
2231 --target_hdr->linked;
2232 kfree(**class_array);
2233 kfree(*class_array);
2234 *class_array = NULL;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002235
2236unlock:
2237 mutex_unlock(&opts->lock);
2238out:
Laurent Pinchart86f3dae2018-08-02 00:14:00 +03002239 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002240 mutex_unlock(su_mutex);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002241}
2242
2243static struct configfs_item_operations uvcg_streaming_class_item_ops = {
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002244 .release = uvcg_config_item_release,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002245 .allow_link = uvcg_streaming_class_allow_link,
2246 .drop_link = uvcg_streaming_class_drop_link,
2247};
2248
Bhumika Goyal97363902017-10-16 17:18:41 +02002249static const struct config_item_type uvcg_streaming_class_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002250 .ct_item_ops = &uvcg_streaming_class_item_ops,
2251 .ct_owner = THIS_MODULE,
2252};
2253
Laurent Pinchartf7d81092018-05-24 17:49:34 +03002254/* -----------------------------------------------------------------------------
2255 * streaming/class
2256 */
2257
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002258static int uvcg_streaming_class_create_children(struct config_group *parent)
2259{
2260 static const char * const names[] = { "fs", "hs", "ss" };
2261 unsigned int i;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002262
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002263 for (i = 0; i < ARRAY_SIZE(names); ++i) {
2264 struct uvcg_streaming_class_group *group;
2265
2266 group = kzalloc(sizeof(*group), GFP_KERNEL);
2267 if (!group)
2268 return -ENOMEM;
2269
2270 group->name = names[i];
2271
2272 config_group_init_type_name(&group->group, group->name,
2273 &uvcg_streaming_class_type);
2274 configfs_add_default_group(&group->group, parent);
2275 }
2276
2277 return 0;
2278}
2279
2280static const struct uvcg_config_group_type uvcg_streaming_class_grp_type = {
2281 .type = {
2282 .ct_item_ops = &uvcg_config_item_ops,
2283 .ct_owner = THIS_MODULE,
2284 },
2285 .name = "class",
2286 .create_children = uvcg_streaming_class_create_children,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002287};
2288
Laurent Pinchartf7d81092018-05-24 17:49:34 +03002289/* -----------------------------------------------------------------------------
2290 * streaming
2291 */
2292
Laurent Pinchartbf715442018-05-23 18:47:56 +03002293static ssize_t uvcg_default_streaming_b_interface_number_show(
2294 struct config_item *item, char *page)
2295{
2296 struct config_group *group = to_config_group(item);
2297 struct mutex *su_mutex = &group->cg_subsys->su_mutex;
2298 struct config_item *opts_item;
2299 struct f_uvc_opts *opts;
2300 int result = 0;
2301
2302 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
2303
2304 opts_item = item->ci_parent;
2305 opts = to_f_uvc_opts(opts_item);
2306
2307 mutex_lock(&opts->lock);
2308 result += sprintf(page, "%u\n", opts->streaming_interface);
2309 mutex_unlock(&opts->lock);
2310
2311 mutex_unlock(su_mutex);
2312
2313 return result;
2314}
2315
2316UVC_ATTR_RO(uvcg_default_streaming_, b_interface_number, bInterfaceNumber);
2317
2318static struct configfs_attribute *uvcg_default_streaming_attrs[] = {
2319 &uvcg_default_streaming_attr_b_interface_number,
2320 NULL,
2321};
2322
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002323static const struct uvcg_config_group_type uvcg_streaming_grp_type = {
2324 .type = {
2325 .ct_item_ops = &uvcg_config_item_ops,
Laurent Pinchartbf715442018-05-23 18:47:56 +03002326 .ct_attrs = uvcg_default_streaming_attrs,
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002327 .ct_owner = THIS_MODULE,
2328 },
2329 .name = "streaming",
2330 .children = (const struct uvcg_config_group_type*[]) {
2331 &uvcg_streaming_header_grp_type,
2332 &uvcg_uncompressed_grp_type,
2333 &uvcg_mjpeg_grp_type,
2334 &uvcg_color_matching_grp_type,
2335 &uvcg_streaming_class_grp_type,
2336 NULL,
2337 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002338};
2339
Laurent Pinchartf7d81092018-05-24 17:49:34 +03002340/* -----------------------------------------------------------------------------
2341 * UVC function
2342 */
2343
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002344static void uvc_func_item_release(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002345{
2346 struct f_uvc_opts *opts = to_f_uvc_opts(item);
2347
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002348 uvcg_config_remove_children(to_config_group(item));
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002349 usb_put_function_instance(&opts->func_inst);
2350}
2351
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002352static struct configfs_item_operations uvc_func_item_ops = {
2353 .release = uvc_func_item_release,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002354};
2355
Petr Cvekc8cd7512017-03-07 00:57:20 +01002356#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002357static ssize_t f_uvc_opts_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002358 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002359{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002360 struct f_uvc_opts *opts = to_f_uvc_opts(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002361 int result; \
2362 \
2363 mutex_lock(&opts->lock); \
2364 result = sprintf(page, "%d\n", conv(opts->cname)); \
2365 mutex_unlock(&opts->lock); \
2366 \
2367 return result; \
2368} \
2369 \
2370static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002371f_uvc_opts_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002372 const char *page, size_t len) \
2373{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002374 struct f_uvc_opts *opts = to_f_uvc_opts(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002375 int ret; \
2376 uxx num; \
2377 \
2378 mutex_lock(&opts->lock); \
2379 if (opts->refcnt) { \
2380 ret = -EBUSY; \
2381 goto end; \
2382 } \
2383 \
2384 ret = str2u(page, 0, &num); \
2385 if (ret) \
2386 goto end; \
2387 \
2388 if (num > limit) { \
2389 ret = -EINVAL; \
2390 goto end; \
2391 } \
2392 opts->cname = vnoc(num); \
2393 ret = len; \
2394end: \
2395 mutex_unlock(&opts->lock); \
2396 return ret; \
2397} \
2398 \
Petr Cvekc8cd7512017-03-07 00:57:20 +01002399UVC_ATTR(f_uvc_opts_, cname, cname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002400
2401#define identity_conv(x) (x)
2402
Petr Cvekc8cd7512017-03-07 00:57:20 +01002403UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
2404 kstrtou8, u8, identity_conv, 16);
2405UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
2406 kstrtou16, u16, le16_to_cpu, 3072);
2407UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
2408 kstrtou8, u8, identity_conv, 15);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002409
2410#undef identity_conv
2411
2412#undef UVCG_OPTS_ATTR
2413
2414static struct configfs_attribute *uvc_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002415 &f_uvc_opts_attr_streaming_interval,
2416 &f_uvc_opts_attr_streaming_maxpacket,
2417 &f_uvc_opts_attr_streaming_maxburst,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002418 NULL,
2419};
2420
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002421static const struct uvcg_config_group_type uvc_func_type = {
2422 .type = {
2423 .ct_item_ops = &uvc_func_item_ops,
2424 .ct_attrs = uvc_attrs,
2425 .ct_owner = THIS_MODULE,
2426 },
2427 .name = "",
2428 .children = (const struct uvcg_config_group_type*[]) {
2429 &uvcg_control_grp_type,
2430 &uvcg_streaming_grp_type,
2431 NULL,
2432 },
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002433};
2434
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002435int uvcg_attach_configfs(struct f_uvc_opts *opts)
2436{
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002437 int ret;
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002438
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002439 config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name,
2440 &uvc_func_type.type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002441
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002442 ret = uvcg_config_create_children(&opts->func_inst.group,
2443 &uvc_func_type);
2444 if (ret < 0)
2445 config_group_put(&opts->func_inst.group);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002446
Laurent Pinchartefbf0af2018-05-24 17:49:34 +03002447 return ret;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002448}