2010-03-18 18:19:43 +03: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 a gamer mouse which consists of a mouse part and a keyboard
* part . The keyboard part enables the mouse to execute stored macros with mixed
* key - and button - events .
*
* TODO implement on - the - fly polling - rate change
* The windows driver has the ability to change the polling rate of the
* device on the press of a mousebutton .
* Is it possible to remove and reinstall the urb in raw - event - or any
* other handler , or to defer this action to be executed somewhere else ?
*
* TODO is it possible to overwrite group for sysfs attributes via udev ?
*/
# include <linux/device.h>
# include <linux/input.h>
# include <linux/hid.h>
# include <linux/module.h>
2010-03-29 21:52:41 +04:00
# include <linux/slab.h>
2011-02-03 18:14:43 +03:00
# include <linux/hid-roccat.h>
2010-03-18 18:19:43 +03:00
# include "hid-ids.h"
2011-01-30 15:38:23 +03:00
# include "hid-roccat-common.h"
2010-03-18 18:19:43 +03:00
# include "hid-roccat-kone.h"
2010-11-26 22:57:38 +03:00
static uint profile_numbers [ 5 ] = { 0 , 1 , 2 , 3 , 4 } ;
2011-08-27 17:24:48 +04:00
static void kone_profile_activated ( struct kone_device * kone , uint new_profile )
{
kone - > actual_profile = new_profile ;
kone - > actual_dpi = kone - > profiles [ new_profile - 1 ] . startup_dpi ;
}
2011-08-27 17:24:51 +04:00
static void kone_profile_report ( struct kone_device * kone , uint new_profile )
{
struct kone_roccat_report roccat_report ;
2014-10-11 19:01:49 +04:00
2011-08-27 17:24:51 +04:00
roccat_report . event = kone_mouse_event_switch_profile ;
roccat_report . value = new_profile ;
roccat_report . key = 0 ;
roccat_report_event ( kone - > chrdev_minor , ( uint8_t * ) & roccat_report ) ;
}
2011-06-01 17:54:17 +04:00
static int kone_receive ( struct usb_device * usb_dev , uint usb_command ,
void * data , uint size )
{
char * buf ;
int len ;
buf = kmalloc ( size , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
len = usb_control_msg ( usb_dev , usb_rcvctrlpipe ( usb_dev , 0 ) ,
HID_REQ_GET_REPORT ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
usb_command , 0 , buf , size , USB_CTRL_SET_TIMEOUT ) ;
memcpy ( data , buf , size ) ;
kfree ( buf ) ;
return ( ( len < 0 ) ? len : ( ( len ! = size ) ? - EIO : 0 ) ) ;
}
static int kone_send ( struct usb_device * usb_dev , uint usb_command ,
void const * data , uint size )
{
char * buf ;
int len ;
2011-11-18 02:43:40 +04:00
buf = kmemdup ( data , size , GFP_KERNEL ) ;
2011-06-01 17:54:17 +04:00
if ( buf = = NULL )
return - ENOMEM ;
len = usb_control_msg ( usb_dev , usb_sndctrlpipe ( usb_dev , 0 ) ,
HID_REQ_SET_REPORT ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT ,
usb_command , 0 , buf , size , USB_CTRL_SET_TIMEOUT ) ;
kfree ( buf ) ;
return ( ( len < 0 ) ? len : ( ( len ! = size ) ? - EIO : 0 ) ) ;
}
2010-11-26 22:57:33 +03:00
/* kone_class is used for creating sysfs attributes via roccat char device */
static struct class * kone_class ;
2010-03-18 18:19:43 +03:00
static void kone_set_settings_checksum ( struct kone_settings * settings )
{
uint16_t checksum = 0 ;
unsigned char * address = ( unsigned char * ) settings ;
int i ;
for ( i = 0 ; i < sizeof ( struct kone_settings ) - 2 ; + + i , + + address )
checksum + = * address ;
settings - > checksum = cpu_to_le16 ( checksum ) ;
}
/*
* Checks success after writing data to mouse
* On success returns 0
* On failure returns errno
*/
static int kone_check_write ( struct usb_device * usb_dev )
{
2011-01-30 15:38:23 +03:00
int retval ;
uint8_t data ;
2010-03-18 18:19:43 +03:00
do {
/*
* Mouse needs 50 msecs until it says ok , but there are
* 30 more msecs needed for next write to work .
*/
msleep ( 80 ) ;
2011-06-01 17:54:17 +04:00
retval = kone_receive ( usb_dev ,
2011-01-30 15:38:23 +03:00
kone_command_confirm_write , & data , 1 ) ;
if ( retval )
return retval ;
2010-03-18 18:19:43 +03:00
/*
* value of 3 seems to mean something like
* " not finished yet, but it looks good "
* So check again after a moment .
*/
2011-01-30 15:38:23 +03:00
} while ( data = = 3 ) ;
2010-03-18 18:19:43 +03:00
2011-01-30 15:38:23 +03:00
if ( data = = 1 ) /* everything alright */
2010-03-18 18:19:43 +03:00
return 0 ;
2011-01-30 15:38:23 +03:00
/* unknown answer */
2012-05-21 00:45:08 +04:00
dev_err ( & usb_dev - > dev , " got retval %d when checking write \n " , data ) ;
2011-01-30 15:38:23 +03:00
return - EIO ;
2010-03-18 18:19:43 +03:00
}
/*
* Reads settings from mouse and stores it in @ buf
* On success returns 0
* On failure returns errno
*/
static int kone_get_settings ( struct usb_device * usb_dev ,
struct kone_settings * buf )
{
2011-06-01 17:54:17 +04:00
return kone_receive ( usb_dev , kone_command_settings , buf ,
2011-01-30 15:38:23 +03:00
sizeof ( struct kone_settings ) ) ;
2010-03-18 18:19:43 +03:00
}
/*
* Writes settings from @ buf to mouse
* On success returns 0
* On failure returns errno
*/
static int kone_set_settings ( struct usb_device * usb_dev ,
struct kone_settings const * settings )
{
2011-01-30 15:38:23 +03:00
int retval ;
2014-10-11 19:01:49 +04:00
2011-06-01 17:54:17 +04:00
retval = kone_send ( usb_dev , kone_command_settings ,
2011-01-30 15:38:23 +03:00
settings , sizeof ( struct kone_settings ) ) ;
if ( retval )
return retval ;
return kone_check_write ( usb_dev ) ;
2010-03-18 18:19:43 +03:00
}
/*
* Reads profile data from mouse and stores it in @ buf
* @ number : profile number to read
* On success returns 0
* On failure returns errno
*/
static int kone_get_profile ( struct usb_device * usb_dev ,
struct kone_profile * buf , int number )
{
int len ;
if ( number < 1 | | number > 5 )
return - EINVAL ;
len = usb_control_msg ( usb_dev , usb_rcvctrlpipe ( usb_dev , 0 ) ,
USB_REQ_CLEAR_FEATURE ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
kone_command_profile , number , buf ,
sizeof ( struct kone_profile ) , USB_CTRL_SET_TIMEOUT ) ;
if ( len ! = sizeof ( struct kone_profile ) )
return - EIO ;
return 0 ;
}
/*
* Writes profile data to mouse .
* @ number : profile number to write
* On success returns 0
* On failure returns errno
*/
static int kone_set_profile ( struct usb_device * usb_dev ,
struct kone_profile const * profile , int number )
{
int len ;
if ( number < 1 | | number > 5 )
return - EINVAL ;
len = usb_control_msg ( usb_dev , usb_sndctrlpipe ( usb_dev , 0 ) ,
USB_REQ_SET_CONFIGURATION ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT ,
2011-01-30 15:38:23 +03:00
kone_command_profile , number , ( void * ) profile ,
2010-03-18 18:19:43 +03:00
sizeof ( struct kone_profile ) ,
USB_CTRL_SET_TIMEOUT ) ;
if ( len ! = sizeof ( struct kone_profile ) )
return len ;
if ( kone_check_write ( usb_dev ) )
return - EIO ;
return 0 ;
}
/*
* Reads value of " fast-clip-weight " and stores it in @ result
* On success returns 0
* On failure returns errno
*/
static int kone_get_weight ( struct usb_device * usb_dev , int * result )
{
2011-01-30 15:38:23 +03:00
int retval ;
uint8_t data ;
2010-03-18 18:19:43 +03:00
2011-06-01 17:54:17 +04:00
retval = kone_receive ( usb_dev , kone_command_weight , & data , 1 ) ;
2010-03-18 18:19:43 +03:00
2011-01-30 15:38:23 +03:00
if ( retval )
return retval ;
2010-03-18 18:19:43 +03:00
2011-01-30 15:38:23 +03:00
* result = ( int ) data ;
2010-03-18 18:19:43 +03:00
return 0 ;
}
/*
* Reads firmware_version of mouse and stores it in @ result
* On success returns 0
* On failure returns errno
*/
static int kone_get_firmware_version ( struct usb_device * usb_dev , int * result )
{
2011-01-30 15:38:23 +03:00
int retval ;
uint16_t data ;
2010-03-18 18:19:43 +03:00
2011-06-01 17:54:17 +04:00
retval = kone_receive ( usb_dev , kone_command_firmware_version ,
2011-01-30 15:38:23 +03:00
& data , 2 ) ;
if ( retval )
return retval ;
2010-03-18 18:19:43 +03:00
2011-01-30 15:38:23 +03:00
* result = le16_to_cpu ( data ) ;
2010-03-18 18:19:43 +03:00
return 0 ;
}
2010-05-21 10:15:32 +04:00
static ssize_t kone_sysfs_read_settings ( struct file * fp , struct kobject * kobj ,
2010-03-18 18:19:43 +03:00
struct bin_attribute * attr , char * buf ,
loff_t off , size_t count ) {
2010-11-26 22:57:33 +03:00
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
2010-03-18 18:19:43 +03:00
struct kone_device * kone = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
if ( off > = sizeof ( struct kone_settings ) )
return 0 ;
if ( off + count > sizeof ( struct kone_settings ) )
count = sizeof ( struct kone_settings ) - off ;
mutex_lock ( & kone - > kone_lock ) ;
2010-06-20 21:19:06 +04:00
memcpy ( buf , ( ( char const * ) & kone - > settings ) + off , count ) ;
2010-03-18 18:19:43 +03:00
mutex_unlock ( & kone - > kone_lock ) ;
return count ;
}
/*
* Writing settings automatically activates startup_profile .
* This function keeps values in kone_device up to date and assumes that in
* case of error the old data is still valid
*/
2010-05-21 10:15:32 +04:00
static ssize_t kone_sysfs_write_settings ( struct file * fp , struct kobject * kobj ,
2010-03-18 18:19:43 +03:00
struct bin_attribute * attr , char * buf ,
loff_t off , size_t count ) {
2010-11-26 22:57:33 +03:00
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
2010-03-18 18:19:43 +03:00
struct kone_device * kone = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
2011-08-27 17:24:51 +04:00
int retval = 0 , difference , old_profile ;
2010-03-18 18:19:43 +03:00
/* I need to get my data in one piece */
if ( off ! = 0 | | count ! = sizeof ( struct kone_settings ) )
return - EINVAL ;
mutex_lock ( & kone - > kone_lock ) ;
difference = memcmp ( buf , & kone - > settings , sizeof ( struct kone_settings ) ) ;
if ( difference ) {
retval = kone_set_settings ( usb_dev ,
( struct kone_settings const * ) buf ) ;
2011-08-27 17:24:48 +04:00
if ( retval ) {
mutex_unlock ( & kone - > kone_lock ) ;
return retval ;
}
2010-03-18 18:19:43 +03:00
2011-08-27 17:24:51 +04:00
old_profile = kone - > settings . startup_profile ;
2011-08-27 17:24:48 +04:00
memcpy ( & kone - > settings , buf , sizeof ( struct kone_settings ) ) ;
2010-03-18 18:19:43 +03:00
2011-08-27 17:24:48 +04:00
kone_profile_activated ( kone , kone - > settings . startup_profile ) ;
2011-08-27 17:24:51 +04:00
if ( kone - > settings . startup_profile ! = old_profile )
kone_profile_report ( kone , kone - > settings . startup_profile ) ;
2011-08-27 17:24:48 +04:00
}
mutex_unlock ( & kone - > kone_lock ) ;
2010-03-18 18:19:43 +03:00
return sizeof ( struct kone_settings ) ;
}
2013-08-20 08:40:26 +04:00
static BIN_ATTR ( settings , 0660 , kone_sysfs_read_settings ,
kone_sysfs_write_settings , sizeof ( struct kone_settings ) ) ;
2010-03-18 18:19:43 +03:00
2010-11-26 22:57:38 +03:00
static ssize_t kone_sysfs_read_profilex ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr ,
char * buf , loff_t off , size_t count ) {
2010-11-26 22:57:33 +03:00
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
2010-03-18 18:19:43 +03:00
struct kone_device * kone = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
if ( off > = sizeof ( struct kone_profile ) )
return 0 ;
if ( off + count > sizeof ( struct kone_profile ) )
count = sizeof ( struct kone_profile ) - off ;
mutex_lock ( & kone - > kone_lock ) ;
2010-11-26 22:57:38 +03:00
memcpy ( buf , ( ( char const * ) & kone - > profiles [ * ( uint * ) ( attr - > private ) ] ) + off , count ) ;
2010-03-18 18:19:43 +03:00
mutex_unlock ( & kone - > kone_lock ) ;
return count ;
}
/* Writes data only if different to stored data */
2010-11-26 22:57:38 +03:00
static ssize_t kone_sysfs_write_profilex ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr ,
char * buf , loff_t off , size_t count ) {
2010-11-26 22:57:33 +03:00
struct device * dev =
container_of ( kobj , struct device , kobj ) - > parent - > parent ;
2010-03-18 18:19:43 +03:00
struct kone_device * kone = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
struct kone_profile * profile ;
int retval = 0 , difference ;
/* I need to get my data in one piece */
if ( off ! = 0 | | count ! = sizeof ( struct kone_profile ) )
return - EINVAL ;
2010-11-26 22:57:38 +03:00
profile = & kone - > profiles [ * ( uint * ) ( attr - > private ) ] ;
2010-03-18 18:19:43 +03:00
mutex_lock ( & kone - > kone_lock ) ;
difference = memcmp ( buf , profile , sizeof ( struct kone_profile ) ) ;
if ( difference ) {
retval = kone_set_profile ( usb_dev ,
2010-11-26 22:57:38 +03:00
( struct kone_profile const * ) buf ,
* ( uint * ) ( attr - > private ) + 1 ) ;
2010-03-18 18:19:43 +03:00
if ( ! retval )
memcpy ( profile , buf , sizeof ( struct kone_profile ) ) ;
}
mutex_unlock ( & kone - > kone_lock ) ;
if ( retval )
return retval ;
return sizeof ( struct kone_profile ) ;
}
2013-08-20 08:40:26 +04:00
# define PROFILE_ATTR(number) \
static struct bin_attribute bin_attr_profile # # number = { \
2013-09-28 07:57:46 +04:00
. attr = { . name = " profile " # number , . mode = 0660 } , \
2013-08-20 08:40:26 +04:00
. size = sizeof ( struct kone_profile ) , \
. read = kone_sysfs_read_profilex , \
. write = kone_sysfs_write_profilex , \
2013-08-20 08:56:46 +04:00
. private = & profile_numbers [ number - 1 ] , \
2014-10-11 19:01:49 +04:00
}
2013-08-20 08:40:26 +04:00
PROFILE_ATTR ( 1 ) ;
PROFILE_ATTR ( 2 ) ;
PROFILE_ATTR ( 3 ) ;
PROFILE_ATTR ( 4 ) ;
PROFILE_ATTR ( 5 ) ;
2010-03-18 18:19:43 +03:00
static ssize_t kone_sysfs_show_actual_profile ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2010-03-18 18:19:43 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , kone - > actual_profile ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_profile , 0440 , kone_sysfs_show_actual_profile , NULL ) ;
2010-03-18 18:19:43 +03:00
static ssize_t kone_sysfs_show_actual_dpi ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2010-03-18 18:19:43 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , kone - > actual_dpi ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( actual_dpi , 0440 , kone_sysfs_show_actual_dpi , NULL ) ;
2010-03-18 18:19:43 +03:00
/* weight is read each time, since we don't get informed when it's changed */
static ssize_t kone_sysfs_show_weight ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone ;
struct usb_device * usb_dev ;
2010-03-18 18:19:43 +03:00
int weight = 0 ;
int retval ;
2010-11-26 22:57:33 +03:00
dev = dev - > parent - > parent ;
kone = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
2010-03-18 18:19:43 +03:00
mutex_lock ( & kone - > kone_lock ) ;
retval = kone_get_weight ( usb_dev , & weight ) ;
mutex_unlock ( & kone - > kone_lock ) ;
if ( retval )
return retval ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , weight ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( weight , 0440 , kone_sysfs_show_weight , NULL ) ;
2010-03-18 18:19:43 +03:00
static ssize_t kone_sysfs_show_firmware_version ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2010-03-18 18:19:43 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , kone - > firmware_version ) ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( firmware_version , 0440 , kone_sysfs_show_firmware_version ,
NULL ) ;
2010-03-18 18:19:43 +03:00
static ssize_t kone_sysfs_show_tcu ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2010-03-18 18:19:43 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , kone - > settings . tcu ) ;
}
static int kone_tcu_command ( struct usb_device * usb_dev , int number )
{
2011-01-30 15:38:23 +03:00
unsigned char value ;
2014-10-11 19:01:49 +04:00
2011-01-30 15:38:23 +03:00
value = number ;
2011-06-01 17:54:17 +04:00
return kone_send ( usb_dev , kone_command_calibrate , & value , 1 ) ;
2010-03-18 18:19:43 +03:00
}
/*
* Calibrating the tcu is the only action that changes settings data inside the
* mouse , so this data needs to be reread
*/
static ssize_t kone_sysfs_set_tcu ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone ;
struct usb_device * usb_dev ;
2010-03-18 18:19:43 +03:00
int retval ;
unsigned long state ;
2010-11-26 22:57:33 +03:00
dev = dev - > parent - > parent ;
kone = 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 , & state ) ;
2010-03-18 18:19:43 +03:00
if ( retval )
return retval ;
if ( state ! = 0 & & state ! = 1 )
return - EINVAL ;
mutex_lock ( & kone - > kone_lock ) ;
if ( state = = 1 ) { /* state activate */
retval = kone_tcu_command ( usb_dev , 1 ) ;
if ( retval )
goto exit_unlock ;
retval = kone_tcu_command ( usb_dev , 2 ) ;
if ( retval )
goto exit_unlock ;
ssleep ( 5 ) ; /* tcu needs this time for calibration */
retval = kone_tcu_command ( usb_dev , 3 ) ;
if ( retval )
goto exit_unlock ;
retval = kone_tcu_command ( usb_dev , 0 ) ;
if ( retval )
goto exit_unlock ;
retval = kone_tcu_command ( usb_dev , 4 ) ;
if ( retval )
goto exit_unlock ;
/*
* Kone needs this time to settle things .
* Reading settings too early will result in invalid data .
* Roccat ' s driver waits 1 sec , maybe this time could be
* shortened .
*/
ssleep ( 1 ) ;
}
/* calibration changes values in settings, so reread */
retval = kone_get_settings ( usb_dev , & kone - > settings ) ;
if ( retval )
goto exit_no_settings ;
/* only write settings back if activation state is different */
if ( kone - > settings . tcu ! = state ) {
kone - > settings . tcu = state ;
kone_set_settings_checksum ( & kone - > settings ) ;
retval = kone_set_settings ( usb_dev , & kone - > settings ) ;
if ( retval ) {
2012-05-21 00:45:08 +04:00
dev_err ( & usb_dev - > dev , " couldn't set tcu state \n " ) ;
2010-03-18 18:19:43 +03:00
/*
* try to reread valid settings into buffer overwriting
* first error code
*/
retval = kone_get_settings ( usb_dev , & kone - > settings ) ;
if ( retval )
goto exit_no_settings ;
goto exit_unlock ;
}
2011-08-27 17:24:48 +04:00
/* calibration resets profile */
kone_profile_activated ( kone , kone - > settings . startup_profile ) ;
2010-03-18 18:19:43 +03:00
}
retval = size ;
exit_no_settings :
2012-05-21 00:45:08 +04:00
dev_err ( & usb_dev - > dev , " couldn't read settings \n " ) ;
2010-03-18 18:19:43 +03:00
exit_unlock :
mutex_unlock ( & kone - > kone_lock ) ;
return retval ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( tcu , 0660 , kone_sysfs_show_tcu , kone_sysfs_set_tcu ) ;
2010-03-18 18:19:43 +03:00
static ssize_t kone_sysfs_show_startup_profile ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
2010-03-18 18:19:43 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , kone - > settings . startup_profile ) ;
}
static ssize_t kone_sysfs_set_startup_profile ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
2010-11-26 22:57:33 +03:00
struct kone_device * kone ;
struct usb_device * usb_dev ;
2010-03-18 18:19:43 +03:00
int retval ;
unsigned long new_startup_profile ;
2010-11-26 22:57:33 +03:00
dev = dev - > parent - > parent ;
kone = 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 , & new_startup_profile ) ;
2010-03-18 18:19:43 +03:00
if ( retval )
return retval ;
if ( new_startup_profile < 1 | | new_startup_profile > 5 )
return - EINVAL ;
mutex_lock ( & kone - > kone_lock ) ;
kone - > settings . startup_profile = new_startup_profile ;
kone_set_settings_checksum ( & kone - > settings ) ;
retval = kone_set_settings ( usb_dev , & kone - > settings ) ;
2011-08-27 17:24:48 +04:00
if ( retval ) {
mutex_unlock ( & kone - > kone_lock ) ;
2010-03-18 18:19:43 +03:00
return retval ;
2011-08-27 17:24:48 +04:00
}
2010-03-18 18:19:43 +03:00
/* changing the startup profile immediately activates this profile */
2011-08-27 17:24:48 +04:00
kone_profile_activated ( kone , new_startup_profile ) ;
2011-08-27 17:24:51 +04:00
kone_profile_report ( kone , new_startup_profile ) ;
2010-03-18 18:19:43 +03:00
2011-08-27 17:24:48 +04:00
mutex_unlock ( & kone - > kone_lock ) ;
2010-03-18 18:19:43 +03:00
return size ;
}
2013-07-25 02:05:11 +04:00
static DEVICE_ATTR ( startup_profile , 0660 , kone_sysfs_show_startup_profile ,
kone_sysfs_set_startup_profile ) ;
2010-03-18 18:19:43 +03:00
2013-07-25 02:05:11 +04:00
static struct attribute * kone_attrs [ ] = {
2010-11-26 22:57:33 +03:00
/*
* Read actual dpi settings .
* Returns raw value for further processing . Refer to enum
* kone_polling_rates to get real value .
*/
2013-07-25 02:05:11 +04:00
& dev_attr_actual_dpi . attr ,
& dev_attr_actual_profile . attr ,
2010-03-18 18:19:43 +03:00
2010-11-26 22:57:33 +03:00
/*
* The mouse can be equipped with one of four supplied weights from 5
* to 20 grams which are recognized and its value can be read out .
* This returns the raw value reported by the mouse for easy evaluation
* by software . Refer to enum kone_weights to get corresponding real
* weight .
*/
2013-07-25 02:05:11 +04:00
& dev_attr_weight . attr ,
2010-03-18 18:19:43 +03:00
2010-11-26 22:57:33 +03:00
/*
* Prints firmware version stored in mouse as integer .
* The raw value reported by the mouse is returned for easy evaluation ,
* to get the real version number the decimal point has to be shifted 2
* positions to the left . E . g . a value of 138 means 1.38 .
*/
2013-07-25 02:05:11 +04:00
& dev_attr_firmware_version . attr ,
2010-03-18 18:19:43 +03:00
2010-11-26 22:57:33 +03:00
/*
* Prints state of Tracking Control Unit as number where 0 = off and
* 1 = on . Writing 0 deactivates tcu and writing 1 calibrates and
* activates the tcu
*/
2013-07-25 02:05:11 +04:00
& dev_attr_tcu . attr ,
2010-03-18 18:19:43 +03:00
2010-11-26 22:57:33 +03:00
/* Prints and takes the number of the profile the mouse starts with */
2013-07-25 02:05:11 +04:00
& dev_attr_startup_profile . attr ,
NULL ,
2010-03-18 18:19:43 +03:00
} ;
2013-08-20 08:40:26 +04:00
static struct bin_attribute * kone_bin_attributes [ ] = {
& bin_attr_settings ,
& bin_attr_profile1 ,
& bin_attr_profile2 ,
& bin_attr_profile3 ,
& bin_attr_profile4 ,
& bin_attr_profile5 ,
NULL ,
} ;
static const struct attribute_group kone_group = {
. attrs = kone_attrs ,
. bin_attrs = kone_bin_attributes ,
} ;
static const struct attribute_group * kone_groups [ ] = {
& kone_group ,
NULL ,
2010-03-18 18:19:43 +03:00
} ;
static int kone_init_kone_device_struct ( struct usb_device * usb_dev ,
struct kone_device * kone )
{
uint i ;
int retval ;
mutex_init ( & kone - > kone_lock ) ;
for ( i = 0 ; i < 5 ; + + i ) {
retval = kone_get_profile ( usb_dev , & kone - > profiles [ i ] , i + 1 ) ;
if ( retval )
return retval ;
}
retval = kone_get_settings ( usb_dev , & kone - > settings ) ;
if ( retval )
return retval ;
retval = kone_get_firmware_version ( usb_dev , & kone - > firmware_version ) ;
if ( retval )
return retval ;
2011-08-27 17:24:48 +04:00
kone_profile_activated ( kone , kone - > settings . startup_profile ) ;
2010-03-18 18:19:43 +03:00
return 0 ;
}
/*
* Since IGNORE_MOUSE quirk moved to hid - apple , there is no way to bind only to
* mousepart if usb_hid is compiled into the kernel and kone is compiled as
* module .
* Secial behaviour is bound only to mousepart since only mouseevents contain
* additional notifications .
*/
static int kone_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 kone_device * kone ;
int retval ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
kone = kzalloc ( sizeof ( * kone ) , GFP_KERNEL ) ;
2014-10-11 19:01:49 +04:00
if ( ! kone )
2010-03-18 18:19:43 +03:00
return - ENOMEM ;
hid_set_drvdata ( hdev , kone ) ;
retval = kone_init_kone_device_struct ( usb_dev , kone ) ;
if ( retval ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " couldn't init struct kone_device \n " ) ;
2010-03-18 18:19:43 +03:00
goto exit_free ;
}
2010-05-19 20:55:16 +04:00
2011-01-30 15:38:25 +03:00
retval = roccat_connect ( kone_class , hdev ,
sizeof ( struct kone_roccat_report ) ) ;
2010-05-19 20:55:16 +04:00
if ( retval < 0 ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " couldn't init char dev \n " ) ;
2010-05-19 20:55:16 +04:00
/* be tolerant about not getting chrdev */
} else {
kone - > roccat_claimed = 1 ;
kone - > chrdev_minor = retval ;
}
2010-03-18 18:19:43 +03:00
} else {
hid_set_drvdata ( hdev , NULL ) ;
}
return 0 ;
exit_free :
kfree ( kone ) ;
return retval ;
}
static void kone_remove_specials ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
2010-05-19 20:55:16 +04:00
struct kone_device * kone ;
2010-03-18 18:19:43 +03:00
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_MOUSE ) {
2010-05-19 20:55:16 +04:00
kone = hid_get_drvdata ( hdev ) ;
if ( kone - > roccat_claimed )
roccat_disconnect ( kone - > chrdev_minor ) ;
2010-03-18 18:19:43 +03:00
kfree ( hid_get_drvdata ( hdev ) ) ;
}
}
static int kone_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
int retval ;
retval = hid_parse ( hdev ) ;
if ( retval ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " parse failed \n " ) ;
2010-03-18 18:19:43 +03:00
goto exit ;
}
retval = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
if ( retval ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " hw start failed \n " ) ;
2010-03-18 18:19:43 +03:00
goto exit ;
}
retval = kone_init_specials ( hdev ) ;
if ( retval ) {
2010-12-10 06:29:03 +03:00
hid_err ( hdev , " couldn't install mouse \n " ) ;
2010-03-18 18:19:43 +03:00
goto exit_stop ;
}
return 0 ;
exit_stop :
hid_hw_stop ( hdev ) ;
exit :
return retval ;
}
static void kone_remove ( struct hid_device * hdev )
{
kone_remove_specials ( hdev ) ;
hid_hw_stop ( hdev ) ;
}
2010-05-18 20:31:04 +04:00
/* handle special events and keep actual profile and dpi values up to date */
static void kone_keep_values_up_to_date ( struct kone_device * kone ,
struct kone_mouse_event const * event )
{
switch ( event - > event ) {
case kone_mouse_event_switch_profile :
2011-08-27 17:24:36 +04:00
kone - > actual_dpi = kone - > profiles [ event - > value - 1 ] .
startup_dpi ;
2010-05-18 20:31:04 +04:00
case kone_mouse_event_osd_profile :
kone - > actual_profile = event - > value ;
break ;
case kone_mouse_event_switch_dpi :
case kone_mouse_event_osd_dpi :
kone - > actual_dpi = event - > value ;
break ;
}
}
2010-05-19 20:55:16 +04:00
static void kone_report_to_chrdev ( struct kone_device const * kone ,
struct kone_mouse_event const * event )
{
struct kone_roccat_report roccat_report ;
switch ( event - > event ) {
case kone_mouse_event_switch_profile :
case kone_mouse_event_switch_dpi :
case kone_mouse_event_osd_profile :
case kone_mouse_event_osd_dpi :
roccat_report . event = event - > event ;
roccat_report . value = event - > value ;
roccat_report . key = 0 ;
roccat_report_event ( kone - > chrdev_minor ,
2011-01-30 15:38:25 +03:00
( uint8_t * ) & roccat_report ) ;
2010-05-19 20:55:16 +04:00
break ;
case kone_mouse_event_call_overlong_macro :
2013-04-07 09:08:44 +04:00
case kone_mouse_event_multimedia :
2010-05-19 20:55:16 +04:00
if ( event - > value = = kone_keystroke_action_press ) {
2013-04-07 09:08:44 +04:00
roccat_report . event = event - > event ;
2010-05-19 20:55:16 +04:00
roccat_report . value = kone - > actual_profile ;
roccat_report . key = event - > macro_key ;
roccat_report_event ( kone - > chrdev_minor ,
2011-01-30 15:38:25 +03:00
( uint8_t * ) & roccat_report ) ;
2010-05-19 20:55:16 +04:00
}
break ;
}
}
2010-03-18 18:19:43 +03:00
/*
* Is called for keyboard - and mousepart .
* Only mousepart gets informations about special events in its extended event
* structure .
*/
static int kone_raw_event ( struct hid_device * hdev , struct hid_report * report ,
u8 * data , int size )
{
struct kone_device * kone = hid_get_drvdata ( hdev ) ;
struct kone_mouse_event * event = ( struct kone_mouse_event * ) data ;
/* keyboard events are always processed by default handler */
if ( size ! = sizeof ( struct kone_mouse_event ) )
return 0 ;
2011-06-12 12:02:44 +04:00
if ( kone = = NULL )
return 0 ;
2010-03-18 18:19:43 +03:00
/*
2010-05-19 15:53:22 +04:00
* Firmware 1.38 introduced new behaviour for tilt and special buttons .
* Pressed button is reported in each movement event .
2010-03-18 18:19:43 +03:00
* Workaround sends only one event per press .
*/
2010-05-19 15:53:22 +04:00
if ( memcmp ( & kone - > last_mouse_event . tilt , & event - > tilt , 5 ) )
memcpy ( & kone - > last_mouse_event , event ,
sizeof ( struct kone_mouse_event ) ) ;
2010-03-18 18:19:43 +03:00
else
2010-05-19 15:53:22 +04:00
memset ( & event - > tilt , 0 , 5 ) ;
2010-03-18 18:19:43 +03:00
2010-05-18 20:31:04 +04:00
kone_keep_values_up_to_date ( kone , event ) ;
2010-03-18 18:19:43 +03:00
2010-05-19 20:55:16 +04:00
if ( kone - > roccat_claimed )
kone_report_to_chrdev ( kone , event ) ;
2010-05-18 20:31:04 +04:00
return 0 ; /* always do further processing */
2010-03-18 18:19:43 +03:00
}
static const struct hid_device_id kone_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_ROCCAT , USB_DEVICE_ID_ROCCAT_KONE ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , kone_devices ) ;
static struct hid_driver kone_driver = {
. name = " kone " ,
. id_table = kone_devices ,
. probe = kone_probe ,
. remove = kone_remove ,
. raw_event = kone_raw_event
} ;
2010-05-08 19:20:38 +04:00
static int __init kone_init ( void )
2010-03-18 18:19:43 +03:00
{
2010-11-26 22:57:33 +03:00
int retval ;
/* class name has to be same as driver name */
kone_class = class_create ( THIS_MODULE , " kone " ) ;
if ( IS_ERR ( kone_class ) )
return PTR_ERR ( kone_class ) ;
2013-07-25 02:05:11 +04:00
kone_class - > dev_groups = kone_groups ;
2010-11-26 22:57:33 +03:00
retval = hid_register_driver ( & kone_driver ) ;
if ( retval )
class_destroy ( kone_class ) ;
return retval ;
2010-03-18 18:19:43 +03:00
}
2010-05-08 19:20:38 +04:00
static void __exit kone_exit ( void )
2010-03-18 18:19:43 +03:00
{
hid_unregister_driver ( & kone_driver ) ;
2011-01-30 15:38:27 +03:00
class_destroy ( kone_class ) ;
2010-03-18 18:19:43 +03:00
}
module_init ( kone_init ) ;
module_exit ( kone_exit ) ;
2010-05-12 19:43:34 +04:00
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat Kone driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;