2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-06-19 10:31:47 +03:00
/*
* V4L2 flash LED sub - device registration helpers .
*
* Copyright ( C ) 2015 Samsung Electronics Co . , Ltd
* Author : Jacek Anaszewski < j . anaszewski @ samsung . com >
*/
# include <linux/led-class-flash.h>
# include <linux/module.h>
# include <linux/mutex.h>
2016-08-31 10:28:46 +03:00
# include <linux/property.h>
2015-06-19 10:31:47 +03:00
# include <linux/slab.h>
# include <linux/types.h>
# include <media/v4l2-flash-led-class.h>
# define has_flash_op(v4l2_flash, op) \
2017-06-08 14:19:49 +03:00
( v4l2_flash & & v4l2_flash - > ops & & v4l2_flash - > ops - > op )
2015-06-19 10:31:47 +03:00
# define call_flash_op(v4l2_flash, op, arg) \
( has_flash_op ( v4l2_flash , op ) ? \
v4l2_flash - > ops - > op ( v4l2_flash , arg ) : \
- EINVAL )
enum ctrl_init_data_id {
LED_MODE ,
TORCH_INTENSITY ,
FLASH_INTENSITY ,
INDICATOR_INTENSITY ,
FLASH_TIMEOUT ,
STROBE_SOURCE ,
/*
* Only above values are applicable to
* the ' ctrls ' array in the struct v4l2_flash .
*/
FLASH_STROBE ,
STROBE_STOP ,
STROBE_STATUS ,
FLASH_FAULT ,
NUM_FLASH_CTRLS ,
} ;
static enum led_brightness __intensity_to_led_brightness (
struct v4l2_ctrl * ctrl , s32 intensity )
{
intensity - = ctrl - > minimum ;
intensity / = ( u32 ) ctrl - > step ;
/*
* Indicator LEDs , unlike torch LEDs , are turned on / off basing on
* the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only .
* Therefore it must be possible to set it to 0 level which in
* the LED subsystem reflects LED_OFF state .
*/
if ( ctrl - > minimum )
+ + intensity ;
return intensity ;
}
static s32 __led_brightness_to_intensity ( struct v4l2_ctrl * ctrl ,
enum led_brightness brightness )
{
/*
* Indicator LEDs , unlike torch LEDs , are turned on / off basing on
* the state of V4L2_CID_FLASH_INDICATOR_INTENSITY control only .
* Do not decrement brightness read from the LED subsystem for
* indicator LED as it may equal 0. For torch LEDs this function
* is called only when V4L2_FLASH_LED_MODE_TORCH is set and the
* brightness read is guaranteed to be greater than 0. In the mode
* V4L2_FLASH_LED_MODE_NONE the cached torch intensity value is used .
*/
if ( ctrl - > id ! = V4L2_CID_FLASH_INDICATOR_INTENSITY )
- - brightness ;
return ( brightness * ctrl - > step ) + ctrl - > minimum ;
}
static void v4l2_flash_set_led_brightness ( struct v4l2_flash * v4l2_flash ,
struct v4l2_ctrl * ctrl )
{
struct v4l2_ctrl * * ctrls = v4l2_flash - > ctrls ;
enum led_brightness brightness ;
if ( has_flash_op ( v4l2_flash , intensity_to_led_brightness ) )
brightness = call_flash_op ( v4l2_flash ,
intensity_to_led_brightness ,
ctrl - > val ) ;
else
brightness = __intensity_to_led_brightness ( ctrl , ctrl - > val ) ;
/*
* In case a LED Flash class driver provides ops for custom
* brightness < - > intensity conversion , it also must have defined
* related v4l2 control step = = 1. In such a case a backward conversion
* from led brightness to v4l2 intensity is required to find out the
* the aligned intensity value .
*/
if ( has_flash_op ( v4l2_flash , led_brightness_to_intensity ) )
ctrl - > val = call_flash_op ( v4l2_flash ,
led_brightness_to_intensity ,
brightness ) ;
if ( ctrl = = ctrls [ TORCH_INTENSITY ] ) {
if ( ctrls [ LED_MODE ] - > val ! = V4L2_FLASH_LED_MODE_TORCH )
return ;
2015-10-07 12:10:48 +03:00
led_set_brightness_sync ( & v4l2_flash - > fled_cdev - > led_cdev ,
2015-06-19 10:31:47 +03:00
brightness ) ;
} else {
2017-06-02 12:30:02 +03:00
led_set_brightness_sync ( v4l2_flash - > iled_cdev ,
2015-06-19 10:31:47 +03:00
brightness ) ;
}
}
static int v4l2_flash_update_led_brightness ( struct v4l2_flash * v4l2_flash ,
struct v4l2_ctrl * ctrl )
{
struct v4l2_ctrl * * ctrls = v4l2_flash - > ctrls ;
struct led_classdev * led_cdev ;
int ret ;
if ( ctrl = = ctrls [ TORCH_INTENSITY ] ) {
/*
* Update torch brightness only if in TORCH_MODE . In other modes
* torch led is turned off , which would spuriously inform the
* user space that V4L2_CID_FLASH_TORCH_INTENSITY control value
* has changed to 0.
*/
if ( ctrls [ LED_MODE ] - > val ! = V4L2_FLASH_LED_MODE_TORCH )
return 0 ;
led_cdev = & v4l2_flash - > fled_cdev - > led_cdev ;
} else {
2017-06-02 12:30:02 +03:00
led_cdev = v4l2_flash - > iled_cdev ;
2015-06-19 10:31:47 +03:00
}
ret = led_update_brightness ( led_cdev ) ;
if ( ret < 0 )
return ret ;
if ( has_flash_op ( v4l2_flash , led_brightness_to_intensity ) )
ctrl - > val = call_flash_op ( v4l2_flash ,
led_brightness_to_intensity ,
led_cdev - > brightness ) ;
else
ctrl - > val = __led_brightness_to_intensity ( ctrl ,
led_cdev - > brightness ) ;
return 0 ;
}
static int v4l2_flash_g_volatile_ctrl ( struct v4l2_ctrl * c )
{
struct v4l2_flash * v4l2_flash = v4l2_ctrl_to_v4l2_flash ( c ) ;
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
bool is_strobing ;
int ret ;
switch ( c - > id ) {
case V4L2_CID_FLASH_TORCH_INTENSITY :
case V4L2_CID_FLASH_INDICATOR_INTENSITY :
return v4l2_flash_update_led_brightness ( v4l2_flash , c ) ;
case V4L2_CID_FLASH_INTENSITY :
ret = led_update_flash_brightness ( fled_cdev ) ;
if ( ret < 0 )
return ret ;
/*
* No conversion is needed as LED Flash class also uses
* microamperes for flash intensity units .
*/
c - > val = fled_cdev - > brightness . val ;
return 0 ;
case V4L2_CID_FLASH_STROBE_STATUS :
ret = led_get_flash_strobe ( fled_cdev , & is_strobing ) ;
if ( ret < 0 )
return ret ;
c - > val = is_strobing ;
return 0 ;
case V4L2_CID_FLASH_FAULT :
/* LED faults map directly to V4L2 flash faults */
return led_get_flash_fault ( fled_cdev , & c - > val ) ;
default :
return - EINVAL ;
}
}
static bool __software_strobe_mode_inactive ( struct v4l2_ctrl * * ctrls )
{
return ( ( ctrls [ LED_MODE ] - > val ! = V4L2_FLASH_LED_MODE_FLASH ) | |
( ctrls [ STROBE_SOURCE ] & & ( ctrls [ STROBE_SOURCE ] - > val ! =
V4L2_FLASH_STROBE_SOURCE_SOFTWARE ) ) ) ;
}
static int v4l2_flash_s_ctrl ( struct v4l2_ctrl * c )
{
struct v4l2_flash * v4l2_flash = v4l2_ctrl_to_v4l2_flash ( c ) ;
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
2017-07-18 16:26:59 +03:00
struct led_classdev * led_cdev = fled_cdev ? & fled_cdev - > led_cdev : NULL ;
2015-06-19 10:31:47 +03:00
struct v4l2_ctrl * * ctrls = v4l2_flash - > ctrls ;
bool external_strobe ;
int ret = 0 ;
switch ( c - > id ) {
case V4L2_CID_FLASH_LED_MODE :
switch ( c - > val ) {
case V4L2_FLASH_LED_MODE_NONE :
2015-10-07 12:10:48 +03:00
led_set_brightness_sync ( led_cdev , LED_OFF ) ;
2015-06-19 10:31:47 +03:00
return led_set_flash_strobe ( fled_cdev , false ) ;
case V4L2_FLASH_LED_MODE_FLASH :
/* Turn the torch LED off */
2015-10-07 12:10:48 +03:00
led_set_brightness_sync ( led_cdev , LED_OFF ) ;
2015-06-19 10:31:47 +03:00
if ( ctrls [ STROBE_SOURCE ] ) {
external_strobe = ( ctrls [ STROBE_SOURCE ] - > val = =
V4L2_FLASH_STROBE_SOURCE_EXTERNAL ) ;
ret = call_flash_op ( v4l2_flash ,
external_strobe_set ,
external_strobe ) ;
}
return ret ;
case V4L2_FLASH_LED_MODE_TORCH :
if ( ctrls [ STROBE_SOURCE ] ) {
ret = call_flash_op ( v4l2_flash ,
external_strobe_set ,
false ) ;
if ( ret < 0 )
return ret ;
}
/* Stop flash strobing */
ret = led_set_flash_strobe ( fled_cdev , false ) ;
if ( ret < 0 )
return ret ;
v4l2_flash_set_led_brightness ( v4l2_flash ,
ctrls [ TORCH_INTENSITY ] ) ;
return 0 ;
}
break ;
case V4L2_CID_FLASH_STROBE_SOURCE :
external_strobe = ( c - > val = = V4L2_FLASH_STROBE_SOURCE_EXTERNAL ) ;
/*
* For some hardware arrangements setting strobe source may
* affect torch mode . Therefore , if not in the flash mode ,
* cache only this setting . It will be applied upon switching
* to flash mode .
*/
if ( ctrls [ LED_MODE ] - > val ! = V4L2_FLASH_LED_MODE_FLASH )
return 0 ;
return call_flash_op ( v4l2_flash , external_strobe_set ,
external_strobe ) ;
case V4L2_CID_FLASH_STROBE :
if ( __software_strobe_mode_inactive ( ctrls ) )
return - EBUSY ;
return led_set_flash_strobe ( fled_cdev , true ) ;
case V4L2_CID_FLASH_STROBE_STOP :
if ( __software_strobe_mode_inactive ( ctrls ) )
return - EBUSY ;
return led_set_flash_strobe ( fled_cdev , false ) ;
case V4L2_CID_FLASH_TIMEOUT :
/*
* No conversion is needed as LED Flash class also uses
* microseconds for flash timeout units .
*/
return led_set_flash_timeout ( fled_cdev , c - > val ) ;
case V4L2_CID_FLASH_INTENSITY :
/*
* No conversion is needed as LED Flash class also uses
* microamperes for flash intensity units .
*/
return led_set_flash_brightness ( fled_cdev , c - > val ) ;
case V4L2_CID_FLASH_TORCH_INTENSITY :
case V4L2_CID_FLASH_INDICATOR_INTENSITY :
v4l2_flash_set_led_brightness ( v4l2_flash , c ) ;
return 0 ;
}
return - EINVAL ;
}
static const struct v4l2_ctrl_ops v4l2_flash_ctrl_ops = {
. g_volatile_ctrl = v4l2_flash_g_volatile_ctrl ,
. s_ctrl = v4l2_flash_s_ctrl ,
} ;
static void __lfs_to_v4l2_ctrl_config ( struct led_flash_setting * s ,
struct v4l2_ctrl_config * c )
{
c - > min = s - > min ;
c - > max = s - > max ;
c - > step = s - > step ;
c - > def = s - > val ;
}
static void __fill_ctrl_init_data ( struct v4l2_flash * v4l2_flash ,
struct v4l2_flash_config * flash_cfg ,
struct v4l2_flash_ctrl_data * ctrl_init_data )
{
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
2017-07-18 16:26:59 +03:00
struct led_classdev * led_cdev = fled_cdev ? & fled_cdev - > led_cdev : NULL ;
2015-06-19 10:31:47 +03:00
struct v4l2_ctrl_config * ctrl_cfg ;
u32 mask ;
2017-07-18 16:26:59 +03:00
/* Init INDICATOR_INTENSITY ctrl data */
if ( v4l2_flash - > iled_cdev ) {
ctrl_init_data [ INDICATOR_INTENSITY ] . cid =
V4L2_CID_FLASH_INDICATOR_INTENSITY ;
ctrl_cfg = & ctrl_init_data [ INDICATOR_INTENSITY ] . config ;
__lfs_to_v4l2_ctrl_config ( & flash_cfg - > intensity ,
ctrl_cfg ) ;
ctrl_cfg - > id = V4L2_CID_FLASH_INDICATOR_INTENSITY ;
ctrl_cfg - > min = 0 ;
ctrl_cfg - > flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE ;
}
if ( ! led_cdev | | WARN_ON ( ! ( led_cdev - > flags & LED_DEV_CAP_FLASH ) ) )
return ;
2015-06-19 10:31:47 +03:00
/* Init FLASH_FAULT ctrl data */
if ( flash_cfg - > flash_faults ) {
ctrl_init_data [ FLASH_FAULT ] . cid = V4L2_CID_FLASH_FAULT ;
ctrl_cfg = & ctrl_init_data [ FLASH_FAULT ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_FAULT ;
ctrl_cfg - > max = flash_cfg - > flash_faults ;
ctrl_cfg - > flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_READ_ONLY ;
}
/* Init FLASH_LED_MODE ctrl data */
mask = 1 < < V4L2_FLASH_LED_MODE_NONE |
1 < < V4L2_FLASH_LED_MODE_TORCH ;
if ( led_cdev - > flags & LED_DEV_CAP_FLASH )
mask | = 1 < < V4L2_FLASH_LED_MODE_FLASH ;
ctrl_init_data [ LED_MODE ] . cid = V4L2_CID_FLASH_LED_MODE ;
ctrl_cfg = & ctrl_init_data [ LED_MODE ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_LED_MODE ;
ctrl_cfg - > max = V4L2_FLASH_LED_MODE_TORCH ;
ctrl_cfg - > menu_skip_mask = ~ mask ;
ctrl_cfg - > def = V4L2_FLASH_LED_MODE_NONE ;
ctrl_cfg - > flags = 0 ;
/* Init TORCH_INTENSITY ctrl data */
ctrl_init_data [ TORCH_INTENSITY ] . cid = V4L2_CID_FLASH_TORCH_INTENSITY ;
ctrl_cfg = & ctrl_init_data [ TORCH_INTENSITY ] . config ;
2017-07-18 16:26:59 +03:00
__lfs_to_v4l2_ctrl_config ( & flash_cfg - > intensity , ctrl_cfg ) ;
2015-06-19 10:31:47 +03:00
ctrl_cfg - > id = V4L2_CID_FLASH_TORCH_INTENSITY ;
ctrl_cfg - > flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE ;
/* Init FLASH_STROBE ctrl data */
ctrl_init_data [ FLASH_STROBE ] . cid = V4L2_CID_FLASH_STROBE ;
ctrl_cfg = & ctrl_init_data [ FLASH_STROBE ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_STROBE ;
/* Init STROBE_STOP ctrl data */
ctrl_init_data [ STROBE_STOP ] . cid = V4L2_CID_FLASH_STROBE_STOP ;
ctrl_cfg = & ctrl_init_data [ STROBE_STOP ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_STROBE_STOP ;
/* Init FLASH_STROBE_SOURCE ctrl data */
if ( flash_cfg - > has_external_strobe ) {
mask = ( 1 < < V4L2_FLASH_STROBE_SOURCE_SOFTWARE ) |
( 1 < < V4L2_FLASH_STROBE_SOURCE_EXTERNAL ) ;
ctrl_init_data [ STROBE_SOURCE ] . cid =
V4L2_CID_FLASH_STROBE_SOURCE ;
ctrl_cfg = & ctrl_init_data [ STROBE_SOURCE ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_STROBE_SOURCE ;
ctrl_cfg - > max = V4L2_FLASH_STROBE_SOURCE_EXTERNAL ;
ctrl_cfg - > menu_skip_mask = ~ mask ;
ctrl_cfg - > def = V4L2_FLASH_STROBE_SOURCE_SOFTWARE ;
}
/* Init STROBE_STATUS ctrl data */
2017-06-08 14:19:49 +03:00
if ( has_flash_op ( fled_cdev , strobe_get ) ) {
2015-06-19 10:31:47 +03:00
ctrl_init_data [ STROBE_STATUS ] . cid =
V4L2_CID_FLASH_STROBE_STATUS ;
ctrl_cfg = & ctrl_init_data [ STROBE_STATUS ] . config ;
ctrl_cfg - > id = V4L2_CID_FLASH_STROBE_STATUS ;
ctrl_cfg - > flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_READ_ONLY ;
}
/* Init FLASH_TIMEOUT ctrl data */
2017-06-08 14:19:49 +03:00
if ( has_flash_op ( fled_cdev , timeout_set ) ) {
2015-06-19 10:31:47 +03:00
ctrl_init_data [ FLASH_TIMEOUT ] . cid = V4L2_CID_FLASH_TIMEOUT ;
ctrl_cfg = & ctrl_init_data [ FLASH_TIMEOUT ] . config ;
__lfs_to_v4l2_ctrl_config ( & fled_cdev - > timeout , ctrl_cfg ) ;
ctrl_cfg - > id = V4L2_CID_FLASH_TIMEOUT ;
}
/* Init FLASH_INTENSITY ctrl data */
2017-06-08 14:19:49 +03:00
if ( has_flash_op ( fled_cdev , flash_brightness_set ) ) {
2015-06-19 10:31:47 +03:00
ctrl_init_data [ FLASH_INTENSITY ] . cid = V4L2_CID_FLASH_INTENSITY ;
ctrl_cfg = & ctrl_init_data [ FLASH_INTENSITY ] . config ;
__lfs_to_v4l2_ctrl_config ( & fled_cdev - > brightness , ctrl_cfg ) ;
ctrl_cfg - > id = V4L2_CID_FLASH_INTENSITY ;
ctrl_cfg - > flags = V4L2_CTRL_FLAG_VOLATILE |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE ;
}
}
static int v4l2_flash_init_controls ( struct v4l2_flash * v4l2_flash ,
struct v4l2_flash_config * flash_cfg )
{
struct v4l2_flash_ctrl_data * ctrl_init_data ;
struct v4l2_ctrl * ctrl ;
struct v4l2_ctrl_config * ctrl_cfg ;
int i , ret , num_ctrls = 0 ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:07:58 +03:00
v4l2_flash - > ctrls = devm_kcalloc ( v4l2_flash - > sd . dev ,
STROBE_SOURCE + 1 ,
sizeof ( * v4l2_flash - > ctrls ) ,
GFP_KERNEL ) ;
2015-06-19 10:31:47 +03:00
if ( ! v4l2_flash - > ctrls )
return - ENOMEM ;
/* allocate memory dynamically so as not to exceed stack frame size */
ctrl_init_data = kcalloc ( NUM_FLASH_CTRLS , sizeof ( * ctrl_init_data ) ,
GFP_KERNEL ) ;
if ( ! ctrl_init_data )
return - ENOMEM ;
__fill_ctrl_init_data ( v4l2_flash , flash_cfg , ctrl_init_data ) ;
for ( i = 0 ; i < NUM_FLASH_CTRLS ; + + i )
if ( ctrl_init_data [ i ] . cid )
+ + num_ctrls ;
v4l2_ctrl_handler_init ( & v4l2_flash - > hdl , num_ctrls ) ;
for ( i = 0 ; i < NUM_FLASH_CTRLS ; + + i ) {
ctrl_cfg = & ctrl_init_data [ i ] . config ;
if ( ! ctrl_init_data [ i ] . cid )
continue ;
if ( ctrl_cfg - > id = = V4L2_CID_FLASH_LED_MODE | |
ctrl_cfg - > id = = V4L2_CID_FLASH_STROBE_SOURCE )
ctrl = v4l2_ctrl_new_std_menu ( & v4l2_flash - > hdl ,
& v4l2_flash_ctrl_ops ,
ctrl_cfg - > id ,
ctrl_cfg - > max ,
ctrl_cfg - > menu_skip_mask ,
ctrl_cfg - > def ) ;
else
ctrl = v4l2_ctrl_new_std ( & v4l2_flash - > hdl ,
& v4l2_flash_ctrl_ops ,
ctrl_cfg - > id ,
ctrl_cfg - > min ,
ctrl_cfg - > max ,
ctrl_cfg - > step ,
ctrl_cfg - > def ) ;
if ( ctrl )
ctrl - > flags | = ctrl_cfg - > flags ;
if ( i < = STROBE_SOURCE )
v4l2_flash - > ctrls [ i ] = ctrl ;
}
kfree ( ctrl_init_data ) ;
if ( v4l2_flash - > hdl . error ) {
ret = v4l2_flash - > hdl . error ;
goto error_free_handler ;
}
v4l2_ctrl_handler_setup ( & v4l2_flash - > hdl ) ;
v4l2_flash - > sd . ctrl_handler = & v4l2_flash - > hdl ;
return 0 ;
error_free_handler :
v4l2_ctrl_handler_free ( & v4l2_flash - > hdl ) ;
return ret ;
}
static int __sync_device_with_v4l2_controls ( struct v4l2_flash * v4l2_flash )
{
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
struct v4l2_ctrl * * ctrls = v4l2_flash - > ctrls ;
int ret = 0 ;
2017-07-18 16:26:59 +03:00
if ( ctrls [ TORCH_INTENSITY ] )
v4l2_flash_set_led_brightness ( v4l2_flash ,
ctrls [ TORCH_INTENSITY ] ) ;
2015-06-19 10:31:47 +03:00
if ( ctrls [ INDICATOR_INTENSITY ] )
v4l2_flash_set_led_brightness ( v4l2_flash ,
ctrls [ INDICATOR_INTENSITY ] ) ;
if ( ctrls [ FLASH_TIMEOUT ] ) {
ret = led_set_flash_timeout ( fled_cdev ,
ctrls [ FLASH_TIMEOUT ] - > val ) ;
if ( ret < 0 )
return ret ;
}
if ( ctrls [ FLASH_INTENSITY ] ) {
ret = led_set_flash_brightness ( fled_cdev ,
ctrls [ FLASH_INTENSITY ] - > val ) ;
if ( ret < 0 )
return ret ;
}
/*
* For some hardware arrangements setting strobe source may affect
* torch mode . Synchronize strobe source setting only if not in torch
* mode . For torch mode case it will get synchronized upon switching
* to flash mode .
*/
if ( ctrls [ STROBE_SOURCE ] & &
ctrls [ LED_MODE ] - > val ! = V4L2_FLASH_LED_MODE_TORCH )
ret = call_flash_op ( v4l2_flash , external_strobe_set ,
ctrls [ STROBE_SOURCE ] - > val ) ;
return ret ;
}
/*
* V4L2 subdev internal operations
*/
static int v4l2_flash_open ( struct v4l2_subdev * sd , struct v4l2_subdev_fh * fh )
{
struct v4l2_flash * v4l2_flash = v4l2_subdev_to_v4l2_flash ( sd ) ;
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
2017-07-18 16:26:59 +03:00
struct led_classdev * led_cdev = fled_cdev ? & fled_cdev - > led_cdev : NULL ;
2017-06-02 12:30:02 +03:00
struct led_classdev * led_cdev_ind = v4l2_flash - > iled_cdev ;
2015-06-19 10:31:47 +03:00
int ret = 0 ;
if ( ! v4l2_fh_is_singular ( & fh - > vfh ) )
return 0 ;
2017-07-18 16:26:59 +03:00
if ( led_cdev ) {
mutex_lock ( & led_cdev - > led_access ) ;
2015-06-19 10:31:47 +03:00
2017-07-18 16:26:59 +03:00
led_sysfs_disable ( led_cdev ) ;
led_trigger_remove ( led_cdev ) ;
2015-06-19 10:31:47 +03:00
2017-07-18 16:26:59 +03:00
mutex_unlock ( & led_cdev - > led_access ) ;
}
2015-06-19 10:31:47 +03:00
2017-06-02 12:30:02 +03:00
if ( led_cdev_ind ) {
2015-06-19 10:31:47 +03:00
mutex_lock ( & led_cdev_ind - > led_access ) ;
led_sysfs_disable ( led_cdev_ind ) ;
led_trigger_remove ( led_cdev_ind ) ;
mutex_unlock ( & led_cdev_ind - > led_access ) ;
}
ret = __sync_device_with_v4l2_controls ( v4l2_flash ) ;
if ( ret < 0 )
goto out_sync_device ;
return 0 ;
out_sync_device :
2017-07-18 16:26:59 +03:00
if ( led_cdev ) {
mutex_lock ( & led_cdev - > led_access ) ;
led_sysfs_enable ( led_cdev ) ;
mutex_unlock ( & led_cdev - > led_access ) ;
}
2015-06-19 10:31:47 +03:00
if ( led_cdev_ind ) {
mutex_lock ( & led_cdev_ind - > led_access ) ;
led_sysfs_enable ( led_cdev_ind ) ;
mutex_unlock ( & led_cdev_ind - > led_access ) ;
}
return ret ;
}
static int v4l2_flash_close ( struct v4l2_subdev * sd , struct v4l2_subdev_fh * fh )
{
struct v4l2_flash * v4l2_flash = v4l2_subdev_to_v4l2_flash ( sd ) ;
struct led_classdev_flash * fled_cdev = v4l2_flash - > fled_cdev ;
2017-07-18 16:26:59 +03:00
struct led_classdev * led_cdev = fled_cdev ? & fled_cdev - > led_cdev : NULL ;
2017-06-02 12:30:02 +03:00
struct led_classdev * led_cdev_ind = v4l2_flash - > iled_cdev ;
2015-06-19 10:31:47 +03:00
int ret = 0 ;
if ( ! v4l2_fh_is_singular ( & fh - > vfh ) )
return 0 ;
2017-07-18 16:26:59 +03:00
if ( led_cdev ) {
mutex_lock ( & led_cdev - > led_access ) ;
2015-06-19 10:31:47 +03:00
2017-07-18 16:26:59 +03:00
if ( v4l2_flash - > ctrls [ STROBE_SOURCE ] )
ret = v4l2_ctrl_s_ctrl (
v4l2_flash - > ctrls [ STROBE_SOURCE ] ,
2015-06-19 10:31:47 +03:00
V4L2_FLASH_STROBE_SOURCE_SOFTWARE ) ;
2017-07-18 16:26:59 +03:00
led_sysfs_enable ( led_cdev ) ;
2015-06-19 10:31:47 +03:00
2017-07-18 16:26:59 +03:00
mutex_unlock ( & led_cdev - > led_access ) ;
}
2015-06-19 10:31:47 +03:00
2017-06-02 12:30:02 +03:00
if ( led_cdev_ind ) {
2015-06-19 10:31:47 +03:00
mutex_lock ( & led_cdev_ind - > led_access ) ;
led_sysfs_enable ( led_cdev_ind ) ;
mutex_unlock ( & led_cdev_ind - > led_access ) ;
}
return ret ;
}
static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = {
. open = v4l2_flash_open ,
. close = v4l2_flash_close ,
} ;
2016-07-03 15:20:46 +03:00
static const struct v4l2_subdev_ops v4l2_flash_subdev_ops ;
2015-06-19 10:31:47 +03:00
2017-07-18 16:26:59 +03:00
static struct v4l2_flash * __v4l2_flash_init (
2016-08-31 10:28:46 +03:00
struct device * dev , struct fwnode_handle * fwn ,
2017-07-18 16:26:59 +03:00
struct led_classdev_flash * fled_cdev , struct led_classdev * iled_cdev ,
const struct v4l2_flash_ops * ops , struct v4l2_flash_config * config )
2015-06-19 10:31:47 +03:00
{
struct v4l2_flash * v4l2_flash ;
struct v4l2_subdev * sd ;
int ret ;
2017-07-18 16:26:59 +03:00
if ( ! config )
2015-06-19 10:31:47 +03:00
return ERR_PTR ( - EINVAL ) ;
2017-07-18 16:26:59 +03:00
v4l2_flash = devm_kzalloc ( dev , sizeof ( * v4l2_flash ) , GFP_KERNEL ) ;
2015-06-19 10:31:47 +03:00
if ( ! v4l2_flash )
return ERR_PTR ( - ENOMEM ) ;
sd = & v4l2_flash - > sd ;
v4l2_flash - > fled_cdev = fled_cdev ;
v4l2_flash - > iled_cdev = iled_cdev ;
v4l2_flash - > ops = ops ;
sd - > dev = dev ;
2017-07-18 16:26:59 +03:00
sd - > fwnode = fwn ? fwn : dev_fwnode ( dev ) ;
2015-06-19 10:31:47 +03:00
v4l2_subdev_init ( sd , & v4l2_flash_subdev_ops ) ;
sd - > internal_ops = & v4l2_flash_subdev_internal_ops ;
sd - > flags | = V4L2_SUBDEV_FL_HAS_DEVNODE ;
2018-09-10 15:19:14 +03:00
strscpy ( sd - > name , config - > dev_name , sizeof ( sd - > name ) ) ;
2015-06-19 10:31:47 +03:00
2015-12-11 12:44:40 +03:00
ret = media_entity_pads_init ( & sd - > entity , 0 , NULL ) ;
2015-06-19 10:31:47 +03:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
2015-12-10 22:25:41 +03:00
sd - > entity . function = MEDIA_ENT_F_FLASH ;
2015-06-19 10:31:47 +03:00
ret = v4l2_flash_init_controls ( v4l2_flash , config ) ;
if ( ret < 0 )
goto err_init_controls ;
2016-08-31 10:28:46 +03:00
fwnode_handle_get ( sd - > fwnode ) ;
2015-06-19 10:31:47 +03:00
ret = v4l2_async_register_subdev ( sd ) ;
if ( ret < 0 )
goto err_async_register_sd ;
return v4l2_flash ;
err_async_register_sd :
2016-08-31 10:28:46 +03:00
fwnode_handle_put ( sd - > fwnode ) ;
2015-06-19 10:31:47 +03:00
v4l2_ctrl_handler_free ( sd - > ctrl_handler ) ;
err_init_controls :
media_entity_cleanup ( & sd - > entity ) ;
return ERR_PTR ( ret ) ;
}
2017-07-18 16:26:59 +03:00
struct v4l2_flash * v4l2_flash_init (
struct device * dev , struct fwnode_handle * fwn ,
struct led_classdev_flash * fled_cdev ,
const struct v4l2_flash_ops * ops ,
struct v4l2_flash_config * config )
{
return __v4l2_flash_init ( dev , fwn , fled_cdev , NULL , ops , config ) ;
}
2015-06-19 10:31:47 +03:00
EXPORT_SYMBOL_GPL ( v4l2_flash_init ) ;
2017-07-18 16:26:59 +03:00
struct v4l2_flash * v4l2_flash_indicator_init (
struct device * dev , struct fwnode_handle * fwn ,
struct led_classdev * iled_cdev ,
struct v4l2_flash_config * config )
{
return __v4l2_flash_init ( dev , fwn , NULL , iled_cdev , NULL , config ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_flash_indicator_init ) ;
2015-06-19 10:31:47 +03:00
void v4l2_flash_release ( struct v4l2_flash * v4l2_flash )
{
struct v4l2_subdev * sd ;
if ( IS_ERR_OR_NULL ( v4l2_flash ) )
return ;
sd = & v4l2_flash - > sd ;
v4l2_async_unregister_subdev ( sd ) ;
2016-08-31 10:28:46 +03:00
fwnode_handle_put ( sd - > fwnode ) ;
2015-06-19 10:31:47 +03:00
v4l2_ctrl_handler_free ( sd - > ctrl_handler ) ;
media_entity_cleanup ( & sd - > entity ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_flash_release ) ;
MODULE_AUTHOR ( " Jacek Anaszewski <j.anaszewski@samsung.com> " ) ;
MODULE_DESCRIPTION ( " V4L2 Flash sub-device helpers " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;