2011-01-30 15:38:24 +03:00
/*
* Roccat Kova [ + ] driver for Linux
*
* Copyright ( c ) 2011 Stefan Achatz < erazor_de @ users . sourceforge . net >
*/
/*
* 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 .
*/
/*
* Roccat Kova [ + ] is a bigger version of the Pyra with two more side buttons .
*/
# include <linux/device.h>
# include <linux/input.h>
# include <linux/hid.h>
# include <linux/module.h>
# include <linux/slab.h>
2011-02-03 18:14:43 +03:00
# include <linux/hid-roccat.h>
2011-01-30 15:38:24 +03:00
# include "hid-ids.h"
# include "hid-roccat-common.h"
# include "hid-roccat-kovaplus.h"
static uint profile_numbers [ 5 ] = { 0 , 1 , 2 , 3 , 4 } ;
static struct class * kovaplus_class ;
static uint kovaplus_convert_event_cpi ( uint value )
{
return ( value = = 7 ? 4 : ( value = = 4 ? 3 : value ) ) ;
}
static void kovaplus_profile_activated ( struct kovaplus_device * kovaplus ,
uint new_profile_index )
{
kovaplus - > actual_profile = new_profile_index ;
kovaplus - > actual_cpi = kovaplus - > profile_settings [ new_profile_index ] . cpi_startup_level ;
kovaplus - > actual_x_sensitivity = kovaplus - > profile_settings [ new_profile_index ] . sensitivity_x ;
kovaplus - > actual_y_sensitivity = kovaplus - > profile_settings [ new_profile_index ] . sensitivity_y ;
}
static int kovaplus_send_control ( struct usb_device * usb_dev , uint value ,
enum kovaplus_control_requests request )
{
int retval ;
2012-05-21 00:45:04 +04:00
struct roccat_common2_control control ;
2011-01-30 15:38:24 +03:00
if ( ( request = = KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS | |
request = = KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS ) & &
value > 4 )
return - EINVAL ;
2012-05-21 00:44:59 +04:00
control . command = ROCCAT_COMMON_COMMAND_CONTROL ;
2011-01-30 15:38:24 +03:00
control . value = value ;
control . request = request ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , ROCCAT_COMMON_COMMAND_CONTROL ,
& control , sizeof ( struct roccat_common2_control ) ) ;
2011-01-30 15:38:24 +03:00
return retval ;
}
static int kovaplus_select_profile ( struct usb_device * usb_dev , uint number ,
enum kovaplus_control_requests request )
{
return kovaplus_send_control ( usb_dev , number , request ) ;
}
static int kovaplus_get_profile_settings ( struct usb_device * usb_dev ,
struct kovaplus_profile_settings * buf , uint number )
{
int retval ;
retval = kovaplus_select_profile ( usb_dev , number ,
KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ) ;
if ( retval )
return retval ;
2012-05-21 00:45:04 +04:00
return roccat_common2_receive ( usb_dev , KOVAPLUS_COMMAND_PROFILE_SETTINGS ,
2012-11-11 09:20:52 +04:00
buf , KOVAPLUS_SIZE_PROFILE_SETTINGS ) ;
2011-01-30 15:38:24 +03:00
}
static int kovaplus_get_profile_buttons ( struct usb_device * usb_dev ,
struct kovaplus_profile_buttons * buf , int number )
{
int retval ;
retval = kovaplus_select_profile ( usb_dev , number ,
KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS ) ;
if ( retval )
return retval ;
2012-05-21 00:45:04 +04:00
return roccat_common2_receive ( usb_dev , KOVAPLUS_COMMAND_PROFILE_BUTTONS ,
2012-11-11 09:20:52 +04:00
buf , KOVAPLUS_SIZE_PROFILE_BUTTONS ) ;
2011-01-30 15:38:24 +03:00
}
/* retval is 0-4 on success, < 0 on error */
static int kovaplus_get_actual_profile ( struct usb_device * usb_dev )
{
struct kovaplus_actual_profile buf ;
int retval ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev , KOVAPLUS_COMMAND_ACTUAL_PROFILE ,
2011-01-30 15:38:24 +03:00
& buf , sizeof ( struct kovaplus_actual_profile ) ) ;
return retval ? retval : buf . actual_profile ;
}
static int kovaplus_set_actual_profile ( struct usb_device * usb_dev ,
int new_profile )
{
struct kovaplus_actual_profile buf ;
buf . command = KOVAPLUS_COMMAND_ACTUAL_PROFILE ;
buf . size = sizeof ( struct kovaplus_actual_profile ) ;
buf . actual_profile = new_profile ;
2012-05-21 00:45:04 +04:00
return roccat_common2_send_with_status ( usb_dev ,
2012-05-21 00:44:59 +04:00
KOVAPLUS_COMMAND_ACTUAL_PROFILE ,
2011-01-30 15:38:24 +03:00
& buf , sizeof ( struct kovaplus_actual_profile ) ) ;
}
2012-11-11 09:20:52 +04:00
static ssize_t kovaplus_sysfs_read ( struct file * fp , struct kobject * kobj ,
char * buf , loff_t off , size_t count ,
size_t real_size , uint command )
2011-01-30 15:38:24 +03:00
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2011-01-30 15:38:24 +03:00
struct kovaplus_device * kovaplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
2012-11-11 09:20:52 +04:00
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval ;
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
if ( off > = real_size )
2011-01-30 15:38:24 +03:00
return 0 ;
2012-11-11 09:20:52 +04:00
if ( off ! = 0 | | count ! = real_size )
return - EINVAL ;
2011-01-30 15:38:24 +03:00
mutex_lock ( & kovaplus - > kovaplus_lock ) ;
2012-11-11 09:20:52 +04:00
retval = roccat_common2_receive ( usb_dev , command , buf , real_size ) ;
2011-01-30 15:38:24 +03:00
mutex_unlock ( & kovaplus - > kovaplus_lock ) ;
2012-11-11 09:20:52 +04:00
if ( retval )
return retval ;
return real_size ;
2011-01-30 15:38:24 +03:00
}
2012-11-11 09:20:52 +04:00
static ssize_t kovaplus_sysfs_write ( struct file * fp , struct kobject * kobj ,
void const * buf , loff_t off , size_t count ,
size_t real_size , uint command )
2011-01-30 15:38:24 +03:00
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2011-01-30 15:38:24 +03:00
struct kovaplus_device * kovaplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
2012-11-11 09:20:52 +04:00
int retval ;
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
if ( off ! = 0 | | count ! = real_size )
2011-01-30 15:38:24 +03:00
return - EINVAL ;
mutex_lock ( & kovaplus - > kovaplus_lock ) ;
2012-11-11 09:20:52 +04:00
retval = roccat_common2_send_with_status ( usb_dev , command ,
buf , real_size ) ;
2011-01-30 15:38:24 +03:00
mutex_unlock ( & kovaplus - > kovaplus_lock ) ;
if ( retval )
return retval ;
2012-11-11 09:20:52 +04:00
return real_size ;
2011-01-30 15:38:24 +03:00
}
2012-11-11 09:20:52 +04:00
# define KOVAPLUS_SYSFS_W(thingy, THINGY) \
static ssize_t kovaplus_sysfs_write_ # # thingy ( struct file * fp , \
struct kobject * kobj , struct bin_attribute * attr , char * buf , \
loff_t off , size_t count ) \
{ \
return kovaplus_sysfs_write ( fp , kobj , buf , off , count , \
KOVAPLUS_SIZE_ # # THINGY , KOVAPLUS_COMMAND_ # # THINGY ) ; \
}
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
# define KOVAPLUS_SYSFS_R(thingy, THINGY) \
static ssize_t kovaplus_sysfs_read_ # # thingy ( struct file * fp , \
struct kobject * kobj , struct bin_attribute * attr , char * buf , \
loff_t off , size_t count ) \
{ \
return kovaplus_sysfs_read ( fp , kobj , buf , off , count , \
KOVAPLUS_SIZE_ # # THINGY , KOVAPLUS_COMMAND_ # # THINGY ) ; \
}
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
# define KOVAPLUS_SYSFS_RW(thingy, THINGY) \
KOVAPLUS_SYSFS_W ( thingy , THINGY ) \
KOVAPLUS_SYSFS_R ( thingy , THINGY )
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
# define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
2013-08-20 08:50:28 +04:00
KOVAPLUS_SYSFS_RW ( thingy , THINGY ) ; \
static struct bin_attribute bin_attr_ # # thingy = { \
2012-11-11 09:20:52 +04:00
. attr = { . name = # thingy , . mode = 0660 } , \
. size = KOVAPLUS_SIZE_ # # THINGY , \
. read = kovaplus_sysfs_read_ # # thingy , \
. write = kovaplus_sysfs_write_ # # thingy \
}
# define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
2013-08-20 08:50:28 +04:00
KOVAPLUS_SYSFS_W ( thingy , THINGY ) ; \
static struct bin_attribute bin_attr_ # # thingy = { \
2012-11-11 09:20:52 +04:00
. attr = { . name = # thingy , . mode = 0220 } , \
. size = KOVAPLUS_SIZE_ # # THINGY , \
. write = kovaplus_sysfs_write_ # # thingy \
2011-01-30 15:38:24 +03:00
}
2013-08-20 08:50:28 +04:00
KOVAPLUS_BIN_ATTRIBUTE_W ( control , CONTROL ) ;
KOVAPLUS_BIN_ATTRIBUTE_RW ( info , INFO ) ;
KOVAPLUS_BIN_ATTRIBUTE_RW ( profile_settings , PROFILE_SETTINGS ) ;
KOVAPLUS_BIN_ATTRIBUTE_RW ( profile_buttons , PROFILE_BUTTONS ) ;
2012-11-11 09:20:52 +04:00
static ssize_t kovaplus_sysfs_read_profilex_settings ( struct file * fp ,
2011-01-30 15:38:24 +03:00
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2011-01-30 15:38:24 +03:00
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
2012-11-11 09:20:52 +04:00
ssize_t retval ;
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
retval = kovaplus_select_profile ( usb_dev , * ( uint * ) ( attr - > private ) ,
KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ) ;
if ( retval )
return retval ;
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
return kovaplus_sysfs_read ( fp , kobj , buf , off , count ,
KOVAPLUS_SIZE_PROFILE_SETTINGS ,
KOVAPLUS_COMMAND_PROFILE_SETTINGS ) ;
}
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
static ssize_t kovaplus_sysfs_read_profilex_buttons ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2012-11-11 09:20:52 +04:00
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
ssize_t retval ;
2011-01-30 15:38:24 +03:00
2012-11-11 09:20:52 +04:00
retval = kovaplus_select_profile ( usb_dev , * ( uint * ) ( attr - > private ) ,
KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS ) ;
2011-01-30 15:38:24 +03:00
if ( retval )
return retval ;
2012-11-11 09:20:52 +04:00
return kovaplus_sysfs_read ( fp , kobj , buf , off , count ,
KOVAPLUS_SIZE_PROFILE_BUTTONS ,
KOVAPLUS_COMMAND_PROFILE_BUTTONS ) ;
2011-01-30 15:38:24 +03:00
}
2013-08-20 08:50:28 +04:00
# define PROFILE_ATTR(number) \
static struct bin_attribute bin_attr_profile # # number # # _settings = { \
2013-09-28 07:57:46 +04:00
. attr = { . name = " profile " # number " _settings " , . mode = 0440 } , \
2013-08-20 08:50:28 +04:00
. size = KOVAPLUS_SIZE_PROFILE_SETTINGS , \
. read = kovaplus_sysfs_read_profilex_settings , \
. private = & profile_numbers [ number - 1 ] , \
} ; \
static struct bin_attribute bin_attr_profile # # number # # _buttons = { \
2013-09-28 07:57:46 +04:00
. attr = { . name = " profile " # number " _buttons " , . mode = 0440 } , \
2013-08-20 08:50:28 +04:00
. size = KOVAPLUS_SIZE_PROFILE_BUTTONS , \
. read = kovaplus_sysfs_read_profilex_buttons , \
. private = & profile_numbers [ number - 1 ] , \
} ;
PROFILE_ATTR ( 1 ) ;
PROFILE_ATTR ( 2 ) ;
PROFILE_ATTR ( 3 ) ;
PROFILE_ATTR ( 4 ) ;
PROFILE_ATTR ( 5 ) ;
2011-01-30 15:38:24 +03:00
static ssize_t kovaplus_sysfs_show_actual_profile ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kovaplus_device * kovaplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , kovaplus - > actual_profile ) ;
}
static ssize_t kovaplus_sysfs_set_actual_profile ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
struct kovaplus_device * kovaplus ;
struct usb_device * usb_dev ;
unsigned long profile ;
int retval ;
2011-08-27 17:24:45 +04:00
struct kovaplus_roccat_report roccat_report ;
2011-01-30 15:38:24 +03:00
dev = dev - > parent - > parent ;
kovaplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
2013-07-19 10:53:16 +04:00
retval = kstrtoul ( buf , 10 , & profile ) ;
2011-01-30 15:38:24 +03:00
if ( retval )
return retval ;
if ( profile > = 5 )
return - EINVAL ;
mutex_lock ( & kovaplus - > kovaplus_lock ) ;
retval = kovaplus_set_actual_profile ( usb_dev , profile ) ;
2011-08-27 17:24:45 +04:00
if ( retval ) {
mutex_unlock ( & kovaplus - > kovaplus_lock ) ;
return retval ;
}
2011-06-12 12:02:44 +04:00
kovaplus_profile_activated ( kovaplus , profile ) ;
2011-08-27 17:24:45 +04:00
roccat_report . type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1 ;
roccat_report . profile = profile + 1 ;
roccat_report . button = 0 ;
roccat_report . data1 = profile + 1 ;
roccat_report . data2 = 0 ;
roccat_report_event ( kovaplus - > chrdev_minor ,
( uint8_t const * ) & roccat_report ) ;
2011-01-30 15:38:24 +03:00
mutex_unlock ( & kovaplus - > kovaplus_lock ) ;
return size ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_profile , 0660 ,
kovaplus_sysfs_show_actual_profile ,
kovaplus_sysfs_set_actual_profile ) ;
2011-01-30 15:38:24 +03:00
static ssize_t kovaplus_sysfs_show_actual_cpi ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kovaplus_device * kovaplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , kovaplus - > actual_cpi ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_cpi , 0440 , kovaplus_sysfs_show_actual_cpi , NULL ) ;
2011-01-30 15:38:24 +03:00
static ssize_t kovaplus_sysfs_show_actual_sensitivity_x ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kovaplus_device * kovaplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , kovaplus - > actual_x_sensitivity ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_sensitivity_x , 0440 ,
kovaplus_sysfs_show_actual_sensitivity_x , NULL ) ;
2011-01-30 15:38:24 +03:00
static ssize_t kovaplus_sysfs_show_actual_sensitivity_y ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct kovaplus_device * kovaplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , kovaplus - > actual_y_sensitivity ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_sensitivity_y , 0440 ,
kovaplus_sysfs_show_actual_sensitivity_y , NULL ) ;
2011-01-30 15:38:24 +03:00
static ssize_t kovaplus_sysfs_show_firmware_version ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2012-11-11 09:20:52 +04:00
struct kovaplus_device * kovaplus ;
struct usb_device * usb_dev ;
struct kovaplus_info info ;
dev = dev - > parent - > parent ;
kovaplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
mutex_lock ( & kovaplus - > kovaplus_lock ) ;
roccat_common2_receive ( usb_dev , KOVAPLUS_COMMAND_INFO ,
& info , KOVAPLUS_SIZE_INFO ) ;
mutex_unlock ( & kovaplus - > kovaplus_lock ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , info . firmware_version ) ;
2011-01-30 15:38:24 +03:00
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( firmware_version , 0440 ,
kovaplus_sysfs_show_firmware_version , NULL ) ;
2011-01-30 15:38:24 +03:00
2013-07-25 02:05:11 +04:00
static struct attribute * kovaplus_attrs [ ] = {
& dev_attr_actual_cpi . attr ,
& dev_attr_firmware_version . attr ,
& dev_attr_actual_profile . attr ,
& dev_attr_actual_sensitivity_x . attr ,
& dev_attr_actual_sensitivity_y . attr ,
NULL ,
2011-01-30 15:38:24 +03:00
} ;
2013-08-20 08:50:28 +04:00
static struct bin_attribute * kovaplus_bin_attributes [ ] = {
& bin_attr_control ,
& bin_attr_info ,
& bin_attr_profile_settings ,
& bin_attr_profile_buttons ,
& bin_attr_profile1_settings ,
& bin_attr_profile2_settings ,
& bin_attr_profile3_settings ,
& bin_attr_profile4_settings ,
& bin_attr_profile5_settings ,
& bin_attr_profile1_buttons ,
& bin_attr_profile2_buttons ,
& bin_attr_profile3_buttons ,
& bin_attr_profile4_buttons ,
& bin_attr_profile5_buttons ,
NULL ,
} ;
static const struct attribute_group kovaplus_group = {
. attrs = kovaplus_attrs ,
. bin_attrs = kovaplus_bin_attributes ,
} ;
static const struct attribute_group * kovaplus_groups [ ] = {
& kovaplus_group ,
NULL ,
2011-01-30 15:38:24 +03:00
} ;
static int kovaplus_init_kovaplus_device_struct ( struct usb_device * usb_dev ,
struct kovaplus_device * kovaplus )
{
int retval , i ;
static uint wait = 70 ; /* device will freeze with just 60 */
mutex_init ( & kovaplus - > kovaplus_lock ) ;
for ( i = 0 ; i < 5 ; + + i ) {
msleep ( wait ) ;
retval = kovaplus_get_profile_settings ( usb_dev ,
& kovaplus - > profile_settings [ i ] , i ) ;
if ( retval )
return retval ;
msleep ( wait ) ;
retval = kovaplus_get_profile_buttons ( usb_dev ,
& kovaplus - > profile_buttons [ i ] , i ) ;
if ( retval )
return retval ;
}
msleep ( wait ) ;
retval = kovaplus_get_actual_profile ( usb_dev ) ;
if ( retval < 0 )
return retval ;
kovaplus_profile_activated ( kovaplus , retval ) ;
return 0 ;
}
static int kovaplus_init_specials ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct usb_device * usb_dev = interface_to_usbdev ( intf ) ;
struct kovaplus_device * kovaplus ;
int retval ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
kovaplus = kzalloc ( sizeof ( * kovaplus ) , GFP_KERNEL ) ;
if ( ! kovaplus ) {
hid_err ( hdev , " can't alloc device descriptor \n " ) ;
return - ENOMEM ;
}
hid_set_drvdata ( hdev , kovaplus ) ;
retval = kovaplus_init_kovaplus_device_struct ( usb_dev , kovaplus ) ;
if ( retval ) {
hid_err ( hdev , " couldn't init struct kovaplus_device \n " ) ;
goto exit_free ;
}
2011-01-30 15:38:25 +03:00
retval = roccat_connect ( kovaplus_class , hdev ,
sizeof ( struct kovaplus_roccat_report ) ) ;
2011-01-30 15:38:24 +03:00
if ( retval < 0 ) {
hid_err ( hdev , " couldn't init char dev \n " ) ;
} else {
kovaplus - > chrdev_minor = retval ;
kovaplus - > roccat_claimed = 1 ;
}
} else {
hid_set_drvdata ( hdev , NULL ) ;
}
return 0 ;
exit_free :
kfree ( kovaplus ) ;
return retval ;
}
static void kovaplus_remove_specials ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct kovaplus_device * kovaplus ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
kovaplus = hid_get_drvdata ( hdev ) ;
if ( kovaplus - > roccat_claimed )
roccat_disconnect ( kovaplus - > chrdev_minor ) ;
kfree ( kovaplus ) ;
}
}
static int kovaplus_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
{
int retval ;
retval = hid_parse ( hdev ) ;
if ( retval ) {
hid_err ( hdev , " parse failed \n " ) ;
goto exit ;
}
retval = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
if ( retval ) {
hid_err ( hdev , " hw start failed \n " ) ;
goto exit ;
}
retval = kovaplus_init_specials ( hdev ) ;
if ( retval ) {
hid_err ( hdev , " couldn't install mouse \n " ) ;
goto exit_stop ;
}
return 0 ;
exit_stop :
hid_hw_stop ( hdev ) ;
exit :
return retval ;
}
static void kovaplus_remove ( struct hid_device * hdev )
{
kovaplus_remove_specials ( hdev ) ;
hid_hw_stop ( hdev ) ;
}
static void kovaplus_keep_values_up_to_date ( struct kovaplus_device * kovaplus ,
u8 const * data )
{
struct kovaplus_mouse_report_button const * button_report ;
if ( data [ 0 ] ! = KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON )
return ;
button_report = ( struct kovaplus_mouse_report_button const * ) data ;
switch ( button_report - > type ) {
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1 :
kovaplus_profile_activated ( kovaplus , button_report - > data1 - 1 ) ;
break ;
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI :
kovaplus - > actual_cpi = kovaplus_convert_event_cpi ( button_report - > data1 ) ;
2013-11-03 09:25:33 +04:00
break ;
2011-01-30 15:38:24 +03:00
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY :
kovaplus - > actual_x_sensitivity = button_report - > data1 ;
kovaplus - > actual_y_sensitivity = button_report - > data2 ;
2013-11-03 09:25:33 +04:00
break ;
default :
break ;
2011-01-30 15:38:24 +03:00
}
}
static void kovaplus_report_to_chrdev ( struct kovaplus_device const * kovaplus ,
u8 const * data )
{
struct kovaplus_roccat_report roccat_report ;
struct kovaplus_mouse_report_button const * button_report ;
if ( data [ 0 ] ! = KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON )
return ;
button_report = ( struct kovaplus_mouse_report_button const * ) data ;
if ( button_report - > type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2 )
return ;
roccat_report . type = button_report - > type ;
roccat_report . profile = kovaplus - > actual_profile + 1 ;
if ( roccat_report . type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO | |
roccat_report . type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT | |
roccat_report . type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH | |
roccat_report . type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER )
roccat_report . button = button_report - > data1 ;
else
roccat_report . button = 0 ;
if ( roccat_report . type = = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI )
roccat_report . data1 = kovaplus_convert_event_cpi ( button_report - > data1 ) ;
else
roccat_report . data1 = button_report - > data1 ;
roccat_report . data2 = button_report - > data2 ;
roccat_report_event ( kovaplus - > chrdev_minor ,
2011-01-30 15:38:25 +03:00
( uint8_t const * ) & roccat_report ) ;
2011-01-30 15:38:24 +03:00
}
static int kovaplus_raw_event ( struct hid_device * hdev ,
struct hid_report * report , u8 * data , int size )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct kovaplus_device * kovaplus = hid_get_drvdata ( hdev ) ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
! = USB_INTERFACE_PROTOCOL_MOUSE )
return 0 ;
2011-06-12 12:02:44 +04:00
if ( kovaplus = = NULL )
return 0 ;
2011-01-30 15:38:24 +03:00
kovaplus_keep_values_up_to_date ( kovaplus , data ) ;
if ( kovaplus - > roccat_claimed )
kovaplus_report_to_chrdev ( kovaplus , data ) ;
return 0 ;
}
static const struct hid_device_id kovaplus_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_ROCCAT , USB_DEVICE_ID_ROCCAT_KOVAPLUS ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , kovaplus_devices ) ;
static struct hid_driver kovaplus_driver = {
. name = " kovaplus " ,
. id_table = kovaplus_devices ,
. probe = kovaplus_probe ,
. remove = kovaplus_remove ,
. raw_event = kovaplus_raw_event
} ;
static int __init kovaplus_init ( void )
{
int retval ;
kovaplus_class = class_create ( THIS_MODULE , " kovaplus " ) ;
if ( IS_ERR ( kovaplus_class ) )
return PTR_ERR ( kovaplus_class ) ;
2013-07-25 02:05:11 +04:00
kovaplus_class - > dev_groups = kovaplus_groups ;
2011-01-30 15:38:24 +03:00
retval = hid_register_driver ( & kovaplus_driver ) ;
if ( retval )
class_destroy ( kovaplus_class ) ;
return retval ;
}
static void __exit kovaplus_exit ( void )
{
hid_unregister_driver ( & kovaplus_driver ) ;
2011-01-30 15:38:27 +03:00
class_destroy ( kovaplus_class ) ;
2011-01-30 15:38:24 +03:00
}
module_init ( kovaplus_init ) ;
module_exit ( kovaplus_exit ) ;
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat Kova[+] driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;