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 >
*/
/*
* 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 .
*/
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 {
2012-05-21 00:44:59 +04:00
ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD = 0 ,
ROCCAT_COMMON_CONTROL_STATUS_OK = 1 ,
ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2 ,
ROCCAT_COMMON_CONTROL_STATUS_WAIT = 3 ,
} ;
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 ;
case ROCCAT_COMMON_CONTROL_STATUS_WAIT :
msleep ( 500 ) ;
continue ;
case ROCCAT_COMMON_CONTROL_STATUS_INVALID :
case ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD :
/* seems to be critical - replug necessary */
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
2011-01-30 15:38:23 +03:00
MODULE_AUTHOR ( " Stefan Achatz " ) ;
MODULE_DESCRIPTION ( " USB Roccat common driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;