Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: uvc: Make bmControls attr read/write

For the Processing Unit and Camera Terminal descriptors defined in
the UVC Gadget we currently hard-code values into their bmControls
fields, which enumerates which controls the gadget is able to
support. This isn't appropriate since only the userspace companion
program to the kernel driver will know which controls are supported.
Make the configfs attributes that point to those fields read/write
so userspace can set them to appropriate values.

Document the new behaviour at the same time so the functionality is
clear.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Link: https://lore.kernel.org/r/20230309105825.216745-1-dan.scally@ideasonboard.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Daniel Scally and committed by
Greg Kroah-Hartman
7bf1c56a 0d6a119c

+149 -4
+2 -2
Documentation/ABI/testing/configfs-usb-gadget-uvc
··· 76 76 KernelVersion: 4.0 77 77 Description: Default camera terminal descriptors 78 78 79 - All attributes read only: 79 + All attributes read only except bmControls, which is read/write: 80 80 81 81 ======================== ==================================== 82 82 bmControls bitmap specifying which controls are ··· 101 101 KernelVersion: 4.0 102 102 Description: Default processing unit descriptors 103 103 104 - All attributes read only: 104 + All attributes read only except bmControls, which is read/write: 105 105 106 106 =============== ======================================== 107 107 iProcessing index of string descriptor
+28
Documentation/usb/gadget_uvc.rst
··· 275 275 276 276 bNrInPins and baSourceID function in the same way. 277 277 278 + Configuring Supported Controls for Camera Terminal and Processing Unit 279 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 280 + 281 + The Camera Terminal and Processing Units in the UVC chain also have bmControls 282 + attributes which function similarly to the same field in an Extension Unit. 283 + Unlike XUs however, the meaning of the bitflag for these units is defined in 284 + the UVC specification; you should consult the "Camera Terminal Descriptor" and 285 + "Processing Unit Descriptor" sections for an enumeration of the flags. 286 + 287 + .. code-block:: bash 288 + 289 + # Set the Processing Unit's bmControls, flagging Brightness, Contrast 290 + # and Hue as available controls: 291 + echo 0x05 > $FUNCTION/control/processing/default/bmControls 292 + 293 + # Set the Camera Terminal's bmControls, flagging Focus Absolute and 294 + # Focus Relative as available controls: 295 + echo 0x60 > $FUNCTION/control/terminal/camera/default/bmControls 296 + 297 + If you do not set these fields then by default the Auto-Exposure Mode control 298 + for the Camera Terminal and the Brightness control for the Processing Unit will 299 + be flagged as available; if they are not supported you should set the field to 300 + 0x00. 301 + 302 + Note that the size of the bmControls field for a Camera Terminal or Processing 303 + Unit is fixed by the UVC specification, and so the bControlSize attribute is 304 + read-only here. 305 + 278 306 Custom Strings Support 279 307 ~~~~~~~~~~~~~~~~~~~~~~ 280 308
+119 -2
drivers/usb/gadget/function/uvc_configfs.c
··· 334 334 335 335 #undef UVCG_DEFAULT_PROCESSING_ATTR 336 336 337 + static ssize_t uvcg_default_processing_bm_controls_store( 338 + struct config_item *item, const char *page, size_t len) 339 + { 340 + struct config_group *group = to_config_group(item); 341 + struct mutex *su_mutex = &group->cg_subsys->su_mutex; 342 + struct uvc_processing_unit_descriptor *pd; 343 + struct config_item *opts_item; 344 + struct f_uvc_opts *opts; 345 + u8 *bm_controls, *tmp; 346 + unsigned int i; 347 + int ret, n = 0; 348 + 349 + mutex_lock(su_mutex); 350 + 351 + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; 352 + opts = to_f_uvc_opts(opts_item); 353 + pd = &opts->uvc_processing; 354 + 355 + mutex_lock(&opts->lock); 356 + if (opts->refcnt) { 357 + ret = -EBUSY; 358 + goto unlock; 359 + } 360 + 361 + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, 362 + sizeof(u8)); 363 + if (ret) 364 + goto unlock; 365 + 366 + if (n > pd->bControlSize) { 367 + ret = -EINVAL; 368 + goto unlock; 369 + } 370 + 371 + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); 372 + if (!bm_controls) { 373 + ret = -ENOMEM; 374 + goto unlock; 375 + } 376 + 377 + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, 378 + sizeof(u8)); 379 + if (ret) 380 + goto free_mem; 381 + 382 + for (i = 0; i < n; i++) 383 + pd->bmControls[i] = bm_controls[i]; 384 + 385 + ret = len; 386 + 387 + free_mem: 388 + kfree(bm_controls); 389 + unlock: 390 + mutex_unlock(&opts->lock); 391 + mutex_unlock(su_mutex); 392 + return ret; 393 + } 394 + 337 395 static ssize_t uvcg_default_processing_bm_controls_show( 338 396 struct config_item *item, char *page) 339 397 { ··· 421 363 return result; 422 364 } 423 365 424 - UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); 366 + UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls); 425 367 426 368 static struct configfs_attribute *uvcg_default_processing_attrs[] = { 427 369 &uvcg_default_processing_attr_b_unit_id, ··· 503 445 504 446 #undef UVCG_DEFAULT_CAMERA_ATTR 505 447 448 + static ssize_t uvcg_default_camera_bm_controls_store( 449 + struct config_item *item, const char *page, size_t len) 450 + { 451 + struct config_group *group = to_config_group(item); 452 + struct mutex *su_mutex = &group->cg_subsys->su_mutex; 453 + struct uvc_camera_terminal_descriptor *cd; 454 + struct config_item *opts_item; 455 + struct f_uvc_opts *opts; 456 + u8 *bm_controls, *tmp; 457 + unsigned int i; 458 + int ret, n = 0; 459 + 460 + mutex_lock(su_mutex); 461 + 462 + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> 463 + ci_parent; 464 + opts = to_f_uvc_opts(opts_item); 465 + cd = &opts->uvc_camera_terminal; 466 + 467 + mutex_lock(&opts->lock); 468 + if (opts->refcnt) { 469 + ret = -EBUSY; 470 + goto unlock; 471 + } 472 + 473 + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, 474 + sizeof(u8)); 475 + if (ret) 476 + goto unlock; 477 + 478 + if (n > cd->bControlSize) { 479 + ret = -EINVAL; 480 + goto unlock; 481 + } 482 + 483 + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); 484 + if (!bm_controls) { 485 + ret = -ENOMEM; 486 + goto unlock; 487 + } 488 + 489 + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, 490 + sizeof(u8)); 491 + if (ret) 492 + goto free_mem; 493 + 494 + for (i = 0; i < n; i++) 495 + cd->bmControls[i] = bm_controls[i]; 496 + 497 + ret = len; 498 + 499 + free_mem: 500 + kfree(bm_controls); 501 + unlock: 502 + mutex_unlock(&opts->lock); 503 + mutex_unlock(su_mutex); 504 + return ret; 505 + } 506 + 506 507 static ssize_t uvcg_default_camera_bm_controls_show( 507 508 struct config_item *item, char *page) 508 509 { ··· 591 474 return result; 592 475 } 593 476 594 - UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); 477 + UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls); 595 478 596 479 static struct configfs_attribute *uvcg_default_camera_attrs[] = { 597 480 &uvcg_default_camera_attr_b_terminal_id,