aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2010-08-01 16:19:29 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 15:43:56 -0400
commit844a9e93d7fcd910cd94f6eb262e2cc43cacbe56 (patch)
tree6f9209f9d1408ab9c16174f766f1d69c5ad7bd71
parent1722f3b376f10182db85c2f6cf5bd79b857bc9e0 (diff)
V4L/DVB: sms: Convert IR support to use the Remote Controller core
Rewrites the siano IR implementation. The previous implementation were non-standard. As such, it has issues if more than one device registers IR, as there used to have some static constants used during protocol decoding phase. Also, it used to implement its on RAW decoder, and only for RC5. The new code uses RC core subsystem for handling IR. This brings several new features to the driver, including: - Allow to dynamically replace the IR keycodes; - Supports all existing raw decoders (JVC, NEC, RC-5, RC-6, SONY); - Supports lirc dev; - Doesn't have race conditions when more than one sms IR is registered; - The code size for the IR implementation is very small; - it exports the IR features via /sys/class/rc. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/IR/ir-keytable.c5
-rw-r--r--drivers/media/dvb/siano/sms-cards.c1
-rw-r--r--drivers/media/dvb/siano/sms-cards.h2
-rw-r--r--drivers/media/dvb/siano/smsir.c254
-rw-r--r--drivers/media/dvb/siano/smsir.h62
5 files changed, 47 insertions, 277 deletions
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 94a8577e72eb..15a0f192d413 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -497,8 +497,9 @@ int __ir_input_register(struct input_dev *input_dev,
497 goto out_event; 497 goto out_event;
498 } 498 }
499 499
500 IR_dprintk(1, "Registered input device on %s for %s remote.\n", 500 IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
501 driver_name, rc_tab->name); 501 driver_name, rc_tab->name,
502 ir_dev->props->driver_type == RC_DRIVER_IR_RAW ? " in raw mode" : "");
502 503
503 return 0; 504 return 0;
504 505
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index dcde60645960..25b43e587fa6 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -64,6 +64,7 @@ static struct sms_board sms_boards[] = {
64 .type = SMS_NOVA_B0, 64 .type = SMS_NOVA_B0,
65 .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", 65 .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
66 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", 66 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
67 .rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW,
67 .board_cfg.leds_power = 26, 68 .board_cfg.leds_power = 26,
68 .board_cfg.led0 = 27, 69 .board_cfg.led0 = 27,
69 .board_cfg.led1 = 28, 70 .board_cfg.led1 = 28,
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 8f19fc000b46..d8cdf756f7cf 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -75,7 +75,7 @@ struct sms_board {
75 enum sms_device_type_st type; 75 enum sms_device_type_st type;
76 char *name, *fw[DEVICE_MODE_MAX]; 76 char *name, *fw[DEVICE_MODE_MAX];
77 struct sms_board_gpio_cfg board_cfg; 77 struct sms_board_gpio_cfg board_cfg;
78 enum ir_kb_type ir_kb_type; 78 char *rc_codes; /* Name of IR codes table */
79 79
80 /* gpios */ 80 /* gpios */
81 int led_power, led_hi, led_lo, lna_ctrl, rf_switch; 81 int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index f8a4fd61e3dc..d0e4639ee9db 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -4,6 +4,11 @@
4 MDTV receiver kernel modules. 4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2009, Uri Shkolnik 5 Copyright (C) 2006-2009, Uri Shkolnik
6 6
7 Copyright (c) 2010 - Mauro Carvalho Chehab
8 - Ported the driver to use rc-core
9 - IR raw event decoding is now done at rc-core
10 - Code almost re-written
11
7 This program is free software: you can redistribute it and/or modify 12 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 13 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 14 the Free Software Foundation, either version 2 of the License, or
@@ -22,227 +27,27 @@
22 27
23#include <linux/types.h> 28#include <linux/types.h>
24#include <linux/input.h> 29#include <linux/input.h>
25#include <media/ir-core.h>
26 30
27#include "smscoreapi.h" 31#include "smscoreapi.h"
28#include "smsir.h" 32#include "smsir.h"
29#include "sms-cards.h" 33#include "sms-cards.h"
30 34
31/* In order to add new IR remote control - 35#define MODULE_NAME "smsmdtv"
32 * 1) Add it to the <enum ir_kb_type> @ smsir,h,
33 * 2) Add its map to keyboard_layout_maps below
34 * 3) Set your board (sms-cards sub-module) to use it
35 */
36
37static struct keyboard_layout_map_t keyboard_layout_maps[] = {
38 [SMS_IR_KB_DEFAULT_TV] = {
39 .ir_protocol = IR_RC5,
40 .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
41 .keyboard_layout_map = {
42 KEY_0, KEY_1, KEY_2,
43 KEY_3, KEY_4, KEY_5,
44 KEY_6, KEY_7, KEY_8,
45 KEY_9, 0, 0, KEY_POWER,
46 KEY_MUTE, 0, 0,
47 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
48 KEY_BRIGHTNESSUP,
49 KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
50 KEY_CHANNELDOWN,
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,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
56 }
57 },
58 [SMS_IR_KB_HCW_SILVER] = {
59 .ir_protocol = IR_RC5,
60 .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
61 .keyboard_layout_map = {
62 KEY_0, KEY_1, KEY_2,
63 KEY_3, KEY_4, KEY_5,
64 KEY_6, KEY_7, KEY_8,
65 KEY_9, KEY_TEXT, KEY_RED,
66 KEY_RADIO, KEY_MENU,
67 KEY_SUBTITLE,
68 KEY_MUTE, KEY_VOLUMEUP,
69 KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
70 KEY_UP, KEY_DOWN, KEY_LEFT,
71 KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
72 KEY_MHP, KEY_EPG, KEY_TV,
73 0, KEY_NEXTSONG, KEY_EXIT,
74 KEY_CHANNELUP, KEY_CHANNELDOWN,
75 KEY_CHANNEL, 0,
76 KEY_PREVIOUSSONG, KEY_ENTER,
77 KEY_SLEEP, 0, 0, KEY_BLUE,
78 0, 0, 0, 0, KEY_GREEN, 0,
79 KEY_PAUSE, 0, KEY_REWIND,
80 0, KEY_FASTFORWARD, KEY_PLAY,
81 KEY_STOP, KEY_RECORD,
82 KEY_YELLOW, 0, 0, KEY_SELECT,
83 KEY_ZOOM, KEY_POWER, 0, 0
84 }
85 },
86 { } /* Terminating entry */
87};
88
89static u32 ir_pos;
90static u32 ir_word;
91static u32 ir_toggle;
92
93#define RC5_PUSH_BIT(dst, bit, pos) \
94 { dst <<= 1; dst |= bit; pos++; }
95
96
97static void sms_ir_rc5_event(struct smscore_device_t *coredev,
98 u32 toggle, u32 addr, u32 cmd)
99{
100 bool toggle_changed;
101 u16 keycode;
102
103 sms_log("IR RC5 word: address %d, command %d, toggle %d",
104 addr, cmd, toggle);
105
106 toggle_changed = ir_toggle != toggle;
107 /* keep toggle */
108 ir_toggle = toggle;
109
110 if (addr !=
111 keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
112 return; /* Check for valid address */
113 36
114 keycode = 37void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
115 keyboard_layout_maps
116 [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
117
118 if (!toggle_changed &&
119 (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
120 return; /* accept only repeated volume, reject other keys */
121
122 sms_log("kernel input keycode (from ir) %d", keycode);
123 input_report_key(coredev->ir.input_dev, keycode, 1);
124 input_sync(coredev->ir.input_dev);
125
126}
127
128/* decode raw bit pattern to RC5 code */
129/* taken from ir-functions.c */
130static u32 ir_rc5_decode(unsigned int code)
131{ 38{
132/* unsigned int org_code = code;*/
133 unsigned int pair;
134 unsigned int rc5 = 0;
135 int i; 39 int i;
40 const s32 *samples = (const void *)buf;
136 41
137 for (i = 0; i < 14; ++i) { 42 for (i = 0; i < len >> 2; i++) {
138 pair = code & 0x3; 43 struct ir_raw_event ev;
139 code >>= 2;
140
141 rc5 <<= 1;
142 switch (pair) {
143 case 0:
144 case 2:
145 break;
146 case 1:
147 rc5 |= 1;
148 break;
149 case 3:
150/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
151 sms_log("bad code");
152 return 0;
153 }
154 }
155/*
156 dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
157 toggle=%x, address=%x, "
158 "instr=%x\n", rc5, org_code, RC5_START(rc5),
159 RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
160*/
161 return rc5;
162}
163
164static void sms_rc5_parse_word(struct smscore_device_t *coredev)
165{
166 #define RC5_START(x) (((x)>>12)&3)
167 #define RC5_TOGGLE(x) (((x)>>11)&1)
168 #define RC5_ADDR(x) (((x)>>6)&0x1F)
169 #define RC5_INSTR(x) ((x)&0x3F)
170
171 int i, j;
172 u32 rc5_word = 0;
173
174 /* Reverse the IR word direction */
175 for (i = 0 ; i < 28 ; i++)
176 RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
177
178 rc5_word = ir_rc5_decode(rc5_word);
179 /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
180
181 sms_ir_rc5_event(coredev,
182 RC5_TOGGLE(rc5_word),
183 RC5_ADDR(rc5_word),
184 RC5_INSTR(rc5_word));
185}
186
187
188static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
189 s32 ir_sample)
190{
191 #define RC5_TIME_GRANULARITY 200
192 #define RC5_DEF_BIT_TIME 889
193 #define RC5_MAX_SAME_BIT_CONT 4
194 #define RC5_WORD_LEN 27 /* 28 bit */
195
196 u32 i, j;
197 s32 delta_time;
198 u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
199 u32 level = (ir_sample < 0) ? 0 : 1;
200 44
201 for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) { 45 ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
202 delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY; 46 ev.pulse = (samples[i] > 0) ? false : true;
203 if (delta_time < 0)
204 continue; /* not so many consecutive bits */
205 if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
206 /* timeout */
207 if (ir_pos == (RC5_WORD_LEN-1))
208 /* complete last bit */
209 RC5_PUSH_BIT(ir_word, level, ir_pos)
210 47
211 if (ir_pos == RC5_WORD_LEN) 48 ir_raw_event_store(coredev->ir.input_dev, &ev);
212 sms_rc5_parse_word(coredev);
213 else if (ir_pos) /* timeout within a word */
214 sms_log("IR error parsing a word");
215
216 ir_pos = 0;
217 ir_word = 0;
218 /* sms_log("timeout %d", time); */
219 break;
220 }
221 /* The time is within the range of this number of bits */
222 for (j = 0 ; j < i ; j++)
223 RC5_PUSH_BIT(ir_word, level, ir_pos)
224
225 break;
226 } 49 }
227} 50 ir_raw_event_handle(coredev->ir.input_dev);
228
229void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
230{
231 #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
232 u32 i;
233 enum ir_protocol ir_protocol =
234 keyboard_layout_maps[coredev->ir.ir_kb_type]
235 .ir_protocol;
236 s32 *samples;
237 int count = len>>2;
238
239 samples = (s32 *)buf;
240/* sms_log("IR buffer received, length = %d", count);*/
241
242 for (i = 0; i < count; i++)
243 if (ir_protocol == IR_RC5)
244 sms_rc5_accumulate_bits(coredev, samples[i]);
245 /* IR_RCMM not implemented */
246} 51}
247 52
248int sms_ir_init(struct smscore_device_t *coredev) 53int sms_ir_init(struct smscore_device_t *coredev)
@@ -258,21 +63,14 @@ int sms_ir_init(struct smscore_device_t *coredev)
258 } 63 }
259 64
260 coredev->ir.input_dev = input_dev; 65 coredev->ir.input_dev = input_dev;
261 coredev->ir.ir_kb_type = sms_get_board(board_id)->ir_kb_type;
262 coredev->ir.keyboard_layout_map =
263 keyboard_layout_maps[coredev->ir.ir_kb_type].
264 keyboard_layout_map;
265 sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
266 66
267 coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ 67 coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
268 coredev->ir.timeout = IR_DEFAULT_TIMEOUT; 68 coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
269 sms_log("IR port %d, timeout %d ms", 69 sms_log("IR port %d, timeout %d ms",
270 coredev->ir.controller, coredev->ir.timeout); 70 coredev->ir.controller, coredev->ir.timeout);
271 71
272 snprintf(coredev->ir.name, 72 snprintf(coredev->ir.name, sizeof(coredev->ir.name),
273 sizeof(coredev->ir.name), 73 "SMS IR (%s)", sms_get_board(board_id)->name);
274 "SMS IR (%s)",
275 sms_get_board(board_id)->name);
276 74
277 strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); 75 strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
278 strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); 76 strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
@@ -281,13 +79,22 @@ int sms_ir_init(struct smscore_device_t *coredev)
281 input_dev->phys = coredev->ir.phys; 79 input_dev->phys = coredev->ir.phys;
282 input_dev->dev.parent = coredev->device; 80 input_dev->dev.parent = coredev->device;
283 81
284 /* Key press events only */ 82#if 0
285 input_dev->evbit[0] = BIT_MASK(EV_KEY); 83 /* TODO: properly initialize the parameters bellow */
286 input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); 84 input_dev->id.bustype = BUS_USB;
85 input_dev->id.version = 1;
86 input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
87 input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
88#endif
89
90 coredev->ir.props.priv = coredev;
91 coredev->ir.props.driver_type = RC_DRIVER_IR_RAW;
92 coredev->ir.props.allowed_protos = IR_TYPE_ALL;
287 93
288 sms_log("Input device (IR) %s is set for key events", input_dev->name); 94 sms_log("Input device (IR) %s is set for key events", input_dev->name);
289 95
290 if (input_register_device(input_dev)) { 96 if (ir_input_register(input_dev, sms_get_board(board_id)->rc_codes,
97 &coredev->ir.props, MODULE_NAME)) {
291 sms_err("Failed to register device"); 98 sms_err("Failed to register device");
292 input_free_device(input_dev); 99 input_free_device(input_dev);
293 return -EACCES; 100 return -EACCES;
@@ -299,8 +106,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
299void sms_ir_exit(struct smscore_device_t *coredev) 106void sms_ir_exit(struct smscore_device_t *coredev)
300{ 107{
301 if (coredev->ir.input_dev) 108 if (coredev->ir.input_dev)
302 input_unregister_device(coredev->ir.input_dev); 109 ir_input_unregister(coredev->ir.input_dev);
303 110
304 sms_log(""); 111 sms_log("");
305} 112}
306
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index 77e65057949b..926e247523bd 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -4,6 +4,11 @@ Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules. 4MDTV receiver kernel modules.
5Copyright (C) 2006-2009, Uri Shkolnik 5Copyright (C) 2006-2009, Uri Shkolnik
6 6
7 Copyright (c) 2010 - Mauro Carvalho Chehab
8 - Ported the driver to use rc-core
9 - IR raw event decoding is now done at rc-core
10 - Code almost re-written
11
7This program is free software: you can redistribute it and/or modify 12This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by 13it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or 14the Free Software Foundation, either version 2 of the License, or
@@ -23,64 +28,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
23#define __SMS_IR_H__ 28#define __SMS_IR_H__
24 29
25#include <linux/input.h> 30#include <linux/input.h>
31#include <media/ir-core.h>
26 32
27#define IR_DEV_NAME_MAX_LEN 40
28#define IR_KEYBOARD_LAYOUT_SIZE 64
29#define IR_DEFAULT_TIMEOUT 100 33#define IR_DEFAULT_TIMEOUT 100
30 34
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; 35struct smscore_device_t;
77 36
78struct ir_t { 37struct ir_t {
79 struct input_dev *input_dev; 38 struct input_dev *input_dev;
80 enum ir_kb_type ir_kb_type; 39 char name[40];
81 char name[IR_DEV_NAME_MAX_LEN + 1];
82 char phys[32]; 40 char phys[32];
83 u16 *keyboard_layout_map; 41
42 char *rc_codes;
43 u64 protocol;
44 struct ir_dev_props props;
45
84 u32 timeout; 46 u32 timeout;
85 u32 controller; 47 u32 controller;
86}; 48};