1 /****************************************************************
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2009, Uri Shkolnik
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ****************************************************************/
23 #include <linux/types.h>
24 #include <linux/input.h>
26 #include "smscoreapi.h"
28 #include "sms-cards.h"
30 /* In order to add new IR remote control -
31 * 1) Add it to the <enum ir_kb_type> @ smsir,h,
32 * 2) Add its map to keyboard_layout_maps below
33 * 3) Set your board (sms-cards sub-module) to use it
36 static struct keyboard_layout_map_t keyboard_layout_maps
[] = {
37 [SMS_IR_KB_DEFAULT_TV
] = {
38 .ir_protocol
= IR_RC5
,
39 .rc5_kbd_address
= KEYBOARD_ADDRESS_TV1
,
40 .keyboard_layout_map
= {
44 KEY_9
, 0, 0, KEY_POWER
,
46 KEY_VOLUMEUP
, KEY_VOLUMEDOWN
,
48 KEY_BRIGHTNESSDOWN
, KEY_CHANNELUP
,
50 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
57 [SMS_IR_KB_HCW_SILVER
] = {
58 .ir_protocol
= IR_RC5
,
59 .rc5_kbd_address
= KEYBOARD_ADDRESS_LIGHTING1
,
60 .keyboard_layout_map
= {
64 KEY_9
, KEY_TEXT
, KEY_RED
,
67 KEY_MUTE
, KEY_VOLUMEUP
,
68 KEY_VOLUMEDOWN
, KEY_PREVIOUS
, 0,
69 KEY_UP
, KEY_DOWN
, KEY_LEFT
,
70 KEY_RIGHT
, KEY_VIDEO
, KEY_AUDIO
,
71 KEY_MHP
, KEY_EPG
, KEY_TV
,
72 0, KEY_NEXTSONG
, KEY_EXIT
,
73 KEY_CHANNELUP
, KEY_CHANNELDOWN
,
75 KEY_PREVIOUSSONG
, KEY_ENTER
,
76 KEY_SLEEP
, 0, 0, KEY_BLUE
,
77 0, 0, 0, 0, KEY_GREEN
, 0,
78 KEY_PAUSE
, 0, KEY_REWIND
,
79 0, KEY_FASTFORWARD
, KEY_PLAY
,
81 KEY_YELLOW
, 0, 0, KEY_SELECT
,
82 KEY_ZOOM
, KEY_POWER
, 0, 0
85 { } /* Terminating entry */
92 #define RC5_PUSH_BIT(dst, bit, pos) \
93 { dst <<= 1; dst |= bit; pos++; }
96 static void sms_ir_rc5_event(struct smscore_device_t
*coredev
,
97 u32 toggle
, u32 addr
, u32 cmd
)
102 sms_log("IR RC5 word: address %d, command %d, toggle %d",
105 toggle_changed
= ir_toggle
!= toggle
;
110 keyboard_layout_maps
[coredev
->ir
.ir_kb_type
].rc5_kbd_address
)
111 return; /* Check for valid address */
115 [coredev
->ir
.ir_kb_type
].keyboard_layout_map
[cmd
];
117 if (!toggle_changed
&&
118 (keycode
!= KEY_VOLUMEUP
&& keycode
!= KEY_VOLUMEDOWN
))
119 return; /* accept only repeated volume, reject other keys */
121 sms_log("kernel input keycode (from ir) %d", keycode
);
122 input_report_key(coredev
->ir
.input_dev
, keycode
, 1);
123 input_sync(coredev
->ir
.input_dev
);
127 /* decode raw bit pattern to RC5 code */
128 /* taken from ir-functions.c */
129 static u32
ir_rc5_decode(unsigned int code
)
131 /* unsigned int org_code = code;*/
133 unsigned int rc5
= 0;
136 for (i
= 0; i
< 14; ++i
) {
149 /* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
155 dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
156 toggle=%x, address=%x, "
157 "instr=%x\n", rc5, org_code, RC5_START(rc5),
158 RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
163 static void sms_rc5_parse_word(struct smscore_device_t
*coredev
)
165 #define RC5_START(x) (((x)>>12)&3)
166 #define RC5_TOGGLE(x) (((x)>>11)&1)
167 #define RC5_ADDR(x) (((x)>>6)&0x1F)
168 #define RC5_INSTR(x) ((x)&0x3F)
173 /* Reverse the IR word direction */
174 for (i
= 0 ; i
< 28 ; i
++)
175 RC5_PUSH_BIT(rc5_word
, (ir_word
>>i
)&1, j
)
177 rc5_word
= ir_rc5_decode(rc5_word
);
178 /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
180 sms_ir_rc5_event(coredev
,
181 RC5_TOGGLE(rc5_word
),
183 RC5_INSTR(rc5_word
));
187 static void sms_rc5_accumulate_bits(struct smscore_device_t
*coredev
,
190 #define RC5_TIME_GRANULARITY 200
191 #define RC5_DEF_BIT_TIME 889
192 #define RC5_MAX_SAME_BIT_CONT 4
193 #define RC5_WORD_LEN 27 /* 28 bit */
197 u32 time
= (ir_sample
> 0) ? ir_sample
: (0-ir_sample
);
198 u32 level
= (ir_sample
< 0) ? 0 : 1;
200 for (i
= RC5_MAX_SAME_BIT_CONT
; i
> 0; i
--) {
201 delta_time
= time
- (i
*RC5_DEF_BIT_TIME
) + RC5_TIME_GRANULARITY
;
203 continue; /* not so many consecutive bits */
204 if (delta_time
> (2 * RC5_TIME_GRANULARITY
)) {
206 if (ir_pos
== (RC5_WORD_LEN
-1))
207 /* complete last bit */
208 RC5_PUSH_BIT(ir_word
, level
, ir_pos
)
210 if (ir_pos
== RC5_WORD_LEN
)
211 sms_rc5_parse_word(coredev
);
212 else if (ir_pos
) /* timeout within a word */
213 sms_log("IR error parsing a word");
217 /* sms_log("timeout %d", time); */
220 /* The time is within the range of this number of bits */
221 for (j
= 0 ; j
< i
; j
++)
222 RC5_PUSH_BIT(ir_word
, level
, ir_pos
)
228 void sms_ir_event(struct smscore_device_t
*coredev
, const char *buf
, int len
)
230 #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
232 enum ir_protocol ir_protocol
=
233 keyboard_layout_maps
[coredev
->ir
.ir_kb_type
]
238 samples
= (s32
*)buf
;
239 /* sms_log("IR buffer received, length = %d", count);*/
241 for (i
= 0; i
< count
; i
++)
242 if (ir_protocol
== IR_RC5
)
243 sms_rc5_accumulate_bits(coredev
, samples
[i
]);
244 /* IR_RCMM not implemented */
247 int sms_ir_init(struct smscore_device_t
*coredev
)
249 struct input_dev
*input_dev
;
251 sms_log("Allocating input device");
252 input_dev
= input_allocate_device();
254 sms_err("Not enough memory");
258 coredev
->ir
.input_dev
= input_dev
;
259 coredev
->ir
.ir_kb_type
=
260 sms_get_board(smscore_get_board_id(coredev
))->ir_kb_type
;
261 coredev
->ir
.keyboard_layout_map
=
262 keyboard_layout_maps
[coredev
->ir
.ir_kb_type
].
264 sms_log("IR remote keyboard type is %d", coredev
->ir
.ir_kb_type
);
266 coredev
->ir
.controller
= 0; /* Todo: vega/nova SPI number */
267 coredev
->ir
.timeout
= IR_DEFAULT_TIMEOUT
;
268 sms_log("IR port %d, timeout %d ms",
269 coredev
->ir
.controller
, coredev
->ir
.timeout
);
271 snprintf(coredev
->ir
.name
,
273 "SMS IR w/kbd type %d",
274 coredev
->ir
.ir_kb_type
);
275 input_dev
->name
= coredev
->ir
.name
;
276 input_dev
->phys
= coredev
->ir
.name
;
277 input_dev
->dev
.parent
= coredev
->device
;
279 /* Key press events only */
280 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
);
281 input_dev
->keybit
[BIT_WORD(BTN_0
)] = BIT_MASK(BTN_0
);
283 sms_log("Input device (IR) %s is set for key events", input_dev
->name
);
285 if (input_register_device(input_dev
)) {
286 sms_err("Failed to register device");
287 input_free_device(input_dev
);
294 void sms_ir_exit(struct smscore_device_t
*coredev
)
296 if (coredev
->ir
.input_dev
)
297 input_unregister_device(coredev
->ir
.input_dev
);