2009-11-27 22:01:23 -03:00
/* ir-register.c - handle IR scancode->keycode tables
*
* Copyright ( C ) 2009 by Mauro Carvalho Chehab < mchehab @ redhat . com >
2009-12-11 08:34:07 -03: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 version 2 of the License .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2009-11-27 22:01:23 -03:00
*/
# include <linux/usb/input.h>
# include <media/ir-common.h>
2009-11-29 11:08:02 -03:00
# define IR_TAB_MIN_SIZE 32
2009-12-04 17:17:47 -03:00
# define IR_TAB_MAX_SIZE 1024
2009-11-29 11:08:02 -03:00
2009-12-02 15:56:47 -03:00
/**
* ir_seek_table ( ) - returns the element order on the table
* @ rc_tab : the ir_scancode_table with the keymap to be used
* @ scancode : the scancode that we ' re seeking
*
* This routine is used by the input routines when a key is pressed at the
* IR . The scancode is received and needs to be converted into a keycode .
* If the key is not found , it returns KEY_UNKNOWN . Otherwise , returns the
* corresponding keycode from the table .
*/
static int ir_seek_table ( struct ir_scancode_table * rc_tab , u32 scancode )
{
int rc ;
unsigned long flags ;
struct ir_scancode * keymap = rc_tab - > scan ;
spin_lock_irqsave ( & rc_tab - > lock , flags ) ;
/* FIXME: replace it by a binary search */
for ( rc = 0 ; rc < rc_tab - > size ; rc + + )
if ( keymap [ rc ] . scancode = = scancode )
goto exit ;
/* Not found */
rc = - EINVAL ;
exit :
spin_unlock_irqrestore ( & rc_tab - > lock , flags ) ;
return rc ;
}
2009-11-29 11:08:02 -03:00
/**
* ir_roundup_tablesize ( ) - gets an optimum value for the table size
* @ n_elems : minimum number of entries to store keycodes
*
* This routine is used to choose the keycode table size .
*
* In order to have some empty space for new keycodes ,
* and knowing in advance that kmalloc allocates only power of two
* segments , it optimizes the allocated space to have some spare space
* for those new keycodes by using the maximum number of entries that
* will be effectively be allocated by kmalloc .
* In order to reduce the quantity of table resizes , it has a minimum
* table size of IR_TAB_MIN_SIZE .
*/
int ir_roundup_tablesize ( int n_elems )
{
size_t size ;
if ( n_elems < IR_TAB_MIN_SIZE )
n_elems = IR_TAB_MIN_SIZE ;
/*
* As kmalloc only allocates sizes of power of two , get as
* much entries as possible for the allocated memory segment
*/
size = roundup_pow_of_two ( n_elems * sizeof ( struct ir_scancode ) ) ;
n_elems = size / sizeof ( struct ir_scancode ) ;
return n_elems ;
}
2009-12-11 08:34:07 -03:00
EXPORT_SYMBOL_GPL ( ir_roundup_tablesize ) ;
2009-11-29 11:08:02 -03:00
/**
* ir_copy_table ( ) - copies a keytable , discarding the unused entries
* @ destin : destin table
* @ origin : origin table
*
* Copies all entries where the keycode is not KEY_UNKNOWN / KEY_RESERVED
*/
int ir_copy_table ( struct ir_scancode_table * destin ,
const struct ir_scancode_table * origin )
{
int i , j = 0 ;
for ( i = 0 ; i < origin - > size ; i + + ) {
2009-12-02 15:56:47 -03:00
if ( origin - > scan [ i ] . keycode = = KEY_UNKNOWN | |
origin - > scan [ i ] . keycode = = KEY_RESERVED )
continue ;
memcpy ( & destin - > scan [ j ] , & origin - > scan [ i ] , sizeof ( struct ir_scancode ) ) ;
j + + ;
2009-11-29 11:08:02 -03:00
}
destin - > size = j ;
2009-12-02 15:56:47 -03:00
IR_dprintk ( 1 , " Copied %d scancodes to the new keycode table \n " , destin - > size ) ;
2009-11-29 11:08:02 -03:00
return 0 ;
}
2009-12-11 08:34:07 -03:00
EXPORT_SYMBOL_GPL ( ir_copy_table ) ;
2009-11-29 11:08:02 -03:00
2009-11-27 22:01:23 -03:00
/**
* ir_getkeycode ( ) - get a keycode at the evdev scancode - > keycode table
* @ dev : the struct input_dev device descriptor
* @ scancode : the desired scancode
* @ keycode : the keycode to be retorned .
*
* This routine is used to handle evdev EVIOCGKEY ioctl .
* If the key is not found , returns - EINVAL , otherwise , returns 0.
*/
static int ir_getkeycode ( struct input_dev * dev ,
int scancode , int * keycode )
{
2009-12-02 15:56:47 -03:00
int elem ;
2009-12-11 09:44:23 -03:00
struct ir_input_dev * ir_dev = input_get_drvdata ( dev ) ;
struct ir_scancode_table * rc_tab = & ir_dev - > rc_tab ;
2009-11-27 22:01:23 -03:00
2009-12-02 15:56:47 -03:00
elem = ir_seek_table ( rc_tab , scancode ) ;
if ( elem > = 0 ) {
* keycode = rc_tab - > scan [ elem ] . keycode ;
return 0 ;
}
2009-11-27 22:01:23 -03:00
2009-12-04 17:17:47 -03:00
/*
* Scancode not found and table can ' t be expanded
*/
if ( elem < 0 & & rc_tab - > size = = IR_TAB_MAX_SIZE )
return - EINVAL ;
/*
* If is there extra space , returns KEY_RESERVED ,
* otherwise , input core won ' t let ir_setkeycode to work
*/
* keycode = KEY_RESERVED ;
return 0 ;
}
/**
* ir_is_resize_needed ( ) - Check if the table needs rezise
* @ table : keycode table that may need to resize
* @ n_elems : minimum number of entries to store keycodes
*
* Considering that kmalloc uses power of two storage areas , this
* routine detects if the real alloced size will change . If not , it
* just returns without doing nothing . Otherwise , it will extend or
* reduce the table size to meet the new needs .
*
* It returns 0 if no resize is needed , 1 otherwise .
*/
static int ir_is_resize_needed ( struct ir_scancode_table * table , int n_elems )
{
int cur_size = ir_roundup_tablesize ( table - > size ) ;
int new_size = ir_roundup_tablesize ( n_elems ) ;
if ( cur_size = = new_size )
return 0 ;
/* Resize is needed */
return 1 ;
}
/**
* ir_delete_key ( ) - remove a keycode from the table
* @ rc_tab : keycode table
* @ elem : element to be removed
*
*/
static void ir_delete_key ( struct ir_scancode_table * rc_tab , int elem )
{
unsigned long flags = 0 ;
int newsize = rc_tab - > size - 1 ;
int resize = ir_is_resize_needed ( rc_tab , newsize ) ;
struct ir_scancode * oldkeymap = rc_tab - > scan ;
struct ir_scancode * newkeymap ;
if ( resize ) {
newkeymap = kzalloc ( ir_roundup_tablesize ( newsize ) *
sizeof ( * newkeymap ) , GFP_ATOMIC ) ;
/* There's no memory for resize. Keep the old table */
if ( ! newkeymap )
resize = 0 ;
}
if ( ! resize ) {
newkeymap = oldkeymap ;
/* We'll modify the live table. Lock it */
spin_lock_irqsave ( & rc_tab - > lock , flags ) ;
}
/*
* Copy the elements before the one that will be deleted
* if ( ! resize ) , both oldkeymap and newkeymap points
* to the same place , so , there ' s no need to copy
*/
if ( resize & & elem > 0 )
memcpy ( newkeymap , oldkeymap ,
elem * sizeof ( * newkeymap ) ) ;
/*
* Copy the other elements overwriting the element to be removed
* This operation applies to both resize and non - resize case
*/
if ( elem < newsize )
memcpy ( & newkeymap [ elem ] , & oldkeymap [ elem + 1 ] ,
( newsize - elem ) * sizeof ( * newkeymap ) ) ;
if ( resize ) {
/*
* As the copy happened to a temporary table , only here
* it needs to lock while replacing the table pointers
* to use the new table
*/
spin_lock_irqsave ( & rc_tab - > lock , flags ) ;
rc_tab - > size = newsize ;
rc_tab - > scan = newkeymap ;
spin_unlock_irqrestore ( & rc_tab - > lock , flags ) ;
/* Frees the old keytable */
kfree ( oldkeymap ) ;
} else {
rc_tab - > size = newsize ;
spin_unlock_irqrestore ( & rc_tab - > lock , flags ) ;
}
}
/**
* ir_insert_key ( ) - insert a keycode at the table
* @ rc_tab : keycode table
* @ scancode : the desired scancode
* @ keycode : the keycode to be retorned .
*
*/
static int ir_insert_key ( struct ir_scancode_table * rc_tab ,
int scancode , int keycode )
{
unsigned long flags ;
int elem = rc_tab - > size ;
int newsize = rc_tab - > size + 1 ;
int resize = ir_is_resize_needed ( rc_tab , newsize ) ;
struct ir_scancode * oldkeymap = rc_tab - > scan ;
struct ir_scancode * newkeymap ;
if ( resize ) {
newkeymap = kzalloc ( ir_roundup_tablesize ( newsize ) *
sizeof ( * newkeymap ) , GFP_ATOMIC ) ;
if ( ! newkeymap )
return - ENOMEM ;
memcpy ( newkeymap , oldkeymap ,
rc_tab - > size * sizeof ( * newkeymap ) ) ;
} else
newkeymap = oldkeymap ;
/* Stores the new code at the table */
IR_dprintk ( 1 , " #%d: New scan 0x%04x with key 0x%04x \n " ,
rc_tab - > size , scancode , keycode ) ;
spin_lock_irqsave ( & rc_tab - > lock , flags ) ;
rc_tab - > size = newsize ;
if ( resize ) {
rc_tab - > scan = newkeymap ;
kfree ( oldkeymap ) ;
}
newkeymap [ elem ] . scancode = scancode ;
newkeymap [ elem ] . keycode = keycode ;
spin_unlock_irqrestore ( & rc_tab - > lock , flags ) ;
return 0 ;
2009-11-27 22:01:23 -03:00
}
/**
* ir_setkeycode ( ) - set a keycode at the evdev scancode - > keycode table
* @ dev : the struct input_dev device descriptor
* @ scancode : the desired scancode
* @ keycode : the keycode to be retorned .
*
* This routine is used to handle evdev EVIOCSKEY ioctl .
* There ' s one caveat here : how can we increase the size of the table ?
* If the key is not found , returns - EINVAL , otherwise , returns 0.
*/
static int ir_setkeycode ( struct input_dev * dev ,
int scancode , int keycode )
{
2009-12-02 15:56:47 -03:00
int rc = 0 ;
2009-12-11 09:44:23 -03:00
struct ir_input_dev * ir_dev = input_get_drvdata ( dev ) ;
struct ir_scancode_table * rc_tab = & ir_dev - > rc_tab ;
2009-11-27 22:01:23 -03:00
struct ir_scancode * keymap = rc_tab - > scan ;
2009-12-02 15:56:47 -03:00
unsigned long flags ;
2009-11-27 22:01:23 -03:00
2009-12-04 17:17:47 -03:00
/*
* Handle keycode table deletions
*
* If userspace is adding a KEY_UNKNOWN or KEY_RESERVED ,
* deal as a trial to remove an existing scancode attribution
* if table become too big , reduce it to save space
*/
if ( keycode = = KEY_UNKNOWN | | keycode = = KEY_RESERVED ) {
rc = ir_seek_table ( rc_tab , scancode ) ;
if ( rc < 0 )
return 0 ;
IR_dprintk ( 1 , " #%d: Deleting scan 0x%04x \n " , rc , scancode ) ;
clear_bit ( keymap [ rc ] . keycode , dev - > keybit ) ;
ir_delete_key ( rc_tab , rc ) ;
return 0 ;
}
/*
* Handle keycode replacements
*
* If the scancode exists , just replace by the new value
*/
2009-12-02 15:56:47 -03:00
rc = ir_seek_table ( rc_tab , scancode ) ;
2009-12-04 17:17:47 -03:00
if ( rc > = 0 ) {
IR_dprintk ( 1 , " #%d: Replacing scan 0x%04x with key 0x%04x \n " ,
rc , scancode , keycode ) ;
2009-11-27 22:01:23 -03:00
2009-12-04 17:17:47 -03:00
clear_bit ( keymap [ rc ] . keycode , dev - > keybit ) ;
2009-11-27 22:01:23 -03:00
2009-12-04 17:17:47 -03:00
spin_lock_irqsave ( & rc_tab - > lock , flags ) ;
keymap [ rc ] . keycode = keycode ;
spin_unlock_irqrestore ( & rc_tab - > lock , flags ) ;
2009-12-02 15:56:47 -03:00
2009-12-04 17:17:47 -03:00
set_bit ( keycode , dev - > keybit ) ;
2009-12-02 15:56:47 -03:00
2009-12-04 17:17:47 -03:00
return 0 ;
}
/*
* Handle new scancode inserts
*
* reallocate table if needed and insert a new keycode
*/
/* Avoid growing the table indefinitely */
if ( rc_tab - > size + 1 > IR_TAB_MAX_SIZE )
return - EINVAL ;
rc = ir_insert_key ( rc_tab , scancode , keycode ) ;
if ( rc < 0 )
return rc ;
2009-12-02 15:56:47 -03:00
set_bit ( keycode , dev - > keybit ) ;
return 0 ;
2009-11-27 22:01:23 -03:00
}
/**
* ir_g_keycode_from_table ( ) - gets the keycode that corresponds to a scancode
2009-12-02 15:56:47 -03:00
* @ input_dev : the struct input_dev descriptor of the device
2009-11-27 22:01:23 -03:00
* @ scancode : the scancode that we ' re seeking
*
* This routine is used by the input routines when a key is pressed at the
* IR . The scancode is received and needs to be converted into a keycode .
* If the key is not found , it returns KEY_UNKNOWN . Otherwise , returns the
* corresponding keycode from the table .
*/
u32 ir_g_keycode_from_table ( struct input_dev * dev , u32 scancode )
{
2009-12-11 09:44:23 -03:00
struct ir_input_dev * ir_dev = input_get_drvdata ( dev ) ;
struct ir_scancode_table * rc_tab = & ir_dev - > rc_tab ;
2009-11-27 22:01:23 -03:00
struct ir_scancode * keymap = rc_tab - > scan ;
2009-12-02 15:56:47 -03:00
int elem ;
2009-11-27 22:01:23 -03:00
2009-12-02 15:56:47 -03:00
elem = ir_seek_table ( rc_tab , scancode ) ;
if ( elem > = 0 ) {
IR_dprintk ( 1 , " %s: scancode 0x%04x keycode 0x%02x \n " ,
dev - > name , scancode , keymap [ elem ] . keycode ) ;
2009-11-27 22:01:23 -03:00
2009-12-02 15:56:47 -03:00
return rc_tab - > scan [ elem ] . keycode ;
}
2009-11-27 22:01:23 -03:00
printk ( KERN_INFO " %s: unknown key for scancode 0x%04x \n " ,
dev - > name , scancode ) ;
2009-12-02 15:56:47 -03:00
/* Reports userspace that an unknown keycode were got */
return KEY_RESERVED ;
2009-11-27 22:01:23 -03:00
}
2009-12-11 08:34:07 -03:00
EXPORT_SYMBOL_GPL ( ir_g_keycode_from_table ) ;
2009-11-27 22:01:23 -03:00
/**
2009-12-11 09:44:23 -03:00
* ir_input_register ( ) - sets the IR keycode table and add the handlers
2009-11-27 22:01:23 -03:00
* for keymap table get / set
* @ input_dev : the struct input_dev descriptor of the device
* @ rc_tab : the struct ir_scancode_table table of scancode / keymap
*
* This routine is used to initialize the input infrastructure to work with
2009-12-02 15:56:47 -03:00
* an IR .
* It should be called before registering the IR device .
2009-11-27 22:01:23 -03:00
*/
2009-12-11 09:44:23 -03:00
int ir_input_register ( struct input_dev * input_dev ,
struct ir_scancode_table * rc_tab )
2009-11-27 22:01:23 -03:00
{
2009-12-11 09:44:23 -03:00
struct ir_input_dev * ir_dev ;
struct ir_scancode * keymap = rc_tab - > scan ;
2009-11-27 22:01:23 -03:00
int i ;
if ( rc_tab - > scan = = NULL | | ! rc_tab - > size )
return - EINVAL ;
2009-12-11 09:44:23 -03:00
ir_dev = kzalloc ( sizeof ( * ir_dev ) , GFP_KERNEL ) ;
if ( ! ir_dev )
return - ENOMEM ;
spin_lock_init ( & rc_tab - > lock ) ;
ir_dev - > rc_tab . size = ir_roundup_tablesize ( rc_tab - > size ) ;
ir_dev - > rc_tab . scan = kzalloc ( ir_dev - > rc_tab . size *
sizeof ( struct ir_scancode ) , GFP_KERNEL ) ;
if ( ! ir_dev - > rc_tab . scan )
return - ENOMEM ;
IR_dprintk ( 1 , " Allocated space for %d keycode entries (%zd bytes) \n " ,
ir_dev - > rc_tab . size ,
ir_dev - > rc_tab . size * sizeof ( ir_dev - > rc_tab . scan ) ) ;
ir_copy_table ( & ir_dev - > rc_tab , rc_tab ) ;
2009-11-27 22:01:23 -03:00
/* set the bits for the keys */
IR_dprintk ( 1 , " key map size: %d \n " , rc_tab - > size ) ;
for ( i = 0 ; i < rc_tab - > size ; i + + ) {
IR_dprintk ( 1 , " #%d: setting bit for keycode 0x%04x \n " ,
i , keymap [ i ] . keycode ) ;
set_bit ( keymap [ i ] . keycode , input_dev - > keybit ) ;
}
2009-12-11 09:44:23 -03:00
clear_bit ( 0 , input_dev - > keybit ) ;
set_bit ( EV_KEY , input_dev - > evbit ) ;
2009-11-27 22:01:23 -03:00
input_dev - > getkeycode = ir_getkeycode ;
input_dev - > setkeycode = ir_setkeycode ;
2009-12-11 09:44:23 -03:00
input_set_drvdata ( input_dev , ir_dev ) ;
2009-11-27 22:01:23 -03:00
return 0 ;
}
2009-12-11 09:44:23 -03:00
EXPORT_SYMBOL_GPL ( ir_input_register ) ;
2009-11-29 11:08:02 -03:00
2009-12-11 09:47:42 -03:00
void ir_input_unregister ( struct input_dev * dev )
2009-11-29 11:08:02 -03:00
{
2009-12-11 09:44:23 -03:00
struct ir_input_dev * ir_dev = input_get_drvdata ( dev ) ;
struct ir_scancode_table * rc_tab = & ir_dev - > rc_tab ;
2009-11-29 11:08:02 -03:00
2009-12-06 08:32:49 -03:00
if ( ! rc_tab )
return ;
2009-11-29 11:08:02 -03:00
IR_dprintk ( 1 , " Freed keycode table \n " ) ;
rc_tab - > size = 0 ;
kfree ( rc_tab - > scan ) ;
rc_tab - > scan = NULL ;
2009-12-11 09:44:23 -03:00
kfree ( ir_dev ) ;
input_set_drvdata ( dev , NULL ) ;
2009-11-29 11:08:02 -03:00
}
2009-12-11 09:47:42 -03:00
EXPORT_SYMBOL_GPL ( ir_input_unregister ) ;
2009-11-29 11:08:02 -03:00
2009-12-11 08:34:07 -03:00
int ir_core_debug ; /* ir_debug level (0,1,2) */
EXPORT_SYMBOL_GPL ( ir_core_debug ) ;
module_param_named ( debug , ir_core_debug , int , 0644 ) ;
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@redhat.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;