2019-05-29 07:18:02 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2016-08-07 02:25:36 -07:00
/*
* ISHTP client driver for HID ( ISH )
*
* Copyright ( c ) 2014 - 2016 , Intel Corporation .
*/
# include <linux/module.h>
# include <linux/hid.h>
2019-03-18 12:14:20 -07:00
# include <linux/intel-ish-client-if.h>
2016-08-07 02:25:36 -07:00
# include <linux/sched.h>
# include "ishtp-hid.h"
/* Rx ring buffer pool size */
# define HID_CL_RX_RING_SIZE 32
# define HID_CL_TX_RING_SIZE 16
2019-03-18 12:14:20 -07:00
# define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
2016-08-07 02:25:36 -07:00
/**
* report_bad_packets ( ) - Report bad packets
* @ hid_ishtp_cl : Client instance to get stats
* @ recv_buf : Raw received host interface message
* @ cur_pos : Current position index in payload
* @ payload_len : Length of payload expected
*
* Dumps error in case bad packet is received
*/
static void report_bad_packet ( struct ishtp_cl * hid_ishtp_cl , void * recv_buf ,
size_t cur_pos , size_t payload_len )
{
struct hostif_msg * recv_msg = recv_buf ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) , " [hid-ish]: BAD packet %02X \n "
2016-08-07 02:25:36 -07:00
" total_bad=%u cur_pos=%u \n "
" [%02X %02X %02X %02X] \n "
" payload_len=%u \n "
" multi_packet_cnt=%u \n "
" is_response=%02X \n " ,
recv_msg - > hdr . command , client_data - > bad_recv_cnt ,
( unsigned int ) cur_pos ,
( ( unsigned char * ) recv_msg ) [ 0 ] , ( ( unsigned char * ) recv_msg ) [ 1 ] ,
( ( unsigned char * ) recv_msg ) [ 2 ] , ( ( unsigned char * ) recv_msg ) [ 3 ] ,
( unsigned int ) payload_len , client_data - > multi_packet_cnt ,
recv_msg - > hdr . command & ~ CMD_MASK ) ;
}
/**
* process_recv ( ) - Received and parse incoming packet
* @ hid_ishtp_cl : Client instance to get stats
* @ recv_buf : Raw received host interface message
* @ data_len : length of the message
*
* Parse the incoming packet . If it is a response packet then it will update
* per instance flags and wake up the caller waiting to for the response .
*/
static void process_recv ( struct ishtp_cl * hid_ishtp_cl , void * recv_buf ,
size_t data_len )
{
struct hostif_msg * recv_msg ;
unsigned char * payload ;
struct device_info * dev_info ;
int i , j ;
2019-03-04 12:48:54 -08:00
size_t payload_len , total_len , cur_pos , raw_len ;
2016-08-07 02:25:36 -07:00
int report_type ;
struct report_list * reports_list ;
char * reports ;
size_t report_len ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
int curr_hid_dev = client_data - > cur_hid_dev ;
2019-03-04 12:48:54 -08:00
struct ishtp_hid_data * hid_data = NULL ;
struct hid_device * hid = NULL ;
2016-08-07 02:25:36 -07:00
payload = recv_buf + sizeof ( struct hostif_msg_hdr ) ;
total_len = data_len ;
cur_pos = 0 ;
do {
2018-04-14 17:06:44 +02:00
if ( cur_pos + sizeof ( struct hostif_msg ) > total_len ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2018-04-14 17:06:44 +02:00
" [hid-ish]: error, received %u which is less than data header %u \n " ,
( unsigned int ) data_len ,
( unsigned int ) sizeof ( struct hostif_msg_hdr ) ) ;
+ + client_data - > bad_recv_cnt ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2018-04-14 17:06:44 +02:00
break ;
}
2016-08-07 02:25:36 -07:00
recv_msg = ( struct hostif_msg * ) ( recv_buf + cur_pos ) ;
payload_len = recv_msg - > hdr . size ;
/* Sanity checks */
if ( cur_pos + payload_len + sizeof ( struct hostif_msg ) >
total_len ) {
+ + client_data - > bad_recv_cnt ;
report_bad_packet ( hid_ishtp_cl , recv_msg , cur_pos ,
payload_len ) ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2016-08-07 02:25:36 -07:00
break ;
}
hid_ishtp_trace ( client_data , " %s %d \n " ,
__func__ , recv_msg - > hdr . command & CMD_MASK ) ;
switch ( recv_msg - > hdr . command & CMD_MASK ) {
case HOSTIF_DM_ENUM_DEVICES :
if ( ( ! ( recv_msg - > hdr . command & ~ CMD_MASK ) | |
client_data - > init_done ) ) {
+ + client_data - > bad_recv_cnt ;
report_bad_packet ( hid_ishtp_cl , recv_msg ,
cur_pos ,
payload_len ) ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2016-08-07 02:25:36 -07:00
break ;
}
client_data - > hid_dev_count = ( unsigned int ) * payload ;
if ( ! client_data - > hid_devices )
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-12 14:07:58 -07:00
client_data - > hid_devices = devm_kcalloc (
2019-03-18 12:14:20 -07:00
cl_data_to_dev ( client_data ) ,
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-12 14:07:58 -07:00
client_data - > hid_dev_count ,
2016-08-07 02:25:36 -07:00
sizeof ( struct device_info ) ,
GFP_KERNEL ) ;
if ( ! client_data - > hid_devices ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" Mem alloc failed for hid device info \n " ) ;
wake_up_interruptible ( & client_data - > init_wait ) ;
break ;
}
for ( i = 0 ; i < client_data - > hid_dev_count ; + + i ) {
if ( 1 + sizeof ( struct device_info ) * i > =
payload_len ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2017-05-18 22:21:43 +02:00
" [hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu \n " ,
2016-08-07 02:25:36 -07:00
1 + sizeof ( struct device_info )
2017-05-18 22:21:43 +02:00
* i , payload_len ) ;
2016-08-07 02:25:36 -07:00
}
if ( 1 + sizeof ( struct device_info ) * i > =
data_len )
break ;
dev_info = ( struct device_info * ) ( payload + 1 +
sizeof ( struct device_info ) * i ) ;
if ( client_data - > hid_devices )
memcpy ( client_data - > hid_devices + i ,
dev_info ,
sizeof ( struct device_info ) ) ;
}
client_data - > enum_devices_done = true ;
wake_up_interruptible ( & client_data - > init_wait ) ;
break ;
case HOSTIF_GET_HID_DESCRIPTOR :
if ( ( ! ( recv_msg - > hdr . command & ~ CMD_MASK ) | |
client_data - > init_done ) ) {
+ + client_data - > bad_recv_cnt ;
report_bad_packet ( hid_ishtp_cl , recv_msg ,
cur_pos ,
payload_len ) ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2016-08-07 02:25:36 -07:00
break ;
}
if ( ! client_data - > hid_descr [ curr_hid_dev ] )
client_data - > hid_descr [ curr_hid_dev ] =
2019-03-18 12:14:20 -07:00
devm_kmalloc ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
payload_len , GFP_KERNEL ) ;
if ( client_data - > hid_descr [ curr_hid_dev ] ) {
memcpy ( client_data - > hid_descr [ curr_hid_dev ] ,
payload , payload_len ) ;
client_data - > hid_descr_size [ curr_hid_dev ] =
payload_len ;
client_data - > hid_descr_done = true ;
}
wake_up_interruptible ( & client_data - > init_wait ) ;
break ;
case HOSTIF_GET_REPORT_DESCRIPTOR :
if ( ( ! ( recv_msg - > hdr . command & ~ CMD_MASK ) | |
client_data - > init_done ) ) {
+ + client_data - > bad_recv_cnt ;
report_bad_packet ( hid_ishtp_cl , recv_msg ,
cur_pos ,
payload_len ) ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2016-08-07 02:25:36 -07:00
break ;
}
if ( ! client_data - > report_descr [ curr_hid_dev ] )
client_data - > report_descr [ curr_hid_dev ] =
2019-03-18 12:14:20 -07:00
devm_kmalloc ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
payload_len , GFP_KERNEL ) ;
if ( client_data - > report_descr [ curr_hid_dev ] ) {
memcpy ( client_data - > report_descr [ curr_hid_dev ] ,
payload ,
payload_len ) ;
client_data - > report_descr_size [ curr_hid_dev ] =
payload_len ;
client_data - > report_descr_done = true ;
}
wake_up_interruptible ( & client_data - > init_wait ) ;
break ;
case HOSTIF_GET_FEATURE_REPORT :
report_type = HID_FEATURE_REPORT ;
goto do_get_report ;
case HOSTIF_GET_INPUT_REPORT :
report_type = HID_INPUT_REPORT ;
do_get_report :
/* Get index of device that matches this id */
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i ) {
if ( recv_msg - > hdr . device_id = =
2019-03-04 12:48:54 -08:00
client_data - > hid_devices [ i ] . dev_id ) {
hid = client_data - > hid_sensor_hubs [ i ] ;
if ( ! hid )
2016-08-07 02:25:36 -07:00
break ;
2019-03-04 12:48:54 -08:00
hid_data = hid - > driver_data ;
if ( hid_data - > raw_get_req ) {
raw_len =
( hid_data - > raw_buf_size <
payload_len ) ?
hid_data - > raw_buf_size :
payload_len ;
memcpy ( hid_data - > raw_buf ,
payload , raw_len ) ;
} else {
hid_input_report
( hid , report_type ,
payload , payload_len ,
0 ) ;
2016-08-07 02:25:36 -07:00
}
2019-03-04 12:48:54 -08:00
ishtp_hid_wakeup ( hid ) ;
break ;
}
2016-08-07 02:25:36 -07:00
}
break ;
case HOSTIF_SET_FEATURE_REPORT :
/* Get index of device that matches this id */
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i ) {
if ( recv_msg - > hdr . device_id = =
client_data - > hid_devices [ i ] . dev_id )
if ( client_data - > hid_sensor_hubs [ i ] ) {
ishtp_hid_wakeup (
client_data - > hid_sensor_hubs [
i ] ) ;
break ;
}
}
break ;
case HOSTIF_PUBLISH_INPUT_REPORT :
report_type = HID_INPUT_REPORT ;
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i )
if ( recv_msg - > hdr . device_id = =
client_data - > hid_devices [ i ] . dev_id )
if ( client_data - > hid_sensor_hubs [ i ] )
hid_input_report (
client_data - > hid_sensor_hubs [
i ] ,
report_type , payload ,
payload_len , 0 ) ;
break ;
case HOSTIF_PUBLISH_INPUT_REPORT_LIST :
report_type = HID_INPUT_REPORT ;
reports_list = ( struct report_list * ) payload ;
reports = ( char * ) reports_list - > reports ;
for ( j = 0 ; j < reports_list - > num_of_reports ; j + + ) {
recv_msg = ( struct hostif_msg * ) ( reports +
sizeof ( uint16_t ) ) ;
report_len = * ( uint16_t * ) reports ;
payload = reports + sizeof ( uint16_t ) +
sizeof ( struct hostif_msg_hdr ) ;
payload_len = report_len -
sizeof ( struct hostif_msg_hdr ) ;
for ( i = 0 ; i < client_data - > num_hid_devices ;
+ + i )
if ( recv_msg - > hdr . device_id = =
client_data - > hid_devices [ i ] . dev_id & &
client_data - > hid_sensor_hubs [ i ] ) {
hid_input_report (
client_data - > hid_sensor_hubs [
i ] ,
report_type ,
payload , payload_len ,
0 ) ;
}
reports + = sizeof ( uint16_t ) + report_len ;
}
break ;
default :
+ + client_data - > bad_recv_cnt ;
report_bad_packet ( hid_ishtp_cl , recv_msg , cur_pos ,
payload_len ) ;
2019-03-18 12:14:27 -07:00
ish_hw_reset ( ishtp_get_ishtp_device ( hid_ishtp_cl ) ) ;
2016-08-07 02:25:36 -07:00
break ;
}
if ( ! cur_pos & & cur_pos + payload_len +
sizeof ( struct hostif_msg ) < total_len )
+ + client_data - > multi_packet_cnt ;
cur_pos + = payload_len + sizeof ( struct hostif_msg ) ;
payload + = payload_len + sizeof ( struct hostif_msg ) ;
} while ( cur_pos < total_len ) ;
}
/**
* ish_cl_event_cb ( ) - bus driver callback for incoming message / packet
* @ device : Pointer to the the ishtp client device for which this message
* is targeted
*
* Remove the packet from the list and process the message by calling
* process_recv
*/
static void ish_cl_event_cb ( struct ishtp_cl_device * device )
{
2018-09-11 16:44:14 -07:00
struct ishtp_cl * hid_ishtp_cl = ishtp_get_drvdata ( device ) ;
2016-08-07 02:25:36 -07:00
struct ishtp_cl_rb * rb_in_proc ;
size_t r_length ;
if ( ! hid_ishtp_cl )
return ;
2018-09-11 16:44:16 -07:00
while ( ( rb_in_proc = ishtp_cl_rx_get_rb ( hid_ishtp_cl ) ) ! = NULL ) {
2016-08-07 02:25:36 -07:00
if ( ! rb_in_proc - > buffer . data )
return ;
r_length = rb_in_proc - > buf_idx ;
/* decide what to do with received data */
process_recv ( hid_ishtp_cl , rb_in_proc - > buffer . data , r_length ) ;
ishtp_cl_io_rb_recycle ( rb_in_proc ) ;
}
}
/**
* hid_ishtp_set_feature ( ) - send request to ISH FW to set a feature request
* @ hid : hid device instance for this request
* @ buf : feature buffer
* @ len : Length of feature buffer
* @ report_id : Report id for the feature set request
*
* This is called from hid core . request ( ) callback . This function doesn ' t wait
* for response .
*/
void hid_ishtp_set_feature ( struct hid_device * hid , char * buf , unsigned int len ,
int report_id )
{
struct ishtp_hid_data * hid_data = hid - > driver_data ;
struct ishtp_cl_data * client_data = hid_data - > client_data ;
struct hostif_msg * msg = ( struct hostif_msg * ) buf ;
int rv ;
int i ;
hid_ishtp_trace ( client_data , " %s hid %p \n " , __func__ , hid ) ;
rv = ishtp_hid_link_ready_wait ( client_data ) ;
if ( rv ) {
hid_ishtp_trace ( client_data , " %s hid %p link not ready \n " ,
__func__ , hid ) ;
return ;
}
memset ( msg , 0 , sizeof ( struct hostif_msg ) ) ;
msg - > hdr . command = HOSTIF_SET_FEATURE_REPORT ;
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i ) {
if ( hid = = client_data - > hid_sensor_hubs [ i ] ) {
msg - > hdr . device_id =
client_data - > hid_devices [ i ] . dev_id ;
break ;
}
}
if ( i = = client_data - > num_hid_devices )
return ;
rv = ishtp_cl_send ( client_data - > hid_ishtp_cl , buf , len ) ;
if ( rv )
hid_ishtp_trace ( client_data , " %s hid %p send failed \n " ,
__func__ , hid ) ;
}
/**
* hid_ishtp_get_report ( ) - request to get feature / input report
* @ hid : hid device instance for this request
* @ report_id : Report id for the get request
* @ report_type : Report type for the this request
*
* This is called from hid core . request ( ) callback . This function will send
* request to FW and return without waiting for response .
*/
void hid_ishtp_get_report ( struct hid_device * hid , int report_id ,
int report_type )
{
struct ishtp_hid_data * hid_data = hid - > driver_data ;
struct ishtp_cl_data * client_data = hid_data - > client_data ;
2018-04-14 17:06:45 +02:00
struct hostif_msg_to_sensor msg = { } ;
2016-08-07 02:25:36 -07:00
int rv ;
int i ;
hid_ishtp_trace ( client_data , " %s hid %p \n " , __func__ , hid ) ;
rv = ishtp_hid_link_ready_wait ( client_data ) ;
if ( rv ) {
hid_ishtp_trace ( client_data , " %s hid %p link not ready \n " ,
__func__ , hid ) ;
return ;
}
2018-04-14 17:06:45 +02:00
msg . hdr . command = ( report_type = = HID_FEATURE_REPORT ) ?
2016-08-07 02:25:36 -07:00
HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT ;
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i ) {
if ( hid = = client_data - > hid_sensor_hubs [ i ] ) {
2018-04-14 17:06:45 +02:00
msg . hdr . device_id =
2016-08-07 02:25:36 -07:00
client_data - > hid_devices [ i ] . dev_id ;
break ;
}
}
if ( i = = client_data - > num_hid_devices )
return ;
2018-04-14 17:06:45 +02:00
msg . report_id = report_id ;
rv = ishtp_cl_send ( client_data - > hid_ishtp_cl , ( uint8_t * ) & msg ,
sizeof ( msg ) ) ;
2016-08-07 02:25:36 -07:00
if ( rv )
hid_ishtp_trace ( client_data , " %s hid %p send failed \n " ,
__func__ , hid ) ;
}
/**
* ishtp_hid_link_ready_wait ( ) - Wait for link ready
* @ client_data : client data instance
*
* If the transport link started suspend process , then wait , till either
* resumed or timeout
*
* Return : 0 on success , non zero on error
*/
int ishtp_hid_link_ready_wait ( struct ishtp_cl_data * client_data )
{
int rc ;
if ( client_data - > suspended ) {
hid_ishtp_trace ( client_data , " wait for link ready \n " ) ;
rc = wait_event_interruptible_timeout (
client_data - > ishtp_resume_wait ,
! client_data - > suspended ,
5 * HZ ) ;
if ( rc = = 0 ) {
hid_ishtp_trace ( client_data , " link not ready \n " ) ;
return - EIO ;
}
hid_ishtp_trace ( client_data , " link ready \n " ) ;
}
return 0 ;
}
/**
* ishtp_enum_enum_devices ( ) - Enumerate hid devices
* @ hid_ishtp_cl : client instance
*
* Helper function to send request to firmware to enumerate HID devices
*
* Return : 0 on success , non zero on error
*/
static int ishtp_enum_enum_devices ( struct ishtp_cl * hid_ishtp_cl )
{
struct hostif_msg msg ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
int retry_count ;
int rv ;
/* Send HOSTIF_DM_ENUM_DEVICES */
memset ( & msg , 0 , sizeof ( struct hostif_msg ) ) ;
msg . hdr . command = HOSTIF_DM_ENUM_DEVICES ;
rv = ishtp_cl_send ( hid_ishtp_cl , ( unsigned char * ) & msg ,
sizeof ( struct hostif_msg ) ) ;
if ( rv )
return rv ;
retry_count = 0 ;
while ( ! client_data - > enum_devices_done & &
retry_count < 10 ) {
wait_event_interruptible_timeout ( client_data - > init_wait ,
client_data - > enum_devices_done ,
3 * HZ ) ;
+ + retry_count ;
if ( ! client_data - > enum_devices_done )
/* Send HOSTIF_DM_ENUM_DEVICES */
rv = ishtp_cl_send ( hid_ishtp_cl ,
( unsigned char * ) & msg ,
sizeof ( struct hostif_msg ) ) ;
}
if ( ! client_data - > enum_devices_done ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: timed out waiting for enum_devices \n " ) ;
return - ETIMEDOUT ;
}
if ( ! client_data - > hid_devices ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: failed to allocate HID dev structures \n " ) ;
return - ENOMEM ;
}
client_data - > num_hid_devices = client_data - > hid_dev_count ;
2019-03-18 12:14:27 -07:00
dev_info ( ishtp_device ( client_data - > cl_device ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: enum_devices_done OK, num_hid_devices=%d \n " ,
client_data - > num_hid_devices ) ;
return 0 ;
}
/**
* ishtp_get_hid_descriptor ( ) - Get hid descriptor
* @ hid_ishtp_cl : client instance
* @ index : Index into the hid_descr array
*
* Helper function to send request to firmware get HID descriptor of a device
*
* Return : 0 on success , non zero on error
*/
static int ishtp_get_hid_descriptor ( struct ishtp_cl * hid_ishtp_cl , int index )
{
struct hostif_msg msg ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
int rv ;
/* Get HID descriptor */
client_data - > hid_descr_done = false ;
memset ( & msg , 0 , sizeof ( struct hostif_msg ) ) ;
msg . hdr . command = HOSTIF_GET_HID_DESCRIPTOR ;
msg . hdr . device_id = client_data - > hid_devices [ index ] . dev_id ;
rv = ishtp_cl_send ( hid_ishtp_cl , ( unsigned char * ) & msg ,
sizeof ( struct hostif_msg ) ) ;
if ( rv )
return rv ;
if ( ! client_data - > hid_descr_done ) {
wait_event_interruptible_timeout ( client_data - > init_wait ,
client_data - > hid_descr_done ,
3 * HZ ) ;
if ( ! client_data - > hid_descr_done ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: timed out for hid_descr_done \n " ) ;
return - EIO ;
}
if ( ! client_data - > hid_descr [ index ] ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: allocation HID desc fail \n " ) ;
return - ENOMEM ;
}
}
return 0 ;
}
/**
* ishtp_get_report_descriptor ( ) - Get report descriptor
* @ hid_ishtp_cl : client instance
* @ index : Index into the hid_descr array
*
* Helper function to send request to firmware get HID report descriptor of
* a device
*
* Return : 0 on success , non zero on error
*/
static int ishtp_get_report_descriptor ( struct ishtp_cl * hid_ishtp_cl ,
int index )
{
struct hostif_msg msg ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
int rv ;
/* Get report descriptor */
client_data - > report_descr_done = false ;
memset ( & msg , 0 , sizeof ( struct hostif_msg ) ) ;
msg . hdr . command = HOSTIF_GET_REPORT_DESCRIPTOR ;
msg . hdr . device_id = client_data - > hid_devices [ index ] . dev_id ;
rv = ishtp_cl_send ( hid_ishtp_cl , ( unsigned char * ) & msg ,
sizeof ( struct hostif_msg ) ) ;
if ( rv )
return rv ;
if ( ! client_data - > report_descr_done )
wait_event_interruptible_timeout ( client_data - > init_wait ,
client_data - > report_descr_done ,
3 * HZ ) ;
if ( ! client_data - > report_descr_done ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: timed out for report descr \n " ) ;
return - EIO ;
}
if ( ! client_data - > report_descr [ index ] ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: failed to alloc report descr \n " ) ;
return - ENOMEM ;
}
return 0 ;
}
/**
* hid_ishtp_cl_init ( ) - Init function for ISHTP client
* @ hid_ishtp_cl : ISHTP client instance
* @ reset : true if called for init after reset
*
* This function complete the initializtion of the client . The summary of
* processing :
* - Send request to enumerate the hid clients
* Get the HID descriptor for each enumearated device
* Get report description of each device
* Register each device wik hid core by calling ishtp_hid_probe
*
* Return : 0 on success , non zero on error
*/
static int hid_ishtp_cl_init ( struct ishtp_cl * hid_ishtp_cl , int reset )
{
struct ishtp_device * dev ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2018-09-11 16:44:18 -07:00
struct ishtp_fw_client * fw_client ;
2016-08-07 02:25:36 -07:00
int i ;
int rv ;
2019-03-18 12:14:20 -07:00
dev_dbg ( cl_data_to_dev ( client_data ) , " %s \n " , __func__ ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s reset flag: %d \n " , __func__ , reset ) ;
2019-03-18 12:14:21 -07:00
rv = ishtp_cl_link ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
if ( rv ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" ishtp_cl_link failed \n " ) ;
return - ENOMEM ;
}
client_data - > init_done = 0 ;
2019-03-18 12:14:27 -07:00
dev = ishtp_get_ishtp_device ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
/* Connect to FW client */
2019-03-18 12:14:27 -07:00
ishtp_set_tx_ring_size ( hid_ishtp_cl , HID_CL_TX_RING_SIZE ) ;
ishtp_set_rx_ring_size ( hid_ishtp_cl , HID_CL_RX_RING_SIZE ) ;
2016-08-07 02:25:36 -07:00
2018-09-11 16:44:18 -07:00
fw_client = ishtp_fw_cl_get_client ( dev , & hid_ishtp_guid ) ;
if ( ! fw_client ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" ish client uuid not found \n " ) ;
2018-09-11 16:44:18 -07:00
return - ENOENT ;
2016-08-07 02:25:36 -07:00
}
2019-03-18 12:14:27 -07:00
ishtp_cl_set_fw_client_id ( hid_ishtp_cl ,
ishtp_get_fw_client_id ( fw_client ) ) ;
ishtp_set_connection_state ( hid_ishtp_cl , ISHTP_CL_CONNECTING ) ;
2016-08-07 02:25:36 -07:00
rv = ishtp_cl_connect ( hid_ishtp_cl ) ;
if ( rv ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" client connect fail \n " ) ;
goto err_cl_unlink ;
}
hid_ishtp_trace ( client_data , " %s client connected \n " , __func__ ) ;
/* Register read callback */
2019-03-18 12:14:27 -07:00
ishtp_register_event_cb ( client_data - > cl_device , ish_cl_event_cb ) ;
2016-08-07 02:25:36 -07:00
rv = ishtp_enum_enum_devices ( hid_ishtp_cl ) ;
if ( rv )
goto err_cl_disconnect ;
hid_ishtp_trace ( client_data , " %s enumerated device count %d \n " ,
__func__ , client_data - > num_hid_devices ) ;
for ( i = 0 ; i < client_data - > num_hid_devices ; + + i ) {
client_data - > cur_hid_dev = i ;
rv = ishtp_get_hid_descriptor ( hid_ishtp_cl , i ) ;
if ( rv )
goto err_cl_disconnect ;
rv = ishtp_get_report_descriptor ( hid_ishtp_cl , i ) ;
if ( rv )
goto err_cl_disconnect ;
if ( ! reset ) {
rv = ishtp_hid_probe ( i , client_data ) ;
if ( rv ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) ,
2016-08-07 02:25:36 -07:00
" [hid-ish]: HID probe for #%u failed: %d \n " ,
i , rv ) ;
goto err_cl_disconnect ;
}
}
} /* for() on all hid devices */
client_data - > init_done = 1 ;
client_data - > suspended = false ;
wake_up_interruptible ( & client_data - > ishtp_resume_wait ) ;
hid_ishtp_trace ( client_data , " %s successful init \n " , __func__ ) ;
return 0 ;
err_cl_disconnect :
2019-03-18 12:14:27 -07:00
ishtp_set_connection_state ( hid_ishtp_cl , ISHTP_CL_DISCONNECTING ) ;
2016-08-07 02:25:36 -07:00
ishtp_cl_disconnect ( hid_ishtp_cl ) ;
err_cl_unlink :
ishtp_cl_unlink ( hid_ishtp_cl ) ;
return rv ;
}
/**
* hid_ishtp_cl_deinit ( ) - Deinit function for ISHTP client
* @ hid_ishtp_cl : ISHTP client instance
*
* Unlink and free hid client
*/
static void hid_ishtp_cl_deinit ( struct ishtp_cl * hid_ishtp_cl )
{
ishtp_cl_unlink ( hid_ishtp_cl ) ;
ishtp_cl_flush_queues ( hid_ishtp_cl ) ;
/* disband and free all Tx and Rx client-level rings */
ishtp_cl_free ( hid_ishtp_cl ) ;
}
static void hid_ishtp_cl_reset_handler ( struct work_struct * work )
{
struct ishtp_cl_data * client_data ;
struct ishtp_cl * hid_ishtp_cl ;
struct ishtp_cl_device * cl_device ;
int retry ;
int rv ;
client_data = container_of ( work , struct ishtp_cl_data , work ) ;
hid_ishtp_cl = client_data - > hid_ishtp_cl ;
cl_device = client_data - > cl_device ;
hid_ishtp_trace ( client_data , " %s hid_ishtp_cl %p \n " , __func__ ,
hid_ishtp_cl ) ;
2019-03-18 12:14:27 -07:00
dev_dbg ( ishtp_device ( client_data - > cl_device ) , " %s \n " , __func__ ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_cl_deinit ( hid_ishtp_cl ) ;
2019-03-18 12:14:20 -07:00
hid_ishtp_cl = ishtp_cl_allocate ( cl_device ) ;
2016-08-07 02:25:36 -07:00
if ( ! hid_ishtp_cl )
return ;
2018-09-11 16:44:14 -07:00
ishtp_set_drvdata ( cl_device , hid_ishtp_cl ) ;
2019-03-18 12:14:27 -07:00
ishtp_set_client_data ( hid_ishtp_cl , client_data ) ;
2016-08-07 02:25:36 -07:00
client_data - > hid_ishtp_cl = hid_ishtp_cl ;
client_data - > num_hid_devices = 0 ;
for ( retry = 0 ; retry < 3 ; + + retry ) {
rv = hid_ishtp_cl_init ( hid_ishtp_cl , 1 ) ;
if ( ! rv )
break ;
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) , " Retry reset init \n " ) ;
2016-08-07 02:25:36 -07:00
}
if ( rv ) {
2019-03-18 12:14:20 -07:00
dev_err ( cl_data_to_dev ( client_data ) , " Reset Failed \n " ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s Failed hid_ishtp_cl %p \n " ,
__func__ , hid_ishtp_cl ) ;
}
}
2019-03-18 12:14:27 -07:00
void ( * hid_print_trace ) ( void * unused , const char * format , . . . ) ;
2019-03-18 12:14:20 -07:00
2016-08-07 02:25:36 -07:00
/**
* hid_ishtp_cl_probe ( ) - ISHTP client driver probe
* @ cl_device : ISHTP client device instance
*
* This function gets called on device create on ISHTP bus
*
* Return : 0 on success , non zero on error
*/
static int hid_ishtp_cl_probe ( struct ishtp_cl_device * cl_device )
{
struct ishtp_cl * hid_ishtp_cl ;
struct ishtp_cl_data * client_data ;
int rv ;
if ( ! cl_device )
return - ENODEV ;
2019-03-18 12:14:20 -07:00
client_data = devm_kzalloc ( ishtp_device ( cl_device ) ,
sizeof ( * client_data ) ,
2016-08-07 02:25:36 -07:00
GFP_KERNEL ) ;
if ( ! client_data )
return - ENOMEM ;
2019-03-18 12:14:20 -07:00
hid_ishtp_cl = ishtp_cl_allocate ( cl_device ) ;
2016-08-07 02:25:36 -07:00
if ( ! hid_ishtp_cl )
return - ENOMEM ;
2018-09-11 16:44:14 -07:00
ishtp_set_drvdata ( cl_device , hid_ishtp_cl ) ;
2019-03-18 12:14:27 -07:00
ishtp_set_client_data ( hid_ishtp_cl , client_data ) ;
2016-08-07 02:25:36 -07:00
client_data - > hid_ishtp_cl = hid_ishtp_cl ;
client_data - > cl_device = cl_device ;
init_waitqueue_head ( & client_data - > init_wait ) ;
init_waitqueue_head ( & client_data - > ishtp_resume_wait ) ;
INIT_WORK ( & client_data - > work , hid_ishtp_cl_reset_handler ) ;
2019-03-18 12:14:20 -07:00
hid_print_trace = ishtp_trace_callback ( cl_device ) ;
2016-08-07 02:25:36 -07:00
rv = hid_ishtp_cl_init ( hid_ishtp_cl , 0 ) ;
if ( rv ) {
ishtp_cl_free ( hid_ishtp_cl ) ;
return rv ;
}
ishtp_get_device ( cl_device ) ;
return 0 ;
}
/**
* hid_ishtp_cl_remove ( ) - ISHTP client driver remove
* @ cl_device : ISHTP client device instance
*
* This function gets called on device remove on ISHTP bus
*
* Return : 0
*/
static int hid_ishtp_cl_remove ( struct ishtp_cl_device * cl_device )
{
2018-09-11 16:44:14 -07:00
struct ishtp_cl * hid_ishtp_cl = ishtp_get_drvdata ( cl_device ) ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s hid_ishtp_cl %p \n " , __func__ ,
hid_ishtp_cl ) ;
2019-03-18 12:14:20 -07:00
dev_dbg ( ishtp_device ( cl_device ) , " %s \n " , __func__ ) ;
2019-03-18 12:14:27 -07:00
ishtp_set_connection_state ( hid_ishtp_cl , ISHTP_CL_DISCONNECTING ) ;
2016-08-07 02:25:36 -07:00
ishtp_cl_disconnect ( hid_ishtp_cl ) ;
ishtp_put_device ( cl_device ) ;
ishtp_hid_remove ( client_data ) ;
hid_ishtp_cl_deinit ( hid_ishtp_cl ) ;
hid_ishtp_cl = NULL ;
client_data - > num_hid_devices = 0 ;
return 0 ;
}
/**
* hid_ishtp_cl_reset ( ) - ISHTP client driver reset
* @ cl_device : ISHTP client device instance
*
* This function gets called on device reset on ISHTP bus
*
* Return : 0
*/
static int hid_ishtp_cl_reset ( struct ishtp_cl_device * cl_device )
{
2018-09-11 16:44:14 -07:00
struct ishtp_cl * hid_ishtp_cl = ishtp_get_drvdata ( cl_device ) ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s hid_ishtp_cl %p \n " , __func__ ,
hid_ishtp_cl ) ;
schedule_work ( & client_data - > work ) ;
return 0 ;
}
/**
* hid_ishtp_cl_suspend ( ) - ISHTP client driver suspend
* @ device : device instance
*
* This function gets called on system suspend
*
* Return : 0
*/
static int hid_ishtp_cl_suspend ( struct device * device )
{
2019-06-05 21:52:27 -07:00
struct ishtp_cl_device * cl_device = ishtp_dev_to_cl_device ( device ) ;
2018-09-11 16:44:14 -07:00
struct ishtp_cl * hid_ishtp_cl = ishtp_get_drvdata ( cl_device ) ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s hid_ishtp_cl %p \n " , __func__ ,
hid_ishtp_cl ) ;
client_data - > suspended = true ;
return 0 ;
}
/**
* hid_ishtp_cl_resume ( ) - ISHTP client driver resume
* @ device : device instance
*
* This function gets called on system resume
*
* Return : 0
*/
static int hid_ishtp_cl_resume ( struct device * device )
{
2019-06-05 21:52:27 -07:00
struct ishtp_cl_device * cl_device = ishtp_dev_to_cl_device ( device ) ;
2018-09-11 16:44:14 -07:00
struct ishtp_cl * hid_ishtp_cl = ishtp_get_drvdata ( cl_device ) ;
2019-03-18 12:14:27 -07:00
struct ishtp_cl_data * client_data = ishtp_get_client_data ( hid_ishtp_cl ) ;
2016-08-07 02:25:36 -07:00
hid_ishtp_trace ( client_data , " %s hid_ishtp_cl %p \n " , __func__ ,
hid_ishtp_cl ) ;
client_data - > suspended = false ;
return 0 ;
}
static const struct dev_pm_ops hid_ishtp_pm_ops = {
. suspend = hid_ishtp_cl_suspend ,
. resume = hid_ishtp_cl_resume ,
} ;
static struct ishtp_cl_driver hid_ishtp_cl_driver = {
. name = " ish-hid " ,
2019-03-18 12:14:19 -07:00
. guid = & hid_ishtp_guid ,
2016-08-07 02:25:36 -07:00
. probe = hid_ishtp_cl_probe ,
. remove = hid_ishtp_cl_remove ,
. reset = hid_ishtp_cl_reset ,
. driver . pm = & hid_ishtp_pm_ops ,
} ;
static int __init ish_hid_init ( void )
{
int rv ;
/* Register ISHTP client device driver with ISHTP Bus */
2019-03-18 12:14:22 -07:00
rv = ishtp_cl_driver_register ( & hid_ishtp_cl_driver , THIS_MODULE ) ;
2016-08-07 02:25:36 -07:00
return rv ;
}
static void __exit ish_hid_exit ( void )
{
ishtp_cl_driver_unregister ( & hid_ishtp_cl_driver ) ;
}
late_initcall ( ish_hid_init ) ;
module_exit ( ish_hid_exit ) ;
MODULE_DESCRIPTION ( " ISH ISHTP HID client driver " ) ;
/* Primary author */
MODULE_AUTHOR ( " Daniel Drubin <daniel.drubin@intel.com> " ) ;
/*
* Several modification for multi instance support
* suspend / resume and clean up
*/
MODULE_AUTHOR ( " Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " ishtp:* " ) ;