2008-06-25 22:31:48 +02:00
/*
* HID driver for some samsung " 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 ) 2006 - 2007 Jiri Kosina
* Copyright ( c ) 2007 Paul Walmsley
* Copyright ( c ) 2008 Jiri Slaby
*/
/*
* 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 "hid-ids.h"
/*
* Samsung IrDA remote controller ( reports as Cypress USB Mouse ) .
*
2009-06-23 11:26:48 +02:00
* There are several variants for 041 9 : 0001 :
*
* 1. 184 byte report descriptor
2008-06-25 22:31:48 +02:00
* Vendor specific report # 4 has a size of 48 bit ,
* and therefore is not accepted when inspecting the descriptors .
* As a workaround we reinterpret the report as :
* Variable type , count 6 , size 8 bit , log . maximum 255
* The burden to reconstruct the data is moved into user space .
2009-06-23 11:26:48 +02:00
*
* 2. 203 byte report descriptor
* Report # 4 has an array field with logical range 0. .18 instead of 1. .15 .
*
* 3. 135 byte report descriptor
* Report # 4 has an array field with logical range 0. .17 instead of 1. .14 .
2008-06-25 22:31:48 +02:00
*/
static void samsung_report_fixup ( struct hid_device * hdev , __u8 * rdesc ,
unsigned int rsize )
{
2009-06-23 11:26:48 +02:00
if ( rsize = = 184 & & rdesc [ 175 ] = = 0x25 & & rdesc [ 176 ] = = 0x40 & &
2008-06-25 22:31:48 +02:00
rdesc [ 177 ] = = 0x75 & & rdesc [ 178 ] = = 0x30 & &
rdesc [ 179 ] = = 0x95 & & rdesc [ 180 ] = = 0x01 & &
rdesc [ 182 ] = = 0x40 ) {
2009-06-23 11:26:48 +02:00
dev_info ( & hdev - > dev , " fixing up Samsung IrDA %d byte report "
" descriptor \n " , 184 ) ;
2008-06-25 22:31:48 +02:00
rdesc [ 176 ] = 0xff ;
rdesc [ 178 ] = 0x08 ;
rdesc [ 180 ] = 0x06 ;
rdesc [ 182 ] = 0x42 ;
2009-06-23 11:26:48 +02:00
} else
if ( rsize = = 203 & & rdesc [ 192 ] = = 0x15 & & rdesc [ 193 ] = = 0x0 & &
rdesc [ 194 ] = = 0x25 & & rdesc [ 195 ] = = 0x12 ) {
dev_info ( & hdev - > dev , " fixing up Samsung IrDA %d byte report "
" descriptor \n " , 203 ) ;
rdesc [ 193 ] = 0x1 ;
rdesc [ 195 ] = 0xf ;
} else
if ( rsize = = 135 & & rdesc [ 124 ] = = 0x15 & & rdesc [ 125 ] = = 0x0 & &
rdesc [ 126 ] = = 0x25 & & rdesc [ 127 ] = = 0x11 ) {
dev_info ( & hdev - > dev , " fixing up Samsung IrDA %d byte report "
" descriptor \n " , 135 ) ;
rdesc [ 125 ] = 0x1 ;
rdesc [ 127 ] = 0xe ;
2008-06-25 22:31:48 +02:00
}
}
static int samsung_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
{
int ret ;
2009-06-23 11:26:48 +02:00
unsigned int cmask = HID_CONNECT_DEFAULT ;
2008-06-25 22:31:48 +02:00
ret = hid_parse ( hdev ) ;
if ( ret ) {
dev_err ( & hdev - > dev , " parse failed \n " ) ;
goto err_free ;
}
2009-06-23 11:26:48 +02:00
if ( hdev - > rsize = = 184 ) {
/* disable hidinput, force hiddev */
cmask = ( cmask & ~ HID_CONNECT_HIDINPUT ) |
HID_CONNECT_HIDDEV_FORCE ;
}
ret = hid_hw_start ( hdev , cmask ) ;
2008-06-25 22:31:48 +02:00
if ( ret ) {
dev_err ( & hdev - > dev , " hw start failed \n " ) ;
goto err_free ;
}
return 0 ;
err_free :
return ret ;
}
static const struct hid_device_id samsung_devices [ ] = {
{ HID_USB_DEVICE ( USB_VENDOR_ID_SAMSUNG , USB_DEVICE_ID_SAMSUNG_IR_REMOTE ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( hid , samsung_devices ) ;
static struct hid_driver samsung_driver = {
. name = " samsung " ,
. id_table = samsung_devices ,
. report_fixup = samsung_report_fixup ,
. probe = samsung_probe ,
} ;
2009-07-02 19:08:38 +02:00
static int __init samsung_init ( void )
2008-06-25 22:31:48 +02:00
{
return hid_register_driver ( & samsung_driver ) ;
}
2009-07-02 19:08:38 +02:00
static void __exit samsung_exit ( void )
2008-06-25 22:31:48 +02:00
{
hid_unregister_driver ( & samsung_driver ) ;
}
module_init ( samsung_init ) ;
module_exit ( samsung_exit ) ;
MODULE_LICENSE ( " GPL " ) ;