aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarod Wilson <jarod@redhat.com>2011-07-13 17:09:48 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:55:59 -0400
commitf5f2cc646af13b0cf74b9d676408473123c9ea76 (patch)
tree097040d201c3d8273513bba0aefe46feec9860ec
parenta062d04bb9adec35dd0c51f848c4c64a8a2224cd (diff)
[media] rc-core support for Microsoft IR keyboard/mouse
This is a custom IR protocol decoder, for the RC-6-ish protocol used by the Microsoft Remote Keyboard, apparently developed internally at Microsoft, and officially dubbed MCIR-2, per their March 2011 remote and transceiver requirements and specifications document, which also touches on this IR keyboard/mouse device. Its a standard keyboard with embedded thumb stick mouse pointer and mouse buttons, along with a number of media keys. The media keys are standard RC-6, identical to the signals from the stock MCE remotes, and will be handled as such. The keyboard and mouse signals will be decoded and delivered to the system by an input device registered specifically by this driver. Successfully tested with multiple mceusb-driven transceivers, as well as with fintek-cir and redrat3 hardware. Essentially, any raw IR hardware with enough sampling resolution should be able to use this decoder, nothing about it is at all receiver-hardware-specific. This work is inspired by lirc_mod_mce: The documentation there and code aided in understanding and decoding the protocol, but the bulk of the code is actually borrowed more from the existing in-kernel decoders than anything. I did recycle the keyboard keycode table, a few defines, and some of the keyboard and mouse data parsing bits from lirc_mod_mce though. Special thanks to James Meyer for providing the hardware, and being patient with me as I took forever to get around to writing this. callback routine to ensure we don't get any stuck keys, and used symbolic names for the keytable. Also cc'ing Florian this time, who I believe is the original mod-mce author... CC: Florian Demski <fdemski@users.sourceforge.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/rc/Kconfig11
-rw-r--r--drivers/media/rc/Makefile1
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c448
-rw-r--r--drivers/media/rc/ir-raw.c1
-rw-r--r--drivers/media/rc/rc-core-priv.h18
-rw-r--r--drivers/media/rc/rc-main.c1
-rw-r--r--include/media/rc-map.h3
7 files changed, 482 insertions, 1 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 7d4bbc226d06..899f783d92fb 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -87,6 +87,17 @@ config IR_RC5_SZ_DECODER
87 uses an IR protocol that is almost standard RC-5, but not quite, 87 uses an IR protocol that is almost standard RC-5, but not quite,
88 as it uses an additional bit). 88 as it uses an additional bit).
89 89
90config IR_MCE_KBD_DECODER
91 tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
92 depends on RC_CORE
93 select BITREVERSE
94 default y
95
96 ---help---
97 Enable this option if you have a Microsoft Remote Keyboard for
98 Windows Media Center Edition, which you would like to use with
99 a raw IR receiver in your system.
100
90config IR_LIRC_CODEC 101config IR_LIRC_CODEC
91 tristate "Enable IR to LIRC bridge" 102 tristate "Enable IR to LIRC bridge"
92 depends on RC_CORE 103 depends on RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 52830e5f4eaa..f224db027c41 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
10obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o 10obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o 11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o 12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
13obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
13obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o 14obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
14 15
15# stand-alone IR receivers/transmitters 16# stand-alone IR receivers/transmitters
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
new file mode 100644
index 000000000000..fe96e541839c
--- /dev/null
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -0,0 +1,448 @@
1/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol
2 * used by the Microsoft Remote Keyboard for Windows Media Center Edition,
3 * referred to by Microsoft's Windows Media Center remote specification docs
4 * as "an internal protocol called MCIR-2".
5 *
6 * Copyright (C) 2011 by Jarod Wilson <jarod@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation version 2 of the License.
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
18#include "rc-core-priv.h"
19
20/*
21 * This decoder currently supports:
22 * - MCIR-2 29-bit IR signals used for mouse movement and buttons
23 * - MCIR-2 32-bit IR signals used for standard keyboard keys
24 *
25 * The media keys on the keyboard send RC-6 signals that are inditinguishable
26 * from the keys of the same name on the stock MCE remote, and will be handled
27 * by the standard RC-6 decoder, and be made available to the system via the
28 * input device for the remote, rather than the keyboard/mouse one.
29 */
30
31#define MCIR2_UNIT 333333 /* ns */
32#define MCIR2_HEADER_NBITS 5
33#define MCIR2_MOUSE_NBITS 29
34#define MCIR2_KEYBOARD_NBITS 32
35#define MCIR2_PREFIX_PULSE (8 * MCIR2_UNIT)
36#define MCIR2_PREFIX_SPACE (1 * MCIR2_UNIT)
37#define MCIR2_MAX_LEN (3 * MCIR2_UNIT)
38#define MCIR2_BIT_START (1 * MCIR2_UNIT)
39#define MCIR2_BIT_END (1 * MCIR2_UNIT)
40#define MCIR2_BIT_0 (1 * MCIR2_UNIT)
41#define MCIR2_BIT_SET (2 * MCIR2_UNIT)
42#define MCIR2_MODE_MASK 0xf /* for the header bits */
43#define MCIR2_KEYBOARD_HEADER 0x4
44#define MCIR2_MOUSE_HEADER 0x1
45#define MCIR2_MASK_KEYS_START 0xe0
46
47enum mce_kbd_mode {
48 MCIR2_MODE_KEYBOARD,
49 MCIR2_MODE_MOUSE,
50 MCIR2_MODE_UNKNOWN,
51};
52
53enum mce_kbd_state {
54 STATE_INACTIVE,
55 STATE_HEADER_BIT_START,
56 STATE_HEADER_BIT_END,
57 STATE_BODY_BIT_START,
58 STATE_BODY_BIT_END,
59 STATE_FINISHED,
60};
61
62static unsigned char kbd_keycodes[256] = {
63 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A,
64 KEY_B, KEY_C, KEY_D, KEY_E, KEY_F,
65 KEY_G, KEY_H, KEY_I, KEY_J, KEY_K,
66 KEY_L, KEY_M, KEY_N, KEY_O, KEY_P,
67 KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U,
68 KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
69 KEY_1, KEY_2, KEY_3, KEY_4, KEY_5,
70 KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
71 KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE,
72 KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH,
73 KEY_RESERVED, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA,
74 KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2,
75 KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7,
76 KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
77 KEY_SYSRQ, KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME,
78 KEY_PAGEUP, KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT,
79 KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK, KEY_KPSLASH,
80 KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1,
81 KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6,
82 KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
83 KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13,
84 KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18,
85 KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23,
86 KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
87 KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY,
88 KEY_PASTE, KEY_FIND, KEY_MUTE, KEY_VOLUMEUP, KEY_VOLUMEDOWN,
89 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED,
90 KEY_RO, KEY_KATAKANAHIRAGANA, KEY_YEN, KEY_HENKAN, KEY_MUHENKAN,
91 KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HANGUEL,
92 KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED,
93 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
94 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
95 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
96 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
97 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
98 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
99 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
100 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
101 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
102 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
103 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
104 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
105 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
106 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
107 KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL,
108 KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT,
109 KEY_RIGHTALT, KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,
110 KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
111 KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND,
112 KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_COFFEE,
113 KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
114 KEY_RESERVED
115};
116
117static void mce_kbd_rx_timeout(unsigned long data)
118{
119 struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data;
120 int i;
121 unsigned char maskcode;
122
123 IR_dprintk(2, "timer callback clearing all keys\n");
124
125 for (i = 0; i < 7; i++) {
126 maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
127 input_report_key(mce_kbd->idev, maskcode, 0);
128 }
129
130 for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
131 input_report_key(mce_kbd->idev, kbd_keycodes[i], 0);
132}
133
134static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
135{
136 switch (data->header & MCIR2_MODE_MASK) {
137 case MCIR2_KEYBOARD_HEADER:
138 return MCIR2_MODE_KEYBOARD;
139 case MCIR2_MOUSE_HEADER:
140 return MCIR2_MODE_MOUSE;
141 default:
142 return MCIR2_MODE_UNKNOWN;
143 }
144}
145
146static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
147 u32 scancode)
148{
149 u8 keydata = (scancode >> 8) & 0xff;
150 u8 shiftmask = scancode & 0xff;
151 unsigned char keycode, maskcode;
152 int i, keystate;
153
154 IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
155 keydata, shiftmask);
156
157 for (i = 0; i < 7; i++) {
158 maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
159 if (shiftmask & (1 << i))
160 keystate = 1;
161 else
162 keystate = 0;
163 input_report_key(idev, maskcode, keystate);
164 }
165
166 if (keydata) {
167 keycode = kbd_keycodes[keydata];
168 input_report_key(idev, keycode, 1);
169 } else {
170 for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
171 input_report_key(idev, kbd_keycodes[i], 0);
172 }
173}
174
175static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
176{
177 /* raw mouse coordinates */
178 u8 xdata = (scancode >> 7) & 0x7f;
179 u8 ydata = (scancode >> 14) & 0x7f;
180 int x, y;
181 /* mouse buttons */
182 bool right = scancode & 0x40;
183 bool left = scancode & 0x20;
184
185 if (xdata & 0x40)
186 x = -((~xdata & 0x7f) + 1);
187 else
188 x = xdata;
189
190 if (ydata & 0x40)
191 y = -((~ydata & 0x7f) + 1);
192 else
193 y = ydata;
194
195 IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n",
196 x, y, left ? "L" : "", right ? "R" : "");
197
198 input_report_rel(idev, REL_X, x);
199 input_report_rel(idev, REL_Y, y);
200
201 input_report_key(idev, BTN_LEFT, left);
202 input_report_key(idev, BTN_RIGHT, right);
203}
204
205/**
206 * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
207 * @dev: the struct rc_dev descriptor of the device
208 * @ev: the struct ir_raw_event descriptor of the pulse/space
209 *
210 * This function returns -EINVAL if the pulse violates the state machine
211 */
212static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
213{
214 struct mce_kbd_dec *data = &dev->raw->mce_kbd;
215 u32 scancode;
216 unsigned long delay;
217
218 if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD))
219 return 0;
220
221 if (!is_timing_event(ev)) {
222 if (ev.reset)
223 data->state = STATE_INACTIVE;
224 return 0;
225 }
226
227 if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
228 goto out;
229
230again:
231 IR_dprintk(2, "started at state %i (%uus %s)\n",
232 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
233
234 if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
235 return 0;
236
237 switch (data->state) {
238
239 case STATE_INACTIVE:
240 if (!ev.pulse)
241 break;
242
243 /* Note: larger margin on first pulse since each MCIR2_UNIT
244 is quite short and some hardware takes some time to
245 adjust to the signal */
246 if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
247 break;
248
249 data->state = STATE_HEADER_BIT_START;
250 data->count = 0;
251 data->header = 0;
252 return 0;
253
254 case STATE_HEADER_BIT_START:
255 if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
256 break;
257
258 data->header <<= 1;
259 if (ev.pulse)
260 data->header |= 1;
261 data->count++;
262 data->state = STATE_HEADER_BIT_END;
263 return 0;
264
265 case STATE_HEADER_BIT_END:
266 if (!is_transition(&ev, &dev->raw->prev_ev))
267 break;
268
269 decrease_duration(&ev, MCIR2_BIT_END);
270
271 if (data->count != MCIR2_HEADER_NBITS) {
272 data->state = STATE_HEADER_BIT_START;
273 goto again;
274 }
275
276 switch (mce_kbd_mode(data)) {
277 case MCIR2_MODE_KEYBOARD:
278 data->wanted_bits = MCIR2_KEYBOARD_NBITS;
279 break;
280 case MCIR2_MODE_MOUSE:
281 data->wanted_bits = MCIR2_MOUSE_NBITS;
282 break;
283 default:
284 IR_dprintk(1, "not keyboard or mouse data\n");
285 goto out;
286 }
287
288 data->count = 0;
289 data->body = 0;
290 data->state = STATE_BODY_BIT_START;
291 goto again;
292
293 case STATE_BODY_BIT_START:
294 if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
295 break;
296
297 data->body <<= 1;
298 if (ev.pulse)
299 data->body |= 1;
300 data->count++;
301 data->state = STATE_BODY_BIT_END;
302 return 0;
303
304 case STATE_BODY_BIT_END:
305 if (!is_transition(&ev, &dev->raw->prev_ev))
306 break;
307
308 if (data->count == data->wanted_bits)
309 data->state = STATE_FINISHED;
310 else
311 data->state = STATE_BODY_BIT_START;
312
313 decrease_duration(&ev, MCIR2_BIT_END);
314 goto again;
315
316 case STATE_FINISHED:
317 if (ev.pulse)
318 break;
319
320 switch (data->wanted_bits) {
321 case MCIR2_KEYBOARD_NBITS:
322 scancode = data->body & 0xffff;
323 IR_dprintk(1, "keyboard data 0x%08x\n", data->body);
324 if (dev->timeout)
325 delay = usecs_to_jiffies(dev->timeout / 1000);
326 else
327 delay = msecs_to_jiffies(100);
328 mod_timer(&data->rx_timeout, jiffies + delay);
329 /* Pass data to keyboard buffer parser */
330 ir_mce_kbd_process_keyboard_data(data->idev, scancode);
331 break;
332 case MCIR2_MOUSE_NBITS:
333 scancode = data->body & 0x1fffff;
334 IR_dprintk(1, "mouse data 0x%06x\n", scancode);
335 /* Pass data to mouse buffer parser */
336 ir_mce_kbd_process_mouse_data(data->idev, scancode);
337 break;
338 default:
339 IR_dprintk(1, "not keyboard or mouse data\n");
340 goto out;
341 }
342
343 data->state = STATE_INACTIVE;
344 input_sync(data->idev);
345 return 0;
346 }
347
348out:
349 IR_dprintk(1, "failed at state %i (%uus %s)\n",
350 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
351 data->state = STATE_INACTIVE;
352 input_sync(data->idev);
353 return -EINVAL;
354}
355
356static int ir_mce_kbd_register(struct rc_dev *dev)
357{
358 struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
359 struct input_dev *idev;
360 int i, ret;
361
362 idev = input_allocate_device();
363 if (!idev)
364 return -ENOMEM;
365
366 snprintf(mce_kbd->name, sizeof(mce_kbd->name),
367 "MCE IR Keyboard/Mouse (%s)", dev->driver_name);
368 strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys));
369
370 idev->name = mce_kbd->name;
371 idev->phys = mce_kbd->phys;
372
373 /* Keyboard bits */
374 set_bit(EV_KEY, idev->evbit);
375 set_bit(EV_REP, idev->evbit);
376 for (i = 0; i < sizeof(kbd_keycodes); i++)
377 set_bit(kbd_keycodes[i], idev->keybit);
378
379 /* Mouse bits */
380 set_bit(EV_REL, idev->evbit);
381 set_bit(REL_X, idev->relbit);
382 set_bit(REL_Y, idev->relbit);
383 set_bit(BTN_LEFT, idev->keybit);
384 set_bit(BTN_RIGHT, idev->keybit);
385
386 /* Report scancodes too */
387 set_bit(EV_MSC, idev->evbit);
388 set_bit(MSC_SCAN, idev->mscbit);
389
390 setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout,
391 (unsigned long)mce_kbd);
392
393 input_set_drvdata(idev, mce_kbd);
394
395#if 0
396 /* Adding this reference means two input devices are associated with
397 * this rc-core device, which ir-keytable doesn't cope with yet */
398 idev->dev.parent = &dev->dev;
399#endif
400
401 ret = input_register_device(idev);
402 if (ret < 0) {
403 input_free_device(idev);
404 return -EIO;
405 }
406
407 mce_kbd->idev = idev;
408
409 return 0;
410}
411
412static int ir_mce_kbd_unregister(struct rc_dev *dev)
413{
414 struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
415 struct input_dev *idev = mce_kbd->idev;
416
417 del_timer_sync(&mce_kbd->rx_timeout);
418 input_unregister_device(idev);
419
420 return 0;
421}
422
423static struct ir_raw_handler mce_kbd_handler = {
424 .protocols = RC_TYPE_MCE_KBD,
425 .decode = ir_mce_kbd_decode,
426 .raw_register = ir_mce_kbd_register,
427 .raw_unregister = ir_mce_kbd_unregister,
428};
429
430static int __init ir_mce_kbd_decode_init(void)
431{
432 ir_raw_handler_register(&mce_kbd_handler);
433
434 printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n");
435 return 0;
436}
437
438static void __exit ir_mce_kbd_decode_exit(void)
439{
440 ir_raw_handler_unregister(&mce_kbd_handler);
441}
442
443module_init(ir_mce_kbd_decode_init);
444module_exit(ir_mce_kbd_decode_exit);
445
446MODULE_LICENSE("GPL");
447MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
448MODULE_DESCRIPTION("MCE Keyboard/mouse IR protocol decoder");
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 423ed45d6c55..27808bb59eba 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -355,6 +355,7 @@ static void init_decoders(struct work_struct *work)
355 load_rc6_decode(); 355 load_rc6_decode();
356 load_jvc_decode(); 356 load_jvc_decode();
357 load_sony_decode(); 357 load_sony_decode();
358 load_mce_kbd_decode();
358 load_lirc_codec(); 359 load_lirc_codec();
359 360
360 /* If needed, we may later add some init code. In this case, 361 /* If needed, we may later add some init code. In this case,
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 873b38789751..04c2c722b6ec 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -84,6 +84,17 @@ struct ir_raw_event_ctrl {
84 unsigned count; 84 unsigned count;
85 unsigned wanted_bits; 85 unsigned wanted_bits;
86 } rc5_sz; 86 } rc5_sz;
87 struct mce_kbd_dec {
88 struct input_dev *idev;
89 struct timer_list rx_timeout;
90 char name[64];
91 char phys[64];
92 int state;
93 u8 header;
94 u32 body;
95 unsigned count;
96 unsigned wanted_bits;
97 } mce_kbd;
87 struct lirc_codec { 98 struct lirc_codec {
88 struct rc_dev *dev; 99 struct rc_dev *dev;
89 struct lirc_driver *drv; 100 struct lirc_driver *drv;
@@ -182,6 +193,13 @@ void ir_raw_init(void);
182#define load_sony_decode() 0 193#define load_sony_decode() 0
183#endif 194#endif
184 195
196/* from ir-mce_kbd-decoder.c */
197#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
198#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder")
199#else
200#define load_mce_kbd_decode() 0
201#endif
202
185/* from ir-lirc-codec.c */ 203/* from ir-lirc-codec.c */
186#ifdef CONFIG_IR_LIRC_CODEC_MODULE 204#ifdef CONFIG_IR_LIRC_CODEC_MODULE
187#define load_lirc_codec() request_module("ir-lirc-codec") 205#define load_lirc_codec() request_module("ir-lirc-codec")
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 30634ab5c226..51a23f48bc7d 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -735,6 +735,7 @@ static struct {
735 { RC_TYPE_JVC, "jvc" }, 735 { RC_TYPE_JVC, "jvc" },
736 { RC_TYPE_SONY, "sony" }, 736 { RC_TYPE_SONY, "sony" },
737 { RC_TYPE_RC5_SZ, "rc-5-sz" }, 737 { RC_TYPE_RC5_SZ, "rc-5-sz" },
738 { RC_TYPE_MCE_KBD, "mce_kbd" },
738 { RC_TYPE_LIRC, "lirc" }, 739 { RC_TYPE_LIRC, "lirc" },
739 { RC_TYPE_OTHER, "other" }, 740 { RC_TYPE_OTHER, "other" },
740}; 741};
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 4e1409ec2613..17c9759ae77b 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -18,12 +18,13 @@
18#define RC_TYPE_JVC (1 << 3) /* JVC protocol */ 18#define RC_TYPE_JVC (1 << 3) /* JVC protocol */
19#define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ 19#define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */
20#define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */ 20#define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */
21#define RC_TYPE_MCE_KBD (1 << 29) /* RC6-ish MCE keyboard/mouse */
21#define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ 22#define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */
22#define RC_TYPE_OTHER (1u << 31) 23#define RC_TYPE_OTHER (1u << 31)
23 24
24#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \ 25#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \
25 RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \ 26 RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \
26 RC_TYPE_RC5_SZ | RC_TYPE_OTHER) 27 RC_TYPE_RC5_SZ | RC_TYPE_MCE_KBD | RC_TYPE_OTHER)
27 28
28struct rc_map_table { 29struct rc_map_table {
29 u32 scancode; 30 u32 scancode;