1 #include <linux/types.h>
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <linux/moduleparam.h>
5 #include <linux/input.h>
6 #include <linux/proc_fs.h>
7 #include <asm/bitops.h>
10 #include "av7110_hw.h"
12 #define UP_TIMEOUT (HZ*7/25)
14 /* enable ir debugging by or'ing debug with 16 */
17 static struct av7110
*av_list
[4];
18 static struct input_dev
*input_dev
;
20 static u8 delay_timer_finished
;
22 static u16 key_map
[256] = {
23 KEY_0
, KEY_1
, KEY_2
, KEY_3
, KEY_4
, KEY_5
, KEY_6
, KEY_7
,
24 KEY_8
, KEY_9
, KEY_BACK
, 0, KEY_POWER
, KEY_MUTE
, 0, KEY_INFO
,
25 KEY_VOLUMEUP
, KEY_VOLUMEDOWN
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 KEY_CHANNELUP
, KEY_CHANNELDOWN
, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, KEY_TEXT
, 0, 0, KEY_TV
, 0, 0, 0, 0, 0, KEY_SETUP
, 0, 0,
29 0, 0, 0, KEY_SUBTITLE
, 0, 0, KEY_LANGUAGE
, 0,
30 KEY_RADIO
, 0, 0, 0, 0, KEY_EXIT
, 0, 0,
31 KEY_UP
, KEY_DOWN
, KEY_LEFT
, KEY_RIGHT
, KEY_OK
, 0, 0, 0,
32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED
, KEY_GREEN
, KEY_YELLOW
,
33 KEY_BLUE
, 0, 0, 0, 0, 0, 0, 0, KEY_MENU
, KEY_LIST
, 0, 0, 0, 0, 0, 0,
34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38 0, 0, 0, 0, KEY_UP
, KEY_UP
, KEY_DOWN
, KEY_DOWN
,
39 0, 0, 0, 0, KEY_EPG
, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR
46 static void av7110_emit_keyup(unsigned long data
)
48 if (!data
|| !test_bit(data
, input_dev
->key
))
51 input_event(input_dev
, EV_KEY
, data
, !!0);
55 static struct timer_list keyup_timer
= { .function
= av7110_emit_keyup
};
58 static void av7110_emit_key(unsigned long parm
)
60 struct av7110
*av7110
= (struct av7110
*) parm
;
61 u32 ir_config
= av7110
->ir_config
;
62 u32 ircom
= av7110
->ir_command
;
65 static u16 old_toggle
= 0;
69 /* extract device address and data */
70 switch (ir_config
& 0x0003) {
71 case 0: /* RC5: 5 bits device address, 6 bits data */
73 addr
= (ircom
>> 6) & 0x1f;
76 case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */
78 addr
= (ircom
>> 8) & 0xff;
81 case 2: /* extended RC5: 5 bits device address, 7 bits data */
83 addr
= (ircom
>> 6) & 0x1f;
84 /* invert 7th data bit for backward compatibility with RC5 keymaps */
85 if (!(ircom
& 0x1000))
90 printk("invalid ir_config %x\n", ir_config
);
94 keycode
= key_map
[data
];
96 dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n",
97 ircom
, addr
, data
, keycode
);
99 /* check device address (if selected) */
100 if (ir_config
& 0x4000)
101 if (addr
!= ((ir_config
>> 16) & 0xff))
105 printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__
, data
);
109 if ((ir_config
& 0x0003) == 1)
110 new_toggle
= 0; /* RCMM */
112 new_toggle
= (ircom
& 0x800); /* RC5, extended RC5 */
114 if (timer_pending(&keyup_timer
)) {
115 del_timer(&keyup_timer
);
116 if (keyup_timer
.data
!= keycode
|| new_toggle
!= old_toggle
) {
117 delay_timer_finished
= 0;
118 input_event(input_dev
, EV_KEY
, keyup_timer
.data
, !!0);
119 input_event(input_dev
, EV_KEY
, keycode
, !0);
121 if (delay_timer_finished
)
122 input_event(input_dev
, EV_KEY
, keycode
, 2);
124 delay_timer_finished
= 0;
125 input_event(input_dev
, EV_KEY
, keycode
, !0);
128 keyup_timer
.expires
= jiffies
+ UP_TIMEOUT
;
129 keyup_timer
.data
= keycode
;
131 add_timer(&keyup_timer
);
133 old_toggle
= new_toggle
;
136 static void input_register_keys(void)
140 memset(input_dev
->keybit
, 0, sizeof(input_dev
->keybit
));
142 for (i
= 0; i
< ARRAY_SIZE(key_map
); i
++) {
143 if (key_map
[i
] > KEY_MAX
)
145 else if (key_map
[i
] > KEY_RESERVED
)
146 set_bit(key_map
[i
], input_dev
->keybit
);
151 static void input_repeat_key(unsigned long data
)
153 /* called by the input driver after rep[REP_DELAY] ms */
154 delay_timer_finished
= 1;
158 static int av7110_ir_write_proc(struct file
*file
, const char __user
*buffer
,
159 unsigned long count
, void *data
)
162 int size
= 4 + 256 * sizeof(u16
);
169 page
= (char *) vmalloc(size
);
173 if (copy_from_user(page
, buffer
, size
)) {
178 memcpy(&ir_config
, page
, 4);
179 memcpy(&key_map
, page
+ 4, 256 * sizeof(u16
));
181 if (FW_VERSION(av_list
[0]->arm_app
) >= 0x2620 && !(ir_config
& 0x0001))
182 ir_config
|= 0x0002; /* enable extended RC5 */
183 for (i
= 0; i
< av_cnt
; i
++)
184 av7110_setup_irc_config(av_list
[i
], ir_config
);
185 input_register_keys();
190 int av7110_setup_irc_config(struct av7110
*av7110
, u32 ir_config
)
194 dprintk(4, "%p\n", av7110
);
196 ret
= av7110_fw_cmd(av7110
, COMTYPE_PIDFILTER
, SetIR
, 1, ir_config
);
197 av7110
->ir_config
= ir_config
;
203 static void ir_handler(struct av7110
*av7110
, u32 ircom
)
205 dprintk(4, "ircommand = %08x\n", ircom
);
206 av7110
->ir_command
= ircom
;
207 tasklet_schedule(&av7110
->ir_tasklet
);
211 int __init
av7110_ir_init(struct av7110
*av7110
)
213 static struct proc_dir_entry
*e
;
215 if (av_cnt
>= sizeof av_list
/sizeof av_list
[0])
218 av7110_setup_irc_config(av7110
, 0x0001);
219 av_list
[av_cnt
++] = av7110
;
222 init_timer(&keyup_timer
);
223 keyup_timer
.data
= 0;
225 input_dev
= input_allocate_device();
229 input_dev
->name
= "DVB on-card IR receiver";
231 set_bit(EV_KEY
, input_dev
->evbit
);
232 set_bit(EV_REP
, input_dev
->evbit
);
233 input_register_keys();
234 input_register_device(input_dev
);
235 input_dev
->timer
.function
= input_repeat_key
;
237 e
= create_proc_entry("av7110_ir", S_IFREG
| S_IRUGO
| S_IWUSR
, NULL
);
239 e
->write_proc
= av7110_ir_write_proc
;
240 e
->size
= 4 + 256 * sizeof(u16
);
244 tasklet_init(&av7110
->ir_tasklet
, av7110_emit_key
, (unsigned long) av7110
);
245 av7110
->ir_handler
= ir_handler
;
251 void __exit
av7110_ir_exit(struct av7110
*av7110
)
258 av7110
->ir_handler
= NULL
;
259 tasklet_kill(&av7110
->ir_tasklet
);
260 for (i
= 0; i
< av_cnt
; i
++)
261 if (av_list
[i
] == av7110
) {
262 av_list
[i
] = av_list
[av_cnt
-1];
263 av_list
[av_cnt
-1] = NULL
;
268 del_timer_sync(&keyup_timer
);
269 remove_proc_entry("av7110_ir", NULL
);
270 input_unregister_device(input_dev
);
276 //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
277 //MODULE_LICENSE("GPL");