2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-10-26 11:15:58 +03:00
/*
* HID driver for Google Fiber TV Box remote controls
*
* Copyright ( c ) 2014 - 2015 Google Inc .
*
* Author : Petri Gynther < pgynther @ google . com >
*/
# include <linux/device.h>
# include <linux/hid.h>
# include <linux/input.h>
# include <linux/module.h>
# include "hid-ids.h"
# define GFRM100 1 /* Google Fiber GFRM100 (Bluetooth classic) */
# define GFRM200 2 /* Google Fiber GFRM200 (Bluetooth LE) */
# define GFRM100_SEARCH_KEY_REPORT_ID 0xF7
# define GFRM100_SEARCH_KEY_DOWN 0x0
# define GFRM100_SEARCH_KEY_AUDIO_DATA 0x1
# define GFRM100_SEARCH_KEY_UP 0x2
static u8 search_key_dn [ 3 ] = { 0x40 , 0x21 , 0x02 } ;
static u8 search_key_up [ 3 ] = { 0x40 , 0x00 , 0x00 } ;
static int gfrm_input_mapping ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
unsigned long hdev_type = ( unsigned long ) hid_get_drvdata ( hdev ) ;
if ( hdev_type = = GFRM100 ) {
if ( usage - > hid = = ( HID_UP_CONSUMER | 0x4 ) ) {
/* Consumer.0004 -> KEY_INFO */
hid_map_usage_clear ( hi , usage , bit , max , EV_KEY , KEY_INFO ) ;
return 1 ;
}
if ( usage - > hid = = ( HID_UP_CONSUMER | 0x41 ) ) {
/* Consumer.0041 -> KEY_OK */
hid_map_usage_clear ( hi , usage , bit , max , EV_KEY , KEY_OK ) ;
return 1 ;
}
}
return 0 ;
}
static int gfrm_raw_event ( struct hid_device * hdev , struct hid_report * report ,
u8 * data , int size )
{
unsigned long hdev_type = ( unsigned long ) hid_get_drvdata ( hdev ) ;
int ret = 0 ;
if ( hdev_type ! = GFRM100 )
return 0 ;
if ( size < 2 | | data [ 0 ] ! = GFRM100_SEARCH_KEY_REPORT_ID )
return 0 ;
/*
* Convert GFRM100 Search key reports into Consumer .0221 ( Key . Search )
* reports . Ignore audio data .
*/
switch ( data [ 1 ] ) {
case GFRM100_SEARCH_KEY_DOWN :
ret = hid_report_raw_event ( hdev , HID_INPUT_REPORT , search_key_dn ,
sizeof ( search_key_dn ) , 1 ) ;
break ;
case GFRM100_SEARCH_KEY_AUDIO_DATA :
break ;
case GFRM100_SEARCH_KEY_UP :
ret = hid_report_raw_event ( hdev , HID_INPUT_REPORT , search_key_up ,
sizeof ( search_key_up ) , 1 ) ;
break ;
default :
break ;
}
return ( ret < 0 ) ? ret : - 1 ;
}
2015-11-05 21:10:27 +03:00
static int gfrm_input_configured ( struct hid_device * hid , struct hid_input * hidinput )
2015-10-26 11:15:58 +03:00
{
/*
* Enable software autorepeat with :
* - repeat delay : 400 msec
* - repeat period : 100 msec
*/
input_enable_softrepeat ( hidinput - > input , 400 , 100 ) ;
2015-11-05 21:10:27 +03:00
return 0 ;
2015-10-26 11:15:58 +03:00
}
static int gfrm_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
int ret ;
hid_set_drvdata ( hdev , ( void * ) id - > driver_data ) ;
ret = hid_parse ( hdev ) ;
if ( ret )
goto done ;
if ( id - > driver_data = = GFRM100 ) {
/*
* GFRM100 HID Report Descriptor does not describe the Search
* key reports . Thus , we need to add it manually here , so that
* those reports reach gfrm_raw_event ( ) from hid_input_report ( ) .
*/
if ( ! hid_register_report ( hdev , HID_INPUT_REPORT ,
2018-04-24 11:04:33 +03:00
GFRM100_SEARCH_KEY_REPORT_ID , 0 ) ) {
2015-10-26 11:15:58 +03:00
ret = - ENOMEM ;
goto done ;
}
}
ret = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
done :
return ret ;
}
static const struct hid_device_id gfrm_devices [ ] = {
{ HID_BLUETOOTH_DEVICE ( 0x58 , 0x2000 ) ,
. driver_data = GFRM100 } ,
{ HID_BLUETOOTH_DEVICE ( 0x471 , 0x2210 ) ,
. driver_data = GFRM200 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , gfrm_devices ) ;
static struct hid_driver gfrm_driver = {
. name = " gfrm " ,
. id_table = gfrm_devices ,
. probe = gfrm_probe ,
. input_mapping = gfrm_input_mapping ,
. raw_event = gfrm_raw_event ,
. input_configured = gfrm_input_configured ,
} ;
module_hid_driver ( gfrm_driver ) ;
MODULE_AUTHOR ( " Petri Gynther <pgynther@google.com> " ) ;
MODULE_DESCRIPTION ( " Google Fiber TV Box remote control driver " ) ;
MODULE_LICENSE ( " GPL " ) ;