diff options
Diffstat (limited to 'drivers/media/rc')
47 files changed, 1222 insertions, 657 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 8fbd377e6311..5e626af8e313 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -84,18 +84,6 @@ config IR_SONY_DECODER Enable this option if you have an infrared remote control which uses the Sony protocol, and you need software decoding support. -config IR_RC5_SZ_DECODER - tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with RC-5 (streamzap) protocol, - and if the IR is decoded in software. (The Streamzap PC Remote - uses an IR protocol that is almost standard RC-5, but not quite, - as it uses an additional bit). - config IR_SANYO_DECODER tristate "Enable IR raw decoder for the Sanyo protocol" depends on RC_CORE @@ -125,6 +113,16 @@ config IR_MCE_KBD_DECODER 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_XMP_DECODER + tristate "Enable IR raw decoder for the XMP protocol" + depends on RC_CORE + select BITREVERSE + default y + + ---help--- + Enable this option if you have IR with XMP protocol, and + if the IR is decoded in software endif #RC_DECODERS menuconfig RC_DEVICES @@ -343,4 +341,14 @@ config RC_ST If you're not sure, select N here. +config IR_SUNXI + tristate "SUNXI IR remote control" + depends on RC_CORE + depends on ARCH_SUNXI + ---help--- + Say Y if you want to use sunXi internal IR Controller + + To compile this driver as a module, choose M here: the module will + be called sunxi-ir. + endif #RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index f8b54ff46601..9f9843a1af5f 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -1,4 +1,4 @@ -rc-core-objs := rc-main.o ir-raw.o +rc-core-objs := rc-main.o rc-ir-raw.o obj-y += keymaps/ @@ -9,11 +9,11 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o 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_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o +obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o # stand-alone IR receivers/transmitters obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o @@ -32,4 +32,5 @@ obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o obj-$(CONFIG_RC_ST) += st_rc.o +obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o obj-$(CONFIG_IR_IMG) += img-ir/ diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 2df7c5516013..a35631891cc0 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -279,46 +279,42 @@ struct ati_remote { /* "Kinds" of messages sent from the hardware to the driver. */ #define KIND_END 0 -#define KIND_LITERAL 1 /* Simply pass to input system */ +#define KIND_LITERAL 1 /* Simply pass to input system as EV_KEY */ #define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ -#define KIND_LU 3 /* Directional keypad diagonals - left up, */ -#define KIND_RU 4 /* right up, */ -#define KIND_LD 5 /* left down, */ -#define KIND_RD 6 /* right down */ -#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ +#define KIND_ACCEL 3 /* Translate to EV_REL mouse-move events */ /* Translation table from hardware messages to input events. */ static const struct { - short kind; - unsigned char data; - int type; - unsigned int code; - int value; + unsigned char kind; + unsigned char data; /* Raw key code from remote */ + unsigned short code; /* Input layer translation */ } ati_remote_tbl[] = { - /* Directional control pad axes */ - {KIND_ACCEL, 0x70, EV_REL, REL_X, -1}, /* left */ - {KIND_ACCEL, 0x71, EV_REL, REL_X, 1}, /* right */ - {KIND_ACCEL, 0x72, EV_REL, REL_Y, -1}, /* up */ - {KIND_ACCEL, 0x73, EV_REL, REL_Y, 1}, /* down */ - /* Directional control pad diagonals */ - {KIND_LU, 0x74, EV_REL, 0, 0}, /* left up */ - {KIND_RU, 0x75, EV_REL, 0, 0}, /* right up */ - {KIND_LD, 0x77, EV_REL, 0, 0}, /* left down */ - {KIND_RD, 0x76, EV_REL, 0, 0}, /* right down */ + /* Directional control pad axes. Code is xxyy */ + {KIND_ACCEL, 0x70, 0xff00}, /* left */ + {KIND_ACCEL, 0x71, 0x0100}, /* right */ + {KIND_ACCEL, 0x72, 0x00ff}, /* up */ + {KIND_ACCEL, 0x73, 0x0001}, /* down */ - /* "Mouse button" buttons */ - {KIND_LITERAL, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ - {KIND_LITERAL, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ - {KIND_LITERAL, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ - {KIND_LITERAL, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + /* Directional control pad diagonals */ + {KIND_ACCEL, 0x74, 0xffff}, /* left up */ + {KIND_ACCEL, 0x75, 0x01ff}, /* right up */ + {KIND_ACCEL, 0x77, 0xff01}, /* left down */ + {KIND_ACCEL, 0x76, 0x0101}, /* right down */ + + /* "Mouse button" buttons. The code below uses the fact that the + * lsbit of the raw code is a down/up indicator. */ + {KIND_LITERAL, 0x78, BTN_LEFT}, /* left btn down */ + {KIND_LITERAL, 0x79, BTN_LEFT}, /* left btn up */ + {KIND_LITERAL, 0x7c, BTN_RIGHT},/* right btn down */ + {KIND_LITERAL, 0x7d, BTN_RIGHT},/* right btn up */ /* Artificial "doubleclick" events are generated by the hardware. * They are mapped to the "side" and "extra" mouse buttons here. */ - {KIND_FILTERED, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ - {KIND_FILTERED, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + {KIND_FILTERED, 0x7a, BTN_SIDE}, /* left dblclick */ + {KIND_FILTERED, 0x7e, BTN_EXTRA},/* right dblclick */ /* Non-mouse events are handled by rc-core */ - {KIND_END, 0x00, EV_MAX + 1, 0, 0} + {KIND_END, 0x00, 0} }; /* @@ -493,7 +489,6 @@ static void ati_remote_input_report(struct urb *urb) unsigned char *data= ati_remote->inbuf; struct input_dev *dev = ati_remote->idev; int index = -1; - int acc; int remote_num; unsigned char scancode; u32 wheel_keycode = KEY_RESERVED; @@ -507,8 +502,9 @@ static void ati_remote_input_report(struct urb *urb) */ /* Deal with strange looking inputs */ - if ( (urb->actual_length != 4) || (data[0] != 0x14) || - ((data[3] & 0x0f) != 0x00) ) { + if ( urb->actual_length != 4 || data[0] != 0x14 || + data[1] != (unsigned char)(data[2] + data[3] + 0xD5) || + (data[3] & 0x0f) != 0x00) { ati_remote_dump(&urb->dev->dev, data, urb->actual_length); return; } @@ -524,9 +520,9 @@ static void ati_remote_input_report(struct urb *urb) remote_num = (data[3] >> 4) & 0x0f; if (channel_mask & (1 << (remote_num + 1))) { dbginfo(&ati_remote->interface->dev, - "Masked input from channel 0x%02x: data %02x,%02x, " + "Masked input from channel 0x%02x: data %02x, " "mask= 0x%02lx\n", - remote_num, data[1], data[2], channel_mask); + remote_num, data[2], channel_mask); return; } @@ -566,16 +562,16 @@ static void ati_remote_input_report(struct urb *urb) } if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) { - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, - ati_remote_tbl[index].value); - input_sync(dev); + /* + * The lsbit of the raw key code is a down/up flag. + * Invert it to match the input layer's conventions. + */ + input_event(dev, EV_KEY, ati_remote_tbl[index].code, + !(data[2] & 1)); ati_remote->old_jiffies = jiffies; - return; - } - if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) { + } else if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) { unsigned long now = jiffies; /* Filter duplicate events which happen "too close" together. */ @@ -588,12 +584,11 @@ static void ati_remote_input_report(struct urb *urb) ati_remote->first_jiffies = now; } - ati_remote->old_data = data[2]; ati_remote->old_jiffies = now; - /* Ensure we skip at least the 4 first duplicate events (generated - * by a single keypress), and continue skipping until repeat_delay - * msecs have passed + /* Ensure we skip at least the 4 first duplicate events + * (generated by a single keypress), and continue skipping + * until repeat_delay msecs have passed. */ if (ati_remote->repeat_count > 0 && (ati_remote->repeat_count < 5 || @@ -601,7 +596,10 @@ static void ati_remote_input_report(struct urb *urb) msecs_to_jiffies(repeat_delay)))) return; - if (index < 0) { + if (index >= 0) { + input_event(dev, EV_KEY, ati_remote_tbl[index].code, 1); + input_event(dev, EV_KEY, ati_remote_tbl[index].code, 0); + } else { /* Not a mouse event, hand it to rc-core. */ int count = 1; @@ -622,61 +620,37 @@ static void ati_remote_input_report(struct urb *urb) * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, scancode, - data[2]); + rc_keydown_notimeout(ati_remote->rdev, RC_TYPE_OTHER, + scancode, data[2]); rc_keyup(ati_remote->rdev); } - return; + goto nosync; } - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, 1); - input_sync(dev); - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, 0); - input_sync(dev); - - } else { + } else if (ati_remote_tbl[index].kind == KIND_ACCEL) { + signed char dx = ati_remote_tbl[index].code >> 8; + signed char dy = ati_remote_tbl[index].code & 255; /* * Other event kinds are from the directional control pad, and * have an acceleration factor applied to them. Without this * acceleration, the control pad is mostly unusable. */ - acc = ati_remote_compute_accel(ati_remote); - - switch (ati_remote_tbl[index].kind) { - case KIND_ACCEL: - input_event(dev, ati_remote_tbl[index].type, - ati_remote_tbl[index].code, - ati_remote_tbl[index].value * acc); - break; - case KIND_LU: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_RU: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, -acc); - break; - case KIND_LD: - input_report_rel(dev, REL_X, -acc); - input_report_rel(dev, REL_Y, acc); - break; - case KIND_RD: - input_report_rel(dev, REL_X, acc); - input_report_rel(dev, REL_Y, acc); - break; - default: - dev_dbg(&ati_remote->interface->dev, - "ati_remote kind=%d\n", - ati_remote_tbl[index].kind); - } - input_sync(dev); - + int acc = ati_remote_compute_accel(ati_remote); + if (dx) + input_report_rel(dev, REL_X, dx * acc); + if (dy) + input_report_rel(dev, REL_Y, dy * acc); ati_remote->old_jiffies = jiffies; - ati_remote->old_data = data[2]; + + } else { + dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + ati_remote_tbl[index].kind); + return; } + input_sync(dev); +nosync: + ati_remote->old_data = data[2]; } /* @@ -763,8 +737,9 @@ static void ati_remote_input_init(struct ati_remote *ati_remote) BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) - if (ati_remote_tbl[i].type == EV_KEY) - set_bit(ati_remote_tbl[i].code, idev->keybit); + if (ati_remote_tbl[i].kind == KIND_LITERAL || + ati_remote_tbl[i].kind == KIND_FILTERED) + __set_bit(ati_remote_tbl[i].code, idev->keybit); input_set_drvdata(idev, ati_remote); @@ -784,7 +759,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->priv = ati_remote; rdev->driver_type = RC_DRIVER_SCANCODE; - rc_set_allowed_protocols(rdev, RC_BIT_OTHER); + rdev->allowed_protocols = RC_BIT_OTHER; rdev->driver_name = "ati_remote"; rdev->open = ati_remote_rc_open; diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index fc9d23f2ed3f..d16d9b496b92 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) learning_mode_force = false; rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; rdev->priv = dev; rdev->open = ene_open; rdev->close = ene_close; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 46b66e59438f..f0a1f7d31ee6 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* Set up the rc device */ rdev->priv = fintek; rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; rdev->open = fintek_open; rdev->close = fintek_close; rdev->input_name = FINTEK_DESCRIPTION; @@ -686,12 +686,12 @@ static struct pnp_driver fintek_driver = { .shutdown = fintek_shutdown, }; -static int fintek_init(void) +static int __init fintek_init(void) { return pnp_register_driver(&fintek_driver); } -static void fintek_exit(void) +static void __exit fintek_exit(void) { pnp_unregister_driver(&fintek_driver); } diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 29b5f89813b4..59853085bc88 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -145,9 +145,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->dev.parent = &pdev->dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; if (pdata->allowed_protos) - rc_set_allowed_protocols(rcdev, pdata->allowed_protos); + rcdev->allowed_protocols = pdata->allowed_protos; else - rc_set_allowed_protocols(rcdev, RC_BIT_ALL); + rcdev->allowed_protocols = RC_BIT_ALL; rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 627ddfd61980..ee60e17fba05 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -495,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf, usb_to_input_id(ir->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rc, RC_BIT_ALL); + rc->allowed_protocols = RC_BIT_ALL; rc->priv = ir; rc->open = iguanair_open; rc->close = iguanair_close; diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index 6b7834834fb8..a0cac2f09109 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -3,6 +3,11 @@ * * Copyright 2010-2014 Imagination Technologies Ltd. * + * 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; either version 2 of the License, or (at your + * option) any later version. + * * This contains core img-ir code for setting up the driver. The two interfaces * (raw and hardware decode) are handled separately. */ diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 0127dd257a57..bfb282a714e8 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -3,6 +3,11 @@ * * Copyright 2010-2014 Imagination Technologies Ltd. * + * 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; either version 2 of the License, or (at your + * option) any later version. + * * This ties into the input subsystem using the RC-core. Protocol support is * provided in separate modules which provide the parameters and scancode * translation functions to set up the hardware decoder and interpret the @@ -507,7 +512,7 @@ unlock: static int img_ir_set_normal_filter(struct rc_dev *dev, struct rc_scancode_filter *sc_filter) { - return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter); + return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter); } static int img_ir_set_wakeup_filter(struct rc_dev *dev, @@ -551,8 +556,8 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, hw->mode = IMG_IR_M_NORMAL; /* clear the wakeup scancode filter */ - rdev->scancode_filters[RC_FILTER_WAKEUP].data = 0; - rdev->scancode_filters[RC_FILTER_WAKEUP].mask = 0; + rdev->scancode_wakeup_filter.data = 0; + rdev->scancode_wakeup_filter.mask = 0; /* clear raw filters */ _img_ir_set_filter(priv, NULL); @@ -656,8 +661,8 @@ success: wakeup_protocols = *ir_type; if (!hw->decoder || !hw->decoder->filter) wakeup_protocols = 0; - rc_set_allowed_wakeup_protocols(rdev, wakeup_protocols); - rc_set_enabled_wakeup_protocols(rdev, wakeup_protocols); + rdev->allowed_wakeup_protocols = wakeup_protocols; + rdev->enabled_wakeup_protocols = wakeup_protocols; return 0; } @@ -671,9 +676,9 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto) spin_unlock_irq(&rdev->rc_map.lock); mutex_lock(&rdev->lock); - rc_set_enabled_protocols(rdev, proto); - rc_set_allowed_wakeup_protocols(rdev, proto); - rc_set_enabled_wakeup_protocols(rdev, proto); + rdev->enabled_protocols = proto; + rdev->allowed_wakeup_protocols = proto; + rdev->enabled_wakeup_protocols = proto; mutex_unlock(&rdev->lock); } @@ -790,9 +795,11 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) struct img_ir_priv_hw *hw = &priv->hw; const struct img_ir_decoder *dec = hw->decoder; int ret = IMG_IR_SCANCODE; - int scancode; + u32 scancode; + enum rc_type protocol = RC_TYPE_UNKNOWN; + if (dec->scancode) - ret = dec->scancode(len, raw, &scancode, hw->enabled_protocols); + ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols); else if (len >= 32) scancode = (u32)raw; else if (len < 32) @@ -801,7 +808,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) len, (unsigned long long)raw); if (ret == IMG_IR_SCANCODE) { dev_dbg(priv->dev, "decoded scan code %#x\n", scancode); - rc_keydown(hw->rdev, scancode, 0); + rc_keydown(hw->rdev, protocol, scancode, 0); img_ir_end_repeat(priv); } else if (ret == IMG_IR_REPEATCODE) { if (hw->mode == IMG_IR_M_REPEATING) { @@ -996,7 +1003,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv) } rdev->priv = priv; rdev->map_name = RC_MAP_EMPTY; - rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv)); + rdev->allowed_protocols = img_ir_allowed_protos(priv); rdev->input_name = "IMG Infrared Decoder"; rdev->s_filter = img_ir_set_normal_filter; rdev->s_wakeup_filter = img_ir_set_wakeup_filter; diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 6c9a94a81190..3e40ce87b898 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -2,6 +2,11 @@ * ImgTec IR Hardware Decoder found in PowerDown Controller. * * Copyright 2010-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #ifndef _IMG_IR_HW_H_ @@ -157,7 +162,8 @@ struct img_ir_decoder { struct img_ir_control control; /* scancode logic */ - int (*scancode)(int len, u64 raw, int *scancode, u64 protocols); + int (*scancode)(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols); int (*filter)(const struct rc_scancode_filter *in, struct img_ir_filter *out, u64 protocols); }; diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c index 10209d200efb..a60dda8bf706 100644 --- a/drivers/media/rc/img-ir/img-ir-jvc.c +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -2,12 +2,18 @@ * ImgTec IR Decoder setup for JVC protocol. * * Copyright 2012-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #include "img-ir-hw.h" /* Convert JVC data to a scancode */ -static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols) +static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols) { unsigned int cust, data; @@ -17,6 +23,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols) cust = (raw >> 0) & 0xff; data = (raw >> 8) & 0xff; + *protocol = RC_TYPE_JVC; *scancode = cust << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 751d9d945269..739897549b5b 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -2,13 +2,19 @@ * ImgTec IR Decoder setup for NEC protocol. * * Copyright 2010-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #include "img-ir-hw.h" #include <linux/bitrev.h> /* Convert NEC data to a scancode */ -static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols) +static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -40,6 +46,7 @@ static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols) *scancode = addr << 8 | data; } + *protocol = RC_TYPE_NEC; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c index cfb01d9e571a..33f37ed87ad2 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.c +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -3,6 +3,11 @@ * * Copyright 2010-2014 Imagination Technologies Ltd. * + * 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; either version 2 of the License, or (at your + * option) any later version. + * * This ties into the input subsystem using the RC-core in raw mode. Raw IR * signal edges are reported and decoded by generic software decoders. */ diff --git a/drivers/media/rc/img-ir/img-ir-raw.h b/drivers/media/rc/img-ir/img-ir-raw.h index 9802ffd51b9a..4c9b7676e6fc 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.h +++ b/drivers/media/rc/img-ir/img-ir-raw.h @@ -2,6 +2,11 @@ * ImgTec IR Raw Decoder found in PowerDown Controller. * * Copyright 2010-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #ifndef _IMG_IR_RAW_H_ diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c index c2c763e08a41..6b0653ecdf5a 100644 --- a/drivers/media/rc/img-ir/img-ir-sanyo.c +++ b/drivers/media/rc/img-ir/img-ir-sanyo.c @@ -3,6 +3,11 @@ * * Copyright 2012-2014 Imagination Technologies Ltd. * + * 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; either version 2 of the License, or (at your + * option) any later version. + * * From ir-sanyo-decoder.c: * * This protocol uses the NEC protocol timings. However, data is formatted as: @@ -18,7 +23,8 @@ #include "img-ir-hw.h" /* Convert Sanyo data to a scancode */ -static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols) +static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols) { unsigned int addr, addr_inv, data, data_inv; /* a repeat code has no data */ @@ -38,6 +44,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols) return -EINVAL; /* Normal Sanyo */ + *protocol = RC_TYPE_SANYO; *scancode = addr << 8 | data; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c index 3397cc5a6794..3300a38802ac 100644 --- a/drivers/media/rc/img-ir/img-ir-sharp.c +++ b/drivers/media/rc/img-ir/img-ir-sharp.c @@ -2,12 +2,18 @@ * ImgTec IR Decoder setup for Sharp protocol. * * Copyright 2012-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #include "img-ir-hw.h" /* Convert Sharp data to a scancode */ -static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols) +static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols) { unsigned int addr, cmd, exp, chk; @@ -26,6 +32,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols) /* probably the second half of the message */ return -EINVAL; + *protocol = RC_TYPE_SHARP; *scancode = addr << 8 | cmd; return IMG_IR_SCANCODE; } diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c index 993409a51a71..3a0f17b0752c 100644 --- a/drivers/media/rc/img-ir/img-ir-sony.c +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -2,40 +2,49 @@ * ImgTec IR Decoder setup for Sony (SIRC) protocol. * * Copyright 2012-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #include "img-ir-hw.h" /* Convert Sony data to a scancode */ -static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols) +static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol, + u32 *scancode, u64 enabled_protocols) { unsigned int dev, subdev, func; switch (len) { case 12: - if (!(protocols & RC_BIT_SONY12)) + if (!(enabled_protocols & RC_BIT_SONY12)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ subdev = 0; + *protocol = RC_TYPE_SONY12; break; case 15: - if (!(protocols & RC_BIT_SONY15)) + if (!(enabled_protocols & RC_BIT_SONY15)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0xff; /* next 8 bits */ subdev = 0; + *protocol = RC_TYPE_SONY15; break; case 20: - if (!(protocols & RC_BIT_SONY20)) + if (!(enabled_protocols & RC_BIT_SONY20)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ raw >>= 5; subdev = raw & 0xff; /* next 8 bits */ + *protocol = RC_TYPE_SONY20; break; default: return -EINVAL; diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h index afb189394af9..2ddf56083182 100644 --- a/drivers/media/rc/img-ir/img-ir.h +++ b/drivers/media/rc/img-ir/img-ir.h @@ -2,6 +2,11 @@ * ImgTec IR Decoder found in PowerDown Controller. * * Copyright 2010-2014 Imagination Technologies Ltd. + * + * 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; either version 2 of the License, or (at your + * option) any later version. */ #ifndef _IMG_IR_H_ diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 6f24e77b1488..7115e68ba697 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -78,11 +78,11 @@ static int display_open(struct inode *inode, struct file *file); static int display_close(struct inode *inode, struct file *file); /* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /* LCD file_operations override function prototypes */ -static ssize_t lcd_write(struct file *file, const char *buf, +static ssize_t lcd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /*** G L O B A L S ***/ @@ -825,7 +825,7 @@ static struct attribute_group imon_rf_attr_group = { * than 32 bytes are provided spaces will be appended to * generate a full screen. */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int i; @@ -912,7 +912,7 @@ exit: * display whatever diacritics you need, and so on), but it's also * a lot more complicated than most LCDs... */ -static ssize_t lcd_write(struct file *file, const char *buf, +static ssize_t lcd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int retval = 0; @@ -1017,7 +1017,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (*rc_type && !rc_protocols_allowed(rc, *rc_type)) + if (*rc_type && !(*rc_type & rc->allowed_protocols)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); @@ -1579,7 +1579,10 @@ static void imon_incoming_packet(struct imon_context *ictx, if (press_type == 0) rc_keyup(ictx->rdev); else { - rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle); + if (ictx->rc_type == RC_BIT_RC6_MCE) + rc_keydown(ictx->rdev, + ictx->rc_type == RC_BIT_RC6_MCE ? RC_TYPE_RC6_MCE : RC_TYPE_OTHER, + ictx->rc_scancode, ictx->rc_toggle); spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = ictx->kc; spin_unlock_irqrestore(&ictx->kc_lock, flags); @@ -1867,8 +1870,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->priv = ictx; rdev->driver_type = RC_DRIVER_SCANCODE; - /* iMON PAD or MCE */ - rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE); + rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1881,7 +1883,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); - rc_set_allowed_protocols(rdev, ictx->rc_type); + rdev->allowed_protocols = ictx->rc_type; } imon_set_display_type(ictx); diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 4ea62a1dcfda..30bcf188d377 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!rc_protocols_enabled(dev, RC_BIT_JVC)) + if (!(dev->enabled_protocols & RC_BIT_JVC)) return 0; if (!is_timing_event(ev)) { @@ -140,7 +140,7 @@ again: scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | (bitrev8((data->bits >> 0) & 0xff) << 0); IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); - rc_keydown(dev, scancode, data->toggle); + rc_keydown(dev, RC_TYPE_JVC, scancode, data->toggle); data->first = false; data->old_bits = data->bits; } else if (data->bits == data->old_bits) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index d731da6c414d..ed2c8a1ed8ca 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!rc_protocols_enabled(dev, RC_BIT_LIRC)) + if (!(dev->enabled_protocols & RC_BIT_LIRC)) return 0; if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 0c55f794c8cf..9f3c9b59f30c 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!rc_protocols_enabled(dev, RC_BIT_MCE_KBD)) + if (!(dev->enabled_protocols & RC_BIT_MCE_KBD)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 35c42e5e270b..7b81fec0820f 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!rc_protocols_enabled(dev, RC_BIT_NEC)) + if (!(dev->enabled_protocols & RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { @@ -189,7 +189,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if (data->is_nec_x) data->necx_repeat = true; - rc_keydown(dev, scancode, 0); + rc_keydown(dev, RC_TYPE_NEC, scancode, 0); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 4295d9b250c8..2ef763928ca4 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -1,6 +1,7 @@ -/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol +/* ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols * * Copyright (C) 2010 by Mauro Carvalho Chehab + * Copyright (C) 2010 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 @@ -13,23 +14,22 @@ */ /* - * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols. - * There are other variants that use a different number of bits. - * This is currently unsupported. - * It considers a carrier of 36 kHz, with a total of 14/20 bits, where - * the first two bits are start bits, and a third one is a filing bit + * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol + * and 20 bit RC5x protocol. */ #include "rc-core-priv.h" #include <linux/module.h> #define RC5_NBITS 14 +#define RC5_SZ_NBITS 15 #define RC5X_NBITS 20 #define CHECK_RC5X_NBITS 8 #define RC5_UNIT 888888 /* ns */ #define RC5_BIT_START (1 * RC5_UNIT) #define RC5_BIT_END (1 * RC5_UNIT) #define RC5X_SPACE (4 * RC5_UNIT) +#define RC5_TRAILER (10 * RC5_UNIT) /* In reality, approx 100 */ enum rc5_state { STATE_INACTIVE, @@ -51,8 +51,9 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) struct rc5_dec *data = &dev->raw->rc5; u8 toggle; u32 scancode; + enum rc_type protocol; - if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X)) + if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) return 0; if (!is_timing_event(ev)) { @@ -65,7 +66,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) goto out; again: - IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n", + IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n", data->state, TO_US(ev.duration), TO_STR(ev.pulse)); if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) @@ -79,12 +80,15 @@ again: data->state = STATE_BIT_START; data->count = 1; - /* We just need enough bits to get to STATE_CHECK_RC5X */ - data->wanted_bits = RC5X_NBITS; decrease_duration(&ev, RC5_BIT_START); goto again; case STATE_BIT_START: + if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) { + data->state = STATE_FINISHED; + goto again; + } + if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) break; @@ -99,9 +103,7 @@ again: if (!is_transition(&ev, &dev->raw->prev_ev)) break; - if (data->count == data->wanted_bits) - data->state = STATE_FINISHED; - else if (data->count == CHECK_RC5X_NBITS) + if (data->count == CHECK_RC5X_NBITS) data->state = STATE_CHECK_RC5X; else data->state = STATE_BIT_START; @@ -111,13 +113,10 @@ again: case STATE_CHECK_RC5X: if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) { - /* RC5X */ - data->wanted_bits = RC5X_NBITS; + data->is_rc5x = true; decrease_duration(&ev, RC5X_SPACE); - } else { - /* RC5 */ - data->wanted_bits = RC5_NBITS; - } + } else + data->is_rc5x = false; data->state = STATE_BIT_START; goto again; @@ -125,10 +124,10 @@ again: if (ev.pulse) break; - if (data->wanted_bits == RC5X_NBITS) { + if (data->is_rc5x && data->count == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!rc_protocols_enabled(dev, RC_BIT_RC5X)) { + if (!(dev->enabled_protocols & RC_BIT_RC5X)) { data->state = STATE_INACTIVE; return 0; } @@ -138,14 +137,12 @@ again: toggle = (data->bits & 0x20000) ? 1 : 0; command += (data->bits & 0x01000) ? 0 : 0x40; scancode = system << 16 | command << 8 | xdata; + protocol = RC_TYPE_RC5X; - IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", - scancode, toggle); - - } else { + } else if (!data->is_rc5x && data->count == RC5_NBITS) { /* RC5 */ u8 command, system; - if (!rc_protocols_enabled(dev, RC_BIT_RC5)) { + if (!(dev->enabled_protocols & RC_BIT_RC5)) { data->state = STATE_INACTIVE; return 0; } @@ -154,25 +151,41 @@ again: toggle = (data->bits & 0x00800) ? 1 : 0; command += (data->bits & 0x01000) ? 0 : 0x40; scancode = system << 8 | command; + protocol = RC_TYPE_RC5; - IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", - scancode, toggle); - } + } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) { + /* RC5 StreamZap */ + u8 command, system; + if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) { + data->state = STATE_INACTIVE; + return 0; + } + command = (data->bits & 0x0003F) >> 0; + system = (data->bits & 0x02FC0) >> 6; + toggle = (data->bits & 0x01000) ? 1 : 0; + scancode = system << 6 | command; + protocol = RC_TYPE_RC5_SZ; - rc_keydown(dev, scancode, toggle); + } else + break; + + IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n", + scancode, protocol, toggle); + + rc_keydown(dev, protocol, scancode, toggle); data->state = STATE_INACTIVE; return 0; } out: - IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } static struct ir_raw_handler rc5_handler = { - .protocols = RC_BIT_RC5 | RC_BIT_RC5X, + .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ, .decode = ir_rc5_decode, }; @@ -180,7 +193,7 @@ static int __init ir_rc5_decode_init(void) { ir_raw_handler_register(&rc5_handler); - printk(KERN_INFO "IR RC5(x) protocol handler initialized\n"); + printk(KERN_INFO "IR RC5(x/sz) protocol handler initialized\n"); return 0; } @@ -193,6 +206,6 @@ module_init(ir_rc5_decode_init); module_exit(ir_rc5_decode_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_AUTHOR("Mauro Carvalho Chehab and Jarod Wilson"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("RC5(x) IR protocol decoder"); +MODULE_DESCRIPTION("RC5(x/sz) IR protocol decoder"); diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c deleted file mode 100644 index dc18b7434db8..000000000000 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ /dev/null @@ -1,154 +0,0 @@ -/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol - * - * Copyright (C) 2010 by Mauro Carvalho Chehab - * Copyright (C) 2010 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. - */ - -/* - * This code handles the 15 bit RC5-ish protocol used by the Streamzap - * PC Remote. - * It considers a carrier of 36 kHz, with a total of 15 bits, where - * the first two bits are start bits, and a third one is a filing bit - */ - -#include "rc-core-priv.h" -#include <linux/module.h> - -#define RC5_SZ_NBITS 15 -#define RC5_UNIT 888888 /* ns */ -#define RC5_BIT_START (1 * RC5_UNIT) -#define RC5_BIT_END (1 * RC5_UNIT) - -enum rc5_sz_state { - STATE_INACTIVE, - STATE_BIT_START, - STATE_BIT_END, - STATE_FINISHED, -}; - -/** - * ir_rc5_sz_decode() - Decode one RC-5 Streamzap 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_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) -{ - struct rc5_sz_dec *data = &dev->raw->rc5_sz; - u8 toggle, command, system; - u32 scancode; - - if (!rc_protocols_enabled(dev, RC_BIT_RC5_SZ)) - return 0; - - if (!is_timing_event(ev)) { - if (ev.reset) - data->state = STATE_INACTIVE; - return 0; - } - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - goto out; - -again: - IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - - if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) - return 0; - - switch (data->state) { - - case STATE_INACTIVE: - if (!ev.pulse) - break; - - data->state = STATE_BIT_START; - data->count = 1; - data->wanted_bits = RC5_SZ_NBITS; - decrease_duration(&ev, RC5_BIT_START); - goto again; - - case STATE_BIT_START: - if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) - break; - - data->bits <<= 1; - if (!ev.pulse) - data->bits |= 1; - data->count++; - data->state = STATE_BIT_END; - return 0; - - case STATE_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_BIT_START; - - decrease_duration(&ev, RC5_BIT_END); - goto again; - - case STATE_FINISHED: - if (ev.pulse) - break; - - /* RC5-sz */ - command = (data->bits & 0x0003F) >> 0; - system = (data->bits & 0x02FC0) >> 6; - toggle = (data->bits & 0x01000) ? 1 : 0; - scancode = system << 6 | command; - - IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", - scancode, toggle); - - rc_keydown(dev, scancode, toggle); - data->state = STATE_INACTIVE; - return 0; - } - -out: - IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); - data->state = STATE_INACTIVE; - return -EINVAL; -} - -static struct ir_raw_handler rc5_sz_handler = { - .protocols = RC_BIT_RC5_SZ, - .decode = ir_rc5_sz_decode, -}; - -static int __init ir_rc5_sz_decode_init(void) -{ - ir_raw_handler_register(&rc5_sz_handler); - - printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); - return 0; -} - -static void __exit ir_rc5_sz_decode_exit(void) -{ - ir_raw_handler_unregister(&rc5_sz_handler); -} - -module_init(ir_rc5_sz_decode_init); -module_exit(ir_rc5_sz_decode_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); -MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index cfbd64e3999c..f1f098e22f7e 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -88,10 +88,11 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) struct rc6_dec *data = &dev->raw->rc6; u32 scancode; u8 toggle; + enum rc_type protocol; - if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | - RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | - RC_BIT_RC6_MCE)) + if (!(dev->enabled_protocols & + (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) return 0; if (!is_timing_event(ev)) { @@ -233,9 +234,11 @@ again: case RC6_MODE_0: scancode = data->body; toggle = data->toggle; + protocol = RC_TYPE_RC6_0; IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", scancode, toggle); break; + case RC6_MODE_6A: if (data->count > CHAR_BIT * sizeof data->body) { IR_dprintk(1, "RC6 too many (%u) data bits\n", @@ -244,23 +247,39 @@ again: } scancode = data->body; - if (data->count == RC6_6A_32_NBITS && - (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { - /* MCE RC */ - toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0; - scancode &= ~RC6_6A_MCE_TOGGLE_MASK; - } else { + switch (data->count) { + case 20: + protocol = RC_TYPE_RC6_6A_20; + toggle = 0; + break; + case 24: + protocol = RC_BIT_RC6_6A_24; toggle = 0; + break; + case 32: + if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { + protocol = RC_TYPE_RC6_MCE; + scancode &= ~RC6_6A_MCE_TOGGLE_MASK; + toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); + } else { + protocol = RC_BIT_RC6_6A_32; + toggle = 0; + } + break; + default: + IR_dprintk(1, "RC6(6A) unsupported length\n"); + goto out; } - IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", - scancode, toggle); + + IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n", + protocol, scancode, toggle); break; default: IR_dprintk(1, "RC6 unknown mode\n"); goto out; } - rc_keydown(dev, scancode, toggle); + rc_keydown(dev, protocol, scancode, toggle); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index eb715f04dc27..ad1dc6ae21fc 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!rc_protocols_enabled(dev, RC_BIT_SANYO)) + if (!(dev->enabled_protocols & RC_BIT_SANYO)) return 0; if (!is_timing_event(ev)) { @@ -167,7 +167,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = address << 8 | command; IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); - rc_keydown(dev, scancode, 0); + rc_keydown(dev, RC_TYPE_SANYO, scancode, 0); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index 66d20394ceaa..b7acdbae8159 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -48,7 +48,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) struct sharp_dec *data = &dev->raw->sharp; u32 msg, echo, address, command, scancode; - if (!rc_protocols_enabled(dev, RC_BIT_SHARP)) + if (!(dev->enabled_protocols & RC_BIT_SHARP)) return 0; if (!is_timing_event(ev)) { @@ -162,7 +162,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = address << 8 | command; IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); - rc_keydown(dev, scancode, 0); + rc_keydown(dev, RC_TYPE_SHARP, scancode, 0); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index 599c19a73360..d12dc3da5931 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -42,11 +42,12 @@ enum sony_state { static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct sony_dec *data = &dev->raw->sony; + enum rc_type protocol; u32 scancode; u8 device, subdevice, function; - if (!rc_protocols_enabled(dev, RC_BIT_SONY12 | RC_BIT_SONY15 | - RC_BIT_SONY20)) + if (!(dev->enabled_protocols & + (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) return 0; if (!is_timing_event(ev)) { @@ -124,31 +125,34 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!rc_protocols_enabled(dev, RC_BIT_SONY12)) { + if (!(dev->enabled_protocols & RC_BIT_SONY12)) { data->state = STATE_INACTIVE; return 0; } device = bitrev8((data->bits << 3) & 0xF8); subdevice = 0; function = bitrev8((data->bits >> 4) & 0xFE); + protocol = RC_TYPE_SONY12; break; case 15: - if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) { + if (!(dev->enabled_protocols & RC_BIT_SONY15)) { data->state = STATE_INACTIVE; return 0; } device = bitrev8((data->bits >> 0) & 0xFF); subdevice = 0; function = bitrev8((data->bits >> 7) & 0xFE); + protocol = RC_TYPE_SONY15; break; case 20: - if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) { + if (!(dev->enabled_protocols & RC_BIT_SONY20)) { data->state = STATE_INACTIVE; return 0; } device = bitrev8((data->bits >> 5) & 0xF8); subdevice = bitrev8((data->bits >> 0) & 0xFF); function = bitrev8((data->bits >> 12) & 0xFE); + protocol = RC_TYPE_SONY20; break; default: IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); @@ -157,7 +161,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = device << 16 | subdevice << 8 | function; IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode); - rc_keydown(dev, scancode, 0); + rc_keydown(dev, protocol, scancode, 0); data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c new file mode 100644 index 000000000000..1017d4816e8d --- /dev/null +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -0,0 +1,225 @@ +/* ir-xmp-decoder.c - handle XMP IR Pulse/Space protocol + * + * Copyright (C) 2014 by Marcel Mol + * + * 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. + * + * - Based on info from http://www.hifi-remote.com + * - Ignore Toggle=9 frames + * - Ignore XMP-1 XMP-2 difference, always store 16 bit OBC + */ + +#include <linux/bitrev.h> +#include <linux/module.h> +#include "rc-core-priv.h" + +#define XMP_UNIT 136000 /* ns */ +#define XMP_LEADER 210000 /* ns */ +#define XMP_NIBBLE_PREFIX 760000 /* ns */ +#define XMP_HALFFRAME_SPACE 13800000 /* ns */ +#define XMP_TRAILER_SPACE 20000000 /* should be 80ms but not all dureation supliers can go that high */ + +enum xmp_state { + STATE_INACTIVE, + STATE_LEADER_PULSE, + STATE_NIBBLE_SPACE, +}; + +/** + * ir_xmp_decode() - Decode one XMP pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct xmp_dec *data = &dev->raw->xmp; + + if (!(dev->enabled_protocols & RC_BIT_XMP)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n", + data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2)) { + data->count = 0; + data->state = STATE_NIBBLE_SPACE; + } + + return 0; + + case STATE_LEADER_PULSE: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2)) + data->state = STATE_NIBBLE_SPACE; + + return 0; + + case STATE_NIBBLE_SPACE: + if (ev.pulse) + break; + + if (geq_margin(ev.duration, XMP_TRAILER_SPACE, XMP_NIBBLE_PREFIX)) { + int divider, i; + u8 addr, subaddr, subaddr2, toggle, oem, obc1, obc2, sum1, sum2; + u32 *n; + u32 scancode; + + if (data->count != 16) { + IR_dprintk(2, "received TRAILER period at index %d: %u\n", + data->count, ev.duration); + data->state = STATE_INACTIVE; + return -EINVAL; + } + + n = data->durations; + /* + * the 4th nibble should be 15 so base the divider on this + * to transform durations into nibbles. Substract 2000 from + * the divider to compensate for fluctuations in the signal + */ + divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000; + if (divider < 50) { + IR_dprintk(2, "divider to small %d.\n", divider); + data->state = STATE_INACTIVE; + return -EINVAL; + } + + /* convert to nibbles and do some sanity checks */ + for (i = 0; i < 16; i++) + n[i] = (n[i] - XMP_NIBBLE_PREFIX) / divider; + sum1 = (15 + n[0] + n[1] + n[2] + n[3] + + n[4] + n[5] + n[6] + n[7]) % 16; + sum2 = (15 + n[8] + n[9] + n[10] + n[11] + + n[12] + n[13] + n[14] + n[15]) % 16; + + if (sum1 != 15 || sum2 != 15) { + IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n", + sum1, sum2); + data->state = STATE_INACTIVE; + return -EINVAL; + } + + subaddr = n[0] << 4 | n[2]; + subaddr2 = n[8] << 4 | n[11]; + oem = n[4] << 4 | n[5]; + addr = n[6] << 4 | n[7]; + toggle = n[10]; + obc1 = n[12] << 4 | n[13]; + obc2 = n[14] << 4 | n[15]; + if (subaddr != subaddr2) { + IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", + subaddr, subaddr2); + data->state = STATE_INACTIVE; + return -EINVAL; + } + if (oem != 0x44) + IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", + oem); + + scancode = addr << 24 | subaddr << 16 | + obc1 << 8 | obc2; + IR_dprintk(1, "XMP scancode 0x%06x\n", scancode); + + if (toggle == 0) { + rc_keydown(dev, RC_TYPE_XMP, scancode, 0); + } else { + rc_repeat(dev); + IR_dprintk(1, "Repeat last key\n"); + } + data->state = STATE_INACTIVE; + + return 0; + + } else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) { + /* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */ + if (data->count == 16) { + IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n", + data->count, ev.duration); + /* + * TODO: for now go back to half frame position + * so trailer can be found and key press + * can be handled. + */ + data->count = 8; + } + + else if (data->count != 8) + IR_dprintk(2, "received half frame pulse at index %d: %u\n", + data->count, ev.duration); + data->state = STATE_LEADER_PULSE; + + return 0; + + } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) { + /* store nibble raw data, decode after trailer */ + if (data->count == 16) { + IR_dprintk(2, "to many pulses (%d) ignoring: %u\n", + data->count, ev.duration); + data->state = STATE_INACTIVE; + return -EINVAL; + } + data->durations[data->count] = ev.duration; + data->count++; + data->state = STATE_LEADER_PULSE; + + return 0; + + } + + break; + } + + IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler xmp_handler = { + .protocols = RC_BIT_XMP, + .decode = ir_xmp_decode, +}; + +static int __init ir_xmp_decode_init(void) +{ + ir_raw_handler_register(&xmp_handler); + + printk(KERN_INFO "IR XMP protocol handler initialized\n"); + return 0; +} + +static void __exit ir_xmp_decode_exit(void) +{ + ir_raw_handler_unregister(&xmp_handler); +} + +module_init(ir_xmp_decode_init); +module_exit(ir_xmp_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marcel Mol <marcel@mesa.nl>"); +MODULE_AUTHOR("MESA Consulting (http://www.mesa.nl)"); +MODULE_DESCRIPTION("XMP IR protocol decoder"); diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index ab24cc6d3655..447fe35862dc 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* set up ir-core props */ rdev->priv = itdev; rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; rdev->open = ite_open; rdev->close = ite_close; rdev->s_idle = ite_s_idle; @@ -1709,12 +1709,12 @@ static struct pnp_driver ite_driver = { .shutdown = ite_shutdown, }; -static int ite_init(void) +static int __init ite_init(void) { return pnp_register_driver(&ite_driver); } -static void ite_exit(void) +static void __exit ite_exit(void) { pnp_unregister_driver(&ite_driver); } diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 81506440eded..4bdc709ec54d 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -26,7 +26,42 @@ #include <linux/module.h> #include <media/rc-map.h> +/* + * Intended usage comments below are from vendor-supplied + * Source: ATI REMOTE WONDERâ„¢ Installation Guide + * http://www2.ati.com/manuals/remctrl.pdf + * + * Scancodes were in strict left-right, top-bottom order on the + * original ATI Remote Wonder, but were moved on later models. + * + * Keys A-F are intended to be user-programmable. + */ + static struct rc_map_table ati_x10[] = { + /* keyboard - Above the cursor pad */ + { 0x00, KEY_A }, + { 0x01, KEY_B }, + { 0x02, KEY_POWER }, /* Power */ + + { 0x03, KEY_TV }, /* TV */ + { 0x04, KEY_DVD }, /* DVD */ + { 0x05, KEY_WWW }, /* WEB */ + { 0x06, KEY_BOOKMARKS }, /* "book": Open Media Library */ + { 0x07, KEY_EDIT }, /* "hand": Toggle left mouse button (grab) */ + + /* Mouse emulation pad goes here, handled by driver separately */ + + { 0x09, KEY_VOLUMEDOWN }, /* VOL + */ + { 0x08, KEY_VOLUMEUP }, /* VOL - */ + { 0x0a, KEY_MUTE }, /* MUTE */ + { 0x0b, KEY_CHANNELUP }, /* CH + */ + { 0x0c, KEY_CHANNELDOWN },/* CH - */ + + /* + * We could use KEY_NUMERIC_x for these, but the X11 protocol + * has problems with keycodes greater than 255, so avoid those high + * keycodes in default maps. + */ { 0x0d, KEY_1 }, { 0x0e, KEY_2 }, { 0x0f, KEY_3 }, @@ -36,46 +71,45 @@ static struct rc_map_table ati_x10[] = { { 0x13, KEY_7 }, { 0x14, KEY_8 }, { 0x15, KEY_9 }, + { 0x16, KEY_MENU }, /* "menu": DVD root menu */ + /* KEY_NUMERIC_STAR? */ { 0x17, KEY_0 }, - { 0x00, KEY_A }, - { 0x01, KEY_B }, + { 0x18, KEY_SETUP }, /* "check": DVD setup menu */ + /* KEY_NUMERIC_POUND? */ + + /* DVD navigation buttons */ { 0x19, KEY_C }, + { 0x1a, KEY_UP }, /* up */ { 0x1b, KEY_D }, - { 0x21, KEY_E }, - { 0x23, KEY_F }, - { 0x18, KEY_KPENTER }, /* "check" */ - { 0x16, KEY_MENU }, /* "menu" */ - { 0x02, KEY_POWER }, /* Power */ - { 0x03, KEY_TV }, /* TV */ - { 0x04, KEY_DVD }, /* DVD */ - { 0x05, KEY_WWW }, /* WEB */ - { 0x06, KEY_BOOKMARKS }, /* "book" */ - { 0x07, KEY_EDIT }, /* "hand" */ - { 0x1c, KEY_COFFEE }, /* "timer" */ - { 0x20, KEY_FRONT }, /* "max" */ + { 0x1c, KEY_PROPS }, /* "timer" Should be Data On Screen */ + /* Symbol is "circle nailed to box" */ { 0x1d, KEY_LEFT }, /* left */ + { 0x1e, KEY_OK }, /* "OK" */ { 0x1f, KEY_RIGHT }, /* right */ + { 0x20, KEY_SCREEN }, /* "max" (X11 warning: 0x177) */ + /* Should be AC View Toggle, but + that's not in <input/input.h>. + KEY_ZOOM (0x174)? */ + { 0x21, KEY_E }, { 0x22, KEY_DOWN }, /* down */ - { 0x1a, KEY_UP }, /* up */ - { 0x1e, KEY_OK }, /* "OK" */ - { 0x09, KEY_VOLUMEDOWN }, /* VOL + */ - { 0x08, KEY_VOLUMEUP }, /* VOL - */ - { 0x0a, KEY_MUTE }, /* MUTE */ - { 0x0b, KEY_CHANNELUP }, /* CH + */ - { 0x0c, KEY_CHANNELDOWN },/* CH - */ + { 0x23, KEY_F }, + /* Play/stop/pause buttons */ + { 0x24, KEY_REWIND }, /* (<<) Rewind */ + { 0x25, KEY_PLAY }, /* ( >) Play (KEY_PLAYCD?) */ + { 0x26, KEY_FASTFORWARD }, /* (>>) Fast forward */ + { 0x27, KEY_RECORD }, /* ( o) red */ - { 0x25, KEY_PLAY }, /* ( >) */ - { 0x24, KEY_REWIND }, /* (<<) */ - { 0x26, KEY_FORWARD }, /* (>>) */ - { 0x28, KEY_STOP }, /* ([]) */ - { 0x29, KEY_PAUSE }, /* ('') */ - { 0x2b, KEY_PREVIOUS }, /* (<-) */ + { 0x28, KEY_STOPCD }, /* ([]) Stop (KEY_STOP is something else!) */ + { 0x29, KEY_PAUSE }, /* ('') Pause (KEY_PAUSECD?) */ + + /* Extra keys, not on the original ATI remote */ { 0x2a, KEY_NEXT }, /* (>+) */ - { 0x2d, KEY_INFO }, /* PLAYING */ + { 0x2b, KEY_PREVIOUS }, /* (<-) */ + { 0x2d, KEY_INFO }, /* PLAYING (X11 warning: 0x166) */ { 0x2e, KEY_HOME }, /* TOP */ { 0x2f, KEY_END }, /* END */ - { 0x30, KEY_SELECT }, /* SELECT */ + { 0x30, KEY_SELECT }, /* SELECT (X11 warning: 0x161) */ }; static struct rc_map_list ati_x10_map = { diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index d6519f8ac95a..520a96f2ff86 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -30,8 +30,8 @@ static struct rc_map_table behold[] = { /* 0x1c 0x12 * * TV/FM POWER * * */ - { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */ - { 0x6b8612, KEY_POWER }, + { 0x866b1c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */ + { 0x866b12, KEY_POWER }, /* 0x01 0x02 0x03 * * 1 2 3 * @@ -42,28 +42,28 @@ static struct rc_map_table behold[] = { * 0x07 0x08 0x09 * * 7 8 9 * * */ - { 0x6b8601, KEY_1 }, - { 0x6b8602, KEY_2 }, - { 0x6b8603, KEY_3 }, - { 0x6b8604, KEY_4 }, - { 0x6b8605, KEY_5 }, - { 0x6b8606, KEY_6 }, - { 0x6b8607, KEY_7 }, - { 0x6b8608, KEY_8 }, - { 0x6b8609, KEY_9 }, + { 0x866b01, KEY_1 }, + { 0x866b02, KEY_2 }, + { 0x866b03, KEY_3 }, + { 0x866b04, KEY_4 }, + { 0x866b05, KEY_5 }, + { 0x866b06, KEY_6 }, + { 0x866b07, KEY_7 }, + { 0x866b08, KEY_8 }, + { 0x866b09, KEY_9 }, /* 0x0a 0x00 0x17 * * RECALL 0 MODE * * */ - { 0x6b860a, KEY_AGAIN }, - { 0x6b8600, KEY_0 }, - { 0x6b8617, KEY_MODE }, + { 0x866b0a, KEY_AGAIN }, + { 0x866b00, KEY_0 }, + { 0x866b17, KEY_MODE }, /* 0x14 0x10 * * ASPECT FULLSCREEN * * */ - { 0x6b8614, KEY_SCREEN }, - { 0x6b8610, KEY_ZOOM }, + { 0x866b14, KEY_SCREEN }, + { 0x866b10, KEY_ZOOM }, /* 0x0b * * Up * @@ -74,17 +74,17 @@ static struct rc_map_table behold[] = { * 0x015 * * Down * * */ - { 0x6b860b, KEY_CHANNELUP }, - { 0x6b8618, KEY_VOLUMEDOWN }, - { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */ - { 0x6b860c, KEY_VOLUMEUP }, - { 0x6b8615, KEY_CHANNELDOWN }, + { 0x866b0b, KEY_CHANNELUP }, + { 0x866b18, KEY_VOLUMEDOWN }, + { 0x866b16, KEY_OK }, /* XXX KEY_ENTER */ + { 0x866b0c, KEY_VOLUMEUP }, + { 0x866b15, KEY_CHANNELDOWN }, /* 0x11 0x0d * * MUTE INFO * * */ - { 0x6b8611, KEY_MUTE }, - { 0x6b860d, KEY_INFO }, + { 0x866b11, KEY_MUTE }, + { 0x866b0d, KEY_INFO }, /* 0x0f 0x1b 0x1a * * RECORD PLAY/PAUSE STOP * @@ -93,26 +93,26 @@ static struct rc_map_table behold[] = { *TELETEXT AUDIO SOURCE * * RED YELLOW * * */ - { 0x6b860f, KEY_RECORD }, - { 0x6b861b, KEY_PLAYPAUSE }, - { 0x6b861a, KEY_STOP }, - { 0x6b860e, KEY_TEXT }, - { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */ - { 0x6b861e, KEY_VIDEO }, + { 0x866b0f, KEY_RECORD }, + { 0x866b1b, KEY_PLAYPAUSE }, + { 0x866b1a, KEY_STOP }, + { 0x866b0e, KEY_TEXT }, + { 0x866b1f, KEY_RED }, /*XXX KEY_AUDIO */ + { 0x866b1e, KEY_VIDEO }, /* 0x1d 0x13 0x19 * * SLEEP PREVIEW DVB * * GREEN BLUE * * */ - { 0x6b861d, KEY_SLEEP }, - { 0x6b8613, KEY_GREEN }, - { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */ + { 0x866b1d, KEY_SLEEP }, + { 0x866b13, KEY_GREEN }, + { 0x866b19, KEY_BLUE }, /* XXX KEY_SAT */ /* 0x58 0x5c * * FREEZE SNAPSHOT * * */ - { 0x6b8658, KEY_SLOW }, - { 0x6b865c, KEY_CAMERA }, + { 0x866b58, KEY_SLOW }, + { 0x866b5c, KEY_CAMERA }, }; diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 8ec881adb7cf..4c50f33c7c41 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -14,68 +14,68 @@ #include <linux/module.h> static struct rc_map_table nebula[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x0a, KEY_TV }, - { 0x0b, KEY_AUX }, - { 0x0c, KEY_DVD }, - { 0x0d, KEY_POWER }, - { 0x0e, KEY_CAMERA }, /* labelled 'Picture' */ - { 0x0f, KEY_AUDIO }, - { 0x10, KEY_INFO }, - { 0x11, KEY_F13 }, /* 16:9 */ - { 0x12, KEY_F14 }, /* 14:9 */ - { 0x13, KEY_EPG }, - { 0x14, KEY_EXIT }, - { 0x15, KEY_MENU }, - { 0x16, KEY_UP }, - { 0x17, KEY_DOWN }, - { 0x18, KEY_LEFT }, - { 0x19, KEY_RIGHT }, - { 0x1a, KEY_ENTER }, - { 0x1b, KEY_CHANNELUP }, - { 0x1c, KEY_CHANNELDOWN }, - { 0x1d, KEY_VOLUMEUP }, - { 0x1e, KEY_VOLUMEDOWN }, - { 0x1f, KEY_RED }, - { 0x20, KEY_GREEN }, - { 0x21, KEY_YELLOW }, - { 0x22, KEY_BLUE }, - { 0x23, KEY_SUBTITLE }, - { 0x24, KEY_F15 }, /* AD */ - { 0x25, KEY_TEXT }, - { 0x26, KEY_MUTE }, - { 0x27, KEY_REWIND }, - { 0x28, KEY_STOP }, - { 0x29, KEY_PLAY }, - { 0x2a, KEY_FASTFORWARD }, - { 0x2b, KEY_F16 }, /* chapter */ - { 0x2c, KEY_PAUSE }, - { 0x2d, KEY_PLAY }, - { 0x2e, KEY_RECORD }, - { 0x2f, KEY_F17 }, /* picture in picture */ - { 0x30, KEY_KPPLUS }, /* zoom in */ - { 0x31, KEY_KPMINUS }, /* zoom out */ - { 0x32, KEY_F18 }, /* capture */ - { 0x33, KEY_F19 }, /* web */ - { 0x34, KEY_EMAIL }, - { 0x35, KEY_PHONE }, - { 0x36, KEY_PC }, + { 0x0000, KEY_0 }, + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + { 0x000a, KEY_TV }, + { 0x000b, KEY_AUX }, + { 0x000c, KEY_DVD }, + { 0x000d, KEY_POWER }, + { 0x000e, KEY_CAMERA }, /* labelled 'Picture' */ + { 0x000f, KEY_AUDIO }, + { 0x0010, KEY_INFO }, + { 0x0011, KEY_F13 }, /* 16:9 */ + { 0x0012, KEY_F14 }, /* 14:9 */ + { 0x0013, KEY_EPG }, + { 0x0014, KEY_EXIT }, + { 0x0015, KEY_MENU }, + { 0x0016, KEY_UP }, + { 0x0017, KEY_DOWN }, + { 0x0018, KEY_LEFT }, + { 0x0019, KEY_RIGHT }, + { 0x001a, KEY_ENTER }, + { 0x001b, KEY_CHANNELUP }, + { 0x001c, KEY_CHANNELDOWN }, + { 0x001d, KEY_VOLUMEUP }, + { 0x001e, KEY_VOLUMEDOWN }, + { 0x001f, KEY_RED }, + { 0x0020, KEY_GREEN }, + { 0x0021, KEY_YELLOW }, + { 0x0022, KEY_BLUE }, + { 0x0023, KEY_SUBTITLE }, + { 0x0024, KEY_F15 }, /* AD */ + { 0x0025, KEY_TEXT }, + { 0x0026, KEY_MUTE }, + { 0x0027, KEY_REWIND }, + { 0x0028, KEY_STOP }, + { 0x0029, KEY_PLAY }, + { 0x002a, KEY_FASTFORWARD }, + { 0x002b, KEY_F16 }, /* chapter */ + { 0x002c, KEY_PAUSE }, + { 0x002d, KEY_PLAY }, + { 0x002e, KEY_RECORD }, + { 0x002f, KEY_F17 }, /* picture in picture */ + { 0x0030, KEY_KPPLUS }, /* zoom in */ + { 0x0031, KEY_KPMINUS }, /* zoom out */ + { 0x0032, KEY_F18 }, /* capture */ + { 0x0033, KEY_F19 }, /* web */ + { 0x0034, KEY_EMAIL }, + { 0x0035, KEY_PHONE }, + { 0x0036, KEY_PC }, }; static struct rc_map_list nebula_map = { .map = { .scan = nebula, .size = ARRAY_SIZE(nebula), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ + .rc_type = RC_TYPE_RC5, .name = RC_MAP_NEBULA, } }; diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c index f9a07578d985..23c061174ed7 100644 --- a/drivers/media/rc/keymaps/rc-streamzap.c +++ b/drivers/media/rc/keymaps/rc-streamzap.c @@ -15,9 +15,7 @@ static struct rc_map_table streamzap[] = { /* * The Streamzap remote is almost, but not quite, RC-5, as it has an extra - * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently, - * an additional RC-5-sz decoder is being deployed to support it, but it - * may be possible to merge it back with the standard RC-5 decoder. + * bit in it. */ { 0x28c0, KEY_NUMERIC_0 }, { 0x28c1, KEY_NUMERIC_1 }, diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index d5c1df3c9db1..45b0894288e5 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -187,6 +187,7 @@ #define VENDOR_CONEXANT 0x0572 #define VENDOR_TWISTEDMELON 0x2596 #define VENDOR_HAUPPAUGE 0x2040 +#define VENDOR_PCTV 0x2013 enum mceusb_model_type { MCE_GEN2 = 0, /* Most boards */ @@ -240,7 +241,6 @@ static const struct mceusb_model mceusb_model[] = { * remotes, but we should have something handy, * to allow testing it */ - .rc_map = RC_MAP_HAUPPAUGE, .name = "Conexant Hybrid TV (cx231xx) MCE IR", }, [CX_HYBRID_TV] = { @@ -248,7 +248,6 @@ static const struct mceusb_model mceusb_model[] = { .name = "Conexant Hybrid TV (cx231xx) MCE IR", }, [HAUPPAUGE_CX_HYBRID_TV] = { - .rc_map = RC_MAP_HAUPPAUGE, .no_tx = 1, /* eeprom says it has no tx */ .name = "Conexant Hybrid TV (cx231xx) MCE IR no TX", }, @@ -396,6 +395,13 @@ static struct usb_device_id mceusb_dev_table[] = { /* Hauppauge WINTV-HVR-HVR 930C-HD - based on cx231xx */ { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb130), .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_PCTV, 0x0259), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_PCTV, 0x025e), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + /* Terminating entry */ { } }; @@ -1192,8 +1198,10 @@ static void mceusb_flash_led(struct mceusb_dev *ir) mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED)); } -static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) +static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir, + struct usb_interface *intf) { + struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); struct device *dev = ir->dev; struct rc_dev *rc; int ret; @@ -1219,7 +1227,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->dev.parent = dev; rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rc, RC_BIT_ALL); + rc->allowed_protocols = RC_BIT_ALL; rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; @@ -1227,8 +1235,19 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->tx_ir = mceusb_tx_ir; } rc->driver_name = DRIVER_NAME; - rc->map_name = mceusb_model[ir->model].rc_map ? - mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE; + + switch (le16_to_cpu(udev->descriptor.idVendor)) { + case VENDOR_HAUPPAUGE: + rc->map_name = RC_MAP_HAUPPAUGE; + break; + case VENDOR_PCTV: + rc->map_name = RC_MAP_PINNACLE_PCTV_HD; + break; + default: + rc->map_name = RC_MAP_RC6_MCE; + } + if (mceusb_model[ir->model].rc_map) + rc->map_name = mceusb_model[ir->model].rc_map; ret = rc_register_device(rc); if (ret < 0) { @@ -1343,7 +1362,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, snprintf(name + strlen(name), sizeof(name) - strlen(name), " %s", buf); - ir->rc = mceusb_init_rc_dev(ir); + ir->rc = mceusb_init_rc_dev(ir, intf); if (!ir->rc) goto rc_dev_fail; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index d244e1a83f43..7f4fd859bba5 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1044,7 +1044,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; @@ -1221,12 +1221,12 @@ static struct pnp_driver nvt_driver = { .shutdown = nvt_shutdown, }; -static int nvt_init(void) +static int __init nvt_init(void) { return pnp_register_driver(&nvt_driver); } -static void nvt_exit(void) +static void __exit nvt_exit(void) { pnp_unregister_driver(&nvt_driver); } diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index da536c93c978..b68d4f762734 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -54,7 +54,7 @@ struct ir_raw_event_ctrl { int state; u32 bits; unsigned count; - unsigned wanted_bits; + bool is_rc5x; } rc5; struct rc6_dec { int state; @@ -77,12 +77,6 @@ struct ir_raw_event_ctrl { bool first; bool toggle; } jvc; - struct rc5_sz_dec { - int state; - u32 bits; - unsigned count; - unsigned wanted_bits; - } rc5_sz; struct sanyo_dec { int state; unsigned count; @@ -116,6 +110,11 @@ struct ir_raw_event_ctrl { bool send_timeout_reports; } lirc; + struct xmp_dec { + int state; + unsigned count; + u32 durations[16]; + } xmp; }; /* macros for IR decoders */ @@ -231,5 +230,12 @@ static inline void load_mce_kbd_decode(void) { } static inline void load_lirc_codec(void) { } #endif +/* from ir-xmp-decoder.c */ +#ifdef CONFIG_IR_XMP_DECODER_MODULE +#define load_xmp_decode() request_module_nowait("ir-xmp-decoder") +#else +static inline void load_xmp_decode(void) { } +#endif + #endif /* _RC_CORE_PRIV */ diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 763c9d131d0f..e8fff2add265 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -1,4 +1,4 @@ -/* ir-raw.c - handle IR pulse/space events +/* rc-ir-raw.c - handle IR pulse/space events * * Copyright (C) 2010 by Mauro Carvalho Chehab * @@ -240,6 +240,12 @@ ir_raw_get_allowed_protocols(void) return protocols; } +static int change_protocol(struct rc_dev *dev, u64 *rc_type) +{ + /* the caller will update dev->enabled_protocols */ + return 0; +} + /* * Used to (un)register raw event clients */ @@ -256,7 +262,8 @@ int ir_raw_event_register(struct rc_dev *dev) return -ENOMEM; dev->raw->dev = dev; - rc_set_enabled_protocols(dev, ~0); + dev->enabled_protocols = ~0; + dev->change_protocol = change_protocol; rc = kfifo_alloc(&dev->raw->kfifo, sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, GFP_KERNEL); @@ -355,6 +362,7 @@ void ir_raw_init(void) load_sharp_decode(); load_mce_kbd_decode(); load_lirc_codec(); + load_xmp_decode(); /* If needed, we may later add some init code. In this case, it is needed to change the CONFIG_MODULE test at rc-core.h diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 0a88e0cf964f..63dace8198b0 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -195,7 +195,7 @@ static int __init loop_init(void) rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; rc->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rc, RC_BIT_ALL); + rc->allowed_protocols = RC_BIT_ALL; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; rc->max_timeout = UINT_MAX; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 970b93d6f399..a7991c7d010a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -285,8 +285,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev, * IR tables from other remotes. So, we support specifying a mask to * indicate the valid bits of the scancodes. */ - if (dev->scanmask) - scancode &= dev->scanmask; + if (dev->scancode_mask) + scancode &= dev->scancode_mask; /* First check if we already have a mapping for this ir command */ for (i = 0; i < rc_map->len; i++) { @@ -623,6 +623,7 @@ EXPORT_SYMBOL_GPL(rc_repeat); /** * ir_do_keydown() - internal function to process a keypress * @dev: the struct rc_dev descriptor of the device + * @protocol: the protocol of the keypress * @scancode: the scancode of the keypress * @keycode: the keycode of the keypress * @toggle: the toggle value of the keypress @@ -630,12 +631,13 @@ EXPORT_SYMBOL_GPL(rc_repeat); * This function is used internally to register a keypress, it must be * called with keylock held. */ -static void ir_do_keydown(struct rc_dev *dev, int scancode, - u32 keycode, u8 toggle) +static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, + u32 scancode, u32 keycode, u8 toggle) { bool new_event = (!dev->keypressed || + dev->last_protocol != protocol || dev->last_scancode != scancode || - dev->last_toggle != toggle); + dev->last_toggle != toggle); if (new_event && dev->keypressed) ir_do_keyup(dev, false); @@ -645,13 +647,14 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode, if (new_event && keycode != KEY_RESERVED) { /* Register a keypress */ dev->keypressed = true; + dev->last_protocol = protocol; dev->last_scancode = scancode; dev->last_toggle = toggle; dev->last_keycode = keycode; IR_dprintk(1, "%s: key down event, " - "key 0x%04x, scancode 0x%04x\n", - dev->input_name, keycode, scancode); + "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + dev->input_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); led_trigger_event(led_feedback, LED_FULL); @@ -663,20 +666,21 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode, /** * rc_keydown() - generates input event for a key press * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking + * @protocol: the protocol for the keypress + * @scancode: the scancode for the keypress * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. */ -void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle) +void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); + ir_do_keydown(dev, protocol, scancode, keycode, toggle); if (dev->keypressed) { dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); @@ -690,20 +694,22 @@ EXPORT_SYMBOL_GPL(rc_keydown); * rc_keydown_notimeout() - generates input event for a key press without * an automatic keyup event at a later time * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking + * @protocol: the protocol for the keypress + * @scancode: the scancode for the keypress * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. The driver must manually call rc_keyup() at a later stage. */ -void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle) +void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, + u32 scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); + ir_do_keydown(dev, protocol, scancode, keycode, toggle); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keydown_notimeout); @@ -794,6 +800,7 @@ static struct { { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, { RC_BIT_LIRC, "lirc" }, + { RC_BIT_XMP, "xmp" }, }; /** @@ -824,7 +831,7 @@ struct rc_filter_attribute { /** * show_protocols() - shows the current/wakeup IR protocol(s) * @device: the device descriptor - * @mattr: the device attribute struct (unused) + * @mattr: the device attribute struct * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). @@ -850,20 +857,20 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - enabled = dev->enabled_protocols[fattr->type]; - if (dev->driver_type == RC_DRIVER_SCANCODE || - fattr->type == RC_FILTER_WAKEUP) - allowed = dev->allowed_protocols[fattr->type]; - else if (dev->raw) - allowed = ir_raw_get_allowed_protocols(); - else { - mutex_unlock(&dev->lock); - return -ENODEV; + if (fattr->type == RC_FILTER_NORMAL) { + enabled = dev->enabled_protocols; + allowed = dev->allowed_protocols; + if (dev->raw && !allowed) + allowed = ir_raw_get_allowed_protocols(); + } else { + enabled = dev->enabled_wakeup_protocols; + allowed = dev->allowed_wakeup_protocols; } - IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", - (long long)allowed, - (long long)enabled); + mutex_unlock(&dev->lock); + + IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n", + __func__, (long long)allowed, (long long)enabled); for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (allowed & enabled & proto_names[i].type) @@ -879,62 +886,29 @@ static ssize_t show_protocols(struct device *device, tmp--; *tmp = '\n'; - mutex_unlock(&dev->lock); - return tmp + 1 - buf; } /** - * store_protocols() - changes the current/wakeup IR protocol(s) - * @device: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the input buffer - * @len: length of the input buffer + * parse_protocol_change() - parses a protocol change request + * @protocols: pointer to the bitmask of current protocols + * @buf: pointer to the buffer with a list of changes * - * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. - * Writing "+proto" will add a protocol to the list of enabled protocols. - * Writing "-proto" will remove a protocol from the list of enabled protocols. + * Writing "+proto" will add a protocol to the protocol mask. + * Writing "-proto" will remove a protocol from protocol mask. * Writing "proto" will enable only "proto". * Writing "none" will disable all protocols. - * Returns -EINVAL if an invalid protocol combination or unknown protocol name - * is used, otherwise @len. - * - * dev->lock is taken to guard against races between device - * registration, store_protocols and show_protocols. + * Returns the number of changes performed or a negative error code. */ -static ssize_t store_protocols(struct device *device, - struct device_attribute *mattr, - const char *data, - size_t len) +static int parse_protocol_change(u64 *protocols, const char *buf) { - struct rc_dev *dev = to_rc_dev(device); - struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); - bool enable, disable; const char *tmp; - u64 old_type, type; + unsigned count = 0; + bool enable, disable; u64 mask; - int rc, i, count = 0; - ssize_t ret; - int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); - int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); - struct rc_scancode_filter local_filter, *filter; - - /* Device is being removed */ - if (!dev) - return -EINVAL; - - mutex_lock(&dev->lock); - - if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) { - IR_dprintk(1, "Protocol switching not supported\n"); - ret = -EINVAL; - goto out; - } - old_type = dev->enabled_protocols[fattr->type]; - type = old_type; + int i; - while ((tmp = strsep((char **) &data, " \n")) != NULL) { + while ((tmp = strsep((char **)&buf, " \n")) != NULL) { if (!*tmp) break; @@ -960,76 +934,124 @@ static ssize_t store_protocols(struct device *device, if (i == ARRAY_SIZE(proto_names)) { IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - ret = -EINVAL; - goto out; + return -EINVAL; } count++; if (enable) - type |= mask; + *protocols |= mask; else if (disable) - type &= ~mask; + *protocols &= ~mask; else - type = mask; + *protocols = mask; } if (!count) { IR_dprintk(1, "Protocol not specified\n"); - ret = -EINVAL; + return -EINVAL; + } + + return count; +} + +/** + * store_protocols() - changes the current/wakeup IR protocol(s) + * @device: the device descriptor + * @mattr: the device attribute struct + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing the IR protocol type. + * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. + * See parse_protocol_change() for the valid commands. + * Returns @len on success or a negative error code. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t store_protocols(struct device *device, + struct device_attribute *mattr, + const char *buf, size_t len) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); + u64 *current_protocols; + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + struct rc_scancode_filter *filter; + int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); + u64 old_protocols, new_protocols; + ssize_t rc; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + if (fattr->type == RC_FILTER_NORMAL) { + IR_dprintk(1, "Normal protocol change requested\n"); + current_protocols = &dev->enabled_protocols; + change_protocol = dev->change_protocol; + filter = &dev->scancode_filter; + set_filter = dev->s_filter; + } else { + IR_dprintk(1, "Wakeup protocol change requested\n"); + current_protocols = &dev->enabled_wakeup_protocols; + change_protocol = dev->change_wakeup_protocol; + filter = &dev->scancode_wakeup_filter; + set_filter = dev->s_wakeup_filter; + } + + if (!change_protocol) { + IR_dprintk(1, "Protocol switching not supported\n"); + return -EINVAL; + } + + mutex_lock(&dev->lock); + + old_protocols = *current_protocols; + new_protocols = old_protocols; + rc = parse_protocol_change(&new_protocols, buf); + if (rc < 0) + goto out; + + rc = change_protocol(dev, &new_protocols); + if (rc < 0) { + IR_dprintk(1, "Error setting protocols to 0x%llx\n", + (long long)new_protocols); goto out; } - change_protocol = (fattr->type == RC_FILTER_NORMAL) - ? dev->change_protocol : dev->change_wakeup_protocol; - if (change_protocol) { - rc = change_protocol(dev, &type); - if (rc < 0) { - IR_dprintk(1, "Error setting protocols to 0x%llx\n", - (long long)type); - ret = -EINVAL; - goto out; - } + if (new_protocols == old_protocols) { + rc = len; + goto out; } - dev->enabled_protocols[fattr->type] = type; - IR_dprintk(1, "Current protocol(s): 0x%llx\n", - (long long)type); + *current_protocols = new_protocols; + IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols); /* * If the protocol is changed the filter needs updating. * Try setting the same filter with the new protocol (if any). * Fall back to clearing the filter. */ - filter = &dev->scancode_filters[fattr->type]; - set_filter = (fattr->type == RC_FILTER_NORMAL) - ? dev->s_filter : dev->s_wakeup_filter; - - if (set_filter && old_type != type && filter->mask) { - local_filter = *filter; - if (!type) { - /* no protocol => clear filter */ - ret = -1; - } else { - /* hardware filtering => try setting, otherwise clear */ - ret = set_filter(dev, &local_filter); - } - if (ret < 0) { - /* clear the filter */ - local_filter.data = 0; - local_filter.mask = 0; - set_filter(dev, &local_filter); - } + if (set_filter && filter->mask) { + if (new_protocols) + rc = set_filter(dev, filter); + else + rc = -1; - /* commit the new filter */ - *filter = local_filter; + if (rc < 0) { + filter->data = 0; + filter->mask = 0; + set_filter(dev, filter); + } } - ret = len; + rc = len; out: mutex_unlock(&dev->lock); - return ret; + return rc; } /** @@ -1055,20 +1077,23 @@ static ssize_t show_filter(struct device *device, { struct rc_dev *dev = to_rc_dev(device); struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); + struct rc_scancode_filter *filter; u32 val; /* Device is being removed */ if (!dev) return -EINVAL; + if (fattr->type == RC_FILTER_NORMAL) + filter = &dev->scancode_filter; + else + filter = &dev->scancode_wakeup_filter; + mutex_lock(&dev->lock); - if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) || - (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter)) - val = 0; - else if (fattr->mask) - val = dev->scancode_filters[fattr->type].mask; + if (fattr->mask) + val = filter->mask; else - val = dev->scancode_filters[fattr->type].data; + val = filter->data; mutex_unlock(&dev->lock); return sprintf(buf, "%#x\n", val); @@ -1095,15 +1120,15 @@ static ssize_t show_filter(struct device *device, */ static ssize_t store_filter(struct device *device, struct device_attribute *attr, - const char *buf, - size_t count) + const char *buf, size_t len) { struct rc_dev *dev = to_rc_dev(device); struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); - struct rc_scancode_filter local_filter, *filter; + struct rc_scancode_filter new_filter, *filter; int ret; unsigned long val; int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); + u64 *enabled_protocols; /* Device is being removed */ if (!dev) @@ -1113,38 +1138,42 @@ static ssize_t store_filter(struct device *device, if (ret < 0) return ret; - /* Can the scancode filter be set? */ - set_filter = (fattr->type == RC_FILTER_NORMAL) ? dev->s_filter : - dev->s_wakeup_filter; + if (fattr->type == RC_FILTER_NORMAL) { + set_filter = dev->s_filter; + enabled_protocols = &dev->enabled_protocols; + filter = &dev->scancode_filter; + } else { + set_filter = dev->s_wakeup_filter; + enabled_protocols = &dev->enabled_wakeup_protocols; + filter = &dev->scancode_wakeup_filter; + } + if (!set_filter) return -EINVAL; mutex_lock(&dev->lock); - /* Tell the driver about the new filter */ - filter = &dev->scancode_filters[fattr->type]; - local_filter = *filter; + new_filter = *filter; if (fattr->mask) - local_filter.mask = val; + new_filter.mask = val; else - local_filter.data = val; + new_filter.data = val; - if (!dev->enabled_protocols[fattr->type] && local_filter.mask) { + if (!*enabled_protocols && val) { /* refuse to set a filter unless a protocol is enabled */ ret = -EINVAL; goto unlock; } - ret = set_filter(dev, &local_filter); + ret = set_filter(dev, &new_filter); if (ret < 0) goto unlock; - /* Success, commit the new filter */ - *filter = local_filter; + *filter = new_filter; unlock: mutex_unlock(&dev->lock); - return (ret < 0) ? ret : count; + return (ret < 0) ? ret : len; } static void rc_dev_release(struct device *device) @@ -1315,7 +1344,7 @@ int rc_register_device(struct rc_dev *dev) dev->dev.groups = dev->sysfs_groups; dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; if (dev->s_filter) - dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; + dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; if (dev->s_wakeup_filter) dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; if (dev->change_wakeup_protocol) @@ -1395,7 +1424,7 @@ int rc_register_device(struct rc_dev *dev) rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; - dev->enabled_protocols[RC_FILTER_NORMAL] = rc_type; + dev->enabled_protocols = rc_type; } mutex_unlock(&dev->lock); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 79abbc8d9600..795b394a5d84 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -878,7 +878,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->dev.parent = dev; rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rc, RC_BIT_ALL); + rc->allowed_protocols = RC_BIT_ALL; rc->timeout = US_TO_NS(2750); rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 22e4c1f28ab4..5c151351afa4 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -287,7 +287,7 @@ static int st_rc_probe(struct platform_device *pdev) st_rc_hardware_init(rc_dev); rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; /* rx sampling rate is 10Mhz */ rdev->rx_resolution = 100; rdev->timeout = US_TO_NS(MAX_SYMB_TIME); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index bd5e4ff9e0ba..80c4feeb01ea 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -63,13 +63,6 @@ MODULE_DEVICE_TABLE(usb, streamzap_table); /* number of samples buffered */ #define SZ_BUF_LEN 128 -/* from ir-rc5-sz-decoder.c */ -#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE -#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder") -#else -#define load_rc5_sz_decode() {} -#endif - enum StreamzapDecoderState { PulseSpace, FullPulse, @@ -316,7 +309,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) rdev->dev.parent = dev; rdev->priv = sz; rdev->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rdev, RC_BIT_ALL); + rdev->allowed_protocols = RC_BIT_ALL; rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; @@ -452,9 +445,6 @@ static int streamzap_probe(struct usb_interface *intf, dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, usbdev->bus->busnum, usbdev->devnum); - /* Load the streamzap not-quite-rc5 decoder too */ - load_rc5_sz_decode(); - return 0; rc_dev_fail: diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c new file mode 100644 index 000000000000..bcee8e1a4e9e --- /dev/null +++ b/drivers/media/rc/sunxi-cir.c @@ -0,0 +1,318 @@ +/* + * Driver for Allwinner sunXi IR controller + * + * Copyright (C) 2014 Alexsey Shestacov <wingrime@linux-sunxi.org> + * Copyright (C) 2014 Alexander Bersenev <bay@hackerdom.ru> + * + * Based on sun5i-ir.c: + * Copyright (C) 2007-2012 Daniel Wang + * Allwinner Technology Co., Ltd. <www.allwinnertech.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; either version 2 of + * the License, or (at your option) any later version. + * + * 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/clk.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <media/rc-core.h> + +#define SUNXI_IR_DEV "sunxi-ir" + +/* Registers */ +/* IR Control */ +#define SUNXI_IR_CTL_REG 0x00 +/* Global Enable */ +#define REG_CTL_GEN BIT(0) +/* RX block enable */ +#define REG_CTL_RXEN BIT(1) +/* CIR mode */ +#define REG_CTL_MD (BIT(4) | BIT(5)) + +/* Rx Config */ +#define SUNXI_IR_RXCTL_REG 0x10 +/* Pulse Polarity Invert flag */ +#define REG_RXCTL_RPPI BIT(2) + +/* Rx Data */ +#define SUNXI_IR_RXFIFO_REG 0x20 + +/* Rx Interrupt Enable */ +#define SUNXI_IR_RXINT_REG 0x2C +/* Rx FIFO Overflow */ +#define REG_RXINT_ROI_EN BIT(0) +/* Rx Packet End */ +#define REG_RXINT_RPEI_EN BIT(1) +/* Rx FIFO Data Available */ +#define REG_RXINT_RAI_EN BIT(4) + +/* Rx FIFO available byte level */ +#define REG_RXINT_RAL(val) (((val) << 8) & (GENMASK(11, 8))) + +/* Rx Interrupt Status */ +#define SUNXI_IR_RXSTA_REG 0x30 +/* RX FIFO Get Available Counter */ +#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (GENMASK(5, 0))) +/* Clear all interrupt status value */ +#define REG_RXSTA_CLEARALL 0xff + +/* IR Sample Config */ +#define SUNXI_IR_CIR_REG 0x34 +/* CIR_REG register noise threshold */ +#define REG_CIR_NTHR(val) (((val) << 2) & (GENMASK(7, 2))) +/* CIR_REG register idle threshold */ +#define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8))) + +/* Hardware supported fifo size */ +#define SUNXI_IR_FIFO_SIZE 16 +/* How many messages in FIFO trigger IRQ */ +#define TRIGGER_LEVEL 8 +/* Required frequency for IR0 or IR1 clock in CIR mode */ +#define SUNXI_IR_BASE_CLK 8000000 +/* Frequency after IR internal divider */ +#define SUNXI_IR_CLK (SUNXI_IR_BASE_CLK / 64) +/* Sample period in ns */ +#define SUNXI_IR_SAMPLE (1000000000ul / SUNXI_IR_CLK) +/* Noise threshold in samples */ +#define SUNXI_IR_RXNOISE 1 +/* Idle Threshold in samples */ +#define SUNXI_IR_RXIDLE 20 +/* Time after which device stops sending data in ms */ +#define SUNXI_IR_TIMEOUT 120 + +struct sunxi_ir { + spinlock_t ir_lock; + struct rc_dev *rc; + void __iomem *base; + int irq; + struct clk *clk; + struct clk *apb_clk; + const char *map_name; +}; + +static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) +{ + unsigned long status; + unsigned char dt; + unsigned int cnt, rc; + struct sunxi_ir *ir = dev_id; + DEFINE_IR_RAW_EVENT(rawir); + + spin_lock(&ir->ir_lock); + + status = readl(ir->base + SUNXI_IR_RXSTA_REG); + + /* clean all pending statuses */ + writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); + + if (status & REG_RXINT_RAI_EN) { + /* How many messages in fifo */ + rc = REG_RXSTA_GET_AC(status); + /* Sanity check */ + rc = rc > SUNXI_IR_FIFO_SIZE ? SUNXI_IR_FIFO_SIZE : rc; + /* If we have data */ + for (cnt = 0; cnt < rc; cnt++) { + /* for each bit in fifo */ + dt = readb(ir->base + SUNXI_IR_RXFIFO_REG); + rawir.pulse = (dt & 0x80) != 0; + rawir.duration = ((dt & 0x7f) + 1) * SUNXI_IR_SAMPLE; + ir_raw_event_store_with_filter(ir->rc, &rawir); + } + } + + if (status & REG_RXINT_ROI_EN) { + ir_raw_event_reset(ir->rc); + } else if (status & REG_RXINT_RPEI_EN) { + ir_raw_event_set_idle(ir->rc, true); + ir_raw_event_handle(ir->rc); + } + + spin_unlock(&ir->ir_lock); + + return IRQ_HANDLED; +} + +static int sunxi_ir_probe(struct platform_device *pdev) +{ + int ret = 0; + unsigned long tmp = 0; + + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node; + struct resource *res; + struct sunxi_ir *ir; + + ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + /* Clock */ + ir->apb_clk = devm_clk_get(dev, "apb"); + if (IS_ERR(ir->apb_clk)) { + dev_err(dev, "failed to get a apb clock.\n"); + return PTR_ERR(ir->apb_clk); + } + ir->clk = devm_clk_get(dev, "ir"); + if (IS_ERR(ir->clk)) { + dev_err(dev, "failed to get a ir clock.\n"); + return PTR_ERR(ir->clk); + } + + ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); + if (ret) { + dev_err(dev, "set ir base clock failed!\n"); + return ret; + } + + if (clk_prepare_enable(ir->apb_clk)) { + dev_err(dev, "try to enable apb_ir_clk failed\n"); + return -EINVAL; + } + + if (clk_prepare_enable(ir->clk)) { + dev_err(dev, "try to enable ir_clk failed\n"); + ret = -EINVAL; + goto exit_clkdisable_apb_clk; + } + + /* IO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ir->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ir->base)) { + dev_err(dev, "failed to map registers\n"); + ret = PTR_ERR(ir->base); + goto exit_clkdisable_clk; + } + + ir->rc = rc_allocate_device(); + if (!ir->rc) { + dev_err(dev, "failed to allocate device\n"); + ret = -ENOMEM; + goto exit_clkdisable_clk; + } + + ir->rc->priv = ir; + ir->rc->input_name = SUNXI_IR_DEV; + ir->rc->input_phys = "sunxi-ir/input0"; + ir->rc->input_id.bustype = BUS_HOST; + ir->rc->input_id.vendor = 0x0001; + ir->rc->input_id.product = 0x0001; + ir->rc->input_id.version = 0x0100; + ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL); + ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; + ir->rc->dev.parent = dev; + ir->rc->driver_type = RC_DRIVER_IR_RAW; + ir->rc->allowed_protocols = RC_BIT_ALL; + ir->rc->rx_resolution = SUNXI_IR_SAMPLE; + ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT); + ir->rc->driver_name = SUNXI_IR_DEV; + + ret = rc_register_device(ir->rc); + if (ret) { + dev_err(dev, "failed to register rc device\n"); + goto exit_free_dev; + } + + platform_set_drvdata(pdev, ir); + + /* IRQ */ + ir->irq = platform_get_irq(pdev, 0); + if (ir->irq < 0) { + dev_err(dev, "no irq resource\n"); + ret = ir->irq; + goto exit_free_dev; + } + + ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir); + if (ret) { + dev_err(dev, "failed request irq\n"); + goto exit_free_dev; + } + + /* Enable CIR Mode */ + writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG); + + /* Set noise threshold and idle threshold */ + writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE), + ir->base + SUNXI_IR_CIR_REG); + + /* Invert Input Signal */ + writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG); + + /* Clear All Rx Interrupt Status */ + writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); + + /* + * Enable IRQ on overflow, packet end, FIFO available with trigger + * level + */ + writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN | + REG_RXINT_RAI_EN | REG_RXINT_RAL(TRIGGER_LEVEL - 1), + ir->base + SUNXI_IR_RXINT_REG); + + /* Enable IR Module */ + tmp = readl(ir->base + SUNXI_IR_CTL_REG); + writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG); + + dev_info(dev, "initialized sunXi IR driver\n"); + return 0; + +exit_free_dev: + rc_free_device(ir->rc); +exit_clkdisable_clk: + clk_disable_unprepare(ir->clk); +exit_clkdisable_apb_clk: + clk_disable_unprepare(ir->apb_clk); + + return ret; +} + +static int sunxi_ir_remove(struct platform_device *pdev) +{ + unsigned long flags; + struct sunxi_ir *ir = platform_get_drvdata(pdev); + + clk_disable_unprepare(ir->clk); + clk_disable_unprepare(ir->apb_clk); + + spin_lock_irqsave(&ir->ir_lock, flags); + /* disable IR IRQ */ + writel(0, ir->base + SUNXI_IR_RXINT_REG); + /* clear All Rx Interrupt Status */ + writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG); + /* disable IR */ + writel(0, ir->base + SUNXI_IR_CTL_REG); + spin_unlock_irqrestore(&ir->ir_lock, flags); + + rc_unregister_device(ir->rc); + return 0; +} + +static const struct of_device_id sunxi_ir_match[] = { + { .compatible = "allwinner,sun4i-a10-ir", }, + {}, +}; + +static struct platform_driver sunxi_ir_driver = { + .probe = sunxi_ir_probe, + .remove = sunxi_ir_remove, + .driver = { + .name = SUNXI_IR_DEV, + .owner = THIS_MODULE, + .of_match_table = sunxi_ir_match, + }, +}; + +module_platform_driver(sunxi_ir_driver); + +MODULE_DESCRIPTION("Allwinner sunXi IR controller driver"); +MODULE_AUTHOR("Alexsey Shestacov <wingrime@linux-sunxi.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index c5be38e2a2fe..bc214e2b3a36 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf, usb_to_input_id(tt->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc_set_allowed_protocols(rc, RC_BIT_ALL); + rc->allowed_protocols = RC_BIT_ALL; rc->priv = tt; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_TT_1500; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index a8b981f5ce2e..d839f73f6a05 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1082,7 +1082,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->dev.parent = &device->dev; data->dev->timeout = MS_TO_NS(100); data->dev->rx_resolution = US_TO_NS(2); - rc_set_allowed_protocols(data->dev, RC_BIT_ALL); + data->dev->allowed_protocols = RC_BIT_ALL; err = rc_register_device(data->dev); if (err) |