2010-11-26 19:57:42 +00:00
/*
* Roccat Kone [ + ] driver for Linux
*
* Copyright ( c ) 2010 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 Kone [ + ] is an updated / improved version of the Kone with more memory
* and functionality and without the non - standard behaviours the Kone had .
*/
# include <linux/device.h>
# include <linux/input.h>
# include <linux/hid.h>
# include <linux/module.h>
# include <linux/slab.h>
2011-02-03 16:14:43 +01:00
# include <linux/hid-roccat.h>
2010-11-26 19:57:42 +00:00
# include "hid-ids.h"
2011-01-30 13:38:23 +01:00
# include "hid-roccat-common.h"
2010-11-26 19:57:42 +00:00
# include "hid-roccat-koneplus.h"
static uint profile_numbers [ 5 ] = { 0 , 1 , 2 , 3 , 4 } ;
static struct class * koneplus_class ;
static void koneplus_profile_activated ( struct koneplus_device * koneplus ,
uint new_profile )
{
koneplus - > actual_profile = new_profile ;
}
static int koneplus_send_control ( struct usb_device * usb_dev , uint value ,
enum koneplus_control_requests request )
{
2011-01-30 13:38:23 +01:00
struct koneplus_control control ;
2010-11-26 19:57:42 +00:00
if ( ( request = = KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS | |
request = = KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS ) & &
value > 4 )
return - EINVAL ;
2011-01-30 13:38:23 +01:00
control . command = KONEPLUS_COMMAND_CONTROL ;
control . value = value ;
control . request = request ;
2010-11-26 19:57:42 +00:00
2011-06-01 15:54:17 +02:00
return roccat_common_send ( usb_dev , KONEPLUS_COMMAND_CONTROL ,
2011-01-30 13:38:23 +01:00
& control , sizeof ( struct koneplus_control ) ) ;
2010-11-26 19:57:42 +00:00
}
static int koneplus_receive_control_status ( struct usb_device * usb_dev )
{
int retval ;
2011-01-30 13:38:23 +01:00
struct koneplus_control control ;
2010-11-26 19:57:42 +00:00
do {
2011-06-01 15:54:17 +02:00
retval = roccat_common_receive ( usb_dev , KONEPLUS_COMMAND_CONTROL ,
2011-01-30 13:38:23 +01:00
& control , sizeof ( struct koneplus_control ) ) ;
2010-11-26 19:57:42 +00:00
/* check if we get a completely wrong answer */
if ( retval )
2011-01-30 13:38:23 +01:00
return retval ;
2010-11-26 19:57:42 +00:00
2011-01-30 13:38:23 +01:00
if ( control . value = = KONEPLUS_CONTROL_REQUEST_STATUS_OK )
return 0 ;
2010-11-26 19:57:42 +00:00
/* indicates that hardware needs some more time to complete action */
2011-01-30 13:38:23 +01:00
if ( control . value = = KONEPLUS_CONTROL_REQUEST_STATUS_WAIT ) {
2010-11-26 19:57:42 +00:00
msleep ( 500 ) ; /* windows driver uses 1000 */
continue ;
}
/* seems to be critical - replug necessary */
2011-01-30 13:38:23 +01:00
if ( control . value = = KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD )
return - EINVAL ;
2010-11-26 19:57:42 +00:00
2011-01-30 13:38:21 +01:00
hid_err ( usb_dev , " koneplus_receive_control_status: "
2011-01-30 13:38:23 +01:00
" unknown response value 0x%x \n " , control . value ) ;
return - EINVAL ;
2010-11-26 19:57:42 +00:00
} while ( 1 ) ;
}
static int koneplus_send ( struct usb_device * usb_dev , uint command ,
2011-01-30 13:38:23 +01:00
void const * buf , uint size )
{
int retval ;
2010-11-26 19:57:42 +00:00
2011-01-30 13:38:23 +01:00
retval = roccat_common_send ( usb_dev , command , buf , size ) ;
if ( retval )
return retval ;
2010-11-26 19:57:42 +00:00
2011-01-30 13:38:23 +01:00
return koneplus_receive_control_status ( usb_dev ) ;
2010-11-26 19:57:42 +00:00
}
static int koneplus_select_profile ( struct usb_device * usb_dev , uint number ,
enum koneplus_control_requests request )
{
int retval ;
retval = koneplus_send_control ( usb_dev , number , request ) ;
if ( retval )
return retval ;
/* allow time to settle things - windows driver uses 500 */
msleep ( 100 ) ;
retval = koneplus_receive_control_status ( usb_dev ) ;
if ( retval )
return retval ;
return 0 ;
}
static int koneplus_get_info ( struct usb_device * usb_dev ,
struct koneplus_info * buf )
{
2011-06-01 15:54:17 +02:00
return roccat_common_receive ( usb_dev , KONEPLUS_COMMAND_INFO ,
2010-11-26 19:57:42 +00:00
buf , sizeof ( struct koneplus_info ) ) ;
}
static int koneplus_get_profile_settings ( struct usb_device * usb_dev ,
struct koneplus_profile_settings * buf , uint number )
{
int retval ;
retval = koneplus_select_profile ( usb_dev , number ,
KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ) ;
if ( retval )
return retval ;
2011-06-01 15:54:17 +02:00
return roccat_common_receive ( usb_dev , KONEPLUS_COMMAND_PROFILE_SETTINGS ,
2010-11-26 19:57:42 +00:00
buf , sizeof ( struct koneplus_profile_settings ) ) ;
}
static int koneplus_set_profile_settings ( struct usb_device * usb_dev ,
struct koneplus_profile_settings const * settings )
{
2011-06-01 15:54:17 +02:00
return koneplus_send ( usb_dev , KONEPLUS_COMMAND_PROFILE_SETTINGS ,
2011-01-30 13:38:23 +01:00
settings , sizeof ( struct koneplus_profile_settings ) ) ;
2010-11-26 19:57:42 +00:00
}
static int koneplus_get_profile_buttons ( struct usb_device * usb_dev ,
struct koneplus_profile_buttons * buf , int number )
{
int retval ;
retval = koneplus_select_profile ( usb_dev , number ,
KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS ) ;
if ( retval )
return retval ;
2011-06-01 15:54:17 +02:00
return roccat_common_receive ( usb_dev , KONEPLUS_COMMAND_PROFILE_BUTTONS ,
2010-11-26 19:57:42 +00:00
buf , sizeof ( struct koneplus_profile_buttons ) ) ;
}
static int koneplus_set_profile_buttons ( struct usb_device * usb_dev ,
struct koneplus_profile_buttons const * buttons )
{
2011-06-01 15:54:17 +02:00
return koneplus_send ( usb_dev , KONEPLUS_COMMAND_PROFILE_BUTTONS ,
2011-01-30 13:38:23 +01:00
buttons , sizeof ( struct koneplus_profile_buttons ) ) ;
2010-11-26 19:57:42 +00:00
}
/* retval is 0-4 on success, < 0 on error */
2011-04-13 17:17:52 +02:00
static int koneplus_get_actual_profile ( struct usb_device * usb_dev )
2010-11-26 19:57:42 +00:00
{
2011-04-13 17:17:52 +02:00
struct koneplus_actual_profile buf ;
2010-11-26 19:57:42 +00:00
int retval ;
2011-06-01 15:54:17 +02:00
retval = roccat_common_receive ( usb_dev , KONEPLUS_COMMAND_ACTUAL_PROFILE ,
2011-04-13 17:17:52 +02:00
& buf , sizeof ( struct koneplus_actual_profile ) ) ;
2010-11-26 19:57:42 +00:00
2011-04-13 17:17:52 +02:00
return retval ? retval : buf . actual_profile ;
2010-11-26 19:57:42 +00:00
}
2011-04-13 17:17:52 +02:00
static int koneplus_set_actual_profile ( struct usb_device * usb_dev ,
int new_profile )
2010-11-26 19:57:42 +00:00
{
2011-04-13 17:17:52 +02:00
struct koneplus_actual_profile buf ;
2010-11-26 19:57:42 +00:00
2011-04-13 17:17:52 +02:00
buf . command = KONEPLUS_COMMAND_ACTUAL_PROFILE ;
buf . size = sizeof ( struct koneplus_actual_profile ) ;
buf . actual_profile = new_profile ;
2010-11-26 19:57:42 +00:00
2011-06-01 15:54:17 +02:00
return koneplus_send ( usb_dev , KONEPLUS_COMMAND_ACTUAL_PROFILE ,
2011-04-13 17:17:52 +02:00
& buf , sizeof ( struct koneplus_actual_profile ) ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_read ( struct file * fp , struct kobject * kobj ,
char * buf , loff_t off , size_t count ,
size_t real_size , uint command )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval ;
2011-01-06 09:00:41 +01:00
if ( off > = real_size )
return 0 ;
2010-11-26 19:57:42 +00:00
if ( off ! = 0 | | count ! = real_size )
return - EINVAL ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
2011-01-30 13:38:23 +01:00
retval = roccat_common_receive ( usb_dev , command , buf , real_size ) ;
2010-11-26 19:57:42 +00:00
mutex_unlock ( & koneplus - > koneplus_lock ) ;
if ( retval )
return retval ;
return real_size ;
}
static ssize_t koneplus_sysfs_write ( struct file * fp , struct kobject * kobj ,
void const * buf , loff_t off , size_t count ,
size_t real_size , uint command )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval ;
if ( off ! = 0 | | count ! = real_size )
return - EINVAL ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
2011-01-30 13:38:23 +01:00
retval = koneplus_send ( usb_dev , command , buf , real_size ) ;
2010-11-26 19:57:42 +00:00
mutex_unlock ( & koneplus - > koneplus_lock ) ;
if ( retval )
return retval ;
return real_size ;
}
2011-05-29 19:32:57 +02:00
static ssize_t koneplus_sysfs_write_talk ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_write ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_talk ) , KONEPLUS_COMMAND_TALK ) ;
2011-05-29 19:32:57 +02:00
}
2010-11-26 19:57:42 +00:00
static ssize_t koneplus_sysfs_write_macro ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_write ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_macro ) , KONEPLUS_COMMAND_MACRO ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_read_sensor ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_read ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_sensor ) , KONEPLUS_COMMAND_SENSOR ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_write_sensor ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_write ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_sensor ) , KONEPLUS_COMMAND_SENSOR ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_write_tcu ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_write ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_tcu ) , KONEPLUS_COMMAND_TCU ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_read_tcu_image ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return koneplus_sysfs_read ( fp , kobj , buf , off , count ,
2011-06-01 15:54:17 +02:00
sizeof ( struct koneplus_tcu_image ) , KONEPLUS_COMMAND_TCU ) ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_read_profilex_settings ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
if ( off > = sizeof ( struct koneplus_profile_settings ) )
return 0 ;
if ( off + count > sizeof ( struct koneplus_profile_settings ) )
count = sizeof ( struct koneplus_profile_settings ) - off ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
2011-01-30 13:38:23 +01:00
memcpy ( buf , ( ( char const * ) & koneplus - > profile_settings [ * ( uint * ) ( attr - > private ) ] ) + off ,
2010-11-26 19:57:42 +00:00
count ) ;
mutex_unlock ( & koneplus - > koneplus_lock ) ;
return count ;
}
static ssize_t koneplus_sysfs_write_profile_settings ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval = 0 ;
int difference ;
int profile_number ;
struct koneplus_profile_settings * profile_settings ;
if ( off ! = 0 | | count ! = sizeof ( struct koneplus_profile_settings ) )
return - EINVAL ;
profile_number = ( ( struct koneplus_profile_settings const * ) buf ) - > number ;
profile_settings = & koneplus - > profile_settings [ profile_number ] ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
difference = memcmp ( buf , profile_settings ,
sizeof ( struct koneplus_profile_settings ) ) ;
if ( difference ) {
retval = koneplus_set_profile_settings ( usb_dev ,
( struct koneplus_profile_settings const * ) buf ) ;
if ( ! retval )
memcpy ( profile_settings , buf ,
sizeof ( struct koneplus_profile_settings ) ) ;
}
mutex_unlock ( & koneplus - > koneplus_lock ) ;
if ( retval )
return retval ;
return sizeof ( struct koneplus_profile_settings ) ;
}
static ssize_t koneplus_sysfs_read_profilex_buttons ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
if ( off > = sizeof ( struct koneplus_profile_buttons ) )
return 0 ;
if ( off + count > sizeof ( struct koneplus_profile_buttons ) )
count = sizeof ( struct koneplus_profile_buttons ) - off ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
2011-01-30 13:38:23 +01:00
memcpy ( buf , ( ( char const * ) & koneplus - > profile_buttons [ * ( uint * ) ( attr - > private ) ] ) + off ,
2010-11-26 19:57:42 +00:00
count ) ;
mutex_unlock ( & koneplus - > koneplus_lock ) ;
return count ;
}
static ssize_t koneplus_sysfs_write_profile_buttons ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
struct koneplus_device * koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval = 0 ;
int difference ;
uint profile_number ;
struct koneplus_profile_buttons * profile_buttons ;
if ( off ! = 0 | | count ! = sizeof ( struct koneplus_profile_buttons ) )
return - EINVAL ;
profile_number = ( ( struct koneplus_profile_buttons const * ) buf ) - > number ;
profile_buttons = & koneplus - > profile_buttons [ profile_number ] ;
mutex_lock ( & koneplus - > koneplus_lock ) ;
difference = memcmp ( buf , profile_buttons ,
sizeof ( struct koneplus_profile_buttons ) ) ;
if ( difference ) {
retval = koneplus_set_profile_buttons ( usb_dev ,
( struct koneplus_profile_buttons const * ) buf ) ;
if ( ! retval )
memcpy ( profile_buttons , buf ,
sizeof ( struct koneplus_profile_buttons ) ) ;
}
mutex_unlock ( & koneplus - > koneplus_lock ) ;
if ( retval )
return retval ;
return sizeof ( struct koneplus_profile_buttons ) ;
}
2011-04-13 17:17:52 +02:00
static ssize_t koneplus_sysfs_show_actual_profile ( struct device * dev ,
2010-11-26 19:57:42 +00:00
struct device_attribute * attr , char * buf )
{
struct koneplus_device * koneplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2011-04-13 17:17:52 +02:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , koneplus - > actual_profile ) ;
2010-11-26 19:57:42 +00:00
}
2011-04-13 17:17:52 +02:00
static ssize_t koneplus_sysfs_set_actual_profile ( struct device * dev ,
2010-11-26 19:57:42 +00:00
struct device_attribute * attr , char const * buf , size_t size )
{
struct koneplus_device * koneplus ;
struct usb_device * usb_dev ;
unsigned long profile ;
int retval ;
2011-04-13 17:17:52 +02:00
struct koneplus_roccat_report roccat_report ;
2010-11-26 19:57:42 +00:00
dev = dev - > parent - > parent ;
koneplus = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
retval = strict_strtoul ( buf , 10 , & profile ) ;
if ( retval )
return retval ;
2011-06-12 10:02:44 +02:00
if ( profile > 4 )
return - EINVAL ;
2010-11-26 19:57:42 +00:00
mutex_lock ( & koneplus - > koneplus_lock ) ;
2011-04-13 17:17:52 +02:00
retval = koneplus_set_actual_profile ( usb_dev , profile ) ;
if ( retval ) {
mutex_unlock ( & koneplus - > koneplus_lock ) ;
2010-11-26 19:57:42 +00:00
return retval ;
2011-04-13 17:17:52 +02:00
}
2010-11-26 19:57:42 +00:00
2011-06-12 10:02:44 +02:00
koneplus_profile_activated ( koneplus , profile ) ;
2010-11-26 19:57:42 +00:00
2011-04-13 17:17:52 +02:00
roccat_report . type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE ;
roccat_report . data1 = profile + 1 ;
roccat_report . data2 = 0 ;
roccat_report . profile = profile + 1 ;
roccat_report_event ( koneplus - > chrdev_minor ,
( uint8_t const * ) & roccat_report ) ;
mutex_unlock ( & koneplus - > koneplus_lock ) ;
return size ;
2010-11-26 19:57:42 +00:00
}
static ssize_t koneplus_sysfs_show_firmware_version ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct koneplus_device * koneplus =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , koneplus - > info . firmware_version ) ;
}
static struct device_attribute koneplus_attributes [ ] = {
2011-04-13 17:17:52 +02:00
__ATTR ( actual_profile , 0660 ,
koneplus_sysfs_show_actual_profile ,
koneplus_sysfs_set_actual_profile ) ,
2010-11-26 19:57:42 +00:00
__ATTR ( startup_profile , 0660 ,
2011-04-13 17:17:52 +02:00
koneplus_sysfs_show_actual_profile ,
koneplus_sysfs_set_actual_profile ) ,
2010-11-26 19:57:42 +00:00
__ATTR ( firmware_version , 0440 ,
koneplus_sysfs_show_firmware_version , NULL ) ,
__ATTR_NULL
} ;
static struct bin_attribute koneplus_bin_attributes [ ] = {
{
2011-03-14 21:43:07 +01:00
. attr = { . name = " sensor " , . mode = 0660 } ,
2010-11-26 19:57:42 +00:00
. size = sizeof ( struct koneplus_sensor ) ,
. read = koneplus_sysfs_read_sensor ,
. write = koneplus_sysfs_write_sensor
} ,
{
. attr = { . name = " tcu " , . mode = 0220 } ,
. size = sizeof ( struct koneplus_tcu ) ,
. write = koneplus_sysfs_write_tcu
} ,
{
. attr = { . name = " tcu_image " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_tcu_image ) ,
. read = koneplus_sysfs_read_tcu_image
} ,
{
. attr = { . name = " profile_settings " , . mode = 0220 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. write = koneplus_sysfs_write_profile_settings
} ,
{
. attr = { . name = " profile1_settings " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. read = koneplus_sysfs_read_profilex_settings ,
. private = & profile_numbers [ 0 ]
} ,
{
. attr = { . name = " profile2_settings " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. read = koneplus_sysfs_read_profilex_settings ,
. private = & profile_numbers [ 1 ]
} ,
{
. attr = { . name = " profile3_settings " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. read = koneplus_sysfs_read_profilex_settings ,
. private = & profile_numbers [ 2 ]
} ,
{
. attr = { . name = " profile4_settings " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. read = koneplus_sysfs_read_profilex_settings ,
. private = & profile_numbers [ 3 ]
} ,
{
. attr = { . name = " profile5_settings " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_settings ) ,
. read = koneplus_sysfs_read_profilex_settings ,
. private = & profile_numbers [ 4 ]
} ,
{
. attr = { . name = " profile_buttons " , . mode = 0220 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. write = koneplus_sysfs_write_profile_buttons
} ,
{
. attr = { . name = " profile1_buttons " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. read = koneplus_sysfs_read_profilex_buttons ,
. private = & profile_numbers [ 0 ]
} ,
{
. attr = { . name = " profile2_buttons " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. read = koneplus_sysfs_read_profilex_buttons ,
. private = & profile_numbers [ 1 ]
} ,
{
. attr = { . name = " profile3_buttons " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. read = koneplus_sysfs_read_profilex_buttons ,
. private = & profile_numbers [ 2 ]
} ,
{
. attr = { . name = " profile4_buttons " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. read = koneplus_sysfs_read_profilex_buttons ,
. private = & profile_numbers [ 3 ]
} ,
{
. attr = { . name = " profile5_buttons " , . mode = 0440 } ,
. size = sizeof ( struct koneplus_profile_buttons ) ,
. read = koneplus_sysfs_read_profilex_buttons ,
. private = & profile_numbers [ 4 ]
} ,
{
. attr = { . name = " macro " , . mode = 0220 } ,
. size = sizeof ( struct koneplus_macro ) ,
. write = koneplus_sysfs_write_macro
} ,
2011-05-29 19:32:57 +02:00
{
. attr = { . name = " talk " , . mode = 0220 } ,
. size = sizeof ( struct koneplus_talk ) ,
. write = koneplus_sysfs_write_talk
} ,
2010-11-26 19:57:42 +00:00
__ATTR_NULL
} ;
static int koneplus_init_koneplus_device_struct ( struct usb_device * usb_dev ,
struct koneplus_device * koneplus )
{
int retval , i ;
2011-04-13 17:17:52 +02:00
static uint wait = 200 ;
2010-11-26 19:57:42 +00:00
mutex_init ( & koneplus - > koneplus_lock ) ;
retval = koneplus_get_info ( usb_dev , & koneplus - > info ) ;
if ( retval )
return retval ;
for ( i = 0 ; i < 5 ; + + i ) {
msleep ( wait ) ;
retval = koneplus_get_profile_settings ( usb_dev ,
& koneplus - > profile_settings [ i ] , i ) ;
if ( retval )
return retval ;
msleep ( wait ) ;
retval = koneplus_get_profile_buttons ( usb_dev ,
& koneplus - > profile_buttons [ i ] , i ) ;
if ( retval )
return retval ;
}
2011-04-13 17:17:52 +02:00
msleep ( wait ) ;
retval = koneplus_get_actual_profile ( usb_dev ) ;
if ( retval < 0 )
return retval ;
koneplus_profile_activated ( koneplus , retval ) ;
2010-11-26 19:57:42 +00:00
return 0 ;
}
static int koneplus_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 koneplus_device * koneplus ;
int retval ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
koneplus = kzalloc ( sizeof ( * koneplus ) , GFP_KERNEL ) ;
if ( ! koneplus ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " can't alloc device descriptor \n " ) ;
2010-11-26 19:57:42 +00:00
return - ENOMEM ;
}
hid_set_drvdata ( hdev , koneplus ) ;
retval = koneplus_init_koneplus_device_struct ( usb_dev , koneplus ) ;
if ( retval ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " couldn't init struct koneplus_device \n " ) ;
2010-11-26 19:57:42 +00:00
goto exit_free ;
}
2011-01-30 13:38:25 +01:00
retval = roccat_connect ( koneplus_class , hdev ,
sizeof ( struct koneplus_roccat_report ) ) ;
2010-11-26 19:57:42 +00:00
if ( retval < 0 ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " couldn't init char dev \n " ) ;
2010-11-26 19:57:42 +00:00
} else {
koneplus - > chrdev_minor = retval ;
koneplus - > roccat_claimed = 1 ;
}
} else {
hid_set_drvdata ( hdev , NULL ) ;
}
return 0 ;
exit_free :
kfree ( koneplus ) ;
return retval ;
}
static void koneplus_remove_specials ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct koneplus_device * koneplus ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
koneplus = hid_get_drvdata ( hdev ) ;
if ( koneplus - > roccat_claimed )
roccat_disconnect ( koneplus - > chrdev_minor ) ;
kfree ( koneplus ) ;
}
}
static int koneplus_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
{
int retval ;
retval = hid_parse ( hdev ) ;
if ( retval ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " parse failed \n " ) ;
2010-11-26 19:57:42 +00:00
goto exit ;
}
retval = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
if ( retval ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " hw start failed \n " ) ;
2010-11-26 19:57:42 +00:00
goto exit ;
}
retval = koneplus_init_specials ( hdev ) ;
if ( retval ) {
2011-01-30 13:38:21 +01:00
hid_err ( hdev , " couldn't install mouse \n " ) ;
2010-11-26 19:57:42 +00:00
goto exit_stop ;
}
return 0 ;
exit_stop :
hid_hw_stop ( hdev ) ;
exit :
return retval ;
}
static void koneplus_remove ( struct hid_device * hdev )
{
koneplus_remove_specials ( hdev ) ;
hid_hw_stop ( hdev ) ;
}
static void koneplus_keep_values_up_to_date ( struct koneplus_device * koneplus ,
u8 const * data )
{
struct koneplus_mouse_report_button const * button_report ;
switch ( data [ 0 ] ) {
case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON :
button_report = ( struct koneplus_mouse_report_button const * ) data ;
switch ( button_report - > type ) {
case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE :
koneplus_profile_activated ( koneplus , button_report - > data1 - 1 ) ;
break ;
}
break ;
}
}
static void koneplus_report_to_chrdev ( struct koneplus_device const * koneplus ,
u8 const * data )
{
struct koneplus_roccat_report roccat_report ;
struct koneplus_mouse_report_button const * button_report ;
if ( data [ 0 ] ! = KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON )
return ;
button_report = ( struct koneplus_mouse_report_button const * ) data ;
if ( ( button_report - > type = = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH | |
button_report - > type = = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER ) & &
button_report - > data2 ! = KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS )
return ;
roccat_report . type = button_report - > type ;
roccat_report . data1 = button_report - > data1 ;
roccat_report . data2 = button_report - > data2 ;
roccat_report . profile = koneplus - > actual_profile + 1 ;
roccat_report_event ( koneplus - > chrdev_minor ,
2011-01-30 13:38:25 +01:00
( uint8_t const * ) & roccat_report ) ;
2010-11-26 19:57:42 +00:00
}
static int koneplus_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 koneplus_device * koneplus = hid_get_drvdata ( hdev ) ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
! = USB_INTERFACE_PROTOCOL_MOUSE )
return 0 ;
2011-06-12 10:02:44 +02:00
if ( koneplus = = NULL )
return 0 ;
2010-11-26 19:57:42 +00:00
koneplus_keep_values_up_to_date ( koneplus , data ) ;
if ( koneplus - > roccat_claimed )
koneplus_report_to_chrdev ( koneplus , data ) ;
return 0 ;
}
static const struct hid_device_id koneplus_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_ROCCAT , USB_DEVICE_ID_ROCCAT_KONEPLUS ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , koneplus_devices ) ;
static struct hid_driver koneplus_driver = {
. name = " koneplus " ,
. id_table = koneplus_devices ,
. probe = koneplus_probe ,
. remove = koneplus_remove ,
. raw_event = koneplus_raw_event
} ;
static int __init koneplus_init ( void )
{
int retval ;
/* class name has to be same as driver name */
koneplus_class = class_create ( THIS_MODULE , " koneplus " ) ;
if ( IS_ERR ( koneplus_class ) )
return PTR_ERR ( koneplus_class ) ;
koneplus_class - > dev_attrs = koneplus_attributes ;
koneplus_class - > dev_bin_attrs = koneplus_bin_attributes ;
retval = hid_register_driver ( & koneplus_driver ) ;
if ( retval )
class_destroy ( koneplus_class ) ;
return retval ;
}
static void __exit koneplus_exit ( void )
{
hid_unregister_driver ( & koneplus_driver ) ;
2011-01-30 13:38:27 +01:00
class_destroy ( koneplus_class ) ;
2010-11-26 19:57:42 +00:00
}
module_init ( koneplus_init ) ;
module_exit ( koneplus_exit ) ;
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat Kone[+] driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;