2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-01-30 15:38:23 +03:00
/*
* Roccat common functions for device specific drivers
*
* Copyright ( c ) 2011 Stefan Achatz < erazor_de @ users . sourceforge . net >
*/
/*
*/
2011-06-01 17:54:17 +04:00
# include <linux/hid.h>
2011-01-30 15:38:23 +03:00
# include <linux/slab.h>
2011-07-03 21:39:48 +04:00
# include <linux/module.h>
2011-01-30 15:38:23 +03:00
# include "hid-roccat-common.h"
2012-05-21 00:45:04 +04:00
static inline uint16_t roccat_common2_feature_report ( uint8_t report_id )
2011-06-01 17:54:17 +04:00
{
return 0x300 | report_id ;
}
2012-05-21 00:45:04 +04:00
int roccat_common2_receive ( struct usb_device * usb_dev , uint report_id ,
2011-01-30 15:38:23 +03:00
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 ) ,
2011-06-01 17:54:17 +04:00
HID_REQ_GET_REPORT ,
2011-01-30 15:38:23 +03:00
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
2012-05-21 00:45:04 +04:00
roccat_common2_feature_report ( report_id ) ,
2011-06-01 17:54:17 +04:00
0 , buf , size , USB_CTRL_SET_TIMEOUT ) ;
2011-01-30 15:38:23 +03:00
memcpy ( data , buf , size ) ;
kfree ( buf ) ;
return ( ( len < 0 ) ? len : ( ( len ! = size ) ? - EIO : 0 ) ) ;
}
2012-05-21 00:45:04 +04:00
EXPORT_SYMBOL_GPL ( roccat_common2_receive ) ;
2011-01-30 15:38:23 +03:00
2012-05-21 00:45:04 +04:00
int roccat_common2_send ( struct usb_device * usb_dev , uint report_id ,
2011-01-30 15:38:23 +03:00
void const * data , uint size )
{
char * buf ;
int len ;
2011-11-18 02:43:40 +04:00
buf = kmemdup ( data , size , GFP_KERNEL ) ;
2011-01-30 15:38:23 +03:00
if ( buf = = NULL )
return - ENOMEM ;
len = usb_control_msg ( usb_dev , usb_sndctrlpipe ( usb_dev , 0 ) ,
2011-06-01 17:54:17 +04:00
HID_REQ_SET_REPORT ,
2011-01-30 15:38:23 +03:00
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT ,
2012-05-21 00:45:04 +04:00
roccat_common2_feature_report ( report_id ) ,
2011-06-01 17:54:17 +04:00
0 , buf , size , USB_CTRL_SET_TIMEOUT ) ;
2011-01-30 15:38:23 +03:00
kfree ( buf ) ;
return ( ( len < 0 ) ? len : ( ( len ! = size ) ? - EIO : 0 ) ) ;
}
2012-05-21 00:45:04 +04:00
EXPORT_SYMBOL_GPL ( roccat_common2_send ) ;
2011-01-30 15:38:23 +03:00
2012-05-21 00:45:04 +04:00
enum roccat_common2_control_states {
2013-10-28 21:52:03 +04:00
ROCCAT_COMMON_CONTROL_STATUS_CRITICAL = 0 ,
2012-05-21 00:44:59 +04:00
ROCCAT_COMMON_CONTROL_STATUS_OK = 1 ,
ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2 ,
2013-10-28 21:52:03 +04:00
ROCCAT_COMMON_CONTROL_STATUS_BUSY = 3 ,
ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW = 4 ,
2012-05-21 00:44:59 +04:00
} ;
2012-05-21 00:45:04 +04:00
static int roccat_common2_receive_control_status ( struct usb_device * usb_dev )
2012-05-21 00:44:59 +04:00
{
int retval ;
2012-05-21 00:45:04 +04:00
struct roccat_common2_control control ;
2012-05-21 00:44:59 +04:00
do {
msleep ( 50 ) ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_receive ( usb_dev ,
2012-05-21 00:44:59 +04:00
ROCCAT_COMMON_COMMAND_CONTROL ,
2012-05-21 00:45:04 +04:00
& control , sizeof ( struct roccat_common2_control ) ) ;
2012-05-21 00:44:59 +04:00
if ( retval )
return retval ;
switch ( control . value ) {
case ROCCAT_COMMON_CONTROL_STATUS_OK :
return 0 ;
2013-10-28 21:52:03 +04:00
case ROCCAT_COMMON_CONTROL_STATUS_BUSY :
2012-05-21 00:44:59 +04:00
msleep ( 500 ) ;
continue ;
case ROCCAT_COMMON_CONTROL_STATUS_INVALID :
2013-10-28 21:52:03 +04:00
case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL :
case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW :
2012-05-21 00:44:59 +04:00
return - EINVAL ;
default :
dev_err ( & usb_dev - > dev ,
2012-05-21 00:45:04 +04:00
" roccat_common2_receive_control_status: "
2012-05-21 00:44:59 +04:00
" unknown response value 0x%x \n " ,
control . value ) ;
return - EINVAL ;
}
} while ( 1 ) ;
}
2012-05-21 00:45:04 +04:00
int roccat_common2_send_with_status ( struct usb_device * usb_dev ,
2012-05-21 00:44:59 +04:00
uint command , void const * buf , uint size )
{
int retval ;
2012-05-21 00:45:04 +04:00
retval = roccat_common2_send ( usb_dev , command , buf , size ) ;
2012-05-21 00:44:59 +04:00
if ( retval )
return retval ;
msleep ( 100 ) ;
2012-05-21 00:45:04 +04:00
return roccat_common2_receive_control_status ( usb_dev ) ;
2012-05-21 00:44:59 +04:00
}
2012-05-21 00:45:04 +04:00
EXPORT_SYMBOL_GPL ( roccat_common2_send_with_status ) ;
2012-05-21 00:44:59 +04:00
2013-10-28 21:52:05 +04:00
int roccat_common2_device_init_struct ( struct usb_device * usb_dev ,
struct roccat_common2_device * dev )
{
mutex_init ( & dev - > lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( roccat_common2_device_init_struct ) ;
ssize_t roccat_common2_sysfs_read ( struct file * fp , struct kobject * kobj ,
char * buf , loff_t off , size_t count ,
size_t real_size , uint command )
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2013-10-28 21:52:05 +04:00
struct roccat_common2_device * roccat_dev = 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 ( & roccat_dev - > lock ) ;
retval = roccat_common2_receive ( usb_dev , command , buf , real_size ) ;
mutex_unlock ( & roccat_dev - > lock ) ;
return retval ? retval : real_size ;
}
EXPORT_SYMBOL_GPL ( roccat_common2_sysfs_read ) ;
ssize_t roccat_common2_sysfs_write ( struct file * fp , struct kobject * kobj ,
void const * buf , loff_t off , size_t count ,
size_t real_size , uint command )
{
2015-12-27 12:25:24 +03:00
struct device * dev = kobj_to_dev ( kobj ) - > parent - > parent ;
2013-10-28 21:52:05 +04:00
struct roccat_common2_device * roccat_dev = 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 ( & roccat_dev - > lock ) ;
retval = roccat_common2_send_with_status ( usb_dev , command , buf , real_size ) ;
mutex_unlock ( & roccat_dev - > lock ) ;
return retval ? retval : real_size ;
}
EXPORT_SYMBOL_GPL ( roccat_common2_sysfs_write ) ;
2011-01-30 15:38:23 +03:00
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat common driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;