2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-06-20 23:26:11 +04:00
/*
* HID driver for some microsoft " special " devices
*
* Copyright ( c ) 1999 Andreas Gal
* Copyright ( c ) 2000 - 2005 Vojtech Pavlik < vojtech @ suse . cz >
* Copyright ( c ) 2005 Michael Haboustak < mike - @ cinci . rr . com > for Concept2 , Inc
* Copyright ( c ) 2006 - 2007 Jiri Kosina
* Copyright ( c ) 2008 Jiri Slaby
*/
/*
*/
# include <linux/device.h>
# include <linux/input.h>
# include <linux/hid.h>
# include <linux/module.h>
# include "hid-ids.h"
2018-07-13 17:13:51 +03:00
# define MS_HIDINPUT BIT(0)
# define MS_ERGONOMY BIT(1)
# define MS_PRESENTER BIT(2)
# define MS_RDESC BIT(3)
# define MS_NOGET BIT(4)
# define MS_DUPLICATE_USAGES BIT(5)
# define MS_SURFACE_DIAL BIT(6)
2018-08-16 05:44:10 +03:00
# define MS_QUIRK_FF BIT(7)
2008-06-20 23:26:11 +04:00
2018-08-16 05:44:09 +03:00
struct ms_data {
unsigned long quirks ;
2018-08-16 05:44:10 +03:00
struct hid_device * hdev ;
struct work_struct ff_worker ;
__u8 strong ;
__u8 weak ;
void * output_report_dmabuf ;
2018-08-16 05:44:09 +03:00
} ;
2018-08-16 05:44:10 +03:00
# define XB1S_FF_REPORT 3
# define ENABLE_WEAK BIT(0)
# define ENABLE_STRONG BIT(1)
enum {
MAGNITUDE_STRONG = 2 ,
MAGNITUDE_WEAK ,
MAGNITUDE_NUM
} ;
struct xb1s_ff_report {
__u8 report_id ;
__u8 enable ;
__u8 magnitude [ MAGNITUDE_NUM ] ;
__u8 duration_10ms ;
__u8 start_delay_10ms ;
__u8 loop_count ;
} __packed ;
2010-08-06 23:03:06 +04:00
static __u8 * ms_report_fixup ( struct hid_device * hdev , __u8 * rdesc ,
unsigned int * rsize )
2008-06-20 23:26:11 +04:00
{
2018-08-16 05:44:09 +03:00
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
unsigned long quirks = ms - > quirks ;
2008-06-20 23:26:11 +04:00
2012-10-19 15:28:46 +04:00
/*
* Microsoft Wireless Desktop Receiver ( Model 1028 ) has
* ' Usage Min / Max ' where it ought to have ' Physical Min / Max '
*/
2010-08-06 23:03:06 +04:00
if ( ( quirks & MS_RDESC ) & & * rsize = = 571 & & rdesc [ 557 ] = = 0x19 & &
2008-06-20 23:26:11 +04:00
rdesc [ 559 ] = = 0x29 ) {
2010-12-10 06:29:03 +03:00
hid_info ( hdev , " fixing up Microsoft Wireless Receiver Model 1028 report descriptor \n " ) ;
2009-01-14 05:03:21 +03:00
rdesc [ 557 ] = 0x35 ;
rdesc [ 559 ] = 0x45 ;
2008-06-20 23:26:11 +04:00
}
2010-08-06 23:03:06 +04:00
return rdesc ;
2008-06-20 23:26:11 +04:00
}
# define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
EV_KEY , ( c ) )
static int ms_ergonomy_kb_quirk ( struct hid_input * hi , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
struct input_dev * input = hi - > input ;
2014-01-29 20:57:44 +04:00
if ( ( usage - > hid & HID_USAGE_PAGE ) = = HID_UP_CONSUMER ) {
switch ( usage - > hid & HID_USAGE ) {
/*
* Microsoft uses these 2 reserved usage ids for 2 keys on
* the MS office kb labelled " Office Home " and " Task Pane " .
*/
case 0x29d :
ms_map_key_clear ( KEY_PROG1 ) ;
return 1 ;
case 0x29e :
ms_map_key_clear ( KEY_PROG2 ) ;
return 1 ;
}
return 0 ;
}
2014-01-29 20:57:42 +04:00
if ( ( usage - > hid & HID_USAGE_PAGE ) ! = HID_UP_MSVENDOR )
return 0 ;
2008-06-20 23:26:11 +04:00
switch ( usage - > hid & HID_USAGE ) {
case 0xfd06 : ms_map_key_clear ( KEY_CHAT ) ; break ;
case 0xfd07 : ms_map_key_clear ( KEY_PHONE ) ; break ;
2014-01-29 20:57:43 +04:00
case 0xff00 :
/* Special keypad keys */
ms_map_key_clear ( KEY_KPEQUAL ) ;
set_bit ( KEY_KPLEFTPAREN , input - > keybit ) ;
set_bit ( KEY_KPRIGHTPAREN , input - > keybit ) ;
break ;
case 0xff01 :
/* Scroll wheel */
hid_map_usage_clear ( hi , usage , bit , max , EV_REL , REL_WHEEL ) ;
break ;
case 0xff02 :
/*
* This byte contains a copy of the modifier keys byte of a
* standard hid keyboard report , as send by interface 0
* ( this usage is found on interface 1 ) .
*
* This byte only gets send when another key in the same report
* changes state , and as such is useless , ignore it .
*/
return - 1 ;
2008-06-20 23:26:11 +04:00
case 0xff05 :
set_bit ( EV_REP , input - > evbit ) ;
ms_map_key_clear ( KEY_F13 ) ;
set_bit ( KEY_F14 , input - > keybit ) ;
set_bit ( KEY_F15 , input - > keybit ) ;
set_bit ( KEY_F16 , input - > keybit ) ;
set_bit ( KEY_F17 , input - > keybit ) ;
set_bit ( KEY_F18 , input - > keybit ) ;
2013-12-15 21:25:26 +04:00
break ;
2008-06-20 23:26:11 +04:00
default :
return 0 ;
}
return 1 ;
}
static int ms_presenter_8k_quirk ( struct hid_input * hi , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
2014-01-29 20:57:42 +04:00
if ( ( usage - > hid & HID_USAGE_PAGE ) ! = HID_UP_MSVENDOR )
return 0 ;
2008-06-20 23:26:11 +04:00
set_bit ( EV_REP , hi - > input - > evbit ) ;
switch ( usage - > hid & HID_USAGE ) {
case 0xfd08 : ms_map_key_clear ( KEY_FORWARD ) ; break ;
case 0xfd09 : ms_map_key_clear ( KEY_BACK ) ; break ;
case 0xfd0b : ms_map_key_clear ( KEY_PLAYPAUSE ) ; break ;
case 0xfd0e : ms_map_key_clear ( KEY_CLOSE ) ; break ;
case 0xfd0f : ms_map_key_clear ( KEY_PLAY ) ; break ;
default :
return 0 ;
}
return 1 ;
}
2018-07-13 17:13:51 +03:00
static int ms_surface_dial_quirk ( struct hid_input * hi , struct hid_field * field ,
struct hid_usage * usage , unsigned long * * bit , int * max )
{
switch ( usage - > hid & HID_USAGE_PAGE ) {
case 0xff070000 :
case HID_UP_DIGITIZER :
/* ignore those axis */
return - 1 ;
case HID_UP_GENDESK :
switch ( usage - > hid ) {
case HID_GD_X :
case HID_GD_Y :
case HID_GD_RFKILL_BTN :
/* ignore those axis */
return - 1 ;
}
}
return 0 ;
}
2008-06-20 23:26:11 +04:00
static int ms_input_mapping ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
2018-08-16 05:44:09 +03:00
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
unsigned long quirks = ms - > quirks ;
2008-06-20 23:26:11 +04:00
if ( quirks & MS_ERGONOMY ) {
int ret = ms_ergonomy_kb_quirk ( hi , usage , bit , max ) ;
if ( ret )
return ret ;
}
if ( ( quirks & MS_PRESENTER ) & &
ms_presenter_8k_quirk ( hi , usage , bit , max ) )
return 1 ;
2018-07-13 17:13:51 +03:00
if ( quirks & MS_SURFACE_DIAL ) {
int ret = ms_surface_dial_quirk ( hi , field , usage , bit , max ) ;
if ( ret )
return ret ;
}
2008-06-20 23:26:11 +04:00
return 0 ;
}
2011-07-11 22:42:52 +04:00
static int ms_input_mapped ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
2018-08-16 05:44:09 +03:00
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
unsigned long quirks = ms - > quirks ;
2011-07-11 22:42:52 +04:00
if ( quirks & MS_DUPLICATE_USAGES )
clear_bit ( usage - > code , * bit ) ;
return 0 ;
}
2008-06-20 23:26:11 +04:00
static int ms_event ( struct hid_device * hdev , struct hid_field * field ,
struct hid_usage * usage , __s32 value )
{
2018-08-16 05:44:09 +03:00
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
unsigned long quirks = ms - > quirks ;
2014-01-29 20:57:43 +04:00
struct input_dev * input ;
2008-06-20 23:26:11 +04:00
if ( ! ( hdev - > claimed & HID_CLAIMED_INPUT ) | | ! field - > hidinput | |
! usage - > type )
return 0 ;
2014-01-29 20:57:43 +04:00
input = field - > hidinput - > input ;
2008-06-20 23:26:11 +04:00
/* Handling MS keyboards special buttons */
2014-01-29 20:57:43 +04:00
if ( quirks & MS_ERGONOMY & & usage - > hid = = ( HID_UP_MSVENDOR | 0xff00 ) ) {
/* Special keypad keys */
input_report_key ( input , KEY_KPEQUAL , value & 0x01 ) ;
input_report_key ( input , KEY_KPLEFTPAREN , value & 0x02 ) ;
input_report_key ( input , KEY_KPRIGHTPAREN , value & 0x04 ) ;
return 1 ;
}
if ( quirks & MS_ERGONOMY & & usage - > hid = = ( HID_UP_MSVENDOR | 0xff01 ) ) {
/* Scroll wheel */
int step = ( ( value & 0x60 ) > > 5 ) + 1 ;
switch ( value & 0x1f ) {
case 0x01 :
input_report_rel ( input , REL_WHEEL , step ) ;
break ;
case 0x1f :
input_report_rel ( input , REL_WHEEL , - step ) ;
break ;
}
return 1 ;
}
2008-06-20 23:26:11 +04:00
if ( quirks & MS_ERGONOMY & & usage - > hid = = ( HID_UP_MSVENDOR | 0xff05 ) ) {
static unsigned int last_key = 0 ;
unsigned int key = 0 ;
switch ( value ) {
case 0x01 : key = KEY_F14 ; break ;
case 0x02 : key = KEY_F15 ; break ;
case 0x04 : key = KEY_F16 ; break ;
case 0x08 : key = KEY_F17 ; break ;
case 0x10 : key = KEY_F18 ; break ;
}
if ( key ) {
input_event ( input , usage - > type , key , 1 ) ;
last_key = key ;
} else
input_event ( input , usage - > type , last_key , 0 ) ;
return 1 ;
}
return 0 ;
}
2018-08-16 05:44:10 +03:00
static void ms_ff_worker ( struct work_struct * work )
{
struct ms_data * ms = container_of ( work , struct ms_data , ff_worker ) ;
struct hid_device * hdev = ms - > hdev ;
struct xb1s_ff_report * r = ms - > output_report_dmabuf ;
int ret ;
memset ( r , 0 , sizeof ( * r ) ) ;
r - > report_id = XB1S_FF_REPORT ;
r - > enable = ENABLE_WEAK | ENABLE_STRONG ;
/*
* Specifying maximum duration and maximum loop count should
* cover maximum duration of a single effect , which is 65536
* ms
*/
r - > duration_10ms = U8_MAX ;
r - > loop_count = U8_MAX ;
r - > magnitude [ MAGNITUDE_STRONG ] = ms - > strong ; /* left actuator */
r - > magnitude [ MAGNITUDE_WEAK ] = ms - > weak ; /* right actuator */
ret = hid_hw_output_report ( hdev , ( __u8 * ) r , sizeof ( * r ) ) ;
2019-09-06 14:06:44 +03:00
if ( ret < 0 )
2018-08-16 05:44:10 +03:00
hid_warn ( hdev , " failed to send FF report \n " ) ;
}
static int ms_play_effect ( struct input_dev * dev , void * data ,
struct ff_effect * effect )
{
struct hid_device * hid = input_get_drvdata ( dev ) ;
struct ms_data * ms = hid_get_drvdata ( hid ) ;
if ( effect - > type ! = FF_RUMBLE )
return 0 ;
/*
* Magnitude is 0. .100 so scale the 16 - bit input here
*/
ms - > strong = ( ( u32 ) effect - > u . rumble . strong_magnitude * 100 ) / U16_MAX ;
ms - > weak = ( ( u32 ) effect - > u . rumble . weak_magnitude * 100 ) / U16_MAX ;
schedule_work ( & ms - > ff_worker ) ;
return 0 ;
}
static int ms_init_ff ( struct hid_device * hdev )
{
2019-10-03 21:53:59 +03:00
struct hid_input * hidinput ;
struct input_dev * input_dev ;
2018-08-16 05:44:10 +03:00
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
2019-10-03 21:53:59 +03:00
if ( list_empty ( & hdev - > inputs ) ) {
hid_err ( hdev , " no inputs found \n " ) ;
return - ENODEV ;
}
hidinput = list_entry ( hdev - > inputs . next , struct hid_input , list ) ;
input_dev = hidinput - > input ;
2018-08-16 05:44:10 +03:00
if ( ! ( ms - > quirks & MS_QUIRK_FF ) )
return 0 ;
ms - > hdev = hdev ;
INIT_WORK ( & ms - > ff_worker , ms_ff_worker ) ;
ms - > output_report_dmabuf = devm_kzalloc ( & hdev - > dev ,
sizeof ( struct xb1s_ff_report ) ,
GFP_KERNEL ) ;
if ( ms - > output_report_dmabuf = = NULL )
return - ENOMEM ;
input_set_capability ( input_dev , EV_FF , FF_RUMBLE ) ;
return input_ff_create_memless ( input_dev , NULL , ms_play_effect ) ;
}
static void ms_remove_ff ( struct hid_device * hdev )
{
struct ms_data * ms = hid_get_drvdata ( hdev ) ;
if ( ! ( ms - > quirks & MS_QUIRK_FF ) )
return ;
cancel_work_sync ( & ms - > ff_worker ) ;
}
2008-06-20 23:26:11 +04:00
static int ms_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
unsigned long quirks = id - > driver_data ;
2018-08-16 05:44:09 +03:00
struct ms_data * ms ;
2008-06-20 23:26:11 +04:00
int ret ;
2018-08-16 05:44:09 +03:00
ms = devm_kzalloc ( & hdev - > dev , sizeof ( * ms ) , GFP_KERNEL ) ;
if ( ms = = NULL )
return - ENOMEM ;
ms - > quirks = quirks ;
hid_set_drvdata ( hdev , ms ) ;
2008-06-20 23:26:11 +04:00
if ( quirks & MS_NOGET )
hdev - > quirks | = HID_QUIRK_NOGET ;
2018-07-13 17:13:51 +03:00
if ( quirks & MS_SURFACE_DIAL )
hdev - > quirks | = HID_QUIRK_INPUT_PER_APP ;
2008-06-20 23:26:11 +04:00
ret = hid_parse ( hdev ) ;
if ( ret ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " parse failed \n " ) ;
2008-06-20 23:26:11 +04:00
goto err_free ;
}
2008-06-27 02:04:24 +04:00
ret = hid_hw_start ( hdev , HID_CONNECT_DEFAULT | ( ( quirks & MS_HIDINPUT ) ?
HID_CONNECT_HIDINPUT_FORCE : 0 ) ) ;
2008-06-20 23:26:11 +04:00
if ( ret ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " hw start failed \n " ) ;
2008-06-20 23:26:11 +04:00
goto err_free ;
}
2018-08-16 05:44:10 +03:00
ret = ms_init_ff ( hdev ) ;
if ( ret )
hid_err ( hdev , " could not initialize ff, continuing anyway " ) ;
2008-06-20 23:26:11 +04:00
return 0 ;
err_free :
return ret ;
}
2018-08-16 05:44:10 +03:00
static void ms_remove ( struct hid_device * hdev )
{
hid_hw_stop ( hdev ) ;
ms_remove_ff ( hdev ) ;
}
2008-06-20 23:26:11 +04:00
static const struct hid_device_id ms_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_SIDEWINDER_GV ) ,
. driver_data = MS_HIDINPUT } ,
2014-01-29 20:57:43 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_OFFICE_KB ) ,
. driver_data = MS_ERGONOMY } ,
2008-06-20 23:26:11 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_NE4K ) ,
. driver_data = MS_ERGONOMY } ,
2013-04-29 08:27:31 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_NE4K_JP ) ,
. driver_data = MS_ERGONOMY } ,
2015-02-21 22:51:08 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_NE7K ) ,
. driver_data = MS_ERGONOMY } ,
2008-06-20 23:26:11 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_LK6K ) ,
. driver_data = MS_ERGONOMY | MS_RDESC } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_PRESENTER_8K_USB ) ,
. driver_data = MS_PRESENTER } ,
2011-06-14 00:08:18 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K ) ,
2016-09-20 20:50:51 +03:00
. driver_data = MS_ERGONOMY } ,
2016-04-04 13:51:40 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K ) ,
. driver_data = MS_ERGONOMY } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 ) ,
. driver_data = MS_ERGONOMY } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 ) ,
. driver_data = MS_ERGONOMY } ,
2008-06-20 23:26:11 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 ) ,
. driver_data = MS_NOGET } ,
2011-07-11 22:42:52 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 ) ,
. driver_data = MS_DUPLICATE_USAGES } ,
2015-06-08 12:11:38 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_POWER_COVER ) ,
. driver_data = MS_HIDINPUT } ,
2016-03-11 19:57:24 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_COMFORT_KEYBOARD ) ,
. driver_data = MS_ERGONOMY } ,
2008-06-20 23:26:11 +04:00
{ HID_BLUETOOTH_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_PRESENTER_8K_BT ) ,
. driver_data = MS_PRESENTER } ,
2018-07-13 17:13:51 +03:00
{ HID_BLUETOOTH_DEVICE ( USB_VENDOR_ID_MICROSOFT , 0x091B ) ,
. driver_data = MS_SURFACE_DIAL } ,
2018-08-16 05:44:10 +03:00
{ HID_BLUETOOTH_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER ) ,
. driver_data = MS_QUIRK_FF } ,
2020-08-29 07:14:29 +03:00
{ HID_BLUETOOTH_DEVICE ( USB_VENDOR_ID_MICROSOFT , USB_DEVICE_ID_8BITDO_SN30_PRO_PLUS ) ,
. driver_data = MS_QUIRK_FF } ,
2008-06-20 23:26:11 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( hid , ms_devices ) ;
static struct hid_driver ms_driver = {
. name = " microsoft " ,
. id_table = ms_devices ,
. report_fixup = ms_report_fixup ,
. input_mapping = ms_input_mapping ,
2011-07-11 22:42:52 +04:00
. input_mapped = ms_input_mapped ,
2008-06-20 23:26:11 +04:00
. event = ms_event ,
. probe = ms_probe ,
2018-08-16 05:44:10 +03:00
. remove = ms_remove ,
2008-06-20 23:26:11 +04:00
} ;
2012-12-18 02:28:26 +04:00
module_hid_driver ( ms_driver ) ;
2008-06-20 23:26:11 +04:00
MODULE_LICENSE ( " GPL " ) ;