aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/siano
diff options
context:
space:
mode:
authorUri Shkolnik <uris@siano-ms.com>2009-04-05 05:01:37 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 18:14:22 -0400
commitebb6c22e80ccb2889b9c459df36d686d223911f5 (patch)
treee22e3b30bc947e0597a1b7ff45c5f1af19b16d70 /drivers/media/dvb/siano
parent53838e4b6126b225d2705a00614bd1de42e15f1d (diff)
V4L/DVB (11559): Siano: add support for infra-red (IR) controllers
This patch add support for IR (infra-red) remote controllers. Further commits are needed in order to enable the activation of the IR components. Signed-off-by: Uri Shkolnik <uris@siano-ms.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/siano')
-rw-r--r--drivers/media/dvb/siano/smsir.c301
-rw-r--r--drivers/media/dvb/siano/smsir.h93
2 files changed, 394 insertions, 0 deletions
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
new file mode 100644
index 000000000000..a5f302c58fdb
--- /dev/null
+++ b/drivers/media/dvb/siano/smsir.c
@@ -0,0 +1,301 @@
1/****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2009, Uri Shkolnik
6
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.
11
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.
16
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/>.
19
20 ****************************************************************/
21
22
23#include <linux/types.h>
24#include <linux/input.h>
25
26#include "smscoreapi.h"
27#include "smsir.h"
28#include "sms-cards.h"
29
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
34 */
35
36static 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 = {
41 KEY_0, KEY_1, KEY_2,
42 KEY_3, KEY_4, KEY_5,
43 KEY_6, KEY_7, KEY_8,
44 KEY_9, 0, 0, KEY_POWER,
45 KEY_MUTE, 0, 0,
46 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
47 KEY_BRIGHTNESSUP,
48 KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
49 KEY_CHANNELDOWN,
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
55 }
56 },
57 [SMS_IR_KB_HCW_SILVER] = {
58 .ir_protocol = IR_RC5,
59 .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
60 .keyboard_layout_map = {
61 KEY_0, KEY_1, KEY_2,
62 KEY_3, KEY_4, KEY_5,
63 KEY_6, KEY_7, KEY_8,
64 KEY_9, KEY_TEXT, KEY_RED,
65 KEY_RADIO, KEY_MENU,
66 KEY_SUBTITLE,
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,
74 KEY_CHANNEL, 0,
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,
80 KEY_STOP, KEY_RECORD,
81 KEY_YELLOW, 0, 0, KEY_SELECT,
82 KEY_ZOOM, KEY_POWER, 0, 0
83 }
84 },
85 { } /* Terminating entry */
86};
87
88u32 ir_pos;
89u32 ir_word;
90u32 ir_toggle;
91
92#define RC5_PUSH_BIT(dst, bit, pos) \
93 { dst <<= 1; dst |= bit; pos++; }
94
95
96static void sms_ir_rc5_event(struct smscore_device_t *coredev,
97 u32 toggle, u32 addr, u32 cmd)
98{
99 bool toggle_changed;
100 u16 keycode;
101
102 sms_info("IR RC5 word: address %d, command %d, toggle %d",
103 addr, cmd, toggle);
104
105 toggle_changed = ir_toggle != toggle;
106 /* keep toggle */
107 ir_toggle = toggle;
108
109 if (addr !=
110 keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
111 return; /* Check for valid address */
112
113 keycode =
114 keyboard_layout_maps
115 [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
116
117 if (!toggle_changed &&
118 (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
119 return; /* accept only repeated volume, reject other keys */
120
121 sms_info("kernel input keycode (from ir) %d", keycode);
122 input_report_key(coredev->ir.input_dev, keycode, 1);
123 input_sync(coredev->ir.input_dev);
124
125}
126
127/* decode raw bit pattern to RC5 code */
128/* taken from ir-functions.c */
129static u32 ir_rc5_decode(unsigned int code)
130{
131/* unsigned int org_code = code;*/
132 unsigned int pair;
133 unsigned int rc5 = 0;
134 int i;
135
136 for (i = 0; i < 14; ++i) {
137 pair = code & 0x3;
138 code >>= 2;
139
140 rc5 <<= 1;
141 switch (pair) {
142 case 0:
143 case 2:
144 break;
145 case 1:
146 rc5 |= 1;
147 break;
148 case 3:
149/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
150 sms_info("bad code");
151 return 0;
152 }
153 }
154/*
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));
159*/
160 return rc5;
161}
162
163static void sms_rc5_parse_word(struct smscore_device_t *coredev)
164{
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)
169
170 int i, j;
171 u32 rc5_word = 0;
172
173 /* Reverse the IR word direction */
174 for (i = 0 ; i < 28 ; i++)
175 RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
176
177 rc5_word = ir_rc5_decode(rc5_word);
178 /* sms_info("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
179
180 sms_ir_rc5_event(coredev,
181 RC5_TOGGLE(rc5_word),
182 RC5_ADDR(rc5_word),
183 RC5_INSTR(rc5_word));
184}
185
186
187static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
188 s32 ir_sample)
189{
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 */
194
195 u32 i, j;
196 s32 delta_time;
197 u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
198 u32 level = (ir_sample < 0) ? 0 : 1;
199
200 for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
201 delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
202 if (delta_time < 0)
203 continue; /* not so many consecutive bits */
204 if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
205 /* timeout */
206 if (ir_pos == (RC5_WORD_LEN-1))
207 /* complete last bit */
208 RC5_PUSH_BIT(ir_word, level, ir_pos)
209
210 if (ir_pos == RC5_WORD_LEN)
211 sms_rc5_parse_word(coredev);
212 else if (ir_pos) /* timeout within a word */
213 sms_info("IR error parsing a word");
214
215 ir_pos = 0;
216 ir_word = 0;
217 /* sms_info("timeout %d", time); */
218 break;
219 }
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)
223
224 break;
225 }
226}
227
228void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
229{
230 #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
231 u32 i;
232 enum ir_protocol ir_protocol =
233 keyboard_layout_maps[coredev->ir.ir_kb_type]
234 .ir_protocol;
235 s32 *samples;
236 int count = len>>2;
237
238 samples = (s32 *)buf;
239/* sms_info("IR buffer received, length = %d", count);*/
240
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 */
245}
246
247int sms_ir_init(struct smscore_device_t *coredev)
248{
249 struct input_dev *input_dev;
250
251 sms_info("Allocating input device");
252 input_dev = input_allocate_device();
253 if (!input_dev) {
254 sms_err("Not enough memory");
255 return -ENOMEM;
256 }
257
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].
263 keyboard_layout_map;
264 sms_info("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
265
266 coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
267 coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
268 sms_info("IR port %d, timeout %d ms",
269 coredev->ir.controller, coredev->ir.timeout);
270
271 snprintf(coredev->ir.name,
272 IR_DEV_NAME_MAX_LEN,
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;
278
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);
282
283 sms_info("Input device (IR) %s is set for key events", input_dev->name);
284
285 if (input_register_device(input_dev)) {
286 sms_err("Failed to register device");
287 input_free_device(input_dev);
288 return -EACCES;
289 }
290
291 return 0;
292}
293
294void sms_ir_exit(struct smscore_device_t *coredev)
295{
296 if (coredev->ir.input_dev)
297 input_unregister_device(coredev->ir.input_dev);
298
299 sms_info("");
300}
301
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
new file mode 100644
index 000000000000..b7d703e2d338
--- /dev/null
+++ b/drivers/media/dvb/siano/smsir.h
@@ -0,0 +1,93 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2009, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
21
22#ifndef __SMS_IR_H__
23#define __SMS_IR_H__
24
25#include <linux/input.h>
26
27#define IR_DEV_NAME_MAX_LEN 23 /* "SMS IR kbd type nn\0" */
28#define IR_KEYBOARD_LAYOUT_SIZE 64
29#define IR_DEFAULT_TIMEOUT 100
30
31enum ir_kb_type {
32 SMS_IR_KB_DEFAULT_TV,
33 SMS_IR_KB_HCW_SILVER
34};
35
36enum rc5_keyboard_address {
37 KEYBOARD_ADDRESS_TV1 = 0,
38 KEYBOARD_ADDRESS_TV2 = 1,
39 KEYBOARD_ADDRESS_TELETEXT = 2,
40 KEYBOARD_ADDRESS_VIDEO = 3,
41 KEYBOARD_ADDRESS_LV1 = 4,
42 KEYBOARD_ADDRESS_VCR1 = 5,
43 KEYBOARD_ADDRESS_VCR2 = 6,
44 KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
45 KEYBOARD_ADDRESS_SAT1 = 8,
46 KEYBOARD_ADDRESS_CAMERA = 9,
47 KEYBOARD_ADDRESS_SAT2 = 10,
48 KEYBOARD_ADDRESS_CDV = 12,
49 KEYBOARD_ADDRESS_CAMCORDER = 13,
50 KEYBOARD_ADDRESS_PRE_AMP = 16,
51 KEYBOARD_ADDRESS_TUNER = 17,
52 KEYBOARD_ADDRESS_RECORDER1 = 18,
53 KEYBOARD_ADDRESS_PRE_AMP1 = 19,
54 KEYBOARD_ADDRESS_CD_PLAYER = 20,
55 KEYBOARD_ADDRESS_PHONO = 21,
56 KEYBOARD_ADDRESS_SATA = 22,
57 KEYBOARD_ADDRESS_RECORDER2 = 23,
58 KEYBOARD_ADDRESS_CDR = 26,
59 KEYBOARD_ADDRESS_LIGHTING = 29,
60 KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
61 KEYBOARD_ADDRESS_PHONE = 31,
62 KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
63};
64
65enum ir_protocol {
66 IR_RC5,
67 IR_RCMM
68};
69
70struct keyboard_layout_map_t {
71 enum ir_protocol ir_protocol;
72 enum rc5_keyboard_address rc5_kbd_address;
73 u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
74};
75
76struct smscore_device_t;
77
78struct ir_t {
79 struct input_dev *input_dev;
80 enum ir_kb_type ir_kb_type;
81 char name[IR_DEV_NAME_MAX_LEN+1];
82 u16 *keyboard_layout_map;
83 u32 timeout;
84 u32 controller;
85};
86
87int sms_ir_init(struct smscore_device_t *coredev);
88void sms_ir_exit(struct smscore_device_t *coredev);
89void sms_ir_event(struct smscore_device_t *coredev,
90 const char *buf, int len);
91
92#endif /* __SMS_IR_H__ */
93