blob: 3d843e14447bb768052aa01b6478a7d4052b1881 [file] [log] [blame]
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001/*
2 * uvc_configfs.c
3 *
4 * Configfs support for the uvc function.
5 *
6 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
7 * http://www.samsung.com
8 *
9 * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15#include "u_uvc.h"
16#include "uvc_configfs.h"
17
18#define UVCG_STREAMING_CONTROL_SIZE 1
19
Christoph Hellwig76e0da32015-10-03 15:32:39 +020020#define UVC_ATTR(prefix, cname, aname) \
21static struct configfs_attribute prefix##attr_##cname = { \
22 .ca_name = __stringify(aname), \
Mian Yousaf Kaukab27681ab2015-11-28 18:35:44 +010023 .ca_mode = S_IRUGO | S_IWUGO, \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020024 .ca_owner = THIS_MODULE, \
25 .show = prefix##cname##_show, \
26 .store = prefix##cname##_store, \
27}
28
29#define UVC_ATTR_RO(prefix, cname, aname) \
30static struct configfs_attribute prefix##attr_##cname = { \
31 .ca_name = __stringify(aname), \
32 .ca_mode = S_IRUGO, \
33 .ca_owner = THIS_MODULE, \
34 .show = prefix##cname##_show, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010035}
36
37static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
38
39/* control/header/<NAME> */
40DECLARE_UVC_HEADER_DESCRIPTOR(1);
41
42struct uvcg_control_header {
43 struct config_item item;
44 struct UVC_HEADER_DESCRIPTOR(1) desc;
45 unsigned linked;
46};
47
kbuild test robotf093a2d2015-01-13 16:55:38 +080048static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010049{
50 return container_of(item, struct uvcg_control_header, item);
51}
52
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010053#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
54static ssize_t uvcg_control_header_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020055 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010056{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020057 struct uvcg_control_header *ch = to_uvcg_control_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010058 struct f_uvc_opts *opts; \
59 struct config_item *opts_item; \
60 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
61 int result; \
62 \
63 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
64 \
65 opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
66 opts = to_f_uvc_opts(opts_item); \
67 \
68 mutex_lock(&opts->lock); \
69 result = sprintf(page, "%d\n", conv(ch->desc.aname)); \
70 mutex_unlock(&opts->lock); \
71 \
72 mutex_unlock(su_mutex); \
73 return result; \
74} \
75 \
76static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020077uvcg_control_header_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010078 const char *page, size_t len) \
79{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +020080 struct uvcg_control_header *ch = to_uvcg_control_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +010081 struct f_uvc_opts *opts; \
82 struct config_item *opts_item; \
83 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
84 int ret; \
85 uxx num; \
86 \
87 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
88 \
89 opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
90 opts = to_f_uvc_opts(opts_item); \
91 \
92 mutex_lock(&opts->lock); \
93 if (ch->linked || opts->refcnt) { \
94 ret = -EBUSY; \
95 goto end; \
96 } \
97 \
98 ret = str2u(page, 0, &num); \
99 if (ret) \
100 goto end; \
101 \
102 if (num > limit) { \
103 ret = -EINVAL; \
104 goto end; \
105 } \
106 ch->desc.aname = vnoc(num); \
107 ret = len; \
108end: \
109 mutex_unlock(&opts->lock); \
110 mutex_unlock(su_mutex); \
111 return ret; \
112} \
113 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200114UVC_ATTR(uvcg_control_header_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100115
116UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
117 0xffff);
118
119UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
120 u32, cpu_to_le32, 0x7fffffff);
121
122#undef UVCG_CTRL_HDR_ATTR
123
124static struct configfs_attribute *uvcg_control_header_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200125 &uvcg_control_header_attr_bcd_uvc,
126 &uvcg_control_header_attr_dw_clock_frequency,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100127 NULL,
128};
129
kbuild test robotf093a2d2015-01-13 16:55:38 +0800130static struct config_item_type uvcg_control_header_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100131 .ct_attrs = uvcg_control_header_attrs,
132 .ct_owner = THIS_MODULE,
133};
134
135static struct config_item *uvcg_control_header_make(struct config_group *group,
136 const char *name)
137{
138 struct uvcg_control_header *h;
139
140 h = kzalloc(sizeof(*h), GFP_KERNEL);
141 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +0300142 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100143
144 h->desc.bLength = UVC_DT_HEADER_SIZE(1);
145 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
146 h->desc.bDescriptorSubType = UVC_VC_HEADER;
147 h->desc.bcdUVC = cpu_to_le16(0x0100);
148 h->desc.dwClockFrequency = cpu_to_le32(48000000);
149
150 config_item_init_type_name(&h->item, name, &uvcg_control_header_type);
151
152 return &h->item;
153}
154
kbuild test robotf093a2d2015-01-13 16:55:38 +0800155static void uvcg_control_header_drop(struct config_group *group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100156 struct config_item *item)
157{
158 struct uvcg_control_header *h = to_uvcg_control_header(item);
159
160 kfree(h);
161}
162
163/* control/header */
164static struct uvcg_control_header_grp {
165 struct config_group group;
166} uvcg_control_header_grp;
167
168static struct configfs_group_operations uvcg_control_header_grp_ops = {
169 .make_item = uvcg_control_header_make,
170 .drop_item = uvcg_control_header_drop,
171};
172
173static struct config_item_type uvcg_control_header_grp_type = {
174 .ct_group_ops = &uvcg_control_header_grp_ops,
175 .ct_owner = THIS_MODULE,
176};
177
178/* control/processing/default */
179static struct uvcg_default_processing {
180 struct config_group group;
181} uvcg_default_processing;
182
183static inline struct uvcg_default_processing
184*to_uvcg_default_processing(struct config_item *item)
185{
186 return container_of(to_config_group(item),
187 struct uvcg_default_processing, group);
188}
189
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100190#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \
191static ssize_t uvcg_default_processing_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200192 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100193{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200194 struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100195 struct f_uvc_opts *opts; \
196 struct config_item *opts_item; \
197 struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \
198 struct uvc_processing_unit_descriptor *pd; \
199 int result; \
200 \
201 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
202 \
203 opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \
204 opts = to_f_uvc_opts(opts_item); \
205 pd = &opts->uvc_processing; \
206 \
207 mutex_lock(&opts->lock); \
208 result = sprintf(page, "%d\n", conv(pd->aname)); \
209 mutex_unlock(&opts->lock); \
210 \
211 mutex_unlock(su_mutex); \
212 return result; \
213} \
214 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200215UVC_ATTR_RO(uvcg_default_processing_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100216
217#define identity_conv(x) (x)
218
219UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv);
220UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv);
221UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
222UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
223
224#undef identity_conv
225
226#undef UVCG_DEFAULT_PROCESSING_ATTR
227
228static ssize_t uvcg_default_processing_bm_controls_show(
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200229 struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100230{
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200231 struct uvcg_default_processing *dp = to_uvcg_default_processing(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100232 struct f_uvc_opts *opts;
233 struct config_item *opts_item;
234 struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
235 struct uvc_processing_unit_descriptor *pd;
236 int result, i;
237 char *pg = page;
238
239 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
240
241 opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
242 opts = to_f_uvc_opts(opts_item);
243 pd = &opts->uvc_processing;
244
245 mutex_lock(&opts->lock);
246 for (result = 0, i = 0; i < pd->bControlSize; ++i) {
247 result += sprintf(pg, "%d\n", pd->bmControls[i]);
248 pg = page + result;
249 }
250 mutex_unlock(&opts->lock);
251
252 mutex_unlock(su_mutex);
253
254 return result;
255}
256
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200257UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100258
259static struct configfs_attribute *uvcg_default_processing_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200260 &uvcg_default_processing_attr_b_unit_id,
261 &uvcg_default_processing_attr_b_source_id,
262 &uvcg_default_processing_attr_w_max_multiplier,
263 &uvcg_default_processing_attr_bm_controls,
264 &uvcg_default_processing_attr_i_processing,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100265 NULL,
266};
267
268static struct config_item_type uvcg_default_processing_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100269 .ct_attrs = uvcg_default_processing_attrs,
270 .ct_owner = THIS_MODULE,
271};
272
273/* struct uvcg_processing {}; */
274
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100275/* control/processing */
276static struct uvcg_processing_grp {
277 struct config_group group;
278} uvcg_processing_grp;
279
280static struct config_item_type uvcg_processing_grp_type = {
281 .ct_owner = THIS_MODULE,
282};
283
284/* control/terminal/camera/default */
285static struct uvcg_default_camera {
286 struct config_group group;
287} uvcg_default_camera;
288
289static inline struct uvcg_default_camera
290*to_uvcg_default_camera(struct config_item *item)
291{
292 return container_of(to_config_group(item),
293 struct uvcg_default_camera, group);
294}
295
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100296#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \
297static ssize_t uvcg_default_camera_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200298 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100299{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200300 struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100301 struct f_uvc_opts *opts; \
302 struct config_item *opts_item; \
303 struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
304 struct uvc_camera_terminal_descriptor *cd; \
305 int result; \
306 \
307 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
308 \
309 opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \
310 ci_parent; \
311 opts = to_f_uvc_opts(opts_item); \
312 cd = &opts->uvc_camera_terminal; \
313 \
314 mutex_lock(&opts->lock); \
315 result = sprintf(page, "%d\n", conv(cd->aname)); \
316 mutex_unlock(&opts->lock); \
317 \
318 mutex_unlock(su_mutex); \
319 \
320 return result; \
321} \
322 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200323UVC_ATTR_RO(uvcg_default_camera_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100324
325#define identity_conv(x) (x)
326
327UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv);
328UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
329UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
330UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
331UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
332 le16_to_cpu);
333UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
334 le16_to_cpu);
335UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
336 le16_to_cpu);
337
338#undef identity_conv
339
340#undef UVCG_DEFAULT_CAMERA_ATTR
341
342static ssize_t uvcg_default_camera_bm_controls_show(
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200343 struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100344{
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200345 struct uvcg_default_camera *dc = to_uvcg_default_camera(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100346 struct f_uvc_opts *opts;
347 struct config_item *opts_item;
348 struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
349 struct uvc_camera_terminal_descriptor *cd;
350 int result, i;
351 char *pg = page;
352
353 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
354
355 opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->
356 ci_parent;
357 opts = to_f_uvc_opts(opts_item);
358 cd = &opts->uvc_camera_terminal;
359
360 mutex_lock(&opts->lock);
361 for (result = 0, i = 0; i < cd->bControlSize; ++i) {
362 result += sprintf(pg, "%d\n", cd->bmControls[i]);
363 pg = page + result;
364 }
365 mutex_unlock(&opts->lock);
366
367 mutex_unlock(su_mutex);
368 return result;
369}
370
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200371UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100372
373static struct configfs_attribute *uvcg_default_camera_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200374 &uvcg_default_camera_attr_b_terminal_id,
375 &uvcg_default_camera_attr_w_terminal_type,
376 &uvcg_default_camera_attr_b_assoc_terminal,
377 &uvcg_default_camera_attr_i_terminal,
378 &uvcg_default_camera_attr_w_objective_focal_length_min,
379 &uvcg_default_camera_attr_w_objective_focal_length_max,
380 &uvcg_default_camera_attr_w_ocular_focal_length,
381 &uvcg_default_camera_attr_bm_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100382 NULL,
383};
384
385static struct config_item_type uvcg_default_camera_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100386 .ct_attrs = uvcg_default_camera_attrs,
387 .ct_owner = THIS_MODULE,
388};
389
390/* struct uvcg_camera {}; */
391
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100392/* control/terminal/camera */
393static struct uvcg_camera_grp {
394 struct config_group group;
395} uvcg_camera_grp;
396
397static struct config_item_type uvcg_camera_grp_type = {
398 .ct_owner = THIS_MODULE,
399};
400
401/* control/terminal/output/default */
402static struct uvcg_default_output {
403 struct config_group group;
404} uvcg_default_output;
405
406static inline struct uvcg_default_output
407*to_uvcg_default_output(struct config_item *item)
408{
409 return container_of(to_config_group(item),
410 struct uvcg_default_output, group);
411}
412
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100413#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \
414static ssize_t uvcg_default_output_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200415 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100416{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200417 struct uvcg_default_output *dout = to_uvcg_default_output(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100418 struct f_uvc_opts *opts; \
419 struct config_item *opts_item; \
420 struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \
421 struct uvc_output_terminal_descriptor *cd; \
422 int result; \
423 \
424 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
425 \
426 opts_item = dout->group.cg_item.ci_parent->ci_parent-> \
427 ci_parent->ci_parent; \
428 opts = to_f_uvc_opts(opts_item); \
429 cd = &opts->uvc_output_terminal; \
430 \
431 mutex_lock(&opts->lock); \
432 result = sprintf(page, "%d\n", conv(cd->aname)); \
433 mutex_unlock(&opts->lock); \
434 \
435 mutex_unlock(su_mutex); \
436 \
437 return result; \
438} \
439 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200440UVC_ATTR_RO(uvcg_default_output_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100441
442#define identity_conv(x) (x)
443
444UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv);
445UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
446UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
447UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
448UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
449
450#undef identity_conv
451
452#undef UVCG_DEFAULT_OUTPUT_ATTR
453
454static struct configfs_attribute *uvcg_default_output_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200455 &uvcg_default_output_attr_b_terminal_id,
456 &uvcg_default_output_attr_w_terminal_type,
457 &uvcg_default_output_attr_b_assoc_terminal,
458 &uvcg_default_output_attr_b_source_id,
459 &uvcg_default_output_attr_i_terminal,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100460 NULL,
461};
462
463static struct config_item_type uvcg_default_output_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100464 .ct_attrs = uvcg_default_output_attrs,
465 .ct_owner = THIS_MODULE,
466};
467
468/* struct uvcg_output {}; */
469
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100470/* control/terminal/output */
471static struct uvcg_output_grp {
472 struct config_group group;
473} uvcg_output_grp;
474
475static struct config_item_type uvcg_output_grp_type = {
476 .ct_owner = THIS_MODULE,
477};
478
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100479/* control/terminal */
480static struct uvcg_terminal_grp {
481 struct config_group group;
482} uvcg_terminal_grp;
483
484static struct config_item_type uvcg_terminal_grp_type = {
485 .ct_owner = THIS_MODULE,
486};
487
488/* control/class/{fs} */
489static struct uvcg_control_class {
490 struct config_group group;
491} uvcg_control_class_fs, uvcg_control_class_ss;
492
493
494static inline struct uvc_descriptor_header
495**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
496{
497 struct uvcg_control_class *cl = container_of(to_config_group(i),
498 struct uvcg_control_class, group);
499
500 if (cl == &uvcg_control_class_fs)
501 return o->uvc_fs_control_cls;
502
503 if (cl == &uvcg_control_class_ss)
504 return o->uvc_ss_control_cls;
505
506 return NULL;
507}
508
509static int uvcg_control_class_allow_link(struct config_item *src,
510 struct config_item *target)
511{
512 struct config_item *control, *header;
513 struct f_uvc_opts *opts;
514 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
515 struct uvc_descriptor_header **class_array;
516 struct uvcg_control_header *target_hdr;
517 int ret = -EINVAL;
518
519 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
520
521 control = src->ci_parent->ci_parent;
522 header = config_group_find_item(to_config_group(control), "header");
523 if (!header || target->ci_parent != header)
524 goto out;
525
526 opts = to_f_uvc_opts(control->ci_parent);
527
528 mutex_lock(&opts->lock);
529
530 class_array = uvcg_get_ctl_class_arr(src, opts);
531 if (!class_array)
532 goto unlock;
533 if (opts->refcnt || class_array[0]) {
534 ret = -EBUSY;
535 goto unlock;
536 }
537
538 target_hdr = to_uvcg_control_header(target);
539 ++target_hdr->linked;
540 class_array[0] = (struct uvc_descriptor_header *)&target_hdr->desc;
541 ret = 0;
542
543unlock:
544 mutex_unlock(&opts->lock);
545out:
Laurent Pinchart013cf512018-08-02 00:14:00 +0300546 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100547 mutex_unlock(su_mutex);
548 return ret;
549}
550
551static int uvcg_control_class_drop_link(struct config_item *src,
552 struct config_item *target)
553{
554 struct config_item *control, *header;
555 struct f_uvc_opts *opts;
556 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
557 struct uvc_descriptor_header **class_array;
558 struct uvcg_control_header *target_hdr;
559 int ret = -EINVAL;
560
561 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
562
563 control = src->ci_parent->ci_parent;
564 header = config_group_find_item(to_config_group(control), "header");
565 if (!header || target->ci_parent != header)
566 goto out;
567
568 opts = to_f_uvc_opts(control->ci_parent);
569
570 mutex_lock(&opts->lock);
571
572 class_array = uvcg_get_ctl_class_arr(src, opts);
573 if (!class_array)
574 goto unlock;
575 if (opts->refcnt) {
576 ret = -EBUSY;
577 goto unlock;
578 }
579
580 target_hdr = to_uvcg_control_header(target);
581 --target_hdr->linked;
582 class_array[0] = NULL;
583 ret = 0;
584
585unlock:
586 mutex_unlock(&opts->lock);
587out:
Laurent Pinchart013cf512018-08-02 00:14:00 +0300588 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100589 mutex_unlock(su_mutex);
590 return ret;
591}
592
593static struct configfs_item_operations uvcg_control_class_item_ops = {
594 .allow_link = uvcg_control_class_allow_link,
595 .drop_link = uvcg_control_class_drop_link,
596};
597
598static struct config_item_type uvcg_control_class_type = {
599 .ct_item_ops = &uvcg_control_class_item_ops,
600 .ct_owner = THIS_MODULE,
601};
602
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100603/* control/class */
604static struct uvcg_control_class_grp {
605 struct config_group group;
606} uvcg_control_class_grp;
607
608static struct config_item_type uvcg_control_class_grp_type = {
609 .ct_owner = THIS_MODULE,
610};
611
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100612/* control */
613static struct uvcg_control_grp {
614 struct config_group group;
615} uvcg_control_grp;
616
617static struct config_item_type uvcg_control_grp_type = {
618 .ct_owner = THIS_MODULE,
619};
620
621/* streaming/uncompressed */
622static struct uvcg_uncompressed_grp {
623 struct config_group group;
624} uvcg_uncompressed_grp;
625
626/* streaming/mjpeg */
627static struct uvcg_mjpeg_grp {
628 struct config_group group;
629} uvcg_mjpeg_grp;
630
631static struct config_item *fmt_parent[] = {
632 &uvcg_uncompressed_grp.group.cg_item,
633 &uvcg_mjpeg_grp.group.cg_item,
634};
635
636enum uvcg_format_type {
637 UVCG_UNCOMPRESSED = 0,
638 UVCG_MJPEG,
639};
640
641struct uvcg_format {
642 struct config_group group;
643 enum uvcg_format_type type;
644 unsigned linked;
645 unsigned num_frames;
646 __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
647};
648
kbuild test robotf093a2d2015-01-13 16:55:38 +0800649static struct uvcg_format *to_uvcg_format(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100650{
651 return container_of(to_config_group(item), struct uvcg_format, group);
652}
653
654static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
655{
656 struct f_uvc_opts *opts;
657 struct config_item *opts_item;
658 struct mutex *su_mutex = &f->group.cg_subsys->su_mutex;
659 int result, i;
660 char *pg = page;
661
662 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
663
664 opts_item = f->group.cg_item.ci_parent->ci_parent->ci_parent;
665 opts = to_f_uvc_opts(opts_item);
666
667 mutex_lock(&opts->lock);
668 result = sprintf(pg, "0x");
669 pg += result;
670 for (i = 0; i < UVCG_STREAMING_CONTROL_SIZE; ++i) {
671 result += sprintf(pg, "%x\n", f->bmaControls[i]);
672 pg = page + result;
673 }
674 mutex_unlock(&opts->lock);
675
676 mutex_unlock(su_mutex);
677 return result;
678}
679
680static ssize_t uvcg_format_bma_controls_store(struct uvcg_format *ch,
681 const char *page, size_t len)
682{
683 struct f_uvc_opts *opts;
684 struct config_item *opts_item;
685 struct mutex *su_mutex = &ch->group.cg_subsys->su_mutex;
686 int ret = -EINVAL;
687
688 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
689
690 opts_item = ch->group.cg_item.ci_parent->ci_parent->ci_parent;
691 opts = to_f_uvc_opts(opts_item);
692
693 mutex_lock(&opts->lock);
694 if (ch->linked || opts->refcnt) {
695 ret = -EBUSY;
696 goto end;
697 }
698
699 if (len < 4 || *page != '0' ||
700 (*(page + 1) != 'x' && *(page + 1) != 'X'))
701 goto end;
702 ret = hex2bin(ch->bmaControls, page + 2, 1);
703 if (ret < 0)
704 goto end;
705 ret = len;
706end:
707 mutex_unlock(&opts->lock);
708 mutex_unlock(su_mutex);
709 return ret;
710}
711
712struct uvcg_format_ptr {
713 struct uvcg_format *fmt;
714 struct list_head entry;
715};
716
717/* streaming/header/<NAME> */
718struct uvcg_streaming_header {
719 struct config_item item;
720 struct uvc_input_header_descriptor desc;
721 unsigned linked;
722 struct list_head formats;
723 unsigned num_fmt;
724};
725
kbuild test robotf093a2d2015-01-13 16:55:38 +0800726static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100727{
728 return container_of(item, struct uvcg_streaming_header, item);
729}
730
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100731static int uvcg_streaming_header_allow_link(struct config_item *src,
732 struct config_item *target)
733{
734 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
735 struct config_item *opts_item;
736 struct f_uvc_opts *opts;
737 struct uvcg_streaming_header *src_hdr;
738 struct uvcg_format *target_fmt = NULL;
739 struct uvcg_format_ptr *format_ptr;
740 int i, ret = -EINVAL;
741
742 src_hdr = to_uvcg_streaming_header(src);
743 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
744
745 opts_item = src->ci_parent->ci_parent->ci_parent;
746 opts = to_f_uvc_opts(opts_item);
747
748 mutex_lock(&opts->lock);
749
750 if (src_hdr->linked) {
751 ret = -EBUSY;
752 goto out;
753 }
754
755 for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i)
756 if (target->ci_parent == fmt_parent[i])
757 break;
758 if (i == ARRAY_SIZE(fmt_parent))
759 goto out;
760
761 target_fmt = container_of(to_config_group(target), struct uvcg_format,
762 group);
763 if (!target_fmt)
764 goto out;
765
766 format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
767 if (!format_ptr) {
Dan Carpenterdf90f832015-01-14 23:59:48 +0300768 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100769 goto out;
770 }
771 ret = 0;
772 format_ptr->fmt = target_fmt;
773 list_add_tail(&format_ptr->entry, &src_hdr->formats);
774 ++src_hdr->num_fmt;
Joel Pepperbfdb0892018-05-29 21:02:12 +0200775 ++target_fmt->linked;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100776
777out:
778 mutex_unlock(&opts->lock);
779 mutex_unlock(su_mutex);
780 return ret;
781}
782
783static int uvcg_streaming_header_drop_link(struct config_item *src,
784 struct config_item *target)
785{
786 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
787 struct config_item *opts_item;
788 struct f_uvc_opts *opts;
789 struct uvcg_streaming_header *src_hdr;
790 struct uvcg_format *target_fmt = NULL;
791 struct uvcg_format_ptr *format_ptr, *tmp;
792 int ret = -EINVAL;
793
794 src_hdr = to_uvcg_streaming_header(src);
795 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
796
797 opts_item = src->ci_parent->ci_parent->ci_parent;
798 opts = to_f_uvc_opts(opts_item);
799
800 mutex_lock(&opts->lock);
801 target_fmt = container_of(to_config_group(target), struct uvcg_format,
802 group);
803 if (!target_fmt)
804 goto out;
805
806 list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
807 if (format_ptr->fmt == target_fmt) {
808 list_del(&format_ptr->entry);
809 kfree(format_ptr);
810 --src_hdr->num_fmt;
811 break;
812 }
813
Joel Pepperbfdb0892018-05-29 21:02:12 +0200814 --target_fmt->linked;
815
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100816out:
817 mutex_unlock(&opts->lock);
818 mutex_unlock(su_mutex);
819 return ret;
820
821}
822
823static struct configfs_item_operations uvcg_streaming_header_item_ops = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100824 .allow_link = uvcg_streaming_header_allow_link,
825 .drop_link = uvcg_streaming_header_drop_link,
826};
827
828#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \
829static ssize_t uvcg_streaming_header_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200830 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100831{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200832 struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100833 struct f_uvc_opts *opts; \
834 struct config_item *opts_item; \
835 struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\
836 int result; \
837 \
838 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
839 \
840 opts_item = sh->item.ci_parent->ci_parent->ci_parent; \
841 opts = to_f_uvc_opts(opts_item); \
842 \
843 mutex_lock(&opts->lock); \
844 result = sprintf(page, "%d\n", conv(sh->desc.aname)); \
845 mutex_unlock(&opts->lock); \
846 \
847 mutex_unlock(su_mutex); \
848 return result; \
849} \
850 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200851UVC_ATTR_RO(uvcg_streaming_header_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100852
853#define identity_conv(x) (x)
854
855UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv);
856UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv);
857UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod,
858 identity_conv);
859UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
860UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
861
862#undef identity_conv
863
864#undef UVCG_STREAMING_HEADER_ATTR
865
866static struct configfs_attribute *uvcg_streaming_header_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200867 &uvcg_streaming_header_attr_bm_info,
868 &uvcg_streaming_header_attr_b_terminal_link,
869 &uvcg_streaming_header_attr_b_still_capture_method,
870 &uvcg_streaming_header_attr_b_trigger_support,
871 &uvcg_streaming_header_attr_b_trigger_usage,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100872 NULL,
873};
874
kbuild test robotf093a2d2015-01-13 16:55:38 +0800875static struct config_item_type uvcg_streaming_header_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100876 .ct_item_ops = &uvcg_streaming_header_item_ops,
877 .ct_attrs = uvcg_streaming_header_attrs,
878 .ct_owner = THIS_MODULE,
879};
880
881static struct config_item
882*uvcg_streaming_header_make(struct config_group *group, const char *name)
883{
884 struct uvcg_streaming_header *h;
885
886 h = kzalloc(sizeof(*h), GFP_KERNEL);
887 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +0300888 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100889
890 INIT_LIST_HEAD(&h->formats);
891 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
892 h->desc.bDescriptorSubType = UVC_VS_INPUT_HEADER;
893 h->desc.bTerminalLink = 3;
894 h->desc.bControlSize = UVCG_STREAMING_CONTROL_SIZE;
895
896 config_item_init_type_name(&h->item, name, &uvcg_streaming_header_type);
897
898 return &h->item;
899}
900
kbuild test robotf093a2d2015-01-13 16:55:38 +0800901static void uvcg_streaming_header_drop(struct config_group *group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100902 struct config_item *item)
903{
904 struct uvcg_streaming_header *h = to_uvcg_streaming_header(item);
905
906 kfree(h);
907}
908
909/* streaming/header */
910static struct uvcg_streaming_header_grp {
911 struct config_group group;
912} uvcg_streaming_header_grp;
913
914static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
915 .make_item = uvcg_streaming_header_make,
916 .drop_item = uvcg_streaming_header_drop,
917};
918
919static struct config_item_type uvcg_streaming_header_grp_type = {
920 .ct_group_ops = &uvcg_streaming_header_grp_ops,
921 .ct_owner = THIS_MODULE,
922};
923
924/* streaming/<mode>/<format>/<NAME> */
925struct uvcg_frame {
926 struct {
927 u8 b_length;
928 u8 b_descriptor_type;
929 u8 b_descriptor_subtype;
930 u8 b_frame_index;
931 u8 bm_capabilities;
932 u16 w_width;
933 u16 w_height;
934 u32 dw_min_bit_rate;
935 u32 dw_max_bit_rate;
936 u32 dw_max_video_frame_buffer_size;
937 u32 dw_default_frame_interval;
938 u8 b_frame_interval_type;
939 } __attribute__((packed)) frame;
940 u32 *dw_frame_interval;
941 enum uvcg_format_type fmt_type;
942 struct config_item item;
943};
944
kbuild test robotf093a2d2015-01-13 16:55:38 +0800945static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100946{
947 return container_of(item, struct uvcg_frame, item);
948}
949
Dan Carpenter3c4c7332015-01-15 00:06:35 +0300950#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200951static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100952{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200953 struct uvcg_frame *f = to_uvcg_frame(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100954 struct f_uvc_opts *opts; \
955 struct config_item *opts_item; \
956 struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
957 int result; \
958 \
959 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
960 \
961 opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
962 opts = to_f_uvc_opts(opts_item); \
963 \
964 mutex_lock(&opts->lock); \
Dan Carpenter3c4c7332015-01-15 00:06:35 +0300965 result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100966 mutex_unlock(&opts->lock); \
967 \
968 mutex_unlock(su_mutex); \
969 return result; \
970} \
971 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200972static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100973 const char *page, size_t len)\
974{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +0200975 struct uvcg_frame *f = to_uvcg_frame(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100976 struct f_uvc_opts *opts; \
977 struct config_item *opts_item; \
978 struct uvcg_format *fmt; \
979 struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
980 int ret; \
Dan Carpenter3c4c7332015-01-15 00:06:35 +0300981 u##bits num; \
982 \
983 ret = kstrtou##bits(page, 0, &num); \
984 if (ret) \
985 return ret; \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +0100986 \
987 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
988 \
989 opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
990 opts = to_f_uvc_opts(opts_item); \
991 fmt = to_uvcg_format(f->item.ci_parent); \
992 \
993 mutex_lock(&opts->lock); \
994 if (fmt->linked || opts->refcnt) { \
995 ret = -EBUSY; \
996 goto end; \
997 } \
998 \
Dan Carpenter3c4c7332015-01-15 00:06:35 +0300999 f->frame.cname = to_little_endian(num); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001000 ret = len; \
1001end: \
1002 mutex_unlock(&opts->lock); \
1003 mutex_unlock(su_mutex); \
1004 return ret; \
1005} \
1006 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001007UVC_ATTR(uvcg_frame_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001008
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001009#define noop_conversion(x) (x)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001010
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001011UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
1012 noop_conversion, 8);
1013UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
1014UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
1015UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
1016UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001017UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001018 le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001019UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001020 le32_to_cpu, cpu_to_le32, 32);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001021
Dan Carpenter3c4c7332015-01-15 00:06:35 +03001022#undef noop_conversion
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001023
1024#undef UVCG_FRAME_ATTR
1025
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001026static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001027 char *page)
1028{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001029 struct uvcg_frame *frm = to_uvcg_frame(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001030 struct f_uvc_opts *opts;
1031 struct config_item *opts_item;
1032 struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
1033 int result, i;
1034 char *pg = page;
1035
1036 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1037
1038 opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
1039 opts = to_f_uvc_opts(opts_item);
1040
1041 mutex_lock(&opts->lock);
1042 for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
1043 result += sprintf(pg, "%d\n",
1044 le32_to_cpu(frm->dw_frame_interval[i]));
1045 pg = page + result;
1046 }
1047 mutex_unlock(&opts->lock);
1048
1049 mutex_unlock(su_mutex);
1050 return result;
1051}
1052
1053static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
1054{
1055 ++*((int *)priv);
1056 return 0;
1057}
1058
1059static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
1060{
1061 u32 num, **interv;
1062 int ret;
1063
1064 ret = kstrtou32(buf, 0, &num);
1065 if (ret)
1066 return ret;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001067
1068 interv = priv;
1069 **interv = cpu_to_le32(num);
1070 ++*interv;
1071
1072 return 0;
1073}
1074
1075static int __uvcg_iter_frm_intrv(const char *page, size_t len,
1076 int (*fun)(char *, void *), void *priv)
1077{
1078 /* sign, base 2 representation, newline, terminator */
1079 char buf[1 + sizeof(u32) * 8 + 1 + 1];
1080 const char *pg = page;
1081 int i, ret;
1082
1083 if (!fun)
1084 return -EINVAL;
1085
1086 while (pg - page < len) {
1087 i = 0;
1088 while (i < sizeof(buf) && (pg - page < len) &&
1089 *pg != '\0' && *pg != '\n')
1090 buf[i++] = *pg++;
1091 if (i == sizeof(buf))
1092 return -EINVAL;
1093 while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
1094 ++pg;
1095 buf[i] = '\0';
1096 ret = fun(buf, priv);
1097 if (ret)
1098 return ret;
1099 }
1100
1101 return 0;
1102}
1103
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001104static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001105 const char *page, size_t len)
1106{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001107 struct uvcg_frame *ch = to_uvcg_frame(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001108 struct f_uvc_opts *opts;
1109 struct config_item *opts_item;
1110 struct uvcg_format *fmt;
1111 struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;
1112 int ret = 0, n = 0;
1113 u32 *frm_intrv, *tmp;
1114
1115 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1116
1117 opts_item = ch->item.ci_parent->ci_parent->ci_parent->ci_parent;
1118 opts = to_f_uvc_opts(opts_item);
1119 fmt = to_uvcg_format(ch->item.ci_parent);
1120
1121 mutex_lock(&opts->lock);
1122 if (fmt->linked || opts->refcnt) {
1123 ret = -EBUSY;
1124 goto end;
1125 }
1126
1127 ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
1128 if (ret)
1129 goto end;
1130
1131 tmp = frm_intrv = kcalloc(n, sizeof(u32), GFP_KERNEL);
1132 if (!frm_intrv) {
1133 ret = -ENOMEM;
1134 goto end;
1135 }
1136
1137 ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
1138 if (ret) {
1139 kfree(frm_intrv);
1140 goto end;
1141 }
1142
1143 kfree(ch->dw_frame_interval);
1144 ch->dw_frame_interval = frm_intrv;
1145 ch->frame.b_frame_interval_type = n;
1146 ret = len;
1147
1148end:
1149 mutex_unlock(&opts->lock);
1150 mutex_unlock(su_mutex);
1151 return ret;
1152}
1153
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001154UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001155
1156static struct configfs_attribute *uvcg_frame_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001157 &uvcg_frame_attr_bm_capabilities,
1158 &uvcg_frame_attr_w_width,
1159 &uvcg_frame_attr_w_height,
1160 &uvcg_frame_attr_dw_min_bit_rate,
1161 &uvcg_frame_attr_dw_max_bit_rate,
1162 &uvcg_frame_attr_dw_max_video_frame_buffer_size,
1163 &uvcg_frame_attr_dw_default_frame_interval,
1164 &uvcg_frame_attr_dw_frame_interval,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001165 NULL,
1166};
1167
kbuild test robotf093a2d2015-01-13 16:55:38 +08001168static struct config_item_type uvcg_frame_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001169 .ct_attrs = uvcg_frame_attrs,
1170 .ct_owner = THIS_MODULE,
1171};
1172
1173static struct config_item *uvcg_frame_make(struct config_group *group,
1174 const char *name)
1175{
1176 struct uvcg_frame *h;
1177 struct uvcg_format *fmt;
1178 struct f_uvc_opts *opts;
1179 struct config_item *opts_item;
1180
1181 h = kzalloc(sizeof(*h), GFP_KERNEL);
1182 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001183 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001184
1185 h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
1186 h->frame.b_frame_index = 1;
1187 h->frame.w_width = cpu_to_le16(640);
1188 h->frame.w_height = cpu_to_le16(360);
1189 h->frame.dw_min_bit_rate = cpu_to_le32(18432000);
1190 h->frame.dw_max_bit_rate = cpu_to_le32(55296000);
1191 h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800);
1192 h->frame.dw_default_frame_interval = cpu_to_le32(666666);
1193
1194 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
1195 opts = to_f_uvc_opts(opts_item);
1196
1197 mutex_lock(&opts->lock);
1198 fmt = to_uvcg_format(&group->cg_item);
1199 if (fmt->type == UVCG_UNCOMPRESSED) {
1200 h->frame.b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED;
1201 h->fmt_type = UVCG_UNCOMPRESSED;
1202 } else if (fmt->type == UVCG_MJPEG) {
1203 h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG;
1204 h->fmt_type = UVCG_MJPEG;
1205 } else {
1206 mutex_unlock(&opts->lock);
Dan Carpenterc5b2dc62015-01-15 00:03:08 +03001207 kfree(h);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001208 return ERR_PTR(-EINVAL);
1209 }
1210 ++fmt->num_frames;
1211 mutex_unlock(&opts->lock);
1212
1213 config_item_init_type_name(&h->item, name, &uvcg_frame_type);
1214
1215 return &h->item;
1216}
1217
kbuild test robotf093a2d2015-01-13 16:55:38 +08001218static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001219{
1220 struct uvcg_frame *h = to_uvcg_frame(item);
1221 struct uvcg_format *fmt;
1222 struct f_uvc_opts *opts;
1223 struct config_item *opts_item;
1224
1225 opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
1226 opts = to_f_uvc_opts(opts_item);
1227
1228 mutex_lock(&opts->lock);
1229 fmt = to_uvcg_format(&group->cg_item);
1230 --fmt->num_frames;
1231 kfree(h);
1232 mutex_unlock(&opts->lock);
1233}
1234
1235/* streaming/uncompressed/<NAME> */
1236struct uvcg_uncompressed {
1237 struct uvcg_format fmt;
1238 struct uvc_format_uncompressed desc;
1239};
1240
kbuild test robotf093a2d2015-01-13 16:55:38 +08001241static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001242{
1243 return container_of(
1244 container_of(to_config_group(item), struct uvcg_format, group),
1245 struct uvcg_uncompressed, fmt);
1246}
1247
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001248static struct configfs_group_operations uvcg_uncompressed_group_ops = {
1249 .make_item = uvcg_frame_make,
1250 .drop_item = uvcg_frame_drop,
1251};
1252
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001253static ssize_t uvcg_uncompressed_guid_format_show(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001254 char *page)
1255{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001256 struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001257 struct f_uvc_opts *opts;
1258 struct config_item *opts_item;
1259 struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
1260
1261 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1262
1263 opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
1264 opts = to_f_uvc_opts(opts_item);
1265
1266 mutex_lock(&opts->lock);
1267 memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat));
1268 mutex_unlock(&opts->lock);
1269
1270 mutex_unlock(su_mutex);
1271
1272 return sizeof(ch->desc.guidFormat);
1273}
1274
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001275static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001276 const char *page, size_t len)
1277{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001278 struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001279 struct f_uvc_opts *opts;
1280 struct config_item *opts_item;
1281 struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
1282 int ret;
1283
1284 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1285
1286 opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
1287 opts = to_f_uvc_opts(opts_item);
1288
1289 mutex_lock(&opts->lock);
1290 if (ch->fmt.linked || opts->refcnt) {
1291 ret = -EBUSY;
1292 goto end;
1293 }
1294
1295 memcpy(ch->desc.guidFormat, page,
1296 min(sizeof(ch->desc.guidFormat), len));
1297 ret = sizeof(ch->desc.guidFormat);
1298
1299end:
1300 mutex_unlock(&opts->lock);
1301 mutex_unlock(su_mutex);
1302 return ret;
1303}
1304
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001305UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001306
1307#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \
1308static ssize_t uvcg_uncompressed_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001309 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001310{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001311 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001312 struct f_uvc_opts *opts; \
1313 struct config_item *opts_item; \
1314 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1315 int result; \
1316 \
1317 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1318 \
1319 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1320 opts = to_f_uvc_opts(opts_item); \
1321 \
1322 mutex_lock(&opts->lock); \
1323 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1324 mutex_unlock(&opts->lock); \
1325 \
1326 mutex_unlock(su_mutex); \
1327 return result; \
1328} \
1329 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001330UVC_ATTR_RO(uvcg_uncompressed_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001331
1332#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \
1333static ssize_t uvcg_uncompressed_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001334 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001335{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001336 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001337 struct f_uvc_opts *opts; \
1338 struct config_item *opts_item; \
1339 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1340 int result; \
1341 \
1342 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1343 \
1344 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1345 opts = to_f_uvc_opts(opts_item); \
1346 \
1347 mutex_lock(&opts->lock); \
1348 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1349 mutex_unlock(&opts->lock); \
1350 \
1351 mutex_unlock(su_mutex); \
1352 return result; \
1353} \
1354 \
1355static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001356uvcg_uncompressed_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001357 const char *page, size_t len) \
1358{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001359 struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001360 struct f_uvc_opts *opts; \
1361 struct config_item *opts_item; \
1362 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1363 int ret; \
1364 u8 num; \
1365 \
1366 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1367 \
1368 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1369 opts = to_f_uvc_opts(opts_item); \
1370 \
1371 mutex_lock(&opts->lock); \
1372 if (u->fmt.linked || opts->refcnt) { \
1373 ret = -EBUSY; \
1374 goto end; \
1375 } \
1376 \
1377 ret = kstrtou8(page, 0, &num); \
1378 if (ret) \
1379 goto end; \
1380 \
1381 if (num > 255) { \
1382 ret = -EINVAL; \
1383 goto end; \
1384 } \
1385 u->desc.aname = num; \
1386 ret = len; \
1387end: \
1388 mutex_unlock(&opts->lock); \
1389 mutex_unlock(su_mutex); \
1390 return ret; \
1391} \
1392 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001393UVC_ATTR(uvcg_uncompressed_, cname, aname);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001394
1395#define identity_conv(x) (x)
1396
1397UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv);
1398UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex,
1399 identity_conv);
1400UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
1401UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
1402UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
1403
1404#undef identity_conv
1405
1406#undef UVCG_UNCOMPRESSED_ATTR
1407#undef UVCG_UNCOMPRESSED_ATTR_RO
1408
1409static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001410uvcg_uncompressed_bma_controls_show(struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001411{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001412 struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001413 return uvcg_format_bma_controls_show(&unc->fmt, page);
1414}
1415
1416static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001417uvcg_uncompressed_bma_controls_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001418 const char *page, size_t len)
1419{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001420 struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
1421 return uvcg_format_bma_controls_store(&unc->fmt, page, len);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001422}
1423
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001424UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001425
1426static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001427 &uvcg_uncompressed_attr_guid_format,
1428 &uvcg_uncompressed_attr_b_bits_per_pixel,
1429 &uvcg_uncompressed_attr_b_default_frame_index,
1430 &uvcg_uncompressed_attr_b_aspect_ratio_x,
1431 &uvcg_uncompressed_attr_b_aspect_ratio_y,
1432 &uvcg_uncompressed_attr_bm_interface_flags,
1433 &uvcg_uncompressed_attr_bma_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001434 NULL,
1435};
1436
kbuild test robotf093a2d2015-01-13 16:55:38 +08001437static struct config_item_type uvcg_uncompressed_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001438 .ct_group_ops = &uvcg_uncompressed_group_ops,
1439 .ct_attrs = uvcg_uncompressed_attrs,
1440 .ct_owner = THIS_MODULE,
1441};
1442
1443static struct config_group *uvcg_uncompressed_make(struct config_group *group,
1444 const char *name)
1445{
1446 static char guid[] = {
1447 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
1448 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
1449 };
1450 struct uvcg_uncompressed *h;
1451
1452 h = kzalloc(sizeof(*h), GFP_KERNEL);
1453 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001454 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001455
1456 h->desc.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE;
1457 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
1458 h->desc.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED;
1459 memcpy(h->desc.guidFormat, guid, sizeof(guid));
1460 h->desc.bBitsPerPixel = 16;
1461 h->desc.bDefaultFrameIndex = 1;
1462 h->desc.bAspectRatioX = 0;
1463 h->desc.bAspectRatioY = 0;
1464 h->desc.bmInterfaceFlags = 0;
1465 h->desc.bCopyProtect = 0;
1466
1467 h->fmt.type = UVCG_UNCOMPRESSED;
1468 config_group_init_type_name(&h->fmt.group, name,
1469 &uvcg_uncompressed_type);
1470
1471 return &h->fmt.group;
1472}
1473
kbuild test robotf093a2d2015-01-13 16:55:38 +08001474static void uvcg_uncompressed_drop(struct config_group *group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001475 struct config_item *item)
1476{
1477 struct uvcg_uncompressed *h = to_uvcg_uncompressed(item);
1478
1479 kfree(h);
1480}
1481
1482static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
1483 .make_group = uvcg_uncompressed_make,
1484 .drop_item = uvcg_uncompressed_drop,
1485};
1486
1487static struct config_item_type uvcg_uncompressed_grp_type = {
1488 .ct_group_ops = &uvcg_uncompressed_grp_ops,
1489 .ct_owner = THIS_MODULE,
1490};
1491
1492/* streaming/mjpeg/<NAME> */
1493struct uvcg_mjpeg {
1494 struct uvcg_format fmt;
1495 struct uvc_format_mjpeg desc;
1496};
1497
kbuild test robotf093a2d2015-01-13 16:55:38 +08001498static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001499{
1500 return container_of(
1501 container_of(to_config_group(item), struct uvcg_format, group),
1502 struct uvcg_mjpeg, fmt);
1503}
1504
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001505static struct configfs_group_operations uvcg_mjpeg_group_ops = {
1506 .make_item = uvcg_frame_make,
1507 .drop_item = uvcg_frame_drop,
1508};
1509
1510#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001511static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001512{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001513 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001514 struct f_uvc_opts *opts; \
1515 struct config_item *opts_item; \
1516 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1517 int result; \
1518 \
1519 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1520 \
1521 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1522 opts = to_f_uvc_opts(opts_item); \
1523 \
1524 mutex_lock(&opts->lock); \
1525 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1526 mutex_unlock(&opts->lock); \
1527 \
1528 mutex_unlock(su_mutex); \
1529 return result; \
1530} \
1531 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001532UVC_ATTR_RO(uvcg_mjpeg_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001533
1534#define UVCG_MJPEG_ATTR(cname, aname, conv) \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001535static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001536{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001537 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001538 struct f_uvc_opts *opts; \
1539 struct config_item *opts_item; \
1540 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1541 int result; \
1542 \
1543 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1544 \
1545 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1546 opts = to_f_uvc_opts(opts_item); \
1547 \
1548 mutex_lock(&opts->lock); \
1549 result = sprintf(page, "%d\n", conv(u->desc.aname)); \
1550 mutex_unlock(&opts->lock); \
1551 \
1552 mutex_unlock(su_mutex); \
1553 return result; \
1554} \
1555 \
1556static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001557uvcg_mjpeg_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001558 const char *page, size_t len) \
1559{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001560 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001561 struct f_uvc_opts *opts; \
1562 struct config_item *opts_item; \
1563 struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
1564 int ret; \
1565 u8 num; \
1566 \
1567 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1568 \
1569 opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
1570 opts = to_f_uvc_opts(opts_item); \
1571 \
1572 mutex_lock(&opts->lock); \
1573 if (u->fmt.linked || opts->refcnt) { \
1574 ret = -EBUSY; \
1575 goto end; \
1576 } \
1577 \
1578 ret = kstrtou8(page, 0, &num); \
1579 if (ret) \
1580 goto end; \
1581 \
1582 if (num > 255) { \
1583 ret = -EINVAL; \
1584 goto end; \
1585 } \
1586 u->desc.aname = num; \
1587 ret = len; \
1588end: \
1589 mutex_unlock(&opts->lock); \
1590 mutex_unlock(su_mutex); \
1591 return ret; \
1592} \
1593 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001594UVC_ATTR(uvcg_mjpeg_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001595
1596#define identity_conv(x) (x)
1597
1598UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex,
1599 identity_conv);
1600UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv);
1601UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
1602UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
1603UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
1604
1605#undef identity_conv
1606
1607#undef UVCG_MJPEG_ATTR
1608#undef UVCG_MJPEG_ATTR_RO
1609
1610static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001611uvcg_mjpeg_bma_controls_show(struct config_item *item, char *page)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001612{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001613 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
1614 return uvcg_format_bma_controls_show(&u->fmt, page);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001615}
1616
1617static inline ssize_t
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001618uvcg_mjpeg_bma_controls_store(struct config_item *item,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001619 const char *page, size_t len)
1620{
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001621 struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
1622 return uvcg_format_bma_controls_store(&u->fmt, page, len);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001623}
1624
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001625UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001626
1627static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001628 &uvcg_mjpeg_attr_b_default_frame_index,
1629 &uvcg_mjpeg_attr_bm_flags,
1630 &uvcg_mjpeg_attr_b_aspect_ratio_x,
1631 &uvcg_mjpeg_attr_b_aspect_ratio_y,
1632 &uvcg_mjpeg_attr_bm_interface_flags,
1633 &uvcg_mjpeg_attr_bma_controls,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001634 NULL,
1635};
1636
kbuild test robotf093a2d2015-01-13 16:55:38 +08001637static struct config_item_type uvcg_mjpeg_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001638 .ct_group_ops = &uvcg_mjpeg_group_ops,
1639 .ct_attrs = uvcg_mjpeg_attrs,
1640 .ct_owner = THIS_MODULE,
1641};
1642
1643static struct config_group *uvcg_mjpeg_make(struct config_group *group,
1644 const char *name)
1645{
1646 struct uvcg_mjpeg *h;
1647
1648 h = kzalloc(sizeof(*h), GFP_KERNEL);
1649 if (!h)
Dan Carpenterdf90f832015-01-14 23:59:48 +03001650 return ERR_PTR(-ENOMEM);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001651
1652 h->desc.bLength = UVC_DT_FORMAT_MJPEG_SIZE;
1653 h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
1654 h->desc.bDescriptorSubType = UVC_VS_FORMAT_MJPEG;
1655 h->desc.bDefaultFrameIndex = 1;
1656 h->desc.bAspectRatioX = 0;
1657 h->desc.bAspectRatioY = 0;
1658 h->desc.bmInterfaceFlags = 0;
1659 h->desc.bCopyProtect = 0;
1660
1661 h->fmt.type = UVCG_MJPEG;
1662 config_group_init_type_name(&h->fmt.group, name,
1663 &uvcg_mjpeg_type);
1664
1665 return &h->fmt.group;
1666}
1667
kbuild test robotf093a2d2015-01-13 16:55:38 +08001668static void uvcg_mjpeg_drop(struct config_group *group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001669 struct config_item *item)
1670{
1671 struct uvcg_mjpeg *h = to_uvcg_mjpeg(item);
1672
1673 kfree(h);
1674}
1675
1676static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
1677 .make_group = uvcg_mjpeg_make,
1678 .drop_item = uvcg_mjpeg_drop,
1679};
1680
1681static struct config_item_type uvcg_mjpeg_grp_type = {
1682 .ct_group_ops = &uvcg_mjpeg_grp_ops,
1683 .ct_owner = THIS_MODULE,
1684};
1685
1686/* streaming/color_matching/default */
1687static struct uvcg_default_color_matching {
1688 struct config_group group;
1689} uvcg_default_color_matching;
1690
1691static inline struct uvcg_default_color_matching
1692*to_uvcg_default_color_matching(struct config_item *item)
1693{
1694 return container_of(to_config_group(item),
1695 struct uvcg_default_color_matching, group);
1696}
1697
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001698#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \
1699static ssize_t uvcg_default_color_matching_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001700 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001701{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001702 struct uvcg_default_color_matching *dc = \
1703 to_uvcg_default_color_matching(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 = &dc->group.cg_subsys->su_mutex; \
1707 struct uvc_color_matching_descriptor *cd; \
1708 int result; \
1709 \
1710 mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
1711 \
1712 opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \
1713 opts = to_f_uvc_opts(opts_item); \
1714 cd = &opts->uvc_color_matching; \
1715 \
1716 mutex_lock(&opts->lock); \
1717 result = sprintf(page, "%d\n", conv(cd->aname)); \
1718 mutex_unlock(&opts->lock); \
1719 \
1720 mutex_unlock(su_mutex); \
1721 return result; \
1722} \
1723 \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001724UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001725
1726#define identity_conv(x) (x)
1727
1728UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
1729 identity_conv);
1730UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
1731 bTransferCharacteristics, identity_conv);
1732UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
1733 identity_conv);
1734
1735#undef identity_conv
1736
1737#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
1738
1739static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02001740 &uvcg_default_color_matching_attr_b_color_primaries,
1741 &uvcg_default_color_matching_attr_b_transfer_characteristics,
1742 &uvcg_default_color_matching_attr_b_matrix_coefficients,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001743 NULL,
1744};
1745
1746static struct config_item_type uvcg_default_color_matching_type = {
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001747 .ct_attrs = uvcg_default_color_matching_attrs,
1748 .ct_owner = THIS_MODULE,
1749};
1750
1751/* struct uvcg_color_matching {}; */
1752
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001753/* streaming/color_matching */
1754static struct uvcg_color_matching_grp {
1755 struct config_group group;
1756} uvcg_color_matching_grp;
1757
1758static struct config_item_type uvcg_color_matching_grp_type = {
1759 .ct_owner = THIS_MODULE,
1760};
1761
1762/* streaming/class/{fs|hs|ss} */
1763static struct uvcg_streaming_class {
1764 struct config_group group;
1765} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
1766
1767
1768static inline struct uvc_descriptor_header
1769***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
1770{
1771 struct uvcg_streaming_class *cl = container_of(to_config_group(i),
1772 struct uvcg_streaming_class, group);
1773
1774 if (cl == &uvcg_streaming_class_fs)
1775 return &o->uvc_fs_streaming_cls;
1776
1777 if (cl == &uvcg_streaming_class_hs)
1778 return &o->uvc_hs_streaming_cls;
1779
1780 if (cl == &uvcg_streaming_class_ss)
1781 return &o->uvc_ss_streaming_cls;
1782
1783 return NULL;
1784}
1785
1786enum uvcg_strm_type {
1787 UVCG_HEADER = 0,
1788 UVCG_FORMAT,
1789 UVCG_FRAME
1790};
1791
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01001792/*
1793 * Iterate over a hierarchy of streaming descriptors' config items.
1794 * The items are created by the user with configfs.
1795 *
1796 * It "processes" the header pointed to by @priv1, then for each format
1797 * that follows the header "processes" the format itself and then for
1798 * each frame inside a format "processes" the frame.
1799 *
1800 * As a "processing" function the @fun is used.
1801 *
1802 * __uvcg_iter_strm_cls() is used in two context: first, to calculate
1803 * the amount of memory needed for an array of streaming descriptors
1804 * and second, to actually fill the array.
1805 *
1806 * @h: streaming header pointer
1807 * @priv2: an "inout" parameter (the caller might want to see the changes to it)
1808 * @priv3: an "inout" parameter (the caller might want to see the changes to it)
1809 * @fun: callback function for processing each level of the hierarchy
1810 */
Andrzej Pietrasiewicz72796832015-01-19 13:52:57 +01001811static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
1812 void *priv2, void *priv3,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001813 int (*fun)(void *, void *, void *, int, enum uvcg_strm_type type))
1814{
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001815 struct uvcg_format_ptr *f;
1816 struct config_group *grp;
1817 struct config_item *item;
1818 struct uvcg_frame *frm;
1819 int ret, i, j;
1820
1821 if (!fun)
1822 return -EINVAL;
1823
1824 i = j = 0;
1825 ret = fun(h, priv2, priv3, 0, UVCG_HEADER);
1826 if (ret)
1827 return ret;
1828 list_for_each_entry(f, &h->formats, entry) {
1829 ret = fun(f->fmt, priv2, priv3, i++, UVCG_FORMAT);
1830 if (ret)
1831 return ret;
1832 grp = &f->fmt->group;
1833 list_for_each_entry(item, &grp->cg_children, ci_entry) {
1834 frm = to_uvcg_frame(item);
1835 ret = fun(frm, priv2, priv3, j++, UVCG_FRAME);
1836 if (ret)
1837 return ret;
1838 }
1839 }
1840
1841 return ret;
1842}
1843
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01001844/*
1845 * Count how many bytes are needed for an array of streaming descriptors.
1846 *
1847 * @priv1: pointer to a header, format or frame
1848 * @priv2: inout parameter, accumulated size of the array
1849 * @priv3: inout parameter, accumulated number of the array elements
1850 * @n: unused, this function's prototype must match @fun in __uvcg_iter_strm_cls
1851 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001852static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
1853 enum uvcg_strm_type type)
1854{
1855 size_t *size = priv2;
1856 size_t *count = priv3;
1857
1858 switch (type) {
1859 case UVCG_HEADER: {
1860 struct uvcg_streaming_header *h = priv1;
1861
1862 *size += sizeof(h->desc);
1863 /* bmaControls */
1864 *size += h->num_fmt * UVCG_STREAMING_CONTROL_SIZE;
1865 }
1866 break;
1867 case UVCG_FORMAT: {
1868 struct uvcg_format *fmt = priv1;
1869
1870 if (fmt->type == UVCG_UNCOMPRESSED) {
1871 struct uvcg_uncompressed *u =
1872 container_of(fmt, struct uvcg_uncompressed,
1873 fmt);
1874
1875 *size += sizeof(u->desc);
1876 } else if (fmt->type == UVCG_MJPEG) {
1877 struct uvcg_mjpeg *m =
1878 container_of(fmt, struct uvcg_mjpeg, fmt);
1879
1880 *size += sizeof(m->desc);
1881 } else {
1882 return -EINVAL;
1883 }
1884 }
1885 break;
1886 case UVCG_FRAME: {
1887 struct uvcg_frame *frm = priv1;
1888 int sz = sizeof(frm->dw_frame_interval);
1889
1890 *size += sizeof(frm->frame);
1891 *size += frm->frame.b_frame_interval_type * sz;
1892 }
1893 break;
1894 }
1895
1896 ++*count;
1897
1898 return 0;
1899}
1900
Andrzej Pietrasiewicz578d0b62015-01-19 13:52:58 +01001901/*
1902 * Fill an array of streaming descriptors.
1903 *
1904 * @priv1: pointer to a header, format or frame
1905 * @priv2: inout parameter, pointer into a block of memory
1906 * @priv3: inout parameter, pointer to a 2-dimensional array
1907 */
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001908static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
1909 enum uvcg_strm_type type)
1910{
1911 void **dest = priv2;
1912 struct uvc_descriptor_header ***array = priv3;
1913 size_t sz;
1914
1915 **array = *dest;
1916 ++*array;
1917
1918 switch (type) {
1919 case UVCG_HEADER: {
1920 struct uvc_input_header_descriptor *ihdr = *dest;
1921 struct uvcg_streaming_header *h = priv1;
1922 struct uvcg_format_ptr *f;
1923
1924 memcpy(*dest, &h->desc, sizeof(h->desc));
1925 *dest += sizeof(h->desc);
1926 sz = UVCG_STREAMING_CONTROL_SIZE;
1927 list_for_each_entry(f, &h->formats, entry) {
1928 memcpy(*dest, f->fmt->bmaControls, sz);
1929 *dest += sz;
1930 }
1931 ihdr->bLength = sizeof(h->desc) + h->num_fmt * sz;
1932 ihdr->bNumFormats = h->num_fmt;
1933 }
1934 break;
1935 case UVCG_FORMAT: {
1936 struct uvcg_format *fmt = priv1;
1937
1938 if (fmt->type == UVCG_UNCOMPRESSED) {
1939 struct uvc_format_uncompressed *unc = *dest;
1940 struct uvcg_uncompressed *u =
1941 container_of(fmt, struct uvcg_uncompressed,
1942 fmt);
1943
1944 memcpy(*dest, &u->desc, sizeof(u->desc));
1945 *dest += sizeof(u->desc);
1946 unc->bNumFrameDescriptors = fmt->num_frames;
1947 unc->bFormatIndex = n + 1;
1948 } else if (fmt->type == UVCG_MJPEG) {
1949 struct uvc_format_mjpeg *mjp = *dest;
1950 struct uvcg_mjpeg *m =
1951 container_of(fmt, struct uvcg_mjpeg, fmt);
1952
1953 memcpy(*dest, &m->desc, sizeof(m->desc));
1954 *dest += sizeof(m->desc);
1955 mjp->bNumFrameDescriptors = fmt->num_frames;
1956 mjp->bFormatIndex = n + 1;
1957 } else {
1958 return -EINVAL;
1959 }
1960 }
1961 break;
1962 case UVCG_FRAME: {
1963 struct uvcg_frame *frm = priv1;
1964 struct uvc_descriptor_header *h = *dest;
1965
1966 sz = sizeof(frm->frame);
1967 memcpy(*dest, &frm->frame, sz);
1968 *dest += sz;
1969 sz = frm->frame.b_frame_interval_type *
1970 sizeof(*frm->dw_frame_interval);
1971 memcpy(*dest, frm->dw_frame_interval, sz);
1972 *dest += sz;
1973 if (frm->fmt_type == UVCG_UNCOMPRESSED)
1974 h->bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(
1975 frm->frame.b_frame_interval_type);
1976 else if (frm->fmt_type == UVCG_MJPEG)
1977 h->bLength = UVC_DT_FRAME_MJPEG_SIZE(
1978 frm->frame.b_frame_interval_type);
1979 }
1980 break;
1981 }
1982
1983 return 0;
1984}
1985
1986static int uvcg_streaming_class_allow_link(struct config_item *src,
1987 struct config_item *target)
1988{
1989 struct config_item *streaming, *header;
1990 struct f_uvc_opts *opts;
1991 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
1992 struct uvc_descriptor_header ***class_array, **cl_arr;
1993 struct uvcg_streaming_header *target_hdr;
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01001994 void *data, *data_save;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01001995 size_t size = 0, count = 0;
1996 int ret = -EINVAL;
1997
1998 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
1999
2000 streaming = src->ci_parent->ci_parent;
2001 header = config_group_find_item(to_config_group(streaming), "header");
2002 if (!header || target->ci_parent != header)
2003 goto out;
2004
2005 opts = to_f_uvc_opts(streaming->ci_parent);
2006
2007 mutex_lock(&opts->lock);
2008
2009 class_array = __uvcg_get_stream_class_arr(src, opts);
2010 if (!class_array || *class_array || opts->refcnt) {
2011 ret = -EBUSY;
2012 goto unlock;
2013 }
2014
2015 target_hdr = to_uvcg_streaming_header(target);
2016 ret = __uvcg_iter_strm_cls(target_hdr, &size, &count, __uvcg_cnt_strm);
2017 if (ret)
2018 goto unlock;
2019
2020 count += 2; /* color_matching, NULL */
2021 *class_array = kcalloc(count, sizeof(void *), GFP_KERNEL);
2022 if (!*class_array) {
Dan Carpenterdf90f832015-01-14 23:59:48 +03002023 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002024 goto unlock;
2025 }
2026
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01002027 data = data_save = kzalloc(size, GFP_KERNEL);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002028 if (!data) {
2029 kfree(*class_array);
2030 *class_array = NULL;
Christophe JAILLETbd610c52016-07-16 09:04:40 +02002031 ret = -ENOMEM;
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002032 goto unlock;
2033 }
2034 cl_arr = *class_array;
2035 ret = __uvcg_iter_strm_cls(target_hdr, &data, &cl_arr,
2036 __uvcg_fill_strm);
2037 if (ret) {
2038 kfree(*class_array);
2039 *class_array = NULL;
Andrzej Pietrasiewicz06ab8b02015-01-16 15:14:27 +01002040 /*
2041 * __uvcg_fill_strm() called from __uvcg_iter_stream_cls()
2042 * might have advanced the "data", so use a backup copy
2043 */
2044 kfree(data_save);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002045 goto unlock;
2046 }
2047 *cl_arr = (struct uvc_descriptor_header *)&opts->uvc_color_matching;
2048
2049 ++target_hdr->linked;
2050 ret = 0;
2051
2052unlock:
2053 mutex_unlock(&opts->lock);
2054out:
Laurent Pinchart013cf512018-08-02 00:14:00 +03002055 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002056 mutex_unlock(su_mutex);
2057 return ret;
2058}
2059
2060static int uvcg_streaming_class_drop_link(struct config_item *src,
2061 struct config_item *target)
2062{
2063 struct config_item *streaming, *header;
2064 struct f_uvc_opts *opts;
2065 struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
2066 struct uvc_descriptor_header ***class_array;
2067 struct uvcg_streaming_header *target_hdr;
2068 int ret = -EINVAL;
2069
2070 mutex_lock(su_mutex); /* for navigating configfs hierarchy */
2071
2072 streaming = src->ci_parent->ci_parent;
2073 header = config_group_find_item(to_config_group(streaming), "header");
2074 if (!header || target->ci_parent != header)
2075 goto out;
2076
2077 opts = to_f_uvc_opts(streaming->ci_parent);
2078
2079 mutex_lock(&opts->lock);
2080
2081 class_array = __uvcg_get_stream_class_arr(src, opts);
2082 if (!class_array || !*class_array)
2083 goto unlock;
2084
2085 if (opts->refcnt) {
2086 ret = -EBUSY;
2087 goto unlock;
2088 }
2089
2090 target_hdr = to_uvcg_streaming_header(target);
2091 --target_hdr->linked;
2092 kfree(**class_array);
2093 kfree(*class_array);
2094 *class_array = NULL;
2095 ret = 0;
2096
2097unlock:
2098 mutex_unlock(&opts->lock);
2099out:
Laurent Pinchart013cf512018-08-02 00:14:00 +03002100 config_item_put(header);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002101 mutex_unlock(su_mutex);
2102 return ret;
2103}
2104
2105static struct configfs_item_operations uvcg_streaming_class_item_ops = {
2106 .allow_link = uvcg_streaming_class_allow_link,
2107 .drop_link = uvcg_streaming_class_drop_link,
2108};
2109
2110static struct config_item_type uvcg_streaming_class_type = {
2111 .ct_item_ops = &uvcg_streaming_class_item_ops,
2112 .ct_owner = THIS_MODULE,
2113};
2114
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002115/* streaming/class */
2116static struct uvcg_streaming_class_grp {
2117 struct config_group group;
2118} uvcg_streaming_class_grp;
2119
2120static struct config_item_type uvcg_streaming_class_grp_type = {
2121 .ct_owner = THIS_MODULE,
2122};
2123
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002124/* streaming */
2125static struct uvcg_streaming_grp {
2126 struct config_group group;
2127} uvcg_streaming_grp;
2128
2129static struct config_item_type uvcg_streaming_grp_type = {
2130 .ct_owner = THIS_MODULE,
2131};
2132
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002133static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
2134{
2135 return container_of(to_config_group(item), struct f_uvc_opts,
2136 func_inst.group);
2137}
2138
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002139static void uvc_attr_release(struct config_item *item)
2140{
2141 struct f_uvc_opts *opts = to_f_uvc_opts(item);
2142
2143 usb_put_function_instance(&opts->func_inst);
2144}
2145
2146static struct configfs_item_operations uvc_item_ops = {
2147 .release = uvc_attr_release,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002148};
2149
Petr Cvek57ddb8e2017-03-07 00:57:20 +01002150#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002151static ssize_t f_uvc_opts_##cname##_show( \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002152 struct config_item *item, char *page) \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002153{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002154 struct f_uvc_opts *opts = to_f_uvc_opts(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002155 int result; \
2156 \
2157 mutex_lock(&opts->lock); \
2158 result = sprintf(page, "%d\n", conv(opts->cname)); \
2159 mutex_unlock(&opts->lock); \
2160 \
2161 return result; \
2162} \
2163 \
2164static ssize_t \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002165f_uvc_opts_##cname##_store(struct config_item *item, \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002166 const char *page, size_t len) \
2167{ \
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002168 struct f_uvc_opts *opts = to_f_uvc_opts(item); \
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002169 int ret; \
2170 uxx num; \
2171 \
2172 mutex_lock(&opts->lock); \
2173 if (opts->refcnt) { \
2174 ret = -EBUSY; \
2175 goto end; \
2176 } \
2177 \
2178 ret = str2u(page, 0, &num); \
2179 if (ret) \
2180 goto end; \
2181 \
2182 if (num > limit) { \
2183 ret = -EINVAL; \
2184 goto end; \
2185 } \
2186 opts->cname = vnoc(num); \
2187 ret = len; \
2188end: \
2189 mutex_unlock(&opts->lock); \
2190 return ret; \
2191} \
2192 \
Petr Cvek57ddb8e2017-03-07 00:57:20 +01002193UVC_ATTR(f_uvc_opts_, cname, cname)
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002194
2195#define identity_conv(x) (x)
2196
Petr Cvek57ddb8e2017-03-07 00:57:20 +01002197UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
2198 kstrtou8, u8, identity_conv, 16);
2199UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
2200 kstrtou16, u16, le16_to_cpu, 3072);
2201UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
2202 kstrtou8, u8, identity_conv, 15);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002203
2204#undef identity_conv
2205
2206#undef UVCG_OPTS_ATTR
2207
2208static struct configfs_attribute *uvc_attrs[] = {
Christoph Hellwig76e0da32015-10-03 15:32:39 +02002209 &f_uvc_opts_attr_streaming_interval,
2210 &f_uvc_opts_attr_streaming_maxpacket,
2211 &f_uvc_opts_attr_streaming_maxburst,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002212 NULL,
2213};
2214
2215static struct config_item_type uvc_func_type = {
2216 .ct_item_ops = &uvc_item_ops,
2217 .ct_attrs = uvc_attrs,
2218 .ct_owner = THIS_MODULE,
2219};
2220
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002221int uvcg_attach_configfs(struct f_uvc_opts *opts)
2222{
2223 config_group_init_type_name(&uvcg_control_header_grp.group,
2224 "header",
2225 &uvcg_control_header_grp_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002226
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002227 config_group_init_type_name(&uvcg_default_processing.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002228 "default", &uvcg_default_processing_type);
2229 config_group_init_type_name(&uvcg_processing_grp.group,
2230 "processing", &uvcg_processing_grp_type);
2231 configfs_add_default_group(&uvcg_default_processing.group,
2232 &uvcg_processing_grp.group);
2233
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002234 config_group_init_type_name(&uvcg_default_camera.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002235 "default", &uvcg_default_camera_type);
2236 config_group_init_type_name(&uvcg_camera_grp.group,
2237 "camera", &uvcg_camera_grp_type);
2238 configfs_add_default_group(&uvcg_default_camera.group,
2239 &uvcg_camera_grp.group);
2240
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002241 config_group_init_type_name(&uvcg_default_output.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002242 "default", &uvcg_default_output_type);
2243 config_group_init_type_name(&uvcg_output_grp.group,
2244 "output", &uvcg_output_grp_type);
2245 configfs_add_default_group(&uvcg_default_output.group,
2246 &uvcg_output_grp.group);
2247
2248 config_group_init_type_name(&uvcg_terminal_grp.group,
2249 "terminal", &uvcg_terminal_grp_type);
2250 configfs_add_default_group(&uvcg_camera_grp.group,
2251 &uvcg_terminal_grp.group);
2252 configfs_add_default_group(&uvcg_output_grp.group,
2253 &uvcg_terminal_grp.group);
2254
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002255 config_group_init_type_name(&uvcg_control_class_fs.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002256 "fs", &uvcg_control_class_type);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002257 config_group_init_type_name(&uvcg_control_class_ss.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002258 "ss", &uvcg_control_class_type);
2259 config_group_init_type_name(&uvcg_control_class_grp.group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002260 "class",
2261 &uvcg_control_class_grp_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002262 configfs_add_default_group(&uvcg_control_class_fs.group,
2263 &uvcg_control_class_grp.group);
2264 configfs_add_default_group(&uvcg_control_class_ss.group,
2265 &uvcg_control_class_grp.group);
2266
2267 config_group_init_type_name(&uvcg_control_grp.group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002268 "control",
2269 &uvcg_control_grp_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002270 configfs_add_default_group(&uvcg_control_header_grp.group,
2271 &uvcg_control_grp.group);
2272 configfs_add_default_group(&uvcg_processing_grp.group,
2273 &uvcg_control_grp.group);
2274 configfs_add_default_group(&uvcg_terminal_grp.group,
2275 &uvcg_control_grp.group);
2276 configfs_add_default_group(&uvcg_control_class_grp.group,
2277 &uvcg_control_grp.group);
2278
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002279 config_group_init_type_name(&uvcg_streaming_header_grp.group,
2280 "header",
2281 &uvcg_streaming_header_grp_type);
2282 config_group_init_type_name(&uvcg_uncompressed_grp.group,
2283 "uncompressed",
2284 &uvcg_uncompressed_grp_type);
2285 config_group_init_type_name(&uvcg_mjpeg_grp.group,
2286 "mjpeg",
2287 &uvcg_mjpeg_grp_type);
2288 config_group_init_type_name(&uvcg_default_color_matching.group,
2289 "default",
2290 &uvcg_default_color_matching_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002291 config_group_init_type_name(&uvcg_color_matching_grp.group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002292 "color_matching",
2293 &uvcg_color_matching_grp_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002294 configfs_add_default_group(&uvcg_default_color_matching.group,
2295 &uvcg_color_matching_grp.group);
2296
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002297 config_group_init_type_name(&uvcg_streaming_class_fs.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002298 "fs", &uvcg_streaming_class_type);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002299 config_group_init_type_name(&uvcg_streaming_class_hs.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002300 "hs", &uvcg_streaming_class_type);
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002301 config_group_init_type_name(&uvcg_streaming_class_ss.group,
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002302 "ss", &uvcg_streaming_class_type);
2303 config_group_init_type_name(&uvcg_streaming_class_grp.group,
2304 "class", &uvcg_streaming_class_grp_type);
2305 configfs_add_default_group(&uvcg_streaming_class_fs.group,
2306 &uvcg_streaming_class_grp.group);
2307 configfs_add_default_group(&uvcg_streaming_class_hs.group,
2308 &uvcg_streaming_class_grp.group);
2309 configfs_add_default_group(&uvcg_streaming_class_ss.group,
2310 &uvcg_streaming_class_grp.group);
2311
2312 config_group_init_type_name(&uvcg_streaming_grp.group,
2313 "streaming", &uvcg_streaming_grp_type);
2314 configfs_add_default_group(&uvcg_streaming_header_grp.group,
2315 &uvcg_streaming_grp.group);
2316 configfs_add_default_group(&uvcg_uncompressed_grp.group,
2317 &uvcg_streaming_grp.group);
2318 configfs_add_default_group(&uvcg_mjpeg_grp.group,
2319 &uvcg_streaming_grp.group);
2320 configfs_add_default_group(&uvcg_color_matching_grp.group,
2321 &uvcg_streaming_grp.group);
2322 configfs_add_default_group(&uvcg_streaming_class_grp.group,
2323 &uvcg_streaming_grp.group);
2324
2325 config_group_init_type_name(&opts->func_inst.group,
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002326 "",
2327 &uvc_func_type);
Christoph Hellwig1ae16022016-02-26 11:02:14 +01002328 configfs_add_default_group(&uvcg_control_grp.group,
2329 &opts->func_inst.group);
2330 configfs_add_default_group(&uvcg_streaming_grp.group,
2331 &opts->func_inst.group);
2332
Andrzej Pietrasiewicz46919a22014-12-10 12:34:02 +01002333 return 0;
2334}