2008-06-26 01:47:04 +04:00
/*
* HID driver for some sony " special " devices
*
* Copyright ( c ) 1999 Andreas Gal
* Copyright ( c ) 2000 - 2005 Vojtech Pavlik < vojtech @ suse . cz >
* Copyright ( c ) 2005 Michael Haboustak < mike - @ cinci . rr . com > for Concept2 , Inc
* Copyright ( c ) 2007 Paul Walmsley
* Copyright ( c ) 2008 Jiri Slaby
2008-10-23 14:58:38 +04:00
* Copyright ( c ) 2006 - 2008 Jiri Kosina
2008-06-26 01:47:04 +04:00
*/
/*
* 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 .
*/
# include <linux/device.h>
# include <linux/hid.h>
# include <linux/module.h>
# include <linux/usb.h>
# include "hid-ids.h"
2008-10-23 14:58:38 +04:00
# define VAIO_RDESC_CONSTANT 0x0001
struct sony_sc {
unsigned long quirks ;
} ;
/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
static void sony_report_fixup ( struct hid_device * hdev , __u8 * rdesc ,
unsigned int rsize )
{
struct sony_sc * sc = hid_get_drvdata ( hdev ) ;
if ( ( sc - > quirks & VAIO_RDESC_CONSTANT ) & &
rsize > = 56 & & rdesc [ 54 ] = = 0x81 & & rdesc [ 55 ] = = 0x07 ) {
dev_info ( & hdev - > dev , " Fixing up Sony Vaio VGX report "
" descriptor \n " ) ;
rdesc [ 55 ] = 0x06 ;
}
}
2008-06-26 01:47:04 +04:00
/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to " operational " . Without this , the ps3 controller will not report any
* events .
*/
static int sony_set_operational ( struct hid_device * hdev )
{
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
struct usb_device * dev = interface_to_usbdev ( intf ) ;
__u16 ifnum = intf - > cur_altsetting - > desc . bInterfaceNumber ;
int ret ;
char * buf = kmalloc ( 18 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
ret = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
HID_REQ_GET_REPORT ,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE ,
( 3 < < 8 ) | 0xf2 , ifnum , buf , 17 ,
USB_CTRL_GET_TIMEOUT ) ;
if ( ret < 0 )
dev_err ( & hdev - > dev , " can't set operational mode \n " ) ;
kfree ( buf ) ;
return ret ;
}
static int sony_probe ( struct hid_device * hdev , const struct hid_device_id * id )
{
int ret ;
2008-10-23 14:58:38 +04:00
unsigned long quirks = id - > driver_data ;
struct sony_sc * sc ;
sc = kzalloc ( sizeof ( * sc ) , GFP_KERNEL ) ;
if ( sc = = NULL ) {
dev_err ( & hdev - > dev , " can't alloc apple descriptor \n " ) ;
return - ENOMEM ;
}
sc - > quirks = quirks ;
hid_set_drvdata ( hdev , sc ) ;
2008-06-26 01:47:04 +04:00
ret = hid_parse ( hdev ) ;
if ( ret ) {
dev_err ( & hdev - > dev , " parse failed \n " ) ;
goto err_free ;
}
2008-06-27 02:04:24 +04:00
ret = hid_hw_start ( hdev , HID_CONNECT_DEFAULT |
HID_CONNECT_HIDDEV_FORCE ) ;
2008-06-26 01:47:04 +04:00
if ( ret ) {
dev_err ( & hdev - > dev , " hw start failed \n " ) ;
goto err_free ;
}
ret = sony_set_operational ( hdev ) ;
2008-12-30 02:49:59 +03:00
if ( ret < 0 )
2008-06-26 01:47:04 +04:00
goto err_stop ;
return 0 ;
err_stop :
hid_hw_stop ( hdev ) ;
err_free :
2008-10-23 14:58:38 +04:00
kfree ( sc ) ;
2008-06-26 01:47:04 +04:00
return ret ;
}
2008-10-23 14:58:38 +04:00
static void sony_remove ( struct hid_device * hdev )
{
hid_hw_stop ( hdev ) ;
kfree ( hid_get_drvdata ( hdev ) ) ;
}
2008-06-26 01:47:04 +04:00
static const struct hid_device_id sony_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_SONY , USB_DEVICE_ID_SONY_PS3_CONTROLLER ) } ,
2008-10-23 14:58:38 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_SONY , USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE ) ,
. driver_data = VAIO_RDESC_CONSTANT } ,
2008-06-26 01:47:04 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( hid , sony_devices ) ;
static struct hid_driver sony_driver = {
. name = " sony " ,
. id_table = sony_devices ,
. probe = sony_probe ,
2008-10-23 14:58:38 +04:00
. remove = sony_remove ,
. report_fixup = sony_report_fixup ,
2008-06-26 01:47:04 +04:00
} ;
2009-07-02 21:08:38 +04:00
static int __init sony_init ( void )
2008-06-26 01:47:04 +04:00
{
return hid_register_driver ( & sony_driver ) ;
}
2009-07-02 21:08:38 +04:00
static void __exit sony_exit ( void )
2008-06-26 01:47:04 +04:00
{
hid_unregister_driver ( & sony_driver ) ;
}
module_init ( sony_init ) ;
module_exit ( sony_exit ) ;
MODULE_LICENSE ( " GPL " ) ;