diff options
Diffstat (limited to 'drivers/media/rc')
-rw-r--r-- | drivers/media/rc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/media/rc/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/rc/ene_ir.c | 4 | ||||
-rw-r--r-- | drivers/media/rc/ene_ir.h | 2 | ||||
-rw-r--r-- | drivers/media/rc/ir-lirc-codec.c | 15 | ||||
-rw-r--r-- | drivers/media/rc/ir-mce_kbd-decoder.c | 449 | ||||
-rw-r--r-- | drivers/media/rc/ir-raw.c | 1 | ||||
-rw-r--r-- | drivers/media/rc/ite-cir.c | 5 | ||||
-rw-r--r-- | drivers/media/rc/keymaps/rc-rc6-mce.c | 3 | ||||
-rw-r--r-- | drivers/media/rc/mceusb.c | 10 | ||||
-rw-r--r-- | drivers/media/rc/nuvoton-cir.c | 12 | ||||
-rw-r--r-- | drivers/media/rc/rc-core-priv.h | 18 | ||||
-rw-r--r-- | drivers/media/rc/rc-loopback.c | 13 | ||||
-rw-r--r-- | drivers/media/rc/rc-main.c | 4 | ||||
-rw-r--r-- | drivers/media/rc/redrat3.c | 63 | ||||
-rw-r--r-- | drivers/media/rc/winbond-cir.c | 28 |
16 files changed, 543 insertions, 96 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 uses an IR protocol that is almost standard RC-5, but not quite, as it uses an additional bit). +config IR_MCE_KBD_DECODER + tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have a Microsoft Remote Keyboard for + Windows Media Center Edition, which you would like to use with + a raw IR receiver in your system. + config IR_LIRC_CODEC tristate "Enable IR to LIRC bridge" 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 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o +obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index a43ed6c41bfc..2b9c2569d74a 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -953,13 +953,13 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle) } /* outside interface: transmit */ -static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n) +static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n) { struct ene_device *dev = rdev->priv; unsigned long flags; dev->tx_buffer = buf; - dev->tx_len = n / sizeof(int); + dev->tx_len = n; dev->tx_pos = 0; dev->tx_reg = 0; dev->tx_done = 0; diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index 337a41d4450b..017c209cdf8a 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -235,7 +235,7 @@ struct ene_device { bool tx_sample_pulse; /* current sample is pulse */ /* TX buffer */ - int *tx_buffer; /* input samples buffer*/ + unsigned *tx_buffer; /* input samples buffer*/ int tx_pos; /* position in that bufer */ int tx_len; /* current len of tx buffer */ int tx_done; /* done transmitting */ diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 1c5cc65ea1e1..e5eeec4da76e 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -103,19 +103,19 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, { struct lirc_codec *lirc; struct rc_dev *dev; - int *txbuf; /* buffer with values to transmit */ - int ret = 0; + unsigned int *txbuf; /* buffer with values to transmit */ + ssize_t ret = 0; size_t count; lirc = lirc_get_pdata(file); if (!lirc) return -EFAULT; - if (n % sizeof(int)) + if (n < sizeof(unsigned) || n % sizeof(unsigned)) return -EINVAL; - count = n / sizeof(int); - if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0) + count = n / sizeof(unsigned); + if (count > LIRCBUF_SIZE || count % 2 == 0) return -EINVAL; txbuf = memdup_user(buf, n); @@ -129,7 +129,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, } if (dev->tx_ir) - ret = dev->tx_ir(dev, txbuf, (u32)n); + ret = dev->tx_ir(dev, txbuf, count); + + if (ret > 0) + ret *= sizeof(unsigned); out: kfree(txbuf); 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..3784ebf80ec7 --- /dev/null +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -0,0 +1,449 @@ +/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol + * used by the Microsoft Remote Keyboard for Windows Media Center Edition, + * referred to by Microsoft's Windows Media Center remote specification docs + * as "an internal protocol called MCIR-2". + * + * Copyright (C) 2011 by Jarod Wilson <jarod@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/module.h> + +#include "rc-core-priv.h" + +/* + * This decoder currently supports: + * - MCIR-2 29-bit IR signals used for mouse movement and buttons + * - MCIR-2 32-bit IR signals used for standard keyboard keys + * + * The media keys on the keyboard send RC-6 signals that are inditinguishable + * from the keys of the same name on the stock MCE remote, and will be handled + * by the standard RC-6 decoder, and be made available to the system via the + * input device for the remote, rather than the keyboard/mouse one. + */ + +#define MCIR2_UNIT 333333 /* ns */ +#define MCIR2_HEADER_NBITS 5 +#define MCIR2_MOUSE_NBITS 29 +#define MCIR2_KEYBOARD_NBITS 32 +#define MCIR2_PREFIX_PULSE (8 * MCIR2_UNIT) +#define MCIR2_PREFIX_SPACE (1 * MCIR2_UNIT) +#define MCIR2_MAX_LEN (3 * MCIR2_UNIT) +#define MCIR2_BIT_START (1 * MCIR2_UNIT) +#define MCIR2_BIT_END (1 * MCIR2_UNIT) +#define MCIR2_BIT_0 (1 * MCIR2_UNIT) +#define MCIR2_BIT_SET (2 * MCIR2_UNIT) +#define MCIR2_MODE_MASK 0xf /* for the header bits */ +#define MCIR2_KEYBOARD_HEADER 0x4 +#define MCIR2_MOUSE_HEADER 0x1 +#define MCIR2_MASK_KEYS_START 0xe0 + +enum mce_kbd_mode { + MCIR2_MODE_KEYBOARD, + MCIR2_MODE_MOUSE, + MCIR2_MODE_UNKNOWN, +}; + +enum mce_kbd_state { + STATE_INACTIVE, + STATE_HEADER_BIT_START, + STATE_HEADER_BIT_END, + STATE_BODY_BIT_START, + STATE_BODY_BIT_END, + STATE_FINISHED, +}; + +static unsigned char kbd_keycodes[256] = { + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, + KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, + KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, + KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, + KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, + KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, + KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, + KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, + KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, + KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, + KEY_RESERVED, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, + KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, + KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, + KEY_SYSRQ, KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, + KEY_PAGEUP, KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, + KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, + KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, + KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, + KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, + KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, + KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, + KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, + KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, + KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, + KEY_PASTE, KEY_FIND, KEY_MUTE, KEY_VOLUMEUP, KEY_VOLUMEDOWN, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, + KEY_RO, KEY_KATAKANAHIRAGANA, KEY_YEN, KEY_HENKAN, KEY_MUHENKAN, + KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_HANGUEL, + KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTCTRL, + KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, + KEY_RIGHTALT, KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, + KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, + KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, + KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_COFFEE, + KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED +}; + +static void mce_kbd_rx_timeout(unsigned long data) +{ + struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data; + int i; + unsigned char maskcode; + + IR_dprintk(2, "timer callback clearing all keys\n"); + + for (i = 0; i < 7; i++) { + maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; + input_report_key(mce_kbd->idev, maskcode, 0); + } + + for (i = 0; i < MCIR2_MASK_KEYS_START; i++) + input_report_key(mce_kbd->idev, kbd_keycodes[i], 0); +} + +static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data) +{ + switch (data->header & MCIR2_MODE_MASK) { + case MCIR2_KEYBOARD_HEADER: + return MCIR2_MODE_KEYBOARD; + case MCIR2_MOUSE_HEADER: + return MCIR2_MODE_MOUSE; + default: + return MCIR2_MODE_UNKNOWN; + } +} + +static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev, + u32 scancode) +{ + u8 keydata = (scancode >> 8) & 0xff; + u8 shiftmask = scancode & 0xff; + unsigned char keycode, maskcode; + int i, keystate; + + IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n", + keydata, shiftmask); + + for (i = 0; i < 7; i++) { + maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i]; + if (shiftmask & (1 << i)) + keystate = 1; + else + keystate = 0; + input_report_key(idev, maskcode, keystate); + } + + if (keydata) { + keycode = kbd_keycodes[keydata]; + input_report_key(idev, keycode, 1); + } else { + for (i = 0; i < MCIR2_MASK_KEYS_START; i++) + input_report_key(idev, kbd_keycodes[i], 0); + } +} + +static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode) +{ + /* raw mouse coordinates */ + u8 xdata = (scancode >> 7) & 0x7f; + u8 ydata = (scancode >> 14) & 0x7f; + int x, y; + /* mouse buttons */ + bool right = scancode & 0x40; + bool left = scancode & 0x20; + + if (xdata & 0x40) + x = -((~xdata & 0x7f) + 1); + else + x = xdata; + + if (ydata & 0x40) + y = -((~ydata & 0x7f) + 1); + else + y = ydata; + + IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n", + x, y, left ? "L" : "", right ? "R" : ""); + + input_report_rel(idev, REL_X, x); + input_report_rel(idev, REL_Y, y); + + input_report_key(idev, BTN_LEFT, left); + input_report_key(idev, BTN_RIGHT, right); +} + +/** + * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct mce_kbd_dec *data = &dev->raw->mce_kbd; + u32 scancode; + unsigned long delay; + + if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) + goto out; + +again: + IR_dprintk(2, "started at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2)) + return 0; + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + /* Note: larger margin on first pulse since each MCIR2_UNIT + is quite short and some hardware takes some time to + adjust to the signal */ + if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT)) + break; + + data->state = STATE_HEADER_BIT_START; + data->count = 0; + data->header = 0; + return 0; + + case STATE_HEADER_BIT_START: + if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) + break; + + data->header <<= 1; + if (ev.pulse) + data->header |= 1; + data->count++; + data->state = STATE_HEADER_BIT_END; + return 0; + + case STATE_HEADER_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + decrease_duration(&ev, MCIR2_BIT_END); + + if (data->count != MCIR2_HEADER_NBITS) { + data->state = STATE_HEADER_BIT_START; + goto again; + } + + switch (mce_kbd_mode(data)) { + case MCIR2_MODE_KEYBOARD: + data->wanted_bits = MCIR2_KEYBOARD_NBITS; + break; + case MCIR2_MODE_MOUSE: + data->wanted_bits = MCIR2_MOUSE_NBITS; + break; + default: + IR_dprintk(1, "not keyboard or mouse data\n"); + goto out; + } + + data->count = 0; + data->body = 0; + data->state = STATE_BODY_BIT_START; + goto again; + + case STATE_BODY_BIT_START: + if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2)) + break; + + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + data->count++; + data->state = STATE_BODY_BIT_END; + return 0; + + case STATE_BODY_BIT_END: + if (!is_transition(&ev, &dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) + data->state = STATE_FINISHED; + else + data->state = STATE_BODY_BIT_START; + + decrease_duration(&ev, MCIR2_BIT_END); + goto again; + + case STATE_FINISHED: + if (ev.pulse) + break; + + switch (data->wanted_bits) { + case MCIR2_KEYBOARD_NBITS: + scancode = data->body & 0xffff; + IR_dprintk(1, "keyboard data 0x%08x\n", data->body); + if (dev->timeout) + delay = usecs_to_jiffies(dev->timeout / 1000); + else + delay = msecs_to_jiffies(100); + mod_timer(&data->rx_timeout, jiffies + delay); + /* Pass data to keyboard buffer parser */ + ir_mce_kbd_process_keyboard_data(data->idev, scancode); + break; + case MCIR2_MOUSE_NBITS: + scancode = data->body & 0x1fffff; + IR_dprintk(1, "mouse data 0x%06x\n", scancode); + /* Pass data to mouse buffer parser */ + ir_mce_kbd_process_mouse_data(data->idev, scancode); + break; + default: + IR_dprintk(1, "not keyboard or mouse data\n"); + goto out; + } + + data->state = STATE_INACTIVE; + input_sync(data->idev); + return 0; + } + +out: + IR_dprintk(1, "failed at state %i (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + input_sync(data->idev); + return -EINVAL; +} + +static int ir_mce_kbd_register(struct rc_dev *dev) +{ + struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; + struct input_dev *idev; + int i, ret; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + snprintf(mce_kbd->name, sizeof(mce_kbd->name), + "MCE IR Keyboard/Mouse (%s)", dev->driver_name); + strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys)); + + idev->name = mce_kbd->name; + idev->phys = mce_kbd->phys; + + /* Keyboard bits */ + set_bit(EV_KEY, idev->evbit); + set_bit(EV_REP, idev->evbit); + for (i = 0; i < sizeof(kbd_keycodes); i++) + set_bit(kbd_keycodes[i], idev->keybit); + + /* Mouse bits */ + set_bit(EV_REL, idev->evbit); + set_bit(REL_X, idev->relbit); + set_bit(REL_Y, idev->relbit); + set_bit(BTN_LEFT, idev->keybit); + set_bit(BTN_RIGHT, idev->keybit); + + /* Report scancodes too */ + set_bit(EV_MSC, idev->evbit); + set_bit(MSC_SCAN, idev->mscbit); + + setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, + (unsigned long)mce_kbd); + + input_set_drvdata(idev, mce_kbd); + +#if 0 + /* Adding this reference means two input devices are associated with + * this rc-core device, which ir-keytable doesn't cope with yet */ + idev->dev.parent = &dev->dev; +#endif + + ret = input_register_device(idev); + if (ret < 0) { + input_free_device(idev); + return -EIO; + } + + mce_kbd->idev = idev; + + return 0; +} + +static int ir_mce_kbd_unregister(struct rc_dev *dev) +{ + struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; + struct input_dev *idev = mce_kbd->idev; + + del_timer_sync(&mce_kbd->rx_timeout); + input_unregister_device(idev); + + return 0; +} + +static struct ir_raw_handler mce_kbd_handler = { + .protocols = RC_TYPE_MCE_KBD, + .decode = ir_mce_kbd_decode, + .raw_register = ir_mce_kbd_register, + .raw_unregister = ir_mce_kbd_unregister, +}; + +static int __init ir_mce_kbd_decode_init(void) +{ + ir_raw_handler_register(&mce_kbd_handler); + + printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n"); + return 0; +} + +static void __exit ir_mce_kbd_decode_exit(void) +{ + ir_raw_handler_unregister(&mce_kbd_handler); +} + +module_init(ir_mce_kbd_decode_init); +module_exit(ir_mce_kbd_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_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) load_rc6_decode(); load_jvc_decode(); load_sony_decode(); + load_mce_kbd_decode(); load_lirc_codec(); /* If needed, we may later add some init code. In this case, diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index d20168fe4c40..682009d76cdf 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -382,7 +382,7 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) /* transmit out IR pulses; what you get here is a batch of alternating * pulse/space/pulse/space lengths that we should write out completely through * the FIFO, blocking on a full FIFO */ -static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) { unsigned long flags; struct ite_dev *dev = rcdev->priv; @@ -398,9 +398,6 @@ static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) /* clear the array just in case */ memset(last_sent, 0, ARRAY_SIZE(last_sent)); - /* n comes in bytes; convert to ints */ - n /= sizeof(int); - spin_lock_irqsave(&dev->lock, flags); /* let everybody know we're now transmitting */ diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 01b69bcc8666..c3907e211d39 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -29,7 +29,7 @@ static struct rc_map_table rc6_mce[] = { { 0x800f040a, KEY_DELETE }, { 0x800f040b, KEY_ENTER }, - { 0x800f040c, KEY_POWER }, /* PC Power */ + { 0x800f040c, KEY_SLEEP }, /* Formerly PC Power */ { 0x800f040d, KEY_MEDIA }, /* Windows MCE button */ { 0x800f040e, KEY_MUTE }, { 0x800f040f, KEY_INFO }, @@ -44,7 +44,6 @@ static struct rc_map_table rc6_mce[] = { { 0x800f0416, KEY_PLAY }, { 0x800f0417, KEY_RECORD }, { 0x800f0418, KEY_PAUSE }, - { 0x800f046e, KEY_PLAYPAUSE }, { 0x800f0419, KEY_STOP }, { 0x800f041a, KEY_NEXT }, { 0x800f041b, KEY_PREVIOUS }, diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index ec972dc25790..85ff9a1ffb39 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -692,20 +692,18 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) } /* Send data out the IR blaster port(s) */ -static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct mceusb_dev *ir = dev->priv; int i, ret = 0; - int count, cmdcount = 0; + int cmdcount = 0; unsigned char *cmdbuf; /* MCE command buffer */ long signal_duration = 0; /* Singnal length in us */ struct timeval start_time, end_time; do_gettimeofday(&start_time); - count = n / sizeof(int); - - cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); + cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL); if (!cmdbuf) return -ENOMEM; @@ -774,7 +772,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) out: kfree(cmdbuf); - return ret ? ret : n; + return ret ? ret : count; } /* Sets active IR outputs -- mce devices typically have two */ diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index ce595f9ab4c7..eae05b500476 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -546,24 +546,18 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to * set TXFCONT as 0xff, until buf_count less than 0xff. */ -static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) { struct nvt_dev *nvt = dev->priv; unsigned long flags; - size_t cur_count; unsigned int i; u8 iren; int ret; spin_lock_irqsave(&nvt->tx.lock, flags); - if (n >= TX_BUF_LEN) { - nvt->tx.buf_count = cur_count = TX_BUF_LEN; - ret = TX_BUF_LEN; - } else { - nvt->tx.buf_count = cur_count = n; - ret = n; - } + ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); + nvt->tx.buf_count = (ret * sizeof(unsigned)); memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); 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 { unsigned count; unsigned wanted_bits; } rc5_sz; + struct mce_kbd_dec { + struct input_dev *idev; + struct timer_list rx_timeout; + char name[64]; + char phys[64]; + int state; + u8 header; + u32 body; + unsigned count; + unsigned wanted_bits; + } mce_kbd; struct lirc_codec { struct rc_dev *dev; struct lirc_driver *drv; @@ -182,6 +193,13 @@ void ir_raw_init(void); #define load_sony_decode() 0 #endif +/* from ir-mce_kbd-decoder.c */ +#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE +#define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") +#else +#define load_mce_kbd_decode() 0 +#endif + /* from ir-lirc-codec.c */ #ifdef CONFIG_IR_LIRC_CODEC_MODULE #define load_lirc_codec() request_module("ir-lirc-codec") diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index cc846b2619cf..efc6a514348a 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -101,21 +101,14 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) return 0; } -static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) +static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { struct loopback_dev *lodev = dev->priv; u32 rxmask; - unsigned count; unsigned total_duration = 0; unsigned i; DEFINE_IR_RAW_EVENT(rawir); - if (n == 0 || n % sizeof(int)) { - dprintk("invalid tx buffer size\n"); - return -EINVAL; - } - - count = n / sizeof(int); for (i = 0; i < count; i++) total_duration += abs(txbuf[i]); @@ -142,7 +135,7 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n) for (i = 0; i < count; i++) { rawir.pulse = i % 2 ? false : true; - rawir.duration = abs(txbuf[i]) * 1000; + rawir.duration = txbuf[i] * 1000; if (rawir.duration) ir_raw_event_store_with_filter(dev, &rawir); } @@ -158,7 +151,7 @@ out: /* Lirc expects this function to take as long as the total duration */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(usecs_to_jiffies(total_duration)); - return n; + return count; } static void loop_set_idle(struct rc_dev *dev, bool enable) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 3186ac7c2c10..51a23f48bc7d 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -735,6 +735,7 @@ static struct { { RC_TYPE_JVC, "jvc" }, { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, + { RC_TYPE_MCE_KBD, "mce_kbd" }, { RC_TYPE_LIRC, "lirc" }, { RC_TYPE_OTHER, "other" }, }; @@ -1099,7 +1100,6 @@ int rc_register_device(struct rc_dev *dev) if (rc < 0) goto out_input; } - mutex_unlock(&dev->lock); if (dev->change_protocol) { rc = dev->change_protocol(dev, rc_map->rc_type); @@ -1107,6 +1107,8 @@ int rc_register_device(struct rc_dev *dev) goto out_raw; } + mutex_unlock(&dev->lock); + IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", dev->devno, dev->driver_name ? dev->driver_name : "unknown", diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 5147767ccb78..a16604477917 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -205,6 +205,7 @@ struct redrat3_dev { /* rx signal timeout timer */ struct timer_list rx_timeout; + u32 hw_timeout; /* Is the device currently receiving? */ bool recv_in_progress; @@ -414,20 +415,10 @@ static u32 redrat3_us_to_len(u32 microsec) } -/* timer callback to send long trailing space on receive timeout */ +/* timer callback to send reset event */ static void redrat3_rx_timeout(unsigned long data) { struct redrat3_dev *rr3 = (struct redrat3_dev *)data; - DEFINE_IR_RAW_EVENT(rawir); - - rawir.pulse = false; - rawir.duration = rr3->rc->timeout; - rr3_dbg(rr3->dev, "storing trailing space with duration %d\n", - rawir.duration); - ir_raw_event_store_with_filter(rr3->rc, &rawir); - - rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n"); - ir_raw_event_handle(rr3->rc); rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n"); ir_raw_event_reset(rr3->rc); @@ -438,7 +429,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) DEFINE_IR_RAW_EVENT(rawir); struct redrat3_signal_header header; struct device *dev; - int i; + int i, trailer = 0; unsigned long delay; u32 mod_freq, single_len; u16 *len_vals; @@ -464,7 +455,8 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) if (!(header.length >= RR3_HEADER_LENGTH)) dev_warn(dev, "read returned less than rr3 header len\n"); - delay = usecs_to_jiffies(rr3->rc->timeout / 1000); + /* Make sure we reset the IR kfifo after a bit of inactivity */ + delay = usecs_to_jiffies(rr3->hw_timeout); mod_timer(&rr3->rx_timeout, jiffies + delay); memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32)); @@ -506,9 +498,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) u16 val = len_vals[data_vals[i]]; single_len = redrat3_len_to_us((u32)be16_to_cpu(val)); - /* cap the value to IR_MAX_DURATION */ - single_len &= IR_MAX_DURATION; - /* we should always get pulse/space/pulse/space samples */ if (i % 2) rawir.pulse = false; @@ -516,6 +505,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) rawir.pulse = true; rawir.duration = US_TO_NS(single_len); + /* Save initial pulse length to fudge trailer */ + if (i == 0) + trailer = rawir.duration; + /* cap the value to IR_MAX_DURATION */ + rawir.duration &= IR_MAX_DURATION; + rr3_dbg(dev, "storing %s with duration %d (i: %d)\n", rawir.pulse ? "pulse" : "space", rawir.duration, i); ir_raw_event_store_with_filter(rr3->rc, &rawir); @@ -525,7 +520,10 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) if (i % 2) { rawir.pulse = false; /* this duration is made up, and may not be ideal... */ - rawir.duration = rr3->rc->timeout / 2; + if (trailer < US_TO_NS(1000)) + rawir.duration = US_TO_NS(2800); + else + rawir.duration = trailer; rr3_dbg(dev, "storing trailing space with duration %d\n", rawir.duration); ir_raw_event_store_with_filter(rr3->rc, &rawir); @@ -629,36 +627,31 @@ static inline void redrat3_delete(struct redrat3_dev *rr3, kfree(rr3); } -static u32 redrat3_get_timeout(struct device *dev, - struct rc_dev *rc, struct usb_device *udev) +static u32 redrat3_get_timeout(struct redrat3_dev *rr3) { u32 *tmp; - u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */ + u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */ int len, ret, pipe; len = sizeof(*tmp); tmp = kzalloc(len, GFP_KERNEL); if (!tmp) { - dev_warn(dev, "Memory allocation faillure\n"); + dev_warn(rr3->dev, "Memory allocation faillure\n"); return timeout; } - pipe = usb_rcvctrlpipe(udev, 0); - ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM, + pipe = usb_rcvctrlpipe(rr3->udev, 0); + ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); if (ret != len) { - dev_warn(dev, "Failed to read timeout from hardware\n"); + dev_warn(rr3->dev, "Failed to read timeout from hardware\n"); return timeout; } - timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp))); - if (timeout < rc->min_timeout) - timeout = rc->min_timeout; - else if (timeout > rc->max_timeout) - timeout = rc->max_timeout; + timeout = redrat3_len_to_us(be32_to_cpu(*tmp)); - rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000)); + rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); return timeout; } @@ -1110,9 +1103,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protos = RC_TYPE_ALL; - rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); - rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); - rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev); + rc->timeout = US_TO_NS(2750); rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; rc->driver_name = DRIVER_NAME; @@ -1186,7 +1177,7 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf, rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); if (rr3 == NULL) { dev_err(dev, "Memory allocation failure\n"); - goto error; + goto no_endpoints; } rr3->dev = &intf->dev; @@ -1242,6 +1233,9 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf, if (retval < 0) goto error; + /* store current hardware timeout, in us, will use for kfifo resets */ + rr3->hw_timeout = redrat3_get_timeout(rr3); + /* default.. will get overridden by any sends with a freq defined */ rr3->carrier = 38000; @@ -1280,6 +1274,7 @@ static void __devexit redrat3_dev_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); rc_unregister_device(rr3->rc); + del_timer_sync(&rr3->rx_timeout); redrat3_delete(rr3, udev); rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n"); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 5d06b899e859..bec8abc965f7 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -6,8 +6,8 @@ * could probably support others (Winbond WEC102X, NatSemi, etc) * with minor modifications. * - * Original Author: David Härdeman <david@hardeman.nu> - * Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu> + * Original Author: David Härdeman <david@hardeman.nu> + * Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu> * * Dedicated to my daughter Matilda, without whose loving attention this * driver would have been finished in half the time and with a fraction @@ -577,16 +577,12 @@ wbcir_txmask(struct rc_dev *dev, u32 mask) } static int -wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize) +wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) { struct wbcir_data *data = dev->priv; - u32 count; unsigned i; unsigned long flags; - /* bufsize has been sanity checked by the caller */ - count = bufsize / sizeof(int); - /* Not sure if this is possible, but better safe than sorry */ spin_lock_irqsave(&data->spinlock, flags); if (data->txstate != WBCIR_TXSTATE_INACTIVE) { @@ -876,18 +872,8 @@ wbcir_init_hw(struct wbcir_data *data) /* prescaler 1.0, tx/rx fifo lvl 16 */ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - /* Set baud divisor to generate one byte per bit/cell */ - switch (protocol) { - case IR_PROTOCOL_RC5: - outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_RC6: - outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL); - break; - case IR_PROTOCOL_NEC: - outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL); - break; - } + /* Set baud divisor to sample every 10 us */ + outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL); outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); /* Set CEIR mode */ @@ -896,9 +882,9 @@ wbcir_init_hw(struct wbcir_data *data) inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - /* Disable RX demod, run-length encoding/decoding, set freq span */ + /* Disable RX demod, enable run-length enc/dec, set freq span */ wbcir_select_bank(data, WBCIR_BANK_7); - outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG); + outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG); /* Disable timer */ wbcir_select_bank(data, WBCIR_BANK_4); |