2009-12-11 14:34:07 +03:00
/*
* Remote Controller core header
*
2010-03-25 02:47:53 +03:00
* Copyright ( C ) 2009 - 2010 by Mauro Carvalho Chehab < mchehab @ redhat . com >
*
2009-12-11 14: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 .
*/
# ifndef _IR_CORE
# define _IR_CORE
# include <linux/spinlock.h>
2010-03-21 02:59:44 +03:00
# include <linux/kfifo.h>
# include <linux/time.h>
2010-03-21 19:00:55 +03:00
# include <linux/timer.h>
2010-04-03 03:01:00 +04:00
# include <media/rc-map.h>
2009-12-11 14:34:07 +03:00
extern int ir_core_debug ;
# define IR_dprintk(level, fmt, arg...) if (ir_core_debug >= level) \
printk ( KERN_DEBUG " %s: " fmt , __func__ , # # arg )
2010-04-07 06:21:46 +04:00
enum rc_driver_type {
RC_DRIVER_SCANCODE = 0 , /* Driver or hardware generates a scancode */
RC_DRIVER_IR_RAW , /* Needs a Infra-Red pulse/space decoder */
} ;
2010-03-21 02:59:44 +03:00
enum raw_event_type {
IR_SPACE = ( 1 < < 0 ) ,
IR_PULSE = ( 1 < < 1 ) ,
IR_START_EVENT = ( 1 < < 2 ) ,
IR_STOP_EVENT = ( 1 < < 3 ) ,
} ;
2010-04-04 21:06:55 +04:00
/**
* struct ir_dev_props - Allow caller drivers to set special properties
2010-04-07 06:21:46 +04:00
* @ driver_type : specifies if the driver or hardware have already a decoder ,
* or if it needs to use the IR raw event decoders to produce a scancode
2010-04-04 21:06:55 +04:00
* @ allowed_protos : bitmask with the supported IR_TYPE_ * protocols
* @ scanmask : some hardware decoders are not capable of providing the full
* scancode to the application . As this is a hardware limit , we can ' t do
* anything with it . Yet , as the same keycode table can be used with other
* devices , a mask is provided to allow its usage . Drivers should generally
* leave this field in blank
* @ priv : driver - specific data , to be used on the callbacks
* @ change_protocol : allow changing the protocol used on hardware decoders
* @ open : callback to allow drivers to enable polling / irq when IR input device
* is opened .
* @ close : callback to allow drivers to disable polling / irq when IR input device
* is opened .
*/
2009-12-14 06:16:55 +03:00
struct ir_dev_props {
2010-04-07 06:21:46 +04:00
enum rc_driver_type driver_type ;
unsigned long allowed_protos ;
u32 scanmask ;
void * priv ;
int ( * change_protocol ) ( void * priv , u64 ir_type ) ;
int ( * open ) ( void * priv ) ;
void ( * close ) ( void * priv ) ;
2009-12-14 06:16:55 +03:00
} ;
2010-03-21 02:59:44 +03:00
struct ir_raw_event_ctrl {
2010-04-08 20:10:00 +04:00
struct work_struct rx_work ; /* for the rx decoding workqueue */
struct kfifo kfifo ; /* fifo for the pulse/space durations */
ktime_t last_event ; /* when last event occurred */
enum raw_event_type last_type ; /* last event type */
struct input_dev * input_dev ; /* pointer to the parent input_dev */
2010-03-21 02:59:44 +03:00
} ;
2009-12-14 08:16:36 +03:00
2009-12-11 15:44:23 +03:00
struct ir_input_dev {
2010-03-11 18:41:56 +03:00
struct device dev ; /* device */
2010-03-13 03:18:14 +03:00
char * driver_name ; /* Name of the driver module */
2009-12-13 22:00:08 +03:00
struct ir_scancode_table rc_tab ; /* scan/key table */
unsigned long devno ; /* device number */
2009-12-14 06:16:55 +03:00
const struct ir_dev_props * props ; /* Device properties */
2010-03-21 02:59:44 +03:00
struct ir_raw_event_ctrl * raw ; /* for raw pulse/space events */
2010-04-02 22:58:29 +04:00
struct input_dev * input_dev ; /* the input device associated with this device */
2010-03-21 18:15:16 +03:00
/* key info - needed by IR keycode handlers */
2010-04-02 22:58:29 +04:00
spinlock_t keylock ; /* protects the below members */
bool keypressed ; /* current state */
unsigned long keyup_jiffies ; /* when should the current keypress be released? */
struct timer_list timer_keyup ; /* timer for releasing a keypress */
u32 last_keycode ; /* keycode of last command */
u32 last_scancode ; /* scancode of last command */
u8 last_toggle ; /* toggle of last command */
2009-12-11 15:44:23 +03:00
} ;
2010-03-21 02:59:44 +03:00
2010-03-25 02:47:53 +03:00
struct ir_raw_handler {
struct list_head list ;
2010-04-08 20:10:00 +04:00
int ( * decode ) ( struct input_dev * input_dev , s64 duration ) ;
2010-03-26 03:13:43 +03:00
int ( * raw_register ) ( struct input_dev * input_dev ) ;
int ( * raw_unregister ) ( struct input_dev * input_dev ) ;
2010-03-25 02:47:53 +03:00
} ;
2009-12-14 08:16:36 +03:00
# define to_ir_input_dev(_attr) container_of(_attr, struct ir_input_dev, attr)
2009-12-11 15:44:23 +03:00
2009-12-11 14:34:07 +03:00
/* Routines from ir-keytable.c */
u32 ir_g_keycode_from_table ( struct input_dev * input_dev ,
u32 scancode ) ;
2010-04-02 22:58:29 +04:00
void ir_repeat ( struct input_dev * dev ) ;
void ir_keydown ( struct input_dev * dev , int scancode , u8 toggle ) ;
2010-04-02 20:18:42 +04:00
int __ir_input_register ( struct input_dev * dev ,
2009-12-14 06:16:55 +03:00
const struct ir_scancode_table * ir_codes ,
2010-03-13 03:18:14 +03:00
const struct ir_dev_props * props ,
const char * driver_name ) ;
2009-12-11 14:34:07 +03:00
2010-04-02 20:18:42 +04:00
static inline int ir_input_register ( struct input_dev * dev ,
const char * map_name ,
const struct ir_dev_props * props ,
const char * driver_name ) {
struct ir_scancode_table * ir_codes ;
2010-04-03 03:01:00 +04:00
struct ir_input_dev * ir_dev ;
int rc ;
if ( ! map_name )
return - EINVAL ;
2010-04-02 09:33:35 +04:00
2010-04-02 20:18:42 +04:00
ir_codes = get_rc_map ( map_name ) ;
if ( ! ir_codes )
return - EINVAL ;
2010-04-03 03:01:00 +04:00
rc = __ir_input_register ( dev , ir_codes , props , driver_name ) ;
if ( rc < 0 )
return - EINVAL ;
ir_dev = input_get_drvdata ( dev ) ;
if ( ! rc & & ir_dev - > props & & ir_dev - > props - > change_protocol )
rc = ir_dev - > props - > change_protocol ( ir_dev - > props - > priv ,
ir_codes - > ir_type ) ;
return rc ;
2010-04-02 20:18:42 +04:00
}
2010-04-03 03:01:00 +04:00
void ir_input_unregister ( struct input_dev * input_dev ) ;
2010-04-02 09:33:35 +04:00
2009-12-13 22:00:08 +03:00
/* Routines from ir-sysfs.c */
int ir_register_class ( struct input_dev * input_dev ) ;
void ir_unregister_class ( struct input_dev * input_dev ) ;
2010-03-21 02:59:44 +03:00
/* Routines from ir-raw-event.c */
int ir_raw_event_register ( struct input_dev * input_dev ) ;
void ir_raw_event_unregister ( struct input_dev * input_dev ) ;
2010-04-08 20:10:00 +04:00
void ir_raw_event_handle ( struct input_dev * input_dev ) ;
int ir_raw_event_store ( struct input_dev * input_dev , s64 duration ) ;
int ir_raw_event_store_edge ( struct input_dev * input_dev , enum raw_event_type type ) ;
static inline void ir_raw_event_reset ( struct input_dev * input_dev )
{
ir_raw_event_store ( input_dev , 0 ) ;
ir_raw_event_handle ( input_dev ) ;
}
2010-03-25 02:47:53 +03:00
int ir_raw_handler_register ( struct ir_raw_handler * ir_raw_handler ) ;
void ir_raw_handler_unregister ( struct ir_raw_handler * ir_raw_handler ) ;
void ir_raw_init ( void ) ;
2010-03-21 02:59:44 +03:00
2010-03-25 02:47:53 +03:00
/* from ir-nec-decoder.c */
# ifdef CONFIG_IR_NEC_DECODER_MODULE
# define load_nec_decode() request_module("ir-nec-decoder")
# else
# define load_nec_decode() 0
2009-12-11 14:34:07 +03:00
# endif
2010-03-25 02:47:53 +03:00
2010-04-04 17:27:20 +04:00
/* from ir-rc5-decoder.c */
# ifdef CONFIG_IR_RC5_DECODER_MODULE
# define load_rc5_decode() request_module("ir-rc5-decoder")
# else
# define load_rc5_decode() 0
# endif
2010-04-08 20:10:00 +04:00
/* macros for ir decoders */
# define PULSE(units) ((units))
# define SPACE(units) (-(units))
# define IS_RESET(duration) ((duration) == 0)
# define IS_PULSE(duration) ((duration) > 0)
# define IS_SPACE(duration) ((duration) < 0)
# define DURATION(duration) (abs((duration)))
# define IS_TRANSITION(x, y) ((x) * (y) < 0)
# define DECREASE_DURATION(duration, amount) \
do { \
if ( IS_SPACE ( duration ) ) \
duration + = ( amount ) ; \
else if ( IS_PULSE ( duration ) ) \
duration - = ( amount ) ; \
} while ( 0 )
# define TO_UNITS(duration, unit_len) \
( ( int ) ( ( duration ) > 0 ? \
DIV_ROUND_CLOSEST ( abs ( ( duration ) ) , ( unit_len ) ) : \
- DIV_ROUND_CLOSEST ( abs ( ( duration ) ) , ( unit_len ) ) ) )
# define TO_US(duration) ((int)TO_UNITS(duration, 1000))
2010-03-25 02:47:53 +03:00
# endif /* _IR_CORE */