2015-02-02 12:26:25 +01:00
/*
* cros_ec_dev - expose the Chrome OS Embedded Controller to user - space
*
* Copyright ( C ) 2014 Google , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/fs.h>
2016-08-01 11:54:38 +02:00
# include <linux/mfd/core.h>
2015-02-02 12:26:25 +01:00
# include <linux/module.h>
2018-06-19 22:47:28 -07:00
# include <linux/mod_devicetable.h>
2015-02-02 12:26:25 +01:00
# include <linux/platform_device.h>
2017-05-16 17:46:48 +02:00
# include <linux/pm.h>
2015-06-09 13:04:42 +02:00
# include <linux/slab.h>
2015-02-02 12:26:25 +01:00
# include <linux/uaccess.h>
# include "cros_ec_dev.h"
2017-11-20 17:15:25 +01:00
# define DRV_NAME "cros-ec-dev"
2015-02-02 12:26:25 +01:00
/* Device variables */
# define CROS_MAX_DEV 128
static int ec_major ;
2015-06-09 13:04:47 +02:00
static const struct attribute_group * cros_ec_groups [ ] = {
& cros_ec_attr_group ,
& cros_ec_lightbar_attr_group ,
2015-09-21 10:38:22 -03:00
& cros_ec_vbc_attr_group ,
2015-06-09 13:04:47 +02:00
NULL ,
} ;
static struct class cros_class = {
. owner = THIS_MODULE ,
. name = " chromeos " ,
. dev_groups = cros_ec_groups ,
} ;
2015-02-02 12:26:25 +01:00
/* Basic communication */
2015-06-09 13:04:47 +02:00
static int ec_get_version ( struct cros_ec_dev * ec , char * str , int maxlen )
2015-02-02 12:26:25 +01:00
{
struct ec_response_get_version * resp ;
static const char * const current_image_name [ ] = {
" unknown " , " read-only " , " read-write " , " invalid " ,
} ;
2015-06-09 13:04:42 +02:00
struct cros_ec_command * msg ;
2015-02-02 12:26:25 +01:00
int ret ;
2015-06-09 13:04:42 +02:00
msg = kmalloc ( sizeof ( * msg ) + sizeof ( * resp ) , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
msg - > version = 0 ;
2015-06-09 13:04:47 +02:00
msg - > command = EC_CMD_GET_VERSION + ec - > cmd_offset ;
2015-06-09 13:04:42 +02:00
msg - > insize = sizeof ( * resp ) ;
msg - > outsize = 0 ;
2015-06-09 13:04:47 +02:00
ret = cros_ec_cmd_xfer ( ec - > ec_dev , msg ) ;
2015-02-02 12:26:25 +01:00
if ( ret < 0 )
2015-06-09 13:04:42 +02:00
goto exit ;
2015-02-02 12:26:25 +01:00
2015-06-09 13:04:42 +02:00
if ( msg - > result ! = EC_RES_SUCCESS ) {
2015-02-02 12:26:25 +01:00
snprintf ( str , maxlen ,
" %s \n Unknown EC version: EC returned %d \n " ,
2015-06-09 13:04:42 +02:00
CROS_EC_DEV_VERSION , msg - > result ) ;
ret = - EINVAL ;
goto exit ;
2015-02-02 12:26:25 +01:00
}
2015-06-09 13:04:42 +02:00
resp = ( struct ec_response_get_version * ) msg - > data ;
2015-02-02 12:26:25 +01:00
if ( resp - > current_image > = ARRAY_SIZE ( current_image_name ) )
resp - > current_image = 3 ; /* invalid */
2015-03-03 13:22:32 +01:00
snprintf ( str , maxlen , " %s \n %s \n %s \n %s \n " , CROS_EC_DEV_VERSION ,
2015-02-02 12:26:25 +01:00
resp - > version_string_ro , resp - > version_string_rw ,
current_image_name [ resp - > current_image ] ) ;
2015-06-09 13:04:42 +02:00
ret = 0 ;
exit :
kfree ( msg ) ;
return ret ;
2015-02-02 12:26:25 +01:00
}
2016-08-01 11:54:37 +02:00
static int cros_ec_check_features ( struct cros_ec_dev * ec , int feature )
{
struct cros_ec_command * msg ;
int ret ;
if ( ec - > features [ 0 ] = = - 1U & & ec - > features [ 1 ] = = - 1U ) {
/* features bitmap not read yet */
msg = kmalloc ( sizeof ( * msg ) + sizeof ( ec - > features ) , GFP_KERNEL ) ;
if ( ! msg )
return - ENOMEM ;
msg - > version = 0 ;
msg - > command = EC_CMD_GET_FEATURES + ec - > cmd_offset ;
msg - > insize = sizeof ( ec - > features ) ;
msg - > outsize = 0 ;
ret = cros_ec_cmd_xfer ( ec - > ec_dev , msg ) ;
if ( ret < 0 | | msg - > result ! = EC_RES_SUCCESS ) {
dev_warn ( ec - > dev , " cannot get EC features: %d/%d \n " ,
ret , msg - > result ) ;
memset ( ec - > features , 0 , sizeof ( ec - > features ) ) ;
2018-05-30 23:23:43 -07:00
} else {
memcpy ( ec - > features , msg - > data , sizeof ( ec - > features ) ) ;
2016-08-01 11:54:37 +02:00
}
dev_dbg ( ec - > dev , " EC features %08x %08x \n " ,
ec - > features [ 0 ] , ec - > features [ 1 ] ) ;
kfree ( msg ) ;
}
return ec - > features [ feature / 32 ] & EC_FEATURE_MASK_0 ( feature ) ;
}
2015-02-02 12:26:25 +01:00
/* Device file ops */
static int ec_device_open ( struct inode * inode , struct file * filp )
{
2015-06-09 13:04:47 +02:00
struct cros_ec_dev * ec = container_of ( inode - > i_cdev ,
struct cros_ec_dev , cdev ) ;
filp - > private_data = ec ;
nonseekable_open ( inode , filp ) ;
2015-02-02 12:26:25 +01:00
return 0 ;
}
static int ec_device_release ( struct inode * inode , struct file * filp )
{
return 0 ;
}
static ssize_t ec_device_read ( struct file * filp , char __user * buffer ,
size_t length , loff_t * offset )
{
2015-06-09 13:04:47 +02:00
struct cros_ec_dev * ec = filp - > private_data ;
2015-02-02 12:26:25 +01:00
char msg [ sizeof ( struct ec_response_get_version ) +
sizeof ( CROS_EC_DEV_VERSION ) ] ;
size_t count ;
int ret ;
if ( * offset ! = 0 )
return 0 ;
ret = ec_get_version ( ec , msg , sizeof ( msg ) ) ;
if ( ret )
return ret ;
count = min ( length , strlen ( msg ) ) ;
if ( copy_to_user ( buffer , msg , count ) )
return - EFAULT ;
* offset = count ;
return count ;
}
/* Ioctls */
2015-06-09 13:04:47 +02:00
static long ec_device_ioctl_xcmd ( struct cros_ec_dev * ec , void __user * arg )
2015-02-02 12:26:25 +01:00
{
long ret ;
2015-06-09 13:04:42 +02:00
struct cros_ec_command u_cmd ;
struct cros_ec_command * s_cmd ;
2015-02-02 12:26:25 +01:00
2015-06-09 13:04:42 +02:00
if ( copy_from_user ( & u_cmd , arg , sizeof ( u_cmd ) ) )
2015-02-02 12:26:25 +01:00
return - EFAULT ;
2016-03-08 09:13:52 -08:00
if ( ( u_cmd . outsize > EC_MAX_MSG_BYTES ) | |
( u_cmd . insize > EC_MAX_MSG_BYTES ) )
return - EINVAL ;
2015-06-09 13:04:42 +02:00
s_cmd = kmalloc ( sizeof ( * s_cmd ) + max ( u_cmd . outsize , u_cmd . insize ) ,
GFP_KERNEL ) ;
if ( ! s_cmd )
return - ENOMEM ;
if ( copy_from_user ( s_cmd , arg , sizeof ( * s_cmd ) + u_cmd . outsize ) ) {
ret = - EFAULT ;
goto exit ;
}
2016-06-21 16:58:46 +03:00
if ( u_cmd . outsize ! = s_cmd - > outsize | |
u_cmd . insize ! = s_cmd - > insize ) {
ret = - EINVAL ;
goto exit ;
}
2015-06-09 13:04:47 +02:00
s_cmd - > command + = ec - > cmd_offset ;
ret = cros_ec_cmd_xfer ( ec - > ec_dev , s_cmd ) ;
2015-02-02 12:26:25 +01:00
/* Only copy data to userland if data was received. */
if ( ret < 0 )
2015-06-09 13:04:42 +02:00
goto exit ;
2015-02-02 12:26:25 +01:00
2016-06-21 16:58:46 +03:00
if ( copy_to_user ( arg , s_cmd , sizeof ( * s_cmd ) + s_cmd - > insize ) )
2015-06-09 13:04:42 +02:00
ret = - EFAULT ;
exit :
kfree ( s_cmd ) ;
return ret ;
2015-02-02 12:26:25 +01:00
}
2015-06-09 13:04:47 +02:00
static long ec_device_ioctl_readmem ( struct cros_ec_dev * ec , void __user * arg )
2015-02-02 12:26:25 +01:00
{
2015-06-09 13:04:47 +02:00
struct cros_ec_device * ec_dev = ec - > ec_dev ;
2015-02-02 12:26:25 +01:00
struct cros_ec_readmem s_mem = { } ;
long num ;
/* Not every platform supports direct reads */
2015-06-09 13:04:47 +02:00
if ( ! ec_dev - > cmd_readmem )
2015-02-02 12:26:25 +01:00
return - ENOTTY ;
if ( copy_from_user ( & s_mem , arg , sizeof ( s_mem ) ) )
return - EFAULT ;
2015-06-09 13:04:47 +02:00
num = ec_dev - > cmd_readmem ( ec_dev , s_mem . offset , s_mem . bytes ,
s_mem . buffer ) ;
2015-02-02 12:26:25 +01:00
if ( num < = 0 )
return num ;
if ( copy_to_user ( ( void __user * ) arg , & s_mem , sizeof ( s_mem ) ) )
return - EFAULT ;
return 0 ;
}
static long ec_device_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
{
2015-06-09 13:04:47 +02:00
struct cros_ec_dev * ec = filp - > private_data ;
2015-02-02 12:26:25 +01:00
if ( _IOC_TYPE ( cmd ) ! = CROS_EC_DEV_IOC )
return - ENOTTY ;
switch ( cmd ) {
case CROS_EC_DEV_IOCXCMD :
return ec_device_ioctl_xcmd ( ec , ( void __user * ) arg ) ;
case CROS_EC_DEV_IOCRDMEM :
return ec_device_ioctl_readmem ( ec , ( void __user * ) arg ) ;
}
return - ENOTTY ;
}
/* Module initialization */
static const struct file_operations fops = {
. open = ec_device_open ,
. release = ec_device_release ,
. read = ec_device_read ,
. unlocked_ioctl = ec_device_ioctl ,
2016-04-14 19:35:29 -07:00
# ifdef CONFIG_COMPAT
. compat_ioctl = ec_device_ioctl ,
# endif
2015-02-02 12:26:25 +01:00
} ;
2016-08-01 11:54:38 +02:00
static void cros_ec_sensors_register ( struct cros_ec_dev * ec )
{
/*
* Issue a command to get the number of sensor reported .
* Build an array of sensors driver and register them all .
*/
int ret , i , id , sensor_num ;
struct mfd_cell * sensor_cells ;
struct cros_ec_sensor_platform * sensor_platforms ;
int sensor_type [ MOTIONSENSE_TYPE_MAX ] ;
struct ec_params_motion_sense * params ;
struct ec_response_motion_sense * resp ;
struct cros_ec_command * msg ;
msg = kzalloc ( sizeof ( struct cros_ec_command ) +
max ( sizeof ( * params ) , sizeof ( * resp ) ) , GFP_KERNEL ) ;
if ( msg = = NULL )
return ;
msg - > version = 2 ;
msg - > command = EC_CMD_MOTION_SENSE_CMD + ec - > cmd_offset ;
msg - > outsize = sizeof ( * params ) ;
msg - > insize = sizeof ( * resp ) ;
params = ( struct ec_params_motion_sense * ) msg - > data ;
params - > cmd = MOTIONSENSE_CMD_DUMP ;
ret = cros_ec_cmd_xfer ( ec - > ec_dev , msg ) ;
if ( ret < 0 | | msg - > result ! = EC_RES_SUCCESS ) {
dev_warn ( ec - > dev , " cannot get EC sensor information: %d/%d \n " ,
ret , msg - > result ) ;
goto error ;
}
resp = ( struct ec_response_motion_sense * ) msg - > data ;
sensor_num = resp - > dump . sensor_count ;
2018-03-23 18:42:47 +01:00
/* Allocate 1 extra sensors in FIFO are needed */
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(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.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- 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 E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- 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 THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:03:40 -07:00
sensor_cells = kcalloc ( sensor_num + 1 , sizeof ( struct mfd_cell ) ,
2016-08-01 11:54:38 +02:00
GFP_KERNEL ) ;
if ( sensor_cells = = NULL )
goto error ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(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.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- 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 E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- 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 THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:03:40 -07:00
sensor_platforms = kcalloc ( sensor_num + 1 ,
sizeof ( struct cros_ec_sensor_platform ) ,
GFP_KERNEL ) ;
2016-08-01 11:54:38 +02:00
if ( sensor_platforms = = NULL )
goto error_platforms ;
memset ( sensor_type , 0 , sizeof ( sensor_type ) ) ;
id = 0 ;
for ( i = 0 ; i < sensor_num ; i + + ) {
params - > cmd = MOTIONSENSE_CMD_INFO ;
params - > info . sensor_num = i ;
ret = cros_ec_cmd_xfer ( ec - > ec_dev , msg ) ;
if ( ret < 0 | | msg - > result ! = EC_RES_SUCCESS ) {
dev_warn ( ec - > dev , " no info for EC sensor %d : %d/%d \n " ,
i , ret , msg - > result ) ;
continue ;
}
switch ( resp - > info . type ) {
case MOTIONSENSE_TYPE_ACCEL :
sensor_cells [ id ] . name = " cros-ec-accel " ;
break ;
2017-01-24 14:41:41 +01:00
case MOTIONSENSE_TYPE_BARO :
sensor_cells [ id ] . name = " cros-ec-baro " ;
break ;
2016-08-01 11:54:38 +02:00
case MOTIONSENSE_TYPE_GYRO :
sensor_cells [ id ] . name = " cros-ec-gyro " ;
break ;
case MOTIONSENSE_TYPE_MAG :
sensor_cells [ id ] . name = " cros-ec-mag " ;
break ;
case MOTIONSENSE_TYPE_PROX :
sensor_cells [ id ] . name = " cros-ec-prox " ;
break ;
case MOTIONSENSE_TYPE_LIGHT :
sensor_cells [ id ] . name = " cros-ec-light " ;
break ;
case MOTIONSENSE_TYPE_ACTIVITY :
sensor_cells [ id ] . name = " cros-ec-activity " ;
break ;
default :
dev_warn ( ec - > dev , " unknown type %d \n " , resp - > info . type ) ;
continue ;
}
sensor_platforms [ id ] . sensor_num = i ;
sensor_cells [ id ] . id = sensor_type [ resp - > info . type ] ;
sensor_cells [ id ] . platform_data = & sensor_platforms [ id ] ;
sensor_cells [ id ] . pdata_size =
sizeof ( struct cros_ec_sensor_platform ) ;
sensor_type [ resp - > info . type ] + + ;
id + + ;
}
2018-03-23 18:42:47 +01:00
if ( sensor_type [ MOTIONSENSE_TYPE_ACCEL ] > = 2 )
ec - > has_kb_wake_angle = true ;
2016-08-01 11:54:38 +02:00
if ( cros_ec_check_features ( ec , EC_FEATURE_MOTION_SENSE_FIFO ) ) {
sensor_cells [ id ] . name = " cros-ec-ring " ;
id + + ;
}
ret = mfd_add_devices ( ec - > dev , 0 , sensor_cells , id ,
NULL , 0 , NULL ) ;
if ( ret )
dev_err ( ec - > dev , " failed to add EC sensors \n " ) ;
kfree ( sensor_platforms ) ;
error_platforms :
kfree ( sensor_cells ) ;
error :
kfree ( msg ) ;
}
2018-07-04 17:08:20 +02:00
static const struct mfd_cell cros_ec_cec_cells [ ] = {
{ . name = " cros-ec-cec " }
} ;
2018-04-18 12:24:01 +02:00
static const struct mfd_cell cros_ec_rtc_cells [ ] = {
{ . name = " cros-ec-rtc " }
} ;
2018-05-02 17:44:18 +02:00
static const struct mfd_cell cros_usbpd_charger_cells [ ] = {
{ . name = " cros-usbpd-charger " }
} ;
2015-02-02 12:26:25 +01:00
static int ec_device_probe ( struct platform_device * pdev )
{
2015-06-09 13:04:47 +02:00
int retval = - ENOMEM ;
struct device * dev = & pdev - > dev ;
struct cros_ec_platform * ec_platform = dev_get_platdata ( dev ) ;
2018-05-30 09:54:22 -07:00
struct cros_ec_dev * ec = devm_kzalloc ( dev , sizeof ( * ec ) , GFP_KERNEL ) ;
2015-06-09 13:04:47 +02:00
if ( ! ec )
return retval ;
2015-02-02 12:26:25 +01:00
2015-06-09 13:04:47 +02:00
dev_set_drvdata ( dev , ec ) ;
ec - > ec_dev = dev_get_drvdata ( dev - > parent ) ;
ec - > dev = dev ;
ec - > cmd_offset = ec_platform - > cmd_offset ;
2016-08-01 11:54:37 +02:00
ec - > features [ 0 ] = - 1U ; /* Not cached yet */
ec - > features [ 1 ] = - 1U ; /* Not cached yet */
2015-06-09 13:04:47 +02:00
device_initialize ( & ec - > class_dev ) ;
2015-02-02 12:26:25 +01:00
cdev_init ( & ec - > cdev , & fops ) ;
2015-06-09 13:04:47 +02:00
/*
* Add the class device
* Link to the character device for creating the / dev entry
* in devtmpfs .
*/
2017-03-17 12:48:14 -06:00
ec - > class_dev . devt = MKDEV ( ec_major , pdev - > id ) ;
2015-06-09 13:04:47 +02:00
ec - > class_dev . class = & cros_class ;
ec - > class_dev . parent = dev ;
retval = dev_set_name ( & ec - > class_dev , " %s " , ec_platform - > ec_name ) ;
if ( retval ) {
dev_err ( dev , " dev_set_name failed => %d \n " , retval ) ;
2017-03-17 12:48:14 -06:00
goto failed ;
2015-02-02 12:26:25 +01:00
}
2018-03-23 18:42:47 +01:00
/* check whether this EC is a sensor hub. */
if ( cros_ec_check_features ( ec , EC_FEATURE_MOTION_SENSE ) )
cros_ec_sensors_register ( ec ) ;
2018-07-04 17:08:20 +02:00
/* Check whether this EC instance has CEC host command support */
if ( cros_ec_check_features ( ec , EC_FEATURE_CEC ) ) {
retval = mfd_add_devices ( ec - > dev , PLATFORM_DEVID_AUTO ,
cros_ec_cec_cells ,
ARRAY_SIZE ( cros_ec_cec_cells ) ,
NULL , 0 , NULL ) ;
if ( retval )
dev_err ( ec - > dev ,
" failed to add cros-ec-cec device: %d \n " ,
retval ) ;
}
2018-04-18 12:24:01 +02:00
/* Check whether this EC instance has RTC host command support */
if ( cros_ec_check_features ( ec , EC_FEATURE_RTC ) ) {
retval = mfd_add_devices ( ec - > dev , PLATFORM_DEVID_AUTO ,
cros_ec_rtc_cells ,
ARRAY_SIZE ( cros_ec_rtc_cells ) ,
NULL , 0 , NULL ) ;
if ( retval )
dev_err ( ec - > dev ,
" failed to add cros-ec-rtc device: %d \n " ,
retval ) ;
}
2018-05-02 17:44:18 +02:00
/* Check whether this EC instance has the PD charge manager */
if ( cros_ec_check_features ( ec , EC_FEATURE_USB_PD ) ) {
retval = mfd_add_devices ( ec - > dev , PLATFORM_DEVID_AUTO ,
cros_usbpd_charger_cells ,
ARRAY_SIZE ( cros_usbpd_charger_cells ) ,
NULL , 0 , NULL ) ;
if ( retval )
dev_err ( ec - > dev ,
" failed to add cros-usbpd-charger device: %d \n " ,
retval ) ;
}
2018-03-23 18:42:47 +01:00
/* Take control of the lightbar from the EC. */
lb_manual_suspend_ctrl ( ec , 1 ) ;
/* We can now add the sysfs class, we know which parameter to show */
2017-03-17 12:48:14 -06:00
retval = cdev_device_add ( & ec - > cdev , & ec - > class_dev ) ;
2015-06-09 13:04:47 +02:00
if ( retval ) {
2017-03-17 12:48:14 -06:00
dev_err ( dev , " cdev_device_add failed => %d \n " , retval ) ;
goto failed ;
2015-06-09 13:04:47 +02:00
}
2015-02-02 12:26:27 +01:00
2017-05-16 17:46:48 +02:00
if ( cros_ec_debugfs_init ( ec ) )
dev_warn ( dev , " failed to create debugfs directory \n " ) ;
2015-02-02 12:26:25 +01:00
return 0 ;
2015-06-09 13:04:47 +02:00
2017-03-17 12:48:14 -06:00
failed :
put_device ( & ec - > class_dev ) ;
2015-06-09 13:04:47 +02:00
return retval ;
2015-02-02 12:26:25 +01:00
}
static int ec_device_remove ( struct platform_device * pdev )
{
2015-06-09 13:04:47 +02:00
struct cros_ec_dev * ec = dev_get_drvdata ( & pdev - > dev ) ;
2017-05-16 17:46:48 +02:00
2017-05-16 17:46:48 +02:00
/* Let the EC take over the lightbar again. */
2017-05-16 17:46:48 +02:00
lb_manual_suspend_ctrl ( ec , 0 ) ;
2017-05-16 17:46:48 +02:00
2017-05-16 17:46:48 +02:00
cros_ec_debugfs_remove ( ec ) ;
2015-02-02 12:26:25 +01:00
cdev_del ( & ec - > cdev ) ;
2015-06-09 13:04:47 +02:00
device_unregister ( & ec - > class_dev ) ;
2015-02-02 12:26:25 +01:00
return 0 ;
}
2018-04-18 12:24:02 +02:00
static void ec_device_shutdown ( struct platform_device * pdev )
{
struct cros_ec_dev * ec = dev_get_drvdata ( & pdev - > dev ) ;
/* Be sure to clear up debugfs delayed works */
cros_ec_debugfs_remove ( ec ) ;
}
2015-06-22 08:27:20 +02:00
static const struct platform_device_id cros_ec_id [ ] = {
2017-11-20 17:15:25 +01:00
{ DRV_NAME , 0 } ,
2018-04-18 12:24:03 +02:00
{ /* sentinel */ }
2015-06-22 08:27:20 +02:00
} ;
MODULE_DEVICE_TABLE ( platform , cros_ec_id ) ;
2017-06-27 17:36:36 +02:00
static __maybe_unused int ec_device_suspend ( struct device * dev )
2017-05-16 17:46:48 +02:00
{
struct cros_ec_dev * ec = dev_get_drvdata ( dev ) ;
2018-04-18 12:24:00 +02:00
cros_ec_debugfs_suspend ( ec ) ;
2017-05-16 17:46:48 +02:00
lb_suspend ( ec ) ;
2017-05-16 17:46:48 +02:00
return 0 ;
}
2017-06-27 17:36:36 +02:00
static __maybe_unused int ec_device_resume ( struct device * dev )
2017-05-16 17:46:48 +02:00
{
struct cros_ec_dev * ec = dev_get_drvdata ( dev ) ;
2018-04-18 12:24:00 +02:00
cros_ec_debugfs_resume ( ec ) ;
2017-05-16 17:46:48 +02:00
lb_resume ( ec ) ;
2017-05-16 17:46:48 +02:00
return 0 ;
}
static const struct dev_pm_ops cros_ec_dev_pm_ops = {
# ifdef CONFIG_PM_SLEEP
. suspend = ec_device_suspend ,
. resume = ec_device_resume ,
# endif
} ;
2015-02-02 12:26:25 +01:00
static struct platform_driver cros_ec_dev_driver = {
. driver = {
2017-11-20 17:15:25 +01:00
. name = DRV_NAME ,
2017-05-16 17:46:48 +02:00
. pm = & cros_ec_dev_pm_ops ,
2015-02-02 12:26:25 +01:00
} ,
. probe = ec_device_probe ,
. remove = ec_device_remove ,
2018-04-18 12:24:02 +02:00
. shutdown = ec_device_shutdown ,
2015-02-02 12:26:25 +01:00
} ;
static int __init cros_ec_dev_init ( void )
{
int ret ;
dev_t dev = 0 ;
2015-06-09 13:04:47 +02:00
ret = class_register ( & cros_class ) ;
if ( ret ) {
2015-02-02 12:26:25 +01:00
pr_err ( CROS_EC_DEV_NAME " : failed to register device class \n " ) ;
2015-06-09 13:04:47 +02:00
return ret ;
2015-02-02 12:26:25 +01:00
}
/* Get a range of minor numbers (starting with 0) to work with */
ret = alloc_chrdev_region ( & dev , 0 , CROS_MAX_DEV , CROS_EC_DEV_NAME ) ;
if ( ret < 0 ) {
pr_err ( CROS_EC_DEV_NAME " : alloc_chrdev_region() failed \n " ) ;
goto failed_chrdevreg ;
}
ec_major = MAJOR ( dev ) ;
/* Register the driver */
ret = platform_driver_register ( & cros_ec_dev_driver ) ;
if ( ret < 0 ) {
pr_warn ( CROS_EC_DEV_NAME " : can't register driver: %d \n " , ret ) ;
goto failed_devreg ;
}
return 0 ;
failed_devreg :
unregister_chrdev_region ( MKDEV ( ec_major , 0 ) , CROS_MAX_DEV ) ;
failed_chrdevreg :
2015-06-09 13:04:47 +02:00
class_unregister ( & cros_class ) ;
2015-02-02 12:26:25 +01:00
return ret ;
}
static void __exit cros_ec_dev_exit ( void )
{
platform_driver_unregister ( & cros_ec_dev_driver ) ;
unregister_chrdev ( ec_major , CROS_EC_DEV_NAME ) ;
2015-06-09 13:04:47 +02:00
class_unregister ( & cros_class ) ;
2015-02-02 12:26:25 +01:00
}
module_init ( cros_ec_dev_init ) ;
module_exit ( cros_ec_dev_exit ) ;
2017-11-20 17:15:25 +01:00
MODULE_ALIAS ( " platform: " DRV_NAME ) ;
2015-02-02 12:26:25 +01:00
MODULE_AUTHOR ( " Bill Richardson <wfrichar@chromium.org> " ) ;
MODULE_DESCRIPTION ( " Userspace interface to the Chrome OS Embedded Controller " ) ;
MODULE_VERSION ( " 1.0 " ) ;
MODULE_LICENSE ( " GPL " ) ;