2011-01-06 11:00:34 +03:00
/*
* Roccat Arvo 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 Arvo is a gamer keyboard with 5 macro keys that can be configured in
* 5 profiles .
*/
# 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-06 11:00:34 +03:00
# include "hid-ids.h"
2011-01-30 15:38:23 +03:00
# include "hid-roccat-common.h"
2011-01-06 11:00:34 +03:00
# include "hid-roccat-arvo.h"
static struct class * arvo_class ;
static ssize_t arvo_sysfs_show_mode_key ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
struct usb_device * usb_dev =
interface_to_usbdev ( to_usb_interface ( dev - > parent - > parent ) ) ;
2011-01-30 15:38:23 +03:00
struct arvo_mode_key temp_buf ;
2011-01-06 11:00:34 +03:00
int retval ;
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev , ARVO_COMMAND_MODE_KEY ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_mode_key ) ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , temp_buf . state ) ;
2011-01-06 11:00:34 +03:00
}
static ssize_t arvo_sysfs_set_mode_key ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
struct usb_device * usb_dev =
interface_to_usbdev ( to_usb_interface ( dev - > parent - > parent ) ) ;
2011-01-30 15:38:23 +03:00
struct arvo_mode_key temp_buf ;
2011-01-06 11:00:34 +03:00
unsigned long state ;
int retval ;
retval = strict_strtoul ( buf , 10 , & state ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
temp_buf . command = ARVO_COMMAND_MODE_KEY ;
temp_buf . state = state ;
2011-01-06 11:00:34 +03:00
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , ARVO_COMMAND_MODE_KEY ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_mode_key ) ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
return size ;
2011-01-06 11:00:34 +03:00
}
static ssize_t arvo_sysfs_show_key_mask ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
struct usb_device * usb_dev =
interface_to_usbdev ( to_usb_interface ( dev - > parent - > parent ) ) ;
2011-01-30 15:38:23 +03:00
struct arvo_key_mask temp_buf ;
2011-01-06 11:00:34 +03:00
int retval ;
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev , ARVO_COMMAND_KEY_MASK ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_key_mask ) ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , temp_buf . key_mask ) ;
2011-01-06 11:00:34 +03:00
}
static ssize_t arvo_sysfs_set_key_mask ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
struct usb_device * usb_dev =
interface_to_usbdev ( to_usb_interface ( dev - > parent - > parent ) ) ;
2011-01-30 15:38:23 +03:00
struct arvo_key_mask temp_buf ;
2011-01-06 11:00:34 +03:00
unsigned long key_mask ;
int retval ;
retval = strict_strtoul ( buf , 10 , & key_mask ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
temp_buf . command = ARVO_COMMAND_KEY_MASK ;
temp_buf . key_mask = key_mask ;
2011-01-06 11:00:34 +03:00
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , ARVO_COMMAND_KEY_MASK ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_key_mask ) ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
return size ;
2011-01-06 11:00:34 +03:00
}
/* retval is 1-5 on success, < 0 on error */
static int arvo_get_actual_profile ( struct usb_device * usb_dev )
{
2011-01-30 15:38:23 +03:00
struct arvo_actual_profile temp_buf ;
2011-01-06 11:00:34 +03:00
int retval ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev , ARVO_COMMAND_ACTUAL_PROFILE ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_actual_profile ) ) ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
if ( retval )
return retval ;
2011-01-06 11:00:34 +03:00
2011-01-30 15:38:23 +03:00
return temp_buf . actual_profile ;
2011-01-06 11:00:34 +03:00
}
static ssize_t arvo_sysfs_show_actual_profile ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , arvo - > actual_profile ) ;
}
static ssize_t arvo_sysfs_set_actual_profile ( struct device * dev ,
struct device_attribute * attr , char const * buf , size_t size )
{
struct arvo_device * arvo =
hid_get_drvdata ( dev_get_drvdata ( dev - > parent - > parent ) ) ;
struct usb_device * usb_dev =
interface_to_usbdev ( to_usb_interface ( dev - > parent - > parent ) ) ;
2011-01-30 15:38:23 +03:00
struct arvo_actual_profile temp_buf ;
2011-01-06 11:00:34 +03:00
unsigned long profile ;
int retval ;
retval = strict_strtoul ( buf , 10 , & profile ) ;
if ( retval )
2011-01-30 15:38:23 +03:00
return retval ;
2011-01-06 11:00:34 +03:00
2011-06-12 12:02:44 +04:00
if ( profile < 1 | | profile > 5 )
return - EINVAL ;
2011-01-30 15:38:23 +03:00
temp_buf . command = ARVO_COMMAND_ACTUAL_PROFILE ;
temp_buf . actual_profile = profile ;
2011-01-06 11:00:34 +03:00
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , ARVO_COMMAND_ACTUAL_PROFILE ,
2011-01-30 15:38:23 +03:00
& temp_buf , sizeof ( struct arvo_actual_profile ) ) ;
2011-01-06 11:00:34 +03:00
if ( ! retval ) {
arvo - > actual_profile = profile ;
retval = size ;
}
mutex_unlock ( & arvo - > arvo_lock ) ;
return retval ;
}
static ssize_t arvo_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 arvo_device * arvo = 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 ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , command , buf , real_size ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
return ( retval ? retval : real_size ) ;
}
static ssize_t arvo_sysfs_read ( struct file * fp ,
struct kobject * kobj , void * 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 arvo_device * arvo = hid_get_drvdata ( dev_get_drvdata ( dev ) ) ;
struct usb_device * usb_dev = interface_to_usbdev ( to_usb_interface ( dev ) ) ;
int retval ;
if ( off > = real_size )
return 0 ;
if ( off ! = 0 | | count ! = real_size )
return - EINVAL ;
mutex_lock ( & arvo - > arvo_lock ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev , command , buf , real_size ) ;
2011-01-06 11:00:34 +03:00
mutex_unlock ( & arvo - > arvo_lock ) ;
return ( retval ? retval : real_size ) ;
}
static ssize_t arvo_sysfs_write_button ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return arvo_sysfs_write ( fp , kobj , buf , off , count ,
2011-06-01 17:54:17 +04:00
sizeof ( struct arvo_button ) , ARVO_COMMAND_BUTTON ) ;
2011-01-06 11:00:34 +03:00
}
static ssize_t arvo_sysfs_read_info ( struct file * fp ,
struct kobject * kobj , struct bin_attribute * attr , char * buf ,
loff_t off , size_t count )
{
return arvo_sysfs_read ( fp , kobj , buf , off , count ,
2011-06-01 17:54:17 +04:00
sizeof ( struct arvo_info ) , ARVO_COMMAND_INFO ) ;
2011-01-06 11:00:34 +03:00
}
static struct device_attribute arvo_attributes [ ] = {
__ATTR ( mode_key , 0660 ,
arvo_sysfs_show_mode_key , arvo_sysfs_set_mode_key ) ,
__ATTR ( key_mask , 0660 ,
arvo_sysfs_show_key_mask , arvo_sysfs_set_key_mask ) ,
__ATTR ( actual_profile , 0660 ,
arvo_sysfs_show_actual_profile ,
arvo_sysfs_set_actual_profile ) ,
__ATTR_NULL
} ;
static struct bin_attribute arvo_bin_attributes [ ] = {
{
. attr = { . name = " button " , . mode = 0220 } ,
. size = sizeof ( struct arvo_button ) ,
. write = arvo_sysfs_write_button
} ,
{
. attr = { . name = " info " , . mode = 0440 } ,
. size = sizeof ( struct arvo_info ) ,
. read = arvo_sysfs_read_info
} ,
__ATTR_NULL
} ;
static int arvo_init_arvo_device_struct ( struct usb_device * usb_dev ,
struct arvo_device * arvo )
{
int retval ;
mutex_init ( & arvo - > arvo_lock ) ;
retval = arvo_get_actual_profile ( usb_dev ) ;
if ( retval < 0 )
return retval ;
arvo - > actual_profile = retval ;
return 0 ;
}
static int arvo_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 arvo_device * arvo ;
int retval ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_KEYBOARD ) {
hid_set_drvdata ( hdev , NULL ) ;
return 0 ;
}
arvo = kzalloc ( sizeof ( * arvo ) , GFP_KERNEL ) ;
if ( ! arvo ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " can't alloc device descriptor \n " ) ;
2011-01-06 11:00:34 +03:00
return - ENOMEM ;
}
hid_set_drvdata ( hdev , arvo ) ;
retval = arvo_init_arvo_device_struct ( usb_dev , arvo ) ;
if ( retval ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " couldn't init struct arvo_device \n " ) ;
2011-01-06 11:00:34 +03:00
goto exit_free ;
}
2011-01-30 15:38:25 +03:00
retval = roccat_connect ( arvo_class , hdev ,
sizeof ( struct arvo_roccat_report ) ) ;
2011-01-06 11:00:34 +03:00
if ( retval < 0 ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " couldn't init char dev \n " ) ;
2011-01-06 11:00:34 +03:00
} else {
arvo - > chrdev_minor = retval ;
arvo - > roccat_claimed = 1 ;
}
return 0 ;
exit_free :
kfree ( arvo ) ;
return retval ;
}
static void arvo_remove_specials ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct arvo_device * arvo ;
if ( intf - > cur_altsetting - > desc . bInterfaceProtocol
= = USB_INTERFACE_PROTOCOL_KEYBOARD )
return ;
arvo = hid_get_drvdata ( hdev ) ;
if ( arvo - > roccat_claimed )
roccat_disconnect ( arvo - > chrdev_minor ) ;
kfree ( arvo ) ;
}
static int arvo_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
{
int retval ;
retval = hid_parse ( hdev ) ;
if ( retval ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " parse failed \n " ) ;
2011-01-06 11:00:34 +03:00
goto exit ;
}
retval = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
if ( retval ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " hw start failed \n " ) ;
2011-01-06 11:00:34 +03:00
goto exit ;
}
retval = arvo_init_specials ( hdev ) ;
if ( retval ) {
2011-01-30 15:38:21 +03:00
hid_err ( hdev , " couldn't install keyboard \n " ) ;
2011-01-06 11:00:34 +03:00
goto exit_stop ;
}
return 0 ;
exit_stop :
hid_hw_stop ( hdev ) ;
exit :
return retval ;
}
static void arvo_remove ( struct hid_device * hdev )
{
arvo_remove_specials ( hdev ) ;
hid_hw_stop ( hdev ) ;
}
static void arvo_report_to_chrdev ( struct arvo_device const * arvo ,
u8 const * data )
{
struct arvo_special_report const * special_report ;
struct arvo_roccat_report roccat_report ;
special_report = ( struct arvo_special_report const * ) data ;
roccat_report . profile = arvo - > actual_profile ;
roccat_report . button = special_report - > event &
ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON ;
if ( ( special_report - > event & ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION ) = =
ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS )
roccat_report . action = ARVO_ROCCAT_REPORT_ACTION_PRESS ;
else
roccat_report . action = ARVO_ROCCAT_REPORT_ACTION_RELEASE ;
2011-01-30 15:38:25 +03:00
roccat_report_event ( arvo - > chrdev_minor ,
( uint8_t const * ) & roccat_report ) ;
2011-01-06 11:00:34 +03:00
}
static int arvo_raw_event ( struct hid_device * hdev ,
struct hid_report * report , u8 * data , int size )
{
struct arvo_device * arvo = hid_get_drvdata ( hdev ) ;
if ( size ! = 3 )
return 0 ;
2011-06-12 12:02:44 +04:00
if ( arvo & & arvo - > roccat_claimed )
2011-01-06 11:00:34 +03:00
arvo_report_to_chrdev ( arvo , data ) ;
return 0 ;
}
static const struct hid_device_id arvo_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_ROCCAT , USB_DEVICE_ID_ROCCAT_ARVO ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , arvo_devices ) ;
static struct hid_driver arvo_driver = {
. name = " arvo " ,
. id_table = arvo_devices ,
. probe = arvo_probe ,
. remove = arvo_remove ,
. raw_event = arvo_raw_event
} ;
static int __init arvo_init ( void )
{
int retval ;
arvo_class = class_create ( THIS_MODULE , " arvo " ) ;
if ( IS_ERR ( arvo_class ) )
return PTR_ERR ( arvo_class ) ;
arvo_class - > dev_attrs = arvo_attributes ;
arvo_class - > dev_bin_attrs = arvo_bin_attributes ;
retval = hid_register_driver ( & arvo_driver ) ;
if ( retval )
class_destroy ( arvo_class ) ;
return retval ;
}
static void __exit arvo_exit ( void )
{
hid_unregister_driver ( & arvo_driver ) ;
2011-01-30 15:38:27 +03:00
class_destroy ( arvo_class ) ;
2011-01-06 11:00:34 +03:00
}
module_init ( arvo_init ) ;
module_exit ( arvo_exit ) ;
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat Arvo driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;