1f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol 2f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * used by the Microsoft Remote Keyboard for Windows Media Center Edition, 3f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * referred to by Microsoft's Windows Media Center remote specification docs 4f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * as "an internal protocol called MCIR-2". 5f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * 6f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * Copyright (C) 2011 by Jarod Wilson <jarod@redhat.com> 7f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * 8f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * This program is free software; you can redistribute it and/or modify 9f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * it under the terms of the GNU General Public License as published by 10f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * the Free Software Foundation version 2 of the License. 11f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * 12f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * This program is distributed in the hope that it will be useful, 13f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * but WITHOUT ANY WARRANTY; without even the implied warranty of 14f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * GNU General Public License for more details. 16f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson */ 17ee2ce3a0b43d14d792d34cf88e7bc2091096744bStephen Rothwell#include <linux/module.h> 18f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 19f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#include "rc-core-priv.h" 20f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 21f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson/* 22f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * This decoder currently supports: 23f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * - MCIR-2 29-bit IR signals used for mouse movement and buttons 24f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * - MCIR-2 32-bit IR signals used for standard keyboard keys 25f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * 26f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * The media keys on the keyboard send RC-6 signals that are inditinguishable 27f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * from the keys of the same name on the stock MCE remote, and will be handled 28f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * by the standard RC-6 decoder, and be made available to the system via the 29f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * input device for the remote, rather than the keyboard/mouse one. 30f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson */ 31f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 32f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_UNIT 333333 /* ns */ 33f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_HEADER_NBITS 5 34f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_MOUSE_NBITS 29 35f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_KEYBOARD_NBITS 32 36f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_PREFIX_PULSE (8 * MCIR2_UNIT) 37f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_PREFIX_SPACE (1 * MCIR2_UNIT) 38f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_MAX_LEN (3 * MCIR2_UNIT) 39f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_BIT_START (1 * MCIR2_UNIT) 40f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_BIT_END (1 * MCIR2_UNIT) 41f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_BIT_0 (1 * MCIR2_UNIT) 42f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_BIT_SET (2 * MCIR2_UNIT) 43f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_MODE_MASK 0xf /* for the header bits */ 44f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_KEYBOARD_HEADER 0x4 45f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_MOUSE_HEADER 0x1 46f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#define MCIR2_MASK_KEYS_START 0xe0 47f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 48f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonenum mce_kbd_mode { 49f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson MCIR2_MODE_KEYBOARD, 50f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson MCIR2_MODE_MOUSE, 51f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson MCIR2_MODE_UNKNOWN, 52f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson}; 53f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 54f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonenum mce_kbd_state { 55f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_INACTIVE, 56f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_HEADER_BIT_START, 57f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_HEADER_BIT_END, 58f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_BODY_BIT_START, 59f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_BODY_BIT_END, 60f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson STATE_FINISHED, 61f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson}; 62f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 63f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic unsigned char kbd_keycodes[256] = { 64f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, 65f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, 66f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, 67f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, 68f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, 69f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, 70f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, 71f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, 72f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, 73f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 74f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, 75f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, 76f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, 77f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 78f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_SYSRQ, KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, 79f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_PAGEUP, KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, 80f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, 81f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, 82f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, 83f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, 84f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, 85f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, 86f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, 87f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, 88f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, 89f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_PASTE, KEY_FIND, KEY_MUTE, KEY_VOLUMEUP, KEY_VOLUMEDOWN, 90f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, 91f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RO, KEY_KATAKANAHIRAGANA, KEY_YEN, KEY_HENKAN, KEY_MUHENKAN, 92f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HANGUEL, 93f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, 94f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 95f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 96f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 97f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 98f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 99f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 100f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 101f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 102f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 103f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 104f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 105f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 106f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 107f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 108f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, 109f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, 110f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RIGHTALT, KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, 111f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, 112f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, 113f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_COFFEE, 114f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, 115f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson KEY_RESERVED 116f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson}; 117f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 118f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic void mce_kbd_rx_timeout(unsigned long data) 119f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 120f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data; 121f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson int i; 122f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson unsigned char maskcode; 123f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 124f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(2, "timer callback clearing all keys\n"); 125f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 126f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson for (i = 0; i < 7; i++) { 127f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; 128f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(mce_kbd->idev, maskcode, 0); 129f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 130f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 131f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson for (i = 0; i < MCIR2_MASK_KEYS_START; i++) 132f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(mce_kbd->idev, kbd_keycodes[i], 0); 133f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 134f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 135f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) 136f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 137f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson switch (data->header & MCIR2_MODE_MASK) { 138f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_KEYBOARD_HEADER: 139f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return MCIR2_MODE_KEYBOARD; 140f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_MOUSE_HEADER: 141f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return MCIR2_MODE_MOUSE; 142f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson default: 143f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return MCIR2_MODE_UNKNOWN; 144f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 145f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 146f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 147f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, 148f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u32 scancode) 149f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 150f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u8 keydata = (scancode >> 8) & 0xff; 151f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u8 shiftmask = scancode & 0xff; 152f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson unsigned char keycode, maskcode; 153f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson int i, keystate; 154f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 155f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", 156f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson keydata, shiftmask); 157f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 158f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson for (i = 0; i < 7; i++) { 159f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; 160f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (shiftmask & (1 << i)) 161f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson keystate = 1; 162f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson else 163f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson keystate = 0; 164f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(idev, maskcode, keystate); 165f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 166f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 167f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (keydata) { 168f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson keycode = kbd_keycodes[keydata]; 169f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(idev, keycode, 1); 170f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } else { 171f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson for (i = 0; i < MCIR2_MASK_KEYS_START; i++) 172f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(idev, kbd_keycodes[i], 0); 173f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 174f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 175f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 176f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) 177f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 178f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* raw mouse coordinates */ 179f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u8 xdata = (scancode >> 7) & 0x7f; 180f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u8 ydata = (scancode >> 14) & 0x7f; 181f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson int x, y; 182f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* mouse buttons */ 183f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson bool right = scancode & 0x40; 184f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson bool left = scancode & 0x20; 185f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 186f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (xdata & 0x40) 187f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson x = -((~xdata & 0x7f) + 1); 188f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson else 189f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson x = xdata; 190f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 191f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ydata & 0x40) 192f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson y = -((~ydata & 0x7f) + 1); 193f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson else 194f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson y = ydata; 195f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 196f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n", 197f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson x, y, left ? "L" : "", right ? "R" : ""); 198f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 199f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_rel(idev, REL_X, x); 200f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_rel(idev, REL_Y, y); 201f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 202f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(idev, BTN_LEFT, left); 203f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_report_key(idev, BTN_RIGHT, right); 204f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 205f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 206f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson/** 207f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space 208f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * @dev: the struct rc_dev descriptor of the device 209f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * @ev: the struct ir_raw_event descriptor of the pulse/space 210f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * 211f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * This function returns -EINVAL if the pulse violates the state machine 212f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson */ 213f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) 214f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 215f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct mce_kbd_dec *data = &dev->raw->mce_kbd; 216f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson u32 scancode; 217f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson unsigned long delay; 218f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 219f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD)) 220f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 221f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 222f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!is_timing_event(ev)) { 223f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ev.reset) 224f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_INACTIVE; 225f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 226f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 227f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 228f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) 229f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto out; 230f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 231f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonagain: 232f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(2, "started at state %i (%uus %s)\n", 233f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 234f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 235f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) 236f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 237f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 238f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson switch (data->state) { 239f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 240f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_INACTIVE: 241f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!ev.pulse) 242f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 243f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 244f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Note: larger margin on first pulse since each MCIR2_UNIT 245f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson is quite short and some hardware takes some time to 246f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson adjust to the signal */ 247f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT)) 248f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 249f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 250f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_HEADER_BIT_START; 251f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->count = 0; 252f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->header = 0; 253f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 254f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 255f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_HEADER_BIT_START: 256f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) 257f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 258f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 259f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->header <<= 1; 260f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ev.pulse) 261f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->header |= 1; 262f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->count++; 263f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_HEADER_BIT_END; 264f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 265f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 266f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_HEADER_BIT_END: 267f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!is_transition(&ev, &dev->raw->prev_ev)) 268f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 269f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 270f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson decrease_duration(&ev, MCIR2_BIT_END); 271f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 272f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (data->count != MCIR2_HEADER_NBITS) { 273f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_HEADER_BIT_START; 274f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto again; 275f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 276f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 277f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson switch (mce_kbd_mode(data)) { 278f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_MODE_KEYBOARD: 279f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->wanted_bits = MCIR2_KEYBOARD_NBITS; 280f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 281f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_MODE_MOUSE: 282f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->wanted_bits = MCIR2_MOUSE_NBITS; 283f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 284f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson default: 285f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "not keyboard or mouse data\n"); 286f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto out; 287f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 288f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 289f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->count = 0; 290f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->body = 0; 291f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_BODY_BIT_START; 292f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto again; 293f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 294f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_BODY_BIT_START: 295f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) 296f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 297f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 298f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->body <<= 1; 299f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ev.pulse) 300f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->body |= 1; 301f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->count++; 302f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_BODY_BIT_END; 303f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 304f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 305f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_BODY_BIT_END: 306f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!is_transition(&ev, &dev->raw->prev_ev)) 307f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 308f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 309f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (data->count == data->wanted_bits) 310f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_FINISHED; 311f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson else 312f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_BODY_BIT_START; 313f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 314f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson decrease_duration(&ev, MCIR2_BIT_END); 315f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto again; 316f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 317f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case STATE_FINISHED: 318f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ev.pulse) 319f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 320f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 321f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson switch (data->wanted_bits) { 322f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_KEYBOARD_NBITS: 323f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson scancode = data->body & 0xffff; 324f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "keyboard data 0x%08x\n", data->body); 325f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (dev->timeout) 326f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson delay = usecs_to_jiffies(dev->timeout / 1000); 327f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson else 328f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson delay = msecs_to_jiffies(100); 329f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson mod_timer(&data->rx_timeout, jiffies + delay); 330f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Pass data to keyboard buffer parser */ 331f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson ir_mce_kbd_process_keyboard_data(data->idev, scancode); 332f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 333f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson case MCIR2_MOUSE_NBITS: 334f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson scancode = data->body & 0x1fffff; 335f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "mouse data 0x%06x\n", scancode); 336f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Pass data to mouse buffer parser */ 337f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson ir_mce_kbd_process_mouse_data(data->idev, scancode); 338f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson break; 339f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson default: 340f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "not keyboard or mouse data\n"); 341f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson goto out; 342f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 343f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 344f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_INACTIVE; 345f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_sync(data->idev); 346f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 347f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 348f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 349f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonout: 350f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson IR_dprintk(1, "failed at state %i (%uus %s)\n", 351f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state, TO_US(ev.duration), TO_STR(ev.pulse)); 352f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson data->state = STATE_INACTIVE; 353f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_sync(data->idev); 354f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return -EINVAL; 355f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 356f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 357f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic int ir_mce_kbd_register(struct rc_dev *dev) 358f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 359f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; 360f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct input_dev *idev; 361f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson int i, ret; 362f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 363f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson idev = input_allocate_device(); 364f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (!idev) 365f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return -ENOMEM; 366f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 367f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson snprintf(mce_kbd->name, sizeof(mce_kbd->name), 368f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson "MCE IR Keyboard/Mouse (%s)", dev->driver_name); 369f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys)); 370f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 371f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson idev->name = mce_kbd->name; 372f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson idev->phys = mce_kbd->phys; 373f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 374f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Keyboard bits */ 375f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(EV_KEY, idev->evbit); 376f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(EV_REP, idev->evbit); 377f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson for (i = 0; i < sizeof(kbd_keycodes); i++) 378f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(kbd_keycodes[i], idev->keybit); 379f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 380f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Mouse bits */ 381f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(EV_REL, idev->evbit); 382f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(REL_X, idev->relbit); 383f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(REL_Y, idev->relbit); 384f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(BTN_LEFT, idev->keybit); 385f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(BTN_RIGHT, idev->keybit); 386f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 387f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Report scancodes too */ 388f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(EV_MSC, idev->evbit); 389f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson set_bit(MSC_SCAN, idev->mscbit); 390f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 391f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 392f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson (unsigned long)mce_kbd); 393f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 394f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_set_drvdata(idev, mce_kbd); 395f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 396f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#if 0 397f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson /* Adding this reference means two input devices are associated with 398f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson * this rc-core device, which ir-keytable doesn't cope with yet */ 399f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson idev->dev.parent = &dev->dev; 400f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson#endif 401f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 402f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson ret = input_register_device(idev); 403f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson if (ret < 0) { 404f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_free_device(idev); 405f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return -EIO; 406f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson } 407f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 408f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson mce_kbd->idev = idev; 409f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 410f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 411f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 412f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 413f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic int ir_mce_kbd_unregister(struct rc_dev *dev) 414f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 415f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; 416f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson struct input_dev *idev = mce_kbd->idev; 417f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 418f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson del_timer_sync(&mce_kbd->rx_timeout); 419f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson input_unregister_device(idev); 420f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 421f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 422f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 423f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 424f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic struct ir_raw_handler mce_kbd_handler = { 425f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson .protocols = RC_TYPE_MCE_KBD, 426f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson .decode = ir_mce_kbd_decode, 427f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson .raw_register = ir_mce_kbd_register, 428f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson .raw_unregister = ir_mce_kbd_unregister, 429f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson}; 430f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 431f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic int __init ir_mce_kbd_decode_init(void) 432f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 433f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson ir_raw_handler_register(&mce_kbd_handler); 434f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 435f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n"); 436f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson return 0; 437f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 438f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 439f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonstatic void __exit ir_mce_kbd_decode_exit(void) 440f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson{ 441f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson ir_raw_handler_unregister(&mce_kbd_handler); 442f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson} 443f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 444f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonmodule_init(ir_mce_kbd_decode_init); 445f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilsonmodule_exit(ir_mce_kbd_decode_exit); 446f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod Wilson 447f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod WilsonMODULE_LICENSE("GPL"); 448f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod WilsonMODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); 449f5f2cc646af13b0cf74b9d676408473123c9ea76Jarod WilsonMODULE_DESCRIPTION("MCE Keyboard/mouse IR protocol decoder"); 450